diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 732d0c4a644eb444d6b4385643ff32fab19fab52..ad02204ce27c2f7c43ac83df01370f8e97ac9d0e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,8 @@ exclude: | ^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 @@ -25,8 +27,13 @@ repos: entry: found forbidden files; remove them language: fail files: "\\.rej$" + - id: en-po-files + name: en.po files cannot exist + entry: found a en.po file + language: fail + files: '[a-zA-Z0-9_]*/i18n/en\.po$' - repo: https://github.com/oca/maintainer-tools - rev: 7d8a9f9ad73db0976fb03cbee43d953bc29b89e9 + rev: ab1d7f6 hooks: # update the NOT INSTALLABLE ADDONS section above - id: oca-update-pre-commit-excluded-addons @@ -48,10 +55,11 @@ repos: hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.6.2 + rev: v2.1.2 hooks: - id: prettier name: prettier (with plugin-xml) + exclude: ^datas/ additional_dependencies: - "prettier@2.1.2" - "@prettier/plugin-xml@0.12.0" @@ -59,7 +67,7 @@ repos: - --plugin=@prettier/plugin-xml files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$ - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.15.0 + rev: v7.8.1 hooks: - id: eslint verbose: true @@ -67,7 +75,7 @@ repos: - --color - --fix - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v3.2.0 hooks: - id: trailing-whitespace # exclude autogenerated files @@ -89,37 +97,33 @@ repos: - id: mixed-line-ending args: ["--fix=lf"] - repo: https://github.com/asottile/pyupgrade - rev: v2.32.1 + rev: v2.7.2 hooks: - id: pyupgrade args: ["--keep-percent-format"] - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort name: isort except __init__.py args: - --settings=. exclude: /__init__\.py$ - - repo: https://gitlab.com/PyCQA/flake8 - rev: 3.9.2 + - repo: https://github.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: v2.11.1 + - repo: https://github.com/OCA/pylint-odoo + rev: 7.0.2 hooks: - - id: pylint + - id: pylint_odoo name: pylint with optional checks args: - --rcfile=.pylintrc - --exit-zero verbose: true - additional_dependencies: &pylint_deps - - pylint-odoo==5.0.5 - - id: pylint - name: pylint with mandatory checks + - id: pylint_odoo args: - --rcfile=.pylintrc-mandatory - additional_dependencies: *pylint_deps diff --git a/datas/mail_data.xml b/datas/mail_data.xml index 08bd158bcb4b4cabb8f1c5eaf408cc008905978c..33542d366ed5c7403c8a703656ff5a77f2e8dce0 100644 --- a/datas/mail_data.xml +++ b/datas/mail_data.xml @@ -4,48 +4,56 @@ <!-- Email d'avis de prélèvement --> <record id="email_template_payment_order" model="mail.template"> <field name="name">CG SCOP : Prélèvements</field> - <field - name="model_id" - ref="account_payment_order.model_account_payment_order" - /> - <field - name="email_from" - >"Confédération Générale des Scop et Scic" <administratif.cg@scop.coop></field> - <field - name="reply_to" - >"Confédération Générale des Scop et Scic" <administratif.cg@scop.coop></field> + <field name="model_id" ref="account_payment_order.model_account_payment_order"/> + <field name="email_from">"Confédération Générale des Scop et Scic" <administratif.cg@scop.coop></field> + <field name="reply_to">"Confédération Générale des Scop et Scic" <administratif.cg@scop.coop></field> <field name="partner_to">${object.get_recipients()}</field> <field name="subject">CG SCOP : Avis de prélèvement</field> <field name="body_html" type="html"> <div style="margin: 0px; padding: 0px;"> <p style="margin: 0px; padding: 0px; font-size: 13px;"> + <p>${object.get_email_values().get("partner_id").member_number} - ${object.get_email_values().get("partner_id").name}</p> + <p> </p> <p>Chère Coopératrice, Cher Coopérateur,</p> <p> </p> - <p - >Vous avez choisi de régler vos cotisations à la Confédération générale des Scop et des Scic par prélèvement bancaire.</p> - <p - >Nous vous informons que nous allons procéder le ${object.get_email_values().get("date").strftime('%d/%m/%Y')} à un prélèvement sur votre compte ${object.get_email_values().get("bank")} de ${format_amount(object.get_email_values().get("total"), object.company_currency_id)}</p> + <p> </p> + <p> + Vous avez choisi de régler vos cotisations à la Confédération générale des Scop et des Scic par prélèvement bancaire. + </p> + <p> + Nous vous informons que nous avons procédé ce jour à un ordre de prélèvement qui sera présenté au débit de votre compte le ${object.get_email_values().get("date").strftime('%d/%m/%Y')}. + </p> + <p> </p> + <p> + Le mandat de prélèvement enregistré pour votre coopérative est le suivant : ${object.get_email_values().get("bank")} + </p> + <p> </p> + <p> + Ce courriel vous est envoyé à titre informatif, l’ordre de prélèvement ne peut plus être arrêté en banque, sauf par vos soins en prenant contact avec votre établissement bancaire. + </p> + <p>Dans ce cas, nous vous remercions de bien vouloir nous en informer.</p> + <p> </p> + <p> + En cas de difficulté économique, nous vous invitons également à vous rapprocher de votre délégation régionale. + </p> <p> </p> <p> Ce prélèvement correspond au paiement des cotisations : <ul> % for line in object.get_email_values().get("deadline"): - % set quarter = "er" if line.get("cotiz_quarter") == "1" else "ème" + % set quarter = "er" if line.get("quarter") == "1" else "ème" <li> - ${line.get("cotiz_quarter")}${quarter} Trimestre ${line.get("year")} : ${format_amount(line.get("amount_total_signed"), object.company_currency_id)} + ${line.get("quarter")}${quarter} Trimestre ${line.get("year")} : ${format_amount(line.get("amount"), object.company_currency_id)} </li> % endfor </ul> </p> <p> </p> - <p - >Nous vous rappelons que les bordereaux de cotisations sont désormais mis à disposition dans <a - href="https://extranet.scop.coop/" - >votre espace extranet</a> et ne sont plus transmis par courrier.</p> <p> - Pour toute question relative à vos cotisations appelées par la CGSCOP, notre équipe est à votre disposition par téléphone au 01 44 85 47 00 ou par courriel à <a - href="mailto:administratif.cg@scop.coop" - >administratif.cg@scop.coop</a>. + Nous vous rappelons que les bordereaux de cotisations sont mis à disposition dans <a href="https://extranet.scop.coop/">votre espace extranet</a> et ne sont plus transmis par courrier. + </p> + <p> + Pour toute question relative à vos cotisations appelées par la CGSCOP, notre équipe est à votre disposition par téléphone au 01 44 85 47 00 ou par courriel à <a href="mailto:administratif.cg@scop.coop">administratif.cg@scop.coop</a>. </p> <p> </p> <p diff --git a/models/account_banking_mandate.py b/models/account_banking_mandate.py index 46bad68f689611c2be1c1194393878dde9530f42..c8c423648d82ea4ea95217337fc9dfeb73d72472 100644 --- a/models/account_banking_mandate.py +++ b/models/account_banking_mandate.py @@ -49,10 +49,12 @@ class AccountBankingMandate(models.Model): Affecte le mandat courant pur la facture passée en paramètre :param invoice : objet account.move """ - payment_mode = self.env["account.payment.mode"].search([ - ("payment_method_id.code", "=", "sepa_direct_debit"), - ("company_id", "=", self.env.company.id) - ]) + payment_mode = self.env["account.payment.mode"].search( + [ + ("payment_method_id.code", "=", "sepa_direct_debit"), + ("company_id", "=", self.env.company.id), + ] + ) if not payment_mode: raise UserError(_("Aucun mode de prélèvement SEPA configuré.")) @@ -70,9 +72,10 @@ class AccountBankingMandate(models.Model): Supprime le mandat courant pur la facture passée en paramètre :param invoice : objet account.move """ - payment_mode = self.env["account.payment.mode"].search([ - ("name", "ilike", "Virement"), ("company_id", "=", self.env.company.id) - ], limit=1) + payment_mode = self.env["account.payment.mode"].search( + [("name", "ilike", "Virement"), ("company_id", "=", self.env.company.id)], + limit=1, + ) for invoice in invoice_ids: invoice.update( { diff --git a/models/account_payment_order.py b/models/account_payment_order.py index 1c817dc143a8111dc671d16b01f669b6b8fda36d..b388710c1a6bf8a5e9d510c054862815c15d878f 100644 --- a/models/account_payment_order.py +++ b/models/account_payment_order.py @@ -1,6 +1,8 @@ # Copyright 2020 Le Filament # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from itertools import groupby + from odoo import _, fields, models from odoo.exceptions import UserError, ValidationError @@ -33,8 +35,11 @@ class AccountPaymentOrder(models.Model): def _compute_bank_line_amount(self): for po in self: - po.bank_line_amount = sum(po.payment_ids.filtered( - lambda p: not p.reversed_entry_id).mapped("amount_total_signed")) + po.bank_line_amount = sum( + po.payment_ids.filtered(lambda p: not p.reversed_entry_id).mapped( + "amount_total_signed" + ) + ) def _compute_attachment_ids(self): Attachment = self.env["ir.attachment"] @@ -124,11 +129,7 @@ class AccountPaymentOrder(models.Model): try: template = self.env.ref("cgscop_cotisation.email_template_payment_order") except Exception: - raise UserError( - _( - "Aucun modèle d'e-mail n'a été trouvé." - ) - ) + raise UserError(_("Aucun modèle d'e-mail n'a été trouvé.")) # Get partners partner_ids = self.payment_line_ids.mapped("partner_id") for partner in partner_ids: @@ -178,20 +179,32 @@ class AccountPaymentOrder(models.Model): partner_line_ids = self.payment_line_ids.filtered( lambda l: l.partner_id == partner_id ) - invoice_ids = partner_line_ids.mapped("move_line_id.move_id").filtered( - "is_contribution" - ) + + quarter_detail = [] + quarter_agg = [] + for line in partner_line_ids: + invoice_id = line.move_line_id.move_id + quarter_detail.append( + ("%s-%s" % (invoice_id.year, invoice_id.cotiz_quarter), line.amount_currency) + ) + quarter_detail.sort(key=lambda x: x[0]) + + for quarter, values in groupby(quarter_detail, key=lambda x: x[0]): + amount = 0 + for val in values: + amount += val[1] + quarter_agg.append({ + "year": quarter[0:4], + "quarter": quarter[-1], + "amount": amount, + }) + return { + "partner_id": partner_id, "total": sum(partner_line_ids.mapped("amount_currency")), "date": partner_line_ids.mapped("date")[0], "bank": partner_line_ids.mapped("partner_bank_id.acc_number")[0], - "deadline": invoice_ids.read_group( - domain=[("id", "in", invoice_ids.ids)], - fields=["year", "cotiz_quarter", "amount_total_signed"], - groupby=["year", "cotiz_quarter"], - orderby="year,cotiz_quarter", - lazy=False, - ), + "deadline": quarter_agg, } def get_recipients(self): diff --git a/views/account_payment_order.xml b/views/account_payment_order.xml index 8d4c7924076463fcd68b24928431afca19b6f34e..0a4df285278d2ae37ddf578ab43012f5008cdabf 100644 --- a/views/account_payment_order.xml +++ b/views/account_payment_order.xml @@ -134,18 +134,35 @@ <!-- />--> </tree> <form> - <h1><field name="name"/></h1> + <h1><field name="name" /></h1> <group> <group> - <field name="datas" filename="name" attrs="{'invisible':[('type','=','url')]}" string="Télécharger le fichier"/> - <field name="name" invisible="1" attrs="{'invisible':[('type','=','url')]}" class="oe_inline oe_right"/> - <field name="url" widget="url" attrs="{'invisible':[('type','=','binary')]}"/> - <field name="mimetype" groups="base.group_no_one"/> - <field name="type"/> + <field + name="datas" + filename="name" + attrs="{'invisible':[('type','=','url')]}" + string="Télécharger le fichier" + /> + <field + name="name" + invisible="1" + attrs="{'invisible':[('type','=','url')]}" + class="oe_inline oe_right" + /> + <field + name="url" + widget="url" + attrs="{'invisible':[('type','=','binary')]}" + /> + <field + name="mimetype" + groups="base.group_no_one" + /> + <field name="type" /> </group> <group> - <field name="create_uid"/> - <field name="create_date"/> + <field name="create_uid" /> + <field name="create_date" /> </group> </group> </form> diff --git a/wizard/scop_deces_wizard.py b/wizard/scop_deces_wizard.py index d2954c0b3ea0b3f2c7ab883dd9a93c4425ec296a..6f41eb0dd52fd367e8fb2ae801e0867d3873db7e 100644 --- a/wizard/scop_deces_wizard.py +++ b/wizard/scop_deces_wizard.py @@ -20,10 +20,12 @@ class ScopDecesWizard(models.TransientModel): if mandate_ids: for mandate in mandate_ids: mandate.update({"state": "expired"}) - invoice_ids = self.env["account.move"].search([ - ("mandate_id", "=", mandate.id), - ("move_type", "in", ("out_invoice", "out_refund")), - ("state", "in", ("draft", "posted")), - ("payment_state", "in", ("draft", "not_paid", "partial")), - ]) + invoice_ids = self.env["account.move"].search( + [ + ("mandate_id", "=", mandate.id), + ("move_type", "in", ("out_invoice", "out_refund")), + ("state", "in", ("draft", "posted")), + ("payment_state", "in", ("draft", "not_paid", "partial")), + ] + ) mandate._remove_invoice_mandate(invoice_ids)