diff --git a/account_commission/models/account_move.py b/account_commission/models/account_move.py index 3a6acca71..51e7ff146 100644 --- a/account_commission/models/account_move.py +++ b/account_commission/models/account_move.py @@ -210,7 +210,6 @@ class AccountInvoiceLineAgent(models.Model): ) currency_id = fields.Many2one( related="object_id.currency_id", - readonly=True, ) @api.depends( diff --git a/account_commission/models/commission_settlement.py b/account_commission/models/commission_settlement.py index 9aff08d02..6984def2a 100644 --- a/account_commission/models/commission_settlement.py +++ b/account_commission/models/commission_settlement.py @@ -87,6 +87,7 @@ def _prepare_invoice(self, journal, product, date=False): partner = self._get_invoice_partner() move_form.partner_id = partner move_form.journal_id = journal + move_form.currency_id = self.currency_id for settlement in self: with move_form.invoice_line_ids.new() as line_form: line_form.product_id = product @@ -118,7 +119,7 @@ def _prepare_invoice(self, journal, product, date=False): return vals def _get_invoice_grouping_keys(self): - return ["company_id", "agent_id"] + return ["company_id", "currency_id", "agent_id"] def make_invoices(self, journal, product, date=False, grouped=False): invoice_vals_list = [] diff --git a/account_commission/readme/CONTRIBUTORS.rst b/account_commission/readme/CONTRIBUTORS.rst index 77b751822..35e90bee4 100644 --- a/account_commission/readme/CONTRIBUTORS.rst +++ b/account_commission/readme/CONTRIBUTORS.rst @@ -7,6 +7,7 @@ * Oihane Crucelaegui * Nicola Malcontenti * Aitor Bouzas +* Alexei Rivera * `Tecnativa `__: diff --git a/account_commission/tests/test_account_commission.py b/account_commission/tests/test_account_commission.py index c691e2b64..14ab83f91 100644 --- a/account_commission/tests/test_account_commission.py +++ b/account_commission/tests/test_account_commission.py @@ -53,11 +53,13 @@ def setUpClass(cls): limit=1, ) - def _create_invoice(self, agent, commission, date=None): + def _create_invoice(self, agent, commission, date=None, currency=None): invoice_form = Form( self.env["account.move"].with_context(default_move_type="out_invoice") ) invoice_form.partner_id = self.partner + if currency: + invoice_form.currency_id = currency with invoice_form.invoice_line_ids.new() as line_form: line_form.product_id = self.product if date: @@ -430,3 +432,68 @@ def test_unlink_settlement_invoice(self): self.assertTrue( all(state == "settled" for state in settlements.mapped("state")) ) + + def test_multi_currency(self): + commission = self.commission_net_invoice + agent = self.agent_monthly + today = fields.Date.today() + last_month = today + relativedelta(months=-1) + + # creating invoices with different currencies, same date + invoice = self._create_invoice(agent, commission, today, currency=None) + invoice.action_post() + invoice1 = self._create_invoice(agent, commission, today, self.foreign_currency) + invoice1.action_post() + + # check settlement creation + self._settle_agent_invoice(agent, 1) + settlements = self.settle_model.search( + [ + ("agent_id", "=", agent.id), + ("state", "=", "settled"), + ] + ) + self.assertEqual(2, len(settlements)) + self.assertEqual(2, len(settlements.mapped("currency_id"))) + + # creating some additional invoices + invoice2 = self._create_invoice(agent, commission, today, self.foreign_currency) + invoice2.action_post() + invoice3 = self._create_invoice( + agent, commission, last_month, self.foreign_currency + ) + invoice3.action_post() + invoice4 = self._create_invoice( + agent, commission, last_month, self.foreign_currency + ) + invoice4.action_post() + + # check settlement creation + self._settle_agent_invoice(agent, 1) + settlements = self.settle_model.search( + [ + ("agent_id", "=", agent.id), + ("state", "=", "settled"), + ] + ) + self.assertEqual(3, len(settlements)) + + # check commission invoices + settlements.make_invoices(self.journal, self.commission_product) + invoices = settlements.mapped("invoice_id") + self.assertEqual(3, len(invoices)) + + # check settlement creation after a commission invoicing process + # (previous settlements were already invoiced) + invoice5 = self._create_invoice(agent, commission, today) + invoice5.action_post() + invoice6 = self._create_invoice(agent, commission, today, self.foreign_currency) + invoice6.action_post() + self._settle_agent_invoice(agent, 1) + settlements = self.settle_model.search( + [ + ("agent_id", "=", agent.id), + ("state", "=", "settled"), + ] + ) + self.assertEqual(2, len(settlements)) diff --git a/account_commission/views/account_move_views.xml b/account_commission/views/account_move_views.xml index 712a6da23..b0954ffa2 100644 --- a/account_commission/views/account_move_views.xml +++ b/account_commission/views/account_move_views.xml @@ -10,7 +10,12 @@ name="commission_id" domain="['|', ('settlement_type', '=', 'sale_invoice'), ('settlement_type', '=', False)]" /> - + + diff --git a/commission/README.rst b/commission/README.rst index 09cf05a16..414fd169d 100644 --- a/commission/README.rst +++ b/commission/README.rst @@ -112,8 +112,6 @@ Known issues / Roadmap ====================== * Make it totally multi-company aware. -* Be multi-currency aware for settlements. -* Allow to calculate and pay in other currency different from company one. * Set agent popup window with a kanban view with richer information and mobile friendly. @@ -147,6 +145,7 @@ Contributors * Oihane Crucelaegui * Nicola Malcontenti * Aitor Bouzas +* Alexei Rivera * `Tecnativa `__: diff --git a/commission/readme/CONTRIBUTORS.rst b/commission/readme/CONTRIBUTORS.rst index 77b751822..35e90bee4 100644 --- a/commission/readme/CONTRIBUTORS.rst +++ b/commission/readme/CONTRIBUTORS.rst @@ -7,6 +7,7 @@ * Oihane Crucelaegui * Nicola Malcontenti * Aitor Bouzas +* Alexei Rivera * `Tecnativa `__: diff --git a/commission/readme/ROADMAP.rst b/commission/readme/ROADMAP.rst index 64f69a38f..b4bdd9c35 100644 --- a/commission/readme/ROADMAP.rst +++ b/commission/readme/ROADMAP.rst @@ -1,5 +1,3 @@ * Make it totally multi-company aware. -* Be multi-currency aware for settlements. -* Allow to calculate and pay in other currency different from company one. * Set agent popup window with a kanban view with richer information and mobile friendly. diff --git a/commission/static/description/index.html b/commission/static/description/index.html index 46eca7993..c7a3107de 100644 --- a/commission/static/description/index.html +++ b/commission/static/description/index.html @@ -468,8 +468,6 @@

