Skip to content

Commit f91a487

Browse files
committed
Merge PR #1188 into 17.0
Signed-off-by pedrobaeza
2 parents caab7b2 + 6629826 commit f91a487

10 files changed

+173
-101
lines changed

product_contract/README.rst

+10-9
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ To use this module, you need to:
6565
Known issues / Roadmap
6666
======================
6767

68-
- There's no support right now for computing the start date for the
69-
following recurrent types: daily, weekly and monthlylastday.
68+
- There's no support right now for computing the start date for the
69+
following recurrent types: daily, weekly and monthlylastday.
7070

7171
Bug Tracker
7272
===========
@@ -90,15 +90,16 @@ Authors
9090
Contributors
9191
------------
9292

93-
- Ted Salmon <[email protected]>
94-
- Souheil Bejaoui <[email protected]>
95-
- `Tecnativa <https://www.tecnativa.com>`__:
93+
- Ted Salmon <[email protected]>
94+
- Souheil Bejaoui <[email protected]>
95+
- `Tecnativa <https://www.tecnativa.com>`__:
9696

97-
- Ernesto Tejeda
98-
- Pedro M. Baeza
99-
- Carlos Roca
97+
- Ernesto Tejeda
98+
- Pedro M. Baeza
99+
- Carlos Roca
100+
- Sergio Teruel
100101

101-
- David Jaen <[email protected]>
102+
- David Jaen <[email protected]>
102103

103104
Maintainers
104105
-----------

product_contract/models/sale_order_line.py

