diff --git a/account_payment_batch_process_discount/README.rst b/account_payment_batch_process_discount/README.rst new file mode 100644 index 000000000000..20cfeac40a06 --- /dev/null +++ b/account_payment_batch_process_discount/README.rst @@ -0,0 +1,111 @@ +========================== +Discount on batch payments +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:7c17d9c000b0c7ea83366b8152a1d91de9b8ca8e1932a7d2b0460c9cad09990a + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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_batch_process_discount + :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_batch_process_discount + :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 allows you to define discounts for early payment and apply them on batch +payments. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +* Go to *Accounting > Invoicing > Payment Terms* +* Select or create a payment term +* Check the box "Early discount payment" +* Exclude the shipping and/or the tax amount +* Create a line with a discount for early payment, like 2% if paid within 15 days + +Usage +===== + +* Go to *Accounting > Customers > Invoices* or *Accounting > Vendors > Bills* +* Select various open invoices or bills +* Go to the Action menu +* Select Batch Payments +* Adjust the information +* Click on Make Payments + +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 +~~~~~~~ + +* Open Source Integrators + +Contributors +~~~~~~~~~~~~ + +* Open Source Integrators + + * Mayank Gosai + * Balaji Kannan + * Maxime Chambreuil + +* Camptocamp + * Denis Leemann + +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-mgosai| image:: https://github.com/mgosai.png?size=40px + :target: https://github.com/mgosai + :alt: mgosai + +Current `maintainer `__: + +|maintainer-mgosai| + +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_batch_process_discount/__init__.py b/account_payment_batch_process_discount/__init__.py new file mode 100644 index 000000000000..e1956e88e7d4 --- /dev/null +++ b/account_payment_batch_process_discount/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import models +from . import wizard diff --git a/account_payment_batch_process_discount/__manifest__.py b/account_payment_batch_process_discount/__manifest__.py new file mode 100644 index 000000000000..bbb54402b0c8 --- /dev/null +++ b/account_payment_batch_process_discount/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Discount on batch payments", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Open Source Integrators, Odoo Community Association (OCA)", + "category": "Accounting & Finance", + "maintainer": "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-payment", + "depends": ["account_payment_batch_process", "account_payment_term_discount"], + "data": [ + "views/account_move.xml", + ], + "development_status": "Beta", + "maintainers": ["mgosai"], + "auto_install": True, +} diff --git a/account_payment_batch_process_discount/i18n/account_payment_batch_process_discount.pot b/account_payment_batch_process_discount/i18n/account_payment_batch_process_discount.pot new file mode 100644 index 000000000000..0f3a3003b8dd --- /dev/null +++ b/account_payment_batch_process_discount/i18n/account_payment_batch_process_discount.pot @@ -0,0 +1,81 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_payment_batch_process_discount +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.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_batch_process_discount +#: model_terms:ir.ui.view,arch_db:account_payment_batch_process_discount.account_move_search_discount_date +msgid "Discount Invoice" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_move__display_name +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment_register__display_name +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment_term_line__display_name +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_invoice_payment_line__display_name +msgid "Display Name" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model_terms:ir.ui.view,arch_db:account_payment_batch_process_discount.account_move_search_discount_date +msgid "Filter invoices with early payment discounts" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_move__id +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment_register__id +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment_term_line__id +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_invoice_payment_line__id +msgid "ID" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model,name:account_payment_batch_process_discount.model_invoice_payment_line +msgid "Invoice Payment Line" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model,name:account_payment_batch_process_discount.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_move____last_update +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment_register____last_update +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment_term_line____last_update +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_invoice_payment_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model,name:account_payment_batch_process_discount.model_account_payment_term_line +msgid "Payment Terms Line" +msgstr "" + +#. module: account_payment_batch_process_discount +#: code:addons/account_payment_batch_process_discount/wizard/account_payment_register.py:0 +#, python-format +msgid "Please enter the payment date." +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model,name:account_payment_batch_process_discount.model_account_payment_register +msgid "Register Payment" +msgstr "" + +#. module: account_payment_batch_process_discount +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_bank_statement_line__valid_discount_date +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_move__valid_discount_date +#: model:ir.model.fields,field_description:account_payment_batch_process_discount.field_account_payment__valid_discount_date +msgid "Valid Discount Date" +msgstr "" diff --git a/account_payment_batch_process_discount/models/__init__.py b/account_payment_batch_process_discount/models/__init__.py new file mode 100644 index 000000000000..2cea17f65f94 --- /dev/null +++ b/account_payment_batch_process_discount/models/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import account_move, account_payment_term_line diff --git a/account_payment_batch_process_discount/models/account_move.py b/account_payment_batch_process_discount/models/account_move.py new file mode 100644 index 000000000000..e9758bee30a1 --- /dev/null +++ b/account_payment_batch_process_discount/models/account_move.py @@ -0,0 +1,24 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from dateutil.relativedelta import relativedelta + +from odoo import fields, models + + +class AccountMove(models.Model): + _inherit = "account.move" + + valid_discount_date = fields.Date() + + def action_post(self): + res = super().action_post() + for rec in self: + if rec.invoice_payment_term_id and rec.invoice_date: + # Check payment date discount validation + invoice_date = fields.Date.from_string(rec.invoice_date) + # Get discount validity days from payment terms + for line in rec.invoice_payment_term_id.line_ids: + rec.valid_discount_date = invoice_date + relativedelta( + days=line.discount_days + ) + return res diff --git a/account_payment_batch_process_discount/models/account_payment_term_line.py b/account_payment_batch_process_discount/models/account_payment_term_line.py new file mode 100644 index 000000000000..b1da878128d7 --- /dev/null +++ b/account_payment_batch_process_discount/models/account_payment_term_line.py @@ -0,0 +1,31 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from dateutil.relativedelta import relativedelta + +from odoo import fields, models + + +class AccountPaymentTermLine(models.Model): + _inherit = "account.payment.term.line" + + def write(self, vals): + res = super().write(vals) + if vals.get("discount_days"): + for item in self: + # get all invoice related to this payment term and update + # validity discount date + invoice_ids = self.env["account.move"].search( + [ + ("state", "=", "posted"), + ("invoice_payment_term_id", "=", item.payment_id.id), + ] + ) + for inv in invoice_ids: + # Check payment date discount validation + invoice_date = fields.Date.from_string(inv.invoice_date) + # Update discount validity days + for line in inv.invoice_payment_term_id.line_ids: + inv.discount_date = invoice_date + relativedelta( + days=line.discount_days + ) + return res diff --git a/account_payment_batch_process_discount/readme/CONFIGURE.rst b/account_payment_batch_process_discount/readme/CONFIGURE.rst new file mode 100644 index 000000000000..a6a95491868e --- /dev/null +++ b/account_payment_batch_process_discount/readme/CONFIGURE.rst @@ -0,0 +1,5 @@ +* Go to *Accounting > Invoicing > Payment Terms* +* Select or create a payment term +* Check the box "Early discount payment" +* Exclude the shipping and/or the tax amount +* Create a line with a discount for early payment, like 2% if paid within 15 days diff --git a/account_payment_batch_process_discount/readme/CONTRIBUTORS.rst b/account_payment_batch_process_discount/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..125f394a6c1b --- /dev/null +++ b/account_payment_batch_process_discount/readme/CONTRIBUTORS.rst @@ -0,0 +1,8 @@ +* Open Source Integrators + + * Mayank Gosai + * Balaji Kannan + * Maxime Chambreuil + +* Camptocamp + * Denis Leemann diff --git a/account_payment_batch_process_discount/readme/DESCRIPTION.rst b/account_payment_batch_process_discount/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..a0384dd82feb --- /dev/null +++ b/account_payment_batch_process_discount/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows you to define discounts for early payment and apply them on batch +payments. diff --git a/account_payment_batch_process_discount/readme/USAGE.rst b/account_payment_batch_process_discount/readme/USAGE.rst new file mode 100644 index 000000000000..f4c10ef2da8f --- /dev/null +++ b/account_payment_batch_process_discount/readme/USAGE.rst @@ -0,0 +1,6 @@ +* Go to *Accounting > Customers > Invoices* or *Accounting > Vendors > Bills* +* Select various open invoices or bills +* Go to the Action menu +* Select Batch Payments +* Adjust the information +* Click on Make Payments diff --git a/account_payment_batch_process_discount/static/description/icon.png b/account_payment_batch_process_discount/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/account_payment_batch_process_discount/static/description/icon.png differ diff --git a/account_payment_batch_process_discount/static/description/index.html b/account_payment_batch_process_discount/static/description/index.html new file mode 100644 index 000000000000..f2997911ce5a --- /dev/null +++ b/account_payment_batch_process_discount/static/description/index.html @@ -0,0 +1,453 @@ + + + + + +Discount on batch payments + + + +
+