Usage

Known issues / Roadmap

  • Make it totally multi-company aware.
  • -
  • Be multi-currency aware for settlements.
  • -
  • Allow to calculate and pay in other currency different from company one.
  • Set agent popup window with a kanban view with richer information and mobile friendly.
@@ -502,6 +500,7 @@

Contributors

  • Oihane Crucelaegui <oihanecruce@gmail.com>
  • Nicola Malcontenti <nicola.malcontenti@agilebg.com>
  • Aitor Bouzas <aitor.bouzas@adaptivecity.com>
  • +
  • Alexei Rivera <arivera@archeti.com>
  • Tecnativa:
    • Pedro M. Baeza
    • Manuel Calero
    • diff --git a/commission/tests/test_commission.py b/commission/tests/test_commission.py index e3b573f01..ac169937e 100644 --- a/commission/tests/test_commission.py +++ b/commission/tests/test_commission.py @@ -50,6 +50,21 @@ def setUpClass(cls): } ) cls.company = cls.env.ref("base.main_company") + cls.foreign_currency = cls.env["res.currency"].create( + { + "name": "Coin X", + "rounding": 0.01, + "symbol": "CX", + } + ) + cls.rate = cls.env["res.currency.rate"].create( + { + "company_id": cls.company.id, + "currency_id": cls.foreign_currency.id, + "name": "2023-01-01", + "rate": 25, + } + ) cls.res_partner_model = cls.env["res.partner"] cls.partner = cls.env.ref("base.res_partner_2") cls.partner.write({"agent": False}) diff --git a/commission/views/commission_settlement_views.xml b/commission/views/commission_settlement_views.xml index 93bf3cbb9..8e97bfa2a 100644 --- a/commission/views/commission_settlement_views.xml +++ b/commission/views/commission_settlement_views.xml @@ -10,8 +10,14 @@ - + + @@ -73,7 +79,10 @@ groups="base.group_multi_company" /> - + diff --git a/commission/wizards/commission_make_settle.py b/commission/wizards/commission_make_settle.py index c42d92c56..e3eb8fc6d 100644 --- a/commission/wizards/commission_make_settle.py +++ b/commission/wizards/commission_make_settle.py @@ -2,6 +2,7 @@ # Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from datetime import date, timedelta +from itertools import groupby from dateutil.relativedelta import relativedelta @@ -66,7 +67,7 @@ def _get_next_period_date(self, agent, current_date): elif agent.settlement == "annual": return current_date + relativedelta(years=1) - def _get_settlement(self, agent, company, sett_from, sett_to): + def _get_settlement(self, agent, company, currency, sett_from, sett_to): self.ensure_one() return self.env["commission.settlement"].search( [ @@ -74,6 +75,7 @@ def _get_settlement(self, agent, company, sett_from, sett_to): ("date_from", "=", sett_from), ("date_to", "=", sett_to), ("company_id", "=", company.id), + ("currency_id", "=", currency.id), ("state", "=", "settled"), ("settlement_type", "=", self.settlement_type), ], @@ -99,6 +101,14 @@ def _get_agent_lines(self, date_to_agent): """Need to be extended according to settlement_type.""" raise NotImplementedError() + @api.model + def _agent_lines_groupby(self, agent_line): + return agent_line.company_id, agent_line.currency_id + + @api.model + def _agent_lines_sorted(self, agent_line): + return agent_line.company_id.id, agent_line.currency_id.id + def action_settle(self): self.ensure_one() settlement_obj = self.env["commission.settlement"] @@ -112,15 +122,20 @@ def action_settle(self): for agent in agents: date_to_agent = self._get_period_start(agent, date_to) # Get non settled elements - agent_lines = self._get_agent_lines(agent, date_to_agent) - for company in agent_lines.mapped("company_id"): - agent_lines_company = agent_lines.filtered( - lambda r: r.object_id.company_id == company - ) + grouped_agent_lines = groupby( + sorted( + self._get_agent_lines(agent, date_to_agent), + key=self._agent_lines_sorted, + ), + key=self._agent_lines_groupby, + ) + for _k, grouper_agent_lines in grouped_agent_lines: + agent_lines = list(grouper_agent_lines) pos = 0 sett_to = date(year=1900, month=1, day=1) - while pos < len(agent_lines_company): - line = agent_lines_company[pos] + settlement_line_vals = [] + while pos < len(agent_lines): + line = agent_lines[pos] pos += 1 if line._skip_settlement(): continue @@ -129,19 +144,23 @@ def action_settle(self): sett_to = self._get_next_period_date(agent, sett_from) sett_to -= timedelta(days=1) settlement = self._get_settlement( - agent, company, sett_from, sett_to + agent, line.company_id, line.currency_id, sett_from, sett_to ) if not settlement: settlement = settlement_obj.create( self._prepare_settlement_vals( - agent, company, sett_from, sett_to + agent, + line.company_id, + sett_from, + sett_to, ) ) + settlement.currency_id = line.currency_id settlement_ids.append(settlement.id) - # TODO: Do creates in batch - settlement_line_obj.create( + settlement_line_vals.append( self._prepare_settlement_line_vals(settlement, line) ) + settlement_line_obj.create(settlement_line_vals) # go to results if len(settlement_ids): return {