From f48da4f036f0fc864f79e3cca986c62371d0e894 Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Fri, 9 Mar 2018 08:32:24 +0100 Subject: [PATCH 01/22] [ADD] Module which create a writeoff when paying an invoice (with a discount) from a payment order --- account_cash_discount_write_off/README.rst | 83 +++++++++ account_cash_discount_write_off/__init__.py | 1 + .../__manifest__.py | 21 +++ account_cash_discount_write_off/i18n/fr.po | 64 +++++++ .../models/__init__.py | 3 + .../models/account_payment_line.py | 89 ++++++++++ .../models/account_payment_order.py | 44 +++++ .../models/res_company.py | 19 +++ .../static/description/icon.png | Bin 0 -> 9455 bytes .../tests/__init__.py | 1 + .../test_account_cash_discount_write_off.py | 160 ++++++++++++++++++ .../views/res_company.xml | 21 +++ 12 files changed, 506 insertions(+) create mode 100644 account_cash_discount_write_off/README.rst create mode 100644 account_cash_discount_write_off/__init__.py create mode 100644 account_cash_discount_write_off/__manifest__.py create mode 100644 account_cash_discount_write_off/i18n/fr.po create mode 100644 account_cash_discount_write_off/models/__init__.py create mode 100644 account_cash_discount_write_off/models/account_payment_line.py create mode 100644 account_cash_discount_write_off/models/account_payment_order.py create mode 100644 account_cash_discount_write_off/models/res_company.py create mode 100644 account_cash_discount_write_off/static/description/icon.png create mode 100644 account_cash_discount_write_off/tests/__init__.py create mode 100644 account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py create mode 100644 account_cash_discount_write_off/views/res_company.xml diff --git a/account_cash_discount_write_off/README.rst b/account_cash_discount_write_off/README.rst new file mode 100644 index 000000000000..0a1e09a007dc --- /dev/null +++ b/account_cash_discount_write_off/README.rst @@ -0,0 +1,83 @@ +.. 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 + +=============================== +Account Cash Discount Write Off +=============================== + +Create an automatic write-off for payment with discount on the payment order +confirmation. If the cash discount amount is computed based on the total +amount, the created write-off will also contains tax adjustments. This +adjustments are computed based on the discount percent configured on the +related invoice. + +Configuration +============= + +To configure this module, you need to: + +#. Go to your companies +#. Set the cash discount write off account +#. Set the cash discount write off journal + +Usage +===== + +To use this module, you need to: + +#. Create a supplier invoice +#. In the "Other Info" tab, you can configure a discount in percent and a discount delay in days +#. Validate the invoice +#. Create a payment order and add the previously created invoice using the search based on the cash discount due date +#. Validate your payment order till the last state +#. The invoice is now marked as "Paid". + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/96/10.0 + +.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt +.. branch is "8.0" for example + +Known issues / Roadmap +====================== + +* The cash discount should only be used when doing a full payment at once. + +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 smash it by providing detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Benjamin Willig +* Christelle De Coninck (ACSONE) + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_cash_discount_write_off/__init__.py b/account_cash_discount_write_off/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/account_cash_discount_write_off/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py new file mode 100644 index 000000000000..248c82e05b01 --- /dev/null +++ b/account_cash_discount_write_off/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Account Cash Discount Write Off', + 'summary': """ + Create an automatic writeoff for payment with discount on the payment + order confirmation""", + 'version': '10.0.1.0.0', + 'license': 'AGPL-3', + 'author': 'ACSONE SA/NV, Odoo Community Association (OCA)', + 'website': 'https://github.com/acsone/account-payment', + 'depends': [ + 'account_cash_discount_payment', + ], + 'data': [ + 'views/res_company.xml', + ], + 'demo': [ + ], +} diff --git a/account_cash_discount_write_off/i18n/fr.po b/account_cash_discount_write_off/i18n/fr.po new file mode 100644 index 000000000000..88e37fd7284b --- /dev/null +++ b/account_cash_discount_write_off/i18n/fr.po @@ -0,0 +1,64 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_cash_discount_write_off +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-03-09 07:20+0000\n" +"PO-Revision-Date: 2018-03-09 07:20+0000\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_cash_discount_write_off +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:47 +#, python-format +msgid "Cash Discount Write-Off" +msgstr "Escompte (écart)" + +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company_default_cash_discount_writeoff_account_id +msgid "Cash Discount Write-Off Account" +msgstr "Compte d'écart de l'escompte" + +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company_default_cash_discount_writeoff_journal_id +msgid "Cash Discount Write-Off Journal" +msgstr "Journal d'écart de l'escompte" + +#. module: account_cash_discount_write_off +#: model:ir.model,name:account_cash_discount_write_off.model_res_company +msgid "Companies" +msgstr "Sociétés" + +#. module: account_cash_discount_write_off +#: model:ir.model,name:account_cash_discount_write_off.model_account_payment_line +msgid "Payment Lines" +msgstr "Lignes de paiement" + +#. module: account_cash_discount_write_off +#: model:ir.model,name:account_cash_discount_write_off.model_account_payment_order +msgid "Payment Order" +msgstr "Ordre de paiement" + +#. module: account_cash_discount_write_off +#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +msgid "Write-Off Account" +msgstr "Compte d'écart" + +#. module: account_cash_discount_write_off +#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +msgid "Write-Off Journal" +msgstr "Journal d'écart" + +#. module: account_cash_discount_write_off +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:43 +#, python-format +msgid "You have to fill in journal and account for cash discount write-off on the company." +msgstr "Vous devez remplir un journal et un compte d'écart pour les escomptes sur la société." + diff --git a/account_cash_discount_write_off/models/__init__.py b/account_cash_discount_write_off/models/__init__.py new file mode 100644 index 000000000000..f07ea21575c1 --- /dev/null +++ b/account_cash_discount_write_off/models/__init__.py @@ -0,0 +1,3 @@ +from . import account_payment_line +from . import account_payment_order +from . import res_company diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py new file mode 100644 index 000000000000..a41e89350e70 --- /dev/null +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models, _ +from odoo.exceptions import UserError + + +class PaymentLine(models.Model): + + _inherit = 'account.payment.line' + + @api.multi + def check_cash_discount_write_off_creation(self): + self.ensure_one() + move_line = self.move_line_id + has_partial_reconciliation = ( + bool(move_line.matched_debit_ids) or + bool(move_line.matched_credit_ids)) + return ( + self.pay_with_discount and + has_partial_reconciliation and + move_line.invoice_id + ) + + @api.multi + def get_cash_discount_writeoff_move_values(self): + self.ensure_one() + move_line = self.move_line_id + partner = move_line.partner_id + partner = partner._find_accounting_partner(partner) + invoice = move_line.invoice_id + company = invoice.company_id + tax_adjustment = company.cash_discount_base_amount_type == 'total' + + woff_account = False + woff_journal = False + + if invoice: + company = invoice.company_id + woff_account = company.default_cash_discount_writeoff_account_id + woff_journal = company.default_cash_discount_writeoff_journal_id + + if not woff_account or not woff_journal: + raise UserError( + _("You have to fill in journal and account for cash discount " + "write-off on the company.") + ) + + move_line_name = _("Cash Discount Write-Off") + supplier_account_amount = invoice.discount_amount + discount_amount_credit = supplier_account_amount + + lines_values = list() + lines_values.append({ + 'partner_id': partner.id, + 'name': move_line_name, + 'debit': supplier_account_amount, + 'account_id': move_line.account_id.id, + }) + + if tax_adjustment: + for tax_line in invoice.tax_line_ids: + amount = tax_line.amount * invoice.discount_percent / 100.0 + discount_amount_credit -= amount + lines_values.append({ + 'partner_id': partner.id, + 'name': move_line_name, + 'credit': amount, + 'account_id': tax_line.account_id.id, + 'tax_line_id': tax_line.tax_id.id, + }) + + lines_values.append({ + 'partner_id': partner.id, + 'name': move_line_name, + 'credit': discount_amount_credit, + 'account_id': woff_account.id, + }) + + move_values = { + 'journal_id': woff_journal.id, + 'partner_id': partner.id, + 'line_ids': [ + (0, 0, values) + for values in lines_values + ] + } + return move_values diff --git a/account_cash_discount_write_off/models/account_payment_order.py b/account_cash_discount_write_off/models/account_payment_order.py new file mode 100644 index 000000000000..d4b6c7473b23 --- /dev/null +++ b/account_cash_discount_write_off/models/account_payment_order.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class AccountPaymentOrder(models.Model): + + _inherit = 'account.payment.order' + + @api.multi + def generated2uploaded(self): + res = super(AccountPaymentOrder, self).generated2uploaded() + for order in self: + order.create_cash_discount_write_off() + return res + + @api.multi + def create_cash_discount_write_off(self): + self.ensure_one() + for payment_line in self.payment_line_ids: + if payment_line.check_cash_discount_write_off_creation(): + self.create_payment_line_discount_write_off(payment_line) + + @api.multi + def create_payment_line_discount_write_off(self, payment_line): + self.ensure_one() + move = self.create_payment_line_discount_write_off_move(payment_line) + move_lines = payment_line.move_line_id | move.line_ids + lines_to_reconcile = move_lines.filtered( + lambda line: + not line.reconciled and + line.account_id == payment_line.move_line_id.account_id + ) + lines_to_reconcile.reconcile() + + @api.multi + def create_payment_line_discount_write_off_move(self, payment_line): + self.ensure_one() + move_values = payment_line.get_cash_discount_writeoff_move_values() + move = self.env['account.move'].create(move_values) + move.post() + return move diff --git a/account_cash_discount_write_off/models/res_company.py b/account_cash_discount_write_off/models/res_company.py new file mode 100644 index 000000000000..80327532e640 --- /dev/null +++ b/account_cash_discount_write_off/models/res_company.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + + _inherit = 'res.company' + + default_cash_discount_writeoff_account_id = fields.Many2one( + comodel_name='account.account', + string="Cash Discount Write-Off Account" + ) + default_cash_discount_writeoff_journal_id = fields.Many2one( + comodel_name='account.journal', + string="Cash Discount Write-Off Journal" + ) diff --git a/account_cash_discount_write_off/static/description/icon.png b/account_cash_discount_write_off/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_cash_discount_write_off/tests/__init__.py b/account_cash_discount_write_off/tests/__init__.py new file mode 100644 index 000000000000..1946b7036593 --- /dev/null +++ b/account_cash_discount_write_off/tests/__init__.py @@ -0,0 +1 @@ +from . import test_account_cash_discount_write_off diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py new file mode 100644 index 000000000000..b1f4e4c3f1de --- /dev/null +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.addons.account_cash_discount_payment.tests.common import \ + TestAccountCashDiscountPaymentCommon +from odoo.exceptions import UserError +from odoo.fields import Date + + +class TestAccountCashDiscountWriteOff(TestAccountCashDiscountPaymentCommon): + + @classmethod + def setUpClass(cls): + super(TestAccountCashDiscountWriteOff, cls).setUpClass() + cls.cash_discount_writeoff_account = cls.Account.create({ + 'name': "Cash Discount Write-Off", + 'code': "CD-W", + 'user_type_id': cls.inc_account_type.id, + }) + + cls.cash_discount_writeoff_journal = cls.Journal.create({ + 'name': "Cash Discount Write-Off", + 'code': "CD-W", + 'type': 'general', + }) + + def test_cash_discount_with_write_off(self): + payment_mode = self.payment_mode_out + discount_due_date = Date.today() + + invoice = self.create_supplier_invoice( + discount_due_date, payment_mode, 1000, 10, []) + invoice.action_invoice_open() + + move = invoice.move_id + move.post() + + payment_order = self.PaymentOrder.create({ + 'payment_mode_id': self.payment_mode_out.id, + 'payment_type': 'outbound', + 'journal_id': self.bank_ing_journal.id, + }) + + payment_line_wizard = self.PaymentLineCreate.with_context( + active_model=payment_order._name, + active_id=payment_order.id, + ).create({ + 'cash_discount_date_start': discount_due_date, + 'cash_discount_date_end': discount_due_date, + 'date_type': 'discount_due_date', + 'journal_ids': [(6, 0, [self.purchase_journal.id])], + }) + + payment_line_wizard.populate() + payment_line_wizard.create_payment_lines() + + payment_order.draft2open() + + payment_line = payment_order.payment_line_ids[0] + self.assertTrue(payment_line.pay_with_discount) + + payment_order.open2generated() + + with self.assertRaises(UserError), self.env.cr.savepoint(): + payment_order.generated2uploaded() + + self.company.write({ + 'default_cash_discount_writeoff_account_id': + self.cash_discount_writeoff_account.id, + 'default_cash_discount_writeoff_journal_id': + self.cash_discount_writeoff_journal.id, + }) + + payment_order.generated2uploaded() + + payment_move_lines = invoice.payment_move_line_ids + write_off_line = self.MoveLine.search([ + ('id', 'in', payment_move_lines.ids), + ('name', '=', "Cash Discount Write-Off"), + ]) + + self.assertEqual(len(write_off_line), 1) + self.assertEqual(write_off_line.debit, 100) + + write_off_base_line = self.MoveLine.search([ + ('id', '!=', write_off_line.id), + ('move_id', '=', write_off_line.move_id.id), + ]) + self.assertEqual(len(write_off_base_line), 1) + self.assertEqual( + write_off_base_line.account_id, + self.cash_discount_writeoff_account) + self.assertEqual(invoice.state, 'paid') + + def test_cash_discount_with_write_off_with_taxes(self): + self.company.write({ + 'default_cash_discount_writeoff_account_id': + self.cash_discount_writeoff_account.id, + 'default_cash_discount_writeoff_journal_id': + self.cash_discount_writeoff_journal.id, + 'cash_discount_base_amount_type': 'total', + }) + self.assertEqual(self.company.cash_discount_base_amount_type, 'total') + + payment_mode = self.payment_mode_out + discount_due_date = Date.today() + + invoice = self.create_supplier_invoice( + discount_due_date, payment_mode, 1000, 10, + [self.tax_10_p.id, self.tax_15_p.id]) + invoice.action_invoice_open() + + move = invoice.move_id + move.post() + + payment_order = self.PaymentOrder.create({ + 'payment_mode_id': self.payment_mode_out.id, + 'payment_type': 'outbound', + 'journal_id': self.bank_ing_journal.id, + }) + + payment_line_wizard = self.PaymentLineCreate.with_context( + active_model=payment_order._name, + active_id=payment_order.id, + ).create({ + 'cash_discount_date_start': discount_due_date, + 'cash_discount_date_end': discount_due_date, + 'date_type': 'discount_due_date', + 'journal_ids': [(6, 0, [self.purchase_journal.id])], + }) + + payment_line_wizard.populate() + payment_line_wizard.create_payment_lines() + + payment_order.draft2open() + payment_order.open2generated() + payment_order.generated2uploaded() + + self.assertEqual(invoice.state, 'paid') + + discount_writeoff_move_lines = self.MoveLine.search([ + ('journal_id', + '=', self.cash_discount_writeoff_journal.id) + ]) + self.assertEqual(len(discount_writeoff_move_lines), 4) + + tax_10_move_line = self.MoveLine.search([ + ('id', 'in', discount_writeoff_move_lines.ids), + ('tax_line_id', '=', self.tax_10_p.id), + ]) + self.assertEqual(len(tax_10_move_line), 1) + self.assertEqual(tax_10_move_line.credit, 10) + + tax_15_move_line = self.MoveLine.search([ + ('id', 'in', discount_writeoff_move_lines.ids), + ('tax_line_id', '=', self.tax_15_p.id), + ]) + self.assertEqual(len(tax_15_move_line), 1) + self.assertEqual(tax_15_move_line.credit, 15) diff --git a/account_cash_discount_write_off/views/res_company.xml b/account_cash_discount_write_off/views/res_company.xml new file mode 100644 index 000000000000..2491b6b95cd7 --- /dev/null +++ b/account_cash_discount_write_off/views/res_company.xml @@ -0,0 +1,21 @@ + + + + + + + res.company.form (in account_cash_discount_write_off) + res.company + + + + + + + + + + + + From a7e7fa2a74dfc39315ebca8205876f27e6172319 Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Thu, 29 Mar 2018 09:38:13 +0200 Subject: [PATCH 02/22] [FIX] Update file's headers (copyright, encoding) --- account_cash_discount_write_off/__manifest__.py | 1 + account_cash_discount_write_off/models/account_payment_line.py | 2 +- .../tests/test_account_cash_discount_write_off.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py index 248c82e05b01..9210558f9f82 100644 --- a/account_cash_discount_write_off/__manifest__.py +++ b/account_cash_discount_write_off/__manifest__.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index a41e89350e70..ce9cbc1c4820 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2014 ACSONE SA/NV +# Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, models, _ diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index b1f4e4c3f1de..d2fbe80a78cd 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2014 ACSONE SA/NV +# Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo.addons.account_cash_discount_payment.tests.common import \ From c5f07b847b17d3612b2d0d0547d4cc44f4ee4086 Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Thu, 29 Mar 2018 10:08:17 +0200 Subject: [PATCH 03/22] [CHG] Don't allow to pay with discount if the payment line is not linked to an invoice which has a discount [CHG] Use a computed flag to know if there is tax adjustments or not [CHG] When the pay_with_discount flag is changed, the amount to paid is computed based on the invoice total and the invoice total with the discount amount deducted [FIX] Invoice report should display the amount_total_with_discount instead of the discount_amount [CHG] Use a single date as a search filter for the discount due date [FIX] The generated discount write off move should be posted depending on the payment mode configuration [CHG] only the pay_with_discount flag should decide if the write off should be created or not [CHG] The accounting partner is already the one defined on the move line --- .../models/account_payment_line.py | 15 +++------------ .../models/account_payment_order.py | 17 +++++++++-------- .../test_account_cash_discount_write_off.py | 12 ++++++------ 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index ce9cbc1c4820..b04282f19025 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -11,27 +11,18 @@ class PaymentLine(models.Model): _inherit = 'account.payment.line' @api.multi - def check_cash_discount_write_off_creation(self): + def _check_cash_discount_write_off_creation(self): self.ensure_one() - move_line = self.move_line_id - has_partial_reconciliation = ( - bool(move_line.matched_debit_ids) or - bool(move_line.matched_credit_ids)) - return ( - self.pay_with_discount and - has_partial_reconciliation and - move_line.invoice_id - ) + return self.pay_with_discount @api.multi def get_cash_discount_writeoff_move_values(self): self.ensure_one() move_line = self.move_line_id partner = move_line.partner_id - partner = partner._find_accounting_partner(partner) invoice = move_line.invoice_id company = invoice.company_id - tax_adjustment = company.cash_discount_base_amount_type == 'total' + tax_adjustment = company.cash_discount_use_tax_adjustment woff_account = False woff_journal = False diff --git a/account_cash_discount_write_off/models/account_payment_order.py b/account_cash_discount_write_off/models/account_payment_order.py index d4b6c7473b23..28fafaee123b 100644 --- a/account_cash_discount_write_off/models/account_payment_order.py +++ b/account_cash_discount_write_off/models/account_payment_order.py @@ -13,20 +13,20 @@ class AccountPaymentOrder(models.Model): def generated2uploaded(self): res = super(AccountPaymentOrder, self).generated2uploaded() for order in self: - order.create_cash_discount_write_off() + order._create_cash_discount_write_off() return res @api.multi - def create_cash_discount_write_off(self): + def _create_cash_discount_write_off(self): self.ensure_one() for payment_line in self.payment_line_ids: - if payment_line.check_cash_discount_write_off_creation(): - self.create_payment_line_discount_write_off(payment_line) + if payment_line._check_cash_discount_write_off_creation(): + self._create_payment_line_discount_write_off(payment_line) @api.multi - def create_payment_line_discount_write_off(self, payment_line): + def _create_payment_line_discount_write_off(self, payment_line): self.ensure_one() - move = self.create_payment_line_discount_write_off_move(payment_line) + move = self._create_payment_line_discount_write_off_move(payment_line) move_lines = payment_line.move_line_id | move.line_ids lines_to_reconcile = move_lines.filtered( lambda line: @@ -36,9 +36,10 @@ def create_payment_line_discount_write_off(self, payment_line): lines_to_reconcile.reconcile() @api.multi - def create_payment_line_discount_write_off_move(self, payment_line): + def _create_payment_line_discount_write_off_move(self, payment_line): self.ensure_one() move_values = payment_line.get_cash_discount_writeoff_move_values() move = self.env['account.move'].create(move_values) - move.post() + if self.payment_mode_id.post_move: + move.post() return move diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index d2fbe80a78cd..eaab349bf727 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -27,6 +27,7 @@ def setUpClass(cls): def test_cash_discount_with_write_off(self): payment_mode = self.payment_mode_out + payment_mode.post_move = True discount_due_date = Date.today() invoice = self.create_supplier_invoice( @@ -37,7 +38,7 @@ def test_cash_discount_with_write_off(self): move.post() payment_order = self.PaymentOrder.create({ - 'payment_mode_id': self.payment_mode_out.id, + 'payment_mode_id': payment_mode.id, 'payment_type': 'outbound', 'journal_id': self.bank_ing_journal.id, }) @@ -46,8 +47,7 @@ def test_cash_discount_with_write_off(self): active_model=payment_order._name, active_id=payment_order.id, ).create({ - 'cash_discount_date_start': discount_due_date, - 'cash_discount_date_end': discount_due_date, + 'cash_discount_date': discount_due_date, 'date_type': 'discount_due_date', 'journal_ids': [(6, 0, [self.purchase_journal.id])], }) @@ -104,6 +104,7 @@ def test_cash_discount_with_write_off_with_taxes(self): self.assertEqual(self.company.cash_discount_base_amount_type, 'total') payment_mode = self.payment_mode_out + payment_mode.post_move = True discount_due_date = Date.today() invoice = self.create_supplier_invoice( @@ -115,7 +116,7 @@ def test_cash_discount_with_write_off_with_taxes(self): move.post() payment_order = self.PaymentOrder.create({ - 'payment_mode_id': self.payment_mode_out.id, + 'payment_mode_id': payment_mode.id, 'payment_type': 'outbound', 'journal_id': self.bank_ing_journal.id, }) @@ -124,8 +125,7 @@ def test_cash_discount_with_write_off_with_taxes(self): active_model=payment_order._name, active_id=payment_order.id, ).create({ - 'cash_discount_date_start': discount_due_date, - 'cash_discount_date_end': discount_due_date, + 'cash_discount_date': discount_due_date, 'date_type': 'discount_due_date', 'journal_ids': [(6, 0, [self.purchase_journal.id])], }) From 7d6bced6914a63ce43383f1f70cfac6eb4d08ca2 Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Thu, 29 Mar 2018 10:21:40 +0200 Subject: [PATCH 04/22] [CHG] Create the tax adjustment based on move lines instead of invoice tax lines [CHG] changed the way to populate tax's move lines debit/credit fields [FIX] the discount due date should be recomputed when the invoice data changes [FIX] the amount of the payment line should not include the discount if the current date is posterior to the discount due date [IMP] Display a button on the payment line tree view to toggle the pay with discount flag [ADD] Show the discount amount/due date in the payment line generation wizard [FIX] Keep the base line with taxes [FIX] do not allow to change the pay_with_discount field value if the payment order is done [CHG] display a filled/emtpy checkbox depending if the discount has been enabled or not [FIX] use the writeoff account for a non tax line [ADD] display the discount due date/amount in the move line search more [FIX] the domain should be recomputed when the discount due date changes [FIX] new onchange method to disable the discount if the amount of a payment line has been changed manually. The writeoff shouldn't be created if the amount of the line doesn't correspond to the invoice total with discount [FIX] the pay with discount field should not be visible if the invoice has already been paid partially [FIX] discount data should only be visible in a supplier invoice --- .../models/account_payment_line.py | 54 ++++++++++++++----- .../test_account_cash_discount_write_off.py | 6 +++ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index b04282f19025..8a3573c5533d 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -4,6 +4,7 @@ from odoo import api, models, _ from odoo.exceptions import UserError +from odoo.tools import float_compare class PaymentLine(models.Model): @@ -13,7 +14,16 @@ class PaymentLine(models.Model): @api.multi def _check_cash_discount_write_off_creation(self): self.ensure_one() - return self.pay_with_discount + return ( + self.pay_with_discount and + self.move_line_id and + self.move_line_id.invoice_id and + self.move_line_id.invoice_id.has_discount and + float_compare( + self.amount_currency, + self.move_line_id.invoice_id.amount_total_with_discount, + precision_rounding=self.currency_id.rounding) == 0 + ) @api.multi def get_cash_discount_writeoff_move_values(self): @@ -42,7 +52,8 @@ def get_cash_discount_writeoff_move_values(self): supplier_account_amount = invoice.discount_amount discount_amount_credit = supplier_account_amount - lines_values = list() + lines_values = [] + lines_values.append({ 'partner_id': partner.id, 'name': move_line_name, @@ -51,23 +62,40 @@ def get_cash_discount_writeoff_move_values(self): }) if tax_adjustment: - for tax_line in invoice.tax_line_ids: - amount = tax_line.amount * invoice.discount_percent / 100.0 + tax_move_lines = self.env['account.move.line'].search([ + ('move_id', '=', move_line.move_id.id), + '|', + ('tax_line_id', '!=', False), + ('tax_ids', '!=', False) + ]) + + for tax_move_line in tax_move_lines: + amount = ( + abs(tax_move_line.balance) * + invoice.discount_percent / 100.0 + ) discount_amount_credit -= amount + if tax_move_line.tax_line_id: + account = tax_move_line.account_id + else: + account = woff_account lines_values.append({ 'partner_id': partner.id, 'name': move_line_name, - 'credit': amount, - 'account_id': tax_line.account_id.id, - 'tax_line_id': tax_line.tax_id.id, + 'debit': tax_move_line.credit > 0 and amount or 0.0, + 'credit': tax_move_line.debit > 0 and amount or 0.0, + 'account_id': account.id, + 'tax_line_id': tax_move_line.tax_line_id.id, + 'tax_ids': [(6, 0, tax_move_line.tax_ids.ids)] }) - lines_values.append({ - 'partner_id': partner.id, - 'name': move_line_name, - 'credit': discount_amount_credit, - 'account_id': woff_account.id, - }) + if discount_amount_credit > 0: + lines_values.append({ + 'partner_id': partner.id, + 'name': move_line_name, + 'credit': discount_amount_credit, + 'account_id': woff_account.id, + }) move_values = { 'journal_id': woff_journal.id, diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index eaab349bf727..c2397c9802f8 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -59,6 +59,12 @@ def test_cash_discount_with_write_off(self): payment_line = payment_order.payment_line_ids[0] self.assertTrue(payment_line.pay_with_discount) + self.assertTrue(payment_line._check_cash_discount_write_off_creation()) + old_amount = payment_line.amount_currency + payment_line.amount_currency = 10 + self.assertFalse( + payment_line._check_cash_discount_write_off_creation()) + payment_line.amount_currency = old_amount payment_order.open2generated() From 7923354b36cde9e01f64b1cc914caeb1a0c8b1fd Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Wed, 22 Aug 2018 16:37:26 +0200 Subject: [PATCH 05/22] [FIX] Round the tax amount to avoid unbalanced entries [FIX] flake8/pylint --- .../models/account_payment_line.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index 8a3573c5533d..d166df9d5d34 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -4,7 +4,7 @@ from odoo import api, models, _ from odoo.exceptions import UserError -from odoo.tools import float_compare +from odoo.tools import float_compare, float_round class PaymentLine(models.Model): @@ -33,6 +33,7 @@ def get_cash_discount_writeoff_move_values(self): invoice = move_line.invoice_id company = invoice.company_id tax_adjustment = company.cash_discount_use_tax_adjustment + rounding = self.currency_id.rounding woff_account = False woff_journal = False @@ -52,14 +53,12 @@ def get_cash_discount_writeoff_move_values(self): supplier_account_amount = invoice.discount_amount discount_amount_credit = supplier_account_amount - lines_values = [] - - lines_values.append({ + lines_values = [{ 'partner_id': partner.id, 'name': move_line_name, 'debit': supplier_account_amount, 'account_id': move_line.account_id.id, - }) + }] if tax_adjustment: tax_move_lines = self.env['account.move.line'].search([ @@ -70,9 +69,10 @@ def get_cash_discount_writeoff_move_values(self): ]) for tax_move_line in tax_move_lines: - amount = ( + amount = float_round( abs(tax_move_line.balance) * - invoice.discount_percent / 100.0 + invoice.discount_percent / 100.0, + precision_rounding=rounding, ) discount_amount_credit -= amount if tax_move_line.tax_line_id: From 0efe7ab9e6f2b48c444dab037f52dcc5570830b1 Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Fri, 19 Oct 2018 13:46:37 +0200 Subject: [PATCH 06/22] [10.0][IMP] account_cash_discount_base: Add precision to discounts [FIX] Fixed error with rounding when creating a writeoff --- .../models/account_payment_line.py | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index d166df9d5d34..8a46126ea361 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -4,7 +4,7 @@ from odoo import api, models, _ from odoo.exceptions import UserError -from odoo.tools import float_compare, float_round +from odoo.tools import float_compare, float_round, float_is_zero class PaymentLine(models.Model): @@ -75,6 +75,7 @@ def get_cash_discount_writeoff_move_values(self): precision_rounding=rounding, ) discount_amount_credit -= amount + if tax_move_line.tax_line_id: account = tax_move_line.account_id else: @@ -89,11 +90,28 @@ def get_cash_discount_writeoff_move_values(self): 'tax_ids': [(6, 0, tax_move_line.tax_ids.ids)] }) - if discount_amount_credit > 0: + amount_left = not float_is_zero( + discount_amount_credit, + precision_rounding=rounding + ) + if amount_left: + writeoff_amount = float_round( + abs(discount_amount_credit), + precision_rounding=rounding, + ) lines_values.append({ 'partner_id': partner.id, 'name': move_line_name, - 'credit': discount_amount_credit, + 'credit': ( + writeoff_amount + if discount_amount_credit > 0 + else 0.0 + ), + 'debit': ( + writeoff_amount + if discount_amount_credit < 0 + else 0.0 + ), 'account_id': woff_account.id, }) From 6e165068b963597558836a54fff497564ddd340c Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Wed, 28 Nov 2018 13:56:16 +0100 Subject: [PATCH 07/22] [ADD] handle supplier refund when paying a supplier invoice which contains a discount [ADD] use the supplier payment term when creating a refund --- .../models/account_payment_line.py | 51 ++++++++++--- .../test_account_cash_discount_write_off.py | 75 +++++++++++++++++++ 2 files changed, 116 insertions(+), 10 deletions(-) diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index 8a46126ea361..0f8f1b207fd8 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -14,16 +14,35 @@ class PaymentLine(models.Model): @api.multi def _check_cash_discount_write_off_creation(self): self.ensure_one() - return ( + create_write_off = ( self.pay_with_discount and self.move_line_id and self.move_line_id.invoice_id and - self.move_line_id.invoice_id.has_discount and - float_compare( - self.amount_currency, - self.move_line_id.invoice_id.amount_total_with_discount, - precision_rounding=self.currency_id.rounding) == 0 + self.move_line_id.invoice_id.has_discount ) + if not create_write_off: + return False + + invoice = self.move_line_id.invoice_id + refunds_amount_total = 0.0 + for pmove_line in invoice.payment_move_line_ids: + pmove_line_inv = pmove_line.invoice_id + if pmove_line_inv and pmove_line_inv.type == 'in_refund': + refunds_amount_total += pmove_line_inv.amount_total + + # Invoice residual has already changed so we need to compute + # the residual with discount before the first reconciliation + amount_to_pay = ( + invoice.amount_total - + refunds_amount_total - + invoice.discount_amount + + invoice.refunds_discount_amount + ) + return float_compare( + self.amount_currency, + amount_to_pay, + precision_rounding=self.currency_id.rounding + ) == 0 @api.multi def get_cash_discount_writeoff_move_values(self): @@ -50,7 +69,10 @@ def get_cash_discount_writeoff_move_values(self): ) move_line_name = _("Cash Discount Write-Off") - supplier_account_amount = invoice.discount_amount + supplier_account_amount = ( + invoice.discount_amount - + invoice.refunds_discount_amount + ) discount_amount_credit = supplier_account_amount lines_values = [{ @@ -61,20 +83,29 @@ def get_cash_discount_writeoff_move_values(self): }] if tax_adjustment: + refund_moves = invoice.payment_move_line_ids.filtered( + lambda line: line.invoice_id.type == 'in_refund' + ).mapped('move_id') + target_move_ids = refund_moves.ids + [move_line.move_id.id] + tax_move_lines = self.env['account.move.line'].search([ - ('move_id', '=', move_line.move_id.id), + ('move_id', 'in', target_move_ids), '|', ('tax_line_id', '!=', False), ('tax_ids', '!=', False) ]) for tax_move_line in tax_move_lines: + tax_invoice = tax_move_line.invoice_id amount = float_round( abs(tax_move_line.balance) * - invoice.discount_percent / 100.0, + tax_invoice.discount_percent / 100.0, precision_rounding=rounding, ) - discount_amount_credit -= amount + if tax_move_line.credit > 0: + discount_amount_credit += amount + elif tax_move_line.debit > 0: + discount_amount_credit -= amount if tax_move_line.tax_line_id: account = tax_move_line.account_id diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index c2397c9802f8..0d07c3155076 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -164,3 +164,78 @@ def test_cash_discount_with_write_off_with_taxes(self): ]) self.assertEqual(len(tax_15_move_line), 1) self.assertEqual(tax_15_move_line.credit, 15) + + def test_cash_discount_with_refund(self): + self.company.write({ + 'default_cash_discount_writeoff_account_id': + self.cash_discount_writeoff_account.id, + 'default_cash_discount_writeoff_journal_id': + self.cash_discount_writeoff_journal.id, + 'cash_discount_base_amount_type': 'total', + }) + + payment_mode = self.payment_mode_out + payment_mode.post_move = True + discount_due_date = Date.today() + + invoice = self.create_supplier_invoice( + discount_due_date, payment_mode, 100, 2, + [self.tax_17_p.id]) + invoice.action_invoice_open() + self.assertAlmostEqual(invoice.residual, 117) + self.assertAlmostEqual(invoice.residual_with_discount, 114.66) + + move = invoice.move_id + move.post() + + self.AccountInvoiceRefund.create({}).with_context( + active_ids=invoice.ids, + ).compute_refund() + + refund = self.AccountInvoice.search([ + ('origin', '=', invoice.number), + ('type', '=', 'in_refund'), + ]) + refund.invoice_line_ids[0].price_unit = 10 + refund.write({ + 'discount_due_date': discount_due_date, + 'discount_percent': 2, + }) + refund.compute_taxes() + refund.action_invoice_open() + credit_aml_id = self.AccountMoveLine.search([ + ('move_id', '=', refund.move_id.id), + ('debit', '>', 0), + ], limit=1) + + invoice.assign_outstanding_credit(credit_aml_id.id) + + self.assertAlmostEqual(invoice.residual, 105.3) + self.assertAlmostEqual(invoice.residual_with_discount, 103.19) + + payment_order = self.PaymentOrder.create({ + 'payment_mode_id': payment_mode.id, + 'payment_type': 'outbound', + 'journal_id': self.bank_ing_journal.id, + }) + + payment_line_wizard = self.PaymentLineCreate.with_context( + active_model=payment_order._name, + active_id=payment_order.id, + ).create({ + 'cash_discount_date': discount_due_date, + 'date_type': 'discount_due_date', + 'journal_ids': [(6, 0, [self.purchase_journal.id])], + }) + + payment_line_wizard.populate() + payment_line_wizard.create_payment_lines() + + payment_line = payment_order.payment_line_ids[0] + self.assertAlmostEqual(payment_line.amount_currency, 103.19) + + payment_order.draft2open() + payment_order.open2generated() + payment_order.generated2uploaded() + + self.assertEqual(invoice.state, 'paid') From f1cac41c3a26d7c5dda369d39084877fb39157da Mon Sep 17 00:00:00 2001 From: oca-travis Date: Wed, 13 Feb 2019 10:08:58 +0000 Subject: [PATCH 08/22] [UPD] Update account_cash_discount_write_off.pot --- .../i18n/account_cash_discount_write_off.pot | 62 +++++++++++++++++++ account_cash_discount_write_off/i18n/fr.po | 16 +++-- 2 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot diff --git a/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot b/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot new file mode 100644 index 000000000000..e0742b739c59 --- /dev/null +++ b/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot @@ -0,0 +1,62 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_cash_discount_write_off +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.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_cash_discount_write_off +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:71 +#, python-format +msgid "Cash Discount Write-Off" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company_default_cash_discount_writeoff_account_id +msgid "Cash Discount Write-Off Account" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company_default_cash_discount_writeoff_journal_id +msgid "Cash Discount Write-Off Journal" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model,name:account_cash_discount_write_off.model_res_company +msgid "Companies" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model,name:account_cash_discount_write_off.model_account_payment_line +msgid "Payment Lines" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model,name:account_cash_discount_write_off.model_account_payment_order +msgid "Payment Order" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +msgid "Write-Off Account" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +msgid "Write-Off Journal" +msgstr "" + +#. module: account_cash_discount_write_off +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:67 +#, python-format +msgid "You have to fill in journal and account for cash discount write-off on the company." +msgstr "" + diff --git a/account_cash_discount_write_off/i18n/fr.po b/account_cash_discount_write_off/i18n/fr.po index 88e37fd7284b..40042e1b777e 100644 --- a/account_cash_discount_write_off/i18n/fr.po +++ b/account_cash_discount_write_off/i18n/fr.po @@ -1,6 +1,6 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * account_cash_discount_write_off +# * account_cash_discount_write_off # msgid "" msgstr "" @@ -10,13 +10,14 @@ msgstr "" "PO-Revision-Date: 2018-03-09 07:20+0000\n" "Last-Translator: <>\n" "Language-Team: \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" #. module: account_cash_discount_write_off -#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:47 +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:71 #, python-format msgid "Cash Discount Write-Off" msgstr "Escompte (écart)" @@ -57,8 +58,11 @@ msgid "Write-Off Journal" msgstr "Journal d'écart" #. module: account_cash_discount_write_off -#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:43 +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:67 #, python-format -msgid "You have to fill in journal and account for cash discount write-off on the company." -msgstr "Vous devez remplir un journal et un compte d'écart pour les escomptes sur la société." - +msgid "" +"You have to fill in journal and account for cash discount write-off on the " +"company." +msgstr "" +"Vous devez remplir un journal et un compte d'écart pour les escomptes sur la " +"société." From 8db2262657ca64a65c18d4edc596c3ab58eded31 Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Mon, 8 Jun 2020 11:29:18 +0200 Subject: [PATCH 09/22] [WIP] account_cash_discount_base/write_off/payment migration --- account_cash_discount_write_off/__manifest__.py | 2 +- account_cash_discount_write_off/models/account_payment_line.py | 1 - account_cash_discount_write_off/models/account_payment_order.py | 1 - account_cash_discount_write_off/models/res_company.py | 1 - .../tests/test_account_cash_discount_write_off.py | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py index 9210558f9f82..1076ddc24d1d 100644 --- a/account_cash_discount_write_off/__manifest__.py +++ b/account_cash_discount_write_off/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -19,4 +18,5 @@ ], 'demo': [ ], + 'installable': False, } diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index 0f8f1b207fd8..121b2d04b940 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/account_cash_discount_write_off/models/account_payment_order.py b/account_cash_discount_write_off/models/account_payment_order.py index 28fafaee123b..86e271ab74d3 100644 --- a/account_cash_discount_write_off/models/account_payment_order.py +++ b/account_cash_discount_write_off/models/account_payment_order.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/account_cash_discount_write_off/models/res_company.py b/account_cash_discount_write_off/models/res_company.py index 80327532e640..b1add138a6d7 100644 --- a/account_cash_discount_write_off/models/res_company.py +++ b/account_cash_discount_write_off/models/res_company.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index 0d07c3155076..612cdfb3fcaf 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). From 669949fad5c14435b6d382fd6db0a6459623643d Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Wed, 10 Jun 2020 11:05:30 +0200 Subject: [PATCH 10/22] [MIG] account_cash_discount_write_off to v13 --- account_cash_discount_write_off/README.rst | 83 ------------------- .../__manifest__.py | 3 +- .../models/account_payment_line.py | 26 +++--- .../models/account_payment_order.py | 8 +- .../readme/CONFIGURATION.rst | 5 ++ .../readme/CONTRIBUTORS.rst | 2 + .../readme/DESCRIPTION.rst | 5 ++ .../readme/USAGE.rst | 8 ++ .../test_account_cash_discount_write_off.py | 60 +++++++------- 9 files changed, 63 insertions(+), 137 deletions(-) delete mode 100644 account_cash_discount_write_off/README.rst create mode 100644 account_cash_discount_write_off/readme/CONFIGURATION.rst create mode 100644 account_cash_discount_write_off/readme/CONTRIBUTORS.rst create mode 100644 account_cash_discount_write_off/readme/DESCRIPTION.rst create mode 100644 account_cash_discount_write_off/readme/USAGE.rst diff --git a/account_cash_discount_write_off/README.rst b/account_cash_discount_write_off/README.rst deleted file mode 100644 index 0a1e09a007dc..000000000000 --- a/account_cash_discount_write_off/README.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. 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 - -=============================== -Account Cash Discount Write Off -=============================== - -Create an automatic write-off for payment with discount on the payment order -confirmation. If the cash discount amount is computed based on the total -amount, the created write-off will also contains tax adjustments. This -adjustments are computed based on the discount percent configured on the -related invoice. - -Configuration -============= - -To configure this module, you need to: - -#. Go to your companies -#. Set the cash discount write off account -#. Set the cash discount write off journal - -Usage -===== - -To use this module, you need to: - -#. Create a supplier invoice -#. In the "Other Info" tab, you can configure a discount in percent and a discount delay in days -#. Validate the invoice -#. Create a payment order and add the previously created invoice using the search based on the cash discount due date -#. Validate your payment order till the last state -#. The invoice is now marked as "Paid". - -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/96/10.0 - -.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt -.. branch is "8.0" for example - -Known issues / Roadmap -====================== - -* The cash discount should only be used when doing a full payment at once. - -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 smash it by providing detailed and welcomed feedback. - -Credits -======= - -Images ------- - -* Odoo Community Association: `Icon `_. - -Contributors ------------- - -* Benjamin Willig -* Christelle De Coninck (ACSONE) - -Maintainer ----------- - -.. image:: https://odoo-community.org/logo.png - :alt: Odoo Community Association - :target: https://odoo-community.org - -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. - -To contribute to this module, please visit https://odoo-community.org. diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py index 1076ddc24d1d..6d26faa1c266 100644 --- a/account_cash_discount_write_off/__manifest__.py +++ b/account_cash_discount_write_off/__manifest__.py @@ -6,7 +6,7 @@ 'summary': """ Create an automatic writeoff for payment with discount on the payment order confirmation""", - 'version': '10.0.1.0.0', + 'version': '13.0.1.0.0', 'license': 'AGPL-3', 'author': 'ACSONE SA/NV, Odoo Community Association (OCA)', 'website': 'https://github.com/acsone/account-payment', @@ -18,5 +18,4 @@ ], 'demo': [ ], - 'installable': False, } diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index 121b2d04b940..f0a2f43f735f 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -10,24 +10,19 @@ class PaymentLine(models.Model): _inherit = 'account.payment.line' - @api.multi def _check_cash_discount_write_off_creation(self): self.ensure_one() create_write_off = ( self.pay_with_discount and self.move_line_id and - self.move_line_id.invoice_id and - self.move_line_id.invoice_id.has_discount + self.move_line_id.move_id and + self.move_line_id.move_id.has_discount ) if not create_write_off: return False - invoice = self.move_line_id.invoice_id - refunds_amount_total = 0.0 - for pmove_line in invoice.payment_move_line_ids: - pmove_line_inv = pmove_line.invoice_id - if pmove_line_inv and pmove_line_inv.type == 'in_refund': - refunds_amount_total += pmove_line_inv.amount_total + invoice = self.move_line_id.move_id + refunds_amount_total = invoice._get_refunds_amount_total()['total'] # Invoice residual has already changed so we need to compute # the residual with discount before the first reconciliation @@ -43,12 +38,11 @@ def _check_cash_discount_write_off_creation(self): precision_rounding=self.currency_id.rounding ) == 0 - @api.multi def get_cash_discount_writeoff_move_values(self): self.ensure_one() move_line = self.move_line_id partner = move_line.partner_id - invoice = move_line.invoice_id + invoice = move_line.move_id company = invoice.company_id tax_adjustment = company.cash_discount_use_tax_adjustment rounding = self.currency_id.rounding @@ -82,8 +76,8 @@ def get_cash_discount_writeoff_move_values(self): }] if tax_adjustment: - refund_moves = invoice.payment_move_line_ids.filtered( - lambda line: line.invoice_id.type == 'in_refund' + refund_moves = invoice._get_payment_move_lines().filtered( + lambda line: line.move_id.type == 'in_refund' ).mapped('move_id') target_move_ids = refund_moves.ids + [move_line.move_id.id] @@ -95,7 +89,7 @@ def get_cash_discount_writeoff_move_values(self): ]) for tax_move_line in tax_move_lines: - tax_invoice = tax_move_line.invoice_id + tax_invoice = tax_move_line.move_id amount = float_round( abs(tax_move_line.balance) * tax_invoice.discount_percent / 100.0, @@ -116,7 +110,9 @@ def get_cash_discount_writeoff_move_values(self): 'debit': tax_move_line.credit > 0 and amount or 0.0, 'credit': tax_move_line.debit > 0 and amount or 0.0, 'account_id': account.id, - 'tax_line_id': tax_move_line.tax_line_id.id, + 'tax_repartition_line_id': ( + tax_move_line.tax_repartition_line_id.id) + , 'tax_ids': [(6, 0, tax_move_line.tax_ids.ids)] }) diff --git a/account_cash_discount_write_off/models/account_payment_order.py b/account_cash_discount_write_off/models/account_payment_order.py index 86e271ab74d3..49b838db054a 100644 --- a/account_cash_discount_write_off/models/account_payment_order.py +++ b/account_cash_discount_write_off/models/account_payment_order.py @@ -1,28 +1,25 @@ # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, models +from odoo import models class AccountPaymentOrder(models.Model): _inherit = 'account.payment.order' - @api.multi def generated2uploaded(self): res = super(AccountPaymentOrder, self).generated2uploaded() for order in self: order._create_cash_discount_write_off() return res - @api.multi def _create_cash_discount_write_off(self): self.ensure_one() for payment_line in self.payment_line_ids: if payment_line._check_cash_discount_write_off_creation(): self._create_payment_line_discount_write_off(payment_line) - @api.multi def _create_payment_line_discount_write_off(self, payment_line): self.ensure_one() move = self._create_payment_line_discount_write_off_move(payment_line) @@ -34,11 +31,10 @@ def _create_payment_line_discount_write_off(self, payment_line): ) lines_to_reconcile.reconcile() - @api.multi def _create_payment_line_discount_write_off_move(self, payment_line): self.ensure_one() move_values = payment_line.get_cash_discount_writeoff_move_values() move = self.env['account.move'].create(move_values) if self.payment_mode_id.post_move: - move.post() + move.action_post() return move diff --git a/account_cash_discount_write_off/readme/CONFIGURATION.rst b/account_cash_discount_write_off/readme/CONFIGURATION.rst new file mode 100644 index 000000000000..4b36a637786b --- /dev/null +++ b/account_cash_discount_write_off/readme/CONFIGURATION.rst @@ -0,0 +1,5 @@ +To configure this module, you need to: + +#. Go to your companies +#. Set the cash discount write off account +#. Set the cash discount write off journal diff --git a/account_cash_discount_write_off/readme/CONTRIBUTORS.rst b/account_cash_discount_write_off/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..69f56a9f80ae --- /dev/null +++ b/account_cash_discount_write_off/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Benjamin Willig +* Christelle De Coninck (ACSONE) diff --git a/account_cash_discount_write_off/readme/DESCRIPTION.rst b/account_cash_discount_write_off/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..9ea67509095d --- /dev/null +++ b/account_cash_discount_write_off/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +Create an automatic write-off for payment with discount on the payment order +confirmation. If the cash discount amount is computed based on the total +amount, the created write-off will also contains tax adjustments. This +adjustments are computed based on the discount percent configured on the +related invoice. diff --git a/account_cash_discount_write_off/readme/USAGE.rst b/account_cash_discount_write_off/readme/USAGE.rst new file mode 100644 index 000000000000..902c3d3d1b01 --- /dev/null +++ b/account_cash_discount_write_off/readme/USAGE.rst @@ -0,0 +1,8 @@ +To use this module, you need to: + +#. Create a supplier invoice +#. In the "Other Info" tab, you can configure a discount in percent and a discount delay in days +#. Validate the invoice +#. Create a payment order and add the previously created invoice using the search based on the cash discount due date +#. Validate your payment order till the last state +#. The invoice is now marked as "Paid". diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index 612cdfb3fcaf..a34eb48c5d25 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -5,6 +5,7 @@ TestAccountCashDiscountPaymentCommon from odoo.exceptions import UserError from odoo.fields import Date +from odoo.tests.common import Form class TestAccountCashDiscountWriteOff(TestAccountCashDiscountPaymentCommon): @@ -31,10 +32,7 @@ def test_cash_discount_with_write_off(self): invoice = self.create_supplier_invoice( discount_due_date, payment_mode, 1000, 10, []) - invoice.action_invoice_open() - - move = invoice.move_id - move.post() + invoice.action_post() payment_order = self.PaymentOrder.create({ 'payment_mode_id': payment_mode.id, @@ -79,7 +77,7 @@ def test_cash_discount_with_write_off(self): payment_order.generated2uploaded() - payment_move_lines = invoice.payment_move_line_ids + payment_move_lines = invoice._get_payment_move_lines() write_off_line = self.MoveLine.search([ ('id', 'in', payment_move_lines.ids), ('name', '=', "Cash Discount Write-Off"), @@ -96,7 +94,7 @@ def test_cash_discount_with_write_off(self): self.assertEqual( write_off_base_line.account_id, self.cash_discount_writeoff_account) - self.assertEqual(invoice.state, 'paid') + self.assertEqual(invoice.invoice_payment_state, 'paid') def test_cash_discount_with_write_off_with_taxes(self): self.company.write({ @@ -114,11 +112,8 @@ def test_cash_discount_with_write_off_with_taxes(self): invoice = self.create_supplier_invoice( discount_due_date, payment_mode, 1000, 10, - [self.tax_10_p.id, self.tax_15_p.id]) - invoice.action_invoice_open() - - move = invoice.move_id - move.post() + [self.tax_10_p, self.tax_15_p]) + invoice.action_post() payment_order = self.PaymentOrder.create({ 'payment_mode_id': payment_mode.id, @@ -142,7 +137,7 @@ def test_cash_discount_with_write_off_with_taxes(self): payment_order.open2generated() payment_order.generated2uploaded() - self.assertEqual(invoice.state, 'paid') + self.assertEqual(invoice.invoice_payment_state, 'paid') discount_writeoff_move_lines = self.MoveLine.search([ ('journal_id', @@ -179,37 +174,40 @@ def test_cash_discount_with_refund(self): invoice = self.create_supplier_invoice( discount_due_date, payment_mode, 100, 2, - [self.tax_17_p.id]) - invoice.action_invoice_open() - self.assertAlmostEqual(invoice.residual, 117) + [self.tax_17_p]) + invoice.action_post() + self.assertAlmostEqual(invoice.amount_residual, 117) self.assertAlmostEqual(invoice.residual_with_discount, 114.66) - move = invoice.move_id - move.post() + move_reversal = self.AccountMoveReversal.with_context( + active_model=invoice._name, + active_ids=invoice.ids + ).create({ + 'reason': 'no reason', + 'refund_method': 'refund', + }) + reversal = move_reversal.reverse_moves() + + refund = self.env["account.move"].browse(reversal["res_id"]) - self.AccountInvoiceRefund.create({}).with_context( - active_ids=invoice.ids, - ).compute_refund() + refund_form = Form(refund) + with refund_form.invoice_line_ids.edit(0) as refund_line: + refund_line.price_unit = 10 + refund_form.save() - refund = self.AccountInvoice.search([ - ('origin', '=', invoice.number), - ('type', '=', 'in_refund'), - ]) - refund.invoice_line_ids[0].price_unit = 10 refund.write({ 'discount_due_date': discount_due_date, 'discount_percent': 2, }) - refund.compute_taxes() - refund.action_invoice_open() + refund.action_post() credit_aml_id = self.AccountMoveLine.search([ - ('move_id', '=', refund.move_id.id), + ('move_id', '=', refund.id), ('debit', '>', 0), ], limit=1) - invoice.assign_outstanding_credit(credit_aml_id.id) + invoice.js_assign_outstanding_line(credit_aml_id.id) - self.assertAlmostEqual(invoice.residual, 105.3) + self.assertAlmostEqual(invoice.amount_residual, 105.3) self.assertAlmostEqual(invoice.residual_with_discount, 103.19) payment_order = self.PaymentOrder.create({ @@ -237,4 +235,4 @@ def test_cash_discount_with_refund(self): payment_order.open2generated() payment_order.generated2uploaded() - self.assertEqual(invoice.state, 'paid') + self.assertEqual(invoice.invoice_payment_state, 'paid') From 864e1826bd3a3ebce8c450e59041be372b69d992 Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Wed, 10 Jun 2020 11:17:27 +0200 Subject: [PATCH 11/22] [FIX] pre-commit --- .../__manifest__.py | 23 +- .../models/account_payment_line.py | 148 +++++------ .../models/account_payment_order.py | 9 +- .../models/res_company.py | 8 +- .../test_account_cash_discount_write_off.py | 251 ++++++++++-------- .../views/res_company.xml | 22 +- 6 files changed, 237 insertions(+), 224 deletions(-) diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py index 6d26faa1c266..4b42d79a7e62 100644 --- a/account_cash_discount_write_off/__manifest__.py +++ b/account_cash_discount_write_off/__manifest__.py @@ -2,20 +2,15 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Account Cash Discount Write Off', - 'summary': """ + "name": "Account Cash Discount Write Off", + "summary": """ Create an automatic writeoff for payment with discount on the payment order confirmation""", - 'version': '13.0.1.0.0', - 'license': 'AGPL-3', - 'author': 'ACSONE SA/NV, Odoo Community Association (OCA)', - 'website': 'https://github.com/acsone/account-payment', - 'depends': [ - 'account_cash_discount_payment', - ], - 'data': [ - 'views/res_company.xml', - ], - 'demo': [ - ], + "version": "13.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV, Odoo Community Association (OCA)", + "website": "https://github.com/acsone/account-payment", + "depends": ["account_cash_discount_payment"], + "data": ["views/res_company.xml"], + "demo": [], } diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index f0a2f43f735f..492611c4e0ae 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -1,42 +1,45 @@ # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, models, _ +from odoo import _, models from odoo.exceptions import UserError -from odoo.tools import float_compare, float_round, float_is_zero +from odoo.tools import float_compare, float_is_zero, float_round class PaymentLine(models.Model): - _inherit = 'account.payment.line' + _inherit = "account.payment.line" def _check_cash_discount_write_off_creation(self): self.ensure_one() create_write_off = ( - self.pay_with_discount and - self.move_line_id and - self.move_line_id.move_id and - self.move_line_id.move_id.has_discount + self.pay_with_discount + and self.move_line_id + and self.move_line_id.move_id + and self.move_line_id.move_id.has_discount ) if not create_write_off: return False invoice = self.move_line_id.move_id - refunds_amount_total = invoice._get_refunds_amount_total()['total'] + refunds_amount_total = invoice._get_refunds_amount_total()["total"] # Invoice residual has already changed so we need to compute # the residual with discount before the first reconciliation amount_to_pay = ( - invoice.amount_total - - refunds_amount_total - - invoice.discount_amount + - invoice.refunds_discount_amount + invoice.amount_total + - refunds_amount_total + - invoice.discount_amount + + invoice.refunds_discount_amount + ) + return ( + float_compare( + self.amount_currency, + amount_to_pay, + precision_rounding=self.currency_id.rounding, + ) + == 0 ) - return float_compare( - self.amount_currency, - amount_to_pay, - precision_rounding=self.currency_id.rounding - ) == 0 def get_cash_discount_writeoff_move_values(self): self.ensure_one() @@ -57,42 +60,48 @@ def get_cash_discount_writeoff_move_values(self): if not woff_account or not woff_journal: raise UserError( - _("You have to fill in journal and account for cash discount " - "write-off on the company.") + _( + "You have to fill in journal and account for cash discount " + "write-off on the company." + ) ) move_line_name = _("Cash Discount Write-Off") supplier_account_amount = ( - invoice.discount_amount - - invoice.refunds_discount_amount + invoice.discount_amount - invoice.refunds_discount_amount ) discount_amount_credit = supplier_account_amount - lines_values = [{ - 'partner_id': partner.id, - 'name': move_line_name, - 'debit': supplier_account_amount, - 'account_id': move_line.account_id.id, - }] + lines_values = [ + { + "partner_id": partner.id, + "name": move_line_name, + "debit": supplier_account_amount, + "account_id": move_line.account_id.id, + } + ] if tax_adjustment: - refund_moves = invoice._get_payment_move_lines().filtered( - lambda line: line.move_id.type == 'in_refund' - ).mapped('move_id') + refund_moves = ( + invoice._get_payment_move_lines() + .filtered(lambda line: line.move_id.type == "in_refund") + .mapped("move_id") + ) target_move_ids = refund_moves.ids + [move_line.move_id.id] - tax_move_lines = self.env['account.move.line'].search([ - ('move_id', 'in', target_move_ids), - '|', - ('tax_line_id', '!=', False), - ('tax_ids', '!=', False) - ]) + tax_move_lines = self.env["account.move.line"].search( + [ + ("move_id", "in", target_move_ids), + "|", + ("tax_line_id", "!=", False), + ("tax_ids", "!=", False), + ] + ) for tax_move_line in tax_move_lines: tax_invoice = tax_move_line.move_id amount = float_round( - abs(tax_move_line.balance) * - tax_invoice.discount_percent / 100.0, + abs(tax_move_line.balance) * tax_invoice.discount_percent / 100.0, precision_rounding=rounding, ) if tax_move_line.credit > 0: @@ -104,49 +113,40 @@ def get_cash_discount_writeoff_move_values(self): account = tax_move_line.account_id else: account = woff_account - lines_values.append({ - 'partner_id': partner.id, - 'name': move_line_name, - 'debit': tax_move_line.credit > 0 and amount or 0.0, - 'credit': tax_move_line.debit > 0 and amount or 0.0, - 'account_id': account.id, - 'tax_repartition_line_id': ( - tax_move_line.tax_repartition_line_id.id) - , - 'tax_ids': [(6, 0, tax_move_line.tax_ids.ids)] - }) + lines_values.append( + { + "partner_id": partner.id, + "name": move_line_name, + "debit": tax_move_line.credit > 0 and amount or 0.0, + "credit": tax_move_line.debit > 0 and amount or 0.0, + "account_id": account.id, + "tax_repartition_line_id": ( + tax_move_line.tax_repartition_line_id.id + ), + "tax_ids": [(6, 0, tax_move_line.tax_ids.ids)], + } + ) amount_left = not float_is_zero( - discount_amount_credit, - precision_rounding=rounding + discount_amount_credit, precision_rounding=rounding ) if amount_left: writeoff_amount = float_round( - abs(discount_amount_credit), - precision_rounding=rounding, + abs(discount_amount_credit), precision_rounding=rounding, + ) + lines_values.append( + { + "partner_id": partner.id, + "name": move_line_name, + "credit": (writeoff_amount if discount_amount_credit > 0 else 0.0), + "debit": (writeoff_amount if discount_amount_credit < 0 else 0.0), + "account_id": woff_account.id, + } ) - lines_values.append({ - 'partner_id': partner.id, - 'name': move_line_name, - 'credit': ( - writeoff_amount - if discount_amount_credit > 0 - else 0.0 - ), - 'debit': ( - writeoff_amount - if discount_amount_credit < 0 - else 0.0 - ), - 'account_id': woff_account.id, - }) move_values = { - 'journal_id': woff_journal.id, - 'partner_id': partner.id, - 'line_ids': [ - (0, 0, values) - for values in lines_values - ] + "journal_id": woff_journal.id, + "partner_id": partner.id, + "line_ids": [(0, 0, values) for values in lines_values], } return move_values diff --git a/account_cash_discount_write_off/models/account_payment_order.py b/account_cash_discount_write_off/models/account_payment_order.py index 49b838db054a..e8b83aa8beae 100644 --- a/account_cash_discount_write_off/models/account_payment_order.py +++ b/account_cash_discount_write_off/models/account_payment_order.py @@ -6,7 +6,7 @@ class AccountPaymentOrder(models.Model): - _inherit = 'account.payment.order' + _inherit = "account.payment.order" def generated2uploaded(self): res = super(AccountPaymentOrder, self).generated2uploaded() @@ -25,16 +25,15 @@ def _create_payment_line_discount_write_off(self, payment_line): move = self._create_payment_line_discount_write_off_move(payment_line) move_lines = payment_line.move_line_id | move.line_ids lines_to_reconcile = move_lines.filtered( - lambda line: - not line.reconciled and - line.account_id == payment_line.move_line_id.account_id + lambda line: not line.reconciled + and line.account_id == payment_line.move_line_id.account_id ) lines_to_reconcile.reconcile() def _create_payment_line_discount_write_off_move(self, payment_line): self.ensure_one() move_values = payment_line.get_cash_discount_writeoff_move_values() - move = self.env['account.move'].create(move_values) + move = self.env["account.move"].create(move_values) if self.payment_mode_id.post_move: move.action_post() return move diff --git a/account_cash_discount_write_off/models/res_company.py b/account_cash_discount_write_off/models/res_company.py index b1add138a6d7..8ca566c03a6a 100644 --- a/account_cash_discount_write_off/models/res_company.py +++ b/account_cash_discount_write_off/models/res_company.py @@ -6,13 +6,11 @@ class ResCompany(models.Model): - _inherit = 'res.company' + _inherit = "res.company" default_cash_discount_writeoff_account_id = fields.Many2one( - comodel_name='account.account', - string="Cash Discount Write-Off Account" + comodel_name="account.account", string="Cash Discount Write-Off Account" ) default_cash_discount_writeoff_journal_id = fields.Many2one( - comodel_name='account.journal', - string="Cash Discount Write-Off Journal" + comodel_name="account.journal", string="Cash Discount Write-Off Journal" ) diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index a34eb48c5d25..f3405744044c 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -1,29 +1,30 @@ # Copyright 2018 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.addons.account_cash_discount_payment.tests.common import \ - TestAccountCashDiscountPaymentCommon from odoo.exceptions import UserError from odoo.fields import Date from odoo.tests.common import Form +from odoo.addons.account_cash_discount_payment.tests.common import ( + TestAccountCashDiscountPaymentCommon, +) -class TestAccountCashDiscountWriteOff(TestAccountCashDiscountPaymentCommon): +class TestAccountCashDiscountWriteOff(TestAccountCashDiscountPaymentCommon): @classmethod def setUpClass(cls): super(TestAccountCashDiscountWriteOff, cls).setUpClass() - cls.cash_discount_writeoff_account = cls.Account.create({ - 'name': "Cash Discount Write-Off", - 'code': "CD-W", - 'user_type_id': cls.inc_account_type.id, - }) - - cls.cash_discount_writeoff_journal = cls.Journal.create({ - 'name': "Cash Discount Write-Off", - 'code': "CD-W", - 'type': 'general', - }) + cls.cash_discount_writeoff_account = cls.Account.create( + { + "name": "Cash Discount Write-Off", + "code": "CD-W", + "user_type_id": cls.inc_account_type.id, + } + ) + + cls.cash_discount_writeoff_journal = cls.Journal.create( + {"name": "Cash Discount Write-Off", "code": "CD-W", "type": "general"} + ) def test_cash_discount_with_write_off(self): payment_mode = self.payment_mode_out @@ -31,23 +32,27 @@ def test_cash_discount_with_write_off(self): discount_due_date = Date.today() invoice = self.create_supplier_invoice( - discount_due_date, payment_mode, 1000, 10, []) + discount_due_date, payment_mode, 1000, 10, [] + ) invoice.action_post() - payment_order = self.PaymentOrder.create({ - 'payment_mode_id': payment_mode.id, - 'payment_type': 'outbound', - 'journal_id': self.bank_ing_journal.id, - }) + payment_order = self.PaymentOrder.create( + { + "payment_mode_id": payment_mode.id, + "payment_type": "outbound", + "journal_id": self.bank_ing_journal.id, + } + ) payment_line_wizard = self.PaymentLineCreate.with_context( - active_model=payment_order._name, - active_id=payment_order.id, - ).create({ - 'cash_discount_date': discount_due_date, - 'date_type': 'discount_due_date', - 'journal_ids': [(6, 0, [self.purchase_journal.id])], - }) + active_model=payment_order._name, active_id=payment_order.id, + ).create( + { + "cash_discount_date": discount_due_date, + "date_type": "discount_due_date", + "journal_ids": [(6, 0, [self.purchase_journal.id])], + } + ) payment_line_wizard.populate() payment_line_wizard.create_payment_lines() @@ -59,8 +64,7 @@ def test_cash_discount_with_write_off(self): self.assertTrue(payment_line._check_cash_discount_write_off_creation()) old_amount = payment_line.amount_currency payment_line.amount_currency = 10 - self.assertFalse( - payment_line._check_cash_discount_write_off_creation()) + self.assertFalse(payment_line._check_cash_discount_write_off_creation()) payment_line.amount_currency = old_amount payment_order.open2generated() @@ -68,67 +72,80 @@ def test_cash_discount_with_write_off(self): with self.assertRaises(UserError), self.env.cr.savepoint(): payment_order.generated2uploaded() - self.company.write({ - 'default_cash_discount_writeoff_account_id': - self.cash_discount_writeoff_account.id, - 'default_cash_discount_writeoff_journal_id': - self.cash_discount_writeoff_journal.id, - }) + woff_account = self.cash_discount_writeoff_account + woff_journal = self.cash_discount_writeoff_journal + self.company.write( + { + "default_cash_discount_writeoff_account_id": woff_account.id, + "default_cash_discount_writeoff_journal_id": woff_journal.id, + "cash_discount_base_amount_type": "total", + } + ) payment_order.generated2uploaded() payment_move_lines = invoice._get_payment_move_lines() - write_off_line = self.MoveLine.search([ - ('id', 'in', payment_move_lines.ids), - ('name', '=', "Cash Discount Write-Off"), - ]) + write_off_line = self.MoveLine.search( + [ + ("id", "in", payment_move_lines.ids), + ("name", "=", "Cash Discount Write-Off"), + ] + ) self.assertEqual(len(write_off_line), 1) self.assertEqual(write_off_line.debit, 100) - write_off_base_line = self.MoveLine.search([ - ('id', '!=', write_off_line.id), - ('move_id', '=', write_off_line.move_id.id), - ]) + write_off_base_line = self.MoveLine.search( + [ + ("id", "!=", write_off_line.id), + ("move_id", "=", write_off_line.move_id.id), + ] + ) self.assertEqual(len(write_off_base_line), 1) self.assertEqual( - write_off_base_line.account_id, - self.cash_discount_writeoff_account) - self.assertEqual(invoice.invoice_payment_state, 'paid') + write_off_base_line.account_id, self.cash_discount_writeoff_account + ) + self.assertEqual(invoice.invoice_payment_state, "paid") def test_cash_discount_with_write_off_with_taxes(self): - self.company.write({ - 'default_cash_discount_writeoff_account_id': - self.cash_discount_writeoff_account.id, - 'default_cash_discount_writeoff_journal_id': - self.cash_discount_writeoff_journal.id, - 'cash_discount_base_amount_type': 'total', - }) - self.assertEqual(self.company.cash_discount_base_amount_type, 'total') + woff_account = self.cash_discount_writeoff_account + woff_journal = self.cash_discount_writeoff_journal + self.company.write( + { + "default_cash_discount_writeoff_account_id": woff_account.id, + "default_cash_discount_writeoff_journal_id": woff_journal.id, + "cash_discount_base_amount_type": "total", + } + ) + + self.assertEqual(self.company.cash_discount_base_amount_type, "total") payment_mode = self.payment_mode_out payment_mode.post_move = True discount_due_date = Date.today() invoice = self.create_supplier_invoice( - discount_due_date, payment_mode, 1000, 10, - [self.tax_10_p, self.tax_15_p]) + discount_due_date, payment_mode, 1000, 10, [self.tax_10_p, self.tax_15_p] + ) invoice.action_post() - payment_order = self.PaymentOrder.create({ - 'payment_mode_id': payment_mode.id, - 'payment_type': 'outbound', - 'journal_id': self.bank_ing_journal.id, - }) + payment_order = self.PaymentOrder.create( + { + "payment_mode_id": payment_mode.id, + "payment_type": "outbound", + "journal_id": self.bank_ing_journal.id, + } + ) payment_line_wizard = self.PaymentLineCreate.with_context( - active_model=payment_order._name, - active_id=payment_order.id, - ).create({ - 'cash_discount_date': discount_due_date, - 'date_type': 'discount_due_date', - 'journal_ids': [(6, 0, [self.purchase_journal.id])], - }) + active_model=payment_order._name, active_id=payment_order.id, + ).create( + { + "cash_discount_date": discount_due_date, + "date_type": "discount_due_date", + "journal_ids": [(6, 0, [self.purchase_journal.id])], + } + ) payment_line_wizard.populate() payment_line_wizard.create_payment_lines() @@ -137,55 +154,56 @@ def test_cash_discount_with_write_off_with_taxes(self): payment_order.open2generated() payment_order.generated2uploaded() - self.assertEqual(invoice.invoice_payment_state, 'paid') + self.assertEqual(invoice.invoice_payment_state, "paid") - discount_writeoff_move_lines = self.MoveLine.search([ - ('journal_id', - '=', self.cash_discount_writeoff_journal.id) - ]) + discount_writeoff_move_lines = self.MoveLine.search( + [("journal_id", "=", self.cash_discount_writeoff_journal.id)] + ) self.assertEqual(len(discount_writeoff_move_lines), 4) - tax_10_move_line = self.MoveLine.search([ - ('id', 'in', discount_writeoff_move_lines.ids), - ('tax_line_id', '=', self.tax_10_p.id), - ]) + tax_10_move_line = self.MoveLine.search( + [ + ("id", "in", discount_writeoff_move_lines.ids), + ("tax_line_id", "=", self.tax_10_p.id), + ] + ) self.assertEqual(len(tax_10_move_line), 1) self.assertEqual(tax_10_move_line.credit, 10) - tax_15_move_line = self.MoveLine.search([ - ('id', 'in', discount_writeoff_move_lines.ids), - ('tax_line_id', '=', self.tax_15_p.id), - ]) + tax_15_move_line = self.MoveLine.search( + [ + ("id", "in", discount_writeoff_move_lines.ids), + ("tax_line_id", "=", self.tax_15_p.id), + ] + ) self.assertEqual(len(tax_15_move_line), 1) self.assertEqual(tax_15_move_line.credit, 15) def test_cash_discount_with_refund(self): - self.company.write({ - 'default_cash_discount_writeoff_account_id': - self.cash_discount_writeoff_account.id, - 'default_cash_discount_writeoff_journal_id': - self.cash_discount_writeoff_journal.id, - 'cash_discount_base_amount_type': 'total', - }) + woff_account = self.cash_discount_writeoff_account + woff_journal = self.cash_discount_writeoff_journal + self.company.write( + { + "default_cash_discount_writeoff_account_id": woff_account.id, + "default_cash_discount_writeoff_journal_id": woff_journal.id, + "cash_discount_base_amount_type": "total", + } + ) payment_mode = self.payment_mode_out payment_mode.post_move = True discount_due_date = Date.today() invoice = self.create_supplier_invoice( - discount_due_date, payment_mode, 100, 2, - [self.tax_17_p]) + discount_due_date, payment_mode, 100, 2, [self.tax_17_p] + ) invoice.action_post() self.assertAlmostEqual(invoice.amount_residual, 117) self.assertAlmostEqual(invoice.residual_with_discount, 114.66) move_reversal = self.AccountMoveReversal.with_context( - active_model=invoice._name, - active_ids=invoice.ids - ).create({ - 'reason': 'no reason', - 'refund_method': 'refund', - }) + active_model=invoice._name, active_ids=invoice.ids + ).create({"reason": "no reason", "refund_method": "refund"}) reversal = move_reversal.reverse_moves() refund = self.env["account.move"].browse(reversal["res_id"]) @@ -195,35 +213,34 @@ def test_cash_discount_with_refund(self): refund_line.price_unit = 10 refund_form.save() - refund.write({ - 'discount_due_date': discount_due_date, - 'discount_percent': 2, - }) + refund.write({"discount_due_date": discount_due_date, "discount_percent": 2}) refund.action_post() - credit_aml_id = self.AccountMoveLine.search([ - ('move_id', '=', refund.id), - ('debit', '>', 0), - ], limit=1) + credit_aml_id = self.AccountMoveLine.search( + [("move_id", "=", refund.id), ("debit", ">", 0)], limit=1 + ) invoice.js_assign_outstanding_line(credit_aml_id.id) self.assertAlmostEqual(invoice.amount_residual, 105.3) self.assertAlmostEqual(invoice.residual_with_discount, 103.19) - payment_order = self.PaymentOrder.create({ - 'payment_mode_id': payment_mode.id, - 'payment_type': 'outbound', - 'journal_id': self.bank_ing_journal.id, - }) + payment_order = self.PaymentOrder.create( + { + "payment_mode_id": payment_mode.id, + "payment_type": "outbound", + "journal_id": self.bank_ing_journal.id, + } + ) payment_line_wizard = self.PaymentLineCreate.with_context( - active_model=payment_order._name, - active_id=payment_order.id, - ).create({ - 'cash_discount_date': discount_due_date, - 'date_type': 'discount_due_date', - 'journal_ids': [(6, 0, [self.purchase_journal.id])], - }) + active_model=payment_order._name, active_id=payment_order.id, + ).create( + { + "cash_discount_date": discount_due_date, + "date_type": "discount_due_date", + "journal_ids": [(6, 0, [self.purchase_journal.id])], + } + ) payment_line_wizard.populate() payment_line_wizard.create_payment_lines() @@ -235,4 +252,4 @@ def test_cash_discount_with_refund(self): payment_order.open2generated() payment_order.generated2uploaded() - self.assertEqual(invoice.invoice_payment_state, 'paid') + self.assertEqual(invoice.invoice_payment_state, "paid") diff --git a/account_cash_discount_write_off/views/res_company.xml b/account_cash_discount_write_off/views/res_company.xml index 2491b6b95cd7..e2d1bb5338a9 100644 --- a/account_cash_discount_write_off/views/res_company.xml +++ b/account_cash_discount_write_off/views/res_company.xml @@ -1,21 +1,25 @@ - + - - res.company.form (in account_cash_discount_write_off) res.company - + - - - + + - - From 0eb667d3a9320c10e3fabc684cf97e9faf8cdaca Mon Sep 17 00:00:00 2001 From: Benjamin Willig Date: Mon, 17 Aug 2020 13:36:28 +0200 Subject: [PATCH 12/22] [FIX] updated /po files to prevent errors --- .../i18n/account_cash_discount_write_off.pot | 4 ++-- account_cash_discount_write_off/i18n/fr.po | 15 +++++---------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot b/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot index e0742b739c59..cc6aff51749f 100644 --- a/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot +++ b/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot @@ -45,12 +45,12 @@ msgid "Payment Order" msgstr "" #. module: account_cash_discount_write_off -#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +#: model_terms:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view msgid "Write-Off Account" msgstr "" #. module: account_cash_discount_write_off -#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +#: model_terms:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view msgid "Write-Off Journal" msgstr "" diff --git a/account_cash_discount_write_off/i18n/fr.po b/account_cash_discount_write_off/i18n/fr.po index 40042e1b777e..92ea0e4bb25d 100644 --- a/account_cash_discount_write_off/i18n/fr.po +++ b/account_cash_discount_write_off/i18n/fr.po @@ -1,16 +1,13 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * account_cash_discount_write_off +# * account_cash_discount_write_off # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 10.0+e\n" +"Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-09 07:20+0000\n" -"PO-Revision-Date: 2018-03-09 07:20+0000\n" "Last-Translator: <>\n" "Language-Team: \n" -"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" @@ -48,21 +45,19 @@ msgid "Payment Order" msgstr "Ordre de paiement" #. module: account_cash_discount_write_off -#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +#: model_terms:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view msgid "Write-Off Account" msgstr "Compte d'écart" #. module: account_cash_discount_write_off -#: model:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view +#: model_terms:ir.ui.view,arch_db:account_cash_discount_write_off.res_company_form_view msgid "Write-Off Journal" msgstr "Journal d'écart" #. module: account_cash_discount_write_off #: code:addons/account_cash_discount_write_off/models/account_payment_line.py:67 #, python-format -msgid "" -"You have to fill in journal and account for cash discount write-off on the " -"company." +msgid "You have to fill in journal and account for cash discount write-off on the company." msgstr "" "Vous devez remplir un journal et un compte d'écart pour les escomptes sur la " "société." From 92f7db7fffd56c487d2bf254e60f334564d1ece3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Honor=C3=A9?= Date: Mon, 9 Nov 2020 14:18:28 +0100 Subject: [PATCH 13/22] [FIX] Fix pre-commit + generate README --- account_cash_discount_write_off/README.rst | 90 ++++ .../static/description/index.html | 437 ++++++++++++++++++ 2 files changed, 527 insertions(+) create mode 100644 account_cash_discount_write_off/README.rst create mode 100644 account_cash_discount_write_off/static/description/index.html diff --git a/account_cash_discount_write_off/README.rst b/account_cash_discount_write_off/README.rst new file mode 100644 index 000000000000..49cc00584423 --- /dev/null +++ b/account_cash_discount_write_off/README.rst @@ -0,0 +1,90 @@ +=============================== +Account Cash Discount Write Off +=============================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/13.0/account_cash_discount_write_off + :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-13-0/account-payment-13-0-account_cash_discount_write_off + :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/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Create an automatic write-off for payment with discount on the payment order +confirmation. If the cash discount amount is computed based on the total +amount, the created write-off will also contains tax adjustments. This +adjustments are computed based on the discount percent configured on the +related invoice. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +#. Create a supplier invoice +#. In the "Other Info" tab, you can configure a discount in percent and a discount delay in days +#. Validate the invoice +#. Create a payment order and add the previously created invoice using the search based on the cash discount due date +#. Validate your payment order till the last state +#. The invoice is now marked as "Paid". + +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 +~~~~~~~ + +* ACSONE SA/NV + +Contributors +~~~~~~~~~~~~ + +* Benjamin Willig +* Christelle De Coninck (ACSONE) + +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. + +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_cash_discount_write_off/static/description/index.html b/account_cash_discount_write_off/static/description/index.html new file mode 100644 index 000000000000..32f2afc9bbbf --- /dev/null +++ b/account_cash_discount_write_off/static/description/index.html @@ -0,0 +1,437 @@ + + + + + + +Account Cash Discount Write Off + + + +
+

