Skip to content

Commit

Permalink
[IMP] account_commission: multi-currency support
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeirivera87 authored and jguenat committed Nov 24, 2023
1 parent c25ef03 commit 5defedd
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 29 deletions.
1 change: 1 addition & 0 deletions account_commission/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ class AccountInvoiceLineAgent(models.Model):
currency_id = fields.Many2one(
related="object_id.currency_id",
readonly=True,
store=True,
)

@api.depends(
Expand Down
7 changes: 6 additions & 1 deletion account_commission/models/commission_settlement.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,20 @@ def action_invoice(self):
def _get_invoice_partner(self):
return self[0].agent_id

def _get_invoice_currency(self):
return self[0].currency_id

def _prepare_invoice(self, journal, product, date=False):
move_form = Form(
self.env["account.move"].with_context(default_move_type="in_invoice")
)
if date:
move_form.invoice_date = date
partner = self._get_invoice_partner()
currency = self._get_invoice_currency()
move_form.partner_id = partner
move_form.journal_id = journal
move_form.currency_id = currency
for settlement in self:
with move_form.invoice_line_ids.new() as line_form:
line_form.product_id = product
Expand Down Expand Up @@ -118,7 +123,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 = []
Expand Down
1 change: 1 addition & 0 deletions account_commission/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Oihane Crucelaegui <[email protected]>
* Nicola Malcontenti <[email protected]>
* Aitor Bouzas <[email protected]>
* Alexei Rivera <[email protected]>

* `Tecnativa <https://www.tecnativa.com>`__:

Expand Down
69 changes: 68 additions & 1 deletion account_commission/tests/test_account_commission.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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))
7 changes: 6 additions & 1 deletion account_commission/views/account_move_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
name="commission_id"
domain="['|', ('settlement_type', '=', 'sale_invoice'), ('settlement_type', '=', False)]"
/>
<field name="amount" />
<field
name="amount"
widget="monetary"
options="{'currency_field': 'currency_id'}"
/>
<field name="currency_id" invisible="1" />
</tree>
</field>
</record>
Expand Down
13 changes: 8 additions & 5 deletions account_commission/wizards/commission_make_settle.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@ class CommissionMakeSettle(models.TransientModel):
ondelete={"sale_invoice": "cascade"},
)

def _get_account_settle_domain(self, agent, date_to_agent):
return [
("invoice_date", "<", date_to_agent),
("agent_id", "=", agent.id),
("settled", "=", False),
]

def _get_agent_lines(self, agent, date_to_agent):
"""Filter sales invoice agent lines for this type of settlement."""
if self.settlement_type != "sale_invoice":
return super()._get_agent_lines(agent, date_to_agent)
return self.env["account.invoice.line.agent"].search(
[
("invoice_date", "<", date_to_agent),
("agent_id", "=", agent.id),
("settled", "=", False),
],
self._get_account_settle_domain(agent, date_to_agent),
order="invoice_date",
)

Expand Down
3 changes: 1 addition & 2 deletions commission/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -147,6 +145,7 @@ Contributors
* Oihane Crucelaegui <[email protected]>
* Nicola Malcontenti <[email protected]>
* Aitor Bouzas <[email protected]>
* Alexei Rivera <[email protected]>

* `Tecnativa <https://www.tecnativa.com>`__:

Expand Down
1 change: 1 addition & 0 deletions commission/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Oihane Crucelaegui <[email protected]>
* Nicola Malcontenti <[email protected]>
* Aitor Bouzas <[email protected]>
* Alexei Rivera <[email protected]>

* `Tecnativa <https://www.tecnativa.com>`__:

Expand Down
2 changes: 0 additions & 2 deletions commission/readme/ROADMAP.rst
Original file line number Diff line number Diff line change
@@ -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.
3 changes: 1 addition & 2 deletions commission/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,6 @@ <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Make it totally multi-company aware.</li>
<li>Be multi-currency aware for settlements.</li>
<li>Allow to calculate and pay in other currency different from company one.</li>
<li>Set agent popup window with a kanban view with richer information and
mobile friendly.</li>
</ul>
Expand Down Expand Up @@ -502,6 +500,7 @@ <h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<li>Oihane Crucelaegui &lt;<a class="reference external" href="mailto:oihanecruce&#64;gmail.com">oihanecruce&#64;gmail.com</a>&gt;</li>
<li>Nicola Malcontenti &lt;<a class="reference external" href="mailto:nicola.malcontenti&#64;agilebg.com">nicola.malcontenti&#64;agilebg.com</a>&gt;</li>
<li>Aitor Bouzas &lt;<a class="reference external" href="mailto:aitor.bouzas&#64;adaptivecity.com">aitor.bouzas&#64;adaptivecity.com</a>&gt;</li>
<li>Alexei Rivera &lt;<a class="reference external" href="mailto:arivera&#64;archeti.com">arivera&#64;archeti.com</a>&gt;</li>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Pedro M. Baeza</li>
<li>Manuel Calero</li>
Expand Down
15 changes: 15 additions & 0 deletions commission/tests/test_commission.py
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
13 changes: 11 additions & 2 deletions commission/views/commission_settlement_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@
<field name="date_from" />
<field name="date_to" />
<field name="settlement_type" />
<field name="total" sum="Settled total" />
<field
name="total"
sum="Settled total"
widget='monetary'
options="{'currency_field': 'currency_id'}"
/>
<field name="state" />
<field name="currency_id" invisible="1" />
</tree>
</field>
</record>
Expand Down Expand Up @@ -73,7 +79,10 @@
groups="base.group_multi_company"
/>
<field name="date_to" />
<field name="currency_id" invisible="1" />
<field
name="currency_id"
groups="base.group_multi_currency"
/>
<field name="agent_type" invisible="1" />
</group>
</group>
Expand Down
46 changes: 33 additions & 13 deletions commission/wizards/commission_make_settle.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -66,26 +67,28 @@ 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(
[
("agent_id", "=", agent.id),
("date_from", "=", sett_from),
("date_to", "=", sett_to),
("company_id", "=", company.id),
("currency_id", "=", currency.id),
("state", "=", "settled"),
("settlement_type", "=", self.settlement_type),
],
limit=1,
)

def _prepare_settlement_vals(self, agent, company, sett_from, sett_to):
def _prepare_settlement_vals(self, agent, company, currency, sett_from, sett_to):
return {
"agent_id": agent.id,
"date_from": sett_from,
"date_to": sett_to,
"company_id": company.id,
"currency_id": currency.id,
"settlement_type": self.settlement_type,
}

Expand All @@ -99,6 +102,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"]
Expand All @@ -112,15 +123,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
Expand All @@ -129,19 +145,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,
line.currency_id,
sett_from,
sett_to,
)
)
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 {
Expand Down

0 comments on commit 5defedd

Please sign in to comment.