Merge branch 'develop'

- Support private file
- Update odoo 14 and 16
- selenium lib support opening kdbx
This commit is contained in:
Mathieu Benoit 2025-08-07 03:34:02 -04:00
commit 63970ed2f5
12 changed files with 120 additions and 12 deletions

1
.gitignore vendored
View file

@ -43,4 +43,3 @@ requirements.txt
requirement/ignore_requirements.txt
screenshots
screencasts
script/todo/todo_override.json

View file

@ -53,14 +53,26 @@ docker_exec_erplibre_repo_show_status:
docker_build_odoo_16:
./script/docker/docker_build.sh --odoo_16
.PHONY: docker_build_odoo_16_clean
docker_build_odoo_16_clean:
./script/docker/docker_build.sh --odoo_16 --no-cache
.PHONY: docker_build_odoo_14
docker_build_odoo_14:
./script/docker/docker_build.sh --odoo_14
.PHONY: docker_build_odoo_14_clean
docker_build_odoo_14_clean:
./script/docker/docker_build.sh --odoo_14 --no-cache
.PHONY: docker_build_odoo_12
docker_build_odoo_12:
./script/docker/docker_build.sh --odoo_12
.PHONY: docker_build_odoo_12_clean
docker_build_odoo_12_clean:
./script/docker/docker_build.sh --odoo_12 --no-cache
# build docker release
.PHONY: docker_build_release
docker_build_release:

View file

@ -221,3 +221,9 @@ cat /proc/sys/fs/inotify/max_user_watches
Tips, when doing `sudo sysctl -p --system`, validate the order of the process, another process can overwrite your new
value.
## How killing all process from selenium
```bash
pkill -f "firefox.*--marionette"
```

View file

@ -27,6 +27,7 @@ services:
# See the volume section at the end of the file
- erplibre_data_dir:/home/odoo/.local/share/Odoo
- ./addons/addons:/ERPLibre/addons/addons
- ./private:/ERPLibre/private
- erplibre_conf:/etc/odoo
restart: always

View file

@ -1,7 +1,7 @@
version: "3.3"
services:
ERPLibre:
image: technolibre/erplibre:1.6.0_odoo_14.0_2a8af84
image: technolibre/erplibre:1.6.0_odoo_14.0_1890768
ports:
- 8069:8069
- 8071:8071
@ -27,6 +27,7 @@ services:
# See the volume section at the end of the file
- erplibre_data_dir:/home/odoo/.local/share/Odoo
- ./addons/addons:/ERPLibre/addons/addons
- ./private:/ERPLibre/private
- erplibre_conf:/etc/odoo
restart: always

View file

@ -27,6 +27,7 @@ services:
# See the volume section at the end of the file
- erplibre_data_dir:/home/odoo/.local/share/Odoo
- ./addons/addons:/ERPLibre/addons/addons
- ./private:/ERPLibre/private
- erplibre_conf:/etc/odoo
restart: always

View file

