Skip to content

Commit 12ffa8f

Browse files
committed
[ADD] account_credit_control_aggregate_level
This is an extraction of the feature added in account_credit_control
1 parent 8b42b7e commit 12ffa8f

36 files changed

+1241
-242
lines changed

account_credit_control/README.rst

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ Configure the policies and policy levels in
4646
You can define as many policy levels as you need. You must set on which
4747
accounts are applied every Credit Control Policy under Accounts tab.
4848

49-
Select ``Auto Process Lower levels`` to auto-process lines from lower
50-
level and same partner when a credit control line generated by this
51-
policy is processed.
52-
5349
Configure a tolerance for the Credit control and a default policy
5450
applied on all partners in each company, under the General Information
5551
tab in your company form.
@@ -87,16 +83,6 @@ communication processes that have been created and follow them.
8783
The 'Credit Control' followers of the linked partner will be
8884
automatically added as followers to the credit control lines.
8985

90-
The option ``Auto Process Lower Levels`` on ``Credit Control Policy``
91-
helps to manage high credit control line generation rates (e.g. if you
92-
are selling monthly subscriptions). In such situation you may want to
93-
avoid spamming reminders to customers with several credit control lines
94-
of different levels, and only take action for the highest level. Thus,
95-
an email sent for a high level will also contain the lower level lines.
96-
Plus, you can use the filter ``Group Lines`` in the
97-
``Credit Control Lines`` menu to hide lines that will be auto-processed
98-
when a highest level line is.
99-
10086
Bug Tracker
10187
===========
10288

@@ -128,7 +114,11 @@ Contributors
128114
- Akim Juillerat (Camptocamp) <akim.juillerat@camptocamp.com>
129115
- Kinner Vachhani (Access Bookings Ltd) <kin.vachhani@gmail.com>
130116
- Raf Ven <raf.ven@dynapps.be>
131-
- Quentin Groulard (ACSONE) <quentin.groulard@acsone.eu>
117+
- `Acsone <https://www.acsone.eu>`__:
118+
119+
- Quentin Groulard
120+
- Yannick Payot
121+
132122
- `Tecnativa <https://www.tecnativa.com>`__:
133123

134124
- Vicent Cubells

account_credit_control/models/credit_control_communication.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Copyright 2018 Access Bookings Ltd (https://accessbookings.com)
44
# Copyright 2020 Manuel Calero - Tecnativa
55
# Copyright 2023 Tecnativa - Víctor Martínez
6+
# Copyright 2019 ACSONE SA/NV
67
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
78
import threading
89

@@ -119,39 +120,32 @@ def _get_credit_lines(
119120
("partner_id", "=", partner_id),
120121
("currency_id", "=", currency_id),
121122
("company_id", "=", company_id),
123+
("policy_level_id", "=", level_id),
122124
]
123-
if level_id:
124-
domain.append(("policy_level_id", "=", level_id))
125125
return cr_line_obj.search(domain, order="level DESC")
126126

127127
@api.model
128128
def _sql_credit_lines_groups(self):
129129
"""Create a query to return:
130130
partner, level, currency, company
131-
132-
Groups with policy in auto process return NULL instead of an ID for the level
133131
"""
134132
return (
135133
"SELECT DISTINCT"
136134
" partner_id,"
137-
" CASE"
138-
" WHEN policy.auto_process_lower_levels"
139-
" THEN NULL"
140-
" ELSE policy_level.id"
141-
" END AS policy_level_id,"
135+
" policy_level_id,"
136+
" policy_level.level,"
142137
" line.currency_id,"
143138
" line.company_id"
144139
" FROM credit_control_line AS line"
145140
" JOIN credit_control_policy_level as policy_level"
146141
" ON (line.policy_level_id = policy_level.id)"
147-
" JOIN credit_control_policy as policy"
148-
" ON (policy_level.policy_id = policy.id)"
149142
" WHERE line.id in %s"
143+
" ORDER BY policy_level.level, line.currency_id"
150144
)
151145

152146
@api.model
153147
def _get_credit_line_groups(self, lines):
154-
""""""
148+
"""Returns key groups to be processed"""
155149
# Needed for related stored fields
156150
# are recomputed before executing the SQL
157151
lines.flush_recordset()
@@ -160,6 +154,18 @@ def _get_credit_line_groups(self, lines):
160154
cr.execute(sql, (tuple(lines.ids),))
161155
return cr.dictfetchall()
162156

157+
@api.model
158+
def _prepare_communication_data(self, cr_lines):
159+
line = cr_lines[0]
160+
company = line.company_id or self.env.company
161+
return {
162+
"credit_control_line_ids": [(6, 0, cr_lines.ids)],
163+
"partner_id": line.partner_id.id,
164+
"policy_level_id": line.policy_level_id.id,
165+
"currency_id": line.currency_id.id or company.currency_id.id,
166+
"company_id": company.id,
167+
}
168+
163169
@api.model
164170
def _aggregate_credit_lines(self, lines):
165171
"""Aggregate credit control line by partner, level, and currency"""
@@ -174,19 +180,9 @@ def _aggregate_credit_lines(self, lines):
174180
group["currency_id"],
175181
group["company_id"],
176182
)
177-
company = (
178-
self.env["res.company"].browse(group["company_id"])
179-
if group["company_id"]
180-
else self.env.company
181-
)
182-
max_policy_level = grouped_lines[0].policy_level_id
183-
data = {
184-
"credit_control_line_ids": [(6, 0, grouped_lines.ids)],
185-
"partner_id": group["partner_id"],
186-
"policy_level_id": max_policy_level.id,
187-
"currency_id": group["currency_id"] or company.currency_id.id,
188-
"company_id": group["company_id"],
189-
}
183+
if not grouped_lines:
184+
continue
185+
data = self._prepare_communication_data(grouped_lines)
190186
datas.append(data)
191187
return datas
192188

account_credit_control/models/credit_control_line.py

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -133,22 +133,6 @@ class CreditControlLine(models.Model):
133133
compute="_compute_partner_user_id",
134134
store=True,
135135
)
136-
auto_process = fields.Selection(
137-
selection=[
138-
("no_auto_process", "No Auto Process"),
139-
("low_level", "Low Level"),
140-
("highest_level", "Highest Level"),
141-
],
142-
help="'No Auto Process' lines are not automatically processed "
143-
"with other lines.\n"
144-
"'Low Level' lines are automatically processed "
145-
"with higher level lines.\n"
146-
"'Highest Level' indicates that all 'Low Level' lines for this "
147-
"line's partner-policy combination will be automatically "
148-
"processed with it.",
149-
default="no_auto_process",
150-
readonly=True,
151-
)
152136

153137
@api.depends("partner_id.user_id")
154138
def _compute_partner_user_id(self):
@@ -290,16 +274,6 @@ def create_or_update_from_mv_lines(
290274

291275
return new_lines
292276

293-
def _update_auto_process(self, exclude_ids=None):
294-
self.ensure_one()
295-
if not self.policy_id.auto_process_lower_levels:
296-
return
297-
highest_related_line = self._get_highest_related_line(exclude_ids=exclude_ids)
298-
highest_related_line.write({"auto_process": "highest_level"})
299-
self._get_related_lines(
300-
exclude_ids=((exclude_ids or []) + highest_related_line.ids)
301-
).write({"auto_process": "low_level"})
302-
303277
def unlink(self):
304278
for line in self:
305279
if line.state != "draft":
@@ -309,112 +283,10 @@ def unlink(self):
309283
"line that is not in draft state."
310284
)
311285
)
312-
line._update_auto_process(exclude_ids=line.ids)
313286
return super().unlink()
314287

