[MIG] account_mass_reconcile: Migration to 15.0

This commit is contained in:
Miquel Raïch
2023-01-09 11:28:45 +01:00
parent 13c636bb4e
commit cc2f249f8f
10 changed files with 44 additions and 52 deletions

View File

@@ -4,7 +4,7 @@
{
"name": "Account Mass Reconcile",
"version": "14.0.1.1.1",
"version": "15.0.1.0.0",
"depends": ["account"],
"author": "Akretion,Camptocamp,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-reconcile",

View File

@@ -6,7 +6,6 @@ from odoo import models
class MassReconcileAdvancedRef(models.TransientModel):
_name = "mass.reconcile.advanced.ref"
_inherit = "mass.reconcile.advanced"
_description = "Mass Reconcile Advanced Ref"
@@ -44,7 +43,7 @@ class MassReconcileAdvancedRef(models.TransientModel):
to consider them as "opposite"
The matchers will be evaluated in the same order as declared
vs the the opposite matchers, so you can gain performance by
vs the opposite matchers, so you can gain performance by
declaring first the partners with the less computation.
All matchers should match with their opposite to be considered
@@ -54,9 +53,9 @@ class MassReconcileAdvancedRef(models.TransientModel):
:return: tuple of tuples (key, value) where the keys are
the matchers keys
(must be the same than `_opposite_matchers` returns,
(They must be the same that `_opposite_matchers` returns,
and their values to match in the opposite lines.
A matching key can have multiples values.
A matching key can have multiples values.)
"""
return (
("partner_id", move_line["partner_id"]),
@@ -97,7 +96,7 @@ class MassReconcileAdvancedRef(models.TransientModel):
yield ('ref', (move_line['ref'], move_line['name'])
An OR is used between the values for the same key.
An AND is used between the differents keys.
An AND is used between the different keys.
:param dict move_line: values of the move_line
:yield: matchers as tuple ('matcher key', value(s))
@@ -151,7 +150,7 @@ class MassReconcileAdvancedName(models.TransientModel):
to consider them as "opposite"
The matchers will be evaluated in the same order as declared
vs the the opposite matchers, so you can gain performance by
vs the opposite matchers, so you can gain performance by
declaring first the partners with the less computation.
All matchers should match with their opposite to be considered
@@ -161,9 +160,9 @@ class MassReconcileAdvancedName(models.TransientModel):
:return: tuple of tuples (key, value) where the keys are
the matchers keys
(must be the same than `_opposite_matchers` returns,
(They must be the same that `_opposite_matchers` returns,
and their values to match in the opposite lines.
A matching key can have multiples values.
A matching key can have multiples values.)
"""
return (
("partner_id", move_line["partner_id"]),
@@ -204,7 +203,7 @@ class MassReconcileAdvancedName(models.TransientModel):
yield ('ref', (move_line['ref'], move_line['name'])
An OR is used between the values for the same key.
An AND is used between the differents keys.
An AND is used between the different keys.
:param dict move_line: values of the move_line
:yield: matchers as tuple ('matcher key', value(s))

View File

@@ -72,9 +72,9 @@ class MassReconcileAdvanced(models.AbstractModel):
:return: tuple of tuples (key, value) where the keys are
the matchers keys
(must be the same than `_opposite_matchers` returns,
(They must be the same that `_opposite_matchers` returns,
and their values to match in the opposite lines.
A matching key can have multiples values.
A matching key can have multiples values.)
"""
raise NotImplementedError
@@ -112,7 +112,7 @@ class MassReconcileAdvanced(models.AbstractModel):
yield ('ref', (move_line['ref'], move_line['name'])
An OR is used between the values for the same key.
An AND is used between the differents keys.
An AND is used between the different keys.
:param dict move_line: values of the move_line
:yield: matchers as tuple ('matcher key', value(s))
@@ -137,7 +137,7 @@ class MassReconcileAdvanced(models.AbstractModel):
@classmethod
def _compare_matcher_values(cls, key, values, opposite_values):
"""Compare every values from a matcher vs an opposite matcher
"""Compare every `values` from a matcher vs an opposite matcher
and return True if it matches
"""
for value, ovalue in product(values, opposite_values):
@@ -155,9 +155,9 @@ class MassReconcileAdvanced(models.AbstractModel):
mkey, mvalue = matcher
omkey, omvalue = opposite_matcher
assert mkey == omkey, _(
"A matcher %s is compared with a matcher %s, the _matchers and "
"A matcher %(mkey)s is compared with a matcher %(omkey)s, the _matchers and "
"_opposite_matchers are probably wrong"
) % (mkey, omkey)
) % {"mkey": mkey, "omkey": omkey}
if not isinstance(mvalue, (list, tuple)):
mvalue = (mvalue,)
if not isinstance(omvalue, (list, tuple)):
@@ -175,10 +175,10 @@ class MassReconcileAdvanced(models.AbstractModel):
for matcher in matchers:
try:
opp_matcher = next(opp_matchers)
except StopIteration:
except StopIteration as e:
# if you fall here, you probably missed to put a `yield`
# in `_opposite_matchers()`
raise ValueError("Missing _opposite_matcher: %s" % matcher[0])
raise ValueError("Missing _opposite_matcher: %s" % matcher[0]) from e
if not self._compare_matchers(matcher, opp_matcher):
# if any of the matcher fails, the opposite line
@@ -238,9 +238,9 @@ class MassReconcileAdvanced(models.AbstractModel):
def _rec_group_by_chunk(self, reconcile_groups, lines_by_id, chunk_size):
"""Commit after each chunk
:param dict reconcile_grous: all groups to reconcile, will be splitted
:param list reconcile_groups: all groups to reconcile, will be split
by chunk
:param list lines_by_id: list of dict of move lines values,
:param dict lines_by_id: dict of move lines values,
the move lines we want to search for
:return: list of reconciled lines
"""
@@ -251,23 +251,19 @@ class MassReconcileAdvanced(models.AbstractModel):
# Copy and commit current transient model before creating a new cursor
# This is required to avoid CacheMiss when using data from `self`
# which is created during current transaction.
with api.Environment.manage():
with registry(self.env.cr.dbname).cursor() as new_cr:
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
self_env = self.with_env(new_env)
rec = self_env.create(self.copy_data())
with registry(self.env.cr.dbname).cursor() as new_cr:
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
self_env = self.with_env(new_env)
rec = self_env.create(self.copy_data())
for i in range(0, len(reconcile_groups), chunk_size):
chunk = reconcile_groups[i : i + chunk_size]
_logger.debug("Reconcile group chunk %s", chunk)
try:
with api.Environment.manage():
with registry(self.env.cr.dbname).cursor() as new_cr:
new_env = api.Environment(
new_cr, self.env.uid, self.env.context
)
# Re-use the commited transient we just commited
self_env = self.with_env(new_env).browse(rec.id)
reconciled_ids += self_env._rec_group(chunk, lines_by_id)
with registry(self.env.cr.dbname).cursor() as new_cr:
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
# Re-use the committed transient we just committed
self_env = self.with_env(new_env).browse(rec.id)
reconciled_ids += self_env._rec_group(chunk, lines_by_id)
except Exception as e:
msg = "Reconciliation failed for group chunk %s with error:\n%s"
_logger.exception(msg, chunk, e)

View File

@@ -77,7 +77,7 @@ class MassReconcileBase(models.AbstractModel):
# it would be great to use dict for params
# but as we use _where_calc in _get_filter
# which returns a list, we have to
# accomodate with that
# accommodate with that
params = [self.account_id.id]
if self.partner_ids:
where += " AND account_move_line.partner_id IN %s"

View File

@@ -64,7 +64,6 @@ class AccountMassReconcileMethod(models.Model):
name = fields.Selection("_selection_name", string="Type", required=True)
sequence = fields.Integer(
string="Sequence",
default=1,
required=True,
help="The sequence field is used to order the reconcile method",
@@ -110,8 +109,8 @@ class AccountMassReconcile(models.Model):
)
rec.last_history = last_history_rs or False
name = fields.Char(string="Name", required=True)
account = fields.Many2one("account.account", string="Account", required=True)
name = fields.Char(required=True)
account = fields.Many2one("account.account", required=True)
reconcile_method = fields.One2many(
"account.mass.reconcile.method", "task_id", string="Method"
)
@@ -134,9 +133,9 @@ class AccountMassReconcile(models.Model):
return {
"account_id": rec_method.task_id.account.id,
"write_off": rec_method.write_off,
"account_lost_id": (rec_method.account_lost_id.id),
"account_profit_id": (rec_method.account_profit_id.id),
"journal_id": (rec_method.journal_id.id),
"account_lost_id": rec_method.account_lost_id.id,
"account_profit_id": rec_method.account_profit_id.id,
"journal_id": rec_method.journal_id.id,
"date_base_on": rec_method.date_base_on,
"_filter": rec_method._filter,
}
@@ -175,13 +174,13 @@ class AccountMassReconcile(models.Model):
" FOR UPDATE NOWAIT",
(rec.id,),
)
except psycopg2.OperationalError:
except psycopg2.OperationalError as e:
raise exceptions.UserError(
_(
"A mass reconcile is already ongoing for this account, "
"please try again later."
)
)
) from e
ctx = self.env.context.copy()
ctx["commit_every"] = rec.account.company_id.reconciliation_commit_every
if ctx["commit_every"]:
@@ -245,7 +244,6 @@ class AccountMassReconcile(models.Model):
"name": name,
"view_mode": "tree,form",
"view_id": False,
"view_type": "form",
"res_model": "account.move.line",
"type": "ir.actions.act_window",
"nodestroy": True,
@@ -280,7 +278,7 @@ class AccountMassReconcile(models.Model):
"""Launch the reconcile with the oldest run
This function is mostly here to be used with cron task
:param run_all: if set it will ingore lookup and launch
:param run_all: if set it will ignore lookup and launch
all reconciliation
:returns: True in case of success or raises an exception

View File

@@ -57,7 +57,6 @@ class MassReconcileHistory(models.Model):
"name": name,
"view_mode": "tree,form",
"view_id": False,
"view_type": "form",
"res_model": "account.move.line",
"type": "ir.actions.act_window",
"nodestroy": True,

View File

@@ -4,7 +4,7 @@
from odoo.tests import common
class TestOnChange(common.SavepointCase):
class TestOnChange(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestOnChange, cls).setUpClass()

View File

@@ -130,7 +130,7 @@ class TestScenarioReconcile(TestAccountReconciliationCommon):
"reconcile_method": [(0, 0, {"name": "mass.reconcile.simple.partner"})],
}
)
# call the automatic reconcilation method
# call the automatic reconciliation method
mass_rec.run_reconcile()
self.assertEqual("paid", invoice.payment_state)
@@ -228,7 +228,7 @@ class TestScenarioReconcile(TestAccountReconciliationCommon):
],
}
)
# call the automatic reconcilation method
# call the automatic reconciliation method
mass_rec.run_reconcile()
self.assertEqual("not_paid", invoice.payment_state)
mass_rec.reconcile_method.write_off = 0.11

View File

@@ -50,7 +50,7 @@
</page>
<page name="history" string="History">
<field name="history_ids" nolabel="1">
<tree string="Automatic Mass Reconcile History">
<tree>
<field name="date" />
<button
icon="fa-share"
@@ -116,7 +116,7 @@ The lines should have the same partner, and the credit entry ref. is matched wit
<field name="priority">20</field>
<field name="model">account.mass.reconcile</field>
<field name="arch" type="xml">
<tree string="Automatic Mass Reconcile">
<tree>
<field name="name" />
<field name="account" />
<field name="company_id" groups="base.group_multi_company" />
@@ -161,7 +161,7 @@ The lines should have the same partner, and the credit entry ref. is matched wit
<field name="priority">20</field>
<field name="model">account.mass.reconcile.method</field>
<field name="arch" type="xml">
<tree editable="top" string="Automatic Mass Reconcile Method">
<tree editable="top">
<field name="sequence" widget="handle" />
<field name="name" />
<field name="write_off" />

View File

@@ -69,7 +69,7 @@
<field name="name">mass.reconcile.history.tree</field>
<field name="model">mass.reconcile.history</field>
<field name="arch" type="xml">
<tree string="Automatic Mass Reconcile History">
<tree>
<field name="mass_reconcile_id" />
<field name="date" />
<button