From f966cb7bee524bce27dbcee6407c011ef111449e Mon Sep 17 00:00:00 2001 From: Kaynnan Date: Sat, 25 Apr 2026 20:04:10 -0300 Subject: [PATCH] [ADD] account_payment_term_installment: add new module --- account_payment_term_installment/README.rst | 105 ++++ account_payment_term_installment/__init__.py | 4 + .../__manifest__.py | 21 + .../models/__init__.py | 1 + .../models/account_payment_term.py | 65 +++ .../readme/CONTRIBUTORS.rst | 4 + .../readme/DESCRIPTION.rst | 1 + .../readme/USAGE.rst | 14 + .../static/description/index.html | 449 ++++++++++++++++++ .../tests/__init__.py | 1 + .../test_account_payment_term_installment.py | 65 +++ .../views/account_payment_term_view.xml | 19 + .../addons/account_payment_term_installment | 1 + .../account_payment_term_installment/setup.py | 6 + 14 files changed, 756 insertions(+) create mode 100644 account_payment_term_installment/README.rst create mode 100644 account_payment_term_installment/__init__.py create mode 100644 account_payment_term_installment/__manifest__.py create mode 100644 account_payment_term_installment/models/__init__.py create mode 100644 account_payment_term_installment/models/account_payment_term.py create mode 100644 account_payment_term_installment/readme/CONTRIBUTORS.rst create mode 100644 account_payment_term_installment/readme/DESCRIPTION.rst create mode 100644 account_payment_term_installment/readme/USAGE.rst create mode 100644 account_payment_term_installment/static/description/index.html create mode 100644 account_payment_term_installment/tests/__init__.py create mode 100644 account_payment_term_installment/tests/test_account_payment_term_installment.py create mode 100644 account_payment_term_installment/views/account_payment_term_view.xml create mode 120000 setup/account_payment_term_installment/odoo/addons/account_payment_term_installment create mode 100644 setup/account_payment_term_installment/setup.py diff --git a/account_payment_term_installment/README.rst b/account_payment_term_installment/README.rst new file mode 100644 index 00000000000..a86c9907783 --- /dev/null +++ b/account_payment_term_installment/README.rst @@ -0,0 +1,105 @@ +================================ +Account Payment Term Installment +================================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:ffcbc0544f94542ee6719e9502f4089138a561681273b6e6aeecac37c099684d + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |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/16.0/account_payment_term_installment + :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-16-0/account-payment-16-0-account_payment_term_installment + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-payment&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds the ability to define a number of installments on a payment term. Whenever the installment count or the interval between installments is changed, the payment term lines are regenerated automatically as equal installments separated by the configured interval, with the last line set as the balance. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +#. Go to *Accounting > Configuration > Payment Terms*. +#. Open or create a payment term. +#. Set the **Number of Installments** field to the desired value. +#. Optionally adjust the **Days Between Installments** (default 30). +#. The terms list is regenerated as equal installments plus a final balance line. + +.. warning:: + + Setting **Number of Installments** greater than 1 replaces the existing + payment term lines. Per-line customizations added by other modules + (e.g. ``account_payment_term_extension`` end-of-month/days-after fields, + ``account_payment_term_discount`` discount fields, + ``account_payment_term_partner_holiday`` holiday data) are not preserved + and must be reapplied after generation. + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Escodoo + +Contributors +~~~~~~~~~~~~ + +* `Escodoo `_: + + * Kaynnan Lemes + * Marcel Savegnago + +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-kaynnan| image:: https://github.com/kaynnan.png?size=40px + :target: https://github.com/kaynnan + :alt: kaynnan + +Current `maintainer `__: + +|maintainer-kaynnan| + +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_installment/__init__.py b/account_payment_term_installment/__init__.py new file mode 100644 index 00000000000..039da28ea58 --- /dev/null +++ b/account_payment_term_installment/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2026 Escodoo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/account_payment_term_installment/__manifest__.py b/account_payment_term_installment/__manifest__.py new file mode 100644 index 00000000000..d53e7e85325 --- /dev/null +++ b/account_payment_term_installment/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2026 Escodoo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Account Payment Term Installment", + "summary": """ + Generate payment term lines automatically from a desired number of + installments.""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Escodoo, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-payment", + "category": "Accounting & Finance", + "depends": ["account"], + "data": [ + "views/account_payment_term_view.xml", + ], + "installable": True, + "application": False, + "maintainers": ["kaynnan"], +} diff --git a/account_payment_term_installment/models/__init__.py b/account_payment_term_installment/models/__init__.py new file mode 100644 index 00000000000..2e019d679c4 --- /dev/null +++ b/account_payment_term_installment/models/__init__.py @@ -0,0 +1 @@ +from . import account_payment_term diff --git a/account_payment_term_installment/models/account_payment_term.py b/account_payment_term_installment/models/account_payment_term.py new file mode 100644 index 00000000000..14496bbfb83 --- /dev/null +++ b/account_payment_term_installment/models/account_payment_term.py @@ -0,0 +1,65 @@ +# Copyright 2026 Escodoo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import Command, _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountPaymentTerm(models.Model): + _inherit = "account.payment.term" + + installment_count = fields.Integer( + string="Number of Installments", + default=1, + help="When set greater than 1, the payment term lines are regenerated" + " automatically as equal installments separated by the configured" + " interval in days. The last line is always the balance.", + ) + installment_interval_days = fields.Integer( + string="Days Between Installments", + default=30, + help="Number of days added between each installment. The first" + " installment is due after this many days.", + ) + + @api.constrains("installment_count", "installment_interval_days") + def _check_installment_values(self): + for term in self: + if term.installment_count < 1: + raise ValidationError(_("Number of installments must be at least 1.")) + if term.installment_interval_days < 0: + raise ValidationError( + _("Days between installments must be zero or positive.") + ) + + @api.onchange("installment_count", "installment_interval_days") + def _onchange_installment_count(self): + if self.installment_count and self.installment_count > 1: + self._generate_installment_lines() + + def _generate_installment_lines(self): + self.ensure_one() + count = self.installment_count or 1 + interval = self.installment_interval_days or 0 + commands = [Command.clear()] + if count > 1: + percent = 100.0 / count + for i in range(1, count): + commands.append( + Command.create( + { + "value": "percent", + "value_amount": percent, + "days": interval * i, + } + ) + ) + commands.append( + Command.create( + { + "value": "balance", + "days": interval * count if count > 1 else 0, + } + ) + ) + self.line_ids = commands diff --git a/account_payment_term_installment/readme/CONTRIBUTORS.rst b/account_payment_term_installment/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..9c91c921af3 --- /dev/null +++ b/account_payment_term_installment/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `Escodoo `_: + + * Kaynnan Lemes + * Marcel Savegnago \ No newline at end of file diff --git a/account_payment_term_installment/readme/DESCRIPTION.rst b/account_payment_term_installment/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..5bf27bf8276 --- /dev/null +++ b/account_payment_term_installment/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module adds the ability to define a number of installments on a payment term. Whenever the installment count or the interval between installments is changed, the payment term lines are regenerated automatically as equal installments separated by the configured interval, with the last line set as the balance. diff --git a/account_payment_term_installment/readme/USAGE.rst b/account_payment_term_installment/readme/USAGE.rst new file mode 100644 index 00000000000..63cb23854e0 --- /dev/null +++ b/account_payment_term_installment/readme/USAGE.rst @@ -0,0 +1,14 @@ +#. Go to *Accounting > Configuration > Payment Terms*. +#. Open or create a payment term. +#. Set the **Number of Installments** field to the desired value. +#. Optionally adjust the **Days Between Installments** (default 30). +#. The terms list is regenerated as equal installments plus a final balance line. + +.. warning:: + + Setting **Number of Installments** greater than 1 replaces the existing + payment term lines. Per-line customizations added by other modules + (e.g. ``account_payment_term_extension`` end-of-month/days-after fields, + ``account_payment_term_discount`` discount fields, + ``account_payment_term_partner_holiday`` holiday data) are not preserved + and must be reapplied after generation. diff --git a/account_payment_term_installment/static/description/index.html b/account_payment_term_installment/static/description/index.html new file mode 100644 index 00000000000..f8504757575 --- /dev/null +++ b/account_payment_term_installment/static/description/index.html @@ -0,0 +1,449 @@ + + + + + +Account Payment Term Installment + + + +
+