Account Cash Discount Write Off

+ + +

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

+

Create an automatic write-off for payment with discount on the payment order +confirmation. If the cash discount amount is computed based on the total +amount, the created write-off will also contains tax adjustments. This +adjustments are computed based on the discount percent configured on the +related invoice.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. Create a supplier invoice
  2. +
  3. In the “Other Info” tab, you can configure a discount in percent and a discount delay in days
  4. +
  5. Validate the invoice
  6. +
  7. Create a payment order and add the previously created invoice using the search based on the cash discount due date
  8. +
  9. Validate your payment order till the last state
  10. +
  11. The invoice is now marked as “Paid”.
  12. +
+
+
+

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

+
    +
  • ACSONE SA/NV
  • +
+
+
+

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.

+

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.

+
+
+
+ + From 0d9048acff1788f4d2e684b603c50ccf088b648f Mon Sep 17 00:00:00 2001 From: hkapatel Date: Fri, 24 Sep 2021 14:30:43 +0530 Subject: [PATCH 14/22] [IMP] account_cash_discount_write_off: black, isort, prettier --- account_cash_discount_write_off/__manifest__.py | 2 +- .../models/account_payment_line.py | 3 ++- .../tests/test_account_cash_discount_write_off.py | 9 ++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py index 4b42d79a7e62..4f8ea1a497d7 100644 --- a/account_cash_discount_write_off/__manifest__.py +++ b/account_cash_discount_write_off/__manifest__.py @@ -9,7 +9,7 @@ "version": "13.0.1.0.0", "license": "AGPL-3", "author": "ACSONE SA/NV, Odoo Community Association (OCA)", - "website": "https://github.com/acsone/account-payment", + "website": "https://github.com/OCA/account-payment", "depends": ["account_cash_discount_payment"], "data": ["views/res_company.xml"], "demo": [], diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index 492611c4e0ae..36016901af80 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -132,7 +132,8 @@ def get_cash_discount_writeoff_move_values(self): ) if amount_left: writeoff_amount = float_round( - abs(discount_amount_credit), precision_rounding=rounding, + abs(discount_amount_credit), + precision_rounding=rounding, ) lines_values.append( { diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index f3405744044c..1ffda744a9fc 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -45,7 +45,8 @@ def test_cash_discount_with_write_off(self): ) payment_line_wizard = self.PaymentLineCreate.with_context( - active_model=payment_order._name, active_id=payment_order.id, + active_model=payment_order._name, + active_id=payment_order.id, ).create( { "cash_discount_date": discount_due_date, @@ -138,7 +139,8 @@ def test_cash_discount_with_write_off_with_taxes(self): ) payment_line_wizard = self.PaymentLineCreate.with_context( - active_model=payment_order._name, active_id=payment_order.id, + active_model=payment_order._name, + active_id=payment_order.id, ).create( { "cash_discount_date": discount_due_date, @@ -233,7 +235,8 @@ def test_cash_discount_with_refund(self): ) payment_line_wizard = self.PaymentLineCreate.with_context( - active_model=payment_order._name, active_id=payment_order.id, + active_model=payment_order._name, + active_id=payment_order.id, ).create( { "cash_discount_date": discount_due_date, From 238f7d2d90f9e562deb18f7bd1030a561276c35f Mon Sep 17 00:00:00 2001 From: hkapatel Date: Fri, 24 Sep 2021 17:06:45 +0530 Subject: [PATCH 15/22] [MIG] account_cash_discount_write_off: Migration to 14.0 --- account_cash_discount_write_off/__manifest__.py | 2 +- .../models/account_payment_line.py | 2 +- account_cash_discount_write_off/readme/CONTRIBUTORS.rst | 1 + .../tests/test_account_cash_discount_write_off.py | 6 +++--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/account_cash_discount_write_off/__manifest__.py b/account_cash_discount_write_off/__manifest__.py index 4f8ea1a497d7..b1ad5106bd76 100644 --- a/account_cash_discount_write_off/__manifest__.py +++ b/account_cash_discount_write_off/__manifest__.py @@ -6,7 +6,7 @@ "summary": """ Create an automatic writeoff for payment with discount on the payment order confirmation""", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "license": "AGPL-3", "author": "ACSONE SA/NV, Odoo Community Association (OCA)", "website": "https://github.com/OCA/account-payment", diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index 36016901af80..b247220910b7 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -84,7 +84,7 @@ def get_cash_discount_writeoff_move_values(self): if tax_adjustment: refund_moves = ( invoice._get_payment_move_lines() - .filtered(lambda line: line.move_id.type == "in_refund") + .filtered(lambda line: line.move_id.move_type == "in_refund") .mapped("move_id") ) target_move_ids = refund_moves.ids + [move_line.move_id.id] diff --git a/account_cash_discount_write_off/readme/CONTRIBUTORS.rst b/account_cash_discount_write_off/readme/CONTRIBUTORS.rst index 69f56a9f80ae..804addf92882 100644 --- a/account_cash_discount_write_off/readme/CONTRIBUTORS.rst +++ b/account_cash_discount_write_off/readme/CONTRIBUTORS.rst @@ -1,2 +1,3 @@ * Benjamin Willig * Christelle De Coninck (ACSONE) +* Helly kapatel diff --git a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py index 1ffda744a9fc..5df9d2f83b88 100644 --- a/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py +++ b/account_cash_discount_write_off/tests/test_account_cash_discount_write_off.py @@ -106,7 +106,7 @@ def test_cash_discount_with_write_off(self): self.assertEqual( write_off_base_line.account_id, self.cash_discount_writeoff_account ) - self.assertEqual(invoice.invoice_payment_state, "paid") + self.assertEqual(invoice.payment_state, "paid") def test_cash_discount_with_write_off_with_taxes(self): woff_account = self.cash_discount_writeoff_account @@ -156,7 +156,7 @@ def test_cash_discount_with_write_off_with_taxes(self): payment_order.open2generated() payment_order.generated2uploaded() - self.assertEqual(invoice.invoice_payment_state, "paid") + self.assertEqual(invoice.payment_state, "paid") discount_writeoff_move_lines = self.MoveLine.search( [("journal_id", "=", self.cash_discount_writeoff_journal.id)] @@ -255,4 +255,4 @@ def test_cash_discount_with_refund(self): payment_order.open2generated() payment_order.generated2uploaded() - self.assertEqual(invoice.invoice_payment_state, "paid") + self.assertEqual(invoice.payment_state, "paid") From 8a68cdcfdc0672b66625470564b8f04991a99f72 Mon Sep 17 00:00:00 2001 From: fkantelberg Date: Fri, 14 Jan 2022 13:40:25 +0100 Subject: [PATCH 16/22] Copy tax tags to new lines --- account_cash_discount_write_off/models/account_payment_line.py | 1 + 1 file changed, 1 insertion(+) diff --git a/account_cash_discount_write_off/models/account_payment_line.py b/account_cash_discount_write_off/models/account_payment_line.py index b247220910b7..36a2cd1ec7ab 100644 --- a/account_cash_discount_write_off/models/account_payment_line.py +++ b/account_cash_discount_write_off/models/account_payment_line.py @@ -124,6 +124,7 @@ def get_cash_discount_writeoff_move_values(self): tax_move_line.tax_repartition_line_id.id ), "tax_ids": [(6, 0, tax_move_line.tax_ids.ids)], + "tax_tag_ids": [(6, 0, tax_move_line.tax_tag_ids.ids)], } ) From a7b4d0e4bd56b002dc55f07bc31c02ec6b105d43 Mon Sep 17 00:00:00 2001 From: fkantelberg Date: Fri, 14 Jan 2022 15:36:16 +0100 Subject: [PATCH 17/22] Generate the discount before reconiliation --- .../models/account_payment_order.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/account_cash_discount_write_off/models/account_payment_order.py b/account_cash_discount_write_off/models/account_payment_order.py index e8b83aa8beae..ddc4dfe35c88 100644 --- a/account_cash_discount_write_off/models/account_payment_order.py +++ b/account_cash_discount_write_off/models/account_payment_order.py @@ -9,9 +9,11 @@ class AccountPaymentOrder(models.Model): _inherit = "account.payment.order" def generated2uploaded(self): - res = super(AccountPaymentOrder, self).generated2uploaded() + # Generate the discount first for order in self: order._create_cash_discount_write_off() + + res = super().generated2uploaded() return res def _create_cash_discount_write_off(self): From ed9d1f8f06689719e9dcae31be4db269ce0f8087 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Fri, 21 Jan 2022 14:33:24 +0000 Subject: [PATCH 18/22] [UPD] Update account_cash_discount_write_off.pot --- .../i18n/account_cash_discount_write_off.pot | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot b/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot index cc6aff51749f..49f2e174587c 100644 --- a/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot +++ b/account_cash_discount_write_off/i18n/account_cash_discount_write_off.pot @@ -1,12 +1,12 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * account_cash_discount_write_off +# * account_cash_discount_write_off # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 10.0\n" +"Project-Id-Version: Odoo Server 14.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,18 +14,18 @@ msgstr "" "Plural-Forms: \n" #. module: account_cash_discount_write_off -#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:71 +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:0 #, python-format msgid "Cash Discount Write-Off" msgstr "" #. module: account_cash_discount_write_off -#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company_default_cash_discount_writeoff_account_id +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company__default_cash_discount_writeoff_account_id msgid "Cash Discount Write-Off Account" msgstr "" #. module: account_cash_discount_write_off -#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company_default_cash_discount_writeoff_journal_id +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company__default_cash_discount_writeoff_journal_id msgid "Cash Discount Write-Off Journal" msgstr "" @@ -34,6 +34,27 @@ msgstr "" msgid "Companies" msgstr "" +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_account_payment_line__display_name +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_account_payment_order__display_name +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company__display_name +msgid "Display Name" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_account_payment_line__id +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_account_payment_order__id +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company__id +msgid "ID" +msgstr "" + +#. module: account_cash_discount_write_off +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_account_payment_line____last_update +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_account_payment_order____last_update +#: model:ir.model.fields,field_description:account_cash_discount_write_off.field_res_company____last_update +msgid "Last Modified on" +msgstr "" + #. module: account_cash_discount_write_off #: model:ir.model,name:account_cash_discount_write_off.model_account_payment_line msgid "Payment Lines" @@ -55,8 +76,9 @@ msgid "Write-Off Journal" msgstr "" #. module: account_cash_discount_write_off -#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:67 +#: code:addons/account_cash_discount_write_off/models/account_payment_line.py:0 #, python-format -msgid "You have to fill in journal and account for cash discount write-off on the company." +msgid "" +"You have to fill in journal and account for cash discount write-off on the " +"company." msgstr "" - From 93be82a89ddb3494270b21905ecd4f0014633c30 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 21 Jan 2022 15:13:16 +0000 Subject: [PATCH 19/22] [UPD] README.rst --- account_cash_discount_write_off/README.rst | 11 ++++++----- .../static/description/index.html | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/account_cash_discount_write_off/README.rst b/account_cash_discount_write_off/README.rst index 49cc00584423..de7c44cb5599 100644 --- a/account_cash_discount_write_off/README.rst +++ b/account_cash_discount_write_off/README.rst @@ -14,13 +14,13 @@ Account Cash Discount Write Off :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/13.0/account_cash_discount_write_off + :target: https://github.com/OCA/account-payment/tree/14.0/account_cash_discount_write_off :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-13-0/account-payment-13-0-account_cash_discount_write_off + :target: https://translation.odoo-community.org/projects/account-payment-14-0/account-payment-14-0-account_cash_discount_write_off :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/13.0 + :target: https://runbot.odoo-community.org/runbot/96/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -54,7 +54,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. @@ -71,6 +71,7 @@ Contributors * Benjamin Willig * Christelle De Coninck (ACSONE) +* Helly kapatel Maintainers ~~~~~~~~~~~ @@ -85,6 +86,6 @@ 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. -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_cash_discount_write_off/static/description/index.html b/account_cash_discount_write_off/static/description/index.html index 32f2afc9bbbf..951aa46687ff 100644 --- a/account_cash_discount_write_off/static/description/index.html +++ b/account_cash_discount_write_off/static/description/index.html @@ -3,7 +3,7 @@ - + Account Cash Discount Write Off