mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[MIG] product_contract: Migration to 14.0
This commit is contained in:
@@ -7,6 +7,7 @@ from collections import namedtuple
|
||||
from datetime import timedelta
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from freezegun import freeze_time
|
||||
|
||||
from odoo import fields
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
@@ -2370,6 +2371,7 @@ class TestContract(TestContractBase):
|
||||
to_date("2018-02-13"),
|
||||
)
|
||||
|
||||
@freeze_time("2020-01-01 00:00:00")
|
||||
def test_recurrency_propagation(self):
|
||||
# Existing contract
|
||||
vals = {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{
|
||||
"name": "Recurring - Product Contract",
|
||||
"version": "13.0.1.0.0",
|
||||
"version": "14.0.1.0.0",
|
||||
"category": "Contract Management",
|
||||
"license": "AGPL-3",
|
||||
"author": "LasLabs, " "ACSONE SA/NV, " "Odoo Community Association (OCA)",
|
||||
|
||||
@@ -65,7 +65,7 @@ class ProductTemplate(models.Model):
|
||||
def write(self, vals):
|
||||
if "is_contract" in vals and vals["is_contract"] is False:
|
||||
for company in self.env["res.company"].search([]):
|
||||
self.with_context(force_company=company.id).write(
|
||||
self.with_company(company).write(
|
||||
{"property_contract_template_id": False}
|
||||
)
|
||||
super().write(vals)
|
||||
|
||||
@@ -16,15 +16,11 @@ class SaleOrder(models.Model):
|
||||
@api.constrains("state")
|
||||
def check_contact_is_not_terminated(self):
|
||||
for rec in self:
|
||||
if (
|
||||
rec.state
|
||||
not in (
|
||||
if rec.state not in (
|
||||
"sale",
|
||||
"done",
|
||||
"cancel",
|
||||
)
|
||||
and rec.order_line.filtered("contract_id.is_terminated")
|
||||
):
|
||||
) and rec.order_line.filtered("contract_id.is_terminated"):
|
||||
raise ValidationError(
|
||||
_("You can't upsell or downsell a terminated contract")
|
||||
)
|
||||
@@ -81,8 +77,8 @@ class SaleOrder(models.Model):
|
||||
)
|
||||
contract_templates = self.env["contract.template"]
|
||||
for order_line in line_to_create_contract:
|
||||
contract_template = order_line.product_id.with_context(
|
||||
force_company=rec.company_id.id
|
||||
contract_template = order_line.product_id.with_company(
|
||||
rec.company_id
|
||||
).property_contract_template_id
|
||||
if not contract_template:
|
||||
raise ValidationError(
|
||||
@@ -94,8 +90,8 @@ class SaleOrder(models.Model):
|
||||
contract_templates |= contract_template
|
||||
for contract_template in contract_templates:
|
||||
order_lines = line_to_create_contract.filtered(
|
||||
lambda r, template=contract_template: r.product_id.with_context(
|
||||
force_company=r.order_id.company_id.id
|
||||
lambda r, template=contract_template: r.product_id.with_company(
|
||||
r.order_id.company_id
|
||||
).property_contract_template_id
|
||||
== template
|
||||
)
|
||||
@@ -112,7 +108,7 @@ class SaleOrder(models.Model):
|
||||
return contracts
|
||||
|
||||
def action_confirm(self):
|
||||
""" If we have a contract in the order, set it up """
|
||||
"""If we have a contract in the order, set it up"""
|
||||
self.filtered(
|
||||
lambda order: (order.company_id.create_contract_at_sale_order_confirmation)
|
||||
).action_create_contract()
|
||||
@@ -127,7 +123,7 @@ class SaleOrder(models.Model):
|
||||
|
||||
def action_show_contracts(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref("contract.action_customer_contract").read()[0]
|
||||
action = self.env.ref("contract.action_customer_contract").sudo().read()[0]
|
||||
contracts = (
|
||||
self.env["contract.line"]
|
||||
.search([("sale_order_line_id", "in", self.order_line.ids)])
|
||||
|
||||
@@ -84,8 +84,8 @@ class SaleOrderLine(models.Model):
|
||||
@api.depends("product_id")
|
||||
def _compute_contract_template_id(self):
|
||||
for rec in self:
|
||||
rec.contract_template_id = rec.product_id.with_context(
|
||||
force_company=rec.order_id.company_id.id
|
||||
rec.contract_template_id = rec.product_id.with_company(
|
||||
rec.order_id.company_id
|
||||
).property_contract_template_id
|
||||
|
||||
def _get_auto_renew_rule_type(self):
|
||||
@@ -95,9 +95,21 @@ class SaleOrderLine(models.Model):
|
||||
return "monthly"
|
||||
return self.recurring_rule_type
|
||||
|
||||
def _get_date_end(self):
|
||||
self.ensure_one()
|
||||
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),
|
||||
)
|
||||
- relativedelta(days=1)
|
||||
)
|
||||
return date_end
|
||||
|
||||
@api.onchange("product_id")
|
||||
def onchange_product(self):
|
||||
contract_line_model = self.env["contract.line"]
|
||||
for rec in self:
|
||||
if rec.product_id.is_contract:
|
||||
rec.product_uom_qty = rec.product_id.default_qty
|
||||
@@ -105,14 +117,7 @@ class SaleOrderLine(models.Model):
|
||||
rec.recurring_invoicing_type = rec.product_id.recurring_invoicing_type
|
||||
rec.date_start = rec.date_start or fields.Date.today()
|
||||
|
||||
rec.date_end = (
|
||||
rec.date_start
|
||||
+ contract_line_model.get_relative_delta(
|
||||
rec._get_auto_renew_rule_type(),
|
||||
int(rec.product_uom_qty),
|
||||
)
|
||||
- relativedelta(days=1)
|
||||
)
|
||||
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
|
||||
@@ -120,19 +125,25 @@ class SaleOrderLine(models.Model):
|
||||
|
||||
@api.onchange("date_start", "product_uom_qty", "recurring_rule_type")
|
||||
def onchange_date_start(self):
|
||||
contract_line_model = self.env["contract.line"]
|
||||
for rec in self.filtered("product_id.is_contract"):
|
||||
if not rec.date_start:
|
||||
rec.date_end = False
|
||||
else:
|
||||
rec.date_end = (
|
||||
rec.date_start
|
||||
+ contract_line_model.get_relative_delta(
|
||||
rec._get_auto_renew_rule_type(),
|
||||
int(rec.product_uom_qty),
|
||||
)
|
||||
- relativedelta(days=1)
|
||||
)
|
||||
rec.date_end = rec._get_date_end() if rec.date_start else False
|
||||
|
||||
def _get_contract_line_qty(self):
|
||||
"""Returns the quantity to be put on new contract lines."""
|
||||
self.ensure_one()
|
||||
# The quantity on the generated contract line is 1, as it
|
||||
# correspond to the most common use cases:
|
||||
# - quantity on the SO line = number of periods sold and unit
|
||||
# price the price of one period, so the
|
||||
# total amount of the SO corresponds to the planned value
|
||||
# of the contract; in this case the quantity on the contract
|
||||
# line must be 1
|
||||
# - quantity on the SO line = number of hours sold,
|
||||
# automatic invoicing of the actual hours through a variable
|
||||
# quantity formula, in which case the quantity on the contract
|
||||
# line is not used
|
||||
# Other use cases are easy to implement by overriding this method.
|
||||
return 1.0
|
||||
|
||||
def _prepare_contract_line_values(
|
||||
self, contract, predecessor_contract_line_id=False
|
||||
@@ -157,19 +168,7 @@ class SaleOrderLine(models.Model):
|
||||
"sequence": self.sequence,
|
||||
"product_id": self.product_id.id,
|
||||
"name": self.name,
|
||||
# The quantity on the generated contract line is 1, as it
|
||||
# correspond to the most common use cases:
|
||||
# - quantity on the SO line = number of periods sold and unit
|
||||
# price the price of one period, so the
|
||||
# total amount of the SO corresponds to the planned value
|
||||
# of the contract; in this case the quantity on the contract
|
||||
# line must be 1
|
||||
# - quantity on the SO line = number of hours sold,
|
||||
# automatic invoicing of the actual hours through a variable
|
||||
# quantity formula, in which case the quantity on the contract
|
||||
# line is not used
|
||||
# Other use cases are easy to implement by overriding this method.
|
||||
"quantity": 1.0,
|
||||
"quantity": self._get_contract_line_qty(),
|
||||
"uom_id": self.product_uom.id,
|
||||
"price_unit": self.price_unit,
|
||||
"discount": self.discount,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.fields import Date
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
@@ -39,7 +39,7 @@ class TestSaleOrder(TransactionCase):
|
||||
],
|
||||
}
|
||||
)
|
||||
self.product1.with_context(force_company=self.sale.company_id.id).write(
|
||||
self.product1.with_company(self.sale.company_id).write(
|
||||
{
|
||||
"is_contract": True,
|
||||
"default_qty": 12,
|
||||
@@ -48,7 +48,7 @@ class TestSaleOrder(TransactionCase):
|
||||
"property_contract_template_id": self.contract_template1.id,
|
||||
}
|
||||
)
|
||||
self.product2.with_context(force_company=self.sale.company_id.id).write(
|
||||
self.product2.with_company(self.sale.company_id).write(
|
||||
{
|
||||
"is_contract": True,
|
||||
"property_contract_template_id": self.contract_template2.id,
|
||||
@@ -116,26 +116,16 @@ class TestSaleOrder(TransactionCase):
|
||||
other_company = self.env["res.company"].create(
|
||||
{"name": "other company", "parent_id": self.sale.company_id.id}
|
||||
)
|
||||
with self.assertRaises(UserError):
|
||||
self.sale.company_id = other_company
|
||||
with self.assertRaises(ValidationError):
|
||||
self.sale.action_confirm()
|
||||
|
||||
def test_change_sale_company_2(self):
|
||||
"""Contract company must be the sale order company."""
|
||||
self.assertTrue(self.sale.company_id)
|
||||
other_company = self.env["res.company"].create(
|
||||
{"name": "other company", "parent_id": self.sale.company_id.id}
|
||||
)
|
||||
self.product1.with_context(
|
||||
force_company=other_company.id
|
||||
).property_contract_template_id = self.contract_template1
|
||||
self.product2.with_context(
|
||||
force_company=other_company.id
|
||||
).property_contract_template_id = self.contract_template2
|
||||
self.sale.company_id = other_company
|
||||
self.sale.action_confirm()
|
||||
contracts = self.sale.order_line.mapped("contract_id")
|
||||
self.assertEqual(contracts.mapped("company_id"), other_company)
|
||||
self.assertEqual(contracts.mapped("company_id"), self.sale.company_id)
|
||||
|
||||
def test_sale_order_invoice_status(self):
|
||||
"""
|
||||
@@ -353,7 +343,7 @@ class TestSaleOrder(TransactionCase):
|
||||
def test_order_lines_with_the_same_contract_template(self):
|
||||
"""It should create one contract with two lines grouped by contract
|
||||
template"""
|
||||
self.product2.with_context(force_company=self.sale.company_id.id).write(
|
||||
self.product2.with_company(self.sale.company_id).write(
|
||||
{
|
||||
"is_contract": True,
|
||||
"property_contract_template_id": self.contract_template1.id,
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
# generated from manifests external_dependencies
|
||||
python-dateutil
|
||||
|
||||
1
setup/product_contract/odoo/addons/product_contract
Symbolic link
1
setup/product_contract/odoo/addons/product_contract
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../product_contract
|
||||
6
setup/product_contract/setup.py
Normal file
6
setup/product_contract/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
Reference in New Issue
Block a user