315288
def write(self, values):
316289
res = super().write(values)
317290
if "manual_followup" in values:
318291
self.partner_id.write({"manual_followup": values.get("manual_followup")})
319-
for line in self:
320-
if "state" in values and values.get("state") == "sent":
321-
line.write({"auto_process": "no_auto_process"})
322-
if "auto_process" not in values:
323-
line._update_auto_process()
324292
return res
325-
326-
@api.model_create_multi
327-
def create(self, vals_list):
328-
lines = super().create(vals_list)
329-
for line in lines:
330-
if line.state == "sent":
331-
line.write({"auto_process": "no_auto_process"})
332-
else:
333-
line._update_auto_process()
334-
return lines
335-
336-
def _get_highest_related_line(self, exclude_ids=None):
337-
self.ensure_one()
338-
return self._get_related_lines(exclude_ids=exclude_ids, limit=1)
339-
340-
def _get_related_lines_domain(self, exclude_ids=None, level=None):
341-
domain = [
342-
("partner_id", "=", self.partner_id.id),
343-
("currency_id", "=", self.currency_id.id),
344-
("policy_id", "=", self.policy_id.id),
345-
("state", "in", ("draft", "to_be_sent")),
346-
]
347-
if exclude_ids:
348-
domain.append(("id", "not in", exclude_ids))
349-
if level:
350-
domain.append(("level", "<=", level))
351-
return domain
352-
353-
def _get_related_lines(self, exclude_ids=None, limit=None, level=None):
354-
"""
355-
Return lines from the same group if grouped
356-
(ie with same partner, policy and currency).
357-
358-
The most important line (ie the one to display to the user)
359-
is the first one of the returned recordset.
360-
"""
361-
self.ensure_one()
362-
if self.policy_id.auto_process_lower_levels:
363-
return self.search(
364-
self._get_related_lines_domain(exclude_ids, level),
365-
limit=limit,
366-
order="level DESC, date_due ASC",
367-
)
368-
else:
369-
return self
370-
371-
def _get_lower_related_lines(self):
372-
"""
373-
Return lines that will receive the same treatment
374-
(ie lines of lower level from the same group if grouped).
375-
"""
376-
self.ensure_one()
377-
if self.policy_id.auto_process_lower_levels:
378-
return self._get_related_lines(level=self.level)
379-
else:
380-
return self
381-
382-
def button_schedule_activity(self):
383-
ctx = self.env.context.copy()
384-
ctx.update(
385-
{
386-
"default_res_id": self.ids[0],
387-
"default_res_model": self._name,
388-
}
389-
)
390-
return {
391-
"type": "ir.actions.act_window",
392-
"name": _("Schedule activity"),
393-
"res_model": "mail.activity",
394-
"view_type": "form",
395-
"view_mode": "form",
396-
"res_id": self.activity_ids and self.activity_ids.ids[0] or False,
397-
"views": [[False, "form"]],
398-
"context": ctx,
399-
"target": "new",
400-
}
401-
402-
def button_credit_control_line_form(self):
403-
self.ensure_one()
404-
action = self.env.ref("account_credit_control.credit_control_line_action")
405-
form = self.env.ref("account_credit_control.credit_control_line_form")
406-
action = action.read()[0]
407-
action["views"] = [(form.id, "form")]
408-
action["res_id"] = self.id
409-
return action
410-
411-
def act_show_auto_process_line(self):
412-
self.ensure_one()
413-
return {
414-
"type": "ir.actions.act_window",
415-
"name": _("Credit Control Lines"),
416-
"res_model": "credit.control.line",
417-
"domain": [("id", "in", self._get_lower_related_lines().ids)],
418-
"view_mode": "list,form",
419-
"context": self.env.context,
420-
}

