diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f951ba8..07ee644 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -44,30 +44,31 @@ test_all_modules:
--db_password flectra
--database test_all
--test-enable
- --init base_cancel_confirm,base_technical_features,base_menu_visibility_restriction,mass_editing,base_optional_quick_create,filter_multi_user,barcode_action,base_tier_validation_server_action,base_tier_validation,document_quick_access,base_export_manager,sequence_check_digit,base_tier_validation_formula,sequence_reset_period,base_search_custom_field_filter,date_range,base_tier_validation_forward,default_multi_user,base_revision,multi_step_wizard,base_import_security_group
+ --init base_cancel_confirm,filter_multi_user,default_multi_user,sequence_reset_period,sequence_check_digit,base_import_security_group,date_range,base_tier_validation_forward,base_menu_visibility_restriction,barcode_action,multi_step_wizard,base_technical_features,base_tier_validation_formula,base_tier_validation,base_search_custom_field_filter,base_revision,base_export_manager,document_quick_access,mass_editing,base_tier_validation_server_action,chained_swapper,base_optional_quick_create
--stop-after-init
--log-level error
--log-handler flectra.addons.base_cancel_confirm:TEST
- --log-handler flectra.addons.base_technical_features:TEST
- --log-handler flectra.addons.base_menu_visibility_restriction:TEST
- --log-handler flectra.addons.mass_editing:TEST
- --log-handler flectra.addons.base_optional_quick_create:TEST
--log-handler flectra.addons.filter_multi_user:TEST
- --log-handler flectra.addons.barcode_action:TEST
- --log-handler flectra.addons.base_tier_validation_server_action:TEST
- --log-handler flectra.addons.base_tier_validation:TEST
- --log-handler flectra.addons.document_quick_access:TEST
- --log-handler flectra.addons.base_export_manager:TEST
- --log-handler flectra.addons.sequence_check_digit:TEST
- --log-handler flectra.addons.base_tier_validation_formula:TEST
+ --log-handler flectra.addons.default_multi_user:TEST
--log-handler flectra.addons.sequence_reset_period:TEST
- --log-handler flectra.addons.base_search_custom_field_filter:TEST
+ --log-handler flectra.addons.sequence_check_digit:TEST
+ --log-handler flectra.addons.base_import_security_group:TEST
--log-handler flectra.addons.date_range:TEST
--log-handler flectra.addons.base_tier_validation_forward:TEST
- --log-handler flectra.addons.default_multi_user:TEST
- --log-handler flectra.addons.base_revision:TEST
+ --log-handler flectra.addons.base_menu_visibility_restriction:TEST
+ --log-handler flectra.addons.barcode_action:TEST
--log-handler flectra.addons.multi_step_wizard:TEST
- --log-handler flectra.addons.base_import_security_group:TEST
+ --log-handler flectra.addons.base_technical_features:TEST
+ --log-handler flectra.addons.base_tier_validation_formula:TEST
+ --log-handler flectra.addons.base_tier_validation:TEST
+ --log-handler flectra.addons.base_search_custom_field_filter:TEST
+ --log-handler flectra.addons.base_revision:TEST
+ --log-handler flectra.addons.base_export_manager:TEST
+ --log-handler flectra.addons.document_quick_access:TEST
+ --log-handler flectra.addons.mass_editing:TEST
+ --log-handler flectra.addons.base_tier_validation_server_action:TEST
+ --log-handler flectra.addons.chained_swapper:TEST
+ --log-handler flectra.addons.base_optional_quick_create:TEST
"
@@ -104,138 +105,6 @@ test_module_base_cancel_confirm:
--log-level error
--log-handler flectra.addons.base_cancel_confirm:TEST"
-test_module_base_technical_features:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_technical_features
- - psql -h psql -U flectra -d test_base_technical_features -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_technical_features
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_technical_features
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_technical_features
- --test-enable -i base_technical_features
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_technical_features:TEST"
-
-test_module_base_menu_visibility_restriction:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_menu_visibility_restriction
- - psql -h psql -U flectra -d test_base_menu_visibility_restriction -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_menu_visibility_restriction
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_menu_visibility_restriction
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_menu_visibility_restriction
- --test-enable -i base_menu_visibility_restriction
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_menu_visibility_restriction:TEST"
-
-test_module_mass_editing:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_mass_editing
- - psql -h psql -U flectra -d test_mass_editing -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_mass_editing
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_mass_editing
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_mass_editing
- --test-enable -i mass_editing
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.mass_editing:TEST"
-
-test_module_base_optional_quick_create:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_optional_quick_create
- - psql -h psql -U flectra -d test_base_optional_quick_create -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_optional_quick_create
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_optional_quick_create
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_optional_quick_create
- --test-enable -i base_optional_quick_create
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_optional_quick_create:TEST"
-
test_module_filter_multi_user:
stage: testsingle
when: on_failure
@@ -269,7 +138,7 @@ test_module_filter_multi_user:
--log-level error
--log-handler flectra.addons.filter_multi_user:TEST"
-test_module_barcode_action:
+test_module_default_multi_user:
stage: testsingle
when: on_failure
image:
@@ -285,220 +154,22 @@ test_module_barcode_action:
- wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_barcode_action
- - psql -h psql -U flectra -d test_barcode_action -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - createdb -h psql -U flectra -O flectra -T template1 test_default_multi_user
+ - psql -h psql -U flectra -d test_default_multi_user -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_barcode_action
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_barcode_action
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_default_multi_user
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_default_multi_user
- su - flectra -c "/opt/flectra/flectra-bin
--addons-path ${CI_PROJECT_DIR}
--db_host psql
--db_port 5432
--db_user flectra
--db_password flectra
- --database test_barcode_action
- --test-enable -i barcode_action
+ --database test_default_multi_user
+ --test-enable -i default_multi_user
--stop-after-init
--log-level error
- --log-handler flectra.addons.barcode_action:TEST"
-
-test_module_base_tier_validation_server_action:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_tier_validation_server_action
- - psql -h psql -U flectra -d test_base_tier_validation_server_action -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_tier_validation_server_action
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_tier_validation_server_action
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_tier_validation_server_action
- --test-enable -i base_tier_validation_server_action
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_tier_validation_server_action:TEST"
-
-test_module_base_tier_validation:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_tier_validation
- - psql -h psql -U flectra -d test_base_tier_validation -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_tier_validation
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_tier_validation
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_tier_validation
- --test-enable -i base_tier_validation
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_tier_validation:TEST"
-
-test_module_document_quick_access:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_document_quick_access
- - psql -h psql -U flectra -d test_document_quick_access -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_document_quick_access
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_document_quick_access
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_document_quick_access
- --test-enable -i document_quick_access
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.document_quick_access:TEST"
-
-test_module_base_export_manager:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_export_manager
- - psql -h psql -U flectra -d test_base_export_manager -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_export_manager
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_export_manager
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_export_manager
- --test-enable -i base_export_manager
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_export_manager:TEST"
-
-test_module_sequence_check_digit:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_sequence_check_digit
- - psql -h psql -U flectra -d test_sequence_check_digit -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_sequence_check_digit
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_sequence_check_digit
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_sequence_check_digit
- --test-enable -i sequence_check_digit
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.sequence_check_digit:TEST"
-
-test_module_base_tier_validation_formula:
- stage: testsingle
- when: on_failure
- image:
- name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
- entrypoint: ["/bin/sh", "-c"]
- script:
- - apt-get install -y p7zip-full
- - apt install -y expect-dev
- - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
- - su - flectra -c "mkdir ~/others"
- - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
- - mkdir ${CI_PROJECT_DIR}/ci_data
- - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- - export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_tier_validation_formula
- - psql -h psql -U flectra -d test_base_tier_validation_formula -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- - su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_tier_validation_formula
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_tier_validation_formula
- - su - flectra -c "/opt/flectra/flectra-bin
- --addons-path ${CI_PROJECT_DIR}
- --db_host psql
- --db_port 5432
- --db_user flectra
- --db_password flectra
- --database test_base_tier_validation_formula
- --test-enable -i base_tier_validation_formula
- --stop-after-init
- --log-level error
- --log-handler flectra.addons.base_tier_validation_formula:TEST"
+ --log-handler flectra.addons.default_multi_user:TEST"
test_module_sequence_reset_period:
stage: testsingle
@@ -533,7 +204,7 @@ test_module_sequence_reset_period:
--log-level error
--log-handler flectra.addons.sequence_reset_period:TEST"
-test_module_base_search_custom_field_filter:
+test_module_sequence_check_digit:
stage: testsingle
when: on_failure
image:
@@ -549,22 +220,55 @@ test_module_base_search_custom_field_filter:
- wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_search_custom_field_filter
- - psql -h psql -U flectra -d test_base_search_custom_field_filter -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - createdb -h psql -U flectra -O flectra -T template1 test_sequence_check_digit
+ - psql -h psql -U flectra -d test_sequence_check_digit -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_search_custom_field_filter
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_search_custom_field_filter
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_sequence_check_digit
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_sequence_check_digit
- su - flectra -c "/opt/flectra/flectra-bin
--addons-path ${CI_PROJECT_DIR}
--db_host psql
--db_port 5432
--db_user flectra
--db_password flectra
- --database test_base_search_custom_field_filter
- --test-enable -i base_search_custom_field_filter
+ --database test_sequence_check_digit
+ --test-enable -i sequence_check_digit
--stop-after-init
--log-level error
- --log-handler flectra.addons.base_search_custom_field_filter:TEST"
+ --log-handler flectra.addons.sequence_check_digit:TEST"
+
+test_module_base_import_security_group:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_import_security_group
+ - psql -h psql -U flectra -d test_base_import_security_group -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_import_security_group
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_import_security_group
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_import_security_group
+ --test-enable -i base_import_security_group
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_import_security_group:TEST"
test_module_date_range:
stage: testsingle
@@ -632,7 +336,7 @@ test_module_base_tier_validation_forward:
--log-level error
--log-handler flectra.addons.base_tier_validation_forward:TEST"
-test_module_default_multi_user:
+test_module_base_menu_visibility_restriction:
stage: testsingle
when: on_failure
image:
@@ -648,24 +352,24 @@ test_module_default_multi_user:
- wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_default_multi_user
- - psql -h psql -U flectra -d test_default_multi_user -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_menu_visibility_restriction
+ - psql -h psql -U flectra -d test_base_menu_visibility_restriction -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_default_multi_user
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_default_multi_user
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_menu_visibility_restriction
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_menu_visibility_restriction
- su - flectra -c "/opt/flectra/flectra-bin
--addons-path ${CI_PROJECT_DIR}
--db_host psql
--db_port 5432
--db_user flectra
--db_password flectra
- --database test_default_multi_user
- --test-enable -i default_multi_user
+ --database test_base_menu_visibility_restriction
+ --test-enable -i base_menu_visibility_restriction
--stop-after-init
--log-level error
- --log-handler flectra.addons.default_multi_user:TEST"
+ --log-handler flectra.addons.base_menu_visibility_restriction:TEST"
-test_module_base_revision:
+test_module_barcode_action:
stage: testsingle
when: on_failure
image:
@@ -681,22 +385,22 @@ test_module_base_revision:
- wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_revision
- - psql -h psql -U flectra -d test_base_revision -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - createdb -h psql -U flectra -O flectra -T template1 test_barcode_action
+ - psql -h psql -U flectra -d test_barcode_action -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_revision
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_revision
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_barcode_action
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_barcode_action
- su - flectra -c "/opt/flectra/flectra-bin
--addons-path ${CI_PROJECT_DIR}
--db_host psql
--db_port 5432
--db_user flectra
--db_password flectra
- --database test_base_revision
- --test-enable -i base_revision
+ --database test_barcode_action
+ --test-enable -i barcode_action
--stop-after-init
--log-level error
- --log-handler flectra.addons.base_revision:TEST"
+ --log-handler flectra.addons.barcode_action:TEST"
test_module_multi_step_wizard:
stage: testsingle
@@ -731,7 +435,7 @@ test_module_multi_step_wizard:
--log-level error
--log-handler flectra.addons.multi_step_wizard:TEST"
-test_module_base_import_security_group:
+test_module_base_technical_features:
stage: testsingle
when: on_failure
image:
@@ -747,20 +451,350 @@ test_module_base_import_security_group:
- wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
- 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
- export PGPASSWORD="flectra"
- - createdb -h psql -U flectra -O flectra -T template1 test_base_import_security_group
- - psql -h psql -U flectra -d test_base_import_security_group -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_technical_features
+ - psql -h psql -U flectra -d test_base_technical_features -f ${CI_PROJECT_DIR}/ci_data/dump.sql
- su - flectra -c "mkdir -p ~/.local/share/filestore"
- - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_import_security_group
- - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_import_security_group
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_technical_features
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_technical_features
- su - flectra -c "/opt/flectra/flectra-bin
--addons-path ${CI_PROJECT_DIR}
--db_host psql
--db_port 5432
--db_user flectra
--db_password flectra
- --database test_base_import_security_group
- --test-enable -i base_import_security_group
+ --database test_base_technical_features
+ --test-enable -i base_technical_features
--stop-after-init
--log-level error
- --log-handler flectra.addons.base_import_security_group:TEST"
+ --log-handler flectra.addons.base_technical_features:TEST"
+
+test_module_base_tier_validation_formula:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_tier_validation_formula
+ - psql -h psql -U flectra -d test_base_tier_validation_formula -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_tier_validation_formula
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_tier_validation_formula
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_tier_validation_formula
+ --test-enable -i base_tier_validation_formula
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_tier_validation_formula:TEST"
+
+test_module_base_tier_validation:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_tier_validation
+ - psql -h psql -U flectra -d test_base_tier_validation -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_tier_validation
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_tier_validation
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_tier_validation
+ --test-enable -i base_tier_validation
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_tier_validation:TEST"
+
+test_module_base_search_custom_field_filter:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_search_custom_field_filter
+ - psql -h psql -U flectra -d test_base_search_custom_field_filter -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_search_custom_field_filter
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_search_custom_field_filter
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_search_custom_field_filter
+ --test-enable -i base_search_custom_field_filter
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_search_custom_field_filter:TEST"
+
+test_module_base_revision:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_revision
+ - psql -h psql -U flectra -d test_base_revision -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_revision
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_revision
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_revision
+ --test-enable -i base_revision
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_revision:TEST"
+
+test_module_base_export_manager:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_export_manager
+ - psql -h psql -U flectra -d test_base_export_manager -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_export_manager
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_export_manager
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_export_manager
+ --test-enable -i base_export_manager
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_export_manager:TEST"
+
+test_module_document_quick_access:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_document_quick_access
+ - psql -h psql -U flectra -d test_document_quick_access -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_document_quick_access
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_document_quick_access
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_document_quick_access
+ --test-enable -i document_quick_access
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.document_quick_access:TEST"
+
+test_module_mass_editing:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_mass_editing
+ - psql -h psql -U flectra -d test_mass_editing -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_mass_editing
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_mass_editing
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_mass_editing
+ --test-enable -i mass_editing
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.mass_editing:TEST"
+
+test_module_base_tier_validation_server_action:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_tier_validation_server_action
+ - psql -h psql -U flectra -d test_base_tier_validation_server_action -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_tier_validation_server_action
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_tier_validation_server_action
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_tier_validation_server_action
+ --test-enable -i base_tier_validation_server_action
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_tier_validation_server_action:TEST"
+
+test_module_chained_swapper:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_chained_swapper
+ - psql -h psql -U flectra -d test_chained_swapper -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_chained_swapper
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_chained_swapper
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_chained_swapper
+ --test-enable -i chained_swapper
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.chained_swapper:TEST"
+
+test_module_base_optional_quick_create:
+ stage: testsingle
+ when: on_failure
+ image:
+ name: registry.gitlab.com/jamotion/flectra/ubuntudev:2-latest
+ entrypoint: ["/bin/sh", "-c"]
+ script:
+ - apt-get install -y p7zip-full
+ - apt install -y expect-dev
+ - pip3 install -r ${CI_PROJECT_DIR}/requirements.txt
+ - su - flectra -c "mkdir ~/others"
+ - sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && dpkg-reconfigure --frontend=noninteractive locales && update-locale LANG=en_US.UTF-8
+ - mkdir ${CI_PROJECT_DIR}/ci_data
+ - wget -O ${CI_PROJECT_DIR}/ci_data/test_base.zip https://gitlab.com/flectra-community/devops/oca2fc/raw/master/ci_data/test_base.zip
+ - 7z x -o ${CI_PROJECT_DIR}/ci_data/ ${CI_PROJECT_DIR}/ci_data/test_base.zip
+ - export PGPASSWORD="flectra"
+ - createdb -h psql -U flectra -O flectra -T template1 test_base_optional_quick_create
+ - psql -h psql -U flectra -d test_base_optional_quick_create -f ${CI_PROJECT_DIR}/ci_data/dump.sql
+ - su - flectra -c "mkdir -p ~/.local/share/filestore"
+ - mv ${CI_PROJECT_DIR}/ci_data/filestore /opt/flectra/.local/share/filestore/test_base_optional_quick_create
+ - chown -R flectra.flectra /opt/flectra/.local/share/filestore/test_base_optional_quick_create
+ - su - flectra -c "/opt/flectra/flectra-bin
+ --addons-path ${CI_PROJECT_DIR}
+ --db_host psql
+ --db_port 5432
+ --db_user flectra
+ --db_password flectra
+ --database test_base_optional_quick_create
+ --test-enable -i base_optional_quick_create
+ --stop-after-init
+ --log-level error
+ --log-handler flectra.addons.base_optional_quick_create:TEST"
diff --git a/README.md b/README.md
index 13a8533..69c5528 100644
--- a/README.md
+++ b/README.md
@@ -10,25 +10,26 @@ Available addons
addon | version | summary
--- | --- | ---
[base_cancel_confirm](base_cancel_confirm/) | 2.0.1.0.2| Base Cancel Confirm
-[base_technical_features](base_technical_features/) | 2.0.1.1.0| Access to technical features without activating debug mode
-[base_menu_visibility_restriction](base_menu_visibility_restriction/) | 2.0.1.0.0| Restrict (with groups) menu visibilty
-[mass_editing](mass_editing/) | 2.0.1.0.1| Mass Editing
-[base_optional_quick_create](base_optional_quick_create/) | 2.0.1.0.0| Avoid "quick create" on m2o fields, on a "by model" basis
[filter_multi_user](filter_multi_user/) | 2.0.1.0.0| Allows to share user-defined filters filters among several users.
-[barcode_action](barcode_action/) | 2.0.1.0.0| Allows to use barcodes as a launcher
-[base_tier_validation_server_action](base_tier_validation_server_action/) | 2.0.1.1.0| Add option to call server action when a tier is validated
-[base_tier_validation](base_tier_validation/) | 2.0.2.3.0| Implement a validation process based on tiers.
-[document_quick_access](document_quick_access/) | 2.0.1.0.0| Document quick access
-[base_export_manager](base_export_manager/) | 2.0.1.0.1| Manage model export profiles
-[sequence_check_digit](sequence_check_digit/) | 2.0.1.0.0| Adds a check digit on sequences
-[base_tier_validation_formula](base_tier_validation_formula/) | 2.0.2.0.0| Formulas for Base tier validation
+[default_multi_user](default_multi_user/) | 2.0.1.0.0| Allows to share user-defined defaults among several users.
[sequence_reset_period](sequence_reset_period/) | 2.0.1.0.0| Auto-generate yearly/monthly/weekly/daily sequence period ranges
-[base_search_custom_field_filter](base_search_custom_field_filter/) | 2.0.1.0.0| Add custom filters for fields via UI
+[sequence_check_digit](sequence_check_digit/) | 2.0.1.0.0| Adds a check digit on sequences
+[base_import_security_group](base_import_security_group/) | 2.0.1.0.0| Group-based permissions for importing CSV files
[date_range](date_range/) | 2.0.2.0.2| Manage all kind of date range
[base_tier_validation_forward](base_tier_validation_forward/) | 2.0.1.0.2| Forward option for base tiers
-[default_multi_user](default_multi_user/) | 2.0.1.0.0| Allows to share user-defined defaults among several users.
-[base_revision](base_revision/) | 2.0.1.0.1| Keep track of revised document
+[base_menu_visibility_restriction](base_menu_visibility_restriction/) | 2.0.1.0.0| Restrict (with groups) menu visibilty
+[barcode_action](barcode_action/) | 2.0.1.0.0| Allows to use barcodes as a launcher
[multi_step_wizard](multi_step_wizard/) | 2.0.1.0.0| Multi-Steps Wizards
-[base_import_security_group](base_import_security_group/) | 2.0.1.0.0| Group-based permissions for importing CSV files
+[base_technical_features](base_technical_features/) | 2.0.1.1.0| Access to technical features without activating debug mode
+[base_tier_validation_formula](base_tier_validation_formula/) | 2.0.2.0.0| Formulas for Base tier validation
+[base_tier_validation](base_tier_validation/) | 2.0.2.4.0| Implement a validation process based on tiers.
+[base_search_custom_field_filter](base_search_custom_field_filter/) | 2.0.1.0.0| Add custom filters for fields via UI
+[base_revision](base_revision/) | 2.0.1.0.1| Keep track of revised document
+[base_export_manager](base_export_manager/) | 2.0.1.0.1| Manage model export profiles
+[document_quick_access](document_quick_access/) | 2.0.1.0.0| Document quick access
+[mass_editing](mass_editing/) | 2.0.1.0.1| Mass Editing
+[base_tier_validation_server_action](base_tier_validation_server_action/) | 2.0.1.1.1| Add option to call server action when a tier is validated
+[chained_swapper](chained_swapper/) | 2.0.1.0.0| Chained Swapper
+[base_optional_quick_create](base_optional_quick_create/) | 2.0.1.0.0| Avoid "quick create" on m2o fields, on a "by model" basis
diff --git a/base_tier_validation/__manifest__.py b/base_tier_validation/__manifest__.py
index e3d80e0..a0476c3 100644
--- a/base_tier_validation/__manifest__.py
+++ b/base_tier_validation/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "Base Tier Validation",
"summary": "Implement a validation process based on tiers.",
- "version": "2.0.2.3.0",
+ "version": "2.0.2.4.0",
"development_status": "Mature",
"maintainers": ["LoisRForgeFlow"],
"category": "Tools",
diff --git a/base_tier_validation/data/mail_data.xml b/base_tier_validation/data/mail_data.xml
index cd1cdb2..42b0ff8 100644
--- a/base_tier_validation/data/mail_data.xml
+++ b/base_tier_validation/data/mail_data.xml
@@ -30,4 +30,14 @@
+
+ Tier Validation Restarted
+
+
+
+
diff --git a/base_tier_validation/i18n/base_tier_validation.pot b/base_tier_validation/i18n/base_tier_validation.pot
index 0240604..7fea642 100644
--- a/base_tier_validation/i18n/base_tier_validation.pot
+++ b/base_tier_validation/i18n/base_tier_validation.pot
@@ -455,6 +455,12 @@ msgstr ""
msgid "The operation is under validation."
msgstr ""
+#. module: base_tier_validation
+#: code:addons/base_tier_validation/models/tier_validation.py:0
+#, python-format
+msgid "The review has been reset by %s."
+msgstr ""
+
#. module: base_tier_validation
#: code:addons/base_tier_validation/models/tier_validation.py:0
#, python-format
@@ -498,6 +504,11 @@ msgstr ""
msgid "Tier Validation Requested"
msgstr ""
+#. module: base_tier_validation
+#: model:mail.message.subtype,name:base_tier_validation.mt_tier_validation_restarted
+msgid "Tier Validation Restarted"
+msgstr ""
+
#. module: base_tier_validation
#: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation
msgid "Tier Validations"
diff --git a/base_tier_validation/i18n/es.po b/base_tier_validation/i18n/es.po
index 461da16..0e09019 100644
--- a/base_tier_validation/i18n/es.po
+++ b/base_tier_validation/i18n/es.po
@@ -478,6 +478,12 @@ msgstr "Estado"
msgid "The operation is under validation."
msgstr "Esta operación está en proceso de validación."
+#. module: base_tier_validation
+#: code:addons/base_tier_validation/models/tier_validation.py:0
+#, python-format
+msgid "The review has been reset by %s."
+msgstr ""
+
#. module: base_tier_validation
#: code:addons/base_tier_validation/models/tier_validation.py:0
#, python-format
@@ -525,6 +531,11 @@ msgstr "Validaciones de Nivel (abstracto)"
msgid "Tier Validation Requested"
msgstr ""
+#. module: base_tier_validation
+#: model:mail.message.subtype,name:base_tier_validation.mt_tier_validation_restarted
+msgid "Tier Validation Restarted"
+msgstr ""
+
#. module: base_tier_validation
#: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation
msgid "Tier Validations"
diff --git a/base_tier_validation/i18n/fr.po b/base_tier_validation/i18n/fr.po
index b131a9a..b9f7010 100644
--- a/base_tier_validation/i18n/fr.po
+++ b/base_tier_validation/i18n/fr.po
@@ -471,6 +471,12 @@ msgstr "Statut"
msgid "The operation is under validation."
msgstr ""
+#. module: base_tier_validation
+#: code:addons/base_tier_validation/models/tier_validation.py:0
+#, python-format
+msgid "The review has been reset by %s."
+msgstr ""
+
#. module: base_tier_validation
#: code:addons/base_tier_validation/models/tier_validation.py:0
#, python-format
@@ -514,6 +520,11 @@ msgstr ""
msgid "Tier Validation Requested"
msgstr "Validation par un tiers demandée"
+#. module: base_tier_validation
+#: model:mail.message.subtype,name:base_tier_validation.mt_tier_validation_restarted
+msgid "Tier Validation Restarted"
+msgstr ""
+
#. module: base_tier_validation
#: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation
msgid "Tier Validations"
diff --git a/base_tier_validation/i18n/nl_NL.po b/base_tier_validation/i18n/nl_NL.po
index d6abfd5..7f5c480 100644
--- a/base_tier_validation/i18n/nl_NL.po
+++ b/base_tier_validation/i18n/nl_NL.po
@@ -460,6 +460,12 @@ msgstr "Status"
msgid "The operation is under validation."
msgstr "De bewerking is onder validatie."
+#. module: base_tier_validation
+#: code:addons/base_tier_validation/models/tier_validation.py:0
+#, python-format
+msgid "The review has been reset by %s."
+msgstr ""
+
#. module: base_tier_validation
#: code:addons/base_tier_validation/models/tier_validation.py:0
#, python-format
@@ -507,6 +513,11 @@ msgstr "Tier-validatie (abstract)"
msgid "Tier Validation Requested"
msgstr ""
+#. module: base_tier_validation
+#: model:mail.message.subtype,name:base_tier_validation.mt_tier_validation_restarted
+msgid "Tier Validation Restarted"
+msgstr ""
+
#. module: base_tier_validation
#: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation
msgid "Tier Validations"
diff --git a/base_tier_validation/i18n/zh_CN.po b/base_tier_validation/i18n/zh_CN.po
index fc3e09b..0fb81e1 100644
--- a/base_tier_validation/i18n/zh_CN.po
+++ b/base_tier_validation/i18n/zh_CN.po
@@ -458,6 +458,12 @@ msgstr "状态"
msgid "The operation is under validation."
msgstr "该操作正在审批中。"
+#. module: base_tier_validation
+#: code:addons/base_tier_validation/models/tier_validation.py:0
+#, python-format
+msgid "The review has been reset by %s."
+msgstr ""
+
#. module: base_tier_validation
#: code:addons/base_tier_validation/models/tier_validation.py:0
#, python-format
@@ -505,6 +511,11 @@ msgstr "多层级审批(抽象)"
msgid "Tier Validation Requested"
msgstr ""
+#. module: base_tier_validation
+#: model:mail.message.subtype,name:base_tier_validation.mt_tier_validation_restarted
+msgid "Tier Validation Restarted"
+msgstr ""
+
#. module: base_tier_validation
#: model:ir.ui.menu,name:base_tier_validation.menu_tier_confirmation
msgid "Tier Validations"
diff --git a/base_tier_validation/models/tier_validation.py b/base_tier_validation/models/tier_validation.py
index bc6dbfc..37f90c9 100644
--- a/base_tier_validation/models/tier_validation.py
+++ b/base_tier_validation/models/tier_validation.py
@@ -211,7 +211,7 @@ class TierValidation(models.AbstractModel):
and getattr(rec, self._state_field) in self._state_from
and not vals.get(self._state_field)
in (self._state_to + [self._cancel_state])
- and not self._check_allow_write_under_validation(vals)
+ and not rec._check_allow_write_under_validation(vals)
):
raise ValidationError(_("The operation is under validation."))
if vals.get(self._state_field) in self._state_from:
@@ -251,11 +251,14 @@ class TierValidation(models.AbstractModel):
def _get_rejected_notification_subtype(self):
return "base_tier_validation.mt_tier_validation_rejected"
+ def _get_restarted_notification_subtype(self):
+ return "base_tier_validation.mt_tier_validation_restarted"
+
def _notify_accepted_reviews(self):
post = "message_post"
if hasattr(self, post):
# Notify state change
- getattr(self, post)(
+ getattr(self.sudo(), post)(
subtype_xmlid=self._get_accepted_notification_subtype(),
body=self._notify_accepted_reviews_body(),
)
@@ -320,7 +323,7 @@ class TierValidation(models.AbstractModel):
post = "message_post"
if hasattr(self, post):
# Notify state change
- getattr(self, post)(
+ getattr(self.sudo(), post)(
subtype_xmlid=self._get_rejected_notification_subtype(),
body=self._notify_rejected_review_body(),
)
@@ -388,11 +391,23 @@ class TierValidation(models.AbstractModel):
self._notify_review_requested(created_trs)
return created_trs
+ def _notify_restarted_review_body(self):
+ return _("The review has been reset by %s.") % (self.env.user.name)
+
+ def _notify_restarted_review(self):
+ post = "message_post"
+ if hasattr(self, post):
+ getattr(self.sudo(), post)(
+ subtype_xmlid=self._get_restarted_notification_subtype(),
+ body=self._notify_restarted_review_body(),
+ )
+
def restart_validation(self):
for rec in self:
if getattr(rec, self._state_field) in self._state_from:
rec.mapped("review_ids").unlink()
self._update_counter()
+ rec._notify_restarted_review()
@api.model
def _update_counter(self):
diff --git a/base_tier_validation_server_action/__manifest__.py b/base_tier_validation_server_action/__manifest__.py
index bb80c4f..fd5136e 100644
--- a/base_tier_validation_server_action/__manifest__.py
+++ b/base_tier_validation_server_action/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "Base Tier Validation - Server Action",
"summary": "Add option to call server action when a tier is validated",
- "version": "2.0.1.1.0",
+ "version": "2.0.1.1.1",
"development_status": "Alpha",
"maintainers": ["kittiu"],
"category": "Tools",
diff --git a/base_tier_validation_server_action/models/tier_review.py b/base_tier_validation_server_action/models/tier_review.py
index bde26b0..6bb42e1 100644
--- a/base_tier_validation_server_action/models/tier_review.py
+++ b/base_tier_validation_server_action/models/tier_review.py
@@ -1,20 +1,24 @@
# Copyright 2020 Ecosoft (http://ecosoft.co.th)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-from flectra import api, models
+from flectra import models
class TierReview(models.Model):
_inherit = "tier.review"
- @api.constrains("status")
- def _trigger_server_action(self):
- for rec in self.filtered(lambda l: l.status in ["approved", "rejected"]):
- server_action = False
- if rec.status == "approved":
- server_action = rec.definition_id.server_action_id
- if rec.status == "rejected":
- server_action = rec.definition_id.rejected_server_action_id
- if server_action:
- ctx = {"active_model": rec.model, "active_id": rec.res_id}
- server_action.with_context(ctx).run()
+ def write(self, vals):
+ res = super().write(vals)
+ if vals.get("status") in ["approved", "rejected"]:
+ for rec in self:
+ server_action = False
+ if rec.status == "approved":
+ server_action = rec.definition_id.server_action_id
+ if rec.status == "rejected":
+ server_action = rec.definition_id.rejected_server_action_id
+ if server_action:
+ server_action.with_context(
+ active_model=rec.model,
+ active_id=rec.res_id,
+ ).sudo().run()
+ return res
diff --git a/chained_swapper/COPYRIGHT b/chained_swapper/COPYRIGHT
new file mode 100644
index 0000000..924accc
--- /dev/null
+++ b/chained_swapper/COPYRIGHT
@@ -0,0 +1,17 @@
+Most of the files are
+
+ :Copyright: This stylesheet has been placed in the public domain.
+
+
+
+
+ Language
+
+
+
+
+
+ child_ids.lang
+
+
+
+ Only parent company
+ bool(records.mapped('parent_id'))
+
+
+
+ Chained swap: Language
+ chained.swapper.wizard
+ form
+ new
+
+ form
+
+
+
+
+
+
+
diff --git a/chained_swapper/hooks.py b/chained_swapper/hooks.py
new file mode 100644
index 0000000..584c812
--- /dev/null
+++ b/chained_swapper/hooks.py
@@ -0,0 +1,14 @@
+# Copyright 2020 Tecnativa - Ernesto Tejeda
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from flectra.api import SUPERUSER_ID, Environment
+
+
+def uninstall_hook(cr, registry):
+ """Delete the actions that were created with chained_swapper when
+ the module is uninstalled"""
+ env = Environment(cr, SUPERUSER_ID, {})
+ env["ir.actions.act_window"].search(
+ [("res_model", "=", "chained.swapper.wizard")]
+ ).unlink()
+ return True
diff --git a/chained_swapper/i18n/chained_swapper.pot b/chained_swapper/i18n/chained_swapper.pot
new file mode 100644
index 0000000..7b0b71a
--- /dev/null
+++ b/chained_swapper/i18n/chained_swapper.pot
@@ -0,0 +1,280 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * chained_swapper
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/wizard/chained_swapper_wizard.py:0
+#, python-format
+msgid "Chained swap done:"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__ref_ir_act_window_id
+msgid "Action"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper__ref_ir_act_window_id
+msgid ""
+"Action to make this template available on records of the related document "
+"model."
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Add Action"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid ""
+"Add a new contextual action of related documents to open a composition "
+"wizard"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Advanced"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__allowed_field_ids
+msgid "Allowed Field"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper_constraint__expression
+msgid ""
+"Boolean python expression. You can use the keyword 'records' as the records "
+"selected to execute the contextual action. Ex.: "
+"bool(records.mapped('parent_id'))"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__chained_swapper_id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__chained_swapper_id
+msgid "Chained Swapper"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper_constraint
+msgid "Chained Swapper Constraint"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper_sub_field
+msgid "Chained Swapper Sub-field"
+msgstr ""
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:0
+#, python-format
+msgid "Chained swap"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.actions.act_window,name:chained_swapper.partner_chained_swap_lang_action_demo
+msgid "Chained swap: Language"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_wizard_view_form
+msgid "Change"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_wizard_view_form
+msgid "Close"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__expression
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_constraint_view_form
+msgid "Constraint expression"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__constraint_ids
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Constraints"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__create_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__create_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__create_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__create_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__create_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__create_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__display_name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__display_name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__display_name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__field_id
+msgid "Field"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.actions.act_window,name:chained_swapper.chained_swapper_action
+#: model:ir.ui.menu,name:chained_swapper.chained_swapper_menu
+#: model:ir.ui.menu,name:chained_swapper.chained_swapper_submenu
+msgid "Field Swaps"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__group_ids
+msgid "Groups"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__id
+msgid "ID"
+msgstr ""
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:0
+#, python-format
+msgid "Incorrect sub-field expression:"
+msgstr ""
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:0
+#, python-format
+msgid "Invalid constraint expression: "
+msgstr ""
+
+#. module: chained_swapper
+#: model:chained.swapper,name:chained_swapper.chained_swapper_demo
+msgid "Language"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper____last_update
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint____last_update
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field____last_update
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__write_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__write_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__write_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__write_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__write_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__write_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__model_id
+msgid "Model"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.constraint,message:chained_swapper.constraint_chained_swapper_model_id_field_id_unique
+msgid "Model and Field must be unique!"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper__model_id
+msgid ""
+"Model is used for Selecting Field. This is editable until Contextual Action "
+"is not created."
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__name
+msgid "Name"
+msgstr ""
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/wizard/chained_swapper_wizard.py:0
+#, python-format
+msgid "Not possible to swap the field due to the constraint"
+msgstr ""
+
+#. module: chained_swapper
+#: model:chained.swapper.constraint,name:chained_swapper.chained_swapper_constraint_demo
+msgid "Only parent company"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Remove Action"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Remove the contextual action to use this template on related documents"
+msgstr ""
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Security"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__sub_field_chain
+msgid "Sub Field Chain"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__sub_field_ids
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Sub-fields"
+msgstr ""
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:0
+#, python-format
+msgid "The sub-field '%s' is not compatible with the main field."
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper_wizard
+msgid "Wizard chained swapper"
+msgstr ""
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper_sub_field__sub_field_chain
+msgid ""
+"You can specify here a field of related fields as dotted names. Ex.: "
+"'child_ids.lang'."
+msgstr ""
diff --git a/chained_swapper/i18n/es.po b/chained_swapper/i18n/es.po
new file mode 100644
index 0000000..05a68e2
--- /dev/null
+++ b/chained_swapper/i18n/es.po
@@ -0,0 +1,296 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * chained_swapper
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-08-14 10:32+0000\n"
+"PO-Revision-Date: 2020-08-14 12:33+0200\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: \n"
+"X-Generator: Poedit 2.3\n"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/wizard/chained_swapper_wizard.py:146
+#, python-format
+msgid "Chained swap done:"
+msgstr "Cambio encadenado realizado:"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__ref_ir_act_window_id
+msgid "Action"
+msgstr "Acción"
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper__ref_ir_act_window_id
+msgid ""
+"Action to make this template available on records of the related document "
+"model."
+msgstr ""
+"Acción contextual para hacer que esta plantilla esté disponible en los "
+"registros del modelo de documento relacionado."
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Add Action"
+msgstr "Añadir acción"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid ""
+"Add a new contextual action of related documents to open a composition wizard"
+msgstr ""
+"Añade una acción contextual para los documentos relacionados para abrir un "
+"asistente de intercambio encadenado"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Advanced"
+msgstr "Avanzado"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__allowed_field_ids
+msgid "Allowed Field"
+msgstr "Campos permitidos"
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper_constraint__expression
+msgid ""
+"Boolean python expression. You can use the keyword 'records' as the records "
+"selected to execute the contextual action. Ex.: bool(records."
+"mapped('parent_id'))"
+msgstr ""
+"Expresión Python booleana. Puede usar la palabra clave 'records' para hacer "
+"referencia a los registros seleccionados al ejecutar la acción contextual. "
+"Ej.: bool(records.mapped('parent_id'))"
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__chained_swapper_id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__chained_swapper_id
+msgid "Chained Swapper"
+msgstr "Intercambiador encadenado"
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper_constraint
+msgid "Chained Swapper Constraint"
+msgstr "Intercambiador encadenado - Restricciones"
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper_sub_field
+msgid "Chained Swapper Sub-field"
+msgstr "Intercambiador encadenado - Sub-campos"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:104
+#, python-format
+msgid "Chained swap"
+msgstr "Cambio encadenado"
+
+#. module: chained_swapper
+#: model:ir.actions.act_window,name:chained_swapper.partner_chained_swap_lang_action_demo
+msgid "Chained swap: Language"
+msgstr "Cambio encadenado: Idioma"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_wizard_view_form
+msgid "Change"
+msgstr "Cambiar"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_wizard_view_form
+msgid "Close"
+msgstr "Cerrar"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__expression
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_constraint_view_form
+msgid "Constraint expression"
+msgstr "Expresión de restricción"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__constraint_ids
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Constraints"
+msgstr "Restricciones"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__create_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__create_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__create_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__create_uid
+msgid "Created by"
+msgstr "Creado por"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__create_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__create_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__create_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__create_date
+msgid "Created on"
+msgstr "Creado el"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__display_name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__display_name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__display_name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__display_name
+msgid "Display Name"
+msgstr "Nombre mostrado"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__field_id
+msgid "Field"
+msgstr "Campo"
+
+#. module: chained_swapper
+#: model:ir.actions.act_window,name:chained_swapper.chained_swapper_action
+#: model:ir.ui.menu,name:chained_swapper.chained_swapper_menu
+#: model:ir.ui.menu,name:chained_swapper.chained_swapper_submenu
+msgid "Field Swaps"
+msgstr "Intercambios de campo"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__group_ids
+msgid "Groups"
+msgstr "Grupos"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__id
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__id
+msgid "ID"
+msgstr "ID"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:151
+#, python-format
+msgid "Incorrect sub-field expression:"
+msgstr "Expresión de sub-campo incorrecta:"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:193
+#, python-format
+msgid "Invalid constraint expression: "
+msgstr "Expresión de restricción no válida:"
+
+#. module: chained_swapper
+#: model:chained.swapper,name:chained_swapper.chained_swapper_demo
+msgid "Language"
+msgstr "Idioma"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper____last_update
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint____last_update
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field____last_update
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard____last_update
+msgid "Last Modified on"
+msgstr "Última modificación en"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__write_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__write_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__write_uid
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__write_uid
+msgid "Last Updated by"
+msgstr "Última actualización por"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__write_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__write_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__write_date
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_wizard__write_date
+msgid "Last Updated on"
+msgstr "Última actualización el"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__model_id
+msgid "Model"
+msgstr "Modelo"
+
+#. module: chained_swapper
+#: sql_constraint:chained.swapper:0
+msgid "Model and Field must be unique!"
+msgstr "La combinación Modelo-Campo debe ser única!"
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper__model_id
+msgid ""
+"Model is used for Selecting Field. This is editable until Contextual Action "
+"is not created."
+msgstr ""
+"El modelo se utiliza para seleccionar el campo. Este es editable mientras la "
+"acción contextual no esté creada."
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__name
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_constraint__name
+msgid "Name"
+msgstr "Nombre"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/wizard/chained_swapper_wizard.py:32
+#, python-format
+msgid "Not possible to swap the field due to the constraint"
+msgstr "No es posible cambiar el campo debido a la restricción"
+
+#. module: chained_swapper
+#: model:chained.swapper.constraint,name:chained_swapper.chained_swapper_constraint_demo
+msgid "Only parent company"
+msgstr "Solo compañías padres"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Remove Action"
+msgstr "Eliminar acción"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Remove the contextual action to use this template on related documents"
+msgstr ""
+"Borrar la acción conceptual para usar esta plantilla en documentos "
+"relacionados"
+
+#. module: chained_swapper
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Security"
+msgstr "Seguridad"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper_sub_field__sub_field_chain
+msgid "Sub Field Chain"
+msgstr "Cadena de sub-campo"
+
+#. module: chained_swapper
+#: model:ir.model.fields,field_description:chained_swapper.field_chained_swapper__sub_field_ids
+#: model_terms:ir.ui.view,arch_db:chained_swapper.chained_swapper_view_form
+msgid "Sub-fields"
+msgstr "Sub-campo"
+
+#. module: chained_swapper
+#: code:addons/chained_swapper/models/chained_swapper.py:162
+#, python-format
+msgid "The sub-field '%s' is not compatible with the main field."
+msgstr "El sub-campo '%s' no es compatible con el campo principal."
+
+#. module: chained_swapper
+#: model:ir.model,name:chained_swapper.model_chained_swapper_wizard
+msgid "Wizard chained swapper"
+msgstr "Asistente de intercambiador encadenado"
+
+#. module: chained_swapper
+#: model:ir.model.fields,help:chained_swapper.field_chained_swapper_sub_field__sub_field_chain
+msgid ""
+"You can specify here a field of related fields as dotted names. Ex.: "
+"'child_ids.lang'."
+msgstr ""
+"Puede especificar aquí un campo de campos relacionados como una cadena de "
+"nombres separada por puntos. Ej.: 'child_ids.lang'."
diff --git a/chained_swapper/models/__init__.py b/chained_swapper/models/__init__.py
new file mode 100644
index 0000000..10e942d
--- /dev/null
+++ b/chained_swapper/models/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import chained_swapper
diff --git a/chained_swapper/models/chained_swapper.py b/chained_swapper/models/chained_swapper.py
new file mode 100644
index 0000000..88e7764
--- /dev/null
+++ b/chained_swapper/models/chained_swapper.py
@@ -0,0 +1,196 @@
+# Copyright 2020 Tecnativa - Ernesto Tejeda
+# Copyright 2020 Tecnativa - Pedro M. Baeza
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from flectra import _, api, exceptions, fields, models
+from flectra.tools.safe_eval import safe_eval
+
+
+class ChainedSwapper(models.Model):
+ _name = "chained.swapper"
+ _description = "Chained Swapper"
+
+ name = fields.Char(required=True, translate=True, index=1)
+ model_id = fields.Many2one(
+ comodel_name="ir.model",
+ required=True,
+ ondelete="cascade",
+ help="Model is used for Selecting Field. This is editable "
+ "until Contextual Action is not created.",
+ )
+ allowed_field_ids = fields.Many2many(
+ comodel_name="ir.model.fields", compute="_compute_allowed_field_ids"
+ )
+ field_id = fields.Many2one(
+ comodel_name="ir.model.fields",
+ required=True,
+ ondelete="cascade",
+ domain="[('id', 'in', allowed_field_ids)]",
+ )
+ sub_field_ids = fields.One2many(
+ comodel_name="chained.swapper.sub.field",
+ inverse_name="chained_swapper_id",
+ string="Sub-fields",
+ )
+ constraint_ids = fields.One2many(
+ comodel_name="chained.swapper.constraint",
+ inverse_name="chained_swapper_id",
+ string="Constraints",
+ )
+ ref_ir_act_window_id = fields.Many2one(
+ comodel_name="ir.actions.act_window",
+ string="Action",
+ readonly=True,
+ help="Action to make this template available on records "
+ "of the related document model.",
+ )
+ group_ids = fields.Many2many(
+ comodel_name="res.groups",
+ relation="mass_group_rel",
+ column1="mass_id",
+ column2="group_id",
+ string="Groups",
+ )
+
+ _sql_constraints = [
+ (
+ "model_id_field_id_unique",
+ "unique (model_id, field_id)",
+ "Model and Field must be unique!",
+ ),
+ ]
+
+ @api.depends("model_id")
+ def _compute_allowed_field_ids(self):
+ model_obj = self.env["ir.model"]
+ field_obj = self.env["ir.model.fields"]
+ for record in self:
+ allowed_field_ids = False
+ if record.model_id:
+ all_models = record.model_id
+ active_model_obj = self.env[record.model_id.model]
+ if active_model_obj._inherits:
+ keys = list(active_model_obj._inherits.keys())
+ all_models |= model_obj.search([("model", "in", keys)])
+ allowed_field_ids = field_obj.search(
+ [
+ ("ttype", "not in", ["reference", "function", "one2many"]),
+ ("model_id", "in", all_models.ids),
+ ]
+ )
+ record.allowed_field_ids = allowed_field_ids
+
+ @api.constrains("model_id", "field_id")
+ def _check_sub_field_ids(self):
+ self.mapped("sub_field_ids")._check_sub_field_chain()
+
+ @api.onchange("model_id")
+ def _onchange_model_id(self):
+ self.field_id = False
+
+ def write(self, vals):
+ res = super().write(vals)
+ if "name" in vals:
+ self.mapped("ref_ir_act_window_id").write({"name": vals["name"]})
+ return res
+
+ def unlink(self):
+ self.unlink_action()
+ return super().unlink()
+
+ def add_action(self):
+ self.ensure_one()
+ action = self.env["ir.actions.act_window"].create(
+ {
+ "name": _("Chained swap") + ": " + self.name,
+ "type": "ir.actions.act_window",
+ "res_model": "chained.swapper.wizard",
+ "groups_id": [(4, x.id) for x in self.group_ids],
+ "context": "{'chained_swapper_id': %d}" % (self.id),
+ "view_mode": "form",
+ "target": "new",
+ "binding_model_id": self.model_id.id,
+ "binding_type": "action",
+ }
+ )
+ self.write({"ref_ir_act_window_id": action.id})
+ return True
+
+ def unlink_action(self):
+ self.mapped("ref_ir_act_window_id").unlink()
+ return True
+
+
+class ChainedSwapperSubField(models.Model):
+ _name = "chained.swapper.sub.field"
+ _description = "Chained Swapper Sub-field"
+
+ chained_swapper_id = fields.Many2one(
+ comodel_name="chained.swapper", ondelete="cascade"
+ )
+ sub_field_chain = fields.Char(
+ required=True,
+ help="You can specify here a field of related fields as "
+ "dotted names. Ex.: 'child_ids.lang'.",
+ )
+
+ @api.constrains("chained_swapper_id", "sub_field_chain")
+ def _check_sub_field_chain(self):
+ for rec in self:
+ # Check sub-field exist
+ try:
+ chain_list = rec.sub_field_chain.split(".")
+ chain_field_name = chain_list.pop()
+ chain_model = self.env[rec.chained_swapper_id.model_id.model]
+ for name in chain_list:
+ chain_model = chain_model[name]
+ chain_model[chain_field_name] # pylint: disable=W0104
+ except KeyError:
+ raise exceptions.ValidationError(
+ _("Incorrect sub-field expression:") + " " + rec.sub_field_chain
+ )
+ # Check sub-field and original field are the same type
+ swap_field = rec.chained_swapper_id.field_id
+ chain_field = self.env["ir.model.fields"].search(
+ [
+ ("model_id", "=", rec.chained_swapper_id.model_id.id),
+ ("name", "=", chain_field_name),
+ ]
+ )
+ if (
+ chain_field.ttype != swap_field.ttype
+ or chain_field.relation != swap_field.relation
+ ):
+ raise exceptions.ValidationError(
+ _("The sub-field '%s' is not compatible with the main" " field.")
+ % rec.sub_field_chain
+ )
+
+
+class ChainedSwapperConstraint(models.Model):
+ _name = "chained.swapper.constraint"
+ _description = "Chained Swapper Constraint"
+
+ chained_swapper_id = fields.Many2one(
+ comodel_name="chained.swapper", ondelete="cascade"
+ )
+ name = fields.Char(required=True, translate=True)
+ expression = fields.Text(
+ string="Constraint expression",
+ required=True,
+ help="Boolean python expression. You can use the keyword "
+ "'records' as the records selected to execute the "
+ "contextual action. Ex.: bool(records.mapped('parent_id'))",
+ default="True",
+ )
+
+ @api.constrains("expression")
+ def _check_expression(self):
+ for record in self:
+ model = self.env[record.chained_swapper_id.model_id.model]
+ try:
+ safe_eval(record.expression, {"records": model})
+ except Exception:
+ raise exceptions.ValidationError(
+ _("Invalid constraint expression:" + " " + record.expression)
+ )
diff --git a/chained_swapper/security/ir.model.access.csv b/chained_swapper/security/ir.model.access.csv
new file mode 100644
index 0000000..4bd1828
--- /dev/null
+++ b/chained_swapper/security/ir.model.access.csv
@@ -0,0 +1,8 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_chained_swapper_user,chained.swapper.user,model_chained_swapper,base.group_user,1,0,0,0
+access_chained_swapper_erp_manager,chained.swapper.erp_manager,model_chained_swapper,base.group_erp_manager,1,1,1,1
+access_chained_swapper_sub_field_user,chained.swapper.sub.field.user,model_chained_swapper_sub_field,base.group_user,1,0,0,0
+access_chained_swapper_sub_field_erp_manager,chained.swapper.sub.field.erp_manager,model_chained_swapper_sub_field,base.group_erp_manager,1,1,1,1
+access_chained_swapper_constraint_user,chained.swapper.constraint.user,model_chained_swapper_constraint,base.group_user,1,0,0,0
+access_chained_swapper_constraint_erp_manager,chained.swapper.constraint.erp_manager,model_chained_swapper_constraint,base.group_erp_manager,1,1,1,1
+access_chained_swapper_wizard,chained.swapper.wizard.constraint.erp_manager,model_chained_swapper_wizard,base.group_user,1,1,1,1
diff --git a/chained_swapper/static/description/icon.png b/chained_swapper/static/description/icon.png
new file mode 100644
index 0000000..3a0328b
Binary files /dev/null and b/chained_swapper/static/description/icon.png differ
diff --git a/chained_swapper/static/description/index.html b/chained_swapper/static/description/index.html
new file mode 100644
index 0000000..20e2be8
--- /dev/null
+++ b/chained_swapper/static/description/index.html
@@ -0,0 +1,490 @@
+
+
+
+
+
+
+Chained Swapper
+
+
+
+
+
Chained Swapper
+
+
+
+
This module allows to swap the value of a field and propagate it in a chained
+way to linked records. Example: changing the delivery address in a confirmed
+sales order, it should be changed in its delivery orders as well.
+
It also allows to apply constraints for not allowing to do that change
+according rules, so the business logic is not broken. Example: Don’t allow
+to change the delivery address if the delivery order is validated.
+
This module requires some technical knowledge for setting the chained swap and
+the constraint, as it’s defined through technical names and Python code.
+
WARNING: Use this module with care, as it can screw up database consistency
+if swaps are not properly designed .
+
Table of contents
+
+
+
+
To configure this module, you need to:
+
+Go to Setting > Field Swaps > Field Swaps.
+
+Create a new object and set the following data as an example:
+
+Name for identifying it and use it for the action name.
+
+Select the source model where the swap will be started.
+
+Select the starting field for which the swap will be done.
+
+Add several chained fields. They are expressed as a string using
+dot notation, taking the source model as beginning for looking there
+the first field, and continuing from there drilling through. Example:
+picking_ids.partner_id for sale.order model will go to the linked
+deliveries orders, and change the customer there.
+
+Add possible constraints for restricting the chained swap. They are
+Python expressions that must be one line that is evaluated as boolean.
+If the evaluation is true, then a message will be thrown and no swap
+will be allowed. You can use the variable records in your code, that
+will be referring the selected records for doing the swap. Example: for
+restricting sales orders that have a delivery order validated:
+any(p.state == ‘done’ for p in records.mapped(‘picking_ids.state’))
+Other variables you can use are env, date and datetime.
+Each constraint has a name for identifying it, but also for showing that
+name when displaying the error trying to do the swap.
+
+
+
+Click on ‘Add action’ smart button to add a new action in the source model.
+
+
+
On demo databases, you can check the example “Language”, that changes the
+language of a contact, and propagate it to children contacts.
+
+
+
+
To use this module, you need to:
+
+- Go to the source document in list mode.
+- Select one or several records.
+- Click on Action and locate the option “Chained swap: <name of the swap>”.
+- If one of the selected records doesn’t comply with one of the constraints,
+a message will be shown, and the swap won’t continue.
+- If everything is OK, a popup will arise, and you will see a field for
+filling the new value.
+- Click on “Change”, and the swap will be done.
+- On the chatter of the source document, an entry will be logged for
+reflecting the done swap.
+
+
+
+
+
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+
+
This module is maintained by the OCA.
+
+
OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
This module is part of the OCA/server-ux project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
diff --git a/chained_swapper/tests/__init__.py b/chained_swapper/tests/__init__.py
new file mode 100644
index 0000000..ccd7e32
--- /dev/null
+++ b/chained_swapper/tests/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from . import test_chained_swapper
diff --git a/chained_swapper/tests/test_chained_swapper.py b/chained_swapper/tests/test_chained_swapper.py
new file mode 100644
index 0000000..626c403
--- /dev/null
+++ b/chained_swapper/tests/test_chained_swapper.py
@@ -0,0 +1,104 @@
+# Copyright 2020 Tecnativa - Ernesto Tejeda
+# Copyright 2020 Tecnativa - Pedro M. Baeza
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from flectra import exceptions
+from flectra.modules import registry
+from flectra.tests import common
+from flectra.tests.common import Form
+
+from ..hooks import uninstall_hook
+
+
+class TestChainedSwapper(common.SavepointCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestChainedSwapper, cls).setUpClass()
+ cls.env["res.lang"].load_lang("es_ES")
+ res_partner = cls.env["res.partner"]
+ cls.partner_parent = res_partner.create(
+ {"name": "parent partner cs", "lang": "en_US"}
+ )
+ cls.partner_child_1 = res_partner.create(
+ {"name": "partner child1 cs", "parent_id": cls.partner_parent.id}
+ )
+ cls.partner_child_2 = res_partner.create(
+ {"name": "partner child2 cs", "parent_id": cls.partner_parent.id}
+ )
+ # Prevent duplicate error removing demo data if exists
+ record = cls.env.ref("chained_swapper.chained_swapper_demo", False)
+ if record:
+ record.unlink()
+
+ chained_swapper_form = Form(cls.env["chained.swapper"])
+ chained_swapper_form.name = "Language"
+ chained_swapper_form.model_id = cls.env.ref("base.model_res_partner")
+ chained_swapper_form.field_id = cls.env.ref("base.field_res_partner__lang")
+ with chained_swapper_form.sub_field_ids.new() as sub_field_form:
+ sub_field_form.sub_field_chain = "child_ids.lang"
+ with chained_swapper_form.constraint_ids.new() as constraint_form:
+ constraint_form.name = "Only parent company"
+ constraint_form.expression = "bool(records.mapped('parent_id'))"
+
+ cls.chained_swapper = chained_swapper_form.save()
+ cls.chained_swapper.add_action()
+
+ def test_create_unlink_action(self):
+ """Test if Sidebar Action is added / removed to / from given object."""
+ action = (
+ self.chained_swapper.ref_ir_act_window_id
+ and self.chained_swapper.ref_ir_act_window_id.binding_model_id
+ )
+ self.assertTrue(action)
+ # Remove the action
+ self.chained_swapper.unlink_action()
+ action = self.chained_swapper.ref_ir_act_window_id
+ self.assertFalse(action)
+ # Add an action
+ self.chained_swapper.add_action()
+ action = (
+ self.chained_swapper.ref_ir_act_window_id
+ and self.chained_swapper.ref_ir_act_window_id.binding_model_id
+ )
+ self.assertTrue(action)
+
+ def test_unlink_chained_swapper(self):
+ """Test if related actions are removed when a chained swapper
+ record is unlinked."""
+ action_id = self.chained_swapper.ref_ir_act_window_id.id
+ self.chained_swapper.unlink()
+ action = self.env["ir.actions.act_window"].search([("id", "=", action_id)])
+ self.assertFalse(action)
+
+ def test_change_constrained_partner_language(self):
+ with self.assertRaises(exceptions.UserError):
+ self.env["chained.swapper.wizard"].with_context(
+ active_model="res.partner",
+ active_id=self.partner_parent.id,
+ active_ids=(self.partner_parent | self.partner_child_1).ids,
+ chained_swapper_id=self.chained_swapper.id,
+ ).create({"lang": "es_ES"})
+
+ def test_change_partner_language(self):
+ self.env["chained.swapper.wizard"].with_context(
+ active_model="res.partner",
+ active_id=self.partner_parent.id,
+ active_ids=[self.partner_parent.id],
+ chained_swapper_id=self.chained_swapper.id,
+ ).create({"lang": "es_ES"})
+ self.assertEqual(self.partner_parent.lang, "es_ES")
+ self.assertEqual(self.partner_child_1.lang, "es_ES")
+ self.assertEqual(self.partner_child_2.lang, "es_ES")
+
+ def test_uninstall_hook(self):
+ """Test if related actions are removed when mass editing
+ record is uninstalled."""
+ action_id = self.chained_swapper.ref_ir_act_window_id.id
+ uninstall_hook(self.cr, registry)
+ self.assertFalse(self.env["ir.actions.act_window"].browse(action_id).exists())
+
+ def test_invalid_constraint(self):
+ with self.assertRaises(exceptions.ValidationError):
+ self.chained_swapper.constraint_ids.write(
+ {"expression": "Something incorrect"}
+ )
diff --git a/chained_swapper/views/chained_swapper_views.xml b/chained_swapper/views/chained_swapper_views.xml
new file mode 100644
index 0000000..ed6013d
--- /dev/null
+++ b/chained_swapper/views/chained_swapper_views.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+ chained.swapper.form
+ chained.swapper
+
+
+
+
+
+ chained.swapper.tree
+ chained.swapper
+
+
+
+
+
+
+
+
+
+ Field Swaps
+ chained.swapper
+ tree,form
+
+
+
+ chained.swapper.sub.field.tree
+ chained.swapper.sub.field
+
+
+
+
+
+
+
+
+ chained.swapper.constraint.tree
+ chained.swapper.constraint
+
+
+
+
+
+
+
+
+ chained.swapper.constraint.form
+ chained.swapper.constraint
+
+
+
+
+
+
+
+
+
diff --git a/chained_swapper/wizard/__init__.py b/chained_swapper/wizard/__init__.py
new file mode 100644
index 0000000..f841eb5
--- /dev/null
+++ b/chained_swapper/wizard/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import chained_swapper_wizard
diff --git a/chained_swapper/wizard/chained_swapper_wizard.py b/chained_swapper/wizard/chained_swapper_wizard.py
new file mode 100644
index 0000000..9165165
--- /dev/null
+++ b/chained_swapper/wizard/chained_swapper_wizard.py
@@ -0,0 +1,164 @@
+# Copyright 2020 Tecnativa - Ernesto Tejeda
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from datetime import date, datetime
+
+from lxml import etree
+
+from flectra import _, api, models
+from flectra.exceptions import UserError
+from flectra.tools.safe_eval import safe_eval
+
+
+class ChainedSwapperWizard(models.TransientModel):
+ _name = "chained.swapper.wizard"
+ _description = "Wizard chained swapper"
+
+ @api.model
+ def default_get(self, fields):
+ context = self.env.context
+ if context.get("chained_swapper_id"):
+ records = self.env[context.get("active_model")].browse(
+ context.get("active_ids")
+ )
+ exp_dict = {
+ "records": records,
+ "env": self.env,
+ "date": date,
+ "datetime": datetime,
+ }
+ chained_swapper = self.env["chained.swapper"].browse(
+ context.get("chained_swapper_id")
+ )
+ for constraint in chained_swapper.constraint_ids:
+ if safe_eval(constraint.expression, exp_dict):
+ raise UserError(
+ _("Not possible to swap the field due to the constraint")
+ + ": "
+ + constraint.name
+ )
+ return super().default_get(fields)
+
+ @api.model
+ def fields_view_get(
+ self, view_id=None, view_type="form", toolbar=False, submenu=False
+ ):
+ """As we don't have any field in this model, result['fields']
+ and result['arch'] are modified to add dynamically the
+ corresponding field.
+ """
+ res = super().fields_view_get(
+ view_id=view_id,
+ view_type=view_type,
+ toolbar=toolbar,
+ submenu=submenu,
+ )
+ if not self.env.context.get("chained_swapper_id"):
+ return res
+ chained_swapper = self.env["chained.swapper"].browse(
+ self.env.context.get("chained_swapper_id")
+ )
+ model_obj = self.env[self.env.context.get("active_model")]
+ field_info = model_obj.fields_get()
+ field = chained_swapper.field_id
+ # Fields dict
+ all_fields = {
+ field.name: {
+ "type": field.ttype,
+ "string": field.field_description,
+ "views": {},
+ }
+ }
+ if field.ttype in ["many2many", "many2one"]:
+ all_fields[field.name]["relation"] = field.relation
+ elif field.ttype == "selection":
+ field_selection = field_info[field.name]["selection"]
+ all_fields[field.name]["selection"] = field_selection
+ # XML view definition
+ doc = etree.XML(res["arch"])
+ group_node = doc.xpath("//group[@name='swap_field_group']")[0]
+ etree.SubElement(group_node, "field", {"name": field.name, "colspan": "4"})
+ if field.ttype in ["one2many", "many2many", "text"]:
+ group_node.set("string", field.field_description)
+ group_node.set("nolabel", "1")
+ res.update(arch=etree.tostring(doc, encoding="unicode"), fields=all_fields)
+ return res
+
+ @api.model
+ def create(self, vals):
+ """As we don't have any field in this model, the key-value pair
+ received in vals dict are only used to change the value in the active
+ models.
+ """
+ model_obj = self.env[self.env.context.get("active_model")]
+ context = self.env.context
+ field_name, new_value = list(vals.items())[0]
+ # write the active model
+ model = model_obj.browse(self.env.context.get("active_ids"))
+ original_values = {m.id: m[field_name] for m in model}
+ model.write(vals)
+ if hasattr(model, "message_post"):
+ self.post_chained_swap(model, field_name, original_values, new_value)
+ # write chained models
+ chained_swapper_obj = self.env["chained.swapper"]
+ chained_swapper = chained_swapper_obj.browse(context.get("chained_swapper_id"))
+ for sub_field in chained_swapper.sub_field_ids:
+ chain_fields = sub_field.sub_field_chain.split(".")
+ field_name = chain_fields.pop()
+ chain_model = model
+ for chain_field in chain_fields:
+ chain_model = chain_model.mapped(chain_field)
+ original_values = {cm.id: cm[field_name] for cm in chain_model}
+ chain_model.write({field_name: new_value})
+ # post swap
+ if hasattr(chain_model, "message_post"):
+ self.post_chained_swap(
+ chain_model, field_name, original_values, new_value
+ )
+ return super().create({})
+
+ def change_action(self):
+ return {"type": "ir.actions.act_window_close"}
+
+ @api.model
+ def post_chained_swap(self, model, field_name, original_values, new_value):
+ def human_readable_field(value):
+ result = value
+ field_def = model._fields[field_name]
+ if field_def.type == "selection":
+ if type(field_def.selection) == list:
+ selection = field_def.selection
+ else:
+ selection = field_def.selection(self)
+ for selection_item in selection:
+ if selection_item[0] == value:
+ result = selection_item[1]
+ break
+ elif field_def.type == "many2one":
+ if type(value) == int:
+ result = self.env[field_def.comodel_name].browse(value)
+ result = result.display_name
+ elif field_def.type == "many2many":
+ if type(value) == list:
+ ids = value[0][2]
+ value = self.env[field_def.comodel_name].browse(ids)
+ result = str(value.mapped("display_name"))
+ return result
+
+ field_desc = model._fields[field_name].string
+ new_value = human_readable_field(new_value)
+ for m in model:
+ original_value = human_readable_field(original_values[m.id])
+ m.message_post(
+ body=_("Chained swap done:")
+ + "
{}: {} ⇒ {}".format(field_desc, original_value, new_value)
+ )
+
+ def read(self, fields, load="_classic_read"):
+ """Without this call, dynamic fields build by fields_view_get()
+ generate a crash and warning, i.e.: read() with unknown field 'myfield'
+ """
+ real_fields = set(fields) & set(self._fields)
+ result = super().read(list(real_fields), load=load)
+ result[0].update({x: False for x in set(fields) - real_fields})
+ return result
diff --git a/chained_swapper/wizard/chained_swapper_wizard_views.xml b/chained_swapper/wizard/chained_swapper_wizard_views.xml
new file mode 100644
index 0000000..083041b
--- /dev/null
+++ b/chained_swapper/wizard/chained_swapper_wizard_views.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ chained.swapper.wizard.form
+ chained.swapper.wizard
+
+
+
+
+
diff --git a/mass_editing/COPYRIGHT b/mass_editing/COPYRIGHT
index abcdd46..2244a61 100644
--- a/mass_editing/COPYRIGHT
+++ b/mass_editing/COPYRIGHT
@@ -1,9 +1,7 @@
Most of the files are
:Copyright: This stylesheet has been placed in the public domain.
- Copyright (C) 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
- Copyright (C) 2019-Today GRAP (http://www.grap.coop)
- Copyright (C) 2020 - Iván Todorovich (https://twitter.com/ivan.todorovich)
+ Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
Copyright (C) 2020 - Iván Todorovich
Copyright (C) 2020 Iván Todorovich (https://twitter.com/ivantodorovich)
Copyright 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)