Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[17.0][FIX] product_contract: Compute date_start and date_end correctly. Make fields computed #1188

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions product_contract/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ To use this module, you need to:
Known issues / Roadmap
======================

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

Bug Tracker
===========
Expand All @@ -90,15 +90,16 @@ Authors
Contributors
------------

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

- Ernesto Tejeda
- Pedro M. Baeza
- Carlos Roca
- Ernesto Tejeda
- Pedro M. Baeza
- Carlos Roca
- Sergio Teruel

- David Jaen <[email protected]>
- David Jaen <[email protected]>

Maintainers
-----------
Expand Down
112 changes: 71 additions & 41 deletions product_contract/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,32 @@ class SaleOrderLine(models.Model):
string="Contract Template",
compute="_compute_contract_template_id",
)
recurring_interval = fields.Integer(
default=1,
string="Invoice Every",
help="Invoice every (Days/Week/Month/Year)",
)
recurring_rule_type = fields.Selection(related="product_id.recurring_rule_type")
recurring_invoicing_type = fields.Selection(
related="product_id.recurring_invoicing_type"
)
date_start = fields.Date()
date_end = fields.Date()

date_start = fields.Date(
compute="_compute_date_start", readonly=False, store=True, precompute=True
)
date_end = fields.Date(
compute="_compute_date_end", readonly=False, store=True, precompute=True
)
contract_line_id = fields.Many2one(
comodel_name="contract.line",
string="Contract Line to replace",
required=False,
copy=False,
)
is_auto_renew = fields.Boolean(
string="Auto Renew",
compute="_compute_auto_renew",
default=False,
store=True,
readonly=False,
precompute=True,
)
auto_renew_interval = fields.Integer(
default=1,
Expand All @@ -57,6 +64,7 @@ class SaleOrderLine(models.Model):
store=True,
readonly=False,
help="Renew every (Days/Week/Month/Year)",
precompute=True,
)
auto_renew_rule_type = fields.Selection(
[
Expand All @@ -71,6 +79,7 @@ class SaleOrderLine(models.Model):
readonly=False,
string="Renewal type",
help="Specify Interval for automatic renewal.",
precompute=True,
)
contract_start_date_method = fields.Selection(
related="product_id.contract_start_date_method"
Expand All @@ -97,47 +106,68 @@ def _compute_contract_template_id(self):
rec.order_id.company_id
).property_contract_template_id

def _get_auto_renew_rule_type(self):
"""monthly last day don't make sense for auto_renew_rule_type"""
self.ensure_one()
if self.recurring_rule_type == "monthlylastday":
return "monthly"
return self.recurring_rule_type
@api.depends("product_id")
def _compute_date_start(self):
for sol in self:
if sol.contract_start_date_method == "start_this":
sol.date_start = sol.order_id.date_order.replace(day=1)
elif sol.contract_start_date_method == "end_this":
sol.date_start = (
sol.order_id.date_order
+ self.get_relative_delta(
sol.recurring_rule_type, sol.product_id.default_qty
)
).replace(day=1) - relativedelta(days=1)
elif sol.contract_start_date_method == "start_next":
# Dia 1 del siguiente recurring_rule_type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please avoid spanglish?

sol.date_start = (
sol.order_id.date_order
+ self.get_relative_delta(
sol.recurring_rule_type, sol.product_id.default_qty
)
).replace(day=1)
elif sol.contract_start_date_method == "end_next":
# Last day of next recurring period
sol.date_start = (
sol.order_id.date_order
+ self.get_relative_delta(
sol.recurring_rule_type, sol.product_id.default_qty + 1
)
).replace(day=1) - relativedelta(days=1)
else:
# Manual method
sol.date_start = False

def _get_date_end(self):
self.ensure_one()
contract_start_date_method = self.product_id.contract_start_date_method
date_end = False
if contract_start_date_method == "manual":
contract_line_model = self.env["contract.line"]
date_end = (
self.date_start
+ contract_line_model.get_relative_delta(
self._get_auto_renew_rule_type(),
int(self.product_uom_qty),
@api.depends(
"is_auto_renew",
"date_start",
"auto_renew_interval",
"auto_renew_rule_type",
)
def _compute_date_end(self):
for sol in self:
if sol.is_auto_renew and sol.date_start:
sol.date_end = self.env["contract.line"]._get_first_date_end(
sol.date_start,
sol.auto_renew_rule_type,
sol.auto_renew_interval,
)
- relativedelta(days=1)
)
return date_end
else:
sol.date_end = False

@api.model
def get_relative_delta(self, recurring_rule_type, interval):
return self.env["contract.recurrency.mixin"].get_relative_delta(
recurring_rule_type, interval
)

@api.depends("product_id")
def _compute_auto_renew(self):
for rec in self:
if rec.product_id.is_contract:
rec.product_uom_qty = rec.product_id.default_qty
contract_start_date_method = rec.product_id.contract_start_date_method
if contract_start_date_method == "manual":
rec.date_start = rec.date_start or fields.Date.today()
rec.date_end = rec._get_date_end()
rec.is_auto_renew = rec.product_id.is_auto_renew
if rec.is_auto_renew:
rec.auto_renew_interval = rec.product_id.auto_renew_interval
rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type

@api.onchange("date_start", "product_uom_qty")
def onchange_date_start(self):
for rec in self.filtered("product_id.is_contract"):
rec.date_end = rec._get_date_end() if rec.date_start else False
rec.product_uom_qty = rec.product_id.default_qty
rec.is_auto_renew = rec.product_id.is_auto_renew
rec.auto_renew_interval = rec.product_id.auto_renew_interval
rec.auto_renew_rule_type = rec.product_id.auto_renew_rule_type

def _get_contract_line_qty(self):
"""Returns the amount that will be placed in new contract lines."""
Expand Down Expand Up @@ -178,7 +208,7 @@ def _prepare_contract_line_values(
"date_end": self.date_end,
"date_start": self.date_start or fields.Date.today(),
"recurring_next_date": recurring_next_date,
"recurring_interval": 1,
"recurring_interval": self.recurring_interval or 1,
"recurring_invoicing_type": self.recurring_invoicing_type,
"recurring_rule_type": self.recurring_rule_type,
"is_auto_renew": self.is_auto_renew,
Expand Down
1 change: 1 addition & 0 deletions product_contract/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
- Ernesto Tejeda
- Pedro M. Baeza
- Carlos Roca
- Sergio Teruel
- David Jaen \<<[email protected]>\>
1 change: 1 addition & 0 deletions product_contract/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ <h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<li>Ernesto Tejeda</li>
<li>Pedro M. Baeza</li>
<li>Carlos Roca</li>
<li>Sergio Teruel</li>
</ul>
</li>
<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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class ProductContractConfiguratorController extends formView.Controller {
is_auto_renew,
auto_renew_interval,
auto_renew_rule_type,
recurring_interval,
} = record.data;
return this.action.doAction({
type: "ir.actions.act_window_close",
Expand All @@ -34,6 +35,7 @@ export class ProductContractConfiguratorController extends formView.Controller {
is_auto_renew,
auto_renew_interval,
auto_renew_rule_type,
recurring_interval,
},
},
});
Expand Down
13 changes: 10 additions & 3 deletions product_contract/static/src/js/sale_product_field.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,31 @@ patch(SaleOrderLineProductField.prototype, {
return super.isConfigurableLine || this.props.record.data.is_contract;
},

async _openContractConfigurator(isNew = false) {
const actionContext = {
get contractContext() {
return {
default_product_id: this.props.record.data.product_id[0],
default_partner_id: this.props.record.model.root.data.partner_id[0],
default_company_id: this.props.record.model.root.data.company_id[0],
default_product_uom_qty: this.props.record.data.product_uom_qty,
default_contract_id: this.props.record.data.contract_id[0],
default_recurring_interval: this.props.record.data.recurring_interval,
default_date_start: this.props.record.data.date_start,
default_date_end: this.props.record.data.date_end,
default_is_auto_renew: this.props.record.data.is_auto_renew,
default_auto_renew_interval: this.props.record.data.auto_renew_interval,
default_auto_renew_rule_type: this.props.record.data.auto_renew_rule_type,
};
},

async _openContractConfigurator(isNew = false) {
const actionContext = this.contractContext;
this.action.doAction("product_contract.product_contract_configurator_action", {
additionalContext: actionContext,
onClose: async (closeInfo) => {
if (closeInfo && !closeInfo.special) {
this.props.record.update(closeInfo.productContractConfiguration);
this.props.record._update(closeInfo.productContractConfiguration, {
withoutOnchange: true,
});
} else if (isNew) {
this.props.record.update({
[this.props.name]: undefined,
Expand Down
8 changes: 4 additions & 4 deletions product_contract/tests/test_sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def test_compute_is_contract(self):
def test_action_confirm(self):
"""It should create a contract for each contract template used in
order_line"""
self.order_line1._compute_auto_renew()
self.order_line1.is_auto_renew = True
self.sale.action_confirm()
contracts = self.sale.order_line.mapped("contract_id")
self.assertEqual(len(contracts), 2)
Expand Down Expand Up @@ -155,7 +155,7 @@ def test_action_confirm_without_contract_creation(self):
"""It should create a contract for each contract template used in
order_line"""
self.sale.company_id.create_contract_at_sale_order_confirmation = False
self.order_line1._compute_auto_renew()
self.order_line1.is_auto_renew = True
self.sale.action_confirm()
self.assertEqual(len(self.sale.order_line.mapped("contract_id")), 0)
self.assertTrue(self.sale.need_contract_creation)
Expand All @@ -174,14 +174,14 @@ def test_action_confirm_without_contract_creation(self):
def test_sale_contract_count(self):
"""It should count contracts as many different contract template used
in order_line"""
self.order_line1._compute_auto_renew()
self.order_line1.is_auto_renew = True
self.sale.action_confirm()
self.assertEqual(self.sale.contract_count, 2)

def test_onchange_product(self):
"""It should get recurrence invoicing info to the sale line from
its product"""
self.order_line1._compute_auto_renew()
self.order_line1.is_auto_renew = True
self.assertEqual(
self.order_line1.recurring_rule_type,
self.product1.recurring_rule_type,
Expand Down
41 changes: 35 additions & 6 deletions product_contract/views/sale_order.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,30 @@
invisible="not is_contract"
/>
<group invisible="not is_contract">
<field name="recurring_rule_type" />
<label for="recurring_interval" />
<div class="o_row">
<field
name="recurring_interval"
readonly="product_uom_readonly"
/>
<field name="recurring_rule_type" />
</div>
</group>
<group invisible="not is_contract">
<field name="recurring_invoicing_type" />
</group>
<group invisible="not is_contract">
<field name="date_start" required="is_contract" />
<field
name="date_start"
required="is_contract"
readonly="product_uom_readonly"
/>
</group>
<group invisible="not is_contract">
<field name="date_end" />
<field name="date_end" readonly="product_uom_readonly" />
</group>
<group invisible="not is_contract">
<field name="is_auto_renew" />
<field name="is_auto_renew" readonly="product_uom_readonly" />
</group>
<group invisible="not is_auto_renew">
<label for="auto_renew_interval" />
Expand All @@ -84,12 +95,14 @@
class="oe_inline"
nolabel="1"
required="is_auto_renew"
readonly="product_uom_readonly"
/>
<field
name="auto_renew_rule_type"
class="oe_inline"
nolabel="1"
required="is_auto_renew"
readonly="product_uom_readonly"
/>
</div>
</group>
Expand All @@ -113,29 +126,45 @@
domain="[('contract_id','=',contract_id)]"
optional="hide"
/>
<field
name="recurring_interval"
optional="hide"
readonly="product_uom_readonly"
/>
<field name="recurring_rule_type" optional="hide" />
<field name="recurring_invoicing_type" optional="hide" />
<field name="contract_start_date_method" column_invisible="1" />
<field
name="date_start"
optional="hide"
required="is_contract and contract_start_date_method == 'manual'"
readonly="product_uom_readonly"
/>
<field
name="date_end"
optional="hide"
readonly="product_uom_readonly"
/>
<field
name="is_auto_renew"
optional="hide"
readonly="product_uom_readonly"
/>
<field name="date_end" optional="hide" />
<field name="is_auto_renew" optional="hide" />
<field
name="auto_renew_interval"
class="oe_inline"
nolabel="1"
required="is_auto_renew"
optional="hide"
readonly="product_uom_readonly"
/>
<field
name="auto_renew_rule_type"
class="oe_inline"
nolabel="1"
required="is_auto_renew"
optional="hide"
readonly="product_uom_readonly"
/>
</xpath>
</field>
Expand Down
Loading
Loading