From bcb496fde4872a589df2aa02b157a6b850b3cb3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?=
Date: Wed, 23 Jun 2021 08:51:42 +0200
Subject: [PATCH 01/19] [ADD] account_payment_term_partner_holiday: Add partner
holidays to exclude it when payment term assigned in invoices set due dates
---
.../README.rst | 96 ++++
.../__init__.py | 1 +
.../__manifest__.py | 19 +
.../account_payment_term_partner_holiday.pot | 179 +++++++
.../i18n/es.po | 182 ++++++++
.../models/__init__.py | 3 +
.../models/account_invoice.py | 36 ++
.../models/account_payment_term.py | 29 ++
.../models/res_partner.py | 109 +++++
.../readme/CONTRIBUTORS.rst | 4 +
.../readme/DESCRIPTION.rst | 2 +
.../readme/USAGE.rst | 7 +
.../security/ir.model.access.csv | 2 +
.../static/description/icon.png | Bin 0 -> 9455 bytes
.../static/description/index.html | 438 ++++++++++++++++++
.../tests/__init__.py | 3 +
.../tests/test_partner_holiday.py | 113 +++++
.../views/res_partner_view.xml | 20 +
18 files changed, 1243 insertions(+)
create mode 100644 account_payment_term_partner_holiday/README.rst
create mode 100644 account_payment_term_partner_holiday/__init__.py
create mode 100644 account_payment_term_partner_holiday/__manifest__.py
create mode 100644 account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot
create mode 100644 account_payment_term_partner_holiday/i18n/es.po
create mode 100644 account_payment_term_partner_holiday/models/__init__.py
create mode 100644 account_payment_term_partner_holiday/models/account_invoice.py
create mode 100644 account_payment_term_partner_holiday/models/account_payment_term.py
create mode 100644 account_payment_term_partner_holiday/models/res_partner.py
create mode 100644 account_payment_term_partner_holiday/readme/CONTRIBUTORS.rst
create mode 100644 account_payment_term_partner_holiday/readme/DESCRIPTION.rst
create mode 100644 account_payment_term_partner_holiday/readme/USAGE.rst
create mode 100644 account_payment_term_partner_holiday/security/ir.model.access.csv
create mode 100644 account_payment_term_partner_holiday/static/description/icon.png
create mode 100644 account_payment_term_partner_holiday/static/description/index.html
create mode 100644 account_payment_term_partner_holiday/tests/__init__.py
create mode 100644 account_payment_term_partner_holiday/tests/test_partner_holiday.py
create mode 100644 account_payment_term_partner_holiday/views/res_partner_view.xml
diff --git a/account_payment_term_partner_holiday/README.rst b/account_payment_term_partner_holiday/README.rst
new file mode 100644
index 000000000000..098dc00333e8
--- /dev/null
+++ b/account_payment_term_partner_holiday/README.rst
@@ -0,0 +1,96 @@
+====================================
+Account Payment Term Partner Holiday
+====================================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
+ :target: https://odoo-community.org/page/development-status
+ :alt: Production/Stable
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--payment-lightgray.png?logo=github
+ :target: https://github.com/OCA/account-payment/tree/12.0/account_payment_term_partner_holiday
+ :alt: OCA/account-payment
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/account-payment-12-0/account-payment-12-0-account_payment_term_partner_holiday
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
+ :target: https://runbot.odoo-community.org/runbot/96/12.0
+ :alt: Try me on Runbot
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+This addon adds the possibility of defining holiday periods in a
+partner so as not to use those periods as the due date on invoices.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Usage
+=====
+
+To use this module, you need to:
+
+#. Go to 'Contacts' and create or edit some record.
+#. Go to 'Sales & Purchases' tab and create some holidays records.
+#. Go to 'Invoicing > Customers > Invoices' or to 'Invoicing > Vendors >
+ Invoices' and create or edit some record.
+#. If the computed due date is inside a holidays period, it's moved to the first available date.
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues `_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+`feedback `_.
+
+Do not contact contributors directly about support or help with technical issues.
+
+Credits
+=======
+
+Authors
+~~~~~~~
+
+* Tecnativa
+
+Contributors
+~~~~~~~~~~~~
+
+* `Tecnativa `__:
+
+ * Víctor Martínez
+ * Pedro M. Baeza
+
+Maintainers
+~~~~~~~~~~~
+
+This module is maintained by the OCA.
+
+.. image:: https://odoo-community.org/logo.png
+ :alt: Odoo Community Association
+ :target: https://odoo-community.org
+
+OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
+.. |maintainer-victoralmau| image:: https://github.com/victoralmau.png?size=40px
+ :target: https://github.com/victoralmau
+ :alt: victoralmau
+
+Current `maintainer `__:
+
+|maintainer-victoralmau|
+
+This module is part of the `OCA/account-payment `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/account_payment_term_partner_holiday/__init__.py b/account_payment_term_partner_holiday/__init__.py
new file mode 100644
index 000000000000..0650744f6bc6
--- /dev/null
+++ b/account_payment_term_partner_holiday/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/account_payment_term_partner_holiday/__manifest__.py b/account_payment_term_partner_holiday/__manifest__.py
new file mode 100644
index 000000000000..378fd281b5c9
--- /dev/null
+++ b/account_payment_term_partner_holiday/__manifest__.py
@@ -0,0 +1,19 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ "name": "Account Payment Term Partner Holiday",
+ "version": "12.0.1.0.0",
+ "website": "https://github.com/OCA/account-payment",
+ "author": "Tecnativa, Odoo Community Association (OCA)",
+ "license": "AGPL-3",
+ "application": False,
+ "installable": True,
+ "depends": ["account"],
+ "maintainers": ["victoralmau"],
+ "development_status": "Production/Stable",
+ "data": [
+ "security/ir.model.access.csv",
+ "views/res_partner_view.xml"
+ ],
+}
diff --git a/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot b/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot
new file mode 100644
index 000000000000..c038beed2658
--- /dev/null
+++ b/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot
@@ -0,0 +1,179 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * account_payment_term_partner_holiday
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:60
+#, python-format
+msgid "April"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:64
+#, python-format
+msgid "August"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_res_partner
+msgid "Contact"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__day_from
+msgid "Day from"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__day_to
+msgid "Day to"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:68
+#, python-format
+msgid "December"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:58
+#, python-format
+msgid "February"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__id
+msgid "ID"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_account_invoice
+msgid "Invoice"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:57
+#, python-format
+msgid "January"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:63
+#, python-format
+msgid "July"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:62
+#, python-format
+msgid "June"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:59
+#, python-format
+msgid "March"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:61
+#, python-format
+msgid "May"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__month_from
+msgid "Month from"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__month_to
+msgid "Month to"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:67
+#, python-format
+msgid "November"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:66
+#, python-format
+msgid "October"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__partner_id
+msgid "Partner"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_res_partner_holiday
+msgid "Partner Holidays"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_account_payment_term
+msgid "Payment Terms"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner__holiday_ids
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_users__holiday_ids
+msgid "Payment Terms Holidays"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:65
+#, python-format
+msgid "September"
+msgstr ""
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:108
+#, python-format
+msgid "You can't set the ending holidays period before the beginning."
+msgstr ""
+
diff --git a/account_payment_term_partner_holiday/i18n/es.po b/account_payment_term_partner_holiday/i18n/es.po
new file mode 100644
index 000000000000..fb3aa751f01c
--- /dev/null
+++ b/account_payment_term_partner_holiday/i18n/es.po
@@ -0,0 +1,182 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * account_payment_term_partner_holiday
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-07-02 08:02+0000\n"
+"PO-Revision-Date: 2021-07-02 10:03+0200\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: \n"
+"X-Generator: Poedit 2.3\n"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:60
+#, python-format
+msgid "April"
+msgstr "Abril"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:64
+#, python-format
+msgid "August"
+msgstr "Agosto"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_res_partner
+msgid "Contact"
+msgstr "Contacto"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__create_uid
+msgid "Created by"
+msgstr "Creado por"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__create_date
+msgid "Created on"
+msgstr "Creado e"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__day_from
+msgid "Day from"
+msgstr "Día desde"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__day_to
+msgid "Day to"
+msgstr "Día hasta"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:68
+#, python-format
+msgid "December"
+msgstr "Diciembre"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__display_name
+msgid "Display Name"
+msgstr "Nombre a mostrar"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:58
+#, python-format
+msgid "February"
+msgstr "Febrero"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__id
+msgid "ID"
+msgstr "ID"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_account_invoice
+msgid "Invoice"
+msgstr "Factura"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:57
+#, python-format
+msgid "January"
+msgstr "Enero"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:63
+#, python-format
+msgid "July"
+msgstr "Julio"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:62
+#, python-format
+msgid "June"
+msgstr "Junio"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday____last_update
+msgid "Last Modified on"
+msgstr "Última modificación el"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__write_uid
+msgid "Last Updated by"
+msgstr "Última actualización por"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__write_date
+msgid "Last Updated on"
+msgstr "Última actualización el"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:59
+#, python-format
+msgid "March"
+msgstr "Marzo"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:61
+#, python-format
+msgid "May"
+msgstr "Mayo"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__month_from
+msgid "Month from"
+msgstr "Mes desde"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__month_to
+msgid "Month to"
+msgstr "Mes hasta"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:67
+#, python-format
+msgid "November"
+msgstr "Noviembre"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:66
+#, python-format
+msgid "October"
+msgstr "Octubre"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner_holiday__partner_id
+msgid "Partner"
+msgstr "Contacto"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_res_partner_holiday
+msgid "Partner Holidays"
+msgstr "Vacaciones de contacto"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model,name:account_payment_term_partner_holiday.model_account_payment_term
+msgid "Payment Terms"
+msgstr "Plazos de pago"
+
+#. module: account_payment_term_partner_holiday
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_partner__holiday_ids
+#: model:ir.model.fields,field_description:account_payment_term_partner_holiday.field_res_users__holiday_ids
+msgid "Payment Terms Holidays"
+msgstr "Vacaciones de términos de pago"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:65
+#, python-format
+msgid "September"
+msgstr "Septiembre"
+
+#. module: account_payment_term_partner_holiday
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:108
+#, python-format
+msgid "You can't set the ending holidays period before the beginning."
+msgstr ""
diff --git a/account_payment_term_partner_holiday/models/__init__.py b/account_payment_term_partner_holiday/models/__init__.py
new file mode 100644
index 000000000000..d0e7f9972b96
--- /dev/null
+++ b/account_payment_term_partner_holiday/models/__init__.py
@@ -0,0 +1,3 @@
+from . import account_invoice
+from . import account_payment_term
+from . import res_partner
diff --git a/account_payment_term_partner_holiday/models/account_invoice.py b/account_payment_term_partner_holiday/models/account_invoice.py
new file mode 100644
index 000000000000..d60068607347
--- /dev/null
+++ b/account_payment_term_partner_holiday/models/account_invoice.py
@@ -0,0 +1,36 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+from odoo import api, models
+from dateutil.relativedelta import relativedelta
+
+
+class AccountInvoice(models.Model):
+ _inherit = "account.invoice"
+
+ @api.onchange('payment_term_id', 'date_invoice')
+ def _onchange_payment_term_date_invoice(self):
+ _self = self
+ if self.partner_id:
+ _self = self.with_context(move_partner_id=self.partner_id.id)
+ super(AccountInvoice, _self)._onchange_payment_term_date_invoice()
+
+ @api.onchange("date_due")
+ def _onchange_date_due_account_payment_term_partner_holiday(self):
+ if self.date_due and self.payment_term_id and self.partner_id:
+ new_date_due = self.date_due
+ is_date_in_holiday = self.partner_id.is_date_in_holiday(new_date_due)
+ if is_date_in_holiday:
+ res_date_end = is_date_in_holiday[1]
+ new_date_due = res_date_end + relativedelta(days=1)
+ if new_date_due != self.date_due:
+ self.date_due = new_date_due
+
+ def action_move_create(self):
+ """Inject a context for getting the partner when computing payment term.
+ The trade-off is that we should split the call to super record per record,
+ but it shouldn't impact in performance.
+ """
+ for item in self:
+ _item = item.with_context(move_partner_id=item.partner_id.id)
+ return super(AccountInvoice, _item).action_move_create()
diff --git a/account_payment_term_partner_holiday/models/account_payment_term.py b/account_payment_term_partner_holiday/models/account_payment_term.py
new file mode 100644
index 000000000000..29afa8e095fd
--- /dev/null
+++ b/account_payment_term_partner_holiday/models/account_payment_term.py
@@ -0,0 +1,29 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+from odoo import api, fields, models
+from dateutil.relativedelta import relativedelta
+
+
+class AccountPaymentTerm(models.Model):
+ _inherit = "account.payment.term"
+
+ @api.one
+ def compute(self, value, date_ref=False):
+ result = super().compute(value=value, date_ref=date_ref)[0]
+ ctx = self.env.context
+ partner_id = ctx.get("move_partner_id", ctx.get("default_partner_id"))
+ if partner_id:
+ partner = self.env["res.partner"].browse(partner_id)
+ result2 = []
+ for item in result:
+ date_item = item[0]
+ is_date_in_holiday = partner.is_date_in_holiday(date_item)
+ if is_date_in_holiday:
+ next_date = is_date_in_holiday[1]
+ next_date += relativedelta(days=1)
+ result2.append((fields.Date.to_string(next_date), item[1]))
+ else:
+ result2.append(item)
+ result = result2
+ return result
diff --git a/account_payment_term_partner_holiday/models/res_partner.py b/account_payment_term_partner_holiday/models/res_partner.py
new file mode 100644
index 000000000000..bace9a81b26b
--- /dev/null
+++ b/account_payment_term_partner_holiday/models/res_partner.py
@@ -0,0 +1,109 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError
+
+
+class ResPartner(models.Model):
+ _inherit = "res.partner"
+
+ holiday_ids = fields.One2many(
+ comodel_name="res.partner.holiday",
+ inverse_name="partner_id",
+ string="Payment Terms Holidays",
+ copy=True,
+ auto_join=True
+ )
+
+ def is_date_in_holiday(self, date):
+ if isinstance(date, str):
+ date = fields.Date.from_string(date)
+ res = self.holiday_ids.filtered(
+ lambda x: int(x.month_from) <= date.month and int(x.month_to) >= date.month
+ and int(x.day_from) <= date.day and int(x.day_to) >= date.day
+ )
+ if bool(res):
+ res = res[0]
+ res_date_to = False
+ day_to = int(res.day_to)
+ while not res_date_to:
+ try:
+ res_date_to = fields.Date.from_string(
+ "%s-%s-%s" % (date.year, res.month_to, day_to)
+ )
+ except:
+ day_to -= 1
+ return [
+ fields.Date.from_string(
+ "%s-%s-%s" % (date.year, res.month_from, res.day_from)
+ ), res_date_to
+ ]
+ return False
+
+
+class ResPartnerHoliday(models.Model):
+ _name = "res.partner.holiday"
+ _description = "Partner Holidays"
+ _order = "month_from, day_from, id"
+
+ @api.model
+ def _selection_days(self):
+ return [(str(i), str(i)) for i in range(1, 32)]
+
+ @api.model
+ def _selection_months(self):
+ return [
+ ("1", _("January")),
+ ("2", _("February")),
+ ("3", _("March")),
+ ("4", _("April")),
+ ("5", _("May")),
+ ("6", _("June")),
+ ("7", _("July")),
+ ("8", _("August")),
+ ("9", _("September")),
+ ("10", _("October")),
+ ("11", _("November")),
+ ("12", _("December"))
+ ]
+
+ partner_id = fields.Many2one(
+ comodel_name="res.partner",
+ string="Partner",
+ required=True,
+ ondelete="cascade",
+ index=True,
+ copy=False
+ )
+ day_from = fields.Selection(
+ selection="_selection_days",
+ string="Day from",
+ required=True,
+ )
+ month_from = fields.Selection(
+ selection="_selection_months",
+ string="Month from",
+ required=True,
+ )
+ day_to = fields.Selection(
+ selection="_selection_days",
+ string="Day to",
+ required=True,
+ )
+ month_to = fields.Selection(
+ selection="_selection_months",
+ string="Month to",
+ required=True,
+ )
+
+ @api.constrains("day_from", "month_from", "day_to", "month_to")
+ def _check_from_end_dates(self):
+ for item in self:
+ if (int(item.month_from) > int(item.month_to)) or (
+ int(item.month_to) == int(item.month_from)
+ and int(item.day_from) > int(item.day_to)
+ ):
+ raise ValidationError(
+ _("You can't set the ending holidays period before the beginning.")
+ )
diff --git a/account_payment_term_partner_holiday/readme/CONTRIBUTORS.rst b/account_payment_term_partner_holiday/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000000..98cc86a54e74
--- /dev/null
+++ b/account_payment_term_partner_holiday/readme/CONTRIBUTORS.rst
@@ -0,0 +1,4 @@
+* `Tecnativa `__:
+
+ * Víctor Martínez
+ * Pedro M. Baeza
diff --git a/account_payment_term_partner_holiday/readme/DESCRIPTION.rst b/account_payment_term_partner_holiday/readme/DESCRIPTION.rst
new file mode 100644
index 000000000000..3a3a82725c14
--- /dev/null
+++ b/account_payment_term_partner_holiday/readme/DESCRIPTION.rst
@@ -0,0 +1,2 @@
+This addon adds the possibility of defining holiday periods in a
+partner so as not to use those periods as the due date on invoices.
diff --git a/account_payment_term_partner_holiday/readme/USAGE.rst b/account_payment_term_partner_holiday/readme/USAGE.rst
new file mode 100644
index 000000000000..7799163be0de
--- /dev/null
+++ b/account_payment_term_partner_holiday/readme/USAGE.rst
@@ -0,0 +1,7 @@
+To use this module, you need to:
+
+#. Go to 'Contacts' and create or edit some record.
+#. Go to 'Sales & Purchases' tab and create some holidays records.
+#. Go to 'Invoicing > Customers > Invoices' or to 'Invoicing > Vendors >
+ Invoices' and create or edit some record.
+#. If the computed due date is inside a holidays period, it's moved to the first available date.
diff --git a/account_payment_term_partner_holiday/security/ir.model.access.csv b/account_payment_term_partner_holiday/security/ir.model.access.csv
new file mode 100644
index 000000000000..4ae1fd2dcf2b
--- /dev/null
+++ b/account_payment_term_partner_holiday/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
+access_res_partner_holiday,res_partner_holiday,model_res_partner_holiday,base.group_user,1,1,1,1
diff --git a/account_payment_term_partner_holiday/static/description/icon.png b/account_payment_term_partner_holiday/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d
GIT binary patch
literal 9455
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
z
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
Xviia!U7SGha1wx#SCgwmn*{w2TRX*I
literal 0
HcmV?d00001
diff --git a/account_payment_term_partner_holiday/static/description/index.html b/account_payment_term_partner_holiday/static/description/index.html
new file mode 100644
index 000000000000..b092ea7722f8
--- /dev/null
+++ b/account_payment_term_partner_holiday/static/description/index.html
@@ -0,0 +1,438 @@
+
+
+
+
+
+
+Account Payment Term Partner Holiday
+
+
+
+
+
Account Payment Term Partner Holiday
+
+
+
+
This addon adds the possibility of defining holiday periods in a
+partner so as not to use those periods as the due date on invoices.
+
Table of contents
+
+
+
+
To use this module, you need to:
+
+- Go to ‘Contacts’ and create or edit some record.
+- Go to ‘Sales & Purchases’ tab and create some holidays records.
+- Go to ‘Invoicing > Customers > Invoices’ or to ‘Invoicing > Vendors >
+Invoices’ and create or edit some record.
+- If the computed due date is inside a holidays period, it’s moved to the first available date.
+
+
+
+
+
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+
+- Tecnativa:
+- Víctor Martínez
+- Pedro M. Baeza
+
+
+
+
+
+
+
This module is maintained by the OCA.
+
+
OCA, or the Odoo Community Association, is a nonprofit organization whose
+mission is to support the collaborative development of Odoo features and
+promote its widespread use.
+
Current maintainer:
+
+
This module is part of the OCA/account-payment project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
diff --git a/account_payment_term_partner_holiday/tests/__init__.py b/account_payment_term_partner_holiday/tests/__init__.py
new file mode 100644
index 000000000000..ad312b2e557d
--- /dev/null
+++ b/account_payment_term_partner_holiday/tests/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import test_partner_holiday
diff --git a/account_payment_term_partner_holiday/tests/test_partner_holiday.py b/account_payment_term_partner_holiday/tests/test_partner_holiday.py
new file mode 100644
index 000000000000..0e08e1c51ec4
--- /dev/null
+++ b/account_payment_term_partner_holiday/tests/test_partner_holiday.py
@@ -0,0 +1,113 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo.tests import common
+from odoo.tests.common import Form
+from odoo import fields
+
+
+class TestPartnerHoliday(common.TransactionCase):
+ def setUp(self):
+ super().setUp()
+ self.partner_1 = self.env["res.partner"].create({
+ "name": "Partner test 1",
+ "holiday_ids": [(0, 0, {
+ "day_from": "1",
+ "month_from": "2",
+ "day_to": "31",
+ "month_to": "2",
+ })]
+ })
+ self.partner_2 = self.env["res.partner"].create({"name": "Partner test 2"})
+ self.payment_term_immediate = self.env["account.payment.term"].create({
+ "name": "Immediate",
+ "line_ids": [(0, 0, {
+ "value": "balance",
+ "days": 0,
+ "option": "day_after_invoice_date"
+ })]
+ })
+ self.payment_term_10_days = self.env["account.payment.term"].create({
+ "name": "10 Days",
+ "line_ids": [(0, 0, {
+ "value": "balance",
+ "days": 10,
+ "option": "day_after_invoice_date"
+ })]
+ })
+ self.journal = self.env["account.journal"].create({
+ "name": "Test sale",
+ "type": "sale",
+ "code": "TEST-SALE"
+ })
+ self.product = self.env["product.product"].create({
+ "name": "Test product",
+ "type": "service"
+ })
+
+ def test_check_dates_in_partner_1(self):
+ self.assertEqual(
+ self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-02-01")), [
+ fields.Date.from_string("2021-02-01"),
+ fields.Date.from_string("2021-02-28")
+ ]
+ )
+ self.assertEqual(
+ self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-02-10")), [
+ fields.Date.from_string("2021-02-01"),
+ fields.Date.from_string("2021-02-28")
+ ]
+ )
+ self.assertFalse(
+ self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-03-01"))
+ )
+
+ def test_check_dates_in_partner_2(self):
+ self.assertFalse(
+ self.partner_2.is_date_in_holiday(fields.Date.from_string("2021-02-01"))
+ )
+ self.assertFalse(
+ self.partner_2.is_date_in_holiday(fields.Date.from_string("2021-02-01"))
+ )
+ self.assertFalse(
+ self.partner_2.is_date_in_holiday(fields.Date.from_string("2021-02-10"))
+ )
+ self.assertFalse(
+ self.partner_2.is_date_in_holiday(fields.Date.from_string("2021-03-01"))
+ )
+
+ def test_invoice_payment_term_partner_1(self):
+ invoice_form = Form(
+ self.env['account.invoice'].with_context(
+ default_journal_id=self.journal.id,
+ default_partner_id=self.partner_1.id,
+ default_date_invoice="2021-02-01"
+ ),
+ view="account.invoice_form"
+ )
+ invoice_form.payment_term_id = self.payment_term_immediate
+ self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-03-01"))
+ invoice_form.payment_term_id = self.payment_term_10_days
+ self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-03-01"))
+ # Save invoice and check action_invoice_open function
+ with invoice_form.invoice_line_ids.new() as line:
+ line.product_id = self.product
+ invoice = invoice_form.save()
+ invoice.date_due = "2021-02-01"
+ self.assertEqual(invoice.date_due, fields.Date.from_string("2021-02-01"))
+ invoice.action_invoice_open()
+ self.assertEqual(invoice.date_due, fields.Date.from_string("2021-03-01"))
+
+ def test_invoice_payment_term_partner_2(self):
+ invoice_form = Form(
+ self.env['account.invoice'].with_context(
+ default_journal_id=self.journal.id,
+ default_partner_id=self.partner_2.id,
+ default_date_invoice="2021-02-01"
+ ),
+ view="account.invoice_form"
+ )
+ invoice_form.payment_term_id = self.payment_term_immediate
+ self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-02-01"))
+ invoice_form.payment_term_id = self.payment_term_10_days
+ self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-02-11"))
diff --git a/account_payment_term_partner_holiday/views/res_partner_view.xml b/account_payment_term_partner_holiday/views/res_partner_view.xml
new file mode 100644
index 000000000000..0f2e3d31bf91
--- /dev/null
+++ b/account_payment_term_partner_holiday/views/res_partner_view.xml
@@ -0,0 +1,20 @@
+
+
+
+ res.partner.holiday_ids
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From ebb683476731d075703a776e395b9ecf3a5843eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?=
Date: Mon, 5 Jul 2021 08:09:27 +0200
Subject: [PATCH 02/19] [IMP] account_payment_term_partner_holiday: black,
isort, prettier
---
.../__manifest__.py | 5 +-
.../models/account_invoice.py | 5 +-
.../models/account_payment_term.py | 3 +-
.../models/res_partner.py | 31 ++---
.../tests/test_partner_holiday.py | 117 +++++++++++-------
.../views/res_partner_view.xml | 12 +-
6 files changed, 95 insertions(+), 78 deletions(-)
diff --git a/account_payment_term_partner_holiday/__manifest__.py b/account_payment_term_partner_holiday/__manifest__.py
index 378fd281b5c9..69d5059c8a44 100644
--- a/account_payment_term_partner_holiday/__manifest__.py
+++ b/account_payment_term_partner_holiday/__manifest__.py
@@ -12,8 +12,5 @@
"depends": ["account"],
"maintainers": ["victoralmau"],
"development_status": "Production/Stable",
- "data": [
- "security/ir.model.access.csv",
- "views/res_partner_view.xml"
- ],
+ "data": ["security/ir.model.access.csv", "views/res_partner_view.xml"],
}
diff --git a/account_payment_term_partner_holiday/models/account_invoice.py b/account_payment_term_partner_holiday/models/account_invoice.py
index d60068607347..d2cf6f403b14 100644
--- a/account_payment_term_partner_holiday/models/account_invoice.py
+++ b/account_payment_term_partner_holiday/models/account_invoice.py
@@ -1,14 +1,15 @@
# Copyright 2021 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-from odoo import api, models
from dateutil.relativedelta import relativedelta
+from odoo import api, models
+
class AccountInvoice(models.Model):
_inherit = "account.invoice"
- @api.onchange('payment_term_id', 'date_invoice')
+ @api.onchange("payment_term_id", "date_invoice")
def _onchange_payment_term_date_invoice(self):
_self = self
if self.partner_id:
diff --git a/account_payment_term_partner_holiday/models/account_payment_term.py b/account_payment_term_partner_holiday/models/account_payment_term.py
index 29afa8e095fd..9e521da691aa 100644
--- a/account_payment_term_partner_holiday/models/account_payment_term.py
+++ b/account_payment_term_partner_holiday/models/account_payment_term.py
@@ -1,9 +1,10 @@
# Copyright 2021 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-from odoo import api, fields, models
from dateutil.relativedelta import relativedelta
+from odoo import api, fields, models
+
class AccountPaymentTerm(models.Model):
_inherit = "account.payment.term"
diff --git a/account_payment_term_partner_holiday/models/res_partner.py b/account_payment_term_partner_holiday/models/res_partner.py
index bace9a81b26b..8974b813cbf1 100644
--- a/account_payment_term_partner_holiday/models/res_partner.py
+++ b/account_payment_term_partner_holiday/models/res_partner.py
@@ -13,15 +13,17 @@ class ResPartner(models.Model):
inverse_name="partner_id",
string="Payment Terms Holidays",
copy=True,
- auto_join=True
+ auto_join=True,
)
def is_date_in_holiday(self, date):
if isinstance(date, str):
date = fields.Date.from_string(date)
res = self.holiday_ids.filtered(
- lambda x: int(x.month_from) <= date.month and int(x.month_to) >= date.month
- and int(x.day_from) <= date.day and int(x.day_to) >= date.day
+ lambda x: int(x.month_from) <= date.month
+ and int(x.month_to) >= date.month
+ and int(x.day_from) <= date.day
+ and int(x.day_to) >= date.day
)
if bool(res):
res = res[0]
@@ -37,7 +39,8 @@ def is_date_in_holiday(self, date):
return [
fields.Date.from_string(
"%s-%s-%s" % (date.year, res.month_from, res.day_from)
- ), res_date_to
+ ),
+ res_date_to,
]
return False
@@ -65,7 +68,7 @@ def _selection_months(self):
("9", _("September")),
("10", _("October")),
("11", _("November")),
- ("12", _("December"))
+ ("12", _("December")),
]
partner_id = fields.Many2one(
@@ -74,27 +77,19 @@ def _selection_months(self):
required=True,
ondelete="cascade",
index=True,
- copy=False
+ copy=False,
)
day_from = fields.Selection(
- selection="_selection_days",
- string="Day from",
- required=True,
+ selection="_selection_days", string="Day from", required=True,
)
month_from = fields.Selection(
- selection="_selection_months",
- string="Month from",
- required=True,
+ selection="_selection_months", string="Month from", required=True,
)
day_to = fields.Selection(
- selection="_selection_days",
- string="Day to",
- required=True,
+ selection="_selection_days", string="Day to", required=True,
)
month_to = fields.Selection(
- selection="_selection_months",
- string="Month to",
- required=True,
+ selection="_selection_months", string="Month to", required=True,
)
@api.constrains("day_from", "month_from", "day_to", "month_to")
diff --git a/account_payment_term_partner_holiday/tests/test_partner_holiday.py b/account_payment_term_partner_holiday/tests/test_partner_holiday.py
index 0e08e1c51ec4..291879a29bc2 100644
--- a/account_payment_term_partner_holiday/tests/test_partner_holiday.py
+++ b/account_payment_term_partner_holiday/tests/test_partner_holiday.py
@@ -1,62 +1,85 @@
# Copyright 2021 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from odoo import fields
from odoo.tests import common
from odoo.tests.common import Form
-from odoo import fields
class TestPartnerHoliday(common.TransactionCase):
def setUp(self):
super().setUp()
- self.partner_1 = self.env["res.partner"].create({
- "name": "Partner test 1",
- "holiday_ids": [(0, 0, {
- "day_from": "1",
- "month_from": "2",
- "day_to": "31",
- "month_to": "2",
- })]
- })
+ self.partner_1 = self.env["res.partner"].create(
+ {
+ "name": "Partner test 1",
+ "holiday_ids": [
+ (
+ 0,
+ 0,
+ {
+ "day_from": "1",
+ "month_from": "2",
+ "day_to": "31",
+ "month_to": "2",
+ },
+ )
+ ],
+ }
+ )
self.partner_2 = self.env["res.partner"].create({"name": "Partner test 2"})
- self.payment_term_immediate = self.env["account.payment.term"].create({
- "name": "Immediate",
- "line_ids": [(0, 0, {
- "value": "balance",
- "days": 0,
- "option": "day_after_invoice_date"
- })]
- })
- self.payment_term_10_days = self.env["account.payment.term"].create({
- "name": "10 Days",
- "line_ids": [(0, 0, {
- "value": "balance",
- "days": 10,
- "option": "day_after_invoice_date"
- })]
- })
- self.journal = self.env["account.journal"].create({
- "name": "Test sale",
- "type": "sale",
- "code": "TEST-SALE"
- })
- self.product = self.env["product.product"].create({
- "name": "Test product",
- "type": "service"
- })
+ self.payment_term_immediate = self.env["account.payment.term"].create(
+ {
+ "name": "Immediate",
+ "line_ids": [
+ (
+ 0,
+ 0,
+ {
+ "value": "balance",
+ "days": 0,
+ "option": "day_after_invoice_date",
+ },
+ )
+ ],
+ }
+ )
+ self.payment_term_10_days = self.env["account.payment.term"].create(
+ {
+ "name": "10 Days",
+ "line_ids": [
+ (
+ 0,
+ 0,
+ {
+ "value": "balance",
+ "days": 10,
+ "option": "day_after_invoice_date",
+ },
+ )
+ ],
+ }
+ )
+ self.journal = self.env["account.journal"].create(
+ {"name": "Test sale", "type": "sale", "code": "TEST-SALE"}
+ )
+ self.product = self.env["product.product"].create(
+ {"name": "Test product", "type": "service"}
+ )
def test_check_dates_in_partner_1(self):
self.assertEqual(
- self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-02-01")), [
+ self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-02-01")),
+ [
fields.Date.from_string("2021-02-01"),
- fields.Date.from_string("2021-02-28")
- ]
+ fields.Date.from_string("2021-02-28"),
+ ],
)
self.assertEqual(
- self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-02-10")), [
+ self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-02-10")),
+ [
fields.Date.from_string("2021-02-01"),
- fields.Date.from_string("2021-02-28")
- ]
+ fields.Date.from_string("2021-02-28"),
+ ],
)
self.assertFalse(
self.partner_1.is_date_in_holiday(fields.Date.from_string("2021-03-01"))
@@ -78,12 +101,12 @@ def test_check_dates_in_partner_2(self):
def test_invoice_payment_term_partner_1(self):
invoice_form = Form(
- self.env['account.invoice'].with_context(
+ self.env["account.invoice"].with_context(
default_journal_id=self.journal.id,
default_partner_id=self.partner_1.id,
- default_date_invoice="2021-02-01"
+ default_date_invoice="2021-02-01",
),
- view="account.invoice_form"
+ view="account.invoice_form",
)
invoice_form.payment_term_id = self.payment_term_immediate
self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-03-01"))
@@ -100,12 +123,12 @@ def test_invoice_payment_term_partner_1(self):
def test_invoice_payment_term_partner_2(self):
invoice_form = Form(
- self.env['account.invoice'].with_context(
+ self.env["account.invoice"].with_context(
default_journal_id=self.journal.id,
default_partner_id=self.partner_2.id,
- default_date_invoice="2021-02-01"
+ default_date_invoice="2021-02-01",
),
- view="account.invoice_form"
+ view="account.invoice_form",
)
invoice_form.payment_term_id = self.payment_term_immediate
self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-02-01"))
diff --git a/account_payment_term_partner_holiday/views/res_partner_view.xml b/account_payment_term_partner_holiday/views/res_partner_view.xml
index 0f2e3d31bf91..25879d850aad 100644
--- a/account_payment_term_partner_holiday/views/res_partner_view.xml
+++ b/account_payment_term_partner_holiday/views/res_partner_view.xml
@@ -1,17 +1,17 @@
-
+
res.partner.holiday_ids
res.partner
-
+
-
-
-
-
+
+
+
+
From 492ffab41326dbd0efefe7183e55d99c3d671a86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?=
Date: Mon, 5 Jul 2021 09:45:41 +0200
Subject: [PATCH 03/19] [MIG] account_payment_term_partner_holiday: Migration
to 13.0
---
.../__manifest__.py | 2 +-
.../models/__init__.py | 2 +-
.../models/account_invoice.py | 37 --------
.../models/account_move.py | 14 +++
.../models/account_payment_term.py | 7 +-
.../models/res_partner.py | 2 +-
.../tests/test_partner_holiday.py | 92 +++++++++++++------
7 files changed, 86 insertions(+), 70 deletions(-)
delete mode 100644 account_payment_term_partner_holiday/models/account_invoice.py
create mode 100644 account_payment_term_partner_holiday/models/account_move.py
diff --git a/account_payment_term_partner_holiday/__manifest__.py b/account_payment_term_partner_holiday/__manifest__.py
index 69d5059c8a44..cbd92b1303d8 100644
--- a/account_payment_term_partner_holiday/__manifest__.py
+++ b/account_payment_term_partner_holiday/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "Account Payment Term Partner Holiday",
- "version": "12.0.1.0.0",
+ "version": "13.0.1.0.0",
"website": "https://github.com/OCA/account-payment",
"author": "Tecnativa, Odoo Community Association (OCA)",
"license": "AGPL-3",
diff --git a/account_payment_term_partner_holiday/models/__init__.py b/account_payment_term_partner_holiday/models/__init__.py
index d0e7f9972b96..810b018a375f 100644
--- a/account_payment_term_partner_holiday/models/__init__.py
+++ b/account_payment_term_partner_holiday/models/__init__.py
@@ -1,3 +1,3 @@
-from . import account_invoice
+from . import account_move
from . import account_payment_term
from . import res_partner
diff --git a/account_payment_term_partner_holiday/models/account_invoice.py b/account_payment_term_partner_holiday/models/account_invoice.py
deleted file mode 100644
index d2cf6f403b14..000000000000
--- a/account_payment_term_partner_holiday/models/account_invoice.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2021 Tecnativa - Víctor Martínez
-# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-
-from dateutil.relativedelta import relativedelta
-
-from odoo import api, models
-
-
-class AccountInvoice(models.Model):
- _inherit = "account.invoice"
-
- @api.onchange("payment_term_id", "date_invoice")
- def _onchange_payment_term_date_invoice(self):
- _self = self
- if self.partner_id:
- _self = self.with_context(move_partner_id=self.partner_id.id)
- super(AccountInvoice, _self)._onchange_payment_term_date_invoice()
-
- @api.onchange("date_due")
- def _onchange_date_due_account_payment_term_partner_holiday(self):
- if self.date_due and self.payment_term_id and self.partner_id:
- new_date_due = self.date_due
- is_date_in_holiday = self.partner_id.is_date_in_holiday(new_date_due)
- if is_date_in_holiday:
- res_date_end = is_date_in_holiday[1]
- new_date_due = res_date_end + relativedelta(days=1)
- if new_date_due != self.date_due:
- self.date_due = new_date_due
-
- def action_move_create(self):
- """Inject a context for getting the partner when computing payment term.
- The trade-off is that we should split the call to super record per record,
- but it shouldn't impact in performance.
- """
- for item in self:
- _item = item.with_context(move_partner_id=item.partner_id.id)
- return super(AccountInvoice, _item).action_move_create()
diff --git a/account_payment_term_partner_holiday/models/account_move.py b/account_payment_term_partner_holiday/models/account_move.py
new file mode 100644
index 000000000000..28769c111449
--- /dev/null
+++ b/account_payment_term_partner_holiday/models/account_move.py
@@ -0,0 +1,14 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+from odoo import models
+
+
+class AccountMove(models.Model):
+ _inherit = "account.move"
+
+ def _recompute_payment_terms_lines(self):
+ _self = self
+ if self.partner_id:
+ _self = self.with_context(move_partner_id=self.partner_id.id)
+ super(AccountMove, _self)._recompute_payment_terms_lines()
diff --git a/account_payment_term_partner_holiday/models/account_payment_term.py b/account_payment_term_partner_holiday/models/account_payment_term.py
index 9e521da691aa..45f86954ab16 100644
--- a/account_payment_term_partner_holiday/models/account_payment_term.py
+++ b/account_payment_term_partner_holiday/models/account_payment_term.py
@@ -3,15 +3,14 @@
from dateutil.relativedelta import relativedelta
-from odoo import api, fields, models
+from odoo import fields, models
class AccountPaymentTerm(models.Model):
_inherit = "account.payment.term"
- @api.one
- def compute(self, value, date_ref=False):
- result = super().compute(value=value, date_ref=date_ref)[0]
+ def compute(self, value, date_ref=False, currency=None):
+ result = super().compute(value=value, date_ref=date_ref, currency=currency)
ctx = self.env.context
partner_id = ctx.get("move_partner_id", ctx.get("default_partner_id"))
if partner_id:
diff --git a/account_payment_term_partner_holiday/models/res_partner.py b/account_payment_term_partner_holiday/models/res_partner.py
index 8974b813cbf1..12ea9162a31f 100644
--- a/account_payment_term_partner_holiday/models/res_partner.py
+++ b/account_payment_term_partner_holiday/models/res_partner.py
@@ -34,7 +34,7 @@ def is_date_in_holiday(self, date):
res_date_to = fields.Date.from_string(
"%s-%s-%s" % (date.year, res.month_to, day_to)
)
- except:
+ except ValueError:
day_to -= 1
return [
fields.Date.from_string(
diff --git a/account_payment_term_partner_holiday/tests/test_partner_holiday.py b/account_payment_term_partner_holiday/tests/test_partner_holiday.py
index 291879a29bc2..c639efe383f1 100644
--- a/account_payment_term_partner_holiday/tests/test_partner_holiday.py
+++ b/account_payment_term_partner_holiday/tests/test_partner_holiday.py
@@ -65,6 +65,24 @@ def setUp(self):
self.product = self.env["product.product"].create(
{"name": "Test product", "type": "service"}
)
+ self.env["account.account"].create(
+ {
+ "name": "Test Account",
+ "code": "TEST",
+ "user_type_id": self.env.ref("account.data_account_type_receivable").id,
+ "reconcile": True,
+ }
+ )
+ self.env["account.account"].create(
+ {
+ "name": "Test Account",
+ "code": "ACC",
+ "user_type_id": self.env.ref(
+ "account.data_account_type_other_income"
+ ).id,
+ "reconcile": True,
+ }
+ )
def test_check_dates_in_partner_1(self):
self.assertEqual(
@@ -99,38 +117,60 @@ def test_check_dates_in_partner_2(self):
self.partner_2.is_date_in_holiday(fields.Date.from_string("2021-03-01"))
)
- def test_invoice_payment_term_partner_1(self):
+ def _create_invoice_form(self, partner_id):
invoice_form = Form(
- self.env["account.invoice"].with_context(
+ self.env["account.move"].with_context(
default_journal_id=self.journal.id,
- default_partner_id=self.partner_1.id,
- default_date_invoice="2021-02-01",
+ default_partner_id=partner_id,
+ default_type="out_invoice",
+ default_invoice_date="2021-02-01",
),
- view="account.invoice_form",
)
- invoice_form.payment_term_id = self.payment_term_immediate
- self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-03-01"))
- invoice_form.payment_term_id = self.payment_term_10_days
- self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-03-01"))
- # Save invoice and check action_invoice_open function
with invoice_form.invoice_line_ids.new() as line:
line.product_id = self.product
+ return invoice_form
+
+ def test_invoice_payment_term_partner_1_payment_term_immediate(self):
+ invoice_form = self._create_invoice_form(self.partner_1.id)
+ invoice_form.invoice_payment_term_id = self.payment_term_immediate
invoice = invoice_form.save()
- invoice.date_due = "2021-02-01"
- self.assertEqual(invoice.date_due, fields.Date.from_string("2021-02-01"))
- invoice.action_invoice_open()
- self.assertEqual(invoice.date_due, fields.Date.from_string("2021-03-01"))
+ invoice_move_line = invoice.line_ids.filtered("date_maturity")
+ self.assertEqual(
+ invoice_move_line.date_maturity, fields.Date.from_string("2021-03-01")
+ )
- def test_invoice_payment_term_partner_2(self):
- invoice_form = Form(
- self.env["account.invoice"].with_context(
- default_journal_id=self.journal.id,
- default_partner_id=self.partner_2.id,
- default_date_invoice="2021-02-01",
- ),
- view="account.invoice_form",
+ def test_invoice_payment_term_partner_1_payment_term_10_days(self):
+ invoice_form = self._create_invoice_form(self.partner_1.id)
+ invoice_form.invoice_payment_term_id = self.payment_term_10_days
+ invoice = invoice_form.save()
+ invoice_move_line = invoice.line_ids.filtered("date_maturity")
+ self.assertEqual(
+ invoice_move_line.date_maturity, fields.Date.from_string("2021-03-01")
+ )
+
+ def test_invoice_payment_term_partner_1_default(self):
+ invoice_form = self._create_invoice_form(self.partner_1.id)
+ invoice_form.invoice_date_due = "2021-02-01"
+ invoice = invoice_form.save()
+ invoice_move_line = invoice.line_ids.filtered("date_maturity")
+ self.assertEqual(
+ invoice_move_line.date_maturity, fields.Date.from_string("2021-02-01")
+ )
+
+ def test_invoice_payment_term_partner_2_payment_term_immediate(self):
+ invoice_form = self._create_invoice_form(self.partner_2.id)
+ invoice_form.invoice_payment_term_id = self.payment_term_immediate
+ invoice = invoice_form.save()
+ invoice_move_line = invoice.line_ids.filtered("date_maturity")
+ self.assertEqual(
+ invoice_move_line.date_maturity, fields.Date.from_string("2021-02-01")
+ )
+
+ def test_invoice_payment_term_partner_2_payment_term_10_days(self):
+ invoice_form = self._create_invoice_form(self.partner_2.id)
+ invoice_form.invoice_payment_term_id = self.payment_term_10_days
+ invoice = invoice_form.save()
+ invoice_move_line = invoice.line_ids.filtered("date_maturity")
+ self.assertEqual(
+ invoice_move_line.date_maturity, fields.Date.from_string("2021-02-11")
)
- invoice_form.payment_term_id = self.payment_term_immediate
- self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-02-01"))
- invoice_form.payment_term_id = self.payment_term_10_days
- self.assertEqual(invoice_form.date_due, fields.Date.from_string("2021-02-11"))
From b9bf1ca2f0a7eef762c6173e65279eaf99997386 Mon Sep 17 00:00:00 2001
From: oca-travis
Date: Thu, 8 Jul 2021 10:40:39 +0000
Subject: [PATCH 04/19] [UPD] Update account_payment_term_partner_holiday.pot
---
.../account_payment_term_partner_holiday.pot | 41 +++++++++----------
1 file changed, 20 insertions(+), 21 deletions(-)
diff --git a/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot b/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot
index c038beed2658..9a4709bde78d 100644
--- a/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot
+++ b/account_payment_term_partner_holiday/i18n/account_payment_term_partner_holiday.pot
@@ -1,12 +1,12 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
-# * account_payment_term_partner_holiday
+# * account_payment_term_partner_holiday
#
msgid ""
msgstr ""
-"Project-Id-Version: Odoo Server 12.0\n"
+"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
-"Last-Translator: <>\n"
+"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -14,13 +14,13 @@ msgstr ""
"Plural-Forms: \n"
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:60
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "April"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:64
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "August"
msgstr ""
@@ -51,7 +51,7 @@ msgid "Day to"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:68
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "December"
msgstr ""
@@ -62,7 +62,7 @@ msgid "Display Name"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:58
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "February"
msgstr ""
@@ -73,24 +73,24 @@ msgid "ID"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: model:ir.model,name:account_payment_term_partner_holiday.model_account_invoice
-msgid "Invoice"
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
+#, python-format
+msgid "January"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:57
-#, python-format
-msgid "January"
+#: model:ir.model,name:account_payment_term_partner_holiday.model_account_move
+msgid "Journal Entries"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:63
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "July"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:62
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "June"
msgstr ""
@@ -111,13 +111,13 @@ msgid "Last Updated on"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:59
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "March"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:61
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "May"
msgstr ""
@@ -133,13 +133,13 @@ msgid "Month to"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:67
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "November"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:66
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "October"
msgstr ""
@@ -166,14 +166,13 @@ msgid "Payment Terms Holidays"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:65
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "September"
msgstr ""
#. module: account_payment_term_partner_holiday
-#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:108
+#: code:addons/account_payment_term_partner_holiday/models/res_partner.py:0
#, python-format
msgid "You can't set the ending holidays period before the beginning."
msgstr ""
-
From 0635674e4307ca445ee1645875dd1daeeeff8657 Mon Sep 17 00:00:00 2001
From: OCA-git-bot
Date: Thu, 8 Jul 2021 10:52:06 +0000
Subject: [PATCH 05/19] [UPD] README.rst
---
account_payment_term_partner_holiday/README.rst | 10 +++++-----
.../static/description/index.html | 6 +++---
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/account_payment_term_partner_holiday/README.rst b/account_payment_term_partner_holiday/README.rst
index 098dc00333e8..2858627013de 100644
--- a/account_payment_term_partner_holiday/README.rst
+++ b/account_payment_term_partner_holiday/README.rst
@@ -14,13 +14,13 @@ Account Payment Term Partner Holiday
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--payment-lightgray.png?logo=github
- :target: https://github.com/OCA/account-payment/tree/12.0/account_payment_term_partner_holiday
+ :target: https://github.com/OCA/account-payment/tree/13.0/account_payment_term_partner_holiday
:alt: OCA/account-payment
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/account-payment-12-0/account-payment-12-0-account_payment_term_partner_holiday
+ :target: https://translation.odoo-community.org/projects/account-payment-13-0/account-payment-13-0-account_payment_term_partner_holiday
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
- :target: https://runbot.odoo-community.org/runbot/96/12.0
+ :target: https://runbot.odoo-community.org/runbot/96/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -50,7 +50,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues `_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -91,6 +91,6 @@ Current `maintainer `__:
|maintainer-victoralmau|
-This module is part of the `OCA/account-payment `_ project on GitHub.
+This module is part of the `OCA/account-payment `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/account_payment_term_partner_holiday/static/description/index.html b/account_payment_term_partner_holiday/static/description/index.html
index b092ea7722f8..462afb0c735e 100644
--- a/account_payment_term_partner_holiday/static/description/index.html
+++ b/account_payment_term_partner_holiday/static/description/index.html
@@ -367,7 +367,7 @@ Account Payment Term Partner Holiday
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-
+
This addon adds the possibility of defining holiday periods in a
partner so as not to use those periods as the due date on invoices.
Table of contents
@@ -399,7 +399,7 @@
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
-feedback.
+feedback.
Do not contact contributors directly about support or help with technical issues.
From 0f95583bd6346e10367ba802fd3d33567815baca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?=
Date: Mon, 12 Jul 2021 10:08:02 +0200
Subject: [PATCH 06/19] [FIX+IMP] account_payment_term_partner_holiday: [FIX]
Improve is_date_in_holiday() to filtered correctly when day_to is less than
date to compare [IMP] Improve is_date_in_holiday() to work fine in child
partners [IMP] Add constraint to holidays to prevent month_to < month_from
[FIX] account_payment_term_partner_holiday: Change month_from and month_to fields to convert in 2 characters to order correctly holidays + Script migration
---
.../README.rst | 5 +
.../__manifest__.py | 2 +-
.../migrations/13.0.1.1.0/post-migration.py | 24 +++
.../models/account_move.py | 20 ++-
.../models/account_payment_term.py | 11 +-
.../models/res_partner.py | 78 ++++----
.../readme/ROADMAP.rst | 1 +
.../static/description/index.html | 29 +--
.../tests/test_partner_holiday.py | 166 ++++++++++++++----
.../views/res_partner_view.xml | 5 +-
10 files changed, 252 insertions(+), 89 deletions(-)
create mode 100644 account_payment_term_partner_holiday/migrations/13.0.1.1.0/post-migration.py
create mode 100644 account_payment_term_partner_holiday/readme/ROADMAP.rst
diff --git a/account_payment_term_partner_holiday/README.rst b/account_payment_term_partner_holiday/README.rst
index 2858627013de..3a5779c9963a 100644
--- a/account_payment_term_partner_holiday/README.rst
+++ b/account_payment_term_partner_holiday/README.rst
@@ -44,6 +44,11 @@ To use this module, you need to:
Invoices' and create or edit some record.
#. If the computed due date is inside a holidays period, it's moved to the first available date.
+Known issues / Roadmap
+======================
+
+* Due dates for invoices are not updated when new holidays are created after.
+
Bug Tracker
===========
diff --git a/account_payment_term_partner_holiday/__manifest__.py b/account_payment_term_partner_holiday/__manifest__.py
index cbd92b1303d8..49f9be504b34 100644
--- a/account_payment_term_partner_holiday/__manifest__.py
+++ b/account_payment_term_partner_holiday/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "Account Payment Term Partner Holiday",
- "version": "13.0.1.0.0",
+ "version": "13.0.1.1.0",
"website": "https://github.com/OCA/account-payment",
"author": "Tecnativa, Odoo Community Association (OCA)",
"license": "AGPL-3",
diff --git a/account_payment_term_partner_holiday/migrations/13.0.1.1.0/post-migration.py b/account_payment_term_partner_holiday/migrations/13.0.1.1.0/post-migration.py
new file mode 100644
index 000000000000..b62ca2530d8b
--- /dev/null
+++ b/account_payment_term_partner_holiday/migrations/13.0.1.1.0/post-migration.py
@@ -0,0 +1,24 @@
+# Copyright 2021 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from openupgradelib import openupgrade
+from psycopg2 import sql
+
+
+def convert_field_to_two_characters(env, field_name):
+ openupgrade.logged_query(
+ env.cr,
+ sql.SQL(
+ """
+ UPDATE res_partner_holiday
+ SET {field_name} = CONCAT('0', {field_name})
+ WHERE length({field_name}) = 1
+ """
+ ).format(field_name=field_name),
+ )
+
+
+@openupgrade.migrate()
+def migrate(env, version):
+ convert_field_to_two_characters(env, sql.Identifier("month_from"))
+ convert_field_to_two_characters(env, sql.Identifier("month_to"))
diff --git a/account_payment_term_partner_holiday/models/account_move.py b/account_payment_term_partner_holiday/models/account_move.py
index 28769c111449..a7ca5b5a765d 100644
--- a/account_payment_term_partner_holiday/models/account_move.py
+++ b/account_payment_term_partner_holiday/models/account_move.py
@@ -1,7 +1,7 @@
# Copyright 2021 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-from odoo import models
+from odoo import api, models
class AccountMove(models.Model):
@@ -12,3 +12,21 @@ def _recompute_payment_terms_lines(self):
if self.partner_id:
_self = self.with_context(move_partner_id=self.partner_id.id)
super(AccountMove, _self)._recompute_payment_terms_lines()
+
+ @api.onchange("invoice_date_due")
+ def _onchange_invoice_date_due_account_payment_term_partner_holiday(self):
+ if self.invoice_date_due and self.partner_id:
+ new_invoice_date_due = self.partner_id._get_valid_due_date(
+ self.invoice_date_due
+ )
+ if new_invoice_date_due != self.invoice_date_due:
+ self.invoice_date_due = new_invoice_date_due
+
+ def action_post(self):
+ """Inject a context for getting the partner when computing payment term.
+ The trade-off is that we should split the call to super record per record,
+ but it shouldn't impact in performance.
+ """
+ for item in self:
+ _item = item.with_context(move_partner_id=item.partner_id.id)
+ return super(AccountMove, _item).action_post()
diff --git a/account_payment_term_partner_holiday/models/account_payment_term.py b/account_payment_term_partner_holiday/models/account_payment_term.py
index 45f86954ab16..6b8967e75640 100644
--- a/account_payment_term_partner_holiday/models/account_payment_term.py
+++ b/account_payment_term_partner_holiday/models/account_payment_term.py
@@ -1,8 +1,6 @@
# Copyright 2021 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-from dateutil.relativedelta import relativedelta
-
from odoo import fields, models
@@ -17,12 +15,9 @@ def compute(self, value, date_ref=False, currency=None):
partner = self.env["res.partner"].browse(partner_id)
result2 = []
for item in result:
- date_item = item[0]
- is_date_in_holiday = partner.is_date_in_holiday(date_item)
- if is_date_in_holiday:
- next_date = is_date_in_holiday[1]
- next_date += relativedelta(days=1)
- result2.append((fields.Date.to_string(next_date), item[1]))
+ new_date_item = partner._get_valid_due_date(item[0])
+ if new_date_item != item[0]:
+ result2.append((fields.Date.to_string(new_date_item), item[1]))
else:
result2.append(item)
result = result2
diff --git a/account_payment_term_partner_holiday/models/res_partner.py b/account_payment_term_partner_holiday/models/res_partner.py
index 12ea9162a31f..8a424ce10992 100644
--- a/account_payment_term_partner_holiday/models/res_partner.py
+++ b/account_payment_term_partner_holiday/models/res_partner.py
@@ -1,6 +1,11 @@
# Copyright 2021 Tecnativa - Víctor Martínez
+# Copyright 2021 Tecnativa - João Marques
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+import calendar
+
+from dateutil.relativedelta import relativedelta
+
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
@@ -16,34 +21,35 @@ class ResPartner(models.Model):
auto_join=True,
)
+ def _get_valid_due_date(self, date):
+ if isinstance(date, str):
+ date = fields.Date.from_string(date)
+ is_date_in_holiday = self.is_date_in_holiday(date)
+ while is_date_in_holiday:
+ date = is_date_in_holiday[1] + relativedelta(days=1)
+ is_date_in_holiday = self.is_date_in_holiday(date)
+ return date
+
def is_date_in_holiday(self, date):
if isinstance(date, str):
date = fields.Date.from_string(date)
- res = self.holiday_ids.filtered(
- lambda x: int(x.month_from) <= date.month
- and int(x.month_to) >= date.month
- and int(x.day_from) <= date.day
- and int(x.day_to) >= date.day
- )
- if bool(res):
- res = res[0]
- res_date_to = False
- day_to = int(res.day_to)
- while not res_date_to:
- try:
- res_date_to = fields.Date.from_string(
- "%s-%s-%s" % (date.year, res.month_to, day_to)
- )
- except ValueError:
- day_to -= 1
- return [
- fields.Date.from_string(
- "%s-%s-%s" % (date.year, res.month_from, res.day_from)
- ),
- res_date_to,
- ]
+ for holiday in self.commercial_partner_id.holiday_ids:
+ holiday_start_date = self._generate_field_date(
+ date.year, int(holiday.month_from), int(holiday.day_from)
+ )
+ holiday_end_date = self._generate_field_date(
+ date.year, int(holiday.month_to), int(holiday.day_to)
+ )
+ if date >= holiday_start_date and date <= holiday_end_date:
+ return [holiday_start_date, holiday_end_date]
return False
+ def _generate_field_date(self, year, month, day):
+ # When the user selects a date that does not exist, assume the last day
+ # for that month
+ days = (day, max(calendar.monthrange(year, month)))
+ return fields.Date.from_string("%s-%s-%s" % (year, month, min(days)))
+
class ResPartnerHoliday(models.Model):
_name = "res.partner.holiday"
@@ -57,15 +63,15 @@ def _selection_days(self):
@api.model
def _selection_months(self):
return [
- ("1", _("January")),
- ("2", _("February")),
- ("3", _("March")),
- ("4", _("April")),
- ("5", _("May")),
- ("6", _("June")),
- ("7", _("July")),
- ("8", _("August")),
- ("9", _("September")),
+ ("01", _("January")),
+ ("02", _("February")),
+ ("03", _("March")),
+ ("04", _("April")),
+ ("05", _("May")),
+ ("06", _("June")),
+ ("07", _("July")),
+ ("08", _("August")),
+ ("09", _("September")),
("10", _("October")),
("11", _("November")),
("12", _("December")),
@@ -92,6 +98,14 @@ def _selection_months(self):
selection="_selection_months", string="Month to", required=True,
)
+ _sql_constraints = [
+ (
+ "month_consistency",
+ "CHECK(month_from <= month_to)",
+ "Month from should be higher than month from",
+ ),
+ ]
+
@api.constrains("day_from", "month_from", "day_to", "month_to")
def _check_from_end_dates(self):
for item in self:
diff --git a/account_payment_term_partner_holiday/readme/ROADMAP.rst b/account_payment_term_partner_holiday/readme/ROADMAP.rst
new file mode 100644
index 000000000000..3953ecddaa3e
--- /dev/null
+++ b/account_payment_term_partner_holiday/readme/ROADMAP.rst
@@ -0,0 +1 @@
+* Due dates for invoices are not updated when new holidays are created after.
diff --git a/account_payment_term_partner_holiday/static/description/index.html b/account_payment_term_partner_holiday/static/description/index.html
index 462afb0c735e..e4a286c8ee7a 100644
--- a/account_payment_term_partner_holiday/static/description/index.html
+++ b/account_payment_term_partner_holiday/static/description/index.html
@@ -3,7 +3,7 @@
-
+
Account Payment Term Partner Holiday