[MIG] product_contract: Migration to 16.0

This commit is contained in:
Rad0van
2023-06-08 18:22:40 +02:00
parent b3f1fa3a39
commit a41cafe605
11 changed files with 109 additions and 90 deletions

View File

@@ -2,10 +2,13 @@
Recurring - Product Contract Recurring - Product Contract
============================ ============================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ad8724fbb6c54e3f450ed7f3b3aa16384ed79b097065f0de96cc56e87eef2e71
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status :target: https://odoo-community.org/page/development-status
@@ -14,14 +17,14 @@ Recurring - Product Contract
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github
:target: https://github.com/OCA/contract/tree/14.0/product_contract :target: https://github.com/OCA/contract/tree/16.0/product_contract
:alt: OCA/contract :alt: OCA/contract
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/contract-14-0/contract-14-0-product_contract :target: https://translation.odoo-community.org/projects/contract-16-0/contract-16-0-product_contract
:alt: Translate me on Weblate :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/110/14.0 :target: https://runboat.odoo-community.org/builds?repo=OCA/contract&target_branch=16.0
:alt: Try me on Runbot :alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5| |badge1| |badge2| |badge3| |badge4| |badge5|
@@ -51,8 +54,8 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/contract/issues>`_. Bugs are tracked on `GitHub Issues <https://github.com/OCA/contract/issues>`_.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/contract/issues/new?body=module:%20product_contract%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. `feedback <https://github.com/OCA/contract/issues/new?body=module:%20product_contract%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues. Do not contact contributors directly about support or help with technical issues.
@@ -96,6 +99,6 @@ Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-sbejaoui| |maintainer-sbejaoui|
This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/14.0/product_contract>`_ project on GitHub. This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/16.0/product_contract>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -4,7 +4,7 @@
{ {
"name": "Recurring - Product Contract", "name": "Recurring - Product Contract",
"version": "14.0.1.0.1", "version": "16.0.1.0.0",
"category": "Contract Management", "category": "Contract Management",
"license": "AGPL-3", "license": "AGPL-3",
"author": "LasLabs, " "ACSONE SA/NV, " "Odoo Community Association (OCA)", "author": "LasLabs, " "ACSONE SA/NV, " "Odoo Community Association (OCA)",

View File

@@ -3,7 +3,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models from odoo import Command, api, fields, models
class ContractLine(models.Model): class ContractLine(models.Model):
@@ -17,10 +17,10 @@ class ContractLine(models.Model):
copy=False, copy=False,
) )
def _prepare_invoice_line(self, move_form): def _prepare_invoice_line(self):
res = super(ContractLine, self)._prepare_invoice_line(move_form) res = super()._prepare_invoice_line()
if self.sale_order_line_id and res: if self.sale_order_line_id and res:
res["sale_line_ids"] = [(6, 0, [self.sale_order_line_id.id])] res["sale_line_ids"] = [Command.set([self.sale_order_line_id.id])]
return res return res
def _get_auto_renew_rule_type(self): def _get_auto_renew_rule_type(self):
@@ -37,9 +37,6 @@ class ContractLine(models.Model):
if rec.product_id.is_contract: if rec.product_id.is_contract:
rec.update( rec.update(
{ {
"recurring_rule_type": rec.product_id.recurring_rule_type,
"recurring_invoicing_type": rec.product_id.recurring_invoicing_type,
"recurring_interval": 1,
"is_auto_renew": rec.product_id.is_auto_renew, "is_auto_renew": rec.product_id.is_auto_renew,
"auto_renew_interval": rec.product_id.auto_renew_interval, "auto_renew_interval": rec.product_id.auto_renew_interval,
"auto_renew_rule_type": rec.product_id.auto_renew_rule_type, "auto_renew_rule_type": rec.product_id.auto_renew_rule_type,
@@ -51,3 +48,30 @@ class ContractLine(models.Model):
), ),
} }
) )
def _set_recurrence_field(self, field):
res = super()._set_recurrence_field(field)
for record in self:
if record.product_id.is_contract and field in record.product_id:
record[field] = record.product_id[field]
return res
@api.depends(
"contract_id.recurring_rule_type", "contract_id.line_recurrence", "product_id"
)
def _compute_recurring_rule_type(self):
return super()._compute_recurring_rule_type()
@api.depends(
"contract_id.recurring_invoicing_type",
"contract_id.line_recurrence",
"product_id",
)
def _compute_recurring_invoicing_type(self):
return super()._compute_recurring_invoicing_type()
@api.depends(
"contract_id.recurring_interval", "contract_id.line_recurrence", "product_id"
)
def _compute_recurring_interval(self):
return super()._compute_recurring_interval()

View File

@@ -68,12 +68,12 @@ class ProductTemplate(models.Model):
self.with_company(company).write( self.with_company(company).write(
{"property_contract_template_id": False} {"property_contract_template_id": False}
) )
super().write(vals) return super().write(vals)
@api.constrains("is_contract", "type") @api.constrains("is_contract", "type")
def _check_contract_product_type(self): def _check_contract_product_type(self):
""" """
Contract product should be service type Contract product should be service type
""" """
if self.is_contract and self.type != "service": if any([product.is_contract and product.type != "service" for product in self]):
raise ValidationError(_("Contract product should be service type")) raise ValidationError(_("Contract product should be service type"))

View File

@@ -14,7 +14,7 @@ class SaleOrder(models.Model):
need_contract_creation = fields.Boolean(compute="_compute_need_contract_creation") need_contract_creation = fields.Boolean(compute="_compute_need_contract_creation")
@api.constrains("state") @api.constrains("state")
def _check_contact_is_not_terminated(self): def _check_contract_is_not_terminated(self):
for rec in self: for rec in self:
if rec.state not in ( if rec.state not in (
"sale", "sale",
@@ -49,9 +49,7 @@ class SaleOrder(models.Model):
def _prepare_contract_value(self, contract_template): def _prepare_contract_value(self, contract_template):
self.ensure_one() self.ensure_one()
return { return {
"name": "{template_name}: {sale_name}".format( "name": f"{contract_template.name}: {self.name}",
template_name=contract_template.name, sale_name=self.name
),
"partner_id": self.partner_id.id, "partner_id": self.partner_id.id,
"company_id": self.company_id.id, "company_id": self.company_id.id,
"contract_template_id": contract_template.id, "contract_template_id": contract_template.id,
@@ -59,7 +57,7 @@ class SaleOrder(models.Model):
"payment_term_id": self.payment_term_id.id, "payment_term_id": self.payment_term_id.id,
"fiscal_position_id": self.fiscal_position_id.id, "fiscal_position_id": self.fiscal_position_id.id,
"invoice_partner_id": self.partner_invoice_id.id, "invoice_partner_id": self.partner_invoice_id.id,
"line_recurrence": self.partner_invoice_id.id, "line_recurrence": True,
} }
def action_create_contract(self): def action_create_contract(self):
@@ -84,8 +82,13 @@ class SaleOrder(models.Model):
raise ValidationError( raise ValidationError(
_( _(
"You must specify a contract " "You must specify a contract "
"template for '{}' product in '{}' company." "template for '%(product_name)s' product "
).format(order_line.product_id.name, rec.company_id.name) "in '%(company_name)s' company."
)
% {
"product_name": order_line.product_id.name,
"company_name": rec.company_id.name,
}
) )
contract_templates |= contract_template contract_templates |= contract_template
for contract_template in contract_templates: for contract_template in contract_templates:
@@ -98,7 +101,7 @@ class SaleOrder(models.Model):
contract = contract_model.create( contract = contract_model.create(
rec._prepare_contract_value(contract_template) rec._prepare_contract_value(contract_template)
) )
contracts.append(contract) contracts.append(contract.id)
contract._onchange_contract_template_id() contract._onchange_contract_template_id()
contract._onchange_contract_type() contract._onchange_contract_type()
order_lines.create_contract_line(contract) order_lines.create_contract_line(contract)
@@ -112,7 +115,7 @@ class SaleOrder(models.Model):
self.filtered( self.filtered(
lambda order: (order.company_id.create_contract_at_sale_order_confirmation) lambda order: (order.company_id.create_contract_at_sale_order_confirmation)
).action_create_contract() ).action_create_contract()
return super(SaleOrder, self).action_confirm() return super().action_confirm()
@api.depends("order_line") @api.depends("order_line")
def _compute_contract_count(self): def _compute_contract_count(self):

View File

@@ -43,8 +43,8 @@ class SaleOrderLine(models.Model):
help="Specify if process date is 'from' or 'to' invoicing date", help="Specify if process date is 'from' or 'to' invoicing date",
copy=False, copy=False,
) )
date_start = fields.Date(string="Date Start") date_start = fields.Date()
date_end = fields.Date(string="Date End") date_end = fields.Date()
contract_line_id = fields.Many2one( contract_line_id = fields.Many2one(
comodel_name="contract.line", comodel_name="contract.line",
@@ -93,7 +93,7 @@ class SaleOrderLine(models.Model):
_("You can't upsell or downsell a terminated contract") _("You can't upsell or downsell a terminated contract")
) )
@api.depends("product_id") @api.depends("product_id", "order_id.company_id")
def _compute_contract_template_id(self): def _compute_contract_template_id(self):
for rec in self: for rec in self:
rec.contract_template_id = rec.product_id.with_company( rec.contract_template_id = rec.product_id.with_company(
@@ -141,21 +141,13 @@ class SaleOrderLine(models.Model):
rec.date_end = rec._get_date_end() if rec.date_start else False rec.date_end = rec._get_date_end() if rec.date_start else False
def _get_contract_line_qty(self): def _get_contract_line_qty(self):
"""Returns the quantity to be put on new contract lines.""" """Returns the amount that will be placed in new contract lines."""
self.ensure_one() self.ensure_one()
# The quantity on the generated contract line is 1, as it # The quantity in the generated contract line is the quantity of
# correspond to the most common use cases: # product requested in the order, since they correspond to the most common
# - quantity on the SO line = number of periods sold and unit # use cases.
# 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. # Other use cases are easy to implement by overriding this method.
return 1.0 return self.product_uom_qty
def _prepare_contract_line_values( def _prepare_contract_line_values(
self, contract, predecessor_contract_line_id=False self, contract, predecessor_contract_line_id=False
@@ -198,7 +190,7 @@ class SaleOrderLine(models.Model):
"contract_id": contract.id, "contract_id": contract.id,
"sale_order_line_id": self.id, "sale_order_line_id": self.id,
"predecessor_contract_line_id": predecessor_contract_line_id, "predecessor_contract_line_id": predecessor_contract_line_id,
"analytic_account_id": self.order_id.analytic_account_id.id, "analytic_distribution": self.analytic_distribution,
} }
def create_contract_line(self, contract): def create_contract_line(self, contract):
@@ -269,17 +261,11 @@ class SaleOrderLine(models.Model):
SaleOrderLine, self.filtered(lambda l: not l.contract_id) SaleOrderLine, self.filtered(lambda l: not l.contract_id)
).invoice_line_create(invoice_id, qty) ).invoice_line_create(invoice_id, qty)
@api.depends( @api.depends("qty_invoiced", "qty_delivered", "product_uom_qty", "state")
"qty_invoiced", def _compute_qty_to_invoice(self):
"qty_delivered",
"product_uom_qty",
"order_id.state",
"product_id.is_contract",
)
def _get_to_invoice_qty(self):
""" """
sale line linked to contracts must not be invoiced from sale order sale line linked to contracts must not be invoiced from sale order
""" """
res = super()._get_to_invoice_qty() res = super()._compute_qty_to_invoice()
self.filtered("product_id.is_contract").update({"qty_to_invoice": 0.0}) self.filtered("product_id.is_contract").update({"qty_to_invoice": 0.0})
return res return res

View File

@@ -3,18 +3,18 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Recurring - Product Contract</title> <title>Recurring - Product Contract</title>
<style type="text/css"> <style type="text/css">
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ :Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet. customize this style sheet.
*/ */
@@ -366,26 +366,28 @@ ul.auto-toc {
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! <!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ad8724fbb6c54e3f450ed7f3b3aa16384ed79b097065f0de96cc56e87eef2e71
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/contract/tree/14.0/product_contract"><img alt="OCA/contract" src="https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/contract-14-0/contract-14-0-product_contract"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/110/14.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/contract/tree/16.0/product_contract"><img alt="OCA/contract" src="https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/contract-16-0/contract-16-0-product_contract"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/contract&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module adds support for products to be linked to contract templates.</p> <p>This module adds support for products to be linked to contract templates.</p>
<p>A contract is created on <tt class="docutils literal">sale.order</tt> confirmation for each different template used in sale order line where recurrence details are set too.</p> <p>A contract is created on <tt class="docutils literal">sale.order</tt> confirmation for each different template used in sale order line where recurrence details are set too.</p>
<p>Contract product are ignored on invoicing process and pass to nothing to invoice directly.</p> <p>Contract product are ignored on invoicing process and pass to nothing to invoice directly.</p>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li> <li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li> <li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul> <li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li> <li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li> <li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li> <li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="usage"> <div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1> <h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>To use this module, you need to:</p> <p>To use this module, you need to:</p>
<ol class="arabic simple"> <ol class="arabic simple">
<li>Go to Sales -&gt; Products and select or create a product.</li> <li>Go to Sales -&gt; Products and select or create a product.</li>
@@ -395,24 +397,24 @@ product</li>
</ol> </ol>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1> <h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/contract/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/contract/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/contract/issues/new?body=module:%20product_contract%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> <a class="reference external" href="https://github.com/OCA/contract/issues/new?body=module:%20product_contract%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
<h1><a class="toc-backref" href="#id3">Credits</a></h1> <h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors"> <div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2> <h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple"> <ul class="simple">
<li>LasLabs</li> <li>LasLabs</li>
<li>ACSONE SA/NV</li> <li>ACSONE SA/NV</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2> <h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple"> <ul class="simple">
<li>Ted Salmon &lt;<a class="reference external" href="mailto:tsalmon&#64;laslabs.com">tsalmon&#64;laslabs.com</a>&gt;</li> <li>Ted Salmon &lt;<a class="reference external" href="mailto:tsalmon&#64;laslabs.com">tsalmon&#64;laslabs.com</a>&gt;</li>
<li>Souheil Bejaoui &lt;<a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu">souheil.bejaoui&#64;acsone.eu</a>&gt;</li> <li>Souheil Bejaoui &lt;<a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu">souheil.bejaoui&#64;acsone.eu</a>&gt;</li>
@@ -424,15 +426,15 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2> <h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p> <p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> <a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p> <p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external" href="https://github.com/sbejaoui"><img alt="sbejaoui" src="https://github.com/sbejaoui.png?size=40px" /></a></p> <p><a class="reference external image-reference" href="https://github.com/sbejaoui"><img alt="sbejaoui" src="https://github.com/sbejaoui.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/contract/tree/14.0/product_contract">OCA/contract</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/OCA/contract/tree/16.0/product_contract">OCA/contract</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> <p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div> </div>
</div> </div>

View File

@@ -3,10 +3,10 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tests.common import SavepointCase from odoo.tests.common import TransactionCase
class TestProductTemplate(SavepointCase): class TestProductTemplate(TransactionCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()

View File

@@ -6,10 +6,10 @@ from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.fields import Date from odoo.fields import Date
from odoo.tests.common import SavepointCase from odoo.tests.common import TransactionCase
class TestSaleOrder(SavepointCase): class TestSaleOrder(TransactionCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()
@@ -143,7 +143,9 @@ class TestSaleOrder(SavepointCase):
self.assertEqual(self.order_line1.invoice_status, "no") self.assertEqual(self.order_line1.invoice_status, "no")
invoice = self.order_line1.contract_id.recurring_create_invoice() invoice = self.order_line1.contract_id.recurring_create_invoice()
self.assertTrue(invoice) self.assertTrue(invoice)
self.assertEqual(self.order_line1.qty_invoiced, 1) self.assertEqual(
self.order_line1.qty_invoiced, self.order_line1.product_uom_qty
)
self.assertEqual(self.order_line1.qty_to_invoice, 0) self.assertEqual(self.order_line1.qty_to_invoice, 0)
def test_action_confirm_without_contract_creation(self): def test_action_confirm_without_contract_creation(self):
@@ -342,7 +344,7 @@ class TestSaleOrder(SavepointCase):
self.order_line1.contract_id = self.contract self.order_line1.contract_id = self.contract
self.sale.action_confirm() self.sale.action_confirm()
self.contract.is_terminated = True self.contract.is_terminated = True
self.sale.action_cancel() self.sale._action_cancel()
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.sale.action_draft() self.sale.action_draft()
self.contract.is_terminated = False self.contract.is_terminated = False

View File

@@ -10,7 +10,7 @@
<field name="inherit_id" ref="sale.view_order_form" /> <field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//header" position="inside"> <xpath expr="//header" position="inside">
<field name="need_contract_creation" attrs="{'invisible': []}" /> <field name="need_contract_creation" invisible="1" />
<button <button
name="action_create_contract" name="action_create_contract"
string="Create Contracts" string="Create Contracts"
@@ -31,21 +31,18 @@
</button> </button>
</xpath> </xpath>
<xpath expr="//field[@name='order_line']" position="before"> <xpath expr="//field[@name='order_line']" position="before">
<field name="is_contract" attrs="{'invisible': []}" /> <field name="is_contract" invisible="1" />
</xpath> </xpath>
<xpath <xpath
expr="//field[@name='order_line']/form//field[@name='product_id']" expr="//field[@name='order_line']/form//field[@name='product_id']"
position="after" position="after"
> >
<field name="contract_template_id" attrs="{'invisible': []}" /> <field name="contract_template_id" invisible="1" />
<field <field
name="contract_id" name="contract_id"
options='{"no_create": True}' options='{"no_create": True}'
attrs="{'invisible': [('is_contract', '=', False)]}" attrs="{'invisible': [('is_contract', '=', False)]}"
domain="['|',('contract_template_id','=',contract_template_id), domain="['|',('contract_template_id','=',contract_template_id), ('contract_template_id','=',False), ('partner_id','=',parent.partner_id), ('is_terminated','=',False),
('contract_template_id','=',False),
('partner_id','=',parent.partner_id),
('is_terminated','=',False),
]" ]"
/> />
<field <field
@@ -58,7 +55,7 @@
expr="//field[@name='order_line']/form//field[@name='tax_id']/parent::group" expr="//field[@name='order_line']/form//field[@name='tax_id']/parent::group"
position="after" position="after"
> >
<field name="is_contract" attrs="{'invisible': []}" /> <field name="is_contract" invisible="1" />
<separator <separator
colspan="4" colspan="4"
string="Recurrence Invoicing" string="Recurrence Invoicing"

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
# generated from manifests external_dependencies
python-dateutil