Skip to content
Extraits de code Groupes Projets
Valider e3943c7d rédigé par Rémi - Le Filament's avatar Rémi - Le Filament
Parcourir les fichiers

[IMP] pre-commit

parent 43523ee2
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de avec 1155 ajouts et 381 suppressions
# 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
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
[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
# 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/
[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
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
# 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"
[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=12.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
[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=12.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
LICENSE 100755 → 100644
Le mode du fichier est passé de 100755 à 100644
...@@ -33,4 +33,3 @@ Maintainer ...@@ -33,4 +33,3 @@ Maintainer
:target: https://le-filament.com :target: https://le-filament.com
This module is maintained by Le Filament This module is maintained by Le Filament
{ {
'name': "ADEFPAT - Gestion des avenants", "name": "ADEFPAT - Gestion des avenants",
'summary': """Gestion des avenants""", "summary": """Gestion des avenants""",
'author': "Le Filament", "author": "Le Filament",
'website': "https://www.le-filament.com", "website": "https://www.le-filament.com",
'version': '12.0.1.0.1', "version": "12.0.1.0.1",
'license': "AGPL-3", "license": "AGPL-3",
'depends': [ "depends": ["adefpat_project", "adefpat_alfresco_generation", "adefpat_account"],
'adefpat_project', 'adefpat_alfresco_generation', 'adefpat_account'], "data": [
'data': [ "security/ir.model.access.csv",
'security/ir.model.access.csv', "views/account_invoice_views.xml",
'views/account_invoice_views.xml', "views/project_views.xml",
'views/project_views.xml',
], ],
} }
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import base64 import base64
from odoo import fields, models, api
from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
_inherit = 'account.invoice' _inherit = "account.invoice"
# ------------------------------------------------------ # ------------------------------------------------------
# Fields declaration # Fields declaration
...@@ -43,46 +44,60 @@ class AccountInvoice(models.Model): ...@@ -43,46 +44,60 @@ class AccountInvoice(models.Model):
# ------------------------------------------------------ # ------------------------------------------------------
@api.multi @api.multi
def generate_alfresco_file(self): def generate_alfresco_file(self):
if self.is_avenant:
""" """
Ajoute un fichier sur la GED Alfresco Ajoute un fichier sur la GED Alfresco
@return: fonction get_partner_files() de res.partner @return: fonction get_partner_files() de res.partner
""" """
if self.is_avenant:
# Get proof folder nodeRef # Get proof folder nodeRef
backend = self.env['cmis.backend'].search([], limit=1) backend = self.env["cmis.backend"].search([], limit=1)
# Si la facture a déjà été créée, ouvrir dans Alfresco # Si la facture a déjà été créée, ouvrir dans Alfresco
if self.alfresco_file: if self.alfresco_file:
prop = backend.get_cmis_repository().getFolder( prop = (
self.alfresco_file).getProperties() backend.get_cmis_repository()
.getFolder(self.alfresco_file)
.getProperties()
)
url = backend.get_content_details_url_from_props(prop) url = backend.get_content_details_url_from_props(prop)
# Sinon, la créer, puis la stocker ainsi que les documents liées à la facture dans Alfresco # Sinon, la créer, puis la stocker ainsi que les documents liées à la
# facture dans Alfresco
else: else:
project_folder = self.project_id.cmis_folder project_folder = self.project_id.cmis_folder
self.cmis_folder = project_folder self.cmis_folder = project_folder
if not project_folder: if not project_folder:
raise UserError("Le dossier du projet n'est pas configuré") raise UserError(_("Le dossier du projet n'est pas configuré"))
# Get Mimetype # Get Mimetype
attachment = self.env.ref('account.account_invoices').retrieve_attachment(self) attachment = self.env.ref(
"account.account_invoices"
).retrieve_attachment(self)
if not attachment: if not attachment:
raise UserError( raise UserError(
"La facture n'a pas encore été générée. Imprimer la facture pour pouvoir la visualiser dans Alfresco") _(
"La facture n'a pas encore été générée. "
"Imprimer la facture pour pouvoir la visualiser dans Alfresco"
)
)
content_type = attachment.mimetype content_type = attachment.mimetype
path_proj = backend.get_cmis_repository().getFolder( path_proj = (
project_folder).getPaths() backend.get_cmis_repository().getFolder(project_folder).getPaths()
)
# Get template doc Facture # Get template doc Facture
template_doc = self.env['adefpat.template.doc'].search([ template_doc = self.env["adefpat.template.doc"].search(
('type_temp', '=', 'facture_av'), [("type_temp", "=", "facture_av"), ("noderef_document", "=", False)]
('noderef_document', '=', False)]) )
# Get doc linked to Facture # Get doc linked to Facture
template_doc_ids = self.env['adefpat.template.doc'].search([ template_doc_ids = self.env["adefpat.template.doc"].search(
('type_temp', '=', 'facture_av'), [
('noderef_document', '!=', False)]) ("type_temp", "=", "facture_av"),
("noderef_document", "!=", False),
]
)
# Strore template in Alfresco # Strore template in Alfresco
for template in template_doc_ids: for template in template_doc_ids:
...@@ -90,24 +105,23 @@ class AccountInvoice(models.Model): ...@@ -90,24 +105,23 @@ class AccountInvoice(models.Model):
self._publipostage_documents(template, keys, False) self._publipostage_documents(template, keys, False)
path_n0 = path_proj + [template_doc.dossier.name] path_n0 = path_proj + [template_doc.dossier.name]
path = '/'.join(path_n0) path = "/".join(path_n0)
cmis_obj = backend.get_folder_by_path(path) cmis_obj = backend.get_folder_by_path(path)
file = cmis_obj.createDocument( file = cmis_obj.createDocument(
name=attachment.name, name=attachment.name,
properties={}, properties={},
contentFile=base64.b64decode(attachment.datas), contentFile=base64.b64decode(attachment.datas),
contentType=content_type contentType=content_type,
) )
file_id = file.getProperties().get('cmis:objectId') file_id = file.getProperties().get("cmis:objectId")
self.alfresco_file = file.getObjectId() self.alfresco_file = file.getObjectId()
prop = backend.get_cmis_repository().getFolder( prop = backend.get_cmis_repository().getFolder(file_id).getProperties()
file_id).getProperties()
url = backend.get_content_details_url_from_props(prop) url = backend.get_content_details_url_from_props(prop)
return { return {
'type': 'ir.actions.act_url', "type": "ir.actions.act_url",
'url': url, "url": url,
'target': 'new', "target": "new",
} }
else: else:
return super(AccountInvoice, self).generate_alfresco_file() return super(AccountInvoice, self).generate_alfresco_file()
# Copyright 2021 Le Filament (<http://www.le-filament.com>) # Copyright 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models, api from odoo import models
class LeFilamentAlfresco(models.AbstractModel): class LeFilamentAlfresco(models.AbstractModel):
""" Appelle l'API alfresco et implémente les fonctions suivantes : """Appelle l'API alfresco et implémente les fonctions suivantes :"""
""" _inherit = "lefilament.alfresco"
_inherit = 'lefilament.alfresco'
def _publipostage_documents_malette_avenant(self, template_doc, keys_obj=None, versionable=None): def _publipostage_documents_malette_avenant(
url = '/alfresco/s/publipostage' self, template_doc, keys_obj=None, versionable=None
):
url = "/alfresco/s/publipostage"
# Récupération du backend # Récupération du backend
backend_name = self._fields['cmis_folder'] backend_name = self._fields["cmis_folder"]
backend = backend_name.get_backend(self.env) backend = backend_name.get_backend(self.env)
# Path du dossier projet # Path du dossier projet
...@@ -21,43 +23,61 @@ class LeFilamentAlfresco(models.AbstractModel): ...@@ -21,43 +23,61 @@ class LeFilamentAlfresco(models.AbstractModel):
# If not parent_id, path = dossier.name # If not parent_id, path = dossier.name
path_all, dossier_id = template_doc.get_path_all() path_all, dossier_id = template_doc.get_path_all()
if dossier_id.model_id.model == 'res.partner.porteur.project': if dossier_id.model_id.model == "res.partner.porteur.project":
object_ids = self.env['res.partner.porteur.project'].search([ object_ids = self.env["res.partner.porteur.project"].search(
('project_id', '=', self.id), [("project_id", "=", self.id), ("is_malette_ok", "=", False)]
('is_malette_ok', '=', False) )
])
for obj in object_ids: for obj in object_ids:
if obj.cmis_folder: if obj.cmis_folder:
parent_path = backend.get_cmis_repository().getFolder( parent_path = (
obj.cmis_folder).getPaths() backend.get_cmis_repository()
.getFolder(obj.cmis_folder)
.getPaths()
)
if path_all: if path_all:
path_n0 = parent_path + [path_all] path_n0 = parent_path + [path_all]
else: else:
path_n0 = parent_path path_n0 = parent_path
path = '/'.join(path_n0) path = "/".join(path_n0)
keys = obj.fill_data() keys = obj.fill_data()
keys_obj.update(keys) keys_obj.update(keys)
# Document PDF # Document PDF
cmis_obj_nodeRef = backend.get_folder_by_path(path).getProperties()['alfcmis:nodeRef'] cmis_obj_nodeRef = backend.get_folder_by_path(path).getProperties()[
mimetype = template_doc.name.split('.')[1] "alfcmis:nodeRef"
if mimetype == 'pdf': ]
mimetype = template_doc.name.split(".")[1]
if mimetype == "pdf":
# get ID document to copy # get ID document to copy
id_doc = template_doc.noderef_document.replace('workspace://SpacesStore/', '') id_doc = template_doc.noderef_document.replace(
"workspace://SpacesStore/", ""
)
# Get ID to noderef Folder parent # Get ID to noderef Folder parent
id_parent = cmis_obj_nodeRef.replace('workspace://SpacesStore/', '') id_parent = cmis_obj_nodeRef.replace(
uri = '/alfresco/s/slingshot/doclib/action/copy-to/node/workspace/SpacesStore/' + id_parent "workspace://SpacesStore/", ""
workspace = 'workspace://SpacesStore/' + id_doc )
workspace_parent = 'workspace://SpacesStore/' + id_parent uri = (
"/alfresco/s/slingshot/doclib/action/copy-to/"
"node/workspace/SpacesStore/" + id_parent
)
workspace = "workspace://SpacesStore/" + id_doc
workspace_parent = "workspace://SpacesStore/" + id_parent
# Copy the document and retur the objectId Created # Copy the document and retur the objectId Created
nodeDoc = self.copy_document( nodeDoc = self.copy_document(
url=uri, url=uri,
workspace=workspace, workspace=workspace,
workspace_parent=workspace_parent, workspace_parent=workspace_parent,
backend=backend) backend=backend,
)
self.update_doc_properties(template_doc, nodeDoc) self.update_doc_properties(template_doc, nodeDoc)
else: else:
document = self.publipostage_documents(url, path, template_doc, backend, keys_obj, versionable) document = self.publipostage_documents(
nodeDoc = document.json().get('nodeRef', '').replace('workspace://SpacesStore/', '') url, path, template_doc, backend, keys_obj, versionable
)
nodeDoc = (
document.json()
.get("nodeRef", "")
.replace("workspace://SpacesStore/", "")
)
self.update_doc_properties(template_doc, nodeDoc) self.update_doc_properties(template_doc, nodeDoc)
# Copyright 2021 Le Filament (<http://www.le-filament.com>) # Copyright 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from datetime import datetime, timedelta from datetime import timedelta
import babel.dates import babel.dates
from odoo import fields, api, models
from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
...@@ -12,11 +14,15 @@ class Project(models.Model): ...@@ -12,11 +14,15 @@ class Project(models.Model):
is_avenant = fields.Boolean("Avenant lancé", default=False) is_avenant = fields.Boolean("Avenant lancé", default=False)
date_ca_av = fields.Date("Date de CA Avenant") date_ca_av = fields.Date("Date de CA Avenant")
date_ca_av_next = fields.Date("Lendemain date de CA Avenant", compute='_compute_date_ca_av_next') date_ca_av_next = fields.Date(
"Lendemain date de CA Avenant", compute="_compute_date_ca_av_next"
)
# Champs étape "Instruction" => Onglet Dossier Avenants # Champs étape "Instruction" => Onglet Dossier Avenants
contexte_av = fields.Text("Rappel du contexte projet") contexte_av = fields.Text("Rappel du contexte projet")
caract_beneficiaire_av = fields.Text("Caractéristiques du bénéficiaire") caract_beneficiaire_av = fields.Text("Caractéristiques du bénéficiaire")
resultats_accompagnement = fields.Text("Résultats de l'accompagnement et besoins subsistants") resultats_accompagnement = fields.Text(
"Résultats de l'accompagnement et besoins subsistants"
)
objectifs_accompagnement_av = fields.Text("Objectifs d’accompagnement") objectifs_accompagnement_av = fields.Text("Objectifs d’accompagnement")
besoins_beneficiaires_av = fields.Text("Besoins des bénéficiaires") besoins_beneficiaires_av = fields.Text("Besoins des bénéficiaires")
...@@ -27,68 +33,75 @@ class Project(models.Model): ...@@ -27,68 +33,75 @@ class Project(models.Model):
lieu_av = fields.Text("Lieu") lieu_av = fields.Text("Lieu")
periode_realisation_av = fields.Text("Période de réalisation") periode_realisation_av = fields.Text("Période de réalisation")
modalite_gap_av = fields.Text( modalite_gap_av = fields.Text("Avenant - Modalités GAP")
"Avenant - Modalités GAP")
# Info Budget # Info Budget
nb_jours_adefpat_av = fields.Float("Nombre de jours CFD") nb_jours_adefpat_av = fields.Float("Nombre de jours CFD")
cout_jour_adefpat_av = fields.Float("Coût jour CFD") cout_jour_adefpat_av = fields.Float("Coût jour CFD")
nb_jour_theorique_tot_av = fields.Float( nb_jour_theorique_tot_av = fields.Float(
"Nombre de jours théoriques total", "Nombre de jours théoriques total", compute="_compute_nb_jour_theorique_tot_av"
compute='_compute_nb_jour_theorique_tot_av') )
nb_jour_theorique_tot_global = fields.Float( nb_jour_theorique_tot_global = fields.Float(
"Nombre de jours théoriques au global", "Nombre de jours théoriques au global",
compute='_compute_nb_jour_theorique_tot_global') compute="_compute_nb_jour_theorique_tot_global",
)
nb_jour_pratique_tot_av = fields.Float( nb_jour_pratique_tot_av = fields.Float(
"Nombre de jours pratiques total", "Nombre de jours pratiques total", compute="_compute_nb_jour_pratique_tot_av"
compute='_compute_nb_jour_pratique_tot_av') )
nb_jour_tot_av = fields.Float( nb_jour_tot_av = fields.Float(
"Nombre de jours total", "Nombre de jours total", compute="_compute_nb_jour_tot_av", store=True
compute='_compute_nb_jour_tot_av', )
store=True)
nb_heure_tot_av = fields.Float( nb_heure_tot_av = fields.Float(
"Nombre d'heures' total", "Nombre d'heures' total", compute="_compute_nb_jour_tot_av", store=True
compute='_compute_nb_jour_tot_av', )
store=True)
total_cout_adefpat_av = fields.Float( total_cout_adefpat_av = fields.Float(
"Total coûts CFD", "Total coûts CFD", compute="_compute_total_cout_adefpat_av"
compute='_compute_total_cout_adefpat_av') )
financement_adefpat_av = fields.Float( financement_adefpat_av = fields.Float(
"Financement Adefpat", "Financement Adefpat", compute="_compute_financement_adefpat_av"
compute='_compute_financement_adefpat_av') )
financement_ids = fields.One2many( financement_ids = fields.One2many(
'adefpat.project.financement', "adefpat.project.financement",
'project_id', "project_id",
domain=[('type_avenant', '=', False)], domain=[("type_avenant", "=", False)],
string="Financements") string="Financements",
)
cout_ids = fields.One2many( cout_ids = fields.One2many(
'adefpat.project.cout', "adefpat.project.cout",
'project_id', "project_id",
domain=[('type_avenant', '=', False)], domain=[("type_avenant", "=", False)],
string="Coûts") string="Coûts",
)
financement_av_ids = fields.One2many( financement_av_ids = fields.One2many(
'adefpat.project.financement', "adefpat.project.financement",
'project_id', "project_id",
domain=[('type_avenant', '=', True)], domain=[("type_avenant", "=", True)],
string="Financements Avenants") string="Financements Avenants",
total_financement_av = fields.Float("Total autres Avenants", compute='_compute_total_financment_av') )
total_financement_av = fields.Float(
"Total autres Avenants", compute="_compute_total_financment_av"
)
cout_av_ids = fields.One2many( cout_av_ids = fields.One2many(
'adefpat.project.cout.av', "adefpat.project.cout.av", "project_id", string="Coûts Avenants"
'project_id', )
string="Coûts Avenants")
total_cout_av = fields.Float("Total coûts Avenants", compute='_compute_total_cout_av') total_cout_av = fields.Float(
"Total coûts Avenants", compute="_compute_total_cout_av"
)
# honoraire_intervenant = fields.Float( # honoraire_intervenant = fields.Float(
# "Honoraires d'intervenants") # "Honoraires d'intervenants")
total_budget_cout_av = fields.Float( total_budget_cout_av = fields.Float(
"Total budget coûts", "Total budget coûts", compute="_compute_total_budget_cout_av"
compute='_compute_total_budget_cout_av') )
total_budget_financement_av = fields.Float("Total budget financements", compute='_compute_total_budget_financement_av') total_budget_financement_av = fields.Float(
"Total budget financements", compute="_compute_total_budget_financement_av"
)
explication_financement_av = fields.Text( explication_financement_av = fields.Text(
"Explication financement porteur de projet",) "Explication financement porteur de projet",
)
# ------------------------------------------------------ # ------------------------------------------------------
# Actions # Actions
...@@ -96,112 +109,144 @@ class Project(models.Model): ...@@ -96,112 +109,144 @@ class Project(models.Model):
@api.multi @api.multi
def fill_avenant(self): def fill_avenant(self):
for project in self: for project in self:
project.write({ project.write(
'is_avenant': True, {
'contexte_av': project.contexte, "is_avenant": True,
'caract_beneficiaire_av': project.caract_beneficiaire, "contexte_av": project.contexte,
'objectifs_accompagnement_av': project.objectifs_accompagnement, "caract_beneficiaire_av": project.caract_beneficiaire,
'besoins_beneficiaires_av': project.besoins_beneficiaires, "objectifs_accompagnement_av": project.objectifs_accompagnement,
'contenu_formation_av': project.contenu_formation, "besoins_beneficiaires_av": project.besoins_beneficiaires,
'methode_savoir_av': project.methode_savoir, "contenu_formation_av": project.contenu_formation,
'travaux_intersessions_av': project.travaux_intersessions, "methode_savoir_av": project.methode_savoir,
'lieu_av': project.lieu, "travaux_intersessions_av": project.travaux_intersessions,
'periode_realisation_av': project.periode_realisation, "lieu_av": project.lieu,
'modalite_gap_av': project.modalite_gap, "periode_realisation_av": project.periode_realisation,
'explication_financement_av': project.explication_financement, "modalite_gap_av": project.modalite_gap,
'nb_jours_adefpat_av': project.nb_jours_adefpat, "explication_financement_av": project.explication_financement,
'cout_jour_adefpat_av': project.cout_jour_adefpat "nb_jours_adefpat_av": project.nb_jours_adefpat,
}) "cout_jour_adefpat_av": project.cout_jour_adefpat,
}
)
def fill_data(self): def fill_data(self):
res = super(Project, self).fill_data() res = super(Project, self).fill_data()
if self.is_avenant and self.date_ca_av_next: if self.is_avenant and self.date_ca_av_next:
res['##date_ca_next##'] = babel.dates.format_date(date=self.date_ca_av_next, format='dd MMMM Y', res["##date_ca_next##"] = babel.dates.format_date(
locale=self._context.get('lang') or 'en_US') date=self.date_ca_av_next,
format="dd MMMM Y",
locale=self._context.get("lang") or "en_US",
)
return res return res
def fill_data_av(self): def fill_data_av(self):
parser = [ parser = [
'name', "name",
'name:NAME', "name:NAME",
'date_ca_av', "date_ca_av",
# Entête Dossier CA # Entête Dossier CA
'name_subtitle', "name_subtitle",
'num_dossier', "num_dossier",
# Critères dossier CA # Critères dossier CA
'nb_activité', "nb_activité",
'nb_emplois', "nb_emplois",
'type_beneficiaire', "type_beneficiaire",
# Blocs CA # Blocs CA
'contenu_formation_av', "contenu_formation_av",
'methode_savoir_av', "methode_savoir_av",
'travaux_intersessions_av', "travaux_intersessions_av",
'lieu_av', "lieu_av",
'periode_realisation_av', "periode_realisation_av",
'explication_financement_av', "explication_financement_av",
'modalite_gap_av', "modalite_gap_av",
'resultats_accompagnement', "resultats_accompagnement",
# CDC # CDC
'contexte_av', "contexte_av",
'caract_beneficiaire_av', "caract_beneficiaire_av",
'historique', "historique",
'besoins_beneficiaires_av', "besoins_beneficiaires_av",
'objectifs_accompagnement_av', "objectifs_accompagnement_av",
'competences_requises', "competences_requises",
'secteurs_requis', "secteurs_requis",
'modalites_intervention', "modalites_intervention",
'modalites_facturation', "modalites_facturation",
'modalites_reponse', "modalites_reponse",
'modalites_modif_marche', "modalites_modif_marche",
'financement_adefpat_av', "financement_adefpat_av",
'total_budget_financement_av', "total_budget_financement_av",
'total_financement_av', "total_financement_av",
'nb_jours_adefpat_av', "nb_jours_adefpat_av",
'cout_jour_adefpat_av', "cout_jour_adefpat_av",
'total_cout_adefpat_av', "total_cout_adefpat_av",
'total_budget_cout_av', "total_budget_cout_av",
'total_cout_av', "total_cout_av",
# # Selection field # # Selection field
'departement', "departement",
'objectif_projet', "objectif_projet",
'secteur_crit', "secteur_crit",
'taille', "taille",
'objectif_formation', "objectif_formation",
'type_formation', "type_formation",
'encadrement', "encadrement",
# Many2one # Many2one
('territoire_id', ['display_name', 'street']), ("territoire_id", ["display_name", "street"]),
('elu_referent_id', ['name']), ("elu_referent_id", ["name"]),
('user_id:cfd_name', ['name']), ("user_id:cfd_name", ["name"]),
('user_id:cfd_email', ['email']), ("user_id:cfd_email", ["email"]),
('type_convention_id', ['name']), ("type_convention_id", ["name"]),
# One2many List # One2many List
( (
'membre_ids:LIST_membres', {'type_data': 'LIST', 'fields': [('partner_id', ['display_name', 'function'])]}), "membre_ids:LIST_membres",
('porteurs_projets_ids:LIST_porteurs_project', {
{'type_data': 'LIST', 'fields': [('porteur_id', ['display_name'])]}), "type_data": "LIST",
('financement_av_ids:LIST_financement', {'type_data': 'LIST', 'fields': [('partner_id', ['display_name'])]}), "fields": [("partner_id", ["display_name", "function"])],
},
('porteurs_projets_ids:LIST_porteurs_adress', ),
{'type_data': 'LIST', 'fields': [('porteur_id', ['display_name', 'street', 'zip', 'city'])]}), (
('financement_av_ids:LIST_financement_adress', "porteurs_projets_ids:LIST_porteurs_project",
{'type_data': 'LIST', 'fields': [('partner_id', ['display_name', 'street', 'zip', 'city'])]}), {"type_data": "LIST", "fields": [("porteur_id", ["display_name"])]},
('od_ids:LIST_ods_adress', {'type_data': 'MULTI', 'fields': ['display_name', 'street', 'zip', 'city']}), ),
(
"financement_av_ids:LIST_financement",
{"type_data": "LIST", "fields": [("partner_id", ["display_name"])]},
),
(
"porteurs_projets_ids:LIST_porteurs_adress",
{
"type_data": "LIST",
"fields": [
("porteur_id", ["display_name", "street", "zip", "city"])
],
},
),
(
"financement_av_ids:LIST_financement_adress",
{
"type_data": "LIST",
"fields": [
("partner_id", ["display_name", "street", "zip", "city"])
],
},
),
(
"od_ids:LIST_ods_adress",
{
"type_data": "MULTI",
"fields": ["display_name", "street", "zip", "city"],
},
),
# One2many Enum # One2many Enum
('petr_ids:petr_list', {'type_data': 'ENUM', 'fields': ['name']}), ("petr_ids:petr_list", {"type_data": "ENUM", "fields": ["name"]}),
('porteurs_projets_ids:commune_list', {'type_data': 'ENUM', 'fields': ['commune']}), (
('cout_ids:consultants', {'type_data': 'ENUM', 'fields': [('partner_id', ['name'])]}), "porteurs_projets_ids:commune_list",
('od_ids:ods', {'type_data': 'ENUM', 'fields': ['name']}), {"type_data": "ENUM", "fields": ["commune"]},
('animateur_ids:animateurs', {'type_data': 'ENUM', 'fields': ['name']}), ),
(
"cout_ids:consultants",
{"type_data": "ENUM", "fields": [("partner_id", ["name"])]},
),
("od_ids:ods", {"type_data": "ENUM", "fields": ["name"]}),
("animateur_ids:animateurs", {"type_data": "ENUM", "fields": ["name"]}),
] ]
keys = self.json_build(parser)[0] keys = self.json_build(parser)[0]
...@@ -210,19 +255,27 @@ class Project(models.Model): ...@@ -210,19 +255,27 @@ class Project(models.Model):
# Nombre de PP eligibles # Nombre de PP eligibles
nb_stagiaires = 0 nb_stagiaires = 0
if self.porteurs_projets_ids: if self.porteurs_projets_ids:
nb_stagiaires = len(self.porteurs_projets_ids.filtered(lambda r: r.eligible == True)) nb_stagiaires = len(self.porteurs_projets_ids.filtered("eligible"))
keys['##nb_porteurs##'] = nb_stagiaires keys["##nb_porteurs##"] = nb_stagiaires
# Tableau des modules # Tableau des modules
tab_mod = [] tab_mod = []
for modul in self.cout_av_ids: for modul in self.cout_av_ids:
tab_par_mod = [modul.module, nb_stagiaires, modul.nb_jour_theorique, modul.nb_jour_pratiques, tab_par_mod = [
(7 * nb_stagiaires * modul.nb_jour_theorique), (7 * nb_stagiaires * modul.nb_jour_pratiques), modul.module,
((7 * nb_stagiaires * modul.nb_jour_theorique) + ( nb_stagiaires,
7 * nb_stagiaires * modul.nb_jour_pratiques))] modul.nb_jour_theorique,
modul.nb_jour_pratiques,
(7 * nb_stagiaires * modul.nb_jour_theorique),
(7 * nb_stagiaires * modul.nb_jour_pratiques),
(
(7 * nb_stagiaires * modul.nb_jour_theorique)
+ (7 * nb_stagiaires * modul.nb_jour_pratiques)
),
]
tab_mod.append(tab_par_mod) tab_mod.append(tab_par_mod)
keys['##TAB_MODULE_AV##'] = tab_mod keys["##TAB_MODULE_AV##"] = tab_mod
# Tableau des porteurs de projets # Tableau des porteurs de projets
tab_pp = [] tab_pp = []
...@@ -236,20 +289,23 @@ class Project(models.Model): ...@@ -236,20 +289,23 @@ class Project(models.Model):
if cout.partner_id: if cout.partner_id:
if res: if res:
if cout.partner_id.name not in res: if cout.partner_id.name not in res:
res += ', ' + cout.partner_id.name res += ", " + cout.partner_id.name
if cout.partner_id.email: if cout.partner_id.email:
res += ' (' + cout.partner_id.email + ')' res += " (" + cout.partner_id.email + ")"
else: else:
res += cout.partner_id.name res += cout.partner_id.name
if cout.partner_id.email: if cout.partner_id.email:
res += ' (' + cout.partner_id.email + ')' res += " (" + cout.partner_id.email + ")"
keys['##consultants_email##'] = res keys["##consultants_email##"] = res
keys['##TAB_PORTEURS##'] = tab_pp keys["##TAB_PORTEURS##"] = tab_pp
if self.date_ca_av_next: if self.date_ca_av_next:
keys['##date_ca_av_next##'] = babel.dates.format_date(date=self.date_ca_av_next, format='dd MMMM Y', keys["##date_ca_av_next##"] = babel.dates.format_date(
locale=self._context.get('lang') or 'en_US') date=self.date_ca_av_next,
format="dd MMMM Y",
locale=self._context.get("lang") or "en_US",
)
return keys return keys
@api.multi @api.multi
...@@ -257,20 +313,26 @@ class Project(models.Model): ...@@ -257,20 +313,26 @@ class Project(models.Model):
for project in self: for project in self:
if not project.cmis_folder: if not project.cmis_folder:
raise UserError( raise UserError(
"Le répertoire Projet d'Alfresco n'est pas configuré") _("Le répertoire Projet d'Alfresco n'est pas configuré")
)
# Récupération du template de Dossier CA # Récupération du template de Dossier CA
template_docs = self.env['adefpat.template.doc'].search([ template_docs = self.env["adefpat.template.doc"].search(
'&', '|', ('convention_ids', '=', False), [
('convention_ids', '=', project.type_convention_id.id), "&",
('type_temp', '=', 'dossier_ca_av')]) "|",
("convention_ids", "=", False),
("convention_ids", "=", project.type_convention_id.id),
("type_temp", "=", "dossier_ca_av"),
]
)
keys = project.fill_data_av() keys = project.fill_data_av()
for template_doc in template_docs: for template_doc in template_docs:
url = project._publipostage_documents(template_doc, keys, True) url = project._publipostage_documents(template_doc, keys, True)
return { return {
'type': 'ir.actions.act_url', "type": "ir.actions.act_url",
'url': url, "url": url,
'target': 'new', "target": "new",
} }
@api.multi @api.multi
...@@ -278,47 +340,81 @@ class Project(models.Model): ...@@ -278,47 +340,81 @@ class Project(models.Model):
for project in self: for project in self:
if not project.cmis_folder: if not project.cmis_folder:
raise UserError( raise UserError(
"Le répertoire Projet d'Alfresco n'est pas configuré") _("Le répertoire Projet d'Alfresco n'est pas configuré")
)
# Fill data project # Fill data project
keys = project.fill_data_av() keys = project.fill_data_av()
# Récupération des conventions d'accompagnement # Récupération des conventions d'accompagnement
# 1 par formateur # 1 par formateur
template_docs = self.env['adefpat.template.doc'].search([ template_docs = self.env["adefpat.template.doc"].search(
'&', '|', ('convention_ids', '=', False), [
('convention_ids', '=', project.type_convention_id.id), "&",
('type_temp', '=', 'convention_accompagnement_av')]) "|",
("convention_ids", "=", False),
("convention_ids", "=", project.type_convention_id.id),
("type_temp", "=", "convention_accompagnement_av"),
]
)
for template_doc in template_docs: for template_doc in template_docs:
#################################### ####################################
# Group by consultants # Group by consultants
#################################### ####################################
consulant_ok_ids = self.consulant_ids.filtered(lambda r: r.is_selected == True) consulant_ok_ids = self.consulant_ids.filtered("is_selected")
for consult in consulant_ok_ids: for consult in consulant_ok_ids:
keys_obj = consult.fill_data() keys_obj = consult.fill_data()
keys.update(keys_obj) keys.update(keys_obj)
cout_ids = self.env['adefpat.project.cout.av'].sudo().read_group( cout_ids = (
[('project_id', '=', project.id), self.env["adefpat.project.cout.av"]
('consultant_id', '=', consult.id)], .sudo()
['partner_id', 'montant', 'nb_jour_theorique', 'nb_jour_pratiques'], .read_group(
['partner_id'], lazy=False) [
("project_id", "=", project.id),
keys['##montant##'] = cout_ids[0]['montant'] ("consultant_id", "=", consult.id),
keys['##nb_jour_theorique_tot_av##'] = cout_ids[0]['nb_jour_theorique'] ],
keys['##nb_jour_pratique_tot_av##'] = cout_ids[0]['nb_jour_pratiques'] [
keys['##nb_jour_tot_av##'] = cout_ids[0]['nb_jour_pratiques'] + cout_ids[0]['nb_jour_theorique'] "partner_id",
keys['##nb_heure_tot_av##'] = (cout_ids[0]['nb_jour_pratiques'] + cout_ids[0]['nb_jour_theorique']) * 7 "montant",
"nb_jour_theorique",
"nb_jour_pratiques",
],
["partner_id"],
lazy=False,
)
)
keys["##montant##"] = cout_ids[0]["montant"]
keys["##nb_jour_theorique_tot_av##"] = cout_ids[0][
"nb_jour_theorique"
]
keys["##nb_jour_pratique_tot_av##"] = cout_ids[0][
"nb_jour_pratiques"
]
keys["##nb_jour_tot_av##"] = (
cout_ids[0]["nb_jour_pratiques"]
+ cout_ids[0]["nb_jour_theorique"]
)
keys["##nb_heure_tot_av##"] = (
cout_ids[0]["nb_jour_pratiques"]
+ cout_ids[0]["nb_jour_theorique"]
) * 7
project._publipostage_documents(template_doc, keys, False) project._publipostage_documents(template_doc, keys, False)
# Récupération des annexes de conventions d'accompagnement # Récupération des annexes de conventions d'accompagnement
# 1 par bénéficiaire # 1 par bénéficiaire
template_docs = self.env['adefpat.template.doc'].search([ template_docs = self.env["adefpat.template.doc"].search(
'&', '|', ('convention_ids', '=', False), [
('convention_ids', '=', project.type_convention_id.id), "&",
('type_temp', '=', 'annexe_convention_av')]) "|",
("convention_ids", "=", False),
("convention_ids", "=", project.type_convention_id.id),
("type_temp", "=", "annexe_convention_av"),
]
)
for template_doc in template_docs: for template_doc in template_docs:
for financ in project.financement_av_ids: for financ in project.financement_av_ids:
...@@ -327,10 +423,15 @@ class Project(models.Model): ...@@ -327,10 +423,15 @@ class Project(models.Model):
project._publipostage_documents(template_doc, keys, False) project._publipostage_documents(template_doc, keys, False)
# Récupération des conventions d'objectif # Récupération des conventions d'objectif
template_docs = self.env['adefpat.template.doc'].search([ template_docs = self.env["adefpat.template.doc"].search(
'&', '|', ('convention_ids', '=', False), [
('convention_ids', '=', project.type_convention_id.id), "&",
('type_temp', '=', 'convention_objectif_av')]) "|",
("convention_ids", "=", False),
("convention_ids", "=", project.type_convention_id.id),
("type_temp", "=", "convention_objectif_av"),
]
)
for template_doc in template_docs: for template_doc in template_docs:
# Get the display name of first Animateur # Get the display name of first Animateur
if project.animateur_ids: if project.animateur_ids:
...@@ -347,20 +448,22 @@ class Project(models.Model): ...@@ -347,20 +448,22 @@ class Project(models.Model):
project._publipostage_documents(template_doc, keys, True) project._publipostage_documents(template_doc, keys, True)
# Open URL from path in alfresco # Open URL from path in alfresco
backend_name = self._fields['cmis_folder'] backend_name = self._fields["cmis_folder"]
backend = backend_name.get_backend(project.env) backend = backend_name.get_backend(project.env)
parent_path = backend.get_cmis_repository().getFolder( parent_path = (
project.cmis_folder).getPaths() backend.get_cmis_repository().getFolder(project.cmis_folder).getPaths()
)
path_proj = parent_path + [template_doc.dossier.name] path_proj = parent_path + [template_doc.dossier.name]
path = '/'.join(path_proj) path = "/".join(path_proj)
cmis_folder = backend.get_folder_by_path(path) cmis_folder = backend.get_folder_by_path(path)
properties = backend.get_cmis_repository().getFolder( properties = (
cmis_folder).getProperties() backend.get_cmis_repository().getFolder(cmis_folder).getProperties()
)
url = backend.get_content_details_url_from_props(properties) url = backend.get_content_details_url_from_props(properties)
return { return {
'type': 'ir.actions.act_url', "type": "ir.actions.act_url",
'url': url, "url": url,
'target': 'new', "target": "new",
} }
@api.multi @api.multi
...@@ -369,17 +472,26 @@ class Project(models.Model): ...@@ -369,17 +472,26 @@ class Project(models.Model):
if project.is_avenant: if project.is_avenant:
if not project.cmis_folder: if not project.cmis_folder:
raise UserError( raise UserError(
"Le répertoire Projet d'Alfresco n'est pas configuré") _("Le répertoire Projet d'Alfresco n'est pas configuré")
)
project.is_send_malette = True project.is_send_malette = True
# Récupération des template pour les malettes # Récupération des template pour les malettes
template_docs = self.env['adefpat.template.doc'].search([ template_docs = self.env["adefpat.template.doc"].search(
'&', '&', '|', ('convention_ids', '=', False), [
('convention_ids', '=', project.type_convention_id.id), "&",
('type_temp', '=', False), "&",
('noderef_document', '!=', False)]) "|",
("convention_ids", "=", False),
("convention_ids", "=", project.type_convention_id.id),
("type_temp", "=", False),
("noderef_document", "!=", False),
]
)
keys = project.fill_data() keys = project.fill_data()
for template_doc in template_docs: for template_doc in template_docs:
project._publipostage_documents_malette_avenant(template_doc, keys, True) project._publipostage_documents_malette_avenant(
template_doc, keys, True
)
# Mise a jour de l'envoi malette sur les porteurs de projet # Mise a jour de l'envoi malette sur les porteurs de projet
for porteur in project.porteurs_projets_ids: for porteur in project.porteurs_projets_ids:
...@@ -387,15 +499,18 @@ class Project(models.Model): ...@@ -387,15 +499,18 @@ class Project(models.Model):
porteur.is_malette_ok = True porteur.is_malette_ok = True
# Open URL Project in Alfresco # Open URL Project in Alfresco
backend_name = self._fields['cmis_folder'] backend_name = self._fields["cmis_folder"]
backend = backend_name.get_backend(project.env) backend = backend_name.get_backend(project.env)
properties = backend.get_cmis_repository().getFolder( properties = (
project.cmis_folder).getProperties() backend.get_cmis_repository()
.getFolder(project.cmis_folder)
.getProperties()
)
url = backend.get_content_details_url_from_props(properties) url = backend.get_content_details_url_from_props(properties)
return { return {
'type': 'ir.actions.act_url', "type": "ir.actions.act_url",
'url': url, "url": url,
'target': 'new', "target": "new",
} }
else: else:
return super(Project, self).generate_dossier_global() return super(Project, self).generate_dossier_global()
...@@ -411,30 +526,35 @@ class Project(models.Model): ...@@ -411,30 +526,35 @@ class Project(models.Model):
if partner.type_structure_id: if partner.type_structure_id:
# search the product corresponding to the company associated # search the product corresponding to the company associated
product_id = self.env['product.product'].search([('type_product', '=', 'collectivite')]) product_id = self.env["product.product"].search(
[("type_product", "=", "collectivite")]
)
else: else:
# search the product corresponding to the company associated # search the product corresponding to the company associated
product_id = self.env['product.product'].search([('type_product', '=', 'particular')]) product_id = self.env["product.product"].search(
[("type_product", "=", "particular")]
)
# If doesn't exist, create the invoice # If doesn't exist, create the invoice
if not benef.invoice_id: if not benef.invoice_id:
account_invoice_id = self.create_invoice( account_invoice_id = self.create_invoice(
product_id, partner, benef.montant) product_id, partner, benef.montant
account_invoice_id.write({ )
'is_avenant': True, account_invoice_id.write(
'name': partner.name + " - avenant"}) {"is_avenant": True, "name": partner.name + " - avenant"}
benef.write({'invoice_id': account_invoice_id.id}) )
benef.write({"invoice_id": account_invoice_id.id})
# ------------------------------------------------------ # ------------------------------------------------------
# Compute # Compute
# ------------------------------------------------------ # ------------------------------------------------------
@api.depends('date_ca_av') @api.depends("date_ca_av")
@api.multi @api.multi
def _compute_date_ca_av_next(self): def _compute_date_ca_av_next(self):
for project in self: for project in self:
if project.date_ca_av: if project.date_ca_av:
project.date_ca_av_next = project.date_ca_av + timedelta(days=1) project.date_ca_av_next = project.date_ca_av + timedelta(days=1)
@api.depends('financement_av_ids', 'financement_av_ids.montant') @api.depends("financement_av_ids", "financement_av_ids.montant")
@api.multi @api.multi
def _compute_total_financment_av(self): def _compute_total_financment_av(self):
for project in self: for project in self:
...@@ -443,7 +563,7 @@ class Project(models.Model): ...@@ -443,7 +563,7 @@ class Project(models.Model):
total_financement += financement.montant total_financement += financement.montant
project.total_financement_av = total_financement project.total_financement_av = total_financement
@api.depends('cout_av_ids', 'cout_av_ids.montant') @api.depends("cout_av_ids", "cout_av_ids.montant")
@api.multi @api.multi
def _compute_total_cout_av(self): def _compute_total_cout_av(self):
for project in self: for project in self:
...@@ -452,7 +572,7 @@ class Project(models.Model): ...@@ -452,7 +572,7 @@ class Project(models.Model):
total_cout += cout.montant total_cout += cout.montant
project.total_cout_av = total_cout project.total_cout_av = total_cout
@api.depends('cout_av_ids', 'cout_av_ids.nb_jour_theorique') @api.depends("cout_av_ids", "cout_av_ids.nb_jour_theorique")
@api.multi @api.multi
def _compute_nb_jour_theorique_tot_av(self): def _compute_nb_jour_theorique_tot_av(self):
for project in self: for project in self:
...@@ -461,19 +581,23 @@ class Project(models.Model): ...@@ -461,19 +581,23 @@ class Project(models.Model):
total_jour += cout.nb_jour_theorique total_jour += cout.nb_jour_theorique
project.nb_jour_theorique_tot_av = total_jour project.nb_jour_theorique_tot_av = total_jour
@api.depends('nb_jour_theorique_tot_av', 'nb_jour_theorique_tot') @api.depends("nb_jour_theorique_tot_av", "nb_jour_theorique_tot")
@api.multi @api.multi
def _compute_nb_jour_theorique_tot_global(self): def _compute_nb_jour_theorique_tot_global(self):
for project in self: for project in self:
project.nb_jour_theorique_tot_global = project.nb_jour_theorique_tot_av + project.nb_jour_theorique_tot project.nb_jour_theorique_tot_global = (
project.nb_jour_theorique_tot_av + project.nb_jour_theorique_tot
)
@api.depends('nb_jour_plann', 'nb_jour_theorique_tot_global') @api.depends("nb_jour_plann", "nb_jour_theorique_tot_global")
@api.multi @api.multi
def _compute_nb_jour_rest(self): def _compute_nb_jour_rest(self):
for project in self: for project in self:
project.nb_jour_rest = project.nb_jour_theorique_tot_global - project.nb_jour_plann project.nb_jour_rest = (
project.nb_jour_theorique_tot_global - project.nb_jour_plann
)
@api.depends('cout_av_ids', 'cout_av_ids.nb_jour_pratiques') @api.depends("cout_av_ids", "cout_av_ids.nb_jour_pratiques")
@api.multi @api.multi
def _compute_nb_jour_pratique_tot_av(self): def _compute_nb_jour_pratique_tot_av(self):
for project in self: for project in self:
...@@ -482,7 +606,9 @@ class Project(models.Model): ...@@ -482,7 +606,9 @@ class Project(models.Model):
total_jour += cout.nb_jour_pratiques total_jour += cout.nb_jour_pratiques
project.nb_jour_pratique_tot_av = total_jour project.nb_jour_pratique_tot_av = total_jour
@api.depends('cout_av_ids', 'cout_av_ids.nb_jour_theorique', 'cout_av_ids.nb_jour_pratiques') @api.depends(
"cout_av_ids", "cout_av_ids.nb_jour_theorique", "cout_av_ids.nb_jour_pratiques"
)
@api.multi @api.multi
def _compute_nb_jour_tot_av(self): def _compute_nb_jour_tot_av(self):
for project in self: for project in self:
...@@ -492,89 +618,104 @@ class Project(models.Model): ...@@ -492,89 +618,104 @@ class Project(models.Model):
project.nb_jour_tot_av = total_jour project.nb_jour_tot_av = total_jour
project.nb_heure_tot_av = total_jour * 7 project.nb_heure_tot_av = total_jour * 7
@api.depends('nb_jours_adefpat_av', 'cout_jour_adefpat_av') @api.depends("nb_jours_adefpat_av", "cout_jour_adefpat_av")
@api.multi @api.multi
def _compute_total_cout_adefpat_av(self): def _compute_total_cout_adefpat_av(self):
for project in self: for project in self:
project.total_cout_adefpat_av = project.nb_jours_adefpat_av * project.cout_jour_adefpat_av project.total_cout_adefpat_av = (
project.nb_jours_adefpat_av * project.cout_jour_adefpat_av
)
@api.depends('total_cout_adefpat_av', 'total_cout_av') @api.depends("total_cout_adefpat_av", "total_cout_av")
@api.multi @api.multi
def _compute_total_budget_cout_av(self): def _compute_total_budget_cout_av(self):
for project in self: for project in self:
project.total_budget_cout_av = project.total_cout_adefpat_av + project.total_cout_av project.total_budget_cout_av = (
project.total_cout_adefpat_av + project.total_cout_av
)
@api.depends('total_budget_cout_av', 'total_financement_av') @api.depends("total_budget_cout_av", "total_financement_av")
@api.multi @api.multi
def _compute_financement_adefpat_av(self): def _compute_financement_adefpat_av(self):
for project in self: for project in self:
project.financement_adefpat_av = project.total_budget_cout_av - project.total_financement_av project.financement_adefpat_av = (
project.total_budget_cout_av - project.total_financement_av
)
@api.depends('financement_adefpat_av', 'total_financement_av') @api.depends("financement_adefpat_av", "total_financement_av")
@api.multi @api.multi
def _compute_total_budget_financement_av(self): def _compute_total_budget_financement_av(self):
for project in self: for project in self:
project.total_budget_financement_av = project.financement_adefpat_av + project.total_financement_av project.total_budget_financement_av = (
project.financement_adefpat_av + project.total_financement_av
)
class AdefpatFinancement(models.Model): class AdefpatFinancement(models.Model):
_inherit = 'adefpat.project.financement' _inherit = "adefpat.project.financement"
type_avenant = fields.Boolean("Type avenant", default=False) type_avenant = fields.Boolean("Type avenant", default=False)
class AdefpatCout(models.Model): class AdefpatCout(models.Model):
_inherit = 'adefpat.project.cout' _inherit = "adefpat.project.cout"
type_avenant = fields.Boolean("Type avenant", default=False) type_avenant = fields.Boolean("Type avenant", default=False)
class AdefpatCoutAV(models.Model): class AdefpatCoutAV(models.Model):
_name = 'adefpat.project.cout.av' _name = "adefpat.project.cout.av"
_description = 'Coûts Avenants' _description = "Coûts Avenants"
@api.model @api.model
def _default_consultant_id(self): def _default_consultant_id(self):
return self.env['res.partner.consultants.project'].search([ return self.env["res.partner.consultants.project"].search(
('project_id', '=', self.env.context.get('default_project_id')), [
('is_selected', '=', True) ("project_id", "=", self.env.context.get("default_project_id")),
], limit=1) ("is_selected", "=", True),
],
limit=1,
)
module = fields.Char("Nom du module") module = fields.Char("Nom du module")
project_id = fields.Many2one( project_id = fields.Many2one(
'project.project', "project.project",
string='Projet', string="Projet",
default=lambda self: self.env.context.get('default_project_id')) default=lambda self: self.env.context.get("default_project_id"),
)
consultant_id = fields.Many2one( consultant_id = fields.Many2one(
'res.partner.consultants.project', "res.partner.consultants.project",
string="Consultant", string="Consultant",
domain="[('is_selected', '=', True)]", domain="[('is_selected', '=', True)]",
on_delete='restrict', on_delete="restrict",
default=_default_consultant_id default=_default_consultant_id,
) )
partner_id = fields.Many2one( partner_id = fields.Many2one(
'res.partner', "res.partner",
string='Consultant', string="Consultant",
related='consultant_id.partner_id', related="consultant_id.partner_id",
store=True) store=True,
)
nb_jour_theorique = fields.Float("Nombre de jours théoriques") nb_jour_theorique = fields.Float("Nombre de jours théoriques")
nb_jour_pratiques = fields.Float("Nombre de jours pratiques") nb_jour_pratiques = fields.Float("Nombre de jours pratiques")
cout_jour = fields.Float("Coût jour", related='consultant_id.cout_journée') cout_jour = fields.Float("Coût jour", related="consultant_id.cout_journée")
montant = fields.Float("Montant", compute='_compute_montant', store=True) montant = fields.Float("Montant", compute="_compute_montant", store=True)
@api.depends('cout_jour', 'nb_jour_theorique') @api.depends("cout_jour", "nb_jour_theorique")
def _compute_montant(self): def _compute_montant(self):
for r in self: for r in self:
r.montant = r.cout_jour * r.nb_jour_theorique\ r.montant = r.cout_jour * r.nb_jour_theorique
class AdefpatTemplateDoc(models.Model): class AdefpatTemplateDoc(models.Model):
_inherit = 'adefpat.template.doc' _inherit = "adefpat.template.doc"
type_temp = fields.Selection(selection_add=[ type_temp = fields.Selection(
('convention_accompagnement_av', "Avenant Conventions d'accompagnement"), selection_add=[
('convention_objectif_av', "Avenant Conventions d'objectif"), ("convention_accompagnement_av", "Avenant Conventions d'accompagnement"),
('annexe_convention_av', "Avenant Annexes Conventions"), ("convention_objectif_av", "Avenant Conventions d'objectif"),
('dossier_ca_av', "Avenant Dossier CA"), ("annexe_convention_av", "Avenant Annexes Conventions"),
('facture_av', "Avenant Facture"), ("dossier_ca_av", "Avenant Dossier CA"),
]) ("facture_av", "Avenant Facture"),
\ No newline at end of file ]
)
# Copyright 2020 Le Filament (<http://www.le-filament.com>) # Copyright 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models, api from odoo import api, fields, models
class ProjectTask(models.Model): class ProjectTask(models.Model):
_inherit = 'project.task' _inherit = "project.task"
@api.model @api.model
def default_get(self, fields): def default_get(self, fields):
res = super(ProjectTask, self).default_get(fields) res = super(ProjectTask, self).default_get(fields)
if 'default_project_id' in self.env.context: if "default_project_id" in self.env.context:
default_project_id = self.env['project.project'].browse(self.env.context['default_project_id']) default_project_id = self.env["project.project"].browse(
self.env.context["default_project_id"]
)
if default_project_id.exists().porteurs_projets_ids: if default_project_id.exists().porteurs_projets_ids:
participant_ids = [] participant_ids = []
for porteur_project in default_project_id.porteurs_projets_ids: for porteur_project in default_project_id.porteurs_projets_ids:
vals = { vals = {
'porteur_id': porteur_project.porteur_id.id, "porteur_id": porteur_project.porteur_id.id,
'lastname': porteur_project.lastname, "lastname": porteur_project.lastname,
'firstname': porteur_project.firstname, "firstname": porteur_project.firstname,
'commune': porteur_project.commune, "commune": porteur_project.commune,
'mobile': porteur_project.mobile, "mobile": porteur_project.mobile,
'fixe': porteur_project.fixe, "fixe": porteur_project.fixe,
'email': porteur_project.email, "email": porteur_project.email,
'eligible': porteur_project.eligible, "eligible": porteur_project.eligible,
} }
participant_ids.append((0, 0, vals)) participant_ids.append((0, 0, vals))
res.update({'participant_ids': participant_ids}) res.update({"participant_ids": participant_ids})
cout_id = self.env['adefpat.project.cout'].search([ cout_id = self.env["adefpat.project.cout"].search(
('project_id', '=', default_project_id.id), [
('partner_id', '!=', False) ("project_id", "=", default_project_id.id),
], limit=1) ("partner_id", "!=", False),
],
limit=1,
)
if cout_id: if cout_id:
res.update({'formateur_id': cout_id.partner_id.id}) res.update({"formateur_id": cout_id.partner_id.id})
return res return res
user_id = fields.Many2one( user_id = fields.Many2one(
'res.users', "res.users",
string='CFD', string="CFD",
default=lambda self: self.env.uid, default=lambda self: self.env.uid,
index=True, index=True,
track_visibility='always') track_visibility="always",
)
formateur_id = fields.Many2one( formateur_id = fields.Many2one(
'res.partner', "res.partner",
string='Formateur', string="Formateur",
domain=[ domain=[
('active', '=', True), ("active", "=", True),
('is_company', '=', False), ("is_company", "=", False),
('is_consultant_form', '=', True), ("is_consultant_form", "=", True),
'|', ('reference', '=', 'reference'), "|",
('reference', '=', 'prereference')], ("reference", "=", "reference"),
on_delete='restrict') ("reference", "=", "prereference"),
duree_jr = fields.Selection([
('demi_journee', "Demi journée"),
('journee', "Journée"),
], ],
"Durée (en jours)") on_delete="restrict",
duree_hr = fields.Float(
"Durée en jours",
compute='_compute_duree_hr',
store=True
) )
duree_jr = fields.Selection(
[
("demi_journee", "Demi journée"),
("journee", "Journée"),
],
"Durée (en jours)",
)
duree_hr = fields.Float("Durée en jours", compute="_compute_duree_hr", store=True)
participant_ids = fields.One2many( participant_ids = fields.One2many(
'res.partner.porteur.project', "res.partner.porteur.project", "task_id", string="Participants"
'task_id', )
string="Participants") cout_seance = fields.Float("Coût de la séance", compute="_compute_cout_seance")
cout_seance = fields.Float("Coût de la séance", compute='_compute_cout_seance')
date_account = fields.Date("Date de la facture") date_account = fields.Date("Date de la facture")
@api.depends('duree_jr') @api.depends("duree_jr")
@api.multi @api.multi
def _compute_duree_hr(self): def _compute_duree_hr(self):
for task in self: for task in self:
if task.duree_jr == 'journee': if task.duree_jr == "journee":
task.duree_hr = 1 task.duree_hr = 1
if task.duree_jr == 'demi_journee': if task.duree_jr == "demi_journee":
task.duree_hr = 0.5\ task.duree_hr = 0.5
@api.depends('formateur_id', 'duree_hr') @api.depends("formateur_id", "duree_hr")
@api.multi @api.multi
def _compute_cout_seance(self): def _compute_cout_seance(self):
for task in self: for task in self:
if task.formateur_id: if task.formateur_id:
formateur_proj = self.env['adefpat.project.cout'].search([ formateur_proj = self.env["adefpat.project.cout"].search(
('project_id', '=', task.project_id.id), [
('partner_id', '=', task.formateur_id.id) ("project_id", "=", task.project_id.id),
], limit=1) ("partner_id", "=", task.formateur_id.id),
],
limit=1,
)
if formateur_proj: if formateur_proj:
task.cout_seance = formateur_proj.cout_jour * task.duree_hr task.cout_seance = formateur_proj.cout_jour * task.duree_hr
Le mode du fichier est passé de 100755 à 100644
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter