Merge branch 'develop_support_arch_linux'

- Upgrade odoo 14 and 16
- Improve selenium odoo navigation and recording
- Improve installation ERPLibre and docker build
This commit is contained in:
Mathieu Benoit 2025-04-12 17:12:23 -04:00
commit 4f39f86cc5
30 changed files with 4204 additions and 2808 deletions

1
.erplibre-semver-version Normal file
View file

@ -0,0 +1 @@
1.5.0

View file

@ -30,6 +30,18 @@ else
endif endif
endif endif
# Example for update
.PHONY: custom_run_example
custom_run_example:
./run.sh -d example_prod
.PHONY: custom_update_example
custom_update_example:
./script/database/db_restore.py --database example_prod --image image_name_to_restore
./script/addons/update_addons_all.sh example_prod
./script/addons/update_prod_to_dev.sh example_prod
######### #########
# RUN # # RUN #
######### #########
@ -727,6 +739,13 @@ tag_push_all:
open_terminal: open_terminal:
./script/open_terminal_code_generator.sh ./script/open_terminal_code_generator.sh
##############
# selenium #
##############
.PHONY: open_selenium
open_selenium:
./.venv/bin/python ./script/selenium/web_login.py
############ ############
# format # # format #
############ ############
@ -938,6 +957,7 @@ config_install:
.PHONY: config_update .PHONY: config_update
config_update: config_update:
# Need http to configure the file config.conf, or will disable it
./run.sh -c config.conf -s --stop-after-init ./run.sh -c config.conf -s --stop-after-init
.PHONY: config_update_over_proxy .PHONY: config_update_over_proxy

View file

@ -122,6 +122,36 @@ git reset --hard REF_OF_REMOTES/m
> git reset --hard remotes/origin/rel/8953/zd552kl/7.1.1-11.40.208 > git reset --hard remotes/origin/rel/8953/zd552kl/7.1.1-11.40.208
``` ```
### fatal: GitCommandError: git command failure
Example of error after an installation with git-repo:
```
raise GitCommandError(
git_command.GitCommandError: GitCommandError: git command failure
Project: manifests
Args: rev-list ^e96a83f03665ecc1b151331776909be32d5e2c7b HEAD --
Stdout:
None
Stderr:
fatal: bad revision 'HEAD'
Skipped fetching project manifests (already have persistent ref)
fatal: GitCommandError: git command failure
Project: manifests
Args: rev-list ^HEAD c8e64956f188f77abcfa7ff0e764af97162d3071 --
Stdout:
None
Stderr:
fatal: bad revision '^HEAD'
```
Solution: Check files into directory `cd .repo/manifests` with commande `git status`. If
you
have some differences in stage, you can try `git reset --hard` and redo the
installation.
If it's not working, re-clone the repo and do a fresh installation.
## OSX installation ## OSX installation
### Docker installation ### Docker installation

View file

@ -52,7 +52,7 @@ Execute migration with OpenUpgrade.
```bash ```bash
make config_gen_migration make config_gen_migration
./.venv/bin/python ./script/OCA_OpenUpgrade/odoo-bin -c ./config.conf --update all --stop-after-init -d BD ./.venv/bin/python ./script/OCA_OpenUpgrade/odoo-bin -c ./config.conf --no-http --update all --stop-after-init -d BD
``` ```
## Migration Odoo 13 to Odoo 14 ## Migration Odoo 13 to Odoo 14
@ -61,5 +61,5 @@ Replace BD to your database name.
```bash ```bash
make config_gen_migration make config_gen_migration
./run.sh --upgrade-path=./script/OCA_OpenUpgrade/openupgrade_scripts/scripts --update all --stop-after-init --load=base,web,openupgrade_framework -d BD ./run.sh --upgrade-path=./script/OCA_OpenUpgrade/openupgrade_scripts/scripts --update all --no-http --stop-after-init --load=base,web,openupgrade_framework -d BD
``` ```

View file

@ -112,7 +112,7 @@ database. WARNING, this is not safe for production, you will expose all data.
Update all features. Update all features.
```bash ```bash
./run.sh --limit-time-real 99999 --stop-after-init -u all -d DATABASE ./run.sh --limit-time-real 99999 --no-http --stop-after-init -u all -d DATABASE
``` ```
# Postgresql # Postgresql

View file

@ -49,17 +49,17 @@ Great idea to run it when updating Odoo, it updates each module database.
First execution, install you requirements, choose a new database. First execution, install you requirements, choose a new database.
```bash ```bash
./run.sh -d [DATABASE] -i [module to test] --test-enable --stop-after-init --log-level=test ./run.sh -d [DATABASE] -i [module to test] --test-enable --no-http --stop-after-init --log-level=test
``` ```
Execute your test on a specific module. Execute your test on a specific module.
```bash ```bash
./run.sh -d [DATABASE] -u [module to test] --test-enable --stop-after-init --log-level=test ./run.sh -d [DATABASE] -u [module to test] --test-enable --no-http --stop-after-init --log-level=test
``` ```
Execute your test on a specific module with tags. Execute your test on a specific module with tags.
```bash ```bash
./run.sh -d [DATABASE] -u [module to test] --test-enable --stop-after-init --log-level=test --test-tags [module_name][tags] ./run.sh -d [DATABASE] -u [module to test] --test-enable --no-http --stop-after-init --log-level=test --test-tags [module_name][tags]
``` ```

View file

@ -45,7 +45,7 @@ RUN cd $ODOO_PREFIX && \
RUN cd $ODOO_PREFIX && \ RUN cd $ODOO_PREFIX && \
ls -lha /ERPLibre && \ ls -lha /ERPLibre && \
echo "${ERPLIBRE_VERSION}" && \ echo "${ERPLIBRE_VERSION}" && \
./script/version/update_env_version.py --erplibre_version "${ERPLIBRE_VERSION}" ./script/version/update_env_version.py --erplibre_version "${ERPLIBRE_VERSION}" --partial_install
RUN cd $ODOO_PREFIX && ls ./manifest -la && \ RUN cd $ODOO_PREFIX && ls ./manifest -la && \
ls -lha /ERPLibre && \ ls -lha /ERPLibre && \

View file

@ -112,6 +112,13 @@ You can change the docker directory by editing file `/etc/docker/daemon.json`
``` ```
And restart docker service. You can delete or move all older locations of docker. And restart docker service. You can delete or move all older locations of docker.
Or
Add `--data-root /second_drive/docker` like example following into file `/lib/systemd/system/docker.service` :
```
ExecStart=/usr/bin/dockerd --data-root /second_drive/docker -H fd:// --containerd=/run/containerd/containerd.sock
```
# Update docker # Update docker
When building your docker with script When building your docker with script
> make docker_build_odoo_16 > make docker_build_odoo_16

View file

@ -96,7 +96,7 @@
<project name="odoo-product-addons.git" path="addons.odoo14.0/Numigi_odoo-product-addons" remote="Numigi" groups="addons"/> <project name="odoo-product-addons.git" path="addons.odoo14.0/Numigi_odoo-product-addons" remote="Numigi" groups="addons"/>
<project name="odoo-project-addons.git" path="addons.odoo14.0/Numigi_odoo-project-addons" remote="Numigi" groups="addons"/> <project name="odoo-project-addons.git" path="addons.odoo14.0/Numigi_odoo-project-addons" remote="Numigi" groups="addons"/>
<project name="odoo-purchase-addons.git" path="addons.odoo14.0/Numigi_odoo-purchase-addons" remote="Numigi" groups="addons"/> <project name="odoo-purchase-addons.git" path="addons.odoo14.0/Numigi_odoo-purchase-addons" remote="Numigi" groups="addons"/>
<project name="odoo-stock-addons.git" path="addons.odoo14.0/Numigi_odoo-stock-addons" remote="Numigi" groups="addons"/> <project name="odoo-stock-addons.git" path="addons.odoo14.0/Numigi_odoo-stock-addons" remote="ERPLibre" revision="14.0_dev" groups="addons"/>
<project name="odoo-survey-addons.git" path="addons.odoo14.0/Numigi_odoo-survey-addons" remote="Numigi" groups="addons"/> <project name="odoo-survey-addons.git" path="addons.odoo14.0/Numigi_odoo-survey-addons" remote="Numigi" groups="addons"/>
<project name="odoo-test-docs.git" path="doc/itpp-labs_odoo-test-docs" remote="itpp-labs" revision="master" groups="odoo"/> <project name="odoo-test-docs.git" path="doc/itpp-labs_odoo-test-docs" remote="itpp-labs" revision="master" groups="odoo"/>
<project name="odoo-timesheet-addons.git" path="addons.odoo14.0/Numigi_odoo-timesheet-addons" remote="Numigi" groups="addons"/> <project name="odoo-timesheet-addons.git" path="addons.odoo14.0/Numigi_odoo-timesheet-addons" remote="Numigi" groups="addons"/>
@ -131,7 +131,7 @@
<project name="server-brand.git" path="addons.odoo14.0/OCA_server-brand" remote="OCA" groups="addons"/> <project name="server-brand.git" path="addons.odoo14.0/OCA_server-brand" remote="OCA" groups="addons"/>
<project name="server-env.git" path="addons.odoo14.0/OCA_server-env" remote="OCA" groups="addons"/> <project name="server-env.git" path="addons.odoo14.0/OCA_server-env" remote="OCA" groups="addons"/>
<project name="server-tools.git" path="addons.odoo14.0/OCA_server-tools" remote="ERPLibre" revision="14.0_dev" groups="addons"/> <project name="server-tools.git" path="addons.odoo14.0/OCA_server-tools" remote="ERPLibre" revision="14.0_dev" groups="addons"/>
<project name="server-ux.git" path="addons.odoo14.0/OCA_server-ux" remote="OCA" groups="addons"/> <project name="server-ux.git" path="addons.odoo14.0/OCA_server-ux" remote="ERPLibre" revision="14.0_dev" groups="addons"/>
<project name="social.git" path="addons.odoo14.0/OCA_social" remote="ERPLibre" revision="14.0_dev" groups="addons"/> <project name="social.git" path="addons.odoo14.0/OCA_social" remote="ERPLibre" revision="14.0_dev" groups="addons"/>
<project name="survey.git" path="addons.odoo14.0/OCA_survey" remote="OCA" groups="addons"/> <project name="survey.git" path="addons.odoo14.0/OCA_survey" remote="OCA" groups="addons"/>
<project name="stock-logistics-warehouse.git" path="addons.odoo14.0/OCA_stock-logistics-warehouse" remote="OCA" groups="addons"/> <project name="stock-logistics-warehouse.git" path="addons.odoo14.0/OCA_stock-logistics-warehouse" remote="OCA" groups="addons"/>

View file

@ -28,7 +28,7 @@
<project name="ERPLibre_image_db.git" path="image_db" remote="ERPLibre" clone-depth="1" revision="main" groups="base"/> <project name="ERPLibre_image_db.git" path="image_db" remote="ERPLibre" clone-depth="1" revision="main" groups="base"/>
<project name="OpenHRMS.git" path="addons.odoo16.0/CybroOdoo_OpenHRMS" remote="CybroOdoo" groups="addons"/> <project name="OpenHRMS.git" path="addons.odoo16.0/CybroOdoo_OpenHRMS" remote="CybroOdoo" groups="addons"/>
<project name="CybroAddons.git" path="addons.odoo16.0/CybroOdoo_CybroAddons" remote="ERPLibre" revision="16.0_dev" groups="addons"/> <project name="CybroAddons.git" path="addons.odoo16.0/CybroOdoo_CybroAddons" remote="ERPLibre" clone-depth="1" revision="16.0_dev" groups="addons"/>
<project name="account-analytic.git" path="addons.odoo16.0/OCA_account-analytic" remote="OCA" groups="addons"/> <project name="account-analytic.git" path="addons.odoo16.0/OCA_account-analytic" remote="OCA" groups="addons"/>
<project name="account-budgeting.git" path="addons.odoo16.0/OCA_account-budgeting" remote="OCA" groups="addons"/> <project name="account-budgeting.git" path="addons.odoo16.0/OCA_account-budgeting" remote="OCA" groups="addons"/>
<project name="account-closing.git" path="addons.odoo16.0/OCA_account-closing" remote="OCA" groups="addons"/> <project name="account-closing.git" path="addons.odoo16.0/OCA_account-closing" remote="OCA" groups="addons"/>
@ -70,6 +70,7 @@
<project name="geospatial.git" path="addons.odoo16.0/OCA_geospatial" remote="OCA" groups="addons"/> <project name="geospatial.git" path="addons.odoo16.0/OCA_geospatial" remote="OCA" groups="addons"/>
<project name="helpdesk.git" path="addons.odoo16.0/OCA_helpdesk" remote="OCA" groups="addons"/> <project name="helpdesk.git" path="addons.odoo16.0/OCA_helpdesk" remote="OCA" groups="addons"/>
<project name="hr.git" path="addons.odoo16.0/OCA_hr" remote="OCA" groups="addons"/> <project name="hr.git" path="addons.odoo16.0/OCA_hr" remote="OCA" groups="addons"/>
<project name="hr-holidays.git" path="addons.odoo16.0/OCA_hr-holidays" remote="OCA" groups="addons"/>
<project name="interface-github.git" path="addons.odoo16.0/OCA_interface-github" remote="OCA" groups="addons"/> <project name="interface-github.git" path="addons.odoo16.0/OCA_interface-github" remote="OCA" groups="addons"/>
<project name="knowledge.git" path="addons.odoo16.0/OCA_knowledge" remote="OCA" groups="addons"/> <project name="knowledge.git" path="addons.odoo16.0/OCA_knowledge" remote="OCA" groups="addons"/>
<project name="l10n-canada.git" path="addons.odoo16.0/OCA_l10n-canada" remote="OCA" groups="addons"/> <project name="l10n-canada.git" path="addons.odoo16.0/OCA_l10n-canada" remote="OCA" groups="addons"/>
@ -114,11 +115,12 @@
<project name="server-env.git" path="addons.odoo16.0/OCA_server-env" remote="OCA" groups="addons"/> <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-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-ux.git" path="addons.odoo16.0/OCA_server-ux" remote="OCA" groups="addons"/>
<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"/>
<project name="survey.git" path="addons.odoo16.0/OCA_survey" remote="ERPLibre" revision="16.0_dev" groups="addons"/> <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="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"/> <project name="storage.git" path="addons.odoo16.0/OCA_storage" remote="OCA" groups="addons"/>
<project name="timesheet.git" path="addons.odoo16.0/OCA_timesheet" remote="OCA" groups="addons"/> <project name="timesheet.git" path="addons.odoo16.0/OCA_timesheet" remote="ERPLibre" revision="16.0-refactor-hr_timesheet_begin_end" groups="addons"/>
<project name="vertical-association.git" path="addons.odoo16.0/OCA_vertical-association" remote="OCA" groups="addons"/> <project name="vertical-association.git" path="addons.odoo16.0/OCA_vertical-association" remote="OCA" groups="addons"/>
<project name="vertical-hotel.git" path="addons.odoo16.0/OCA_vertical-hotel" remote="OCA" groups="addons"/> <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-isp.git" path="addons.odoo16.0/OCA_vertical-isp" remote="OCA" groups="addons"/>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -19,31 +19,32 @@ authors = [ "Mathieu Benoit <mathben@technolibre.ca>",]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8.20" python = "^3.8.20"
acme = "^2.11.0" acme = "2.11.0"
agithub = "^2.2.2" agithub = "^2.2.2"
aiohttp = "^3.10.10" aiohttp = "3.10.10"
aioshutil = "<1.2" aioshutil = "<1.2"
argcomplete = "^3.5.1" anyio = ">=3.5"
argcomplete = "^3.6.1"
astor = "0.8.1" astor = "0.8.1"
avalara = "^24.10.0" avalara = "^25.3.0"
azure-identity = "1.13.0" azure-identity = "1.13.0"
azure-storage-blob = "12.16.0" azure-storage-blob = "12.16.0"
babel = "2.9.1" babel = "2.9.1"
beautifulsoup4 = "^4.12.3" beautifulsoup4 = "^4.13.3"
bokeh = "2.3.1" bokeh = "2.3.1"
boto3 = ">=1.20.41" boto3 = ">=1.20.41"
cachetools = "^5.5.0" cachetools = "^5.5.2"
chardet = "5.0.0" chardet = "5.0.0"
chromedriver-binary = "^132.0.6786.0.0" chromedriver-binary = "^136.0.7088.0.0"
click = "^8.1.7" click = "^8.1.8"
cloudflare = "2.20.0" cloudflare = "2.20.0"
colorama = "^0.4.6" colorama = "^0.4.6"
contextvars = "^2.4" contextvars = "^2.4"
coverage = "7.6.1" coverage = "7.6.1"
cryptography = "39.0.1" cryptography = "39.0.1"
css-html-prettify = "^2.5.5" css-html-prettify = "^2.5.5"
cython = "^3.0.11" cython = "^3.0.12"
dateparser = "^1.2.0" dateparser = "^1.2.1"
ddt = "1.2.1" ddt = "1.2.1"
decorator = "4.3.0" decorator = "4.3.0"
dicttoxml = "^1.7.16" dicttoxml = "^1.7.16"
@ -51,10 +52,10 @@ dnspython = "2.6.1"
docutils = "0.16.0" docutils = "0.16.0"
ebaysdk = "2.1.5" ebaysdk = "2.1.5"
email-validator = "^2.2.0" email-validator = "^2.2.0"
emoji = "^2.14.0" emoji = "^2.14.1"
endesive = "^2.17.3" endesive = "^2.18.5"
extract-msg = "0.36.1" extract-msg = "0.36.1"
factur-x = "^3.1" factur-x = "<=3.1"
fdfgen = "^0.16.1" fdfgen = "^0.16.1"
feedparser = "6.0.10" feedparser = "6.0.10"
flake8 = "<6.0.0" flake8 = "<6.0.0"
@ -65,19 +66,19 @@ geojson = "<3.0.0"
gevent = "20.9.0" gevent = "20.9.0"
gitpython = "3.1.30" gitpython = "3.1.30"
giturlparse = "^0.12.0" giturlparse = "^0.12.0"
google-api-python-client = "^2.149.0" google-api-python-client = "^2.165.0"
google-auth-httplib2 = "^0.2.0" google-auth-httplib2 = "^0.2.0"
google-auth-oauthlib = "^1.2.1" google-auth-oauthlib = "^1.2.1"
greenlet = "0.4.17" greenlet = "0.4.17"
gst = "^0.1.0" gst = "^0.1.4"
html2text = "^2024.2.26" html2text = "^2024.2.26"
idna = "2.6" idna = "2.8"
img2pdf = "^0.5.1" img2pdf = "^0.6.0"
invoice2data = "^0.4.5" invoice2data = "^0.4.5"
iscompatible = "^0.1.1" iscompatible = "^0.1.1"
isort = "<5.12.0" isort = "<5.12.0"
jinja2 = "2.11.3" jinja2 = "2.11.3"
josepy = "^1.14.0" josepy = "1.14.0"
keystoneauth1 = "3.14.0" keystoneauth1 = "3.14.0"
libsass = "0.17.0" libsass = "0.17.0"
lxml = "4.9.1" lxml = "4.9.1"
@ -91,17 +92,18 @@ numpy = "1.21.1"
numpy-financial = "<=1.0.0" numpy-financial = "<=1.0.0"
odoo-test-helper = "^2.1.1" odoo-test-helper = "^2.1.1"
odoorpc = "^0.10.1" odoorpc = "^0.10.1"
ofxparse = "0.19" ofxparse = "0.21"
openai = "^1.68.2"
openpyxl = "^3.1.5" openpyxl = "^3.1.5"
openupgradelib = "^3.7.1" openupgradelib = "^3.9.3"
ovh = "1.1.2" ovh = "1.1.2"
packaging = "21.3" packaging = "21.3"
pandas = "1.3.5" pandas = "1.3.5"
paramiko = "^3.5.0" paramiko = "^3.5.1"
passlib = "1.7.1" passlib = "1.7.1"
pathspec = "0.12.1" pathspec = "0.12.1"
pdf2image = "^1.17.0" pdf2image = "^1.17.0"
phonenumbers = "^8.13.47" phonenumbers = "^9.0.1"
pillow = "9.3.0" pillow = "9.3.0"
plotly = "5.4.0" plotly = "5.4.0"
polib = "1.1.0" polib = "1.1.0"
@ -114,12 +116,13 @@ py3o-formats = "^0.3"
py3o-template = "^0.10.0" py3o-template = "^0.10.0"
pycountry = "^24.6.1" pycountry = "^24.6.1"
pydot = "1.4.1" pydot = "1.4.1"
pyftpdlib = "^2.0.0" pyftpdlib = "^2.0.1"
pygithub = "2.3.0" pygithub = "2.3.0"
pygments = "2.7.4" pygments = "2.7.4"
pygobject = "3.44.1" pygobject = "3.44.1"
pygount = "1.5.1" pygount = "1.5.1"
pyjwt = "2.5.0" pyjwt = "2.5.0"
pylint = "3.1.0"
pyopenssl = "21.0.0" pyopenssl = "21.0.0"
pypdf = ">=3.1.0,<5.0" pypdf = ">=3.1.0,<5.0"
pypdf2 = "1.27.9" pypdf2 = "1.27.9"
@ -130,7 +133,7 @@ pysftp = "^0.2.9"
python-chess = "^1.999" python-chess = "^1.999"
python-dateutil = "2.7.3" python-dateutil = "2.7.3"
python-git = "^2018.2.1" python-git = "^2018.2.1"
python-jose = "^3.3.0" python-jose = "^3.4.0"
python-json-logger = "0.1.5" python-json-logger = "0.1.5"
python-keystoneclient = "3.22.0" python-keystoneclient = "3.22.0"
python-ldap = "3.1.0" python-ldap = "3.1.0"
@ -151,17 +154,17 @@ reportlab = "3.6.5"
requests = "2.28.1" requests = "2.28.1"
retrying = "^1.3.4" retrying = "^1.3.4"
roulier = "^1.1.1" roulier = "^1.1.1"
selenium = "^4.25.0" selenium = "4.25.0"
sentry-sdk = "<=1.9.0" sentry-sdk = "<=1.9.0"
setuptools = "65.5.1" setuptools = "65.5.1"
shapely = "1.8.5" shapely = "1.8.5"
simplejson = "3.16.0" simplejson = "3.16.0"
sphinx = "4.3.2" sphinx = "4.3.2"
sphinx-intl = "^2.2.0" sphinx-intl = "2.2.0"
sphinx-rtd-theme = "1.3.0" sphinx-rtd-theme = "1.3.0"
statsd = "3.2.1" statsd = "3.2.1"
toml = "^0.10.2" toml = "^0.10.2"
tqdm = "^4.66.5" tqdm = "^4.67.1"
unicodecsv = "^0.14.1" unicodecsv = "^0.14.1"
unidecode = "1.0.23" unidecode = "1.0.23"
unidiff = "^0.7.5" unidiff = "^0.7.5"
@ -170,21 +173,21 @@ uvloop = "^0.21.0"
validators = "0.24.0" validators = "0.24.0"
vobject = "0.9.6.1" vobject = "0.9.6.1"
voicent-python = "^1.0" voicent-python = "^1.0"
webcolors = "^24.8.0" webcolors = "24.8.0"
websocket-client = "^1.8.0" websocket-client = "^1.8.0"
werkzeug = "0.16.1" werkzeug = "0.16.1"
wheel = "^0.44.0" wheel = "^0.45.1"
win-unicode-console = "^0.5" win-unicode-console = "^0.5"
xlrd = "1.1.0" xlrd = "1.1.0"
xlsxwriter = "1.1.2" xlsxwriter = "1.1.2"
xlwt = "1.3" xlwt = "1.3"
xmlformatter = "^0.2.6" xmlformatter = "^0.2.8"
xmlrunner = "^1.7.7" xmlrunner = "^1.7.7"
xmlschema = "^3.4.2" xmlschema = "^3.4.5"
xmltodict = "^0.14.2" xmltodict = "^0.14.2"
zeep = "3.2.0" zeep = "3.2.0"
zipp = ">=3.6.0" zipp = ">=3.6.0"
zxcvbn = "^4.4.28" zxcvbn = "^4.5.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
websocket_client = "^1.1.0" websocket_client = "^1.1.0"
@ -195,3 +198,4 @@ rev = "22.3.0"
[tool.poetry.dependencies.pylint-odoo] [tool.poetry.dependencies.pylint-odoo]
git = "https://github.com/oca/pylint-odoo.git" git = "https://github.com/oca/pylint-odoo.git"
rev = "v9.1.3"

