From a3b8eb539e158b1cef82c523074de312d7e05382 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 18 Dec 2024 17:34:53 +0100 Subject: [PATCH] [MIG] sale_commission_partial_settlement: Migration to 16.0 --- sale_commission_partial_settlement/README.rst | 10 +- .../__manifest__.py | 4 +- sale_commission_partial_settlement/i18n/es.po | 69 +++--- .../migrations/14.0.1.0.1/post-migrate.py | 11 - .../models/__init__.py | 8 +- .../models/account_invoice_line_agent.py | 109 +++++++++ .../account_invoice_line_agent_partial.py | 23 ++ .../models/account_move.py | 113 ---------- .../models/account_partial_reconcile.py | 21 +- .../{sale_commission.py => commission.py} | 4 +- .../models/commission_settlement.py | 9 + ...ement.py => commission_settlement_line.py} | 10 +- .../static/description/index.html | 6 +- .../tests/common.py | 183 +++++++++++++++ .../tests/test_partial_settlement.py | 208 +----------------- ...ommission_view.xml => commission_view.xml} | 8 +- .../wizard/__init__.py | 2 +- ...rd_settle.py => commission_make_settle.py} | 41 ++-- .../models/sale.py | 2 +- .../addons/sale_commission_partial_settlement | 1 + .../setup.py | 6 + 21 files changed, 431 insertions(+), 417 deletions(-) delete mode 100644 sale_commission_partial_settlement/migrations/14.0.1.0.1/post-migrate.py create mode 100644 sale_commission_partial_settlement/models/account_invoice_line_agent.py create mode 100644 sale_commission_partial_settlement/models/account_invoice_line_agent_partial.py delete mode 100644 sale_commission_partial_settlement/models/account_move.py rename sale_commission_partial_settlement/models/{sale_commission.py => commission.py} (81%) create mode 100644 sale_commission_partial_settlement/models/commission_settlement.py rename sale_commission_partial_settlement/models/{settlement.py => commission_settlement_line.py} (72%) create mode 100644 sale_commission_partial_settlement/tests/common.py rename sale_commission_partial_settlement/views/{sale_commission_view.xml => commission_view.xml} (56%) rename sale_commission_partial_settlement/wizard/{wizard_settle.py => commission_make_settle.py} (76%) create mode 120000 setup/sale_commission_partial_settlement/odoo/addons/sale_commission_partial_settlement create mode 100644 setup/sale_commission_partial_settlement/setup.py diff --git a/sale_commission_partial_settlement/README.rst b/sale_commission_partial_settlement/README.rst index 984415fd0..4cd76a036 100644 --- a/sale_commission_partial_settlement/README.rst +++ b/sale_commission_partial_settlement/README.rst @@ -17,13 +17,13 @@ Sales commissions based on paid amount :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcommission-lightgray.png?logo=github - :target: https://github.com/OCA/commission/tree/14.0/sale_commission_partial_settlement + :target: https://github.com/OCA/commission/tree/16.0/sale_commission_partial_settlement :alt: OCA/commission .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/commission-14-0/commission-14-0-sale_commission_partial_settlement + :target: https://translation.odoo-community.org/projects/commission-16-0/commission-16-0-sale_commission_partial_settlement :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/commission&target_branch=14.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/commission&target_branch=16.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -50,7 +50,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -105,6 +105,6 @@ Current `maintainers `__: |maintainer-aleuffre| |maintainer-renda-dev| |maintainer-PicchiSeba| -This module is part of the `OCA/commission `_ project on GitHub. +This module is part of the `OCA/commission `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_commission_partial_settlement/__manifest__.py b/sale_commission_partial_settlement/__manifest__.py index 1b98f3e68..019f8ea1e 100644 --- a/sale_commission_partial_settlement/__manifest__.py +++ b/sale_commission_partial_settlement/__manifest__.py @@ -1,7 +1,7 @@ # Copyright 2023 Nextev { "name": "Sales commissions based on paid amount", - "version": "14.0.1.0.1", + "version": "16.0.1.0.0", "author": "Nextev Srl," "Ooops," "Odoo Community Association (OCA)", "maintainers": ["aleuffre", "renda-dev", "PicchiSeba"], "category": "Sales Management", @@ -10,7 +10,7 @@ "website": "https://github.com/OCA/commission", "data": [ "security/ir.model.access.csv", - "views/sale_commission_view.xml", + "views/commission_view.xml", ], "installable": True, } diff --git a/sale_commission_partial_settlement/i18n/es.po b/sale_commission_partial_settlement/i18n/es.po index d260ab6af..f97d4bd96 100644 --- a/sale_commission_partial_settlement/i18n/es.po +++ b/sale_commission_partial_settlement/i18n/es.po @@ -4,17 +4,16 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-12-13 15:35+0000\n" -"Last-Translator: Ivorra78 \n" -"Language-Team: none\n" -"Language: es\n" +"POT-Creation-Date: 2024-09-13 07:50+0000\n" +"PO-Revision-Date: 2024-09-13 07:50+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: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.17\n" +"Plural-Forms: \n" #. module: sale_commission_partial_settlement #: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent_partial__agent_line @@ -22,27 +21,28 @@ msgid "Agent Line" msgstr "Línea de Agente" #. module: sale_commission_partial_settlement -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_settlement_line__agent_line_partial_ids +#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_commission_settlement_line__agent_line_partial_ids msgid "Agent Line Partial" -msgstr "Agente Línea Parcial" +msgstr "Línea de Agente Parcial" #. module: sale_commission_partial_settlement #: model:ir.model,name:sale_commission_partial_settlement.model_account_invoice_line_agent msgid "Agent detail of commission line in invoice lines" msgstr "Detalle de agente de línea de comisión en líneas de pedido" +#. module: sale_commission_partial_settlement +#: model:ir.model,name:sale_commission_partial_settlement.model_commission +msgid "Commission" +msgstr "Comisión" + #. module: sale_commission_partial_settlement #: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent_partial__amount msgid "Commission Amount" msgstr "Importe de la Comisión" #. module: sale_commission_partial_settlement -#: model:ir.model,name:sale_commission_partial_settlement.model_sale_commission -msgid "Commission in sales" -msgstr "Comisión en ventas" - -#. module: sale_commission_partial_settlement -#: code:addons/sale_commission_partial_settlement/wizard/wizard_settle.py:0 +#. odoo-python +#: code:addons/sale_commission_partial_settlement/wizard/commission_make_settle.py:0 #, python-format msgid "Created Settlements" msgstr "Liquidaciones Creadas" @@ -63,29 +63,19 @@ msgid "Currency" msgstr "Divisa" #. module: sale_commission_partial_settlement -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent__display_name #: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent_partial__display_name -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_partial_reconcile__display_name -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission__display_name -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_make_settle__display_name -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_settlement_line__display_name msgid "Display Name" msgstr "Nombre a Mostrar" #. module: sale_commission_partial_settlement -#: model:ir.model.fields.selection,name:sale_commission_partial_settlement.selection__sale_commission__payment_amount_type__full +#: model:ir.model.fields.selection,name:sale_commission_partial_settlement.selection__commission__payment_amount_type__full msgid "Full amount" msgstr "Importe total" #. module: sale_commission_partial_settlement -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent__id #: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent_partial__id -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_partial_reconcile__id -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission__id -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_make_settle__id -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_settlement_line__id msgid "ID" -msgstr "ID" +msgstr "" #. module: sale_commission_partial_settlement #: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent_partial__invoice_line_agent_id @@ -93,12 +83,7 @@ msgid "Invoice Line Agent" msgstr "Agente de Línea de Facturación" #. module: sale_commission_partial_settlement -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent____last_update #: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_invoice_line_agent_partial____last_update -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_account_partial_reconcile____last_update -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission____last_update -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_make_settle____last_update -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_settlement_line____last_update msgid "Last Modified on" msgstr "Última Modificación el" @@ -113,12 +98,12 @@ msgid "Last Updated on" msgstr "Última Actualización el" #. module: sale_commission_partial_settlement -#: model:ir.model,name:sale_commission_partial_settlement.model_sale_commission_settlement_line +#: model:ir.model,name:sale_commission_partial_settlement.model_commission_settlement_line msgid "Line of a commission settlement" -msgstr "Línea de liquidación de comisión" +msgstr "Línea de liquidación de una comisión" #. module: sale_commission_partial_settlement -#: model:ir.model.fields.selection,name:sale_commission_partial_settlement.selection__sale_commission__payment_amount_type__paid +#: model:ir.model.fields.selection,name:sale_commission_partial_settlement.selection__commission__payment_amount_type__paid msgid "Paid amount" msgstr "Importe pagado" @@ -135,7 +120,7 @@ msgstr "Comisión Parcial Liquidada" #. module: sale_commission_partial_settlement #: model:ir.model,name:sale_commission_partial_settlement.model_account_partial_reconcile msgid "Partial Reconcile" -msgstr "Conciliación Parcial" +msgstr "Conciliación parcial" #. module: sale_commission_partial_settlement #: model:ir.model,name:sale_commission_partial_settlement.model_account_invoice_line_agent_partial @@ -143,7 +128,7 @@ msgid "Partial agent commissions" msgstr "Comisiones parciales de agente" #. module: sale_commission_partial_settlement -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission__payment_amount_type +#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_commission__payment_amount_type msgid "Payment amount type" msgstr "Tipo de importe del pago" @@ -153,11 +138,11 @@ msgid "Settled" msgstr "Liquidado" #. module: sale_commission_partial_settlement -#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_sale_commission_settlement_line__settled_amount +#: model:ir.model.fields,field_description:sale_commission_partial_settlement.field_commission_settlement_line__settled_amount msgid "Settled Amount" -msgstr "Importe Liquidado" +msgstr "Cantidad Liquidada" #. module: sale_commission_partial_settlement -#: model:ir.model,name:sale_commission_partial_settlement.model_sale_commission_make_settle -msgid "Wizard for settling commissions in invoices" -msgstr "Asistente para liquidar comisiones en facturas" +#: model:ir.model,name:sale_commission_partial_settlement.model_commission_make_settle +msgid "Wizard for settling commissions" +msgstr "Asistente para liquidación de comisiones" \ No newline at end of file diff --git a/sale_commission_partial_settlement/migrations/14.0.1.0.1/post-migrate.py b/sale_commission_partial_settlement/migrations/14.0.1.0.1/post-migrate.py deleted file mode 100644 index 626eae3f9..000000000 --- a/sale_commission_partial_settlement/migrations/14.0.1.0.1/post-migrate.py +++ /dev/null @@ -1,11 +0,0 @@ -from openupgradelib import openupgrade - - -@openupgrade.migrate() -def migrate(env, version): - env["account.invoice.line.agent"].search( - [ - ("settled", "=", True), - ("commission_id.payment_amount_type", "=", "paid"), - ] - )._compute_settled() diff --git a/sale_commission_partial_settlement/models/__init__.py b/sale_commission_partial_settlement/models/__init__.py index 4e17db438..c782fe739 100644 --- a/sale_commission_partial_settlement/models/__init__.py +++ b/sale_commission_partial_settlement/models/__init__.py @@ -1,4 +1,6 @@ -from . import sale_commission -from . import account_move +from . import commission +from . import account_invoice_line_agent +from . import account_invoice_line_agent_partial from . import account_partial_reconcile -from . import settlement +from . import commission_settlement +from . import commission_settlement_line diff --git a/sale_commission_partial_settlement/models/account_invoice_line_agent.py b/sale_commission_partial_settlement/models/account_invoice_line_agent.py new file mode 100644 index 000000000..4c17e0481 --- /dev/null +++ b/sale_commission_partial_settlement/models/account_invoice_line_agent.py @@ -0,0 +1,109 @@ +# Copyright 2023 Nextev +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.tools.float_utils import float_compare + + +class AccountInvoiceLineAgent(models.Model): + _inherit = "account.invoice.line.agent" + + partial_settled = fields.Monetary( + string="Partial Commission Amount Settled", + compute="_compute_partial_settled", + store=True, + ) + is_fully_settled = fields.Boolean(compute="_compute_is_fully_settled", store=True) + invoice_line_agent_partial_ids = fields.One2many( + "account.invoice.line.agent.partial", "invoice_line_agent_id" + ) + + @api.depends( + "invoice_line_agent_partial_ids.amount", + "invoice_line_agent_partial_ids.agent_line.settlement_id.state", + ) + def _compute_partial_settled(self): + for rec in self: + rec.partial_settled = sum( + ailap.amount + for ailap in rec.invoice_line_agent_partial_ids + if ailap.mapped("agent_line.settlement_id")[:1].state != "cancel" + ) + + @api.depends( + "commission_id.payment_amount_type", "amount", "settled", "partial_settled" + ) + def _compute_is_fully_settled(self): + for rec in self: + if rec.commission_id.payment_amount_type != "paid": + rec.is_fully_settled = rec.settled + else: + rec.is_fully_settled = rec.settled and ( + float_compare( + rec.partial_settled, + rec.amount, + precision_rounding=rec.currency_id.rounding, + ) + == 0 + ) + + def _partial_commissions(self, date_payment_to): + """ + This method iterates through agent invoice lines and calculates + partial commissions based on the payment amount. + If the partial payment amount is greater than the invoice line + amount, it fully settles the corresponding agent line. + Otherwise, it calculates the partial commission proportionally to + the amount paid, invoice amount and total commissions. + """ + partial_lines_to_settle = [] + partial_payment_remaining = {} + for line in self: + line_total_amount = line.amount + reconciled_partials, _ = line.invoice_id._get_reconciled_invoices_partials() + for ( + partial, + amount, + counterpart_line, + ) in reconciled_partials: + if partial.partial_commission_settled: + continue + elif date_payment_to and date_payment_to < counterpart_line.date: + break + if partial.id in partial_payment_remaining: + payment_amount = partial_payment_remaining[partial.id][ + "remaining_amount" + ] + else: + payment_amount = amount + partial_payment_remaining[partial.id] = {"remaining_amount": amount} + if line.object_id.price_total <= payment_amount: + partial_lines_to_settle.append( + self._partial_agent_line_values( + line, line_total_amount, partial + ) + ) + partial_payment_remaining[partial.id] = { + "remaining_amount": amount - line.object_id.price_total + } + break + + paid_in_proportion = payment_amount / line.invoice_id.amount_total + partial_commission = ( + line.invoice_id.commission_total * paid_in_proportion + ) + partial_lines_to_settle.append( + self._partial_agent_line_values(line, partial_commission, partial) + ) + partial_agent_lines = self.env["account.invoice.line.agent.partial"].create( + partial_lines_to_settle + ) + return partial_agent_lines + + def _partial_agent_line_values(self, line, amount, partial): + return { + "invoice_line_agent_id": line.id, + "currency_id": line.currency_id.id, + "amount": amount, + "account_partial_reconcile_id": partial.id, + } diff --git a/sale_commission_partial_settlement/models/account_invoice_line_agent_partial.py b/sale_commission_partial_settlement/models/account_invoice_line_agent_partial.py new file mode 100644 index 000000000..7e4ff420a --- /dev/null +++ b/sale_commission_partial_settlement/models/account_invoice_line_agent_partial.py @@ -0,0 +1,23 @@ +from odoo import fields, models + + +class AccountInvoiceLineAgentPartial(models.Model): + _name = "account.invoice.line.agent.partial" + _description = "Partial agent commissions" + + invoice_line_agent_id = fields.Many2one("account.invoice.line.agent", required=True) + agent_line = fields.Many2many( + comodel_name="commission.settlement.line", + relation="settlement_agent_line_partial_rel", + column1="agent_line_partial_id", + column2="settlement_id", + copy=False, + ) + account_partial_reconcile_id = fields.Many2one("account.partial.reconcile") + amount = fields.Monetary( + string="Commission Amount", + ) + currency_id = fields.Many2one( + related="invoice_line_agent_id.currency_id", + ) + settled = fields.Boolean() diff --git a/sale_commission_partial_settlement/models/account_move.py b/sale_commission_partial_settlement/models/account_move.py deleted file mode 100644 index a402c5ed3..000000000 --- a/sale_commission_partial_settlement/models/account_move.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2023 Nextev -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - -from odoo import fields, models - - -class AccountInvoiceLineAgent(models.Model): - _inherit = "account.invoice.line.agent" - - partial_settled = fields.Monetary(string="Partial Commission Amount Settled") - - def _compute_settled(self): - filtered_lines = self.filtered( - lambda x: x.commission_id.payment_amount_type != "paid" - ) - for line in self - filtered_lines: - if not line.mapped("agent_line.settlement_id"): - line.settled = False - - super(AccountInvoiceLineAgent, filtered_lines)._compute_settled() - - def _partial_commissions(self, date_payment_to): - """ - This method iterates through agent invoice lines and calculates - partial commissions based on the payment amount. - If the partial payment amount is greater than the invoice line - amount, it fully settles the corresponding agent line. - Otherwise, it calculates the partial commission proportionally to - the amount paid, invoice amount and total commissions. - """ - partial_lines_to_settle = [] - partial_payment_remaining = {} - lines_to_update = {} - for line in self: - line_total_amount = line.amount - for ( - partial, - amount, - counterpart_line, - ) in line.invoice_id._get_reconciled_invoices_partials(): - if partial.partial_commission_settled: - continue - elif date_payment_to and date_payment_to < counterpart_line.date: - break - if partial.id in partial_payment_remaining: - payment_amount = partial_payment_remaining[partial.id][ - "remaining_amount" - ] - else: - payment_amount = amount - partial_payment_remaining[partial.id] = {"remaining_amount": amount} - if line.object_id.price_total <= payment_amount: - partial_lines_to_settle.append( - { - "invoice_line_agent_id": line.id, - "currency_id": line.currency_id.id, - "amount": line_total_amount, - } - ) - lines_to_update[line.id] = { - "partial_settled": line_total_amount, - "settled": True, - } - partial_payment_remaining[partial.id] = { - "remaining_amount": amount - line.object_id.price_total - } - break - - paid_in_proportion = payment_amount / line.invoice_id.amount_total - partial_commission = ( - line.invoice_id.commission_total * paid_in_proportion - ) - partial_lines_to_settle.append( - { - "invoice_line_agent_id": line.id, - "currency_id": line.currency_id.id, - "amount": partial_commission, - } - ) - if line.id in lines_to_update: - lines_to_update[line.id]["partial_settled"] += partial_commission - else: - lines_to_update[line.id] = {"partial_settled": partial_commission} - - if lines_to_update[line.id]["partial_settled"] >= line_total_amount: - lines_to_update[line.id].update({"settled": True}) - break - partial.partial_commission_settled = True - partial_agent_lines = self.env["account.invoice.line.agent.partial"].create( - partial_lines_to_settle - ) - return partial_agent_lines, lines_to_update - - -class AccountInvoiceLineAgentPartial(models.Model): - _name = "account.invoice.line.agent.partial" - _description = "Partial agent commissions" - - invoice_line_agent_id = fields.Many2one("account.invoice.line.agent", required=True) - agent_line = fields.Many2many( - comodel_name="sale.commission.settlement.line", - relation="settlement_agent_line_partial_rel", - column1="agent_line_partial_id", - column2="settlement_id", - copy=False, - ) - amount = fields.Monetary( - string="Commission Amount", - ) - currency_id = fields.Many2one( - related="invoice_line_agent_id.currency_id", - ) - settled = fields.Boolean() diff --git a/sale_commission_partial_settlement/models/account_partial_reconcile.py b/sale_commission_partial_settlement/models/account_partial_reconcile.py index 7c1714d4d..a97dee0bc 100644 --- a/sale_commission_partial_settlement/models/account_partial_reconcile.py +++ b/sale_commission_partial_settlement/models/account_partial_reconcile.py @@ -1,7 +1,24 @@ -from odoo import fields, models +from odoo import api, fields, models class AccountPartialReconcile(models.Model): _inherit = "account.partial.reconcile" - partial_commission_settled = fields.Boolean() + account_invoice_line_agent_partial_ids = fields.One2many( + "account.invoice.line.agent.partial", "account_partial_reconcile_id" + ) + partial_commission_settled = fields.Boolean( + compute="_compute_partial_commission_settled", store=True + ) + + @api.depends( + "account_invoice_line_agent_partial_ids", + "account_invoice_line_agent_partial_ids.agent_line.settlement_id.state", + ) + def _compute_partial_commission_settled(self): + for rec in self: + rec.partial_commission_settled = bool( + rec.account_invoice_line_agent_partial_ids.filtered( + lambda x: x.mapped("agent_line.settlement_id")[:1].state != "cancel" + ) + ) diff --git a/sale_commission_partial_settlement/models/sale_commission.py b/sale_commission_partial_settlement/models/commission.py similarity index 81% rename from sale_commission_partial_settlement/models/sale_commission.py rename to sale_commission_partial_settlement/models/commission.py index 68f03aea9..dcb090762 100644 --- a/sale_commission_partial_settlement/models/sale_commission.py +++ b/sale_commission_partial_settlement/models/commission.py @@ -3,8 +3,8 @@ from odoo import fields, models -class SaleCommission(models.Model): - _inherit = "sale.commission" +class Commission(models.Model): + _inherit = "commission" payment_amount_type = fields.Selection( [("full", "Full amount"), ("paid", "Paid amount")], diff --git a/sale_commission_partial_settlement/models/commission_settlement.py b/sale_commission_partial_settlement/models/commission_settlement.py new file mode 100644 index 000000000..263c7744f --- /dev/null +++ b/sale_commission_partial_settlement/models/commission_settlement.py @@ -0,0 +1,9 @@ +from odoo import models + + +class CommissionSettlement(models.Model): + _inherit = "commission.settlement" + + def unlink(self): + self.mapped("line_ids.agent_line_partial_ids").unlink() + return super().unlink() diff --git a/sale_commission_partial_settlement/models/settlement.py b/sale_commission_partial_settlement/models/commission_settlement_line.py similarity index 72% rename from sale_commission_partial_settlement/models/settlement.py rename to sale_commission_partial_settlement/models/commission_settlement_line.py index f25ba11e0..f916565ab 100644 --- a/sale_commission_partial_settlement/models/settlement.py +++ b/sale_commission_partial_settlement/models/commission_settlement_line.py @@ -1,8 +1,8 @@ from odoo import api, fields, models -class SettlementLine(models.Model): - _inherit = "sale.commission.settlement.line" +class CommissionSettlementLine(models.Model): + _inherit = "commission.settlement.line" agent_line_partial_ids = fields.Many2many( comodel_name="account.invoice.line.agent.partial", @@ -23,4 +23,8 @@ def _compute_settled_amount(self): if rec.commission_id.payment_amount_type == "paid": rec.settled_amount = rec.agent_line_partial_ids[:1].amount else: - rec.settled_amount = rec.agent_line[:1].amount + rec.settled_amount = rec.invoice_agent_line_id[:1].amount + + def unlink(self): + self.mapped("agent_line_partial_ids").unlink() + return super().unlink() diff --git a/sale_commission_partial_settlement/static/description/index.html b/sale_commission_partial_settlement/static/description/index.html index 6bf4cbe3b..2b9e0dc17 100644 --- a/sale_commission_partial_settlement/static/description/index.html +++ b/sale_commission_partial_settlement/static/description/index.html @@ -369,7 +369,7 @@