Discount on batch payments

+ + +

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

+

This module allows you to define discounts for early payment and apply them on batch +payments.

+

Table of contents

+ +
+

Configuration

+
    +
  • Go to Accounting > Invoicing > Payment Terms
  • +
  • Select or create a payment term
  • +
  • Check the box “Early discount payment”
  • +
  • Exclude the shipping and/or the tax amount
  • +
  • Create a line with a discount for early payment, like 2% if paid within 15 days
  • +
+
+
+

Usage

+
    +
  • Go to Accounting > Customers > Invoices or Accounting > Vendors > Bills
  • +
  • Select various open invoices or bills
  • +
  • Go to the Action menu
  • +
  • Select Batch Payments
  • +
  • Adjust the information
  • +
  • Click on Make Payments
  • +
+
+
+

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

+
    +
  • Open Source Integrators
  • +
+
+ +
+

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:

+

mgosai

+

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_batch_process_discount/tests/__init__.py b/account_payment_batch_process_discount/tests/__init__.py new file mode 100644 index 000000000000..cd4d051fe285 --- /dev/null +++ b/account_payment_batch_process_discount/tests/__init__.py @@ -0,0 +1 @@ +from . import test_account_payment_batch_process_discount diff --git a/account_payment_batch_process_discount/tests/test_account_payment_batch_process_discount.py b/account_payment_batch_process_discount/tests/test_account_payment_batch_process_discount.py new file mode 100644 index 000000000000..36c29567f8a9 --- /dev/null +++ b/account_payment_batch_process_discount/tests/test_account_payment_batch_process_discount.py @@ -0,0 +1,240 @@ +# Copyright 2024 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from datetime import datetime, timedelta + +from odoo import Command +from odoo.tests.common import Form, TransactionCase + + +class TestAccountPaymentBatchProcessDiscount(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env.ref("base.res_partner_2") + cls.vendor = cls.env.ref("base.res_partner_3") + cls.sale_journal = cls.env["account.journal"].search( + [("type", "=", "sale")], limit=1 + ) + cls.purchase_journal = cls.env["account.journal"].search( + [("type", "=", "purchase")], limit=1 + ) + cls.account_revenue = cls.env["account.account"].search( + [ + ("account_type", "=", "income"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + cls.account_expense = cls.env["account.account"].search( + [ + ("account_type", "=", "expense"), + ("company_id", "=", cls.env.company.id), + ], + limit=1, + ) + + cls.payment_term = cls.env["account.payment.term"].create( + { + "name": "15 Days", + "is_discount": True, + "line_ids": [ + Command.create( + { + "value": "balance", + "days": 15, + "discount_percentage": 10, + "discount_days": 10, + "discount_expense_account_id": cls.account_expense.id, + "discount_income_account_id": cls.account_revenue.id, + }, + ) + ], + } + ) + + cls.cust_invoice_1 = cls.env["account.move"].create( + { + "name": "Test Customer Invoice 1", + "move_type": "out_invoice", + "journal_id": cls.sale_journal.id, + "partner_id": cls.partner.id, + "invoice_payment_term_id": cls.payment_term.id, + "invoice_line_ids": [ + Command.create( + { + "product_id": cls.env.ref("product.product_product_3").id, + "quantity": 1.0, + "price_unit": 100, + "account_id": cls.account_revenue.id, + "tax_ids": False, + }, + ) + ], + } + ) + + cls.cust_invoice_2 = cls.env["account.move"].create( + { + "name": "Test Customer Invoice 2", + "move_type": "out_invoice", + "journal_id": cls.sale_journal.id, + "partner_id": cls.partner.id, + "invoice_payment_term_id": cls.payment_term.id, + "invoice_line_ids": [ + Command.create( + { + "product_id": cls.env.ref("product.product_product_2").id, + "quantity": 1.0, + "price_unit": 1000, + "account_id": cls.account_revenue.id, + "tax_ids": False, + }, + ) + ], + } + ) + + cls.vendor_bill_1 = cls.env["account.move"].create( + { + "name": "Test Vendor Invoice 1", + "move_type": "in_invoice", + "invoice_date": datetime.now(), + "journal_id": cls.purchase_journal.id, + "partner_id": cls.vendor.id, + "invoice_payment_term_id": cls.payment_term.id, + "invoice_line_ids": [ + Command.create( + { + "product_id": cls.env.ref("product.product_product_3").id, + "quantity": 1.0, + "price_unit": 500, + "account_id": cls.account_expense.id, + "tax_ids": False, + }, + ) + ], + } + ) + + cls.vendor_bill_2 = cls.env["account.move"].create( + { + "name": "Test Vendor Invoice 2", + "move_type": "in_invoice", + "invoice_date": datetime.now(), + "journal_id": cls.purchase_journal.id, + "partner_id": cls.vendor.id, + "invoice_payment_term_id": cls.payment_term.id, + "invoice_line_ids": [ + Command.create( + { + "product_id": cls.env.ref("product.product_product_2").id, + "quantity": 1.0, + "price_unit": 200, + "account_id": cls.account_expense.id, + "tax_ids": False, + }, + ) + ], + } + ) + + def test_customer_payments_discount(self): + self.cust_invoice_1.action_post() + # discount_date should be 10 days(define discount days in payment term) + # from invoice date + self.assertEqual( + self.cust_invoice_1.discount_date, + self.cust_invoice_1.invoice_date + timedelta(10), + ) + # check discount amount + self.assertEqual(self.cust_invoice_1.discount_amt, 10) + + self.cust_invoice_2.action_post() + # discount_date should be 10 days(define discount days in payment term) + # from invoice date + self.assertEqual( + self.cust_invoice_2.discount_date, + self.cust_invoice_2.invoice_date + timedelta(10), + ) + # check discount amount + self.assertEqual(self.cust_invoice_2.discount_amt, 100) + + context = { + "active_model": "account.move", + "batch": True, + "active_ids": [self.cust_invoice_1.id, self.cust_invoice_2.id], + } + with Form( + self.env["account.payment.register"].with_context(**context) + ) as register_wizard_form: + register_wizard = register_wizard_form.save() + + self.assertEqual( + register_wizard.total_amount, + self.cust_invoice_1.amount_total + - self.cust_invoice_1.discount_amt + + self.cust_invoice_2.amount_total + - self.cust_invoice_2.discount_amt, + ) + + for invoice_payment_line in register_wizard.invoice_payments: + self.assertEqual( + invoice_payment_line.amount, + invoice_payment_line.invoice_id.amount_total + - invoice_payment_line.invoice_id.discount_amt, + ) + register_wizard.make_payments() + + self.assertEqual(self.cust_invoice_1.payment_state, "paid") + self.assertEqual(self.cust_invoice_2.payment_state, "paid") + + def test_vendor_payments_discount(self): + self.vendor_bill_1.action_post() + # discount_date should be 10 days(define discount days in payment term) + # from bill date + self.assertEqual( + self.vendor_bill_1.discount_date, + self.vendor_bill_1.invoice_date + timedelta(10), + ) + # check discount amount + self.assertEqual(self.vendor_bill_1.discount_amt, 50) + + self.vendor_bill_2.action_post() + # discount_date should be 10 days(define discount days in payment term) + # from bill date + self.assertEqual( + self.vendor_bill_2.discount_date, + self.vendor_bill_2.invoice_date + timedelta(10), + ) + # check discount amount + self.assertEqual(self.vendor_bill_2.discount_amt, 20) + + context = { + "active_model": "account.move", + "batch": True, + "active_ids": [self.vendor_bill_1.id, self.vendor_bill_2.id], + } + with Form( + self.env["account.payment.register"].with_context(**context) + ) as register_wizard_form: + register_wizard = register_wizard_form.save() + + self.assertEqual( + register_wizard.total_amount, + self.vendor_bill_1.amount_total + - self.vendor_bill_1.discount_amt + + self.vendor_bill_2.amount_total + - self.vendor_bill_2.discount_amt, + ) + + for invoice_payment_line in register_wizard.invoice_payments: + self.assertEqual( + invoice_payment_line.amount, + invoice_payment_line.invoice_id.amount_total + - invoice_payment_line.invoice_id.discount_amt, + ) + register_wizard.make_payments() + + self.assertEqual(self.vendor_bill_1.payment_state, "paid") + self.assertEqual(self.vendor_bill_2.payment_state, "paid") diff --git a/account_payment_batch_process_discount/views/account_move.xml b/account_payment_batch_process_discount/views/account_move.xml new file mode 100644 index 000000000000..4944f627f73c --- /dev/null +++ b/account_payment_batch_process_discount/views/account_move.xml @@ -0,0 +1,31 @@ + + + + + account.move.form.discount.date + account.move + + + + + + + + + + account.move.search.discount.date + account.move + + + + + + + + + diff --git a/account_payment_batch_process_discount/wizard/__init__.py b/account_payment_batch_process_discount/wizard/__init__.py new file mode 100644 index 000000000000..b66b6cea6686 --- /dev/null +++ b/account_payment_batch_process_discount/wizard/__init__.py @@ -0,0 +1,6 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import ( + account_payment_register, + invoice_payment_line, +) diff --git a/account_payment_batch_process_discount/wizard/account_payment_register.py b/account_payment_batch_process_discount/wizard/account_payment_register.py new file mode 100644 index 000000000000..08f4c917fc0c --- /dev/null +++ b/account_payment_batch_process_discount/wizard/account_payment_register.py @@ -0,0 +1,106 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, exceptions, fields, models + +MAP_INVOICE_TYPE_PARTNER_TYPE = { + "out_invoice": "customer", + "out_refund": "customer", + "in_invoice": "supplier", + "in_refund": "supplier", +} + +# Since invoice amounts are unsigned, +# this is how we know if money comes in or goes out +MAP_INVOICE_TYPE_PAYMENT_SIGN = { + "out_invoice": 1, + "in_refund": 1, + "in_invoice": -1, + "out_refund": -1, +} + + +class AccountPaymentRegister(models.TransientModel): + _inherit = "account.payment.register" + + @api.onchange("payment_date") + def onchange_payment_date(self): + if self.payment_date: + for rec in self.invoice_payments: + rec.with_context(reset_autofill=True).onchange_amount() + + @api.onchange("invoice_payments") + def _get_amount(self): + total = 0.0 + for rec in self.invoice_payments: + total += rec.amount + if self.invoice_payments: + self.cheque_amount = total + + def get_batch_payment_amount(self, invoice=None, payment_date=None): + res = super().get_batch_payment_amount(invoice, payment_date) + discount_information = ( + invoice.invoice_payment_term_id._check_payment_term_discount( + invoice, payment_date + ) + ) + discount_amt = discount_information[0] + discount_account_id = discount_information[1] + # compute payment difference + payment_difference = self.payment_difference + if payment_difference <= discount_amt: + # Prepare val + res.update( + { + "payment_difference": discount_amt, + "amount": abs(invoice.amount_residual - discount_amt), + "payment_difference_handling": "reconcile", + "writeoff_account_id": discount_account_id, + "note": (payment_difference != 0.0) + and "Early Pay Discount" + or False, + } + ) + return res + + def get_invoice_payment_line(self, invoice): + if invoice.discount_amt == 0.0: + return super().get_invoice_payment_line(invoice) + # Set payment date as today + today = fields.Date.today() + vals = self.get_batch_payment_amount(invoice, today) + discount_information = ( + invoice.invoice_payment_term_id._check_payment_term_discount(invoice, today) + ) + discount = discount_information[0] + if discount_information[2]: + amount = discount_information[2] - discount + else: + amount = invoice.amount_residual + payment_difference = discount + if amount <= 0.0: + amount = vals.get("amt") or 0.0 + if discount <= 0.0: + payment_difference = vals.get("payment_difference") or 0.0 + return ( + 0, + 0, + { + "partner_id": invoice.partner_id.id, + "invoice_id": invoice.id, + "balance": invoice.amount_residual or 0.0, + "amount": amount, + "payment_difference_handling": vals.get( + "payment_difference_handling", False + ), + "payment_difference": payment_difference, + "writeoff_account_id": vals.get("writeoff_account_id", False), + "note": vals.get("note", False), + }, + ) + + def auto_fill_payments(self): + # Check if payment date set + if not self.payment_date: + raise exceptions.ValidationError(_("Please enter the payment date.")) + return super().auto_fill_payments() diff --git a/account_payment_batch_process_discount/wizard/invoice_payment_line.py b/account_payment_batch_process_discount/wizard/invoice_payment_line.py new file mode 100644 index 000000000000..d9c1b81cd74d --- /dev/null +++ b/account_payment_batch_process_discount/wizard/invoice_payment_line.py @@ -0,0 +1,64 @@ +# Copyright (C) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class InvoicePaymentLine(models.TransientModel): + _inherit = "invoice.payment.line" + + @api.onchange("payment_difference_handling") + def onchange_payment_diff_handling(self): + """ + Special case: When payment diff amount is 0, payment difference + handling should be in 'open' action + """ + if ( + self.payment_difference_handling + and self.payment_difference_handling == "reconcile" + and self.payment_difference == 0.0 + ): + # Change handling difference + self.payment_difference_handling = "open" + + @api.onchange("amount") + def onchange_amount(self): + rec = self + + # is discount applicable + payment_date = fields.Date.from_string(rec.wizard_id.payment_date) + discount_information = ( + rec.invoice_id.invoice_payment_term_id._check_payment_term_discount( + rec.invoice_id, payment_date + ) + ) + discount_amount = discount_information[0] + discount_account_id = discount_information[1] + if discount_information[2]: + amount = discount_information[2] - discount_amount + else: + amount = rec.invoice_id.amount_residual + # if paying_amt change is triggered by date change + if self._context.get("reset_autofill", False): + rec.amount = amount + + # compute difference + due_or_balance = rec.balance - rec.amount + + # apply discount + if round(due_or_balance, 2) <= discount_amount: + overpayment = discount_amount - due_or_balance + rec.payment_difference = discount_amount - overpayment + rec.payment_difference_handling = "reconcile" + rec.writeoff_account_id = False + rec.note = "" + + if due_or_balance: + rec.writeoff_account_id = discount_account_id + rec.note = "Early Pay Discount" + + # cannot apply discount + else: + rec.payment_difference = due_or_balance + rec.payment_difference_handling = "open" + rec.writeoff_account_id = False + rec.note = False diff --git a/setup/account_payment_batch_process_discount/odoo/addons/account_payment_batch_process_discount b/setup/account_payment_batch_process_discount/odoo/addons/account_payment_batch_process_discount new file mode 120000 index 000000000000..fc4e97200f08 --- /dev/null +++ b/setup/account_payment_batch_process_discount/odoo/addons/account_payment_batch_process_discount @@ -0,0 +1 @@ +../../../../account_payment_batch_process_discount \ No newline at end of file diff --git a/setup/account_payment_batch_process_discount/setup.py b/setup/account_payment_batch_process_discount/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/account_payment_batch_process_discount/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)