[IMP] account_mass_reconcile: Add 'oldest move line' option on reconcile option

pull/635/head
Aritz Olea 2023-10-23 16:32:48 +02:00 committed by JasminSForgeFlow
parent 2491f49914
commit 957c7e2ccd
5 changed files with 139 additions and 3 deletions

View File

@ -128,6 +128,9 @@ class MassReconcileBase(models.AbstractModel):
def last_date(mlines):
return max(mlines, key=itemgetter("date"))
def oldest_date(mlines):
return min(mlines, key=itemgetter("date"))
def credit(mlines):
return [line for line in mlines if line["credit"] > 0]
@ -136,6 +139,8 @@ class MassReconcileBase(models.AbstractModel):
if based_on == "newest":
return last_date(lines)["date"]
elif based_on == "oldest":
return oldest_date(lines)["date"]
elif based_on == "newest_credit":
return last_date(credit(lines))["date"]
elif based_on == "newest_debit":

View File

@ -28,7 +28,11 @@ class MassReconcileOptions(models.AbstractModel):
@api.model
def _get_rec_base_date(self):
return [("newest", "Most recent move line"), ("actual", "Today")]
return [
("newest", "Most recent move line"),
("actual", "Today"),
("oldest", "Oldest move line"),
]
write_off = fields.Float("Write off allowed", default=0.0)
account_lost_id = fields.Many2one("account.account", string="Account Lost")

View File

@ -58,7 +58,12 @@ class MassReconcileSimple(models.AbstractModel):
return res
def _simple_order(self, *args, **kwargs):
return "ORDER BY account_move_line.%s" % self._key_field
ret = "ORDER BY account_move_line.%s" % self._key_field
if self.date_base_on == "oldest":
ret += ", date"
elif self.date_base_on == "newest":
ret += ", date desc"
return ret
def _action_rec(self):
"""Match only 2 move lines, do not allow partial reconcile"""

View File

@ -15,4 +15,7 @@ in order to provide:
in this module, the simple reconciliations works
on 2 lines (1 debit / 1 credit) and do not allow
partial reconciliation, they also match on 1 key,
partner or Journal item name.
partner or Journal item name. There is also an
option for 'most recent move line' or
'oldest move line' which is used to choose the
move to be reconciled if more than one is found.

View File

@ -1,4 +1,5 @@
# © 2014-2016 Camptocamp SA (Damien Crier)
# © 2023 FactorLibre - Aritz Olea <aritz.olea@factorlibre.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
@ -67,6 +68,124 @@ class TestScenarioReconcile(TestAccountReconciliationCommon):
mass_rec.run_reconcile()
self.assertEqual("paid", invoice.payment_state)
def test_scenario_reconcile_newest(self):
invoice = self.create_invoice()
self.assertEqual("posted", invoice.state)
receivalble_account_id = invoice.partner_id.property_account_receivable_id.id
# create payments
payment_old = self.env["account.payment"].create(
{
"partner_type": "customer",
"payment_type": "inbound",
"partner_id": invoice.partner_id.id,
"destination_account_id": receivalble_account_id,
"amount": 50.0,
"journal_id": self.bank_journal.id,
"date": fields.Date.from_string("2023-10-01"),
}
)
payment_new = self.env["account.payment"].create(
{
"partner_type": "customer",
"payment_type": "inbound",
"partner_id": invoice.partner_id.id,
"destination_account_id": receivalble_account_id,
"amount": 50.0,
"journal_id": self.bank_journal.id,
"date": fields.Date.from_string("2023-10-20"),
}
)
payment_old.action_post()
payment_new.action_post()
# create the mass reconcile record
mass_rec = self.mass_rec_obj.create(
{
"name": "mass_reconcile_1",
"account": invoice.partner_id.property_account_receivable_id.id,
"reconcile_method": [
(
0,
0,
{
"name": "mass.reconcile.simple.partner",
"date_base_on": "newest",
},
)
],
}
)
# call the automatic reconciliation method
mass_rec.run_reconcile()
self.assertEqual("paid", invoice.payment_state)
self.assertTrue(mass_rec.last_history)
payment_new_line = payment_new.move_id.line_ids.filtered(lambda l: l.credit)
payment_old_line = payment_old.move_id.line_ids.filtered(lambda l: l.credit)
self.assertTrue(payment_new_line in mass_rec.last_history.reconcile_line_ids)
self.assertTrue(payment_new_line.reconciled)
self.assertFalse(payment_old_line in mass_rec.last_history.reconcile_line_ids)
self.assertFalse(payment_old_line.reconciled)
def test_scenario_reconcile_oldest(self):
invoice = self.create_invoice()
self.assertEqual("posted", invoice.state)
receivalble_account_id = invoice.partner_id.property_account_receivable_id.id
# create payments
payment_old = self.env["account.payment"].create(
{
"partner_type": "customer",
"payment_type": "inbound",
"partner_id": invoice.partner_id.id,
"destination_account_id": receivalble_account_id,
"amount": 50.0,
"journal_id": self.bank_journal.id,
"date": fields.Date.from_string("2023-10-01"),
}
)
payment_new = self.env["account.payment"].create(
{
"partner_type": "customer",
"payment_type": "inbound",
"partner_id": invoice.partner_id.id,
"destination_account_id": receivalble_account_id,
"amount": 50.0,
"journal_id": self.bank_journal.id,
"date": fields.Date.from_string("2023-10-20"),
}
)
payment_old.action_post()
payment_new.action_post()
# create the mass reconcile record
mass_rec = self.mass_rec_obj.create(
{
"name": "mass_reconcile_1",
"account": invoice.partner_id.property_account_receivable_id.id,
"reconcile_method": [
(
0,
0,
{
"name": "mass.reconcile.simple.partner",
"date_base_on": "oldest",
},
)
],
}
)
# call the automatic reconciliation method
mass_rec.run_reconcile()
self.assertEqual("paid", invoice.payment_state)
self.assertTrue(mass_rec.last_history)
payment_new_line = payment_new.move_id.line_ids.filtered(lambda l: l.credit)
payment_old_line = payment_old.move_id.line_ids.filtered(lambda l: l.credit)
self.assertFalse(payment_new_line in mass_rec.last_history.reconcile_line_ids)
self.assertFalse(payment_new_line.reconciled)
self.assertTrue(payment_old_line in mass_rec.last_history.reconcile_line_ids)
self.assertTrue(payment_old_line.reconciled)
def test_scenario_reconcile_currency(self):
currency_rate = (
self.env["res.currency.rate"]