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..d4cc423ccda9db9691205c9da83307af97b2670f --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,187 @@ +env: + browser: true + es6: true + +# See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449 +parserOptions: + ecmaVersion: 2017 + +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 + +# 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/.flake8 b/.flake8 new file mode 100644 index 0000000000000000000000000000000000000000..e397e8ed4e3e7f7fe7785dd391bb80aa6d85575e --- /dev/null +++ b/.flake8 @@ -0,0 +1,12 @@ +[flake8] +max-line-length = 88 +max-complexity = 16 +# B = bugbear +# B9 = bugbear opinionated (incl line length) +select = C,E,F,W,B,B9 +# E203: whitespace before ':' (black behaviour) +# E501: flake8 line length (covered by bugbear B950) +# W503: line break before binary operator (black behaviour) +ignore = E203,E501,W503 +per-file-ignores= + __init__.py:F401 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..818770fb1bdc0a144e924c9a5940f0b035df8a0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +/.venv +/.pytest_cache + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +*.eggs + +# 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/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0ec187efd1bf802844749f508cda0c8f138970f9 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,13 @@ +[settings] +; see https://github.com/psf/black +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +combine_as_imports=True +use_parentheses=True +line_length=88 +known_odoo=odoo +known_odoo_addons=odoo.addons +sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER +default_section=THIRDPARTY +ensure_newline_before_comments = True diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8a5999af4419f630dda23d9366b51967b8322ed3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,127 @@ +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$| + # You don't usually want a bot to modify your legal texts + (LICENSE.*|COPYING.*) +default_language_version: + python: python3 + node: "14.13.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$" + - repo: https://github.com/oca/maintainer-tools + rev: ab1d7f6 + 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"] + - repo: https://github.com/myint/autoflake + rev: v1.4 + hooks: + - id: autoflake + args: + - --expand-star-imports + - --ignore-init-module-imports + - --in-place + - --remove-all-unused-imports + - --remove-duplicate-keys + - --remove-unused-variables + - repo: https://github.com/psf/black + rev: 20.8b1 + hooks: + - id: black + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.1.2 + hooks: + - id: prettier + name: prettier (with plugin-xml) + additional_dependencies: + - "prettier@2.1.2" + - "@prettier/plugin-xml@0.12.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: v7.8.1 + hooks: + - id: eslint + verbose: true + args: + - --color + - --fix + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.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/asottile/pyupgrade + rev: v2.7.2 + hooks: + - id: pyupgrade + args: ["--keep-percent-format"] + - repo: https://github.com/PyCQA/isort + rev: 5.5.1 + hooks: + - id: isort + name: isort except __init__.py + args: + - --settings=. + exclude: /__init__\.py$ + - repo: https://gitlab.com/PyCQA/flake8 + rev: 3.8.3 + hooks: + - id: flake8 + name: flake8 + additional_dependencies: ["flake8-bugbear==20.1.4"] + - repo: https://github.com/PyCQA/pylint + rev: pylint-2.5.3 + hooks: + - id: pylint + name: pylint with optional checks + args: + - --rcfile=.pylintrc + - --exit-zero + verbose: true + additional_dependencies: &pylint_deps + - pylint-odoo==3.5.0 + - id: pylint + name: pylint with mandatory checks + args: + - --rcfile=.pylintrc-mandatory + additional_dependencies: *pylint_deps diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000000000000000000000000000000000000..5b6d4b361ace92f3877993bf2848fac190d8fab6 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,8 @@ +# Defaults for all prettier-supported languages. +# Prettier will complete this with settings from .editorconfig file. +bracketSpacing: false +printWidth: 88 +proseWrap: always +semi: true +trailingComma: "es5" +xmlWhitespaceSensitivity: "strict" diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000000000000000000000000000000000..542c686d3824ecbc48c169d1bf3b146afb2acb70 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,87 @@ +[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=13.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, + # 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, + 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..74be5fff287bdab1da64e3e5a2ad43a99999e1cc --- /dev/null +++ b/.pylintrc-mandatory @@ -0,0 +1,64 @@ +[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=13.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 + +[REPORTS] +msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} +output-format=colorized +reports=no diff --git a/README.rst b/README.rst index b2712b0899e75997cf0655dc8fe321ea21ed73a9..6bf29538b7e791359faf9527a0f44ca3db096a28 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ CG SCOP - Calendar Description =========== -Ce module permet hérite le module *calendar* d'Odoo pour ajouter les fonctionnalités suivantes : +Ce module permet hérite le module *calendar* d'Odoo pour ajouter les fonctionnalités suivantes : * ajout de champs spécifiques à la CG Scop * modification de l'ajout d'un évènement diff --git a/__init__.py b/__init__.py index bf853b2cb717d382cf347fbce0e83b0b651435fa..e3bc617b1241f1778644d22df337206bd4c8f6fd 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,4 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from . import models -from . import wizard +from . import models, wizard diff --git a/__manifest__.py b/__manifest__.py index eeee44603c7574d073a04e8559b1e0fd917ece16..3a27a6f57af77f532dc23f2209a9650411dcda0f 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -1,16 +1,16 @@ { "name": "CG SCOP - Agenda", "summary": "Adaptation agenda pour la CG Scop", - "version": "12.0.1.2.0", + "version": "13.0.1.0.0", "development_status": "Production/Stable", "author": "Le Filament", "license": "AGPL-3", "application": False, "depends": [ - 'calendar', - 'cgscop_fullcalendar', - 'cgscop_partner', - 'cgscop_timesheet', + "calendar", + "cgscop_fullcalendar", + "cgscop_partner", + "cgscop_timesheet", ], "data": [ "security/security_rules.xml", @@ -18,9 +18,9 @@ "views/hr_timesheet.xml", "wizard/calendar_event_transform.xml", ], - 'qweb': [ - 'static/src/xml/*.xml', + "qweb": [ + "static/src/xml/*.xml", ], - 'installable': True, - 'auto_install': False, + "installable": True, + "auto_install": False, } diff --git a/models/__init__.py b/models/__init__.py index d014ecac84b3ef4546616be335d35937e71eecaa..846e6a1fcf0a99390d1598eabea77763f029f170 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -3,4 +3,3 @@ from . import calendar from . import hr_timesheet - diff --git a/models/calendar.py b/models/calendar.py index 1ca38218a3d9235723eceaa30b42726564859ff2..a56833c51995e84ea9cf1b7086dc788dfbafe7a7 100644 --- a/models/calendar.py +++ b/models/calendar.py @@ -2,112 +2,125 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from datetime import timedelta + import pytz -from odoo import models, fields, api +from odoo import api, fields, models +from odoo.exceptions import UserError, ValidationError from odoo.fields import Date from odoo.tools import pycompat -from odoo.exceptions import UserError, ValidationError from odoo.addons.calendar.models.calendar import calendar_id2real_id class CGScopAttendee(models.Model): - _inherit = 'calendar.attendee' + _inherit = "calendar.attendee" timesheet_ids = fields.One2many( - comodel_name='account.analytic.line', - inverse_name='attendee_id', - string='Timesheet linked', - copy=False) + comodel_name="account.analytic.line", + inverse_name="attendee_id", + string="Timesheet linked", + copy=False, + ) class CGScopCalendar(models.Model): - _inherit = 'calendar.event' + _inherit = "calendar.event" @api.model def _default_coop_id(self): - if self.env.context.get('default_res_model') == 'res.partner': - if self.env.context.get('default_res_id'): - return self.env['res.partner'].browse( - self.env.context.get('default_res_id')) + if self.env.context.get("default_res_model") == "res.partner": + if self.env.context.get("default_res_id"): + return self.env["res.partner"].browse( + self.env.context.get("default_res_id") + ) return False - partner_ids = fields.Many2many(domain=[ - ('user_ids', '!=', False)]) + partner_ids = fields.Many2many(domain=[("user_ids", "!=", False)]) type = fields.Selection( - [('outside', 'Extérieur'), - ('ur', 'UR'), - ('training', 'Formation'), - ('teleworking', 'Télétravail'), - ('absent', 'Absence, Congés, Divers')], - string="Lieu de Réunion") + [ + ("outside", "Extérieur"), + ("ur", "UR"), + ("training", "Formation"), + ("teleworking", "Télétravail"), + ("absent", "Absence, Congés, Divers"), + ], + string="Lieu de Réunion", + ) format = fields.Selection( - [('exchange', 'Echange'), - ('meeting', 'Rendez-vous'), - ('workshop', 'Atelier'), - ('training', 'Formation'), - ('networking', 'Animation réseau')], - string="Format du rdv") + [ + ("exchange", "Echange"), + ("meeting", "Rendez-vous"), + ("workshop", "Atelier"), + ("training", "Formation"), + ("networking", "Animation réseau"), + ], + string="Format du rdv", + ) location = fields.Text() coop_id = fields.Many2one( - comodel_name='res.partner', - string='Contact', - domain=[('is_company', '=', 'True')], - ondelete='set null', - default=_default_coop_id) + comodel_name="res.partner", + string="Contact", + domain=[("is_company", "=", "True")], + ondelete="set null", + default=_default_coop_id, + ) project_id = fields.Many2one( comodel_name="project.project", string="Code Activité UR", - domain=[('allow_timesheets', '=', True)]) + domain=[("allow_timesheets", "=", True)], + ) cgscop_timesheet_code_id = fields.Many2one( - related='project_id.cgscop_timesheet_code_id', - string='Code Activité National', - store=True) + related="project_id.cgscop_timesheet_code_id", + string="Code Activité National", + store=True, + ) ur_financial_system_id = fields.Many2one( - comodel_name='ur.financial.system', - string='Dispositif Financier') + comodel_name="ur.financial.system", string="Dispositif Financier" + ) ur_regional_convention_id = fields.Many2one( - comodel_name='ur.regional.convention', - string='Convention Régionale') + comodel_name="ur.regional.convention", string="Convention Régionale" + ) ur_id = fields.Many2one( - 'union.regionale', - string='Union Régionale', + "union.regionale", + string="Union Régionale", index=True, - ondelete='restrict', - compute='_compute_ur_id', - store=True) + ondelete="restrict", + compute="_compute_ur_id", + store=True, + ) ur_financial_system_nb = fields.Integer( - string="Nb Dispositifs Financiers", - compute="_compute_ur_system_nb") + string="Nb Dispositifs Financiers", compute="_compute_ur_system_nb" + ) ur_regional_convention_nb = fields.Integer( - string="Nb conventions régionales", - compute="_compute_ur_system_nb") + string="Nb conventions régionales", compute="_compute_ur_system_nb" + ) attendees_initial = fields.Char( - string='Initiales Participants', - compute='_compute_attendees_initial') + string="Initiales Participants", compute="_compute_attendees_initial" + ) state = fields.Selection( - [('needsAction', 'Non répondu'), - ('tentative', 'Incertain'), - ('declined', 'Refusé'), - ('accepted', 'Accepté')], - string='Statut', - compute='_compute_attendee_state', + [ + ("needsAction", "Non répondu"), + ("tentative", "Incertain"), + ("declined", "Refusé"), + ("accepted", "Accepté"), + ], + string="Statut", + compute="_compute_attendee_state", help="Statut du participant", - default='needsAction') + default="needsAction", + ) is_attendee = fields.Boolean( - string='Est participant', - compute='_compute_is_attendee', - default=False) + string="Est participant", compute="_compute_is_attendee", default=False + ) is_transfered = fields.Boolean( - string='Transféré', - compute='_compute_is_transfered', - default=False) + string="Transféré", compute="_compute_is_transfered", default=False + ) # ------------------------------------------------------ # Compute # ------------------------------------------------------ - @api.depends('user_id') + @api.depends("user_id") def _compute_ur_id(self): for event in self: # affecte l'id UR du user pour la gestion @@ -115,35 +128,37 @@ class CGScopCalendar(models.Model): # sur son UR actuelle event.ur_id = event.user_id.ur_id - @api.depends('ur_id') + @api.depends("ur_id") def _compute_ur_system_nb(self): for event in self: # Calcul nombre de dispositifs financiers - financial_system = event.env['ur.financial.system'].search([ - ('ur_id', '=', event.ur_id.id)]) - event.ur_financial_system_nb = len( - financial_system) + financial_system = event.env["ur.financial.system"].search( + [("ur_id", "=", event.ur_id.id)] + ) + event.ur_financial_system_nb = len(financial_system) # Calcul nombre de conventions - regional_convention = event.env['ur.regional.convention'].search([ - ('ur_id', '=', event.ur_id.id)]) - event.ur_regional_convention_nb = len( - regional_convention) + regional_convention = event.env["ur.regional.convention"].search( + [("ur_id", "=", event.ur_id.id)] + ) + event.ur_regional_convention_nb = len(regional_convention) - @api.depends('partner_ids') + @api.depends("partner_ids") def _compute_attendees_initial(self): for event in self: - initials = '' + initials = "" for partner in event.partner_ids: - if ((partner.lastname) and (partner.firstname)): - initials += (partner.lastname[0] + '.' + partner.firstname[0] - + ', ') + if (partner.lastname) and (partner.firstname): + initials += partner.lastname[0] + "." + partner.firstname[0] + ", " event.attendees_initial = initials def _compute_attendee_state(self): for event in self: - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', event.id), - ('partner_id', '=', self.env.user.partner_id.id)]) + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", event.id), + ("partner_id", "=", self.env.user.partner_id.id), + ] + ) event.state = attendee.state def _compute_is_attendee(self): @@ -155,14 +170,17 @@ class CGScopCalendar(models.Model): def _compute_is_transfered(self): for event in self: - event_id = event.get_metadata()[0].get('id') - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', event_id), - ('partner_id', '=', self.env.user.partner_id.id)]) + event_id = event.get_metadata()[0].get("id") + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", event_id), + ("partner_id", "=", self.env.user.partner_id.id), + ] + ) # l'attendee a des feuilles de temps liées à la même date - if (attendee.timesheet_ids - and attendee.timesheet_ids.filtered( - lambda t: t.date == event.start.date())): + if attendee.timesheet_ids and attendee.timesheet_ids.filtered( + lambda t: t.date == event.start.date() + ): event.is_transfered = True else: event.is_transfered = False @@ -170,148 +188,169 @@ class CGScopCalendar(models.Model): # ------------------------------------------------------ # Onchange # ------------------------------------------------------ - @api.onchange('project_id') + @api.onchange("project_id") def _onchange_project_id(self): if self.project_id.partner_id: self.coop_id = self.project_id.partner_id - @api.onchange('coop_id') + @api.onchange("coop_id") def _onchange_coop_id(self): # affiche l'adresse de la coop sur le RDV context = self.env.context - address = '' + address = "" if self.coop_id.street: - address += self.coop_id.street + '\n' + address += self.coop_id.street + "\n" if self.coop_id.street2: - address += self.coop_id.street2 + '\n' + address += self.coop_id.street2 + "\n" if self.coop_id.street3: - address += self.coop_id.street3 + '\n' + address += self.coop_id.street3 + "\n" if self.coop_id.zip: - address += self.coop_id.zip + ' ' + address += self.coop_id.zip + " " if self.coop_id.city: address += self.coop_id.city self.location = address # changement dispositifs si différent de action dupliquer - if not context.get('duplicate'): + if not context.get("duplicate"): # affiche le Dispositif Financier par défaut sur le RDV # si il n'y a pas de date limite du dispositif # ou si la date du RDV est inférieure à la date limite du dispositif - if not self.coop_id.ur_financial_system_date or \ - fields.Date.to_date(self.start) <= self.coop_id.ur_financial_system_date: + if ( + not self.coop_id.ur_financial_system_date + or fields.Date.to_date(self.start) + <= self.coop_id.ur_financial_system_date + ): self.ur_financial_system_id = self.coop_id.ur_financial_system_id # affiche la Convention par défaut sur le RDV # si il n'y a pas de date limite de la convention # ou si la date du RDV est inférieure à la date limite de la convention - if not self.coop_id.ur_regional_convention_date or \ - fields.Date.to_date(self.start) <= self.coop_id.ur_regional_convention_date: - self.ur_regional_convention_id = self.coop_id.\ - ur_regional_convention_id + if ( + not self.coop_id.ur_regional_convention_date + or fields.Date.to_date(self.start) + <= self.coop_id.ur_regional_convention_date + ): + self.ur_regional_convention_id = self.coop_id.ur_regional_convention_id # ------------------------------------------------------ # Contrains # ------------------------------------------------------ - @api.constrains('project_id', 'start', 'stop') + @api.constrains("project_id", "start", "stop") def _check_activity_code(self): for event in self: if event.project_id: # Récupère les entrées en intersection # avec la plage horaire - entries = self.search([ - ('start', '<', event.stop), - ('stop', '>', event.start), - ('user_id', '=', self.env.uid), - ('project_id', '=', event.project_id.id), - ('id', '!=', event.id) - ]) + entries = self.search( + [ + ("start", "<", event.stop), + ("stop", ">", event.start), + ("user_id", "=", self.env.uid), + ("project_id", "=", event.project_id.id), + ("id", "!=", event.id), + ] + ) if entries: raise ValidationError( "Vous ne pouvez programmer 2 évènements avec le " "même code activité sur la même plage horaire\n" - "Evènement : %s" % str(entries.mapped('name'))[1:-1]) + "Evènement : %s" % str(entries.mapped("name"))[1:-1] + ) # ------------------------------------------------------ # Fonction boutons # ------------------------------------------------------ - @api.multi def do_accept(self): - """ Accepte l'invitation - Modifie le statut de la table Attendees + """Accepte l'invitation + Modifie le statut de la table Attendees """ for event in self: - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', event.id), - ('partner_id', '=', self.env.user.partner_id.id)]) - attendee.state = 'accepted' + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", event.id), + ("partner_id", "=", self.env.user.partner_id.id), + ] + ) + attendee.state = "accepted" - @api.multi def do_decline(self): - """ Refuse l'invitation - Modifie le statut de la table Attendees + """Refuse l'invitation + Modifie le statut de la table Attendees """ for event in self: - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', event.id), - ('partner_id', '=', self.env.user.partner_id.id)]) - attendee.state = 'declined' + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", event.id), + ("partner_id", "=", self.env.user.partner_id.id), + ] + ) + attendee.state = "declined" - @api.multi def do_tentative(self): - """ Incertain pour l'invitation - Modifie le statut de la table Attendees + """Incertain pour l'invitation + Modifie le statut de la table Attendees """ for event in self: - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', event.id), - ('partner_id', '=', self.env.user.partner_id.id)]) - attendee.state = 'tentative' + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", event.id), + ("partner_id", "=", self.env.user.partner_id.id), + ] + ) + attendee.state = "tentative" - @api.multi def create_timesheet(self): - """ Crée une ligne de temps à partir de l'entrée d'agenda - """ + """Crée une ligne de temps à partir de l'entrée d'agenda""" partner = self.env.user.partner_id for event in self: - event_id = event.get_metadata()[0].get('id') + event_id = event.get_metadata()[0].get("id") if partner not in event.partner_ids: - raise UserError("Vous ne faites pas partie des participants, \ + raise UserError( + "Vous ne faites pas partie des participants, \ vous ne pouvez donc pas transformer cette entrée d'agenda \ - en ligne de temps.") + en ligne de temps." + ) if not event.project_id.analytic_account_id: - raise UserError("Le code activité UR doit être \ - renseigné sur chaque entrée d'agenda") + raise UserError( + "Le code activité UR doit être \ + renseigné sur chaque entrée d'agenda" + ) else: - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', event_id), - ('partner_id', '=', partner.id)]) + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", event_id), + ("partner_id", "=", partner.id), + ] + ) # l'attendee a des feuilles de temps liées à la même date - if (attendee.timesheet_ids - and attendee.timesheet_ids.filtered( - lambda t: t.date == event.start.date())): - raise UserError("Vous avez déjà transféré cette entrée \ - d'agenda : %s" % event.name) + if attendee.timesheet_ids and attendee.timesheet_ids.filtered( + lambda t: t.date == event.start.date() + ): + raise UserError( + "Vous avez déjà transféré cette entrée \ + d'agenda : %s" + % event.name + ) else: values = { - 'user_id': self.env.user.id, - 'project_id': event.project_id.id, - 'account_id': event.project_id.analytic_account_id.id, - 'ur_financial_system_id': event.ur_financial_system_id.id, - 'ur_regional_convention_id': event.ur_regional_convention_id.id, - 'name': event.name, - 'company_id': self.env.user.company_id.id, - 'partner_id': event.coop_id.id, - 'event_id': event_id, - 'attendee_id': attendee.id, + "user_id": self.env.user.id, + "project_id": event.project_id.id, + "account_id": event.project_id.analytic_account_id.id, + "ur_financial_system_id": event.ur_financial_system_id.id, + "ur_regional_convention_id": event.ur_regional_convention_id.id, + "name": event.name, + "company_id": self.env.user.company_id.id, + "partner_id": event.coop_id.id, + "event_id": event_id, + "attendee_id": attendee.id, } # Gestion des évènements sur toute la journée if event.allday: # Création d'une ligne de 8h pour chaque jour for i in range((event.stop - event.start).days + 1): - values['date'] = event.start + timedelta(days=i) - values['unit_amount'] = 8.0 - ts = self.env['account.analytic.line'].create( - values) - attendee.write({'timesheet_id': ts.id}) + values["date"] = event.start + timedelta(days=i) + values["unit_amount"] = 8.0 + ts = self.env["account.analytic.line"].create(values) + attendee.write({"timesheet_id": ts.id}) # Gestion des évènements sur plusieurs jours non flagués # allday elif (event.stop - event.start).days > 0: @@ -322,157 +361,179 @@ class CGScopCalendar(models.Model): day = event.start + timedelta(days=i) # si premier jour calcul heures if i == 0: - end_day_tz = local.localize( - day.replace(hour=18)) + end_day_tz = local.localize(day.replace(hour=18)) start_tz = fields.Datetime.context_timestamp( - record=self.env.user, - timestamp=event.start) - hours_cal = ((end_day_tz - start_tz).seconds - // 3600) + record=self.env.user, timestamp=event.start + ) + hours_cal = (end_day_tz - start_tz).seconds // 3600 hours = hours_cal if hours_cal <= 8 else 8.0 # si dernier jour elif i == (event.stop - event.start).days: - start_day_tz = local.localize( - day.replace(hour=8)) + start_day_tz = local.localize(day.replace(hour=8)) stop_tz = fields.Datetime.context_timestamp( - record=self.env.user, - timestamp=event.stop) - hours_cal = ((stop_tz - start_day_tz).seconds - // 3600) + record=self.env.user, timestamp=event.stop + ) + hours_cal = (stop_tz - start_day_tz).seconds // 3600 hours = hours_cal if hours_cal <= 8 else 8.0 else: hours = 8.0 - values['date'] = day - values['unit_amount'] = hours - ts = self.env['account.analytic.line'].create( - values) - attendee.write({'timesheet_id': ts.id}) + values["date"] = day + values["unit_amount"] = hours + ts = self.env["account.analytic.line"].create(values) + attendee.write({"timesheet_id": ts.id}) # Gestion des évènements classiques else: - values['date'] = event.start - values['unit_amount'] = event.duration - ts = self.env['account.analytic.line'].create(values) - attendee.write({'timesheet_id': ts.id}) + values["date"] = event.start + values["unit_amount"] = event.duration + ts = self.env["account.analytic.line"].create(values) + attendee.write({"timesheet_id": ts.id}) - @api.multi def duplicate_entry(self): """ - Duplique la ligne de temps + Duplique la ligne de temps """ for event in self: return { - 'type': 'ir.actions.act_window', - 'res_model': 'calendar.event', - 'view_type': 'form', - 'view_mode': 'form', - 'target': 'new', - 'context': { - 'default_project_id': event.project_id.id, - 'default_name': event.name, - 'default_coop_id': event.coop_id.id, - 'default_partner_ids': event.partner_ids.ids, - 'default_start': event.start, - 'default_duration': event.duration, - 'default_stop': event.stop, - 'default_allday': event.allday, - 'default_type': event.type, - 'default_format': event.format, - 'default_ur_id': event.ur_id.id, - 'default_ur_financial_system_id': event.ur_financial_system_id.id, - 'default_ur_regional_convention_id': event.ur_regional_convention_id.id, - 'duplicate': True + "type": "ir.actions.act_window", + "res_model": "calendar.event", + "view_type": "form", + "view_mode": "form", + "target": "new", + "context": { + "default_project_id": event.project_id.id, + "default_name": event.name, + "default_coop_id": event.coop_id.id, + "default_partner_ids": event.partner_ids.ids, + "default_start": event.start, + "default_duration": event.duration, + "default_stop": event.stop, + "default_allday": event.allday, + "default_type": event.type, + "default_format": event.format, + "default_ur_id": event.ur_id.id, + "default_ur_financial_system_id": event.ur_financial_system_id.id, + "default_ur_regional_convention_id": event.ur_regional_convention_id.id, + "duplicate": True, }, } # ------------------------------------------------------ # Override ORM # ------------------------------------------------------ - @api.multi - def read(self, fields=None, load='_classic_read'): - """ Surcharge la fonction read de calendar pour gérer le transfert des - lignes de temps sur les virtual events. + def read(self, fields=None, load="_classic_read"): + """Surcharge la fonction read de calendar pour gérer le transfert des + lignes de temps sur les virtual events. - Ajoute le calcul de la valeur du champs 'is_transfered' dans la - boucle 'for calendar_id, real_id in select' + Ajoute le calcul de la valeur du champs 'is_transfered' dans la + boucle 'for calendar_id, real_id in select' """ if not fields: fields = list(self._fields) fields2 = fields and fields[:] - EXTRAFIELDS = ('privacy', 'user_id', 'duration', 'allday', 'start', - 'rrule') + EXTRAFIELDS = ( + "privacy", + "user_id", + "duration", + "allday", + "start", + "rrule", + ) for f in EXTRAFIELDS: if fields and (f not in fields): fields2.append(f) select = [(x, calendar_id2real_id(x)) for x in self.ids] real_events = self.browse([real_id for calendar_id, real_id in select]) - real_data = super(CGScopCalendar, real_events).read(fields=fields2, - load=load) - real_data = dict((d['id'], d) for d in real_data) + real_data = super(CGScopCalendar, real_events).read(fields=fields2, load=load) + real_data = {d["id"]: d for d in real_data} result = [] for calendar_id, real_id in select: if not real_data.get(real_id): continue res = real_data[real_id].copy() - ls = calendar_id2real_id(calendar_id, with_date=res - and res.get('duration', 0) > 0 - and res.get('duration') or 1) - if not isinstance(ls, (pycompat.string_types, - pycompat.integer_types)) and len(ls) >= 2: - res['start'] = ls[1] - res['stop'] = ls[2] - - if res['allday']: - res['start_date'] = ls[1] - res['stop_date'] = ls[2] + ls = calendar_id2real_id( + calendar_id, + with_date=res + and res.get("duration", 0) > 0 + and res.get("duration") + or 1, + ) + if not isinstance(ls, (str, int)) and len(ls) >= 2: + res["start"] = ls[1] + res["stop"] = ls[2] + + if res["allday"]: + res["start_date"] = ls[1] + res["stop_date"] = ls[2] else: - res['start_datetime'] = ls[1] - res['stop_datetime'] = ls[2] - - if 'display_time' in fields: - res['display_time'] = self._get_display_time( - ls[1], ls[2], res['duration'], res['allday']) - - attendee = self.env['calendar.attendee'].search([ - ('event_id', '=', ls[0]), - ('partner_id', '=', self.env.user.partner_id.id)]) + res["start_datetime"] = ls[1] + res["stop_datetime"] = ls[2] + + if "display_time" in fields: + res["display_time"] = self._get_display_time( + ls[1], ls[2], res["duration"], res["allday"] + ) + + attendee = self.env["calendar.attendee"].search( + [ + ("event_id", "=", ls[0]), + ("partner_id", "=", self.env.user.partner_id.id), + ] + ) # l'attendee a des feuilles de temps liées à la même date - if (attendee.timesheet_ids - and attendee.timesheet_ids.filtered( - lambda t: t.date == Date.to_date(ls[1]))): - res['is_transfered'] = True + if attendee.timesheet_ids and attendee.timesheet_ids.filtered( + lambda t: t.date == Date.to_date(ls[1]) + ): + res["is_transfered"] = True else: - res['is_transfered'] = False + res["is_transfered"] = False - res['id'] = calendar_id + res["id"] = calendar_id result.append(res) for r in result: - if r['user_id']: - user_id = (type(r['user_id']) in (tuple, list) - and r['user_id'][0] or r['user_id']) + if r["user_id"]: + user_id = ( + type(r["user_id"]) in (tuple, list) + and r["user_id"][0] + or r["user_id"] + ) partner_id = self.env.user.partner_id.id - if user_id == (self.env.user.id - or partner_id in r.get("partner_ids", [])): + if user_id == ( + self.env.user.id or partner_id in r.get("partner_ids", []) + ): continue - if r['privacy'] == 'private': + if r["privacy"] == "private": for f in r: recurrent_fields = self._get_recurrent_fields() - public_fields = list(set(recurrent_fields - + ['id', 'allday', 'start', - 'stop', 'display_start', - 'display_stop', 'duration', - 'user_id', 'state', 'interval', - 'count', 'recurrent_id_date', - 'rrule'])) + public_fields = list( + set( + recurrent_fields + + [ + "id", + "allday", + "start", + "stop", + "display_start", + "display_stop", + "duration", + "user_id", + "state", + "interval", + "count", + "recurrent_id_date", + "rrule", + ] + ) + ) if f not in public_fields: if isinstance(r[f], list): r[f] = [] else: r[f] = False - if f == 'name': - r[f] = ('Busy') + if f == "name": + r[f] = "Busy" for r in result: for k in EXTRAFIELDS: diff --git a/models/hr_timesheet.py b/models/hr_timesheet.py index 590b2663d7eb23d7ed89bf4c48bf1499211a8441..b91af4e5adfb697ac85db42961c631cca96d81df 100644 --- a/models/hr_timesheet.py +++ b/models/hr_timesheet.py @@ -1,26 +1,31 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models, fields +from odoo import fields, models class ScopHrTimesheetCalendar(models.Model): _inherit = "account.analytic.line" event_id = fields.Many2one( - comodel_name='calendar.event', + comodel_name="calendar.event", string="Entrée d'Agenda", copy=False, - ondelete="set null") + ondelete="set null", + ) attendee_id = fields.Many2one( - comodel_name='calendar.attendee', + comodel_name="calendar.attendee", string="Invitation", copy=False, - ondelete="set null") - type_event = fields.Selection([ - ('outside', 'Extérieur'), - ('ur', 'UR'), - ('training', 'Formation'), - ('absent', 'Absence, Congés, Divers')], + ondelete="set null", + ) + type_event = fields.Selection( + [ + ("outside", "Extérieur"), + ("ur", "UR"), + ("training", "Formation"), + ("absent", "Absence, Congés, Divers"), + ], string="Type de Réunion", - related='event_id.type') + related="event_id.type", + ) diff --git a/security/security_rules.xml b/security/security_rules.xml index ab3c0484fde67f703c25713559b7122995683181..a8a2a105d90bff01a87a8bca802ae0ce5e84ab89 100644 --- a/security/security_rules.xml +++ b/security/security_rules.xml @@ -1,28 +1,27 @@ -<?xml version="1.0"?> +<?xml version="1.0" ?> <!-- Copyright 2019 Le Filament License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> - <odoo> <data> <record id="calendar_event_my_ur" model="ir.rule"> <field name="name">Calendar Event my UR</field> - <field name="model_id" ref="calendar.model_calendar_event"/> + <field name="model_id" ref="calendar.model_calendar_event" /> <field name="domain_force">[('ur_id','=',user.company_id.ur_id.id)]</field> - <field name="groups" eval="[(6, 0, [ref('base.group_user')])]"/> - <field name="perm_read" eval="True"/> - <field name="perm_write" eval="False"/> - <field name="perm_create" eval="False"/> - <field name="perm_unlink" eval="False"/> + <field name="groups" eval="[(6, 0, [ref('base.group_user')])]" /> + <field name="perm_read" eval="True" /> + <field name="perm_write" eval="False" /> + <field name="perm_create" eval="False" /> + <field name="perm_unlink" eval="False" /> </record> <record id="calendar.calendar_event_rule_my" model="ir.rule"> <field name="name">My Calendar Events</field> - <field name="model_id" ref="calendar.model_calendar_event"/> + <field name="model_id" ref="calendar.model_calendar_event" /> <field name="domain_force">[('user_id','=',user.id)]</field> - <field name="groups" eval="[(6, 0, [ref('base.group_user')])]"/> - <field name="perm_read" eval="True"/> - <field name="perm_write" eval="True"/> - <field name="perm_create" eval="True"/> - <field name="perm_unlink" eval="True"/> + <field name="groups" eval="[(6, 0, [ref('base.group_user')])]" /> + <field name="perm_read" eval="True" /> + <field name="perm_write" eval="True" /> + <field name="perm_create" eval="True" /> + <field name="perm_unlink" eval="True" /> </record> </data> </odoo> diff --git a/tests/test_event_creation.py b/tests/test_event_creation.py index f74115d404d1039f096e5d9dcd0263ddc7d19395..ddc8c76c75465d95adb4b54b98f471bd09ec66c1 100644 --- a/tests/test_event_creation.py +++ b/tests/test_event_creation.py @@ -1,33 +1,29 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import random import logging -from odoo.tests import tagged, common +from odoo.tests import common, tagged _logger = logging.getLogger(__name__) -@tagged('post_install', '-at_install') +@tagged("post_install", "-at_install") class TestEventCreation(common.TransactionCase): - def setUp(self): super(TestEventCreation, self).setUp() - self.CalendarEvent = self.env['calendar.event'] + self.CalendarEvent = self.env["calendar.event"] def test_calender_simple_event(self): - m = self.CalendarEvent.create({ - 'name': "Test compute", - 'start': '2017-07-12 14:30:00', - 'allday': False, - 'stop': '2017-07-12 15:00:00', - 'user_id': 180 - }) - - self.assertEqual( - (m.ur_id), - (m.user_id.partner_id.ur_id), - "Event UR check" + m = self.CalendarEvent.create( + { + "name": "Test compute", + "start": "2017-07-12 14:30:00", + "allday": False, + "stop": "2017-07-12 15:00:00", + "user_id": 180, + } ) + + self.assertEqual((m.ur_id), (m.user_id.partner_id.ur_id), "Event UR check") diff --git a/views/calendar.xml b/views/calendar.xml index b1e4090074ae580039d9bdf468a543954c578a35..e62c286b22e779fc07896d4871ce0b7f2928345c 100644 --- a/views/calendar.xml +++ b/views/calendar.xml @@ -1,19 +1,18 @@ -<?xml version="1.0"?> +<?xml version="1.0" ?> <!-- Copyright 2019 Le Filament License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> - <odoo> <data> - + <!-- ****************************** *** Inherited Views - ****************************** --> + ****************************** --> <!-- Agenda Tree View --> <record id="view_calendar_cooperative_tree_inherited" model="ir.ui.view"> <field name="name">calendar.event.cgscop.tree</field> <field name="model">calendar.event</field> - <field name="inherit_id" ref="calendar.view_calendar_event_tree"/> + <field name="inherit_id" ref="calendar.view_calendar_event_tree" /> <field name="arch" type="xml"> <tree position="attributes"> <attribute name="default_order">start</attribute> @@ -25,13 +24,21 @@ <attribute name="invisible">True</attribute> </field> <field name="location" position="after"> - <field name="ur_regional_convention_nb" invisible="1"/> - <field name="ur_financial_system_nb" invisible="1"/> - <field name="coop_id"/> - <field name="project_id"/> - <field name="type"/> - <field name="ur_financial_system_id" options="{'no_open': True, 'no_create': True}" attrs="{'required':[('ur_financial_system_nb', '>', 0)], 'invisible':[('ur_financial_system_nb', '<', 1)]}"/> - <field name="ur_regional_convention_id" options="{'no_open': True, 'no_create': True}" attrs="{'required':[('ur_regional_convention_nb', '>', 0)], 'invisible':[('ur_regional_convention_nb', '<', 1)]}"/> + <field name="ur_regional_convention_nb" invisible="1" /> + <field name="ur_financial_system_nb" invisible="1" /> + <field name="coop_id" /> + <field name="project_id" /> + <field name="type" /> + <field + name="ur_financial_system_id" + options="{'no_open': True, 'no_create': True}" + attrs="{'required':[('ur_financial_system_nb', '>', 0)], 'invisible':[('ur_financial_system_nb', '<', 1)]}" + /> + <field + name="ur_regional_convention_id" + options="{'no_open': True, 'no_create': True}" + attrs="{'required':[('ur_regional_convention_nb', '>', 0)], 'invisible':[('ur_regional_convention_nb', '<', 1)]}" + /> <field name="is_transfered" /> </field> </field> @@ -42,24 +49,25 @@ <record id="view_calendar_cooperative_form_inherited" model="ir.ui.view"> <field name="name">calendar.event.cgscop.form</field> <field name="model">calendar.event</field> - <field name="inherit_id" ref="calendar.view_calendar_event_form"/> + <field name="inherit_id" ref="calendar.view_calendar_event_form" /> <field name="arch" type="xml"> <!-- Header --> <sheet position="before"> <header> - <button + <button string="Dupliquer" - type="object" + type="object" name="duplicate_entry" class="oe_highlight" - /> - <button + /> + <button string="Transformer en ligne de temps" - type="object" + type="object" name="create_timesheet" class="oe_highlight" - attrs="{'invisible': - ['|', '|', '|', ('project_id', '=', False), ('coop_id', '=', False), ('is_attendee', '!=', True), ('is_transfered', '=', True)]}"/> + attrs="{'invisible': + ['|', '|', '|', ('project_id', '=', False), ('coop_id', '=', False), ('is_attendee', '!=', True), ('is_transfered', '=', True)]}" + /> </header> </sheet> <!-- Boutons --> @@ -70,18 +78,38 @@ <!-- Titre --> <div class="oe_title" position="replace"> <div class="oe_button_box" name="button_box" modifiers="{}"> - <button name="do_accept" string="Accepter" states="needsAction,tentative,declined" type="object" icon="fa-check"> + <button + name="do_accept" + string="Accepter" + states="needsAction,tentative,declined" + type="object" + icon="fa-check" + > </button> - <button name="do_decline" string="Refuser" states="needsAction,tentative,accepted" type="object" icon="fa-times-circle"/> - <button name="do_tentative" widget="boolean_button" class="oe_stat_button" states="needsAction,declined,accepted" string="Incertain" type="object" icon="fa-circle"> + <button + name="do_decline" + string="Refuser" + states="needsAction,tentative,accepted" + type="object" + icon="fa-times-circle" + /> + <button + name="do_tentative" + widget="boolean_button" + class="oe_stat_button" + states="needsAction,declined,accepted" + string="Incertain" + type="object" + icon="fa-circle" + > </button> </div> - <div class="oe_title" > + <div class="oe_title"> <div class="oe_edit_only"> - <label for="name"/> + <label for="name" /> </div> <h1> - <field name="name" placeholder="e.g. Business Lunch"/> + <field name="name" placeholder="e.g. Business Lunch" /> </h1> </div> </div> @@ -90,98 +118,181 @@ <notebook position="before"> <group name="event_info" col="1"> <group> - <field name="state"/> - <field name="is_transfered" widget="toggle_button"/> - <field name="is_attendee" invisible="1"/> - <field name="project_id" options="{'no_open': True, 'no_create': True}"/> - <field name="coop_id" options="{'no_open': True, 'no_create': True}" domain="[('ur_id', '=', ur_id),('is_company', '=', 'True')]"/> - <field name="ur_id" invisible="1"/> - <field + <field name="state" /> + <field name="is_transfered" widget="toggle_button" /> + <field name="is_attendee" invisible="1" /> + <field + name="project_id" + options="{'no_open': True, 'no_create': True}" + /> + <field + name="coop_id" + options="{'no_open': True, 'no_create': True}" + domain="[('ur_id', '=', ur_id),('is_company', '=', 'True')]" + /> + <field name="ur_id" invisible="1" /> + <field name="partner_ids" options="{'no_open': True, 'no_create': True}" widget="many2manyattendee" context="{'force_email':True}" domain="[('user_ids', '!=', False), ('ur_id', '=', ur_id)]" - /> + /> </group> <group> - <field name="start_date" string="Starting at" attrs="{'required': [('allday','=',True)], 'invisible': [('allday','=',False)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}" force_save="1"/> - <field name="stop_date" string="Ending at" attrs="{'required': [('allday','=',True)],'invisible': [('allday','=',False)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}" force_save="1"/> + <field + name="start_date" + string="Starting at" + attrs="{'required': [('allday','=',True)], 'invisible': [('allday','=',False)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}" + force_save="1" + /> + <field + name="stop_date" + string="Ending at" + attrs="{'required': [('allday','=',True)],'invisible': [('allday','=',False)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}" + force_save="1" + /> - <field name="start_datetime" string="Starting at" attrs="{'required': [('allday','=',False)], 'invisible': [('allday','=',True)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/> - <field name="stop_datetime" invisible="1"/> - <label for="duration" attrs="{'invisible': [('allday','=',True)]}"/> + <field + name="start_datetime" + string="Starting at" + attrs="{'required': [('allday','=',False)], 'invisible': [('allday','=',True)], 'readonly': [('id', '!=', False), ('recurrency','=',True)]}" + /> + <field name="stop_datetime" invisible="1" /> + <label + for="duration" + attrs="{'invisible': [('allday','=',True)]}" + /> <div attrs="{'invisible': [('allday','=',True)]}"> - <field name="duration" widget="float_time" string="Duration" class="oe_inline" attrs="{'readonly': [('id', '!=', False), ('recurrency','=',True)]}"/> + <field + name="duration" + widget="float_time" + string="Duration" + class="oe_inline" + attrs="{'readonly': [('id', '!=', False), ('recurrency','=',True)]}" + /> <span> hours</span> </div> - <field name="allday" attrs="{'readonly': [('id', '!=', False), ('recurrency','=',True)]}" force_save="1"/> - <field name="type" attrs="{'required': [('ur_id','=',%(cgscop_partner.riga_14231)d)]}"/> - <field name="format" attrs="{'invisible': [('ur_id','!=',%(cgscop_partner.riga_14231)d)]}"/> + <field + name="allday" + attrs="{'readonly': [('id', '!=', False), ('recurrency','=',True)]}" + force_save="1" + /> + <field + name="type" + attrs="{'required': [('ur_id','=',%(cgscop_partner.riga_14231)d)]}" + /> + <field + name="format" + attrs="{'invisible': [('ur_id','!=',%(cgscop_partner.riga_14231)d)]}" + /> <field name="location" /> - <field name="ur_financial_system_nb" invisible="1"/> - <field name="ur_regional_convention_nb" invisible="1"/> - <field name="ur_financial_system_id" options="{'no_open': True, 'no_create': True}" attrs="{'required':[('ur_financial_system_nb', '>', 0)], 'invisible':[('ur_financial_system_id', '=', 0)]}"/> - <field name="ur_regional_convention_id" options="{'no_open': True, 'no_create': True}" attrs="{'required':[('ur_regional_convention_nb', '>', 0)], 'invisible':[('ur_regional_convention_nb', '=', 0)]}"/> + <field name="ur_financial_system_nb" invisible="1" /> + <field name="ur_regional_convention_nb" invisible="1" /> + <field + name="ur_financial_system_id" + options="{'no_open': True, 'no_create': True}" + attrs="{'required':[('ur_financial_system_nb', '>', 0)], 'invisible':[('ur_financial_system_id', '=', 0)]}" + /> + <field + name="ur_regional_convention_id" + options="{'no_open': True, 'no_create': True}" + attrs="{'required':[('ur_regional_convention_nb', '>', 0)], 'invisible':[('ur_regional_convention_nb', '=', 0)]}" + /> </group> </group> <group string="Description du rendez-vous"> - <field name="description"/> + <field name="description" /> </group> - <group string="Informations complémentaires" name="event_extra_info"> + <group + string="Informations complémentaires" + name="event_extra_info" + > <div> <group> - <field name="alarm_ids" widget="many2many_tags" options="{'no_open': True, 'no_create': True}" /> - <field name="recurrency"/> + <field + name="alarm_ids" + widget="many2many_tags" + options="{'no_open': True, 'no_create': True}" + /> + <field name="recurrency" /> </group> <div attrs="{'invisible': [('recurrency', '=', False)]}"> <group> - <label for="interval"/> + <label for="interval" /> <div class="o_row"> - <field name="interval" attrs="{'required': [('recurrency', '=', True)]}"/> - <field name="rrule_type" attrs="{'required': [('recurrency', '=', True)]}"/> + <field + name="interval" + attrs="{'required': [('recurrency', '=', True)]}" + /> + <field + name="rrule_type" + attrs="{'required': [('recurrency', '=', True)]}" + /> </div> - <label string="Until" for="end_type"/> + <label string="Until" for="end_type" /> <div class="o_row"> - <field name="end_type" attrs="{'required': [('recurrency', '=', True)]}"/> - <field name="count" attrs="{'invisible': [('end_type', '!=', 'count')], 'required': [('recurrency', '=', True)]}"/> - <field name="final_date" attrs="{'invisible': [('end_type', '!=', 'end_date')], 'required': [('end_type', '=', 'end_date'), ('recurrency', '=', True)]}"/> + <field + name="end_type" + attrs="{'required': [('recurrency', '=', True)]}" + /> + <field + name="count" + attrs="{'invisible': [('end_type', '!=', 'count')], 'required': [('recurrency', '=', True)]}" + /> + <field + name="final_date" + attrs="{'invisible': [('end_type', '!=', 'end_date')], 'required': [('end_type', '=', 'end_date'), ('recurrency', '=', True)]}" + /> </div> </group> - <group attrs="{'invisible': [('rrule_type', '!=', 'weekly')]}" name="weekdays"> - <field name="mo"/> - <field name="tu"/> - <field name="we"/> - <field name="th"/> - <field name="fr"/> - <field name="sa"/> - <field name="su"/> + <group + attrs="{'invisible': [('rrule_type', '!=', 'weekly')]}" + name="weekdays" + > + <field name="mo" /> + <field name="tu" /> + <field name="we" /> + <field name="th" /> + <field name="fr" /> + <field name="sa" /> + <field name="su" /> </group> - <group attrs="{'invisible': [('rrule_type', '!=', 'monthly')]}"> - <label string="Day of Month" for="month_by"/> + <group + attrs="{'invisible': [('rrule_type', '!=', 'monthly')]}" + > + <label string="Day of Month" for="month_by" /> <div class="o_row"> - <field name="month_by"/> - <field name="day" + <field name="month_by" /> + <field + name="day" attrs="{'required': [('month_by', '=', 'date'), ('rrule_type', '=', 'monthly')], - 'invisible': [('month_by', '!=', 'date')]}"/> - <field name="byday" string="The" + 'invisible': [('month_by', '!=', 'date')]}" + /> + <field + name="byday" + string="The" attrs="{'required': [('recurrency', '=', True), ('month_by', '=', 'day'), ('rrule_type', '=', 'monthly')], - 'invisible': [('month_by', '!=', 'day')]}"/> - <field name="week_list" nolabel="1" + 'invisible': [('month_by', '!=', 'day')]}" + /> + <field + name="week_list" + nolabel="1" attrs="{'required': [('recurrency', '=', True), ('month_by', '=', 'day'), ('rrule_type', '=', 'monthly')], - 'invisible': [('month_by', '!=', 'day')]}"/> + 'invisible': [('month_by', '!=', 'day')]}" + /> </div> </group> </div> </div> <group> - <field name="privacy"/> - <field name="show_as"/> + <field name="privacy" /> + <field name="show_as" /> <field name="recurrent_id" invisible="1" /> </group> </group> </notebook> - + <notebook position="attributes"> <attribute name="invisible">True</attribute> </notebook> @@ -192,21 +303,28 @@ <record id="view_calendar_cooperative_calendar_inherited" model="ir.ui.view"> <field name="name">calendar.event.cgscop.calendar</field> <field name="model">calendar.event</field> - <field name="inherit_id" ref="calendar.view_calendar_event_calendar"/> + <field name="inherit_id" ref="calendar.view_calendar_event_calendar" /> <field name="arch" type="xml"> <calendar position="attributes"> <attribute name="quick_add">False</attribute> - <attribute name="readonly_form_view_id">cgscop_calendar.view_calendar_cooperative_form_inherited</attribute> + <attribute + name="form_view_id" + >cgscop_calendar.view_calendar_cooperative_form_inherited</attribute> </calendar> <field name="partner_ids" position="before"> - <field name="project_id" invisible="1"/> - <field name="ur_id" invisible="1"/> - <field name="coop_id" options="{'no_open': True, 'no_create': True}"/> - <field name="type" options="{'no_open': True, 'no_create': True}"/> - <field name="attendees_initial"/> + <field name="project_id" invisible="1" /> + <field name="ur_id" invisible="1" /> + <field + name="coop_id" + options="{'no_open': True, 'no_create': True}" + /> + <field name="type" options="{'no_open': True, 'no_create': True}" /> + <field name="attendees_initial" /> </field> <field name="partner_ids" position="attributes"> - <attribute name="domain">[('user_ids', '!=', False), ('ur_id', '=', ur_id)]</attribute> + <attribute + name="domain" + >[('user_ids', '!=', False), ('ur_id', '=', ur_id)]</attribute> </field> </field> </record> @@ -215,28 +333,53 @@ <record id="view_calendar_cooperative_search_inherited" model="ir.ui.view"> <field name="name">calendar.event.cgscop.search</field> <field name="model">calendar.event</field> - <field name="inherit_id" ref="calendar.view_calendar_event_search"/> + <field name="inherit_id" ref="calendar.view_calendar_event_search" /> <field name="arch" type="xml"> <!-- Masque étiquettes --> <field name="name" position="after"> - <field name="coop_id"/> + <field name="coop_id" /> </field> <filter name="mymeetings" position="after"> - <separator/> - <filter string="UR" name="ur" domain="[('type', '=', 'ur')]"/> - <filter string="Hors UR" name="not_ur" domain="[('type', '=', 'outside')]"/> - <filter string="Absent" name="absent" domain="[('type', '=', 'absent')]"/> - <separator/> - <filter string="Ce mois-ci" name="this_month" domain="[('start','<=', (context_today()-relativedelta(day=31, months=0)).strftime('%Y-%m-%d')), - ('start','>=',(context_today()-relativedelta(day=1,months=0)).strftime('%Y-%m-%d'))]"/> - <filter string="Le mois pécédent" name="last_month" domain="[('start','<=', (context_today()-relativedelta(day=31, months=1)).strftime('%Y-%m-%d')), - ('start','>=',(context_today()-relativedelta(day=1,months=1)).strftime('%Y-%m-%d'))]"/> - <filter string="Ce trimestre" name="this_trimester" domain="[ - ('start','>=',(context_today()-relativedelta(months=3)).strftime('%Y-%m-%d'))]" invisible="1"/> + <separator /> + <filter string="UR" name="ur" domain="[('type', '=', 'ur')]" /> + <filter + string="Hors UR" + name="not_ur" + domain="[('type', '=', 'outside')]" + /> + <filter + string="Absent" + name="absent" + domain="[('type', '=', 'absent')]" + /> + <separator /> + <filter + string="Ce mois-ci" + name="this_month" + domain="[('start','<=', (context_today()-relativedelta(day=31, months=0)).strftime('%Y-%m-%d')), + ('start','>=',(context_today()-relativedelta(day=1,months=0)).strftime('%Y-%m-%d'))]" + /> + <filter + string="Le mois pécédent" + name="last_month" + domain="[('start','<=', (context_today()-relativedelta(day=31, months=1)).strftime('%Y-%m-%d')), + ('start','>=',(context_today()-relativedelta(day=1,months=1)).strftime('%Y-%m-%d'))]" + /> + <filter + string="Ce trimestre" + name="this_trimester" + domain="[ + ('start','>=',(context_today()-relativedelta(months=3)).strftime('%Y-%m-%d'))]" + invisible="1" + /> </filter> - <filter name="privacy" position="after"> - <separator/> - <filter name="start" string="Date de début" context="{'group_by': 'start'}"/> + <filter name="privacy" position="after"> + <separator /> + <filter + name="start" + string="Date de début" + context="{'group_by': 'start'}" + /> </filter> </field> </record> @@ -250,31 +393,45 @@ <field name="name">calendar.event.cgscop.calendar</field> <field name="model">calendar.event</field> <field name="arch" type="xml"> - <resource + <resource string="Meetings" date_start="start" date_stop="stop" date_delay="duration" all_day="allday" - readonly_form_view_id="cgscop_calendar.view_calendar_cooperative_form_inherited" + form_view_id="cgscop_calendar.view_calendar_cooperative_form_inherited" event_open_popup="true" event_limit="3" color="type" quick_add="False" - resource_field='partner_ids'> + resource_field='partner_ids' + > <field name="name" /> <field name="ur_id" invisible="1" /> - <field name="coop_id" options="{'no_open': True, 'no_create': True}" /> - <field name="type" options="{'no_open': True, 'no_create': True}" /> - <field name="partner_id" options="{'no_open': True, 'no_create': True}" invisible="1"/> + <field + name="coop_id" + options="{'no_open': True, 'no_create': True}" + /> + <field + name="type" + options="{'no_open': True, 'no_create': True}" + /> + <field + name="partner_id" + options="{'no_open': True, 'no_create': True}" + invisible="1" + /> <field name="attendees_initial" /> - <field name="partner_ids" domain="[('user_ids', '!=', False), ('ur_id', '=', ur_id)]"/> + <field + name="partner_ids" + domain="[('user_ids', '!=', False), ('ur_id', '=', ur_id)]" + /> <field name="is_highlighted" invisible="1" /> </resource> </field> </record> - - + + <!-- ****************************** *** Actions ****************************** --> @@ -290,9 +447,8 @@ <field name="name">Mes Rendez-vous</field> <field name="res_model">calendar.event</field> <field name="view_mode">calendar,tree,form</field> - <field name="view_id" ref="calendar.view_calendar_event_calendar"/> - <field name="search_view_id" ref="calendar.view_calendar_event_search"/> - <field name="view_mode">calendar,tree,form</field> + <field name="view_id" ref="calendar.view_calendar_event_calendar" /> + <field name="search_view_id" ref="calendar.view_calendar_event_search" /> <field name="context">{ 'ur_sidebar_filter': True, 'search_default_mymeetings': True @@ -304,12 +460,15 @@ <field name="name">Agenda UR</field> <field name="res_model">calendar.event</field> <field name="view_mode">resource,calendar,tree,form</field> - <field name="search_view_id" ref="calendar.view_calendar_event_search"/> - <field name="view_ids" eval="[(5, 0, 0), + <field name="search_view_id" ref="calendar.view_calendar_event_search" /> + <field + name="view_ids" + eval="[(5, 0, 0), (0, 0, {'view_mode': 'resource', 'view_id': ref('view_calendar_cooperative_resource')}), (0, 0, {'view_mode': 'calendar', 'view_id': ref('calendar.view_calendar_event_calendar')}), (0, 0, {'view_mode': 'tree', 'view_id': ref('calendar.view_calendar_event_tree')}), - (0, 0, {'view_mode': 'form', 'view_id': ref('calendar.view_calendar_event_form')})]"/> + (0, 0, {'view_mode': 'form', 'view_id': ref('calendar.view_calendar_event_form')})]" + /> </record> @@ -320,21 +479,24 @@ id="mail_submenu_calendar" name="Calendrier" parent="calendar.mail_menu_calendar" - sequence="1"/> + sequence="1" + /> <menuitem id="menu_calendar_scop_all" parent="mail_submenu_calendar" name="Toutes les entrées" sequence="1" action="calendar.action_calendar_event" - groups="base.group_user"/> + groups="base.group_user" + /> <menuitem id="menu_calendar_scop_my_events" parent="mail_submenu_calendar" name="Mes rendez-vous" sequence="10" action="action_calendar_my_events" - groups="base.group_user"/> + groups="base.group_user" + /> <menuitem id="menu_calendar_scop" @@ -342,7 +504,8 @@ name="Agenda UR" sequence="2" action="action_calendar_scop" - groups="base.group_user"/> + groups="base.group_user" + /> </data> </odoo> diff --git a/views/hr_timesheet.xml b/views/hr_timesheet.xml index 4b43a7ef8e582b272d20aee9e793bb4ae5964d42..6d3a190a97f96c618b28abef6a33ecbe9e5e1104 100644 --- a/views/hr_timesheet.xml +++ b/views/hr_timesheet.xml @@ -1,9 +1,8 @@ -<?xml version="1.0"?> +<?xml version="1.0" ?> <!-- Copyright 2019 Le Filament License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> - <odoo> - <data noupdate="0"> + <data> <!-- Vues @@ -13,12 +12,15 @@ <record id="view_cgscop_hr_timesheet_calendar_line_tree" model="ir.ui.view"> <field name="name">account.analytic.line.calendar.cgscop</field> <field name="model">account.analytic.line</field> - <field name="inherit_id" ref="cgscop_timesheet.view_cgscop_hr_timesheet_line_tree"/> + <field + name="inherit_id" + ref="cgscop_timesheet.view_cgscop_hr_timesheet_line_tree" + /> <field name="arch" type="xml"> <field name="ur_financial_system_nb" position="after"> - <field name="type_event" readonly="1"/> + <field name="type_event" readonly="1" /> </field> </field> </record> </data> -</odoo> \ No newline at end of file +</odoo> diff --git a/wizard/__init__.py b/wizard/__init__.py index f78bd199843715168023c0f45dc7753437a3e1e5..ea73a94ee994f892f1a7cf4c0b520c8a70a87e6d 100644 --- a/wizard/__init__.py +++ b/wizard/__init__.py @@ -1,4 +1,4 @@ # © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from . import calendar_event_transform \ No newline at end of file +from . import calendar_event_transform diff --git a/wizard/calendar_event_transform.py b/wizard/calendar_event_transform.py index a28610c4803d611209472c1dbb997ddbefc4b92e..dc8d921c1585af70210667a3b09e49a69dbe12d0 100644 --- a/wizard/calendar_event_transform.py +++ b/wizard/calendar_event_transform.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -from odoo import models, api +from odoo import models class CalendarEventTransform(models.TransientModel): @@ -11,11 +10,10 @@ class CalendarEventTransform(models.TransientModel): _name = "calendar.event.transform" _description = "Confirm the selected calendar entries" - @api.multi def events_confirm(self): context = dict(self._context or {}) - active_ids = context.get('active_ids', []) or [] + active_ids = context.get("active_ids", []) or [] - events = self.env['calendar.event'].browse(active_ids) + events = self.env["calendar.event"].browse(active_ids) events.create_timesheet() - return {'type': 'ir.actions.act_window_close'} + return {"type": "ir.actions.act_window_close"} diff --git a/wizard/calendar_event_transform.xml b/wizard/calendar_event_transform.xml index 694d2011f4c3cf1b8a460560dac19e0950f1a2d7..51550159bddc4846deb5681077bf472b38cb36e0 100644 --- a/wizard/calendar_event_transform.xml +++ b/wizard/calendar_event_transform.xml @@ -1,6 +1,7 @@ <odoo> + <!-- Copyright 2019 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> <data> - <record id="calendar_event_transform_view" model="ir.ui.view"> <field name="name">calendar.event.transform.form</field> <field name="model">calendar.event.transform</field> @@ -11,23 +12,35 @@ Pensez à vérifier qu'un code activité UR a été renseigné pour chaque entrée. </p> <footer> - <button string="Transformer en lignes de temps" name="events_confirm" type="object" default_focus="1" class="btn-primary"/> - <button string="Cancel" class="btn-secondary" special="cancel"/> + <button + string="Transformer en lignes de temps" + name="events_confirm" + type="object" + default_focus="1" + class="btn-primary" + /> + <button + string="Cancel" + class="btn-secondary" + special="cancel" + /> </footer> </form> </field> </record> <!-- Action Multi --> - <act_window id="action_calendar_transform_multi" - multi="True" - key2="client_action_multi" - name="Transformer en ligne de temps" - res_model="calendar.event.transform" - src_model="calendar.event" - view_mode="form" - target="new" - view_type="form" /> + <record id="action_calendar_transform_multi" model="ir.actions.act_window"> + <field name="name">Transformer en ligne de temps</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">calendar.event.transform</field> + <field name="view_mode">form</field> + <field name="view_id" ref="calendar_event_transform_view" /> + <field name="context">{}</field> + <field name="target">new</field> + <field name="binding_model_id" ref="calendar.model_calendar_event" /> + <field name="binding_view_types">list</field> + </record> </data> -</odoo> \ No newline at end of file +</odoo>