@ -97,7 +97,7 @@
<project name="openeducat_erp.git" path="addons.odoo16.0/openeducat_openeducat_erp" remote="openeducat" groups="addons"/>
<project name="OpenUpgrade.git" path="script/OCA_OpenUpgrade" remote="OCA" clone-depth="10" groups="migration"/>
<project name="operating-unit.git" path="addons.odoo16.0/OCA_operating-unit" remote="OCA" groups="addons"/>
<project name="partner-contact.git" path="addons.odoo16.0/OCA_partner-contact" remote="OCA" groups="addons"/>
<project name="partner-contact.git" path="addons.odoo16.0/OCA_partner-contact" remote="OCA" groups="addons,base"/>
<project name="pos.git" path="addons.odoo16.0/OCA_pos" remote="OCA" groups="addons"/>
<project name="product-attribute.git" path="addons.odoo16.0/OCA_product-attribute" remote="OCA" groups="addons"/>
<project name="product-configurator.git" path="addons.odoo16.0/OCA_product-configurator" remote="OCA" groups="addons"/>
@ -107,20 +107,20 @@
<project name="project-agile.git" path="addons.odoo16.0/OCA_project-agile" remote="OCA" groups="addons"/>
<project name="project.git" path="addons.odoo16.0/OCA_project" remote="OCA" groups="addons"/>
<project name="purchase-workflow.git" path="addons.odoo16.0/OCA_purchase-workflow" remote="OCA" groups="addons"/>
<project name="queue.git" path="addons.odoo16.0/OCA_queue" remote="OCA" groups="addons"/>
<project name="queue.git" path="addons.odoo16.0/OCA_queue" remote="OCA" groups="addons,base"/>
<project name="reporting-engine.git" path="addons.odoo16.0/OCA_reporting-engine" remote="OCA" groups="addons"/>
<project name="rma.git" path="addons.odoo16.0/OCA_rma" remote="OCA" groups="addons"/>
<project name="saas-addons.git" path="addons.odoo16.0/it-projects-llc_saas-addons" remote="it-projects-llc" groups="addons"/>
<project name="sale-reporting.git" path="addons.odoo16.0/OCA_sale-reporting" remote="OCA" groups="addons"/>
<project name="sale-workflow.git" path="addons.odoo16.0/OCA_sale-workflow" remote="OCA" groups="addons"/>
<project name="server-auth.git" path="addons.odoo16.0/OCA_server-auth" remote="OCA" groups="addons"/>
<project name="server-auth.git" path="addons.odoo16.0/OCA_server-auth" remote="OCA" groups="addons,base"/>
<project name="server-backend.git" path="addons.odoo16.0/OCA_server-backend" remote="OCA" groups="addons"/>
<project name="server-brand.git" path="addons.odoo16.0/OCA_server-brand" remote="OCA" groups="addons"/>
<project name="server-brand.git" path="addons.odoo16.0/OCA_server-brand" remote="OCA" groups="addons,base"/>
<project name="server-env.git" path="addons.odoo16.0/OCA_server-env" remote="OCA" groups="addons"/>
<project name="server-tools.git" path="addons.odoo16.0/OCA_server-tools" remote="ERPLibre" revision="ERPLibre/16.0" groups="addons"/>
<project name="server-ux.git" path="addons.odoo16.0/OCA_server-ux" remote="OCA" groups="addons"/>
<project name="server-tools.git" path="addons.odoo16.0/OCA_server-tools" remote="ERPLibre" revision="ERPLibre/16.0" groups="addons,base"/>
<project name="server-ux.git" path="addons.odoo16.0/OCA_server-ux" remote="OCA" groups="addons,base"/>
<project name="shift-planning.git" path="addons.odoo16.0/OCA_shift-planning" remote="ERPLibre" revision="16.0_dev" groups="addons"/>
<project name="social.git" path="addons.odoo16.0/OCA_social" remote="OCA" groups="addons"/>
<project name="social.git" path="addons.odoo16.0/OCA_social" remote="OCA" groups="addons,base"/>
<project name="survey.git" path="addons.odoo16.0/OCA_survey" remote="ERPLibre" revision="16.0_dev" groups="addons"/>
<project name="stock-logistics-warehouse.git" path="addons.odoo16.0/OCA_stock-logistics-warehouse" remote="OCA" groups="addons"/>
<project name="storage.git" path="addons.odoo16.0/OCA_storage" remote="OCA" groups="addons"/>
@ -129,7 +129,7 @@
<project name="vertical-hotel.git" path="addons.odoo16.0/OCA_vertical-hotel" remote="OCA" groups="addons"/>
<project name="vertical-isp.git" path="addons.odoo16.0/OCA_vertical-isp" remote="OCA" groups="addons"/>
<project name="vertical-travel.git" path="addons.odoo16.0/OCA_vertical-travel" remote="OCA" groups="addons"/>
<project name="web.git" path="addons.odoo16.0/OCA_web" remote="OCA" groups="addons"/>
<project name="web.git" path="addons.odoo16.0/OCA_web" remote="OCA" groups="addons,base"/>
<project name="website-cms.git" path="addons.odoo16.0/OCA_website-cms" remote="OCA" groups="addons"/>
<project name="website.git" path="addons.odoo16.0/OCA_website" remote="OCA" groups="addons"/>
<project name="wms.git" path="addons.odoo16.0/OCA_wms" remote="OCA" groups="addons"/>

1
private/TODO.md Normal file
View file

@ -0,0 +1 @@
Move your private file and project configuration here. The docker will share a volume with this repertory.

0
private/__init__.py Normal file
View file

View file

@ -8,7 +8,13 @@ import random
import re
import sys
import time
import json
import tempfile
from subprocess import getoutput
import tkinter as tk
from tkinter import filedialog
import getpass
from pykeepass import PyKeePass
from randomwordfr import RandomWordFr
from selenium import webdriver
@ -20,16 +26,24 @@ from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions.wheel_input import ScrollOrigin
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
# TODO maybe use TODO lib
CONFIG_FILE = "./script/todo/todo.json"
CONFIG_OVERRIDE_FILE = "./private/todo.json"
LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt"
class SeleniumLib(object):
def __init__(self, config):
self.config = config
self.kdbx = None
self.video_recorder = None
self.default_download_dir_path = tempfile.mkdtemp()
if self.config.video_suffix:
self.filename_recording = (
f"video_{self.config.video_suffix}_"
@ -67,6 +81,9 @@ class SeleniumLib(object):
if not self.config.not_private_mode:
firefox_options.add_argument("--private")
if self.config.headless:
firefox_options.add_argument("--headless")
# firefox_options.set_preference("browser.link.open_newwindow", 3)
# firefox_options.set_preference("browser.link.open_newwindow.restriction", 2)
@ -75,6 +92,18 @@ class SeleniumLib(object):
firefox_options.set_preference(
"permissions.default.desktop-notification", 1
)
firefox_options.set_preference("browser.download.folderList", 2)
firefox_options.set_preference(
"browser.download.manager.showWhenStarting", False
)
firefox_options.set_preference(
"browser.download.dir", self.default_download_dir_path
)
firefox_options.set_preference(
"browser.helperApps.neverAsk.saveToDisk",
"application/octet-stream,application/pdf,application/x-pdf",
)
firefox_options.set_preference("pdfjs.disabled", True)
firefox_services = None
if self.config.firefox_binary_path:
firefox_services = Service(
@ -182,6 +211,53 @@ class SeleniumLib(object):
self.driver.close()
self.driver.switch_to.window(self.driver.window_handles[0])
def get_kdbx(self):
if self.kdbx:
return self.kdbx
# Open file
chemin_fichier_kdbx = self.get_config(["kdbx", "path"])
if not chemin_fichier_kdbx:
root = tk.Tk()
root.withdraw() # Hide the main window
chemin_fichier_kdbx = filedialog.askopenfilename(
title="Select a File",
filetypes=(("KeepassX files", "*.kdbx"),),
)
if not chemin_fichier_kdbx:
# _logger.error(f"KDBX is not configured, please fill {CONFIG_FILE}")
return
mot_de_passe_kdbx = self.get_config(["kdbx", "password"])
if not mot_de_passe_kdbx:
mot_de_passe_kdbx = getpass.getpass(
prompt="Entrez votre mot de passe : "
)
kp = PyKeePass(chemin_fichier_kdbx, password=mot_de_passe_kdbx)
if kp:
self.kdbx = kp
return kp
def get_config(self, lst_params):
# Open file
config_file = CONFIG_FILE
if os.path.exists(CONFIG_OVERRIDE_FILE):
config_file = CONFIG_OVERRIDE_FILE
with open(config_file) as cfg:
dct_data = json.load(cfg)
for param in lst_params:
try:
dct_data = dct_data[param]
except KeyError:
# _logger.error(
# f"KeyError on file {config_file} with keys"
# f" {lst_params}"
# )
return
return dct_data
@staticmethod
def get_french_word_no_space_no_accent():
word = ""
@ -248,6 +324,12 @@ class SeleniumLib(object):
return ele
def get_text_from_element(
self, by: str = By.ID, value: str = None, timeout=5
):
ele = self.get_element(by, value, timeout=timeout)
return ele.text
def get_all_element(self, by: str = By.ID, value: str = None, timeout=5):
wait = WebDriverWait(self.driver, timeout)
ele = wait.until(
@ -1133,6 +1215,11 @@ def fill_parser(parser):
action="store_true",
help="Default is private mode.",
)
group_browser.add_argument(
"--headless",
action="store_true",
help="For automation without GUI.",
)
group_browser.add_argument(
"--no_dark_mode",
action="store_true",

View file

@ -1,4 +1,4 @@
TODO is an assistant robot to use ERPLibre
Execute it with `./script/todo/todo.py` or `make todo`.
For a new project, copy todo_example.json to todo_override.json and edit it.
For a new project, copy todo_example.json to private/todo.json and edit it.

View file

@ -87,7 +87,7 @@ except ModuleNotFoundError as e:
_logger = logging.getLogger(__name__)
CONFIG_FILE = "./script/todo/todo.json"
CONFIG_OVERRIDE_FILE = "./script/todo/todo_override.json"
CONFIG_OVERRIDE_FILE = "./private/todo.json"
LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt"