[14.0][IMP] contract_sale_generation

Use the generation_type field defined now in contract base module.

Improve tests
This commit is contained in:
Denis Roussel
2021-11-07 10:08:41 +01:00
parent 0fe90c96ad
commit 897ff24882
11 changed files with 119 additions and 110 deletions

View File

@@ -14,18 +14,18 @@ Contracts Management - Recurring Sales
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcontract-lightgray.png?logo=github
:target: https://github.com/OCA/contract/tree/12.0/contract_sale_generation
:target: https://github.com/OCA/contract/tree/14.0/contract_sale_generation
:alt: OCA/contract
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/contract-12-0/contract-12-0-contract_sale_generation
:target: https://translation.odoo-community.org/projects/contract-14-0/contract-14-0-contract_sale_generation
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/110/12.0
:target: https://runbot.odoo-community.org/runbot/110/14.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends functionality of contracts to be able to generate sales
This module extends functionality of contracts to be able to generate sales
orders instead of invoices.
**Table of contents**
@@ -50,7 +50,7 @@ Bug Tracker
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.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/contract/issues/new?body=module:%20contract_sale_generation%0Aversion:%2012.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:%20contract_sale_generation%0Aversion:%2014.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.
@@ -60,6 +60,7 @@ Credits
Authors
~~~~~~~
* ACSONE SA/NV
* PESOL
Contributors
@@ -68,6 +69,7 @@ Contributors
* Angel Moya <angel.moya@pesol.es>
* Florent THOMAS <florent.thomas@mind-and-go.com>
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
* Denis Roussel <denis.roussel@acsone.eu>
Maintainers
~~~~~~~~~~~
@@ -82,6 +84,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/12.0/contract_sale_generation>`_ project on GitHub.
This module is part of the `OCA/contract <https://github.com/OCA/contract/tree/14.0/contract_sale_generation>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -8,13 +8,12 @@
"version": "14.0.1.0.0",
"category": "Contract Management",
"license": "AGPL-3",
"author": "PESOL, " "Odoo Community Association (OCA)",
"author": "ACSONE SA/NV, PESOL, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/contract",
"depends": ["contract_sale"],
"data": [
"data/contract_cron.xml",
"views/contract.xml",
"views/contract_template.xml",
],
"installable": True,
}

View File

@@ -2,5 +2,6 @@
from . import abstract_contract
from . import contract
from . import sale_order
from . import sale_order_line
from . import contract_line

View File

@@ -2,16 +2,16 @@
# Copyright 2017 Angel Moya <angel.moya@pesol.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
from odoo import api, fields, models
class ContractAbstractContract(models.AbstractModel):
_inherit = "contract.abstract.contract"
type = fields.Selection(
[("invoice", "Invoice"), ("sale", "Sale")],
string="Type",
default="invoice",
required=True,
)
sale_autoconfirm = fields.Boolean(string="Sale Autoconfirm")
@api.model
def _get_generation_type_selection(self):
res = super()._get_generation_type_selection()
res.append(("sale", "Sale"))
return res

View File

@@ -114,39 +114,13 @@ class ContractContract(models.Model):
def _recurring_create_sale(self, date_ref=False):
sales_values = self._prepare_recurring_sales_values(date_ref)
so_rec = self.env["sale.order"].create(sales_values)
for _rec in self.filtered(lambda c: c.sale_autoconfirm):
so_rec.action_confirm()
return so_rec
sale_orders = self.env["sale.order"].create(sales_values)
sale_orders_to_confirm = sale_orders.filtered(
lambda sale: sale.contract_auto_confirm
)
sale_orders_to_confirm.action_confirm()
return sale_orders
@api.model
def cron_recurring_create_sale(self, date_ref=None):
if not date_ref:
date_ref = fields.Date.context_today(self)
domain = self._get_contracts_to_invoice_domain(date_ref)
domain.extend([("type", "=", "sale")])
sales = self.env["sale.order"]
# Sales by companies, so assignation emails get correct context
companies_to_sale = self.read_group(domain, ["company_id"], ["company_id"])
for row in companies_to_sale:
contracts_to_sale = self.search(row["__domain"]).with_context(
allowed_company_ids=[row["company_id"][0]]
)
sales |= contracts_to_sale._recurring_create_sale(date_ref)
return sales
@api.model
def cron_recurring_create_invoice(self, date_ref=None):
if not date_ref:
date_ref = fields.Date.context_today(self)
domain = self._get_contracts_to_invoice_domain(date_ref)
domain.extend([("type", "=", "invoice")])
invoices = self.env["account.move"]
# Invoice by companies, so assignation emails get correct context
companies_to_invoice = self.read_group(domain, ["company_id"], ["company_id"])
for row in companies_to_invoice:
contracts_to_invoice = self.search(row["__domain"]).with_context(
allowed_company_ids=[row["company_id"][0]]
)
invoices |= contracts_to_invoice._recurring_create_invoice(date_ref)
return invoices
return self._cron_recurring_create(date_ref, create_type="sale")

View File

@@ -0,0 +1,24 @@
# Copyright 2021 ACSONE SA/NV (<http://acsone.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = "sale.order"
contract_auto_confirm = fields.Boolean(
compute="_compute_contract_auto_confirm",
help="This is a technical field in order to know if the order should"
"be automatically confirmed if generated by contract.",
)
def _compute_contract_auto_confirm(self):
sale_auto_confirm = self.filtered(
lambda sale: any(
line.contract_line_id.contract_id.sale_autoconfirm
for line in sale.order_line
)
)
sale_auto_confirm.contract_auto_confirm = True
(self - sale_auto_confirm).contract_auto_confirm = False

View File

@@ -1,3 +1,4 @@
* Angel Moya <angel.moya@pesol.es>
* Florent THOMAS <florent.thomas@mind-and-go.com>
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
* Denis Roussel <denis.roussel@acsone.eu>

View File

@@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<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: http://docutils.sourceforge.net/" />
<title>Contracts Management - Recurring Sales</title>
<style type="text/css">
@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/12.0/contract_sale_generation"><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-12-0/contract-12-0-contract_sale_generation"><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/12.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" 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/contract_sale_generation"><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-contract_sale_generation"><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>This module extends functionality of contracts to be able to generate sales
orders instead of invoices.</p>
<p><strong>Table of contents</strong></p>
@@ -400,7 +400,7 @@ orders instead of invoices.</p>
<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.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/contract/issues/new?body=module:%20contract_sale_generation%0Aversion:%2012.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:%20contract_sale_generation%0Aversion:%2014.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>
</div>
<div class="section" id="credits">
@@ -408,6 +408,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>ACSONE SA/NV</li>
<li>PESOL</li>
</ul>
</div>
@@ -417,6 +418,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<li>Angel Moya &lt;<a class="reference external" href="mailto:angel.moya&#64;pesol.es">angel.moya&#64;pesol.es</a>&gt;</li>
<li>Florent THOMAS &lt;<a class="reference external" href="mailto:florent.thomas&#64;mind-and-go.com">florent.thomas&#64;mind-and-go.com</a>&gt;</li>
<li>Serpent Consulting Services Pvt. Ltd. &lt;<a class="reference external" href="mailto:support&#64;serpentcs.com">support&#64;serpentcs.com</a>&gt;</li>
<li>Denis Roussel &lt;<a class="reference external" href="mailto:denis.roussel&#64;acsone.eu">denis.roussel&#64;acsone.eu</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
@@ -426,7 +428,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/contract/tree/12.0/contract_sale_generation">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/14.0/contract_sale_generation">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>
</div>
</div>

View File

@@ -2,78 +2,83 @@
# Copyright 2017 Pesol (<http://pesol.es>)
# Copyright 2017 Angel Moya <angel.moya@pesol.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from freezegun import freeze_time
from odoo import fields
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
from odoo.tests import Form
from odoo.tests.common import SavepointCase
def to_date(date):
return fields.Date.to_date(date)
class TestContractSale(TransactionCase):
class TestContractSale(SavepointCase):
# Use case : Prepare some data for current test case
def setUp(self):
super(TestContractSale, self).setUp()
self.pricelist = self.env["product.pricelist"].create(
@classmethod
def setUpClass(cls):
super().setUpClass()
contract_date = "2020-01-15"
cls.pricelist = cls.env["product.pricelist"].create(
{
"name": "pricelist for contract test",
}
)
self.partner = self.env["res.partner"].create(
cls.partner = cls.env["res.partner"].create(
{
"name": "partner test contract",
"property_product_pricelist": self.pricelist.id,
"property_product_pricelist": cls.pricelist.id,
}
)
self.product_1 = self.env.ref("product.product_product_1")
self.product_1.taxes_id += self.env["account.tax"].search(
cls.product_1 = cls.env.ref("product.product_product_1")
cls.product_1.taxes_id += cls.env["account.tax"].search(
[("type_tax_use", "=", "sale")], limit=1
)
self.product_1.description_sale = "Test description sale"
self.line_template_vals = {
"product_id": self.product_1.id,
cls.product_1.description_sale = "Test description sale"
cls.line_template_vals = {
"product_id": cls.product_1.id,
"name": "Test Contract Template",
"quantity": 1,
"uom_id": self.product_1.uom_id.id,
"uom_id": cls.product_1.uom_id.id,
"price_unit": 100,
"discount": 50,
"recurring_rule_type": "yearly",
"recurring_interval": 1,
}
self.template_vals = {
cls.template_vals = {
"name": "Test Contract Template",
"contract_type": "sale",
"contract_line_ids": [
(0, 0, self.line_template_vals),
(0, 0, cls.line_template_vals),
],
}
self.template = self.env["contract.template"].create(self.template_vals)
cls.template = cls.env["contract.template"].create(cls.template_vals)
# For being sure of the applied price
self.env["product.pricelist.item"].create(
cls.env["product.pricelist.item"].create(
{
"pricelist_id": self.partner.property_product_pricelist.id,
"product_id": self.product_1.id,
"pricelist_id": cls.partner.property_product_pricelist.id,
"product_id": cls.product_1.id,
"compute_price": "formula",
"base": "list_price",
}
)
self.contract = self.env["contract.contract"].create(
cls.contract = cls.env["contract.contract"].create(
{
"name": "Test Contract",
"partner_id": self.partner.id,
"pricelist_id": self.partner.property_product_pricelist.id,
"type": "sale",
"partner_id": cls.partner.id,
"pricelist_id": cls.partner.property_product_pricelist.id,
"generation_type": "sale",
"sale_autoconfirm": False,
}
)
self.line_vals = {
"contract_id": self.contract.id,
"product_id": self.product_1.id,
cls.line_vals = {
# "contract_id": cls.contract.id,
# "product_id": cls.product_1.id,
"name": "Services from #START# to #END#",
"quantity": 1,
"uom_id": self.product_1.uom_id.id,
# "uom_id": cls.product_1.uom_id.id,
"price_unit": 100,
"discount": 50,
"recurring_rule_type": "monthly",
@@ -81,25 +86,36 @@ class TestContractSale(TransactionCase):
"date_start": "2020-01-01",
"recurring_next_date": "2020-01-15",
}
self.contract.contract_template_id = self.template
self.contract._onchange_contract_template_id()
self.contract_line = self.env["contract.line"].create(self.line_vals)
self.contract2 = self.env["contract.contract"].create(
with Form(cls.contract) as contract_form, freeze_time(contract_date):
contract_form.contract_template_id = cls.template
with contract_form.contract_line_ids.new() as line_form:
line_form.product_id = cls.product_1
line_form.name = "Services from #START# to #END#"
line_form.quantity = 1
line_form.price_unit = 100.0
line_form.discount = 50
line_form.recurring_rule_type = "monthly"
line_form.recurring_interval = 1
line_form.date_start = "2020-01-15"
line_form.recurring_next_date = "2020-01-15"
cls.contract_line = cls.contract.contract_line_ids[1]
cls.contract2 = cls.env["contract.contract"].create(
{
"name": "Test Contract 2",
"type": "sale",
"partner_id": self.partner.id,
"pricelist_id": self.partner.property_product_pricelist.id,
"generation_type": "sale",
"partner_id": cls.partner.id,
"pricelist_id": cls.partner.property_product_pricelist.id,
"contract_type": "purchase",
"contract_line_ids": [
(
0,
0,
{
"product_id": self.product_1.id,
"product_id": cls.product_1.id,
"name": "Services from #START# to #END#",
"quantity": 1,
"uom_id": self.product_1.uom_id.id,
"uom_id": cls.product_1.uom_id.id,
"price_unit": 100,
"discount": 50,
"recurring_rule_type": "monthly",
@@ -156,6 +172,7 @@ class TestContractSale(TransactionCase):
self.contract.contract_template_id = self.template
self.contract._onchange_contract_template_id()
res = {
"contract_type": "sale",
"contract_line_ids": [
(
0,
@@ -171,7 +188,7 @@ class TestContractSale(TransactionCase):
"recurring_interval": 1,
},
)
]
],
}
del self.template_vals["name"]
self.assertDictEqual(res, self.template_vals)
@@ -195,11 +212,11 @@ class TestContractSale(TransactionCase):
self.contract_line.date_start = "2020-01-01"
self.contract_line.recurring_invoicing_type = "post-paid"
self.contract_line.date_end = "2020-03-15"
self.contract_line._onchange_date_start()
self.contract_line._onchange_is_auto_renew()
contracts = self.contract2
for _i in range(10):
contracts |= self.contract.copy({"type": "sale"})
self.env["contract.contract"].cron_recurring_create_sale()
contracts |= self.contract.copy({"generation_type": "sale"})
self.env["contract.contract"]._cron_recurring_create(create_type="sale")
order_lines = self.env["sale.order.line"].search(
[("contract_line_id", "in", contracts.mapped("contract_line_ids").ids)]
)

View File

@@ -10,9 +10,9 @@
name="recurring_sale_or_invoicing"
string="Recurring Sales/Invoicing"
>
<field name="type" />
<field name="generation_type" />
<field
attrs="{'invisible':[('type','!=', 'sale')]}"
attrs="{'invisible':[('generation_type','!=', 'sale')]}"
name="sale_autoconfirm"
/>
</group>
@@ -23,11 +23,11 @@
>
<attribute
name="attrs"
>{'invisible': ['|', ('create_invoice_visibility', '=', False),('type','!=','invoice')]}</attribute>
>{'invisible': ['|', ('create_invoice_visibility', '=', False),('generation_type','!=','invoice')]}</attribute>
</xpath>
<xpath expr="//button[@name='recurring_create_invoice']" position="before">
<button
attrs="{'invisible': [('type','!=','sale')]}"
attrs="{'invisible': [('generation_type','!=','sale')]}"
class="oe_link"
groups="base.group_no_one"
name="recurring_create_sale"
@@ -35,14 +35,15 @@
type="object"
/>
</xpath>
<!--
<xpath expr="//button[@name='action_show_invoices']" position="attributes">
<attribute
name="attrs"
>{'invisible': [('type','!=','invoice')]}</attribute>
</xpath>
</xpath>-->
<xpath expr="//button[@name='action_show_invoices']" position="after">
<button
attrs="{'invisible': [('type','!=','sale')]}"
attrs="{'invisible': [('generation_type','!=','sale')]}"
class="oe_stat_button"
icon="fa-list"
name="action_show_sales"

View File

@@ -1,12 +0,0 @@
<odoo>
<record id="contract_template_form_view_inherit_sale" model="ir.ui.view">
<field name="name">contract.template form view (in contract)</field>
<field name="model">contract.template</field>
<field name="inherit_id" ref="contract.contract_template_form_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='pricelist_id']" position="after">
<field name="type" />
</xpath>
</field>
</record>
</odoo>