View file

@ -20,30 +20,32 @@ authors = [ "Mathieu Benoit <mathben@technolibre.ca>",]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10.14" python = "^3.10.14"
agithub = "^2.2.2" agithub = "^2.2.2"
argcomplete = "^3.5.1" argcomplete = "^3.6.2"
asana = "^5.0.10" asana = "^5.1.0"
asn1crypto = "^1.5.1" asn1crypto = "^1.5.1"
astor = "^0.8.1" astor = "^0.8.1"
avalara = "^24.11.2" avalara = "^25.3.2"
azure-identity = "1.13.0" azure-identity = "1.13.0"
azure-storage-blob = "12.16.0" azure-storage-blob = "12.16.0"
babel = "2.9.1" babel = "2.9.1"
base64io = "^1.0.3" base64io = "^1.0.3"
beautifulsoup4 = "^4.12.3" beautifulsoup4 = "^4.13.3"
bokeh = "3.1.1" bokeh = "3.1.1"
boto3 = "1.26.7" boto3 = "1.26.7"
bs4 = "^0.0.2" bs4 = "^0.0.2"
cachetools = "^5.5.0" cachetools = "^5.5.2"
cairosvg = "^2.7.1" cairosvg = "^2.7.1"
cerberus = "^1.3.7"
chardet = "4.0.0" chardet = "4.0.0"
chromedriver-binary = "^137.0.7118.2.0"
clicksend-client = "^5.0.78" clicksend-client = "^5.0.78"
cloudflare = "^3.1.0" cloudflare = "^4.1.0"
cmake = "^3.31.1" cmake = "^4.0.0"
colorama = "^0.4.6" colorama = "^0.4.6"
countryinfo = "^0.1.2" countryinfo = "^0.1.2"
cryptography = "3.4.8" cryptography = "3.4.8"
cybersource-rest-client-python = "0.0.56" cybersource-rest-client-python = "0.0.56"
cython = "^3.0.11" cython = "^3.0.12"
decorator = "4.4.2" decorator = "4.4.2"
dlib = "^19.24.6" dlib = "^19.24.6"
docutils = "0.16" docutils = "0.16"
@ -51,44 +53,46 @@ dotty-dict = "^1.3.1"
dropbox = "^12.0.2" dropbox = "^12.0.2"
ebaysdk = "2.1.5" ebaysdk = "2.1.5"
email-validator = "^2.2.0" email-validator = "^2.2.0"
endesive = "^2.17.3" endesive = "^2.18.5"
extract-msg = "^0.52.0" extract-msg = "^0.54.0"
ezdxf = "^1.3.4" ezdxf = "^1.4.0"
face-recognition = "^1.3.0" face-recognition = "^1.3.0"
factur-x = "^3.1" factur-x = "^3.6"
filetype = "^1.2.0" filetype = "^1.2.0"
formio-data = "^2.1.0" formio-data = "^2.1.0"
freezegun = "0.3.15" freezegun = "0.3.15"
fsspec = ">=2024.5.0" fsspec = ">=2024.5.0"
gdown = "^5.2.0" gdown = "^5.2.0"
geocoder = "^1.38.1" geocoder = "^1.38.1"
geojson = "^3.1.0" geojson = "^3.2.0"
geopy = "^2.4.1" geopy = "^2.4.1"
gevent = "21.8.0" gevent = "21.12.0"
gitpython = "3.1.30" gitpython = "3.1.30"
giturlparse = "^0.12.0" giturlparse = "^0.12.0"
googletrans-py = "4.0.0" googletrans-py = "4.0.0"
greenlet = "1.1.2" greenlet = "1.1.2"
gst = "^0.1.2" gst = "^0.1.4"
httpagentparser = "1.8.1" httpagentparser = "1.8.1"
hubspot-api-client = "10.0.0" hubspot-api-client = "10.0.0"
idna = "2.10" idna = "2.10"
iscompatible = "^0.1.1" iscompatible = "^0.1.1"
isort = "^6.0.1"
jinja2 = "2.11.3" jinja2 = "2.11.3"
keystoneauth1 = "5.0.0" keystoneauth1 = "5.0.0"
libsass = "0.20.1" libsass = "0.20.1"
linkedin = "^0.1.5" linkedin = "^0.1.5"
lottie = "^0.7.1" lottie = "^0.7.1"
lxml = "4.6.5" lxml = "4.6.5"
lxml-html-clean = "^0.4.1" lxml-html-clean = "^0.4.2"
mako = "^1.3.6" mako = "^1.3.9"
markupsafe = "1.1.1" markupsafe = "1.1.1"
matplotlib = "^3.9.2" matplotlib = "^3.10.1"
mechanize = "^0.4.10" mechanize = "^0.4.10"
messagebird = "^2.2.0" messagebird = "^2.2.0"
mock = "^5.1.0" meteostat = "^1.6.8"
mock = "^5.2.0"
mpld3 = "0.5.9" mpld3 = "0.5.9"
mysqlclient = "^2.2.6" mysqlclient = "^2.2.7"
nextcloud-api-wrapper = "^0.2.3" nextcloud-api-wrapper = "^0.2.3"
num2words = "0.5.13" num2words = "0.5.13"
numpy = ">=1.15" numpy = ">=1.15"
@ -98,21 +102,22 @@ odoo-test-helper = "^2.1.1"
odoorpc = "^0.10.1" odoorpc = "^0.10.1"
ofxparse = "0.21" ofxparse = "0.21"
ofxtools = "^0.9.5" ofxtools = "^0.9.5"
openai = "^1.55.2" openai = "^1.72.0"
opencv-python = "^4.10.0.84" opencv-python = "^4.11.0.86"
openpyxl = "^3.1.5" openpyxl = "^3.1.5"
openupgradelib = "^3.9.4"
pandas = ">=0.25.3" pandas = ">=0.25.3"
paramiko = "^3.5.0" paramiko = "^3.5.1"
passlib = "1.7.4" passlib = "1.7.4"
pathspec = "^0.12.1" pathspec = "^0.12.1"
pay-ccavenue = "^1.0.0" pay-ccavenue = "^1.0.0"
pdf2image = "^1.17.0" pdf2image = "^1.17.0"
pdfminer = "^20191125" pdfminer = "^20191125"
phonenumbers = "^8.13.50" phonenumbers = "^9.0.2"
pillow = "9.0.1" pillow = "9.0.1"
plotly = "5.13.1" plotly = "5.13.1"
polib = "1.1.0" polib = "1.1.0"
pre-commit = "^4.0.1" pre-commit = "^4.2.0"
premailer = "^3.10.0" premailer = "^3.10.0"
printnodeapi = "^0.2.0" printnodeapi = "^0.2.0"
prometheus-client = "0.15.0" prometheus-client = "0.15.0"
@ -124,24 +129,26 @@ py3o-formats = "^0.3"
py3o-template = "^0.10.0" py3o-template = "^0.10.0"
pyaudio = "^0.2.14" pyaudio = "^0.2.14"
pycountry = "^24.6.1" pycountry = "^24.6.1"
pydevd-odoo = "^1.2.2"
pydifact = "^0.1.8" pydifact = "^0.1.8"
pydot = "1.4.2" pydot = "1.4.2"
pyfcm = "^2.0.7" pyfcm = "^2.0.8"
pygithub = "^2.5.0" pygithub = "^2.6.1"
pygobject = "3.44.1" pygobject = "3.44.1"
pyjwt = "^2.10.1" pyjwt = "^2.10.1"
pymssql = "<=2.2.5" pykeepass = "^4.1.1.post1"
pymssql = "<=2.2.8"
pyncclient = "^0.7" pyncclient = "^0.7"
pyopenssl = "20.0.1" pyopenssl = "20.0.1"
pypdf2 = "1.26.0" pypdf2 = "1.26.0"
pyrfc6266 = "^1.0.2" pyrfc6266 = "^1.0.2"
pysaml2 = "^7.5.0" pysaml2 = "^7.5.2"
pyserial = "3.5" pyserial = "3.5"
pysftp = "^0.2.9" pysftp = "^0.2.9"
pytesseract = "^0.3.13" pytesseract = "^0.3.13"
python-barcode = "^0.15.1" python-barcode = "^0.15.1"
python-dateutil = "2.8.1" python-dateutil = ">=2.8.2"
python-jose = "^3.3.0" python-jose = "^3.4.0"
python-json-logger = "2.0.4" python-json-logger = "2.0.4"
python-keystoneclient = "5.0.0" python-keystoneclient = "5.0.0"
python-ldap = "3.4.0" python-ldap = "3.4.0"
@ -150,43 +157,44 @@ python-resize-image = "^1.1.20"
python-slugify = "^8.0.4" python-slugify = "^8.0.4"
python-stdnum = "1.16" python-stdnum = "1.16"
python-swiftclient = "4.1.0" python-swiftclient = "4.1.0"
python-telegram-bot = "^21.7" python-telegram-bot = "^22.0"
pytz = "^2024.2" pytz = "^2025.2"
pyusb = "1.0.2" pyusb = "1.0.2"
pyyaml = "6.0" pyyaml = "6.0"
pyzbar = "^0.1.9" pyzbar = "^0.1.9"
pyzk = "^0.9" pyzk = "^0.9"
qrcode = "6.1" qrcode = "6.1"
redis = "4.3.4" redis = "4.3.4"
reportlab = "3.5.59" reportlab = "3.6.5"
requests = "2.30.0" requests = "2.30.0"
requests-toolbelt = "^1.0.0" requests-toolbelt = "^1.0.0"
responses = "^0.25.3" responses = "^0.25.7"
retrying = "^1.3.4" retrying = "^1.3.4"
rl-renderpm = "4.0.3" rl-renderpm = "4.0.3"
roulier = "^1.1.1" roulier = "^1.1.1"
schwifty = "2024.4.0" schwifty = "2024.4.0"
selenium = "^4.27.1" selenium = "^4.31.0"
sentry-sdk = "<=1.9.0" sentry-sdk = "<=1.9.0"
shapely = "^2.0.6" shapely = "^2.1.0"
simplejson = "^3.19.3" simplejson = "^3.20.1"
spacy = "^3.8.2" spacy = "3.8.2"
speechrecognition = "3.10.0" speechrecognition = "3.10.0"
sqlalchemy = "^2.0.36" sqlalchemy = "^2.0.40"
statsd = "4.0.1" statsd = "4.0.1"
telesign = "^2.2.5" telesign = "^2.2.6"
telnyx = "^2.1.3" telnyx = "^2.1.5"
todoist-python = "^8.1.4" todoist-python = "^8.1.4"
toml = "^0.10.2" toml = "^0.10.2"
tweepy = "^4.14.0" tweepy = "^4.15.0"
twilio = "^9.3.7" twilio = "^9.5.2"
unidecode = "^1.3.8" unidecode = "^1.3.8"
unidiff = "^0.7.5" unidiff = "^0.7.5"
urllib3 = "1.26.5" urllib3 = "1.26.5"
uvloop = "^0.21.0" uvloop = "^0.21.0"
validate-email = "^1.3" validate-email = "^1.3"
virtualenv = "20.30.0"
vobject = "0.9.6.1" vobject = "0.9.6.1"
vonage = "^4.0.0" vonage = "^4.4.0"
vonage-verify-v2 = "1.1.4" vonage-verify-v2 = "1.1.4"
werkzeug = "2.0.2" werkzeug = "2.0.2"
wheel = "^0.45.1" wheel = "^0.45.1"
@ -202,7 +210,3 @@ websocket_client = "^1.1.0"
[tool.poetry.dependencies.black] [tool.poetry.dependencies.black]
git = "https://github.com/psf/black.git" git = "https://github.com/psf/black.git"
rev = "24.8.0" rev = "24.8.0"
[tool.poetry.dependencies.openupgradelib]
git = "https://github.com/OCA/openupgradelib"
rev = "master"