+71-41
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,32 @@ class SaleOrderLine(models.Model):
3030
string="Contract Template",
3131
compute="_compute_contract_template_id",
3232
)
33+
recurring_interval = fields.Integer(
34+
default=1,
35+
string="Invoice Every",
36+
help="Invoice every (Days/Week/Month/Year)",
37+
)
3338
recurring_rule_type = fields.Selection(related="product_id.recurring_rule_type")
3439
recurring_invoicing_type = fields.Selection(
3540
related="product_id.recurring_invoicing_type"
3641
)
37-
date_start = fields.Date()
38-
date_end = fields.Date()
39-
42+
date_start = fields.Date(
43+
compute="_compute_date_start", readonly=False, store=True, precompute=True
44+
)
45+
date_end = fields.Date(
46+
compute="_compute_date_end", readonly=False, store=True, precompute=True
47+
)
4048
contract_line_id = fields.Many2one(
4149
comodel_name="contract.line",
4250
string="Contract Line to replace",
43-
required=False,
4451
copy=False,
4552
)
4653
is_auto_renew = fields.Boolean(
4754
string="Auto Renew",
4855
compute="_compute_auto_renew",
49-
default=False,
5056
store=True,
5157
readonly=False,
58+
precompute=True,
5259
)
5360
auto_renew_interval = fields.Integer(
5461
default=1,
@@ -57,6 +64,7 @@ class SaleOrderLine(models.Model):
5764
store=True,
5865
readonly=False,
5966
help="Renew every (Days/Week/Month/Year)",
67+
precompute=True,
6068
)
6169
auto_renew_rule_type = fields.Selection(
6270
[
@@ -71,6 +79,7 @@ class SaleOrderLine(models.Model):
7179
readonly=False,
7280
string="Renewal type",
7381
help="Specify Interval for automatic renewal.",
82+
precompute=True,
7483
)
7584
contract_start_date_method = fields.Selection(
7685
related="product_id.contract_start_date_method"
@@ -97,47 +106,68 @@ def _compute_contract_template_id(self):
97106
rec.order_id.company_id
98107
).property_contract_template_id
99108

100-
def _get_auto_renew_rule_type(self):
101-
"""monthly last day don't make sense for auto_renew_rule_type"""
102-
self.ensure_one()
103-
if self.recurring_rule_type == "monthlylastday":
104-
return "monthly"
105-
return self.recurring_rule_type
109+
@api.depends("product_id")
110+
def _compute_date_start(self):
111+
for sol in self:
112+
if sol.contract_start_date_method == "start_this":
113+
sol.date_start = sol.order_id.date_order.replace(day=1)
114+
elif sol.contract_start_date_method == "end_this":
115+
sol.date_start = (
116+
sol.order_id.date_order
117+
+ self.get_relative_delta(
118+
sol.recurring_rule_type, sol.product_id.default_qty
119+
)
120+
).replace(day=1) - relativedelta(days=1)
121+
elif sol.contract_start_date_method == "start_next":
122+
# Dia 1 del siguiente recurring_rule_type
123+
sol.date_start = (
124+
sol.order_id.date_order
125+
+ self.get_relative_delta(
126+
sol.recurring_rule_type, sol.product_id.default_qty
127+
)
128+
).replace(day=1)
129+
elif sol.contract_start_date_method == "end_next":
130+
# Last day of next recurring period
131+
sol.date_start = (
132+
sol.order_id.date_order
133+
+ self.get_relative_delta(
134+
sol.recurring_rule_type, sol.product_id.default_qty + 1
135+
)
136+
).replace(day=1) - relativedelta(days=1)
137+
else:
138+
# Manual method
139+
sol.date_start = False
106140

107-
def _get_date_end(self):
108-
self.ensure_one()
109-
contract_start_date_method = self.product_id.contract_start_date_method
110-
date_end = False
111-
if contract_start_date_method == "manual":
112-
contract_line_model = self.env["contract.line"]
113-
date_end = (
114-
self.date_start
115-
+ contract_line_model.get_relative_delta(
116-
self._get_auto_renew_rule_type(),
117-
int(self.product_uom_qty),
141+
@api.depends(
142+
"is_auto_renew",
143+
"date_start",
144+
"auto_renew_interval",
145+
"auto_renew_rule_type",
146+
)
147+
def _compute_date_end(self):
148+
for sol in self:
149+
if sol.is_auto_renew and sol.date_start:
150+
sol.date_end = self.env["contract.line"]._get_first_date_end(
151+
sol.date_start,
152+
sol.auto_renew_rule_type,
153+
sol.auto_renew_interval,
118154
)
119-
- relativedelta(days=1)
120-
)
121-
return date_end
155+
else:
156+
sol.date_end = False
157+
158+
@api.model
159+
def get_relative_delta(self, recurring_rule_type, interval):
160+
return self.env["contract.recurrency.mixin"].get_relative_delta(
161+
recurring_rule_type, interval
162+
)
122163

123164
@api.depends("product_id")
124165
def _compute_auto_renew(self):
125-
for rec in self:
126-
if rec.product_id.is_contract:
127-
rec.product_uom_qty = rec.product_id.default_qty
128-
contract_start_date_method = rec.product_id.contract_start_date_method
129-
if contract_start_date_method == "manual":
130-
rec.date_start = rec.date_start or fields.Date.today()
131-
rec.date_end = rec._get_date_end()
132-
rec.is_auto_renew = rec.product_id.is_auto_renew
133-
if rec.is_auto_renew:
134-
rec.auto_renew_interval = rec.product_id.auto_renew_interval
135-
rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type
136-
137-
@api.onchange("date_start", "product_uom_qty")
138-
def onchange_date_start(self):
139166
for rec in self.filtered("product_id.is_contract"):
140-
rec.date_end = rec._get_date_end() if rec.date_start else False
167+
rec.product_uom_qty = rec.product_id.default_qty
168+
rec.is_auto_renew = rec.product_id.is_auto_renew
169+
rec.auto_renew_interval = rec.product_id.auto_renew_interval
170+
rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type
141171

142172
def _get_contract_line_qty(self):
143173
"""Returns the amount that will be placed in new contract lines."""
@@ -178,7 +208,7 @@ def _prepare_contract_line_values(
178208
"date_end": self.date_end,
179209
"date_start": self.date_start or fields.Date.today(),
180210
"recurring_next_date": recurring_next_date,
181-
"recurring_interval": 1,
211+
"recurring_interval": self.recurring_interval or 1,
182212
"recurring_invoicing_type": self.recurring_invoicing_type,
183213
"recurring_rule_type": self.recurring_rule_type,
184214
"is_auto_renew": self.is_auto_renew,

product_contract/readme/CONTRIBUTORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
- Ernesto Tejeda
55
- Pedro M. Baeza
66
- Carlos Roca
7+
- Sergio Teruel
78
- David Jaen \<<[email protected]>\>

product_contract/static/description/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ <h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
444444
<li>Ernesto Tejeda</li>
445445
<li>Pedro M. Baeza</li>
446446
<li>Carlos Roca</li>
447+
<li>Sergio Teruel</li>
447448
</ul>
448449
</li>
449450
<li>David Jaen &lt;<a class="reference external" href="mailto:david.jaen.revert&#64;gmail.com">david.jaen.revert&#64;gmail.com</a>&gt;</li>

product_contract/static/src/js/contract_configurator_controller.esm.js

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class ProductContractConfiguratorController extends formView.Controller {
2121
is_auto_renew,
2222
auto_renew_interval,
2323
auto_renew_rule_type,
24+
recurring_interval,
2425
} = record.data;
2526
return this.action.doAction({
2627
type: "ir.actions.act_window_close",
@@ -34,6 +35,7 @@ export class ProductContractConfiguratorController extends formView.Controller {
3435
is_auto_renew,
3536
auto_renew_interval,
3637
auto_renew_rule_type,
38+
recurring_interval,
3739
},
3840
},
3941
});

product_contract/static/src/js/sale_product_field.esm.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,31 @@ patch(SaleOrderLineProductField.prototype, {
3737
return super.isConfigurableLine || this.props.record.data.is_contract;
3838
},
3939

40-
async _openContractConfigurator(isNew = false) {
41-
const actionContext = {
40+
get contractContext() {
41+
return {
4242
default_product_id: this.props.record.data.product_id[0],
4343
default_partner_id: this.props.record.model.root.data.partner_id[0],
4444
default_company_id: this.props.record.model.root.data.company_id[0],
4545
default_product_uom_qty: this.props.record.data.product_uom_qty,
4646
default_contract_id: this.props.record.data.contract_id[0],
47+
default_recurring_interval: this.props.record.data.recurring_interval,
4748
default_date_start: this.props.record.data.date_start,
4849
default_date_end: this.props.record.data.date_end,
4950
default_is_auto_renew: this.props.record.data.is_auto_renew,
5051
default_auto_renew_interval: this.props.record.data.auto_renew_interval,
5152
default_auto_renew_rule_type: this.props.record.data.auto_renew_rule_type,
5253
};
54+
},
55+
56+
async _openContractConfigurator(isNew = false) {
57+
const actionContext = this.contractContext;
5358
this.action.doAction("product_contract.product_contract_configurator_action", {
5459
additionalContext: actionContext,
5560
onClose: async (closeInfo) => {
5661
if (closeInfo && !closeInfo.special) {
57-
this.props.record.update(closeInfo.productContractConfiguration);
62+
this.props.record._update(closeInfo.productContractConfiguration, {
63+
withoutOnchange: true,
64+
});
5865
} else if (isNew) {
5966
this.props.record.update({
6067
[this.props.name]: undefined,

product_contract/tests/test_sale_order.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_compute_is_contract(self):
109109
def test_action_confirm(self):
110110
"""It should create a contract for each contract template used in
111111
order_line"""
112-
self.order_line1._compute_auto_renew()
112+
self.order_line1.is_auto_renew = True
113113
self.sale.action_confirm()
114114
contracts = self.sale.order_line.mapped("contract_id")
115115
self.assertEqual(len(contracts), 2)
@@ -155,7 +155,7 @@ def test_action_confirm_without_contract_creation(self):
155155
"""It should create a contract for each contract template used in
156156
order_line"""
157157
self.sale.company_id.create_contract_at_sale_order_confirmation = False
158-
self.order_line1._compute_auto_renew()
158+
self.order_line1.is_auto_renew = True
159159
self.sale.action_confirm()
160160
self.assertEqual(len(self.sale.order_line.mapped("contract_id")), 0)
161161
self.assertTrue(self.sale.need_contract_creation)
@@ -174,14 +174,14 @@ def test_action_confirm_without_contract_creation(self):
174174
def test_sale_contract_count(self):
175175
"""It should count contracts as many different contract template used
176176
in order_line"""
177-
self.order_line1._compute_auto_renew()
177+
self.order_line1.is_auto_renew = True
178178
self.sale.action_confirm()
179179
self.assertEqual(self.sale.contract_count, 2)
180180

181181
def test_onchange_product(self):
182182
"""It should get recurrence invoicing info to the sale line from
183183
its product"""
184-
self.order_line1._compute_auto_renew()
184+
self.order_line1.is_auto_renew = True
185185
self.assertEqual(
186186
self.order_line1.recurring_rule_type,
187187
self.product1.recurring_rule_type,

product_contract/views/sale_order.xml

+35-6
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,30 @@
6262
invisible="not is_contract"
6363
/>
6464
<group invisible="not is_contract">
65-
<field name="recurring_rule_type" />
65+
<label for="recurring_interval" />
66+
<div class="o_row">
67+
<field
68+
name="recurring_interval"
69+
readonly="product_uom_readonly"
70+
/>
71+
<field name="recurring_rule_type" />
72+
</div>
6673
</group>
6774
<group invisible="not is_contract">
6875
<field name="recurring_invoicing_type" />
6976
</group>
7077
<group invisible="not is_contract">
71-
<field name="date_start" required="is_contract" />
78+
<field
79+
name="date_start"
80+
required="is_contract"
81+
readonly="product_uom_readonly"
82+
/>
7283
</group>
7384
<group invisible="not is_contract">
74-
<field name="date_end" />
85+
<field name="date_end" readonly="product_uom_readonly" />
7586
</group>
7687
<group invisible="not is_contract">
77-
<field name="is_auto_renew" />
88+
<field name="is_auto_renew" readonly="product_uom_readonly" />
7889
</group>
7990
<group invisible="not is_auto_renew">
8091
<label for="auto_renew_interval" />
@@ -84,12 +95,14 @@
8495
class="oe_inline"
8596
nolabel="1"
8697
required="is_auto_renew"
98+
readonly="product_uom_readonly"
8799
/>
88100
<field
89101
name="auto_renew_rule_type"
90102
class="oe_inline"
91103
nolabel="1"
92104
required="is_auto_renew"
105+
readonly="product_uom_readonly"
93106
/>
94107
</div>
95108
</group>
@@ -113,29 +126,45 @@
113126
domain="[('contract_id','=',contract_id)]"
114127
optional="hide"
115128
/>
129+
<field
130+
name="recurring_interval"
131+
optional="hide"
132+
readonly="product_uom_readonly"
133+
/>
116134
<field name="recurring_rule_type" optional="hide" />
117135
<field name="recurring_invoicing_type" optional="hide" />
118136
<field name="contract_start_date_method" column_invisible="1" />
119137
<field
120138
name="date_start"
121139
optional="hide"
122140
required="is_contract and contract_start_date_method == 'manual'"
141+
readonly="product_uom_readonly"
142+
/>
143+
<field
144+
name="date_end"
145+
optional="hide"
146+
readonly="product_uom_readonly"
147+
/>
148+
<field
149+
name="is_auto_renew"
150+
optional="hide"
151+
readonly="product_uom_readonly"
123152
/>
124-
<field name="date_end" optional="hide" />
125-
<field name="is_auto_renew" optional="hide" />
126153
<field
127154
name="auto_renew_interval"
128155
class="oe_inline"
129156
nolabel="1"
130157
required="is_auto_renew"
131158
optional="hide"
159+
readonly="product_uom_readonly"
132160
/>
133161
<field
134162
name="auto_renew_rule_type"
135163
class="oe_inline"
136164
nolabel="1"
137165
required="is_auto_renew"
138166
optional="hide"
167+
readonly="product_uom_readonly"
139168
/>
140169
</xpath>
141170
</field>

0 commit comments

Comments
 (0)