diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..bfd7ac53df9f103f6dc8853738c63fd364445fde --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# Configuration for known file extensions +[*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{json,yml,yaml,rst,md}] +indent_size = 2 + +# Do not configure editor for libs and autogenerated content +[{*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst}] +charset = unset +end_of_line = unset +indent_size = unset +indent_style = unset +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000000000000000000000000000000000000..fed88d70d23ecb3297ea28854b320c4d62ee3c26 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,188 @@ +env: + browser: true + es6: true + +# See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449 +parserOptions: + ecmaVersion: 2019 + +overrides: + - files: + - "**/*.esm.js" + parserOptions: + sourceType: module + +# Globals available in Odoo that shouldn't produce errorings +globals: + _: readonly + $: readonly + fuzzy: readonly + jQuery: readonly + moment: readonly + odoo: readonly + openerp: readonly + owl: readonly + luxon: readonly + +# Styling is handled by Prettier, so we only need to enable AST rules; +# see https://github.com/OCA/maintainer-quality-tools/pull/618#issuecomment-558576890 +rules: + accessor-pairs: warn + array-callback-return: warn + callback-return: warn + capitalized-comments: + - warn + - always + - ignoreConsecutiveComments: true + ignoreInlineComments: true + complexity: + - warn + - 15 + constructor-super: warn + dot-notation: warn + eqeqeq: warn + global-require: warn + handle-callback-err: warn + id-blacklist: warn + id-match: warn + init-declarations: error + max-depth: warn + max-nested-callbacks: warn + max-statements-per-line: warn + no-alert: warn + no-array-constructor: warn + no-caller: warn + no-case-declarations: warn + no-class-assign: warn + no-cond-assign: error + no-const-assign: error + no-constant-condition: warn + no-control-regex: warn + no-debugger: error + no-delete-var: warn + no-div-regex: warn + no-dupe-args: error + no-dupe-class-members: error + no-dupe-keys: error + no-duplicate-case: error + no-duplicate-imports: error + no-else-return: warn + no-empty-character-class: warn + no-empty-function: error + no-empty-pattern: error + no-empty: warn + no-eq-null: error + no-eval: error + no-ex-assign: error + no-extend-native: warn + no-extra-bind: warn + no-extra-boolean-cast: warn + no-extra-label: warn + no-fallthrough: warn + no-func-assign: error + no-global-assign: error + no-implicit-coercion: + - warn + - allow: ["~"] + no-implicit-globals: warn + no-implied-eval: warn + no-inline-comments: warn + no-inner-declarations: warn + no-invalid-regexp: warn + no-irregular-whitespace: warn + no-iterator: warn + no-label-var: warn + no-labels: warn + no-lone-blocks: warn + no-lonely-if: error + no-mixed-requires: error + no-multi-str: warn + no-native-reassign: error + no-negated-condition: warn + no-negated-in-lhs: error + no-new-func: warn + no-new-object: warn + no-new-require: warn + no-new-symbol: warn + no-new-wrappers: warn + no-new: warn + no-obj-calls: warn + no-octal-escape: warn + no-octal: warn + no-param-reassign: warn + no-path-concat: warn + no-process-env: warn + no-process-exit: warn + no-proto: warn + no-prototype-builtins: warn + no-redeclare: warn + no-regex-spaces: warn + no-restricted-globals: warn + no-restricted-imports: warn + no-restricted-modules: warn + no-restricted-syntax: warn + no-return-assign: error + no-script-url: warn + no-self-assign: warn + no-self-compare: warn + no-sequences: warn + no-shadow-restricted-names: warn + no-shadow: warn + no-sparse-arrays: warn + no-sync: warn + no-this-before-super: warn + no-throw-literal: warn + no-undef-init: warn + no-undef: error + no-unmodified-loop-condition: warn + no-unneeded-ternary: error + no-unreachable: error + no-unsafe-finally: error + no-unused-expressions: error + no-unused-labels: error + no-unused-vars: error + no-use-before-define: error + no-useless-call: warn + no-useless-computed-key: warn + no-useless-concat: warn + no-useless-constructor: warn + no-useless-escape: warn + no-useless-rename: warn + no-void: warn + no-with: warn + operator-assignment: [error, always] + prefer-const: warn + radix: warn + require-yield: warn + sort-imports: warn + spaced-comment: [error, always] + strict: [error, function] + use-isnan: error + valid-jsdoc: + - warn + - prefer: + arg: param + argument: param + augments: extends + constructor: class + exception: throws + func: function + method: function + prop: property + return: returns + virtual: abstract + yield: yields + preferType: + array: Array + bool: Boolean + boolean: Boolean + number: Number + object: Object + str: String + string: String + requireParamDescription: false + requireReturn: false + requireReturnDescription: false + requireReturnType: false + valid-typeof: warn + yoda: warn diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d99361a24aa02c2d19d8165c3a057b84bc575166 --- /dev/null +++ b/.gitignore @@ -0,0 +1,76 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +/.venv +/.pytest_cache +/.ruff_cache + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +*.eggs +.copier-answers.yml + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo + +# Pycharm +.idea + +# Eclipse +.settings + +# Visual Studio cache/options directory +.vs/ +.vscode + +# OSX Files +.DS_Store + +# Django stuff: +*.log + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Rope +.ropeproject + +# Sphinx documentation +docs/_build/ + +# Backup files +*~ +*.swp + +# OCA rules +!static/lib/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3efb4d9157dc36d84e372eec5fc21e7f4a417a58 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,117 @@ +exclude: | + (?x) + # NOT INSTALLABLE ADDONS + # END NOT INSTALLABLE ADDONS + # Files and folders generated by bots, to avoid loops + ^setup/|/static/description/index\.html$| + # We don't want to mess with tool-generated files + .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/| + # Maybe reactivate this when all README files include prettier ignore tags? + ^README\.md$| + # Library files can have extraneous formatting (even minimized) + /static/(src/)?lib/| + # Repos using Sphinx to generate docs don't need prettying + ^docs/_templates/.*\.html$| + # Don't bother non-technical authors with formatting issues in docs + readme/.*\.(rst|md)$| + # Ignore build and dist directories in addons + /build/|/dist/| + # You don't usually want a bot to modify your legal texts + (LICENSE.*|COPYING.*) +default_language_version: + python: python3 + node: "16.17.0" +repos: + - repo: local + hooks: + # These files are most likely copier diff rejection junks; if found, + # review them manually, fix the problem (if needed) and remove them + - id: forbidden-files + name: forbidden files + entry: found forbidden files; remove them + language: fail + files: "\\.rej$" + - id: en-po-files + name: en.po files cannot exist + entry: found a en.po file + language: fail + files: '[a-zA-Z0-9_]*/i18n/en\.po$' + - repo: https://github.com/oca/maintainer-tools + rev: f71041f22b8cd68cf7c77b73a14ca8d8cd190a60 + hooks: + # update the NOT INSTALLABLE ADDONS section above + - id: oca-update-pre-commit-excluded-addons + - id: oca-fix-manifest-website + args: ["https://le-filament.com"] + - id: oca-gen-addon-readme + args: + - --addons-dir=. + - --branch=16.0 + - --org-name=lefilament + - --repo-name=template_module + - --if-source-changed + - --keep-source-digest + - repo: https://github.com/OCA/odoo-pre-commit-hooks + rev: v0.0.25 + hooks: + - id: oca-checks-odoo-module + - id: oca-checks-po + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.7.1 + hooks: + - id: prettier + name: prettier (with plugin-xml) + additional_dependencies: + - "prettier@2.7.1" + - "@prettier/plugin-xml@2.2.0" + args: + - --plugin=@prettier/plugin-xml + files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$ + - repo: https://github.com/pre-commit/mirrors-eslint + rev: v8.24.0 + hooks: + - id: eslint + verbose: true + args: + - --color + - --fix + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + # exclude autogenerated files + exclude: /README\.rst$|\.pot?$ + - id: end-of-file-fixer + # exclude autogenerated files + exclude: /README\.rst$|\.pot?$ + - id: debug-statements + - id: fix-encoding-pragma + args: ["--remove"] + - id: check-case-conflict + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-merge-conflict + # exclude files where underlines are not distinguishable from merge conflicts + exclude: /README\.rst$|^docs/.*\.rst$ + - id: check-symlinks + - id: check-xml + - id: mixed-line-ending + args: ["--fix=lf"] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.3 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format + - repo: https://github.com/OCA/pylint-odoo + rev: v8.0.19 + hooks: + - id: pylint_odoo + name: pylint with optional checks + args: + - --rcfile=.pylintrc + - --exit-zero + verbose: true + - id: pylint_odoo + args: + - --rcfile=.pylintrc-mandatory diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000000000000000000000000000000000..71c476d4f10ac08a7333729b93705c9573d240d5 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,123 @@ + + +[MASTER] +load-plugins=pylint_odoo +score=n + +[ODOOLINT] +readme_template_url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" +manifest_required_authors=Le Filament +manifest_required_keys=license +manifest_deprecated_keys=description,active +license_allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 +valid_odoo_versions=16.0 + +[MESSAGES CONTROL] +disable=all + +# This .pylintrc contains optional AND mandatory checks and is meant to be +# loaded in an IDE to have it check everything, in the hope this will make +# optional checks more visible to contributors who otherwise never look at a +# green travis to see optional checks that failed. +# .pylintrc-mandatory containing only mandatory checks is used the pre-commit +# config as a blocking check. + +enable=anomalous-backslash-in-string, + api-one-deprecated, + api-one-multi-together, + assignment-from-none, + attribute-deprecated, + class-camelcase, + dangerous-default-value, + dangerous-view-replace-wo-priority, + development-status-allowed, + duplicate-id-csv, + duplicate-key, + duplicate-xml-fields, + duplicate-xml-record-id, + eval-referenced, + eval-used, + incoherent-interpreter-exec-perm, + license-allowed, + manifest-author-string, + manifest-deprecated-key, + manifest-required-author, + manifest-required-key, + manifest-version-format, + method-compute, + method-inverse, + method-required-super, + method-search, + openerp-exception-warning, + pointless-statement, + pointless-string-statement, + print-used, + redundant-keyword-arg, + redundant-modulename-xml, + reimported, + relative-import, + return-in-init, + rst-syntax-error, + sql-injection, + too-few-format-args, + translation-field, + translation-required, + unreachable, + use-vim-comment, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + attribute-string-redundant, + character-not-valid-in-resource-link, + consider-merging-classes-inherited, + context-overridden, + create-user-wo-reset-password, + dangerous-filter-wo-user, + dangerous-qweb-replace-wo-priority, + deprecated-data-xml-node, + deprecated-openerp-xml-node, + duplicate-po-message-definition, + except-pass, + file-not-used, + invalid-commit, + manifest-maintainers-list, + missing-newline-extrafiles, + missing-readme, + missing-return, + odoo-addons-relative-import, + old-api7-method-defined, + po-msgstr-variables, + po-syntax-error, + renamed-field-parameter, + resource-not-exist, + str-format-used, + test-folder-imported, + translation-contains-variable, + translation-positional-used, + unnecessary-utf8-coding-comment, + website-manifest-key-not-valid-uri, + xml-attribute-translatable, + xml-deprecated-qweb-directive, + xml-deprecated-tree-attribute, + external-request-timeout, + # messages that do not cause the lint step to fail + consider-merging-classes-inherited, + create-user-wo-reset-password, + dangerous-filter-wo-user, + deprecated-module, + file-not-used, + invalid-commit, + missing-manifest-dependency, + missing-newline-extrafiles, + missing-readme, + no-utf8-coding-comment, + odoo-addons-relative-import, + old-api7-method-defined, + redefined-builtin, + too-complex, + unnecessary-utf8-coding-comment + + +[REPORTS] +msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} +output-format=colorized +reports=no diff --git a/.pylintrc-mandatory b/.pylintrc-mandatory new file mode 100644 index 0000000000000000000000000000000000000000..99064933ef82c469ba5fda5b2904447c05c99dbe --- /dev/null +++ b/.pylintrc-mandatory @@ -0,0 +1,98 @@ + +[MASTER] +load-plugins=pylint_odoo +score=n + +[ODOOLINT] +readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" +manifest-required-authors=Le Filament +manifest-required-keys=license +manifest-deprecated-keys=description,active +license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 +valid-odoo-versions=16.0 + +[MESSAGES CONTROL] +disable=all + +enable=anomalous-backslash-in-string, + api-one-deprecated, + api-one-multi-together, + assignment-from-none, + attribute-deprecated, + class-camelcase, + dangerous-default-value, + dangerous-view-replace-wo-priority, + development-status-allowed, + duplicate-id-csv, + duplicate-key, + duplicate-xml-fields, + duplicate-xml-record-id, + eval-referenced, + eval-used, + incoherent-interpreter-exec-perm, + license-allowed, + manifest-author-string, + manifest-deprecated-key, + manifest-required-author, + manifest-required-key, + manifest-version-format, + method-compute, + method-inverse, + method-required-super, + method-search, + openerp-exception-warning, + pointless-statement, + pointless-string-statement, + print-used, + redundant-keyword-arg, + redundant-modulename-xml, + reimported, + relative-import, + return-in-init, + rst-syntax-error, + sql-injection, + too-few-format-args, + translation-field, + translation-required, + unreachable, + use-vim-comment, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + attribute-string-redundant, + character-not-valid-in-resource-link, + consider-merging-classes-inherited, + context-overridden, + create-user-wo-reset-password, + dangerous-filter-wo-user, + dangerous-qweb-replace-wo-priority, + deprecated-data-xml-node, + deprecated-openerp-xml-node, + duplicate-po-message-definition, + except-pass, + file-not-used, + invalid-commit, + manifest-maintainers-list, + missing-newline-extrafiles, + missing-readme, + missing-return, + odoo-addons-relative-import, + old-api7-method-defined, + po-msgstr-variables, + po-syntax-error, + renamed-field-parameter, + resource-not-exist, + str-format-used, + test-folder-imported, + translation-contains-variable, + translation-positional-used, + unnecessary-utf8-coding-comment, + website-manifest-key-not-valid-uri, + xml-attribute-translatable, + xml-deprecated-qweb-directive, + xml-deprecated-tree-attribute, + external-request-timeout + +[REPORTS] +msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} +output-format=colorized +reports=no diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000000000000000000000000000000000000..0240c75f6a4ae4550f3473ad0a5faaef022bf6c7 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,30 @@ + +target-version = "py310" +fix = true + +[lint] +extend-select = [ + "B", + "C90", + "E501", # line too long (default 88) + "I", # isort + "UP", # pyupgrade +] +exclude = ["setup/*"] + +[format] +exclude = ["setup/*"] + +[per-file-ignores] +"__init__.py" = ["F401", "I001"] # ignore unused and unsorted imports in __init__.py +"__manifest__.py" = ["B018"] # useless expression + +[isort] +section-order = ["future", "standard-library", "third-party", "odoo", "odoo-addons", "first-party", "local-folder"] + +[isort.sections] +"odoo" = ["odoo"] +"odoo-addons" = ["odoo.addons"] + +[mccabe] +max-complexity = 16 diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.rst b/README.rst old mode 100755 new mode 100644 index 31f5ec189812092afdd470ea352f2e81153d7c11..2ca61d694a386abcc4b005ddc04284cd86eeac23 --- a/README.rst +++ b/README.rst @@ -32,4 +32,3 @@ Maintainer :target: https://le-filament.com This module is maintained by Le Filament - diff --git a/__manifest__.py b/__manifest__.py old mode 100755 new mode 100644 index 0b9294fb23d1dddbff78d9e85f7aeae268641c7b..d27de1e8e9381cb1497cce0a4bea4faa89b28e25 --- a/__manifest__.py +++ b/__manifest__.py @@ -1,24 +1,28 @@ { - 'name': "Co-Savoirs - Sales", - 'summary': "Interaction Odoo - Digiforma pour les devis", - 'author': "Le Filament", - 'website': "https://www.le-filament.com", - 'version': '12.0.1.0.1', - 'license': "AGPL-3", - 'depends': ['cosavoirs_digiforma', 'sale'], - 'data': [ + "name": "Co-Savoirs - Sales", + "summary": "Interaction Odoo - Digiforma pour les devis", + "author": "Le Filament", + "website": "https://www.le-filament.com", + "version": "16.0.1.0.1", + "license": "AGPL-3", + "depends": ["cosavoirs_digiforma", "sale"], + "data": [ "security/ir.model.access.csv", # datas # views - "views/assets.xml", "views/product_template.xml", "views/sale_order.xml", # views menu # wizard ], - 'qweb': [ - 'static/src/xml/*.xml', + "qweb": [ + "static/src/xml/sessions_report.xml", ], - 'installable': True, - 'auto_install': False, + "assets": { + "web.assets_backend": [ + "cosavoirs_digiforma_sales/static/src/js/sessions_report.js", + ], + }, + "installable": True, + "auto_install": False, } diff --git a/models/digiforma_session_data.py b/models/digiforma_session_data.py index 31e48845478b37e261ee502ea09d2103833abff9..807745f0a8663d5871c4ee6fbc1d9b5b327c8ea7 100644 --- a/models/digiforma_session_data.py +++ b/models/digiforma_session_data.py @@ -1,30 +1,29 @@ -# © 2020 Le Filament (<http://www.le-filament.com>) +# Copyright 2020- Le Filament (https://le-filament.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models, fields from datetime import datetime +from odoo import fields, models + class DigiformaSession(models.Model): - _name = 'digiforma.session.data' + _name = "digiforma.session.data" _description = "Sessions digiforma créées via devis Odoo" - name = fields.Char('Nom') - digiforma_id = fields.Integer('ID Digiforma') + name = fields.Char("Nom") + digiforma_id = fields.Integer("ID Digiforma") sale_order_id = fields.Many2one( - comodel_name='sale.order', - string='Sale_order_id', - required=True) + comodel_name="sale.order", string="Sale_order_id", required=True + ) sale_order_line_id = fields.Many2one( - comodel_name='sale.order.line', - string='Sale_order_line_id', - required=True) + comodel_name="sale.order.line", string="Sale_order_line_id", required=True + ) def get_sessions_to_display(self, *all_sessions_digiforma): res_sessions = list() for odoo_session in self: for remote_session in all_sessions_digiforma: - remote_session_id = int(remote_session.get('id')) + remote_session_id = int(remote_session.get("id")) if odoo_session.digiforma_id == remote_session_id: remote_session = self.get_data_to_display(**remote_session) res_sessions.append(remote_session) @@ -32,32 +31,32 @@ class DigiformaSession(models.Model): def get_data_to_display(self, **session): dictionnary = { - 'draft': 'Projet', - 'incomplete': 'Plannification en cours', - 'ongoing': 'Plannifiée', - 'finished': 'Terminée', + "draft": "Projet", + "incomplete": "Plannification en cours", + "ongoing": "Plannifiée", + "finished": "Terminée", } for key, value in dictionnary.items(): - if session.get('pipelineState') == key: - session['pipelineState'] = { - 'key': key, - 'value': value - } - if session.get('startDate'): - session['startDate'] = \ - datetime.strptime( - session['startDate'], '%Y-%m-%d').strftime('%d/%m/%Y') - if session.get('endDate'): - session['endDate'] = \ - datetime.strptime( - session['endDate'], '%Y-%m-%d').strftime('%d/%m/%Y') - if session.get('dates'): - for date in session['dates']: - date['date'] = datetime.strptime( - date['date'], '%Y-%m-%d').strftime('%d/%m/%Y') - date['startTime'] = datetime.strptime( - date['startTime'], '%H:%M:%S').strftime('%Hh%M') - date['endTime'] = datetime.strptime( - date['endTime'], '%H:%M:%S').strftime('%-Hh%M') + if session.get("pipelineState") == key: + session["pipelineState"] = {"key": key, "value": value} + if session.get("startDate"): + session["startDate"] = datetime.strptime( + session["startDate"], "%Y-%m-%d" + ).strftime("%d/%m/%Y") + if session.get("endDate"): + session["endDate"] = datetime.strptime( + session["endDate"], "%Y-%m-%d" + ).strftime("%d/%m/%Y") + if session.get("dates"): + for date in session["dates"]: + date["date"] = datetime.strptime(date["date"], "%Y-%m-%d").strftime( + "%d/%m/%Y" + ) + date["startTime"] = datetime.strptime( + date["startTime"], "%H:%M:%S" + ).strftime("%Hh%M") + date["endTime"] = datetime.strptime( + date["endTime"], "%H:%M:%S" + ).strftime("%-Hh%M") return session diff --git a/models/product_template.py b/models/product_template.py index 6f573c28c4a396836813b69dd258a433e21776c3..5ddaee286f8c1d8f8fc4dea6242348c5b633d237 100644 --- a/models/product_template.py +++ b/models/product_template.py @@ -1,23 +1,25 @@ -# Copyright 2021 Le Filament (<http://www.le-filament.com>) +# Copyright 2021- Le Filament (https://le-filament.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import fields, models class Product(models.Model): - _inherit = 'product.template' + _inherit = "product.template" # ------------------------------------------------------ # Fields declaration # ------------------------------------------------------ is_formation_digi = fields.Boolean( - string='Est une formation Digiforma', - required=False, default=False) + string="Est une formation Digiforma", required=False, default=False + ) is_quantity_independent = fields.Boolean( - string='Formation indépendante de la quantité commandée', - required=False, default=False) + string="Formation indépendante de la quantité commandée", + required=False, + default=False, + ) is_contracted = fields.Boolean( - string='Formation réalisée en sous-traitance', - required=False, default=False) + string="Formation réalisée en sous-traitance", required=False, default=False + ) diff --git a/models/sale_order.py b/models/sale_order.py index 266a9e253e210eebe3bc289da39b70e670ccc46c..83736892373d738c0bbe35b736e07a1d47b21699 100644 --- a/models/sale_order.py +++ b/models/sale_order.py @@ -1,26 +1,26 @@ -# Copyright 2021 Le Filament (<http://www.le-filament.com>) +# Copyright 2021- Le Filament (https://le-filament.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api +from odoo import _, api, fields, models from odoo.exceptions import UserError class CoSavoirsSaleOrder(models.Model): - _name = 'sale.order' - _inherit = ['sale.order', 'digiforma.api'] + _name = "sale.order" + _inherit = ["sale.order", "digiforma.api"] # ------------------------------------------------------ # Fields declaration # ------------------------------------------------------ digiforma_session_ids = fields.One2many( - comodel_name='digiforma.session.data', - inverse_name='sale_order_id', - string='Sessions associées', - required=False) + comodel_name="digiforma.session.data", + inverse_name="sale_order_id", + string="Sessions associées", + required=False, + ) count_digiforma_session = fields.Integer( - 'Sessions digiforma associées', - compute='_compute_count_digiforma_session' + "Sessions digiforma associées", compute="_compute_count_digiforma_session" ) # ------------------------------------------------------ @@ -46,12 +46,11 @@ class CoSavoirsSaleOrder(models.Model): """ for so in self: # check if product digiforma in SOL - digi_sol = so.order_line.filtered('product_id.is_formation_digi') + digi_sol = so.order_line.filtered("product_id.is_formation_digi") if digi_sol: digiforma_partner = so.digiforma_fetch_company() if not digiforma_partner: - raise UserError( - 'Ce client n\'est pas configuré avec Digiforma') + raise UserError(_("Ce client n'est pas configuré avec Digiforma")) else: so.create_digiforma_sessions_so() return super(CoSavoirsSaleOrder, so).action_confirm() @@ -68,7 +67,9 @@ class CoSavoirsSaleOrder(models.Model): if sol.digiforma_session_ids: sessions_to_show.append( sol.digiforma_session_ids.get_sessions_to_display( - *all_sessions_digiforma)) + *all_sessions_digiforma + ) + ) return sessions_to_show def delete_digiforma_sessions_so(self): @@ -81,8 +82,7 @@ class CoSavoirsSaleOrder(models.Model): if self.digiforma_delete_sessions(session.digiforma_id): session.unlink() else: - raise UserError( - 'La suppression des sessions n\'a pas fonctionné') + raise UserError(_("La suppression des sessions n'a pas fonctionné")) # ------------------------------------------------------ # Business methods @@ -92,8 +92,9 @@ class CoSavoirsSaleOrder(models.Model): Create sessions in digiforma and sessions stored in Odoo :return: """ - so_line_digiforma = self.mapped('order_line').filtered( - lambda sol: sol.product_id.is_formation_digi) + so_line_digiforma = self.mapped("order_line").filtered( + lambda sol: sol.product_id.is_formation_digi + ) for so_line in so_line_digiforma: if len(so_line.digiforma_session_ids) == 0: product = so_line.product_id @@ -105,40 +106,43 @@ class CoSavoirsSaleOrder(models.Model): qty = int(so_line.product_uom_qty) cost = so_line.price_unit session_variables = { - 'name': - {'value': "Odoo - " + product.name}, - 'pipelineState': - {'value': "incomplete"}, - 'contracted': - {'value': True if product.is_contracted else False, - 'type': 'bool'}, - 'costs': - {'value': [{'cost': {'value': cost}, - 'costIndependant': {'value': cost}, - 'costIndividual': {'value': cost}, - 'description': {'value': 'Formation'}, - 'vat': {'value': vat} - }, ], - 'type': 'object'} + "name": {"value": "Odoo - " + product.name}, + "pipelineState": {"value": "incomplete"}, + "contracted": { + "value": True if product.is_contracted else False, + "type": "bool", + }, + "costs": { + "value": [ + { + "cost": {"value": cost}, + "costIndependant": {"value": cost}, + "costIndividual": {"value": cost}, + "description": {"value": "Formation"}, + "vat": {"value": vat}, + }, + ], + "type": "object", + }, } - for i in range(0, qty, 1): - digiforma_session_id = \ - self.digiforma_create_session(session_variables) + for _i in range(0, qty, 1): + digiforma_session_id = self.digiforma_create_session( + session_variables + ) customer_variables = { - 'companyId': - {'value': int(self.partner_id.digiforma_id)}, - 'crmStatus': - {'value': 'WON', 'type': 'enum'}, - 'trainingSessionId': - {'value': digiforma_session_id}, + "companyId": {"value": int(self.partner_id.digiforma_id)}, + "crmStatus": {"value": "WON", "type": "enum"}, + "trainingSessionId": {"value": digiforma_session_id}, } self.digiforma_create_customer(customer_variables) - self.env['digiforma.session.data'].create({ - 'digiforma_id': digiforma_session_id, - 'name': product.name, - 'sale_order_id': self.id, - 'sale_order_line_id': so_line.id - }).env.cr.commit() + self.env["digiforma.session.data"].create( + { + "digiforma_id": digiforma_session_id, + "name": product.name, + "sale_order_id": self.id, + "sale_order_line_id": so_line.id, + } + ).env.cr.commit() # ------------------------------------------------------ # CRUD methods (ORM overrides) @@ -148,7 +152,10 @@ class CoSavoirsSaleOrder(models.Model): for so in self: if so.digiforma_session_ids: raise UserError( - 'Vous ne pouvez pas supprimer un devis rattaché à une ' - 'ou des sessions Digiforma : \n Vous pouvez l\'annuler ' - 'ou supprimer les sessions associées.') - return super(CoSavoirsSaleOrder, self).unlink() + _( + "Vous ne pouvez pas supprimer un devis rattaché à une " + "ou des sessions Digiforma : \n Vous pouvez l'annuler " + "ou supprimer les sessions associées." + ) + ) + return super().unlink() diff --git a/models/sale_order_line.py b/models/sale_order_line.py index 88a2e30041b810f5df75d73c0b21a6398a3efa34..35db8c8ba47940661b0a7e09d167ec3a7324eb06 100644 --- a/models/sale_order_line.py +++ b/models/sale_order_line.py @@ -1,23 +1,23 @@ -# Copyright 2021 Le Filament (<http://www.le-filament.com>) +# Copyright 2021- Le Filament (https://le-filament.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models, fields, api +from odoo import _, api, fields, models from odoo.exceptions import UserError class CoSavoirsSaleOrderLine(models.Model): - _name = 'sale.order.line' - _inherit = ['sale.order.line', 'digiforma.api'] + _name = "sale.order.line" + _inherit = ["sale.order.line", "digiforma.api"] digiforma_session_ids = fields.One2many( - comodel_name='digiforma.session.data', - inverse_name='sale_order_line_id', - string='Sessions associées', - required=False) + comodel_name="digiforma.session.data", + inverse_name="sale_order_line_id", + string="Sessions associées", + required=False, + ) count_digiforma_session = fields.Integer( - 'Sessions digiforma associées', - compute='_compute_count_digiforma_session' + "Sessions digiforma associées", compute="_compute_count_digiforma_session" ) # ------------------------------------------------------ @@ -42,7 +42,9 @@ class CoSavoirsSaleOrderLine(models.Model): if self.digiforma_session_ids: sessions_to_show.append( self.digiforma_session_ids.get_sessions_to_display( - *all_sessions_digiforma)) + *all_sessions_digiforma + ) + ) return sessions_to_show @@ -56,8 +58,7 @@ class CoSavoirsSaleOrderLine(models.Model): if self.digiforma_delete_sessions(session.digiforma_id): session.unlink() else: - raise UserError( - 'La suppression des sessions n\'a pas fonctionné') + raise UserError(_("La suppression des sessions n'a pas fonctionné")) # ------------------------------------------------------ # CRUD methods (ORM overrides) @@ -67,7 +68,10 @@ class CoSavoirsSaleOrderLine(models.Model): for sol in self: if sol.digiforma_session_ids: raise UserError( - 'Vous ne pouvez pas supprimer une ligne de commandes' - ' rattachée à une ou des sessions Digiforma : \n Vous ' - 'pouvez supprimer les sessions associées.') - return super(CoSavoirsSaleOrderLine, self).unlink() + _( + "Vous ne pouvez pas supprimer une ligne de commandes" + " rattachée à une ou des sessions Digiforma : \n Vous " + "pouvez supprimer les sessions associées." + ) + ) + return super().unlink() diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv old mode 100755 new mode 100644 diff --git a/static/description/icon.png b/static/description/icon.png old mode 100755 new mode 100644 diff --git a/static/src/js/sessions_report.js b/static/src/js/sessions_report.js index a3d0ef0bfca167a3daa1ba620a6d9700f567dc79..a4f32adb36661aa70cc8c557fcbde47006a47def 100644 --- a/static/src/js/sessions_report.js +++ b/static/src/js/sessions_report.js @@ -1,50 +1,42 @@ -// © 2021 Le Filament (<http://www.le-filament.com>) +// Copyright 2021- Le Filament (https://le-filament.com) // License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -odoo.define('cosavoirs_digiforma_sales.sessions_report', function (require) { - "use strict"; - - var core = require('web.core'); - var session = require('web.session'); - var AbstractAction = require('web.AbstractAction'); - var QWeb = core.qweb; - - var SessionsReport = AbstractAction.extend({ - template: 'Sessions', - - init: function(parent, params) { - var result = this._super.apply(this, arguments); - this.model = params.context.active_model; - this.action = params.context.action; - this.active_id = params.context.active_id; - return result; - }, - - willStart: function() { - var deferred = new jQuery.Deferred(); - var self = this; - this.values = {}; - - console.log(this) - this._rpc({ - model: self.model, - method: self.action, - args: [self.active_id], - }) - .then(function(results) { - console.log(results); - self.values = results; - deferred.resolve(); - }); - return jQuery.when(this._super.apply(this, arguments),deferred); - }, - - start: function() { - }, - - }); - - core.action_registry.add('cosavoirs_digiforma_sales.sessions_report', SessionsReport); - - +odoo.define("cosavoirs_digiforma_sales.sessions_report", function (require) { + "use strict"; + + var core = require("web.core"); + var AbstractAction = require("web.AbstractAction"); + + var SessionsReport = AbstractAction.extend({ + template: "Sessions", + + init: function (parent, params) { + var result = this._super.apply(this, arguments); + this.model = params.context.active_model; + this.action = params.context.action; + this.active_id = params.context.active_id; + return result; + }, + + willStart: function () { + var deferred = new jQuery.Deferred(); + var self = this; + this.values = {}; + + this._rpc({ + model: self.model, + method: self.action, + args: [self.active_id], + }).then(function (results) { + self.values = results; + deferred.resolve(); + }); + return jQuery.when(this._super.apply(this, arguments), deferred); + }, + }); + + core.action_registry.add( + "cosavoirs_digiforma_sales.sessions_report", + SessionsReport + ); }); diff --git a/static/src/xml/sessions_report.xml b/static/src/xml/sessions_report.xml index efca5a781d61ce3d8f6078ec54f58927ed0b910c..f777b24bc07e0d96ae1548c6ea9297d53e113572 100644 --- a/static/src/xml/sessions_report.xml +++ b/static/src/xml/sessions_report.xml @@ -1,74 +1,81 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>) - License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> +<?xml version="1.0" encoding="UTF-8" ?> +<!-- Copyright 2021- Le Filament (https://le-filament.com) +License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <templates xml:space="preserve"> - <t t-name="Sessions"> - <div class="container"> + <t t-name="Sessions"> + <div class="container"> - <t t-foreach="widget.values" t-as="sessions_by_order_line"> - <ul class="list-group"> + <t t-foreach="widget.values" t-as="sessions_by_order_line"> + <ul class="list-group"> - <t t-foreach="sessions_by_order_line" t-as="session"> - <div t-att-class="'btn alert ' + - (session.pipelineState.key != 'finished' ? ' alert-primary' : '') + - (session.pipelineState.key == 'finished' ? ' alert-success' : '') - " role="alert" - data-toggle="collapse" t-attf-href="#container_{{ session.id }}" aria-expanded="true"> - <div class="row" style="white-space: normal;"> - <div class="col-4 font-weight-bold"> - <t t-esc="session.name"/> - </div> - <div class="col-2"> - <t t-esc="session.pipelineState.value"/> - </div> - <div class="col-2"> - <t t-if="session.contracted == true"> - En sous-traitance - </t> - <t t-if="session.contracted == false"> - En interne - </t> - </div> - <div class="col-3"> - <t t-if="session.startDate"> - <t t-esc="session.startDate"/> - </t> - <t t-if="session.endDate"> - - <t t-esc="session.endDate"/> - </t> - </div> - <div class="col-1 text-uppercase"> - <t t-esc="session.type"/> - </div> - </div> - </div> + <t t-foreach="sessions_by_order_line" t-as="session"> + <div + t-att-class="'btn alert ' + + (session.pipelineState.key != 'finished' ? ' alert-primary' : '') + + (session.pipelineState.key == 'finished' ? ' alert-success' : '') + " + role="alert" + data-toggle="collapse" + t-attf-href="#container_{{ session.id }}" + aria-expanded="true" + > + <div class="row" style="white-space: normal;"> + <div class="col-4 font-weight-bold"> + <t t-esc="session.name" /> + </div> + <div class="col-2"> + <t t-esc="session.pipelineState.value" /> + </div> + <div class="col-2"> + <t t-if="session.contracted == true"> + En sous-traitance + </t> + <t t-if="session.contracted == false"> + En interne + </t> + </div> + <div class="col-3"> + <t t-if="session.startDate"> + <t t-esc="session.startDate" /> + </t> + <t t-if="session.endDate"> + - <t t-esc="session.endDate" /> + </t> + </div> + <div class="col-1 text-uppercase"> + <t t-esc="session.type" /> + </div> + </div> + </div> - <div class="container show" t-attf-id="container_{{ session.id }}"> - <ul class="list-group mb-3"> - <t t-foreach="session.dates" t-as="date"> - <li class="list-group-item"> - <div class="row"> - <div class="col-2"> - <t t-esc="date.subsession.name"/> - </div> - <div class="col-2"> - <t t-esc="date.date"/> - </div> - <div class="col-2"> - <t t-esc="date.startTime"/> - <t t-esc="date.endTime"/> - </div> - </div> - </li> - </t> - </ul> - </div> + <div class="container show" t-attf-id="container_{{ session.id }}"> + <ul class="list-group mb-3"> + <t t-foreach="session.dates" t-as="date"> + <li class="list-group-item"> + <div class="row"> + <div class="col-2"> + <t t-esc="date.subsession.name" /> + </div> + <div class="col-2"> + <t t-esc="date.date" /> + </div> + <div class="col-2"> + <t t-esc="date.startTime" /> - <t + t-esc="date.endTime" + /> + </div> + </div> + </li> + </t> + </ul> + </div> - </t> - </ul> - </t> + </t> + </ul> + </t> - </div> - </t> + </div> + </t> </templates> diff --git a/views/assets.xml b/views/assets.xml deleted file mode 100644 index bdc2b85c9a62f3c641770b590e33f3f8bd35a3f6..0000000000000000000000000000000000000000 --- a/views/assets.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>) - License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> -<odoo> - <data> - - <template id="cosavoirs_assets_backend" inherit_id="web.assets_backend"> - <xpath expr="." position="inside"> - - <script type="text/javascript" src="/cosavoirs_digiforma_sales/static/src/js/sessions_report.js"/> - - </xpath> - </template> - - </data> -</odoo> diff --git a/views/product_template.xml b/views/product_template.xml old mode 100755 new mode 100644 index b0be4715bdebd874fb13437aafa55bcc273c8af2..fd17fd0f23919e1e3b3457234b982a9539ea6a27 --- a/views/product_template.xml +++ b/views/product_template.xml @@ -1,26 +1,34 @@ -<?xml version="1.0"?> -<!-- Copyright 2021 Le Filament +<?xml version="1.0" ?> +<!-- Copyright 2021- Le Filament (https://le-filament.com) License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> - <odoo> - <data> - <!-- FORM --> - <record id="product_template_only_form_view_inherit_cosavoirs" model="ir.ui.view"> - <field name="name">cosavoirs.product.template.form.inherit</field> - <field name="model">product.template</field> - <field name="inherit_id" ref="product.product_template_only_form_view"/> - <field name="arch" type="xml"> - - <xpath expr="//group" position="inside"> - <group col="1"> - <field name="is_formation_digi"/> - <field name="is_quantity_independent" attrs="{'invisible': [('is_formation_digi', '=', False)]}"/> - <field name="is_contracted" attrs="{'invisible': [('is_formation_digi', '=', False)]}"/> - </group> - </xpath> + <!-- FORM --> + <record + id="product_template_only_form_view_inherit_cosavoirs" + model="ir.ui.view" + > + <field name="name">cosavoirs.product.template.form.inherit</field> + <field name="model">product.template</field> + <field + name="inherit_id" + ref="product.product_template_only_form_view" + /> + <field name="arch" type="xml"> - </field> - </record> + <xpath expr="//group" position="inside"> + <group col="1"> + <field name="is_formation_digi" /> + <field + name="is_quantity_independent" + attrs="{'invisible': [('is_formation_digi', '=', False)]}" + /> + <field + name="is_contracted" + attrs="{'invisible': [('is_formation_digi', '=', False)]}" + /> + </group> + </xpath> - </data> + </field> + </record> </odoo> diff --git a/views/sale_order.xml b/views/sale_order.xml index fecff1a7c30edb67a7d33d0298dd3b0c36998e94..b677a5b3e14453557857ec93bd1066395aa78a21 100644 --- a/views/sale_order.xml +++ b/views/sale_order.xml @@ -1,54 +1,77 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2021 Le Filament +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright 2021- Le Filament (https://le-filament.com) License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <odoo> - <data> + <record id="report_digiforma_sessions_so" model="ir.actions.client"> + <field name="name">Session(s) Digiforma associée(s) au devis</field> + <field name="tag">cosavoirs_digiforma_sales.sessions_report</field> + <field name="target">new</field> + <field name="context">{'action': 'show_digiforma_sessions_so'}</field> + </record> - <record id="report_digiforma_sessions_so" model="ir.actions.client"> - <field name="name">Session(s) Digiforma associée(s) au devis</field> - <field name="tag">cosavoirs_digiforma_sales.sessions_report</field> - <field name="target">new</field> - <field name="context">{'action': 'show_digiforma_sessions_so'}</field> - </record> + <record id="report_digiforma_sessions_sol" model="ir.actions.client"> + <field + name="name" + >Session(s) Digiforma associée(s) à la ligne de commande</field> + <field name="tag">cosavoirs_digiforma_sales.sessions_report</field> + <field name="target">new</field> + <field name="context">{'action': 'show_digiforma_sessions_sol'}</field> + </record> - <record id="report_digiforma_sessions_sol" model="ir.actions.client"> - <field name="name">Session(s) Digiforma associée(s) à la ligne de commande</field> - <field name="tag">cosavoirs_digiforma_sales.sessions_report</field> - <field name="target">new</field> - <field name="context">{'action': 'show_digiforma_sessions_sol'}</field> - </record> - - <record id="sale_view_order_form_inherit_cosavoirs" model="ir.ui.view"> - <field name="name">cosavoirs.sale.order.form</field> - <field name="model">sale.order</field> - <field name="inherit_id" ref="sale.view_order_form"/> - <field name="arch" type="xml"> - <xpath expr="//header" position="inside"> - <button name="delete_digiforma_sessions_so" type="object" - string="Supprimer les sessions Digiforma" icon="fa-trash" - attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" - confirm="Êtes-vous sûr de vouloir supprimer les sessions sur Digiforma ?"/> - </xpath> - <xpath expr="//sheet/div[@name='button_box']" position="inside"> - <button class="oe_stat_button" type="action" name="cosavoirs_digiforma_sales.report_digiforma_sessions_so" - icon="fa-calendar" attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" - help="Nombre des sessions associées sur Digiforma"> - <div class="o_stat_info"> - <field name="count_digiforma_session" class="o_stat_value"/> - <span class="o_stat_text">Digiforma</span> - </div> - </button> - </xpath> - <xpath expr="//page[@name='order_lines']//field[@name='order_line']//tree" position="inside"> - <button name="cosavoirs_digiforma_sales.report_digiforma_sessions_sol" type="action" string="Voir les sessions Digiforma" - icon="fa-eye" attrs="{'invisible': [('count_digiforma_session', '=', 0)]}"/> - <field name="count_digiforma_session" invisible="1"/> - <button name="delete_digiforma_sessions_sol" type="object" string="Supprimer les sessions Digiforma" - icon="fa-times" attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" - confirm="Êtes-vous sûr de vouloir supprimer les sessions sur Digiforma ?"/> - </xpath> - </field> - </record> - - </data> -</odoo> \ No newline at end of file + <record id="sale_view_order_form_inherit_cosavoirs" model="ir.ui.view"> + <field name="name">cosavoirs.sale.order.form</field> + <field name="model">sale.order</field> + <field name="inherit_id" ref="sale.view_order_form" /> + <field name="arch" type="xml"> + <xpath expr="//header" position="inside"> + <button + name="delete_digiforma_sessions_so" + type="object" + string="Supprimer les sessions Digiforma" + icon="fa-trash" + attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" + confirm="Êtes-vous sûr de vouloir supprimer les sessions sur Digiforma ?" + /> + </xpath> + <xpath expr="//sheet/div[@name='button_box']" position="inside"> + <button + class="oe_stat_button" + type="action" + name="cosavoirs_digiforma_sales.report_digiforma_sessions_so" + icon="fa-calendar" + attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" + help="Nombre des sessions associées sur Digiforma" + > + <div class="o_stat_info"> + <field + name="count_digiforma_session" + class="o_stat_value" + /> + <span class="o_stat_text">Digiforma</span> + </div> + </button> + </xpath> + <xpath + expr="//page[@name='order_lines']//field[@name='order_line']//tree" + position="inside" + > + <button + name="cosavoirs_digiforma_sales.report_digiforma_sessions_sol" + type="action" + string="Voir les sessions Digiforma" + icon="fa-eye" + attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" + /> + <field name="count_digiforma_session" invisible="1" /> + <button + name="delete_digiforma_sessions_sol" + type="object" + string="Supprimer les sessions Digiforma" + icon="fa-times" + attrs="{'invisible': [('count_digiforma_session', '=', 0)]}" + confirm="Êtes-vous sûr de vouloir supprimer les sessions sur Digiforma ?" + /> + </xpath> + </field> + </record> +</odoo>