View file

@ -35,12 +35,11 @@ python-git
voicent-python voicent-python
python-swiftclient python-swiftclient
python-keystoneclient python-keystoneclient
coverage
# For logical test # For logical test
docutils==0.16.0 docutils==0.16.0
flake8<6.0.0 flake8<6.0.0
git+https://github.com/oca/pylint-odoo.git git+https://github.com/oca/pylint-odoo.git@v9.1.3
# oca-maintainers-tools # oca-maintainers-tools
# git+https://github.com/OCA/maintainer-tools.git#egg=oca-maintainers-tools # git+https://github.com/OCA/maintainer-tools.git#egg=oca-maintainers-tools
xmlformatter xmlformatter
@ -98,7 +97,6 @@ geojson<3.0.0
regex==2022.3.2 regex==2022.3.2
pygount==1.5.1 pygount==1.5.1
pysaml2==7.2.1 pysaml2==7.2.1
gevent==1.5.0
freezegun==0.3.15 freezegun==0.3.15
pyopenssl==21.0.0 pyopenssl==21.0.0
ovh==1.1.2 ovh==1.1.2
@ -106,6 +104,16 @@ sphinx-rtd-theme==1.3.0
sphinx_rtd_theme==1.3.0 sphinx_rtd_theme==1.3.0
dnspython==2.6.1 dnspython==2.6.1
coverage==7.6.1 coverage==7.6.1
webcolors==24.8.0
aiohttp==3.10.10
josepy==1.14.0
acme==2.11.0
sphinx-intl==2.2.0
selenium==4.25.0
anyio>=3.5
openai
idna==2.8
pylint==3.1.0
# asyncio # asyncio
aioshutil<1.2 aioshutil<1.2

