|
@@ -0,0 +1,164 @@
|
|
|
|
+
|
|
|
|
+from asyncio.windows_events import NULL
|
|
|
|
+from time import sleep
|
|
|
|
+from app_logging import logger_name, init as init_logging
|
|
|
|
+import logging
|
|
|
|
+logger = logging.getLogger(logger_name)
|
|
|
|
+import requests,json
|
|
|
|
+import datetime
|
|
|
|
+import argparse
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+init_logging()
|
|
|
|
+
|
|
|
|
+logger.debug(__name__)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+logger.info("")
|
|
|
|
+logger.info("")
|
|
|
|
+logger.info("")
|
|
|
|
+logger.info("------- welcome to Slash-Dolistripe -------")
|
|
|
|
+
|
|
|
|
+# Method to read config file settings
|
|
|
|
+logger.info(" --- -------------------------------------------------------------------------------- ---")
|
|
|
|
+logger.info(" --- ---------------------------------- ARG PHASE ----------------------------------- ---")
|
|
|
|
+logger.info(" --- -------------------------------------------------------------------------------- ---")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+parser = argparse.ArgumentParser()
|
|
|
|
+parser.add_argument("-v","--verbosity", help="increase output verbosity",action="store_true")
|
|
|
|
+parser.add_argument("-d","--dry", help="perform a dry run",action="store_true")
|
|
|
|
+parser.add_argument("-m","--mail", help="send invoice per mail to client (you can add a contact mail copy in the reference.conf file)",action="store_true")
|
|
|
|
+parser.add_argument("-p","--planned", help="trigger planned work to ",action="store_true")
|
|
|
|
+
|
|
|
|
+args = parser.parse_args()
|
|
|
|
+if args.verbosity:
|
|
|
|
+ logger.info("Args : Debug Verbose Enabled")
|
|
|
|
+ logger.setLevel(logging.DEBUG)
|
|
|
|
+else :
|
|
|
|
+ logger.setLevel(logging.INFO)
|
|
|
|
+
|
|
|
|
+args = parser.parse_args()
|
|
|
|
+if args.dry:
|
|
|
|
+ logger.info("Args : Dry Run Enabled")
|
|
|
|
+
|
|
|
|
+args = parser.parse_args()
|
|
|
|
+if args.mail:
|
|
|
|
+ logger.info("Args : send invoice per Mails Enabled")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+logger.info(" --- -------------------------------------------------------------------------------- ---")
|
|
|
|
+logger.info(" --- ---------------------------------- CONF PHASE ---------------------------------- ---")
|
|
|
|
+logger.info(" --- -------------------------------------------------------------------------------- ---")
|
|
|
|
+logger.info("Reading Reference ConfIguration File")
|
|
|
|
+import configparser
|
|
|
|
+config = configparser.ConfigParser()
|
|
|
|
+config.optionxform = str # to make the read Case Sensitive
|
|
|
|
+config.read('references.conf')
|
|
|
|
+
|
|
|
|
+dolibarr_url = config["credentials"]["dolibarr_url"]
|
|
|
|
+dolibarr_username = config["credentials"]["dolibarr_username"]
|
|
|
|
+dolibarr_password = config["credentials"]["dolibarr_password"]
|
|
|
|
+
|
|
|
|
+if args.planned :
|
|
|
|
+ dolibarr_planned_work_key = config["credentials"]["planned_work_key"]
|
|
|
|
+ dolibarr_planned_work_cron_job_id = config["credentials"]["cron_job_id"]
|
|
|
|
+
|
|
|
|
+contact_mail = None
|
|
|
|
+
|
|
|
|
+if config.has_option("credentials", "contact_mail") :
|
|
|
|
+ contact_mail = config["credentials"]["contact_mail"]
|
|
|
|
+
|
|
|
|
+logger.debug("contact mail in configuration is : " + contact_mail)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+logger.info(" --- -------------------------------------------------------------------------------- ---")
|
|
|
|
+logger.info(" --- -------------------------------- READ CRM PHASE -------------------------------- ---")
|
|
|
|
+logger.info(" --- -------------------------------------------------------------------------------- ---")
|
|
|
|
+
|
|
|
|
+from selenium import webdriver
|
|
|
|
+from selenium.webdriver.common.keys import Keys
|
|
|
|
+from selenium.webdriver.common.by import By
|
|
|
|
+import logging
|
|
|
|
+from selenium.webdriver.remote.remote_connection import LOGGER
|
|
|
|
+LOGGER.setLevel(logging.CRITICAL)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+logger.info("CRM Login")
|
|
|
|
+driver = webdriver.Edge()
|
|
|
|
+driver.get(dolibarr_url + "/index.php")
|
|
|
|
+assert "Identifiant" in driver.title
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+driver.find_element(By.NAME,"username").send_keys(str(dolibarr_username))
|
|
|
|
+pass_field = driver.find_element(By.NAME,"password")
|
|
|
|
+pass_field.send_keys(str(dolibarr_password))
|
|
|
|
+pass_field.send_keys(Keys.RETURN)
|
|
|
|
+logger.info(driver.title)
|
|
|
|
+assert "Accueil" in driver.title
|
|
|
|
+
|
|
|
|
+logger.info("login successful")
|
|
|
|
+
|
|
|
|
+current_date = datetime.datetime.now()
|
|
|
|
+
|
|
|
|
+driver.get(dolibarr_url + "//compta/facture/list.php?leftmenu=customers_bills")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+# iterating over links63
|
|
|
|
+logger.info("iterating over invoice")
|
|
|
|
+invoices_table = driver.find_elements(By.XPATH,"//div[contains(@id,'contrat-lines-container')]/div")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+invoices_table = driver.find_element(By.CLASS_NAME,'liste')
|
|
|
|
+invoices_entries = invoices_table.find_elements(By.CLASS_NAME,"oddeven")
|
|
|
|
+
|
|
|
|
+class invoice_to_process :
|
|
|
|
+ link : str
|
|
|
|
+ name : str
|
|
|
|
+ amount : float
|
|
|
|
+
|
|
|
|
+invoices_to_process = set()
|
|
|
|
+
|
|
|
|
+logger.info("checkin all invoices to found unpaid ones with amount 0...")
|
|
|
|
+for invoice_entry in invoices_entries :
|
|
|
|
+
|
|
|
|
+ inv = invoice_to_process()
|
|
|
|
+ logger.debug("----------")
|
|
|
|
+ item = invoice_entry.find_element(By.CLASS_NAME,"classfortooltip")
|
|
|
|
+ inv.name = item.text
|
|
|
|
+ inv.link = item.get_attribute("href")
|
|
|
|
+
|
|
|
|
+ logger.debug("invoice name : " + inv.name)
|
|
|
|
+ logger.debug("invoice link : " + inv.link)
|
|
|
|
+
|
|
|
|
+ inv.amount = float(invoice_entry.find_element(By.CLASS_NAME,"amount").text.replace(',','.').replace(' ',''))
|
|
|
|
+ logger.debug("invoice amount : " + str(inv.amount))
|
|
|
|
+ status = invoice_entry.find_element(By.CLASS_NAME,"badge-status").text
|
|
|
|
+ logger.debug("status : " + str(status))
|
|
|
|
+ if str(status) == "Impayée" and inv.amount == 0.0:
|
|
|
|
+ logger.info("## An invoice is suitable for processing ! : " + inv.name)
|
|
|
|
+ invoices_to_process.add(inv)
|
|
|
|
+
|
|
|
|
+ logger.debug("----------")
|
|
|
|
+
|
|
|
|
+if args.dry:
|
|
|
|
+ driver.close()
|
|
|
|
+ logger.info("dry run enabled, exiting here...")
|
|
|
|
+ exit(0)
|
|
|
|
+
|
|
|
|
+logger.info("processing target invoices...")
|
|
|
|
+invoice : invoice_to_process
|
|
|
|
+for invoice in invoices_to_process :
|
|
|
|
+ logger.info("processing invoice " + invoice.name + "...")
|
|
|
|
+ driver.get(invoice.link + "&action=paid")
|
|
|
|
+ buttons = driver.find_element(By.CLASS_NAME,"ui-dialog-buttonset")
|
|
|
|
+ logger.debug(buttons.get_attribute("innerHTML"))
|
|
|
|
+ buttons.find_element(By.XPATH,'button[contains(text(), "Oui")]').click()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+exit(0)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|