account_credit_control/models/credit_control_policy.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ class CreditControlPolicy(models.Model):
2727
do_nothing = fields.Boolean(
2828
help="For policies which should not generate lines or are obsolete"
2929
)
30-
auto_process_lower_levels = fields.Boolean(
31-
string="Auto Process Lower levels",
32-
help="When an action is performed on a credit control line generated "
33-
"by this policy, lower level lines for the same partner and policy "
34-
"will also be processed.",
35-
)
3630
company_id = fields.Many2one(comodel_name="res.company")
3731
account_ids = fields.Many2many(
3832
comodel_name="account.account",

account_credit_control/readme/CONFIGURE.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ Configure the policies and policy levels in
33
You can define as many policy levels as you need. You must set on which
44
accounts are applied every Credit Control Policy under Accounts tab.
55

6-
Select ``Auto Process Lower levels`` to auto-process lines from lower level and
7-
same partner when a credit control line generated by this policy is processed.
8-
96
Configure a tolerance for the Credit control and a default policy
107
applied on all partners in each company, under the General Information
118
tab in your company form.

account_credit_control/readme/CONTRIBUTORS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
- Akim Juillerat (Camptocamp) \<<akim.juillerat@camptocamp.com>\>
55
- Kinner Vachhani (Access Bookings Ltd) \<<kin.vachhani@gmail.com>\>
66
- Raf Ven \<<raf.ven@dynapps.be>\>
7-
- Quentin Groulard (ACSONE) \<<quentin.groulard@acsone.eu>\>
7+
- [Acsone](https://www.acsone.eu):
8+
- Quentin Groulard
9+
- Yannick Payot
810
- [Tecnativa](https://www.tecnativa.com):
911
- Vicent Cubells
1012
- Manuel Calero

account_credit_control/readme/USAGE.md

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,3 @@ communication processes that have been created and follow them.
2424

2525
The 'Credit Control' followers of the linked partner will be automatically
2626
added as followers to the credit control lines.
27-
28-
The option ``Auto Process Lower Levels`` on ``Credit Control Policy`` helps to
29-
manage high credit control line generation rates (e.g. if you are selling
30-
monthly subscriptions).
31-
In such situation you may want to avoid spamming reminders to customers with
32-
several credit control lines of different levels, and only take action for the
33-
highest level. Thus, an email sent for a high level will also contain the lower
34-
level lines.
35-
Plus, you can use the filter ``Group Lines`` in the ``Credit Control Lines``
36-
menu to hide lines that will be auto-processed when a highest level line is.

account_credit_control/static/description/index.html

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -394,9 +394,6 @@ <h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
394394
<tt class="docutils literal">Invoicing&nbsp; &gt; Configuration &gt; Credit Control &gt; Credit Control Policies</tt>.
395395
You can define as many policy levels as you need. You must set on which
396396
accounts are applied every Credit Control Policy under Accounts tab.</p>
397-
<p>Select <tt class="docutils literal">Auto Process Lower levels</tt> to auto-process lines from lower
398-
level and same partner when a credit control line generated by this
399-
policy is processed.</p>
400397
<p>Configure a tolerance for the Credit control and a default policy
401398
applied on all partners in each company, under the General Information
402399
tab in your company form.</p>
@@ -427,15 +424,6 @@ <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
427424
communication processes that have been created and follow them.</p>
428425
<p>The ‘Credit Control’ followers of the linked partner will be
429426
automatically added as followers to the credit control lines.</p>
430-
<p>The option <tt class="docutils literal">Auto Process Lower Levels</tt> on <tt class="docutils literal">Credit Control Policy</tt>
431-
helps to manage high credit control line generation rates (e.g. if you
432-
are selling monthly subscriptions). In such situation you may want to
433-
avoid spamming reminders to customers with several credit control lines
434-
of different levels, and only take action for the highest level. Thus,
435-
an email sent for a high level will also contain the lower level lines.
436-
Plus, you can use the filter <tt class="docutils literal">Group Lines</tt> in the
437-
<tt class="docutils literal">Credit Control Lines</tt> menu to hide lines that will be auto-processed
438-
when a highest level line is.</p>
439427
</div>
440428
<div class="section" id="bug-tracker">
441429
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
@@ -466,7 +454,11 @@ <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
466454
<li>Akim Juillerat (Camptocamp) &lt;<a class="reference external" href="mailto:akim.juillerat&#64;camptocamp.com">akim.juillerat&#64;camptocamp.com</a>&gt;</li>
467455
<li>Kinner Vachhani (Access Bookings Ltd) &lt;<a class="reference external" href="mailto:kin.vachhani&#64;gmail.com">kin.vachhani&#64;gmail.com</a>&gt;</li>
468456
<li>Raf Ven &lt;<a class="reference external" href="mailto:raf.ven&#64;dynapps.be">raf.ven&#64;dynapps.be</a>&gt;</li>
469-
<li>Quentin Groulard (ACSONE) &lt;<a class="reference external" href="mailto:quentin.groulard&#64;acsone.eu">quentin.groulard&#64;acsone.eu</a>&gt;</li>
457+
<li><a class="reference external" href="https://www.acsone.eu">Acsone</a>:<ul>
458+
<li>Quentin Groulard</li>
459+
<li>Yannick Payot</li>
460+
</ul>
461+
</li>
470462
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
471463
<li>Vicent Cubells</li>
472464
<li>Manuel Calero</li>

account_credit_control/tests/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@
33
from . import test_res_partner
44
from . import test_account_move
55
from . import test_credit_control_run
6-
from . import test_credit_control_line

0 commit comments

Comments
 (0)