View file

@ -17,6 +17,8 @@ selenium
# mmg # depend on weasyprint 59.0 and depend on old version pillow 9.0.1 # mmg # depend on weasyprint 59.0 and depend on old version pillow 9.0.1
uvloop uvloop
python-randomword-fr python-randomword-fr
isort
pykeepass
# For OSX # For OSX
cython cython
@ -51,7 +53,7 @@ pre-commit
# For python 3.10 from odoo/requirements.txt, poetry_update.py cannot support python_version # For python 3.10 from odoo/requirements.txt, poetry_update.py cannot support python_version
cryptography==3.4.8 cryptography==3.4.8
freezegun==0.3.15 freezegun==0.3.15
gevent==21.8.0 gevent==21.12.0
greenlet==1.1.2 greenlet==1.1.2
Jinja2==2.11.3 Jinja2==2.11.3
libsass==0.20.1 libsass==0.20.1
@ -66,7 +68,7 @@ PyPDF2==1.26.0
python-ldap==3.4.0 python-ldap==3.4.0
pyusb==1.0.2 pyusb==1.0.2
requests==2.30.0 requests==2.30.0
reportlab==3.5.59 reportlab==3.6.5
urllib3==1.26.5 urllib3==1.26.5
Werkzeug==2.0.2 Werkzeug==2.0.2
xlrd==1.2.0 xlrd==1.2.0
@ -83,3 +85,18 @@ hubspot-api-client==10.0.0
# Optional Odoo # Optional Odoo
pdfminer pdfminer
# Optional PyDev
pydevd-odoo
# For fixing module ocr_data_retrieval check file ocr_data_retrieval/models/ocr_data_template.py
spacy==3.8.2
# Fix update dateutil from odoo
python-dateutil>=2.8.2
# Extra module
meteostat
# Force upgrade package to fix Ubuntu 25.04
virtualenv==20.30.0

View file