Account Payment Term Installment

+ + +

Beta License: AGPL-3 OCA/account-payment Translate me on Weblate Try me on Runboat

+

This module adds the ability to define a number of installments on a payment term. Whenever the installment count or the interval between installments is changed, the payment term lines are regenerated automatically as equal installments separated by the configured interval, with the last line set as the balance.

+

Table of contents

+ +
+

Usage

+
    +
  1. Go to Accounting > Configuration > Payment Terms.
  2. +
  3. Open or create a payment term.
  4. +
  5. Set the Number of Installments field to the desired value.
  6. +
  7. Optionally adjust the Days Between Installments (default 30).
  8. +
  9. The terms list is regenerated as equal installments plus a final balance line.
  10. +
+
+

Warning

+

Setting Number of Installments greater than 1 replaces the existing +payment term lines. Per-line customizations added by other modules +(e.g. account_payment_term_extension end-of-month/days-after fields, +account_payment_term_discount discount fields, +account_payment_term_partner_holiday holiday data) are not preserved +and must be reapplied after generation.

+
+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Escodoo
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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:

+

kaynnan

+

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_installment/tests/__init__.py b/account_payment_term_installment/tests/__init__.py new file mode 100644 index 00000000000..7dd141098a2 --- /dev/null +++ b/account_payment_term_installment/tests/__init__.py @@ -0,0 +1 @@ +from . import test_account_payment_term_installment diff --git a/account_payment_term_installment/tests/test_account_payment_term_installment.py b/account_payment_term_installment/tests/test_account_payment_term_installment.py new file mode 100644 index 00000000000..651476c3713 --- /dev/null +++ b/account_payment_term_installment/tests/test_account_payment_term_installment.py @@ -0,0 +1,65 @@ +# Copyright 2026 Escodoo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError +from odoo.tests.common import Form, TransactionCase + + +class TestAccountPaymentTermInstallment(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.term = cls.env["account.payment.term"].create({"name": "Test Term"}) + + def test_default_values(self): + self.assertEqual(self.term.installment_count, 1) + self.assertEqual(self.term.installment_interval_days, 30) + + def test_generate_single_installment_keeps_balance(self): + self.term.installment_count = 1 + self.term._generate_installment_lines() + self.assertEqual(len(self.term.line_ids), 1) + self.assertEqual(self.term.line_ids[0].value, "balance") + self.assertEqual(self.term.line_ids[0].days, 0) + + def test_generate_three_installments(self): + self.term.installment_count = 3 + self.term.installment_interval_days = 30 + self.term._generate_installment_lines() + lines = self.term.line_ids.sorted("days") + self.assertEqual(len(lines), 3) + self.assertEqual(lines[0].value, "percent") + self.assertAlmostEqual(lines[0].value_amount, 100.0 / 3, places=4) + self.assertEqual(lines[0].days, 30) + self.assertEqual(lines[1].value, "percent") + self.assertEqual(lines[1].days, 60) + self.assertEqual(lines[2].value, "balance") + self.assertEqual(lines[2].days, 90) + + def test_generate_custom_interval(self): + self.term.installment_count = 2 + self.term.installment_interval_days = 15 + self.term._generate_installment_lines() + lines = self.term.line_ids.sorted("days") + self.assertEqual(len(lines), 2) + self.assertEqual(lines[0].days, 15) + self.assertEqual(lines[1].days, 30) + + def test_onchange_regenerates_lines(self): + form = Form(self.env["account.payment.term"]) + form.name = "Onchange Term" + form.installment_count = 4 + form.installment_interval_days = 10 + term = form.save() + lines = term.line_ids.sorted("days") + self.assertEqual(len(lines), 4) + self.assertEqual(lines[-1].value, "balance") + self.assertEqual(lines[-1].days, 40) + + def test_constrains_count_below_one(self): + with self.assertRaises(ValidationError): + self.term.installment_count = 0 + + def test_constrains_interval_negative(self): + with self.assertRaises(ValidationError): + self.term.installment_interval_days = -5 diff --git a/account_payment_term_installment/views/account_payment_term_view.xml b/account_payment_term_installment/views/account_payment_term_view.xml new file mode 100644 index 00000000000..66e9f788d2b --- /dev/null +++ b/account_payment_term_installment/views/account_payment_term_view.xml @@ -0,0 +1,19 @@ + + + + account.payment.term.form.installment + account.payment.term + + + + + + + + + + + diff --git a/setup/account_payment_term_installment/odoo/addons/account_payment_term_installment b/setup/account_payment_term_installment/odoo/addons/account_payment_term_installment new file mode 120000 index 00000000000..065b2e32ae6 --- /dev/null +++ b/setup/account_payment_term_installment/odoo/addons/account_payment_term_installment @@ -0,0 +1 @@ +../../../../account_payment_term_installment \ No newline at end of file diff --git a/setup/account_payment_term_installment/setup.py b/setup/account_payment_term_installment/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/account_payment_term_installment/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)