Sales commissions based on paid amount

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:72b8b9ff4225524c4105f059588ec2038649d39259909c6d43d8e7c4b62b06a2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

This module allows to settle commissions based on paid amount.

Table of contents

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

+feedback.

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

@@ -447,7 +447,7 @@

Maintainers

promote its widespread use.

Current maintainers:

aleuffre renda-dev PicchiSeba

-

This module is part of the OCA/commission project on GitHub.

+

This module is part of the OCA/commission project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/sale_commission_partial_settlement/tests/common.py b/sale_commission_partial_settlement/tests/common.py new file mode 100644 index 000000000..374984a01 --- /dev/null +++ b/sale_commission_partial_settlement/tests/common.py @@ -0,0 +1,183 @@ +from dateutil.relativedelta import relativedelta + +from odoo import fields +from odoo.tests.common import TransactionCase + + +class TestPartialSettlementCommon(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.commission_model = cls.env["commission"] + cls.partial_commission_net_paid = cls.commission_model.create( + { + "name": "20% fixed commission (Net amount) - Payment Based - Partial", + "fix_qty": 20.0, + "invoice_state": "paid", + "amount_base_type": "net_amount", + "payment_amount_type": "paid", + } + ) + cls.company = cls.env.ref("base.main_company") + cls.res_partner_model = cls.env["res.partner"] + cls.partner = cls.env.ref("base.res_partner_2") + cls.partner.write({"agent": False}) + cls.sale_order_model = cls.env["sale.order"] + cls.advance_inv_model = cls.env["sale.advance.payment.inv"] + cls.settle_model = cls.env["commission.settlement"] + cls.make_settle_model = cls.env["commission.make.settle"] + cls.make_inv_model = cls.env["commission.make.invoice"] + cls.product = cls.env.ref("product.product_product_5") + cls.product.list_price = 5 # for testing specific commission section + cls.commission_product = cls.env["product.product"].create( + {"name": "Commission test product", "type": "service"} + ) + cls.product.write({"invoice_policy": "order"}) + cls.journal = cls.env["account.journal"].search( + [("type", "=", "purchase")], limit=1 + ) + cls.agent_monthly = cls.res_partner_model.create( + { + "name": "Test Agent - Monthly", + "agent": True, + "settlement": "monthly", + "lang": "en_US", + "commission_id": cls.partial_commission_net_paid.id, + } + ) + cls.income_account = cls.env["account.account"].search( + [ + ("company_id", "=", cls.company.id), + ("account_type", "=", "income"), + ], + limit=1, + ) + cls.commission_net_invoice = cls.commission_model.create( + { + "name": "10% fixed commission (Net amount) - Invoice Based", + "fix_qty": 10.0, + "amount_base_type": "net_amount", + } + ) + cls.agent_biweekly = cls.res_partner_model.create( + { + "name": "Test Agent - Bi-weekly", + "agent": True, + "settlement": "biweekly", + "lang": "en_US", + "commission_id": cls.commission_net_invoice.id, + } + ) + + def _create_multi_line_sale_order(self, agent, commission): + return self.sale_order_model.create( + { + "partner_id": self.partner.id, + "order_line": [ + ( + 0, + 0, + { + "name": self.product.name, + "product_id": self.product.id, + "product_uom_qty": 1.0, + "product_uom": self.ref("uom.product_uom_unit"), + "price_unit": self.product.lst_price, + "agent_ids": [ + ( + 0, + 0, + { + "agent_id": agent.id, + "commission_id": commission.id, + }, + ) + ], + }, + ), + ( + 0, + 0, + { + "name": self.product.name, + "product_id": self.product.id, + "product_uom_qty": 5.0, + "product_uom": self.ref("uom.product_uom_unit"), + "price_unit": self.product.lst_price, + "agent_ids": [ + ( + 0, + 0, + { + "agent_id": self.agent_monthly.id, + "commission_id": self.partial_commission_net_paid.id, + }, + ) + ], + }, + ), + ], + } + ) + + def _invoice_sale_order(self, sale_order): + old_invoices = sale_order.invoice_ids + wizard = self.advance_inv_model.create( + {"advance_payment_method": "delivered", "sale_order_ids": [sale_order.id]} + ) + wizard.with_context( + **{ + "active_model": "sale.order", + "active_ids": [sale_order.id], + "active_id": sale_order.id, + } + ).create_invoices() + invoice = sale_order.invoice_ids - old_invoices + return invoice + + def _settle_agent(self, agent=None, period=None, date=None): + vals = { + "date_to": ( + ( + fields.Datetime.from_string(fields.Datetime.now()) + + relativedelta(months=period) + ) + if period + else date + ), + "settlement_type": "sale_invoice", + } + if agent: + vals["agent_ids"] = [(4, agent.id)] + wizard = self.make_settle_model.create(vals) + wizard.action_settle() + + def register_payment( + self, + invoice, + payment_date, + amount=None, + payment_difference_handling="reconcile", + ): + payment_model = self.env["account.payment.register"] + invoice.action_post() + if not amount: + amount = invoice.amount_total + ctx = { + "active_model": "account.move", + "active_ids": [invoice.id], + } + return ( + payment_model.with_context(**ctx) + .create( + { + "payment_date": payment_date, + "amount": amount, + "journal_id": self.env["account.journal"] + .search([("type", "=", "bank")], limit=1) + .id, + "payment_difference_handling": payment_difference_handling, + } + ) + .action_create_payments() + ) diff --git a/sale_commission_partial_settlement/tests/test_partial_settlement.py b/sale_commission_partial_settlement/tests/test_partial_settlement.py index 66ba38ea4..54fa1448b 100644 --- a/sale_commission_partial_settlement/tests/test_partial_settlement.py +++ b/sale_commission_partial_settlement/tests/test_partial_settlement.py @@ -6,187 +6,11 @@ from dateutil.relativedelta import relativedelta from odoo import fields -from odoo.tests.common import SavepointCase +from .common import TestPartialSettlementCommon -class TestPartialSettlement(SavepointCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.commission_model = cls.env["sale.commission"] - cls.partial_commission_net_paid = cls.commission_model.create( - { - "name": "20% fixed commission (Net amount) - Payment Based - Partial", - "fix_qty": 20.0, - "invoice_state": "paid", - "amount_base_type": "net_amount", - "payment_amount_type": "paid", - } - ) - cls.company = cls.env.ref("base.main_company") - cls.res_partner_model = cls.env["res.partner"] - cls.partner = cls.env.ref("base.res_partner_2") - cls.partner.write({"agent": False}) - cls.sale_order_model = cls.env["sale.order"] - cls.advance_inv_model = cls.env["sale.advance.payment.inv"] - cls.settle_model = cls.env["sale.commission.settlement"] - cls.make_settle_model = cls.env["sale.commission.make.settle"] - cls.make_inv_model = cls.env["sale.commission.make.invoice"] - cls.product = cls.env.ref("product.product_product_5") - cls.product.list_price = 5 # for testing specific commission section - cls.commission_product = cls.env["product.product"].create( - {"name": "Commission test product", "type": "service"} - ) - cls.product.write({"invoice_policy": "order"}) - cls.journal = cls.env["account.journal"].search( - [("type", "=", "purchase")], limit=1 - ) - cls.agent_monthly = cls.res_partner_model.create( - { - "name": "Test Agent - Monthly", - "agent": True, - "settlement": "monthly", - "lang": "en_US", - "commission_id": cls.partial_commission_net_paid.id, - } - ) - cls.income_account = cls.env["account.account"].search( - [ - ("company_id", "=", cls.company.id), - ("user_type_id.name", "=", "Income"), - ], - limit=1, - ) - cls.commission_net_invoice = cls.commission_model.create( - { - "name": "10% fixed commission (Net amount) - Invoice Based", - "fix_qty": 10.0, - "amount_base_type": "net_amount", - } - ) - cls.agent_biweekly = cls.res_partner_model.create( - { - "name": "Test Agent - Bi-weekly", - "agent": True, - "settlement": "biweekly", - "lang": "en_US", - "commission_id": cls.commission_net_invoice.id, - } - ) - - def _create_multi_line_sale_order(self, agent, commission): - return self.sale_order_model.create( - { - "partner_id": self.partner.id, - "order_line": [ - ( - 0, - 0, - { - "name": self.product.name, - "product_id": self.product.id, - "product_uom_qty": 1.0, - "product_uom": self.ref("uom.product_uom_unit"), - "price_unit": self.product.lst_price, - "agent_ids": [ - ( - 0, - 0, - { - "agent_id": agent.id, - "commission_id": commission.id, - }, - ) - ], - }, - ), - ( - 0, - 0, - { - "name": self.product.name, - "product_id": self.product.id, - "product_uom_qty": 5.0, - "product_uom": self.ref("uom.product_uom_unit"), - "price_unit": self.product.lst_price, - "agent_ids": [ - ( - 0, - 0, - { - "agent_id": self.agent_monthly.id, - "commission_id": self.partial_commission_net_paid.id, - }, - ) - ], - }, - ), - ], - } - ) - - def _invoice_sale_order(self, sale_order, date=None): - old_invoices = sale_order.invoice_ids - wizard = self.advance_inv_model.create({"advance_payment_method": "delivered"}) - wizard.with_context( - { - "active_model": "sale.order", - "active_ids": [sale_order.id], - "active_id": sale_order.id, - } - ).create_invoices() - invoice = sale_order.invoice_ids - old_invoices - invoice.flush() - return invoice - - def _settle_agent(self, agent=None, period=None, date=None, date_payment_to=None): - vals = { - "date_to": ( - fields.Datetime.from_string(fields.Datetime.now()) - + relativedelta(months=period) - ) - if period - else date, - "date_payment_to": date_payment_to, - } - if agent: - vals["agent_ids"] = [(4, agent.id)] - wizard = self.make_settle_model.create(vals) - wizard.action_settle() - - def register_payment( - self, - invoice, - payment_date, - amount=None, - payment_difference_handling="reconcile", - ): - payment_model = self.env["account.payment.register"] - invoice.action_post() - if not amount: - amount = invoice.amount_total - ctx = { - "active_model": "account.move", - "active_ids": [invoice.id], - } - return ( - payment_model.with_context(ctx) - .create( - { - "payment_date": payment_date, - "amount": amount, - "journal_id": self.env["account.journal"] - .search([("type", "=", "bank")], limit=1) - .id, - "payment_method_id": self.env.ref( - "account.account_payment_method_manual_out" - ).id, - "payment_difference_handling": payment_difference_handling, - } - ) - .action_create_payments() - ) +class TestPartialSettlement(TestPartialSettlementCommon): def test_partial_payment_amount_settlement(self): sale_order = self._create_multi_line_sale_order( self.agent_monthly, self.partial_commission_net_paid @@ -202,8 +26,8 @@ def test_partial_payment_amount_settlement(self): payment_difference_handling="open", ) self.assertTrue(invoice._get_reconciled_invoices_partials()) - self._settle_agent(self.agent_monthly, 1, date_payment_to=datetime.now()) - settlements = self.env["sale.commission.settlement"].search( + self._settle_agent(self.agent_monthly, 1, datetime.now()) + settlements = self.env["commission.settlement"].search( [ ( "agent_id", @@ -217,30 +41,6 @@ def test_partial_payment_amount_settlement(self): self.assertEqual(2, len(settlements.line_ids)) self.assertEqual(2, len(invoice.line_ids.agent_ids)) - def test_skip_partial_future_payment(self): - sale_order = self._create_multi_line_sale_order( - self.agent_monthly, self.partial_commission_net_paid - ) - sale_order.action_confirm() - date = fields.Date.today() - invoice = self._invoice_sale_order(sale_order) - self.register_payment( - invoice, - date + relativedelta(days=2), - ) - self._settle_agent(self.agent_monthly, 1, date_payment_to=datetime.now()) - settlements = self.env["sale.commission.settlement"].search( - [ - ( - "agent_id", - "=", - self.agent_monthly.id, - ), - ("state", "=", "settled"), - ] - ) - self.assertEqual(0, len(settlements)) - def test_multi_agents_settlement(self): agent_net = self.agent_biweekly commission_net = self.commission_net_invoice diff --git a/sale_commission_partial_settlement/views/sale_commission_view.xml b/sale_commission_partial_settlement/views/commission_view.xml similarity index 56% rename from sale_commission_partial_settlement/views/sale_commission_view.xml rename to sale_commission_partial_settlement/views/commission_view.xml index b82c7b9d1..9dc52314f 100644 --- a/sale_commission_partial_settlement/views/sale_commission_view.xml +++ b/sale_commission_partial_settlement/views/commission_view.xml @@ -1,9 +1,9 @@ - - sale.commission.payment.amount.form - sale.commission - + + commission.partial.settlement.form.view + commission +