@ -5,4 +5,4 @@ if [ $# -lt 1 ]; then
exit 1 exit 1
fi fi
source ./.venv/bin/activate source ./.venv/bin/activate
python3 ./odoo/odoo-bin -c ./config.conf --limit-time-real 99999 --limit-time-cpu 99999 --stop-after-init -i user_test,disable_mail_server,disable_auto_backup --dev prod -d $@ python3 ./odoo/odoo-bin -c ./config.conf --limit-time-real 99999 --limit-time-cpu 99999 --no-http --stop-after-init -i user_test,disable_mail_server,disable_auto_backup --dev prod -d $@

View file

@ -67,15 +67,15 @@ echo $POETRY_VERSION
if [ "$IS_RELEASE_ALPHA" == true ] if [ "$IS_RELEASE_ALPHA" == true ]
then then
# Add commit hash when release alpha # Add commit hash when release alpha
ERPLIBRE_VERSION="${ERPLIBRE_VERSION}_ALPHA_$(git rev-parse --short HEAD)" ERPLIBRE_VERSION="${ERPLIBRE_VERSION}_ALPHA_odoo_${ODOO_VERSION}_$(git rev-parse --short HEAD)"
elif [ "$IS_RELEASE_BETA" == true ] elif [ "$IS_RELEASE_BETA" == true ]
then then
# Add commit hash when release beta # Add commit hash when release beta
ERPLIBRE_VERSION="${ERPLIBRE_VERSION}_BETA_$(git rev-parse --short HEAD)" ERPLIBRE_VERSION="${ERPLIBRE_VERSION}_BETA_odoo_${ODOO_VERSION}_$(git rev-parse --short HEAD)"
elif [ "$IS_RELEASE" == false ] elif [ "$IS_RELEASE" == false ]
then then
# Add commit hash when not a release # Add commit hash when not a release
ERPLIBRE_VERSION="${ERPLIBRE_VERSION}_$(git rev-parse --short HEAD)" ERPLIBRE_VERSION="${ERPLIBRE_VERSION}_odoo_${ODOO_VERSION}_$(git rev-parse --short HEAD)"
fi fi

View file

@ -29,6 +29,7 @@ if [[ ${EL_MINIMAL_ADDONS} = "False" ]]; then
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/CybroOdoo_CybroAddons," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/CybroOdoo_CybroAddons," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/CybroOdoo_OpenHRMS," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/CybroOdoo_OpenHRMS," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/ERPLibre_erplibre_addons," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/ERPLibre_erplibre_addons," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/MathBenTech_odoo-business-spending-management-quebec-canada," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_account-analytic," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_account-analytic," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_account-budgeting," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_account-budgeting," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_account-closing," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_account-closing," >> "${EL_CONFIG_FILE}"
@ -68,6 +69,7 @@ if [[ ${EL_MINIMAL_ADDONS} = "False" ]]; then
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_geospatial," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_geospatial," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_helpdesk," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_helpdesk," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_hr," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_hr," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_hr-holidays," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_interface-github," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_interface-github," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_knowledge," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_knowledge," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_l10n-canada," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_l10n-canada," >> "${EL_CONFIG_FILE}"
@ -99,6 +101,7 @@ if [[ ${EL_MINIMAL_ADDONS} = "False" ]]; then
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_server-env," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_server-env," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_server-tools," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_server-tools," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_server-ux," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_server-ux," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_shift-planning," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_social," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_social," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_stock-logistics-warehouse," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_stock-logistics-warehouse," >> "${EL_CONFIG_FILE}"
printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_storage," >> "${EL_CONFIG_FILE}" printf "${EL_HOME}/addons.odoo${EL_ODOO_VERSION}/OCA_storage," >> "${EL_CONFIG_FILE}"

View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
install_package() {
local package_name=$1
# Check package is already installed
if pacman -Qs "$package_name" > /dev/null; then
echo "$package_name is already installed."
else
echo "Installation of package $package_name..."
yes|yay -S "$package_name"
fi
}
# Odoo installation
install_package postgis
install_package postgresql
install_package mariadb
install_package libev
install_package wkhtmltopdf
echo "Need password to create symbolic link, create postgres user and install npm :"
sudo ln -fs /usr/lib/libldap.so /usr/lib/libldap_r.so
sudo su - postgres -c "createuser -s ${EL_USER}" 2>/dev/null || true
echo -e "\n---- Update NPM ----"
install_package npm
sudo npm install npm@latest -g
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "npm install npm lastest installation error."
exit 1
fi
sudo npm install -g rtlcss
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "npm install rtlcss installation error."
exit 1
fi
sudo npm install -g less
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "npm install less installation error."
exit 1
fi
echo -e "\n---- Test tool ----"
npm install
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "npm install prettier + plugin-xml installation error."
exit 1
fi
# TODO install nginx
# ERPLibre installation
install_package cmake
install_package parallel
install_package tk

View file

@ -14,7 +14,7 @@ EL_USER=${USER}
UBUNTU_VERSION=$(lsb_release -rs) UBUNTU_VERSION=$(lsb_release -rs)
DEBIAN_VERSION=$(lsb_release -cs) DEBIAN_VERSION=$(lsb_release -cs)
OS=$(lsb_release -si) OS=$(lsb_release -si)
if [ "24.04" == "${UBUNTU_VERSION}" ] || [ "24.10" == "${UBUNTU_VERSION}" ] || [ "23.10" == "${UBUNTU_VERSION}" ] || [ "23.04" == "${UBUNTU_VERSION}" ] || [ "22.10" == "${UBUNTU_VERSION}" ] || [ "22.04" == "${UBUNTU_VERSION}" ]; then if [ "25.04" == "${UBUNTU_VERSION}" ] || [ "24.04" == "${UBUNTU_VERSION}" ] || [ "24.10" == "${UBUNTU_VERSION}" ] || [ "23.10" == "${UBUNTU_VERSION}" ] || [ "23.04" == "${UBUNTU_VERSION}" ] || [ "22.10" == "${UBUNTU_VERSION}" ] || [ "22.04" == "${UBUNTU_VERSION}" ]; then
WKHTMLTOX_X64=https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb WKHTMLTOX_X64=https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb
elif [ "20.04" == "${UBUNTU_VERSION}" ]; then elif [ "20.04" == "${UBUNTU_VERSION}" ]; then
WKHTMLTOX_X64=https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb WKHTMLTOX_X64=https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb

View file

@ -1,20 +1,21 @@
#!/usr/bin/env bash #!/usr/bin/env bash
if [[ "${OSTYPE}" == "linux-gnu" ]]; then if [[ "${OSTYPE}" == "linux-gnu" ]]; then
OS=$(lsb_release -si) source /etc/os-release
VERSION=$(cat /etc/issue) if [[ "${ID}" == "ubuntu" ]]; then
if [[ "${OS}" == *"Ubuntu"* ]]; then if [[ "${VERSION_ID}" == "18.04" || "${VERSION_ID}" == "20.04" || "${VERSION_ID}" == "22.04" || "${VERSION_ID}" == "22.10" || "${VERSION_ID}" == "23.04" || "${VERSION_ID}" == "23.10" || "${VERSION_ID}" == "24.04" || "${VERSION_ID}" == "25.04" ]]; then
if [[ "${VERSION}" == Ubuntu\ 18.04* || "${VERSION}" == Ubuntu\ 20.04* || "${VERSION}" == Ubuntu\ 22.04* || "${VERSION}" == Ubuntu\ 22.10* || "${VERSION}" == Ubuntu\ 23.04* || "${VERSION}" == Ubuntu\ 23.10* || "${VERSION}" == Ubuntu\ 24.04* ]]; then
echo "\n---- linux-gnu installation process started ----" echo "\n---- linux-gnu installation process started ----"
./script/install/install_debian_dependency.sh ./script/install/install_debian_dependency.sh
else else
echo "Your version is not supported, only support 18.04, 20.04 and 22.04 - 24.04 : ${VERSION}" echo "Your version is not supported, only support 18.04, 20.04 and 22.04 - 24.04, 25.04 : ${VERSION_ID}"
fi fi
elif [[ "${OS}" == *"Debian"* ]]; then elif [[ "${ID}" == "debian" ]]; then
./script/install/install_debian_dependency.sh ./script/install/install_debian_dependency.sh
elif [[ "${ID}" == "arch" ]]; then
./script/install/install_arch_linux.sh
else else
./script/install/install_debian_dependency.sh ./script/install/install_debian_dependency.sh
echo "Your Linux system is not supported, only support Ubuntu 18.04 or Ubuntu 20.04 or Ubuntu 22.04 - Ubuntu 23.10 - Ubuntu 24.04 ." echo "Your Linux system is not supported, only support Ubuntu 18.04 or Ubuntu 20.04 or Ubuntu 22.04 - Ubuntu 23.10 - Ubuntu 24.04, Ubuntu 25.04 ."
fi fi
elif [[ "${OSTYPE}" == "darwin"* ]]; then elif [[ "${OSTYPE}" == "darwin"* ]]; then
echo "\n---- Darwin installation process started ----" echo "\n---- Darwin installation process started ----"

View file

@ -105,6 +105,10 @@ def combine_requirements(config):
lst_requirements_file = get_lst_requirements_txt() lst_requirements_file = get_lst_requirements_txt()
# lst_requirements_with_condition = set() # lst_requirements_with_condition = set()
# dct_special_condition = defaultdict(list) # dct_special_condition = defaultdict(list)
if not os.path.isfile(priority_filename_requirement):
_logger.error(f"File {priority_filename_requirement} not found.")
dct_requirements_module_filename = defaultdict(list) dct_requirements_module_filename = defaultdict(list)
for requirements_filename in lst_requirements_file: for requirements_filename in lst_requirements_file:
with open(requirements_filename, "r") as f: with open(requirements_filename, "r") as f:

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Get two last .webm file
videos=($(ls -t *.webm | head -n 2))
if [ ${#videos[@]} -ne 2 ]; then
echo "Error : you need two files .webm in root directory"
exit 1
fi
timestamp=$(date +"%Y%m%d_%H%M%S")
output_name="output_${timestamp}.webm"
video1="${videos[0]}"
video2="${videos[1]}"
echo "first video ${video1}"
echo "second video ${video2}"
# Obtenez les durées des vidéos
duration1=$(ffmpeg -i "$video1" 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | tr -d ,)
duration2=$(ffmpeg -i "$video2" 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | tr -d ,)
echo "duration 1 : ${duration1}"
echo "duration 2 : ${duration2}"
# Convertir les durées en secondes
duration1_sec=$(echo "$duration1" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
duration2_sec=$(echo "$duration2" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
echo "duration 1 sec : ${duration1_sec}"
echo "duration 2 sec : ${duration2_sec}"
# Déterminer la durée la plus courte
min_duration=$(echo "$duration1_sec $duration2_sec" | awk '{print ($1 < $2) ? $1 : $2}')
echo "Min duration : ${min_duration}"
# Créez la sortie
#output_name="output.mp4"
# Utiliser ffmpeg pour couper et empiler les vidéos
#ffmpeg -i "$video1" -i "$video2" -filter_complex "
# [0:v]trim=start=0:end=$min_duration,setpts=PTS-STARTPTS[v0];
# [1:v]trim=start=0:end=$min_duration,setpts=PTS-STARTPTS[v1];
# [v0][v1]hstack=inputs=2" "$output_name"
#echo "Les vidéos ont été combinées en $output_name"
ffmpeg -i "${videos[0]}" -i "${videos[1]}" -filter_complex "hstack=inputs=2" "${output_name}"
# with normalize size video
#ffmpeg -i "${videos[0]}" -i "${videos[1]}" -filter_complex "[0:v]scale=320:240[v0]; [1:v]scale=320:240[v1]; [v0][v1]hstack=inputs=2" "${output_name}"
echo "${output_name}"

View file

@ -2,10 +2,11 @@
# © 2021-2024 TechnoLibre (http://www.technolibre.ca) # © 2021-2024 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import sys
import argparse import argparse
import web_login import sys
import selenium_lib import selenium_lib
import web_login
def run(config, selenium_tool): def run(config, selenium_tool):

View file

@ -2,29 +2,46 @@
# © 2021-2024 TechnoLibre (http://www.technolibre.ca) # © 2021-2024 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from randomwordfr import RandomWordFr import datetime
import re
import os import os
import re
import sys import sys
import time import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.firefox.service import Service
from subprocess import getoutput from subprocess import getoutput
from randomwordfr import RandomWordFr
from selenium import webdriver
from selenium.common.exceptions import (
ElementClickInterceptedException,
TimeoutException,
)
from selenium.webdriver import ActionChains from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions.wheel_input import ScrollOrigin 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.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
class SeleniumLib(object): class SeleniumLib(object):
def __init__(self, config): def __init__(self, config):
self.config = config self.config = config
self.video_recorder = None self.video_recorder = None
self.filename = "video_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm" if self.config.video_suffix:
self.filename = (
f"video_{self.config.video_suffix}_"
+ time.strftime("%Y_%m_%d-%H_%M_%S")
+ ".webm"
)
else:
self.filename = (
"video_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm"
)
self.driver = None self.driver = None
def configure(self): def configure(self, ignore_open_web=False):
# Configuration pour lancer Firefox en mode de navigation privée # Configuration pour lancer Firefox en mode de navigation privée
firefox_options = webdriver.FirefoxOptions() firefox_options = webdriver.FirefoxOptions()
if not self.config.not_private_mode: if not self.config.not_private_mode:
@ -70,6 +87,7 @@ class SeleniumLib(object):
# Ajout de l'enregistrement # Ajout de l'enregistrement
if self.config.record_mode: if self.config.record_mode:
# Create recording
new_path = os.path.normpath( new_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "..", "..") os.path.join(os.path.dirname(__file__), "..", "..")
) )
@ -121,7 +139,8 @@ class SeleniumLib(object):
) )
# Ouvrez la page web # Ouvrez la page web
self.driver.get(f"{self.config.url}/web") if not ignore_open_web:
self.driver.get(f"{self.config.url}/web")
# Close tab opening by DarkReader # Close tab opening by DarkReader
if self.config.not_private_mode and not self.config.no_dark_mode: if self.config.not_private_mode and not self.config.no_dark_mode:
@ -150,6 +169,7 @@ class SeleniumLib(object):
) )
) )
button.click() button.click()
return button
def get_element(self, by: str = By.ID, value: str = None, timeout=5): def get_element(self, by: str = By.ID, value: str = None, timeout=5):
wait = WebDriverWait(self.driver, timeout) wait = WebDriverWait(self.driver, timeout)
@ -164,6 +184,125 @@ class SeleniumLib(object):
return ele[0] return ele[0]
def get_element_not_visible(
self, by: str = By.ID, value: str = None, timeout=5
):
wait = WebDriverWait(self.driver, timeout)
ele = wait.until(
EC.presence_of_element_located(
(
by,
value,
)
)
)
return ele
def get_elements_not_visible(
self, by: str = By.ID, value: str = None, timeout=5
):
wait = WebDriverWait(self.driver, timeout)
ele = wait.until(
EC.presence_of_all_elements_located(
(
by,
value,
)
)
)
return ele
def get_all_element(self, by: str = By.ID, value: str = None, timeout=5):
wait = WebDriverWait(self.driver, timeout)
ele = wait.until(
EC.visibility_of_all_elements_located(
(
by,
value,
)
)
)
return ele
def wait_new_element_and_click(
self,
by: str = By.ID,
value: str = None,
delay_wait=1,
timeout=5,
inject_cursor=False,
):
new_element = self.wait_new_element(
by=by, value=value, delay_wait=delay_wait, timeout=timeout
)
if new_element:
if inject_cursor:
self.inject_cursor()
self.click_with_mouse_move(element=new_element, no_scroll=True)
return new_element
def wait_new_element(
self,
by: str = By.ID,
value: str = None,
delay_wait=1,
timeout=5,
timeout_wait=None,
):
element = None
# TODO support timeout_wait
while element is None:
time.sleep(delay_wait)
try:
element = self.get_element(by, value, timeout)
except TimeoutException as e:
pass
print(f"Waiting {delay_wait} seconds after value '{value}'")
return element
def wait_add_new_element_and_click(
self, by: str = By.ID, value: str = None, delay_wait=1, timeout=5
):
new_element = self.wait_add_new_element(
by=by, value=value, delay_wait=delay_wait, timeout=timeout
)
self.click_with_mouse_move(element=new_element, no_scroll=True)
return new_element
def wait_add_new_element(
self, by: str = By.ID, value: str = None, delay_wait=1, timeout=5
):
all_element_init = self.get_all_element(by=by, value=value)
len_all_element_init = len(all_element_init)
len_all_element = len_all_element_init
all_element = []
while len_all_element_init == len_all_element:
time.sleep(delay_wait)
all_element = self.get_all_element(by=by, value=value)
len_all_element = len(all_element)
print(f"Waiting {delay_wait} seconds after value '{value}'")
new_element = all_element[-1]
return new_element
def wait_increment_number_text_and_click(
self, by: str = By.ID, value: str = None, delay_wait=1, timeout=5
):
element_init = self.get_element(by=by, value=value, timeout=timeout)
actual_number = int(element_init.text)
number_goal = actual_number + 1
while actual_number < number_goal:
time.sleep(delay_wait)
element_goal = self.get_element(
by=by, value=value, timeout=timeout
)
actual_number = int(element_goal.text)
print(f"Waiting {delay_wait} seconds after value '{value}'")
self.click_with_mouse_move(element=element_init, no_scroll=True)
return element_init
def click_with_mouse_move( def click_with_mouse_move(
self, self,
by: str = By.ID, by: str = By.ID,
@ -172,9 +311,15 @@ class SeleniumLib(object):
no_scroll: bool = False, no_scroll: bool = False,
viewport_ele_by: str = By.ID, viewport_ele_by: str = By.ID,
viewport_ele_value: str = None, viewport_ele_value: str = None,
element: WebElement = None,
with_index: bool = False,
index_of_list: int = 0,
): ):
# ele = self.driver.find_element(by, value) # ele = self.driver.find_element(by, value)
ele = self.get_element(by, value, timeout) if element:
ele = element
else:
ele = self.get_element(by, value, timeout)
if not no_scroll: if not no_scroll:
viewport_ele = None viewport_ele = None
if viewport_ele_value: if viewport_ele_value:
@ -182,18 +327,67 @@ class SeleniumLib(object):
viewport_ele_by, viewport_ele_value, timeout viewport_ele_by, viewport_ele_value, timeout
) )
self.scrollto_element(ele, viewport_ele=viewport_ele) self.scrollto_element(ele, viewport_ele=viewport_ele)
# ActionChains(self.driver).move_to_element(ele).click().perform()
ActionChains(self.driver).move_to_element(ele).perform() ActionChains(self.driver).move_to_element(ele).perform()
time.sleep(self.config.selenium_default_delay) time.sleep(self.config.selenium_default_delay)
wait = WebDriverWait(self.driver, timeout) wait = WebDriverWait(self.driver, timeout)
button = wait.until( if element:
EC.element_to_be_clickable( button = wait.until(EC.element_to_be_clickable(element))
( else:
by, if with_index:
value, buttons = wait.until(
EC.presence_of_all_elements_located(
(
by,
value,
)
)
) )
) button = buttons[index_of_list]
) else:
button.click() button = wait.until(
EC.element_to_be_clickable(
(
by,
value,
)
)
)
try:
button.click()
except ElementClickInterceptedException as e:
try:
print(e)
self.driver.execute_script(
"arguments[0].scrollIntoView(true);", button
)
button.click()
except ElementClickInterceptedException as e:
print(e)
self.driver.execute_script("arguments[0].click();", button)
return button
def click_canvas_form(
self,
by: str = By.ID,
value: str = None,
timeout: int = 5,
form="carre",
):
# ele = self.driver.find_element(by, value)
ele = self.get_element(by, value, timeout)
actions = ActionChains(self.driver)
actions.move_to_element_with_offset(ele, -50, -50)
actions.click_and_hold()
if form == "carre":
actions.move_by_offset(50, 0)
actions.move_by_offset(0, 50)
actions.move_by_offset(-50, 0)
actions.move_by_offset(0, -50)
actions.release()
actions.perform()
def input_text_with_mouse_move( def input_text_with_mouse_move(
self, self,
@ -216,6 +410,8 @@ class SeleniumLib(object):
) )
self.scrollto_element(ele, viewport_ele=viewport_ele) self.scrollto_element(ele, viewport_ele=viewport_ele)
ActionChains(self.driver).move_to_element(ele).perform() ActionChains(self.driver).move_to_element(ele).perform()
# Write content
ele.send_keys(text_value) ele.send_keys(text_value)
if delay_after > 0: if delay_after > 0:
time.sleep(delay_after) time.sleep(delay_after)
@ -346,7 +542,50 @@ class SeleniumLib(object):
cursor.style.top = e.pageY - 5 + 'px'; cursor.style.top = e.pageY - 5 + 'px';
}); });
""" """
self.driver.execute_script(cursor_script) try:
try:
self.driver.execute_script(cursor_script)
except Exception as e:
time.sleep(1)
print("Error execute script cursor, wait 1 second")
self.driver.execute_script(cursor_script)
except Exception as e:
time.sleep(3)
print("Error execute script cursor, wait 3 second")
self.driver.execute_script(cursor_script)
def scenario_create_new_account_with_random_user(
self, show_cursor=False, def_action_before_submit=None
):
# Click no account
if show_cursor:
self.inject_cursor()
self.click_with_mouse_move(
By.XPATH, "/html/body/div[1]/main/div/form/div[3]/div[1]/a[1]"
)
# Trouvez les éléments du formulaire
if show_cursor:
self.inject_cursor()
# Remplissez le courriel et le mot de passe
first_name = self.get_french_word_no_space_no_accent()
password = first_name.lower()
second_name = self.get_french_word_no_space_no_accent()
full_name = f"{first_name} {second_name}"
domain = self.get_french_word_no_space_no_accent().lower()
self.input_text_with_mouse_move(
By.NAME, "login", f"{password}@{domain}.com"
)
self.input_text_with_mouse_move(By.NAME, "name", full_name)
self.input_text_with_mouse_move(By.NAME, "password", password)
self.input_text_with_mouse_move(By.NAME, "confirm_password", password)
if def_action_before_submit:
def_action_before_submit()
self.click_with_mouse_move(
By.XPATH, "/html/body/div[1]/main/div/form/div[6]/button"
)
def open_tab(self, url): def open_tab(self, url):
# Open a new window # Open a new window
@ -364,9 +603,157 @@ class SeleniumLib(object):
except Exception: except Exception:
print("Chatbot cannot be found, stop searching it.") print("Chatbot cannot be found, stop searching it.")
# Website
def odoo_website_menu_click(self, from_text=""):
if not from_text:
raise Exception(
"Cannot click, empty parameter from method"
" odoo_website_menu_click"
)
button = self.click_with_mouse_move(
By.LINK_TEXT, from_text, timeout=30
)
return button
# Web
def odoo_fill_widget_char(self, field_name, text):
# Type input
text_field = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.NAME, field_name))
)
text_field.send_keys(text)
return text_field
def odoo_web_click_principal_menu(self):
# Click menu button
button = self.click_with_mouse_move(
By.CSS_SELECTOR, "a.full[data-toggle='dropdown']", timeout=30
)
return button
def odoo_web_principal_menu_click_root_menu(self, from_text=""):
if not from_text:
raise Exception(
"Cannot click, empty parameter from method"
" odoo_web_principal_menu_click_root_menu"
)
button = self.click_with_mouse_move(
By.LINK_TEXT, from_text, timeout=30
)
# If not work, force it
# selenium_tool.driver.execute_script("arguments[0].click();", button)
return button
def odoo_web_action_button_new(self):
# From web view kanban, list
return self.click_with_mouse_move(
By.CLASS_NAME, "o-kanban-button-new", timeout=30
)
def odoo_web_kanban_click(self, button_text, btn_class="btn-primary"):
# From web view kanban, list
return self.click_with_mouse_move(
By.XPATH,
f"//button[contains(@class, 'btn {btn_class} o_kanban_edit') and"
f" text()='{button_text}']",
timeout=30,
)
def odoo_web_form_notebook_tab_click(self, tab_text):
return self.click_with_mouse_move(
By.XPATH,
f"//a[text()='{tab_text}']",
timeout=30,
)
def odoo_fill_widget_selection(self, field_name, text):
return self.odoo_fill_widget_many2one(field_name, text)
def odoo_fill_widget_boolean(self, field_name, value):
self.driver.implicitly_wait(10)
checkbox_div = self.driver.find_element(
By.XPATH, f"//div[@name='{field_name}']"
)
checkbox = checkbox_div.find_element(
By.CSS_SELECTOR, 'input[type="checkbox"]'
)
is_selected = checkbox.get_attribute("selected")
# Check if already set
if is_selected == "true" and value:
return checkbox
elif is_selected is None and not value:
return checkbox
parent_element = checkbox.find_element(By.XPATH, "..")
parent_element.click()
return checkbox
def odoo_fill_widget_many2one(self, field_name, text):
# TODO read this file odoo/addons/web/static/src/js/fields/field_registry.js
div_field = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.NAME, field_name))
)
input_field = div_field.find_element(By.XPATH, ".//input")
input_field.send_keys(text)
# TODO improve speed by observation of comportement
time.sleep(0.5)
input_field.send_keys(Keys.ENTER)
return input_field
def odoo_fill_widget_date(self, field_name, date_to_select):
# Type date
self.driver.implicitly_wait(10)
checkbox_div = self.driver.find_element(
By.XPATH, f"//div[@name='{field_name}']"
)
checkbox_div.click()
# TODO improve speed by observation of comportement
time.sleep(0.5)
checkbox_date_div = self.driver.find_element(
By.CSS_SELECTOR, ".bootstrap-datetimepicker-widget"
)
# time.sleep(0.5)
str_date_today = date_to_select.strftime("%Y-%m-%d")
new_value = checkbox_date_div.find_element(
By.XPATH, f"//td[@data-day='{str_date_today}']"
)
new_value.click()
return new_value
def start_record(self): def start_record(self):
# Démarrer l'enregistrement # Démarrer l'enregistrement
if self.config.record_mode: if self.config.record_mode:
if self.config.record_wait_before_start_time:
time.sleep(int(self.config.record_wait_before_start_time))
# Sync before record
has_sync_error = False
if self.config.sync_file_record_read:
if not self.config.sync_file_record_write:
print(
"Error, cannot sync, missing 'sync_file_record_write'"
)
has_sync_error = True
if self.config.sync_file_record_write:
if not self.config.sync_file_record_read:
print(
"Error, cannot sync, missing 'sync_file_record_read'"
)
has_sync_error = True
if (
not has_sync_error
and self.config.sync_file_record_read
and self.config.sync_file_record_write
):
# Do sync
file_name_1 = f"/tmp/erplibre_sync_temp_file{self.config.sync_file_record_write}"
file_name_2 = f"/tmp/erplibre_sync_temp_file{self.config.sync_file_record_read}"
with open(file_name_1, "w") as file:
file.write(f"Recording {self.filename}\n")
while not os.path.exists(file_name_2):
var_wait_time = 0.001
print(f"File {self.filename} wait {var_wait_time} seconds")
time.sleep(var_wait_time)
self.video_recorder.start() self.video_recorder.start()
def stop_record(self): def stop_record(self):
@ -377,6 +764,7 @@ class SeleniumLib(object):
time.sleep(self.config.selenium_video_time_waiting_end) time.sleep(self.config.selenium_video_time_waiting_end)
self.video_recorder.stop() self.video_recorder.stop()
print("End of recording video") print("End of recording video")
print(self.filename)
if self.config.selenium_video_auto_play_video: if self.config.selenium_video_auto_play_video:
print(f"Play video {self.filename}") print(f"Play video {self.filename}")
@ -402,7 +790,7 @@ def fill_parser(parser):
"--selenium_default_delay", "--selenium_default_delay",
default=0.4, default=0.4,
type=float, type=float,
help="Pause at the end before close video.", help="Pause at the end of an action.",
) )
group_browser = parser.add_argument_group(title="Browser") group_browser = parser.add_argument_group(title="Browser")
@ -434,6 +822,31 @@ def fill_parser(parser):
action="store_true", action="store_true",
help="Start recording (not finish to be implemented).", help="Start recording (not finish to be implemented).",
) )
group_record.add_argument(
"--record_wait_before_start_time",
help="Time to wait in second before start recording.",
)
parser.add_argument(
"--video_suffix",
default="",
help="Will modify video name.",
)
parser.add_argument(
"--sync_file_record_read",
default="",
help=(
"Will sync and check file from tmp before record, write before"
" read."
),
)
parser.add_argument(
"--sync_file_record_write",
default="",
help=(
"Will sync and check file from tmp before record, write before"
" read."
),
)
group_record.add_argument( group_record.add_argument(
"--selenium_video_time_waiting_end", "--selenium_video_time_waiting_end",
default=5, default=5,

View file

@ -26,7 +26,7 @@ class VideoRecorder(object):
self, self,
driver, driver,
filename="video.webm", filename="video.webm",
framerate="25/1", framerate="33/1",
width=None, width=None,
height=None, height=None,
): ):

View file

@ -8,7 +8,6 @@ import sys
import time import time
import selenium_lib import selenium_lib
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
@ -35,18 +34,24 @@ def run(config, selenium_tool):
# Trouvez les éléments du formulaire # Trouvez les éléments du formulaire
courriel_input = selenium_tool.driver.find_element(By.NAME, "login") courriel_input = selenium_tool.driver.find_element(By.NAME, "login")
mot_de_passe_input = selenium_tool.driver.find_element(By.NAME, "password") mot_de_passe_input = selenium_tool.driver.find_element(By.NAME, "password")
try: div_connexion_button = selenium_tool.driver.find_element(
connexion_button = selenium_tool.driver.find_element( By.CLASS_NAME, "oe_login_buttons"
By.XPATH, )
"/html/body/div/div/div/form/div[3]/button", connexion_button = div_connexion_button.find_element(
# '//button[contains(text(), "Log in")]' By.CLASS_NAME, "btn-primary"
) )
except Exception: # try:
connexion_button = selenium_tool.driver.find_element( # connexion_button = selenium_tool.driver.find_element(
By.XPATH, # By.XPATH,
"/html/body/div/main/div/form/div[3]/button", # "/html/body/div/div/div/form/div[3]/button",
# '//button[contains(text(), "Connexion")]' # # '//button[contains(text(), "Log in")]'
) # )
# except Exception:
# connexion_button = selenium_tool.driver.find_element(
# By.XPATH,
# "/html/body/div/main/div/form/div[3]/button",
# # '//button[contains(text(), "Connexion")]'
# )
# Remplissez le courriel et le mot de passe # Remplissez le courriel et le mot de passe
courriel_input.send_keys(config.default_email_auth) courriel_input.send_keys(config.default_email_auth)
@ -105,6 +110,7 @@ def run(config, selenium_tool):
if config.open_dashboard: if config.open_dashboard:
selenium_tool.click( selenium_tool.click(
"/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[3]/a", "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[3]/a",
timeout=15,
) )
# Open conversation chat # Open conversation chat

View file

@ -4,13 +4,13 @@
# This script need only basic importation # This script need only basic importation
import argparse import argparse
import logging
import json import json
import logging
import os import os
import shutil import shutil
import subprocess
import sys import sys
import time import time
import subprocess
logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO")) logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
@ -100,6 +100,11 @@ def get_config():
action="store_true", action="store_true",
help="Install developer environment.", help="Install developer environment.",
) )
parser.add_argument(
"--partial_install",
action="store_true",
help="Preparation environment file, without installation. Docker need this",
)
parser.add_argument( parser.add_argument(
"--force_install", "--force_install",
action="store_true", action="store_true",
@ -457,7 +462,15 @@ class Update:
# Force create addons link # Force create addons link
if os.path.isdir(ADDONS_PATH): if os.path.isdir(ADDONS_PATH):
os.remove(ADDONS_PATH) if os.path.islink(ADDONS_PATH):
os.remove(ADDONS_PATH)
else:
os.rename(
ADDONS_PATH,
ADDONS_PATH
+ "_"
+ time.strftime('%Yy%mm%dd-%Hh%Mm%Ss'),
)
os.symlink(addons_path_with_version, ADDONS_PATH) os.symlink(addons_path_with_version, ADDONS_PATH)
return status return status
@ -688,13 +701,14 @@ def main():
_logger.info("Validate environment") _logger.info("Validate environment")
status = 0 status = 0
if update.config.install_dev or update.config.is_in_switch: if update.config.install_dev or update.config.partial_install or update.config.is_in_switch:
status = update.validate_environment() status = update.validate_environment()
if update.config.install: if update.config.install:
status = update.install_system() status = update.install_system()
if ( if (
update.config.force_install update.config.force_install
or update.config.install_dev or update.config.install_dev
or update.config.partial_install
or update.config.is_in_switch or update.config.is_in_switch
) and not status: ) and not status:
update.update_environment() update.update_environment()

View file

@ -14,7 +14,7 @@ if [ ! -f "${CONFIG_PATH}" ]; then
fi fi
fi fi
coverage run -p ./odoo/odoo-bin -c "${CONFIG_PATH}" --limit-time-real 99999 --limit-time-cpu 99999 --log-level=test --test-enable --stop-after-init "$@" coverage run -p ./odoo/odoo-bin -c "${CONFIG_PATH}" --limit-time-real 99999 --limit-time-cpu 99999 --log-level=test --test-enable --no-http --stop-after-init "$@"
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "${Red}Error${Color_Off} run.sh" echo "${Red}Error${Color_Off} run.sh"