From 53a7704458ba4055b14fe67cbdcf5602d3bea640 Mon Sep 17 00:00:00 2001 From: Angel Moya Pardo Date: Thu, 10 Aug 2017 14:11:49 +0200 Subject: [PATCH 01/69] ADD contract_sale_generation module --- contract_sale_generation/README.rst | 57 +++++++++ contract_sale_generation/__init__.py | 2 + contract_sale_generation/__manifest__.py | 22 ++++ contract_sale_generation/models/__init__.py | 5 + .../models/account_analytic_account.py | 80 +++++++++++++ .../models/account_analytic_contract.py | 20 ++++ contract_sale_generation/tests/__init__.py | 5 + .../tests/test_contract_invoice.py | 87 ++++++++++++++ .../tests/test_contract_sale.py | 113 ++++++++++++++++++ .../views/account_analytic_account_view.xml | 39 ++++++ .../views/account_analytic_contract_view.xml | 15 +++ contract_sale_generation/views/sale_view.xml | 15 +++ 12 files changed, 460 insertions(+) create mode 100644 contract_sale_generation/README.rst create mode 100644 contract_sale_generation/__init__.py create mode 100644 contract_sale_generation/__manifest__.py create mode 100644 contract_sale_generation/models/__init__.py create mode 100644 contract_sale_generation/models/account_analytic_account.py create mode 100644 contract_sale_generation/models/account_analytic_contract.py create mode 100644 contract_sale_generation/tests/__init__.py create mode 100644 contract_sale_generation/tests/test_contract_invoice.py create mode 100644 contract_sale_generation/tests/test_contract_sale.py create mode 100644 contract_sale_generation/views/account_analytic_account_view.xml create mode 100644 contract_sale_generation/views/account_analytic_contract_view.xml create mode 100644 contract_sale_generation/views/sale_view.xml diff --git a/contract_sale_generation/README.rst b/contract_sale_generation/README.rst new file mode 100644 index 0000000000..dda5002294 --- /dev/null +++ b/contract_sale_generation/README.rst @@ -0,0 +1,57 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +============================= +Contracts for recurrent sales +============================= + +This module extends functionality of contracts to be able to generate sales +orders instead of invoices. + +Usage +===== + +To use this module, you need to: + +#. Go to Accounting -> Contracts and select or create a new contract. +#. Check *Generate recurring invoices automatically*. +#. Fill fields for selecting the recurrency and invoice parameters: + + * Type defines document that contract will generate, can be "Sales" or "Invoices" + * Sale Autoconfirm, validate Sales Orders if type is "Sales" + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/110/10.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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. + +Credits +======= + +Contributors +------------ + +* Angel Moya + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +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. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/contract_sale_generation/__init__.py b/contract_sale_generation/__init__.py new file mode 100644 index 0000000000..a0fdc10fe1 --- /dev/null +++ b/contract_sale_generation/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import models diff --git a/contract_sale_generation/__manifest__.py b/contract_sale_generation/__manifest__.py new file mode 100644 index 0000000000..072fa46147 --- /dev/null +++ b/contract_sale_generation/__manifest__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Pesol () +# Copyright 2017 Angel Moya +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) + + +{ + 'name': 'Contracts Management - Recurring Sales', + 'version': '10.0.1.0.0', + 'category': 'Contract Management', + 'license': 'AGPL-3', + 'author': "PESOL, " + "Odoo Community Association (OCA)", + 'website': 'https://github.com/oca/contract', + 'depends': ['contract', 'sale'], + 'data': [ + 'views/account_analytic_account_view.xml', + 'views/account_analytic_contract_view.xml', + 'views/sale_view.xml', + ], + 'installable': True, +} diff --git a/contract_sale_generation/models/__init__.py b/contract_sale_generation/models/__init__.py new file mode 100644 index 0000000000..a3782ea728 --- /dev/null +++ b/contract_sale_generation/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import account_analytic_contract +from . import account_analytic_account diff --git a/contract_sale_generation/models/account_analytic_account.py b/contract_sale_generation/models/account_analytic_account.py new file mode 100644 index 0000000000..b29b4afd0c --- /dev/null +++ b/contract_sale_generation/models/account_analytic_account.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# © 2004-2010 OpenERP SA +# © 2014 Angel Moya +# © 2015 Pedro M. Baeza +# © 2016 Carlos Dauden +# Copyright 2016-2017 LasLabs Inc. +# Copyright 2017 Pesol () +# Copyright 2017 Angel Moya +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models +from odoo.exceptions import ValidationError +from odoo.tools.translate import _ + + +class AccountAnalyticAccount(models.Model): + _inherit = 'account.analytic.account' + + @api.model + def _prepare_sale_line(self, line, order_id): + sale_line = self.env['sale.order.line'].new({ + 'order_id': order_id, + 'product_id': line.product_id.id, + 'proudct_uom_qty': line.quantity, + 'proudct_uom_id': line.uom_id.id, + }) + # Get other invoice line values from product onchange + sale_line.product_id_change() + sale_line_vals = sale_line._convert_to_write(sale_line._cache) + # Insert markers + name = line.name + contract = line.analytic_account_id + if 'old_date' in self.env.context and 'next_date' in self.env.context: + lang_obj = self.env['res.lang'] + lang = lang_obj.search( + [('code', '=', contract.partner_id.lang)]) + date_format = lang.date_format or '%m/%d/%Y' + name = self._insert_markers( + line, self.env.context['old_date'], + self.env.context['next_date'], date_format) + sale_line_vals.update({ + 'name': name, + 'discount': line.discount, + 'price_unit': line.price_unit, + }) + return sale_line_vals + + @api.multi + def _prepare_sale(self): + self.ensure_one() + if not self.partner_id: + raise ValidationError( + _("You must first select a Customer for Contract %s!") % + self.name) + sale = self.env['sale.order'].new({ + 'partner_id': self.partner_id, + 'date_order': self.recurring_next_date, + 'origin': self.name, + 'company_id': self.company_id.id, + 'user_id': self.partner_id.user_id.id, + 'project_id': self.id + }) + # Get other invoice values from partner onchange + sale.onchange_partner_id() + return sale._convert_to_write(sale._cache) + + @api.multi + def _create_invoice(self): + self.ensure_one() + if self.type == 'invoice': + return super(AccountAnalyticAccount, self)._create_invoice() + else: + sale_vals = self._prepare_sale() + sale = self.env['sale.order'].create(sale_vals) + for line in self.recurring_invoice_line_ids: + sale_line_vals = self._prepare_sale_line(line, sale.id) + self.env['sale.order.line'].create(sale_line_vals) + if self.sale_autoconfirm: + sale.action_confirm() + return sale diff --git a/contract_sale_generation/models/account_analytic_contract.py b/contract_sale_generation/models/account_analytic_contract.py new file mode 100644 index 0000000000..2db200daab --- /dev/null +++ b/contract_sale_generation/models/account_analytic_contract.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Pesol () +# Copyright 2017 Angel Moya +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountAnalyticContract(models.Model): + _inherit = 'account.analytic.contract' + + type = fields.Selection( + string='Type', + selection=[('invoice', 'Invoice'), + ('sale', 'Sale')], + default='invoice', + required=True, + ) + sale_autoconfirm = fields.Boolean( + string='Sale autoconfirm') diff --git a/contract_sale_generation/tests/__init__.py b/contract_sale_generation/tests/__init__.py new file mode 100644 index 0000000000..dc292d5e39 --- /dev/null +++ b/contract_sale_generation/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_contract_invoice +from . import test_contract_sale diff --git a/contract_sale_generation/tests/test_contract_invoice.py b/contract_sale_generation/tests/test_contract_invoice.py new file mode 100644 index 0000000000..5974b6bb7f --- /dev/null +++ b/contract_sale_generation/tests/test_contract_invoice.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# © 2016 Carlos Dauden +# Copyright 2017 Pesol () +# Copyright 2017 Angel Moya +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestContractInvoice(TransactionCase): + # Use case : Prepare some data for current test case + + def setUp(self): + super(TestContractInvoice, self).setUp() + self.partner = self.env.ref('base.res_partner_2') + self.product = self.env.ref('product.product_product_2') + self.product.taxes_id += self.env['account.tax'].search( + [('type_tax_use', '=', 'sale')], limit=1) + self.product.description_sale = 'Test description sale' + self.template_vals = { + 'recurring_rule_type': 'yearly', + 'recurring_interval': 1, + 'name': 'Test Contract Template', + 'type': 'invoice' + } + self.template = self.env['account.analytic.contract'].create( + self.template_vals, + ) + self.contract = self.env['account.analytic.account'].create({ + 'name': 'Test Contract', + 'partner_id': self.partner.id, + 'pricelist_id': self.partner.property_product_pricelist.id, + 'recurring_invoices': True, + 'date_start': '2016-02-15', + 'recurring_next_date': '2016-02-29', + }) + self.contract.contract_template_id = self.template + self.contract._onchange_contract_template_id() + self.contract_line = self.env['account.analytic.invoice.line'].create({ + 'analytic_account_id': self.contract.id, + 'product_id': self.product.id, + 'name': 'Services from #START# to #END#', + 'quantity': 1, + 'uom_id': self.product.uom_id.id, + 'price_unit': 100, + 'discount': 50, + }) + + def test_check_discount(self): + with self.assertRaises(ValidationError): + self.contract_line.write({'discount': 120}) + + def test_contract(self): + self.assertAlmostEqual(self.contract_line.price_subtotal, 50.0) + res = self.contract_line._onchange_product_id() + self.assertIn('uom_id', res['domain']) + self.contract_line.price_unit = 100.0 + + self.contract.partner_id = False + with self.assertRaises(ValidationError): + self.contract.recurring_create_invoice() + self.contract.partner_id = self.partner.id + + self.contract.recurring_create_invoice() + self.invoice_monthly = self.env['account.invoice'].search( + [('contract_id', '=', self.contract.id)]) + self.assertTrue(self.invoice_monthly) + self.assertEqual(self.contract.recurring_next_date, '2017-02-28') + + self.inv_line = self.invoice_monthly.invoice_line_ids[0] + self.assertTrue(self.inv_line.invoice_line_tax_ids) + self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0) + self.assertEqual(self.contract.partner_id.user_id, + self.invoice_monthly.user_id) + + def test_onchange_contract_template_id(self): + """ It should change the contract values to match the template. """ + self.contract.contract_template_id = self.template + self.contract._onchange_contract_template_id() + res = { + 'recurring_rule_type': self.contract.recurring_rule_type, + 'recurring_interval': self.contract.recurring_interval, + 'type': 'invoice' + } + del self.template_vals['name'] + self.assertDictEqual(res, self.template_vals) diff --git a/contract_sale_generation/tests/test_contract_sale.py b/contract_sale_generation/tests/test_contract_sale.py new file mode 100644 index 0000000000..02aacac5c1 --- /dev/null +++ b/contract_sale_generation/tests/test_contract_sale.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +# © 2016 Carlos Dauden +# Copyright 2017 Pesol () +# Copyright 2017 Angel Moya +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestContractSale(TransactionCase): + # Use case : Prepare some data for current test case + + def setUp(self): + super(TestContractSale, self).setUp() + self.partner = self.env.ref('base.res_partner_2') + self.product = self.env.ref('product.product_product_2') + self.product.taxes_id += self.env['account.tax'].search( + [('type_tax_use', '=', 'sale')], limit=1) + self.product.description_sale = 'Test description sale' + self.template_vals = { + 'recurring_rule_type': 'yearly', + 'recurring_interval': 1, + 'name': 'Test Contract Template', + 'type': 'sale', + 'sale_autoconfirm': False + } + self.template = self.env['account.analytic.contract'].create( + self.template_vals, + ) + self.contract = self.env['account.analytic.account'].create({ + 'name': 'Test Contract', + 'partner_id': self.partner.id, + 'pricelist_id': self.partner.property_product_pricelist.id, + 'recurring_invoices': True, + 'date_start': '2016-02-15', + 'recurring_next_date': '2016-02-29', + }) + self.contract.contract_template_id = self.template + self.contract._onchange_contract_template_id() + self.contract_line = self.env['account.analytic.invoice.line'].create({ + 'analytic_account_id': self.contract.id, + 'product_id': self.product.id, + 'name': 'Services from #START# to #END#', + 'quantity': 1, + 'uom_id': self.product.uom_id.id, + 'price_unit': 100, + 'discount': 50, + }) + + def test_check_discount(self): + with self.assertRaises(ValidationError): + self.contract_line.write({'discount': 120}) + + def test_contract(self): + self.assertAlmostEqual(self.contract_line.price_subtotal, 50.0) + res = self.contract_line._onchange_product_id() + self.assertIn('uom_id', res['domain']) + self.contract_line.price_unit = 100.0 + + self.contract.partner_id = False + with self.assertRaises(ValidationError): + self.contract.recurring_create_invoice() + self.contract.partner_id = self.partner.id + + self.contract.recurring_create_invoice() + self.sale_monthly = self.env['sale.order'].search( + [('project_id', '=', self.contract.id), + ('state', '=', 'draft')]) + self.assertTrue(self.sale_monthly) + self.assertEqual(self.contract.recurring_next_date, '2017-02-28') + + self.sale_line = self.sale_monthly.order_line[0] + self.assertAlmostEqual(self.sale_line.price_subtotal, 50.0) + self.assertEqual(self.contract.partner_id.user_id, + self.sale_monthly.user_id) + + def test_contract_autoconfirm(self): + self.contract.sale_autoconfirm = True + self.assertAlmostEqual(self.contract_line.price_subtotal, 50.0) + res = self.contract_line._onchange_product_id() + self.assertIn('uom_id', res['domain']) + self.contract_line.price_unit = 100.0 + + self.contract.partner_id = False + with self.assertRaises(ValidationError): + self.contract.recurring_create_invoice() + self.contract.partner_id = self.partner.id + + self.contract.recurring_create_invoice() + self.sale_monthly = self.env['sale.order'].search( + [('project_id', '=', self.contract.id), + ('state', '=', 'sale')]) + self.assertTrue(self.sale_monthly) + self.assertEqual(self.contract.recurring_next_date, '2017-02-28') + + self.sale_line = self.sale_monthly.order_line[0] + self.assertAlmostEqual(self.sale_line.price_subtotal, 50.0) + self.assertEqual(self.contract.partner_id.user_id, + self.sale_monthly.user_id) + + def test_onchange_contract_template_id(self): + """ It should change the contract values to match the template. """ + self.contract.contract_template_id = self.template + self.contract._onchange_contract_template_id() + res = { + 'recurring_rule_type': self.contract.recurring_rule_type, + 'recurring_interval': self.contract.recurring_interval, + 'type': 'sale', + 'sale_autoconfirm': False + } + del self.template_vals['name'] + self.assertDictEqual(res, self.template_vals) diff --git a/contract_sale_generation/views/account_analytic_account_view.xml b/contract_sale_generation/views/account_analytic_account_view.xml new file mode 100644 index 0000000000..9157863392 --- /dev/null +++ b/contract_sale_generation/views/account_analytic_account_view.xml @@ -0,0 +1,39 @@ + + + + + account.analytic.account.invoice.recurring.sale.form + account.analytic.account + + + + + + + + {'invisible': ['|',('recurring_invoices','!=',True),('type','!=','invoice')]} + + + + + + + + diff --git a/contract_sale_generation/views/contract_template.xml b/contract_sale_generation/views/contract_template.xml new file mode 100644 index 0000000000..9a4707c5a7 --- /dev/null +++ b/contract_sale_generation/views/contract_template.xml @@ -0,0 +1,14 @@ + + + + contract.template form view (in contract) + contract.template + + + + + + + + + diff --git a/contract_sale_generation/views/sale_view.xml b/contract_sale_generation/views/sale_view.xml deleted file mode 100644 index e23bded0b2..0000000000 --- a/contract_sale_generation/views/sale_view.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - {'search_default_project_id': - [active_id], - 'default_project_id': active_id} - - Sales - sale.order - - - - - From 9ba24a89ba6d5cc225695a4ff8ffb4ab35e413e2 Mon Sep 17 00:00:00 2001 From: Eder Brito Date: Fri, 6 Nov 2020 05:25:10 +0000 Subject: [PATCH 12/69] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (15 of 15 strings) Translation: contract-12.0/contract-12.0-contract_sale_generation Translate-URL: https://translation.odoo-community.org/projects/contract-12-0/contract-12-0-contract_sale_generation/pt_BR/ --- contract_sale_generation/i18n/de.po | 2 -- contract_sale_generation/i18n/es.po | 2 -- contract_sale_generation/i18n/fi.po | 2 -- contract_sale_generation/i18n/fr.po | 2 -- contract_sale_generation/i18n/gl.po | 2 -- contract_sale_generation/i18n/hr.po | 2 -- contract_sale_generation/i18n/pt_BR.po | 39 ++++++++++++++------------ contract_sale_generation/i18n/ru.po | 1 - contract_sale_generation/i18n/tr.po | 2 -- 9 files changed, 21 insertions(+), 33 deletions(-) diff --git a/contract_sale_generation/i18n/de.po b/contract_sale_generation/i18n/de.po index 948c7f1985..45208dab37 100644 --- a/contract_sale_generation/i18n/de.po +++ b/contract_sale_generation/i18n/de.po @@ -81,7 +81,6 @@ msgstr "Verkaufsaufträge" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "automatisches Bestätigen der Verkaufsaufträge" @@ -93,7 +92,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Verkäufe" diff --git a/contract_sale_generation/i18n/es.po b/contract_sale_generation/i18n/es.po index c8f184613b..3d0592741d 100644 --- a/contract_sale_generation/i18n/es.po +++ b/contract_sale_generation/i18n/es.po @@ -81,7 +81,6 @@ msgstr "Venta" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "Autoconfirmar venta" @@ -93,7 +92,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Ventas" diff --git a/contract_sale_generation/i18n/fi.po b/contract_sale_generation/i18n/fi.po index eba320656d..c45918938b 100644 --- a/contract_sale_generation/i18n/fi.po +++ b/contract_sale_generation/i18n/fi.po @@ -81,7 +81,6 @@ msgstr "Myynti" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "Myynnin automaattivahvistus" @@ -93,7 +92,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Myynnit" diff --git a/contract_sale_generation/i18n/fr.po b/contract_sale_generation/i18n/fr.po index 28a98b15c2..d471ccb70a 100644 --- a/contract_sale_generation/i18n/fr.po +++ b/contract_sale_generation/i18n/fr.po @@ -81,7 +81,6 @@ msgstr "Vente" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "Confirmation automatique des commandes" @@ -93,7 +92,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Ventes" diff --git a/contract_sale_generation/i18n/gl.po b/contract_sale_generation/i18n/gl.po index 0e1e152c88..435c880ac2 100644 --- a/contract_sale_generation/i18n/gl.po +++ b/contract_sale_generation/i18n/gl.po @@ -81,7 +81,6 @@ msgstr "Venda" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "Autoconfirmar venda" @@ -93,7 +92,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Vendas" diff --git a/contract_sale_generation/i18n/hr.po b/contract_sale_generation/i18n/hr.po index 1907cd897a..8ccef407b0 100644 --- a/contract_sale_generation/i18n/hr.po +++ b/contract_sale_generation/i18n/hr.po @@ -82,7 +82,6 @@ msgstr "Prodaja" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "Automatski potvrdi ponude" @@ -94,7 +93,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Prodaje" diff --git a/contract_sale_generation/i18n/pt_BR.po b/contract_sale_generation/i18n/pt_BR.po index f8485a3420..451ef6f645 100644 --- a/contract_sale_generation/i18n/pt_BR.po +++ b/contract_sale_generation/i18n/pt_BR.po @@ -10,40 +10,41 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-04-03 12:19+0000\n" -"PO-Revision-Date: 2018-04-03 12:19+0000\n" -"Last-Translator: Albert Vonpupp , 2017\n" -"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/" -"teams/23907/pt_BR/)\n" +"PO-Revision-Date: 2020-11-06 08:08+0000\n" +"Last-Translator: Eder Brito \n" +"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/teams/" +"23907/pt_BR/)\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_contract_abstract_contract msgid "Abstract Recurring Contract" -msgstr "" +msgstr "Contrato Recorrente Abstrato" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form msgid "CREATE SALES" -msgstr "" +msgstr "CRIAR VENDAS" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_contract_contract msgid "Contract" -msgstr "" +msgstr "Contrato" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_contract_line msgid "Contract Line" -msgstr "" +msgstr "Linha do Contrato" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_sale_order_line__contract_line_id msgid "Contract Line to replace" -msgstr "" +msgstr "Linha do Contrato para substituir" #. module: contract_sale_generation #: code:addons/contract_sale_generation/models/contract.py:79 @@ -52,13 +53,15 @@ msgid "" "Contract manually sale order: Sale Order" msgstr "" +"Contratar pedido de venda manual: Pedido de Venda" #. module: contract_sale_generation #: model:ir.actions.server,name:contract_sale_generation.contract_cron_for_sale_ir_actions_server #: model:ir.cron,cron_name:contract_sale_generation.contract_cron_for_sale #: model:ir.cron,name:contract_sale_generation.contract_cron_for_sale msgid "Generate Recurring sales from Contracts" -msgstr "" +msgstr "Gerar vendas recorrentes a partir de Contratos" #. module: contract_sale_generation #: selection:contract.abstract.contract,type:0 @@ -69,42 +72,42 @@ msgstr "Fatura" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form msgid "Recurring Sales/Invoicing" -msgstr "" +msgstr "Vendas/Faturas Recorrentes" #. module: contract_sale_generation #: selection:contract.abstract.contract,type:0 #: selection:contract.contract,type:0 selection:contract.template,type:0 msgid "Sale" -msgstr "" +msgstr "Venda" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_abstract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm msgid "Sale Autoconfirm" -msgstr "" +msgstr "Autoconfirmar Venda" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_count msgid "Sale Count" -msgstr "" +msgstr "Contagem de Venda" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form msgid "Sales Order" -msgstr "" +msgstr "Pedidos de Venda" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_sale_order_line msgid "Sales Order Line" -msgstr "" +msgstr "Linhas dos Pedidos de Venda" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_abstract_contract__type #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__type #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__type msgid "Type" -msgstr "" +msgstr "Tipo" #~ msgid "Analytic Account" #~ msgstr "Conta Analítica" diff --git a/contract_sale_generation/i18n/ru.po b/contract_sale_generation/i18n/ru.po index aebad3f2ff..f6009cd0e3 100644 --- a/contract_sale_generation/i18n/ru.po +++ b/contract_sale_generation/i18n/ru.po @@ -93,7 +93,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Продажи" diff --git a/contract_sale_generation/i18n/tr.po b/contract_sale_generation/i18n/tr.po index 5c20def0c8..3b9e81b021 100644 --- a/contract_sale_generation/i18n/tr.po +++ b/contract_sale_generation/i18n/tr.po @@ -80,7 +80,6 @@ msgstr "Satış" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm #, fuzzy -#| msgid "Sale autoconfirm" msgid "Sale Autoconfirm" msgstr "Satış otomatik onaylama" @@ -92,7 +91,6 @@ msgstr "" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form #, fuzzy -#| msgid "Sales" msgid "Sales Order" msgstr "Satışlar" From e4a1314f97722f5ad51055527fc44cf9d1f10da8 Mon Sep 17 00:00:00 2001 From: Florent THOMAS Date: Sat, 2 Jan 2021 21:44:43 +0100 Subject: [PATCH 13/69] add display type in default values --- contract_sale_generation/models/contract_line.py | 1 + 1 file changed, 1 insertion(+) diff --git a/contract_sale_generation/models/contract_line.py b/contract_sale_generation/models/contract_line.py index 02dd76ad1d..d75351654f 100644 --- a/contract_sale_generation/models/contract_line.py +++ b/contract_sale_generation/models/contract_line.py @@ -19,6 +19,7 @@ def _prepare_sale_line(self, order_id=False, sale_values=False): 'uom_id': self.uom_id.id, 'discount': self.discount, 'contract_line_id': self.id, + 'display_type': self.display_type, } if order_id: sale_line_vals['order_id'] = order_id.id From 7258c58ffe517c00a86d475e3b306caef49721ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi?= Date: Mon, 4 Jan 2021 09:56:16 +0000 Subject: [PATCH 14/69] Translated using Weblate (French) Currently translated at 100.0% (15 of 15 strings) Translation: contract-12.0/contract-12.0-contract_sale_generation Translate-URL: https://translation.odoo-community.org/projects/contract-12-0/contract-12-0-contract_sale_generation/fr/ --- contract_sale_generation/__manifest__.py | 2 +- contract_sale_generation/i18n/fr.po | 31 ++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/contract_sale_generation/__manifest__.py b/contract_sale_generation/__manifest__.py index 0c68fd6486..f4f5df03f7 100644 --- a/contract_sale_generation/__manifest__.py +++ b/contract_sale_generation/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Contracts Management - Recurring Sales', - 'version': '12.0.1.0.0', + 'version': '12.0.1.0.1', 'category': 'Contract Management', 'license': 'AGPL-3', 'author': "PESOL, " diff --git a/contract_sale_generation/i18n/fr.po b/contract_sale_generation/i18n/fr.po index d471ccb70a..24e94ddef4 100644 --- a/contract_sale_generation/i18n/fr.po +++ b/contract_sale_generation/i18n/fr.po @@ -10,39 +10,40 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-05-19 02:01+0000\n" -"PO-Revision-Date: 2018-05-19 02:01+0000\n" -"Last-Translator: Fabien Bourgeois , 2018\n" +"PO-Revision-Date: 2021-01-04 11:44+0000\n" +"Last-Translator: Rémi \n" "Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_contract_abstract_contract msgid "Abstract Recurring Contract" -msgstr "" +msgstr "Base pour les contrats récurrents" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form msgid "CREATE SALES" -msgstr "" +msgstr "CRÉER LES COMMANDES" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_contract_contract msgid "Contract" -msgstr "" +msgstr "Contrat" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_contract_line msgid "Contract Line" -msgstr "" +msgstr "Ligne de Contrat" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_sale_order_line__contract_line_id msgid "Contract Line to replace" -msgstr "" +msgstr "Ligne de contrat à remplacer" #. module: contract_sale_generation #: code:addons/contract_sale_generation/models/contract.py:79 @@ -51,13 +52,15 @@ msgid "" "Contract manually sale order: Sale Order" msgstr "" +"Création manuelle de la commande depuis le contrat : Commande" #. module: contract_sale_generation #: model:ir.actions.server,name:contract_sale_generation.contract_cron_for_sale_ir_actions_server #: model:ir.cron,cron_name:contract_sale_generation.contract_cron_for_sale #: model:ir.cron,name:contract_sale_generation.contract_cron_for_sale msgid "Generate Recurring sales from Contracts" -msgstr "" +msgstr "Générer les ventes récurrentes depuis les Contrats" #. module: contract_sale_generation #: selection:contract.abstract.contract,type:0 @@ -68,7 +71,7 @@ msgstr "Facture" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form msgid "Recurring Sales/Invoicing" -msgstr "" +msgstr "Commandes / Factures Récurrentes" #. module: contract_sale_generation #: selection:contract.abstract.contract,type:0 @@ -80,25 +83,23 @@ msgstr "Vente" #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_abstract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_autoconfirm #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_template__sale_autoconfirm -#, fuzzy msgid "Sale Autoconfirm" msgstr "Confirmation automatique des commandes" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_contract__sale_count msgid "Sale Count" -msgstr "" +msgstr "Nombre de Commandes" #. module: contract_sale_generation #: model_terms:ir.ui.view,arch_db:contract_sale_generation.contract_contract_form_view_recurring_sale_form -#, fuzzy msgid "Sales Order" -msgstr "Ventes" +msgstr "Commandes" #. module: contract_sale_generation #: model:ir.model,name:contract_sale_generation.model_sale_order_line msgid "Sales Order Line" -msgstr "" +msgstr "Ligne de commande" #. module: contract_sale_generation #: model:ir.model.fields,field_description:contract_sale_generation.field_contract_abstract_contract__type From 13bf49c67ba350ac4bc247c946d8507c9e53c0a8 Mon Sep 17 00:00:00 2001 From: Mkxm Awilix Date: Wed, 27 Jan 2021 10:15:39 +0100 Subject: [PATCH 15/69] [12.0][FIX] contract: Incorrect product UOM qty dict key for the sale.order.line The product UOM qty was not correctly set on the Sale Order Line During the creation of a recurring Order from a Contract, the given quantity on the Contract Line was not correctly set on the created Sale Order Line. --- contract_sale_generation/__manifest__.py | 2 +- contract_sale_generation/models/contract_line.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contract_sale_generation/__manifest__.py b/contract_sale_generation/__manifest__.py index f4f5df03f7..2dd931b40b 100644 --- a/contract_sale_generation/__manifest__.py +++ b/contract_sale_generation/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Contracts Management - Recurring Sales', - 'version': '12.0.1.0.1', + 'version': '12.0.1.0.2', 'category': 'Contract Management', 'license': 'AGPL-3', 'author': "PESOL, " diff --git a/contract_sale_generation/models/contract_line.py b/contract_sale_generation/models/contract_line.py index d75351654f..bdb571fe05 100644 --- a/contract_sale_generation/models/contract_line.py +++ b/contract_sale_generation/models/contract_line.py @@ -15,7 +15,7 @@ def _prepare_sale_line(self, order_id=False, sale_values=False): ) sale_line_vals = { 'product_id': self.product_id.id, - 'quantity': self._get_quantity_to_invoice(*dates), + 'product_uom_qty': self._get_quantity_to_invoice(*dates), 'uom_id': self.uom_id.id, 'discount': self.discount, 'contract_line_id': self.id, From 551a1a4c9fc4b6ce77096debd5137e06c7b1f036 Mon Sep 17 00:00:00 2001 From: Freni-OSI Date: Wed, 7 Apr 2021 16:41:41 +0530 Subject: [PATCH 16/69] [14.0][FIX] Travis --- contract_sale_generation/__init__.py | 1 - contract_sale_generation/__manifest__.py | 25 ++- .../data/contract_cron.xml | 6 +- .../models/abstract_contract.py | 12 +- contract_sale_generation/models/contract.py | 76 ++++--- .../models/contract_line.py | 44 ++-- .../models/sale_order_line.py | 4 +- .../readme/DESCRIPTION.rst | 2 +- .../tests/test_contract_sale.py | 202 +++++++++--------- contract_sale_generation/views/contract.xml | 68 +++--- .../views/contract_template.xml | 4 +- 11 files changed, 231 insertions(+), 213 deletions(-) diff --git a/contract_sale_generation/__init__.py b/contract_sale_generation/__init__.py index a9e3372262..0650744f6b 100644 --- a/contract_sale_generation/__init__.py +++ b/contract_sale_generation/__init__.py @@ -1,2 +1 @@ - from . import models diff --git a/contract_sale_generation/__manifest__.py b/contract_sale_generation/__manifest__.py index 2dd931b40b..053a252392 100644 --- a/contract_sale_generation/__manifest__.py +++ b/contract_sale_generation/__manifest__.py @@ -4,18 +4,17 @@ { - 'name': 'Contracts Management - Recurring Sales', - 'version': '12.0.1.0.2', - 'category': 'Contract Management', - 'license': 'AGPL-3', - 'author': "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', + "name": "Contracts Management - Recurring Sales", + "version": "14.0.1.0.0", + "category": "Contract Management", + "license": "AGPL-3", + "author": "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, + "installable": True, } diff --git a/contract_sale_generation/data/contract_cron.xml b/contract_sale_generation/data/contract_cron.xml index 841f529711..c2f206dc16 100644 --- a/contract_sale_generation/data/contract_cron.xml +++ b/contract_sale_generation/data/contract_cron.xml @@ -1,8 +1,7 @@ - - + Generate Recurring sales from Contracts - + code model.cron_recurring_create_sale() @@ -11,5 +10,4 @@ -1 - diff --git a/contract_sale_generation/models/abstract_contract.py b/contract_sale_generation/models/abstract_contract.py index bda9742c10..e5c4a60c32 100644 --- a/contract_sale_generation/models/abstract_contract.py +++ b/contract_sale_generation/models/abstract_contract.py @@ -6,14 +6,12 @@ class ContractAbstractContract(models.AbstractModel): - _inherit = 'contract.abstract.contract' + _inherit = "contract.abstract.contract" type = fields.Selection( - [('invoice', 'Invoice'), - ('sale', 'Sale')], - string='Type', - default='invoice', + [("invoice", "Invoice"), ("sale", "Sale")], + string="Type", + default="invoice", required=True, ) - sale_autoconfirm = fields.Boolean( - string='Sale Autoconfirm') + sale_autoconfirm = fields.Boolean(string="Sale Autoconfirm") diff --git a/contract_sale_generation/models/contract.py b/contract_sale_generation/models/contract.py index 17c622d12a..d8d966e5d6 100644 --- a/contract_sale_generation/models/contract.py +++ b/contract_sale_generation/models/contract.py @@ -8,24 +8,26 @@ # Copyright 2018 Therp BV . # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models class ContractContract(models.Model): - _inherit = 'contract.contract' + _inherit = "contract.contract" sale_count = fields.Integer(compute="_compute_sale_count") @api.multi def _prepare_sale(self, date_ref): self.ensure_one() - sale = self.env['sale.order'].new({ - 'partner_id': self.partner_id, - 'date_order': fields.Date.to_string(date_ref), - 'origin': self.name, - 'company_id': self.company_id.id, - 'user_id': self.partner_id.user_id.id, - }) + sale = self.env["sale.order"].new( + { + "partner_id": self.partner_id, + "date_order": fields.Date.to_string(date_ref), + "origin": self.name, + "company_id": self.company_id.id, + "user_id": self.partner_id.user_id.id, + } + ) if self.payment_term_id: sale.payment_term_id = self.payment_term_id.id if self.fiscal_position_id: @@ -37,10 +39,11 @@ def _prepare_sale(self, date_ref): @api.multi def _get_related_sales(self): self.ensure_one() - sales = (self.env['sale.order.line'] - .search([('contract_line_id', 'in', - self.contract_line_ids.ids) - ]).mapped('order_id')) + sales = ( + self.env["sale.order.line"] + .search([("contract_line_id", "in", self.contract_line_ids.ids)]) + .mapped("order_id") + ) return sales @api.multi @@ -51,20 +54,18 @@ def _compute_sale_count(self): @api.multi def action_show_sales(self): self.ensure_one() - tree_view = self.env.ref('sale.view_order_tree', - raise_if_not_found=False) - form_view = self.env.ref('sale.view_order_form', - raise_if_not_found=False) + tree_view = self.env.ref("sale.view_order_tree", raise_if_not_found=False) + form_view = self.env.ref("sale.view_order_form", raise_if_not_found=False) action = { - 'type': 'ir.actions.act_window', - 'name': 'Sales Orders', - 'res_model': 'sale.order', - 'view_type': 'form', - 'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity', - 'domain': [('id', 'in', self._get_related_sales().ids)], + "type": "ir.actions.act_window", + "name": "Sales Orders", + "res_model": "sale.order", + "view_type": "form", + "view_mode": "tree,kanban,form,calendar,pivot,graph,activity", + "domain": [("id", "in", self._get_related_sales().ids)], } if tree_view and form_view: - action['views'] = [(tree_view.id, 'tree'), (form_view.id, 'form')] + action["views"] = [(tree_view.id, "tree"), (form_view.id, "form")] return action @api.multi @@ -77,10 +78,10 @@ def recurring_create_sale(self): for sale_rec in sales: self.message_post( body=_( - 'Contract manually sale order: ' + "Contract manually sale order: " '' - 'Sale Order' - '' + "Sale Order" + "" ) % (sale_rec._name, sale_rec.id) ) @@ -107,14 +108,12 @@ def _prepare_recurring_sales_values(self, date_ref=False): continue sale_values = contract._prepare_sale(date_ref) for line in contract_lines: - sale_values.setdefault('order_line', []) + sale_values.setdefault("order_line", []) invoice_line_values = line._prepare_sale_line( sale_values=sale_values, ) if invoice_line_values: - sale_values['order_line'].append( - (0, 0, invoice_line_values) - ) + sale_values["order_line"].append((0, 0, invoice_line_values)) sales_values.append(sale_values) contract_lines._update_recurring_next_date() return sales_values @@ -123,7 +122,7 @@ def _prepare_recurring_sales_values(self, date_ref=False): 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): + for _rec in self.filtered(lambda c: c.sale_autoconfirm): so_rec.action_confirm() return so_rec @@ -132,11 +131,10 @@ 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')]) + 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"]) + 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]] @@ -149,15 +147,13 @@ 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')]) + domain.extend([("type", "=", "invoice")]) invoices = self.env["account.invoice"] # Invoice by companies, so assignation emails get correct context - companies_to_invoice = self.read_group( - domain, ["company_id"], ["company_id"]) + 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) + invoices |= contracts_to_invoice._recurring_create_invoice(date_ref) return invoices diff --git a/contract_sale_generation/models/contract_line.py b/contract_sale_generation/models/contract_line.py index bdb571fe05..bc9df45af3 100644 --- a/contract_sale_generation/models/contract_line.py +++ b/contract_sale_generation/models/contract_line.py @@ -5,7 +5,7 @@ class ContractLine(models.Model): - _inherit = 'contract.line' + _inherit = "contract.line" @api.multi def _prepare_sale_line(self, order_id=False, sale_values=False): @@ -14,22 +14,30 @@ def _prepare_sale_line(self, order_id=False, sale_values=False): self.last_date_invoiced, self.recurring_next_date ) sale_line_vals = { - 'product_id': self.product_id.id, - 'product_uom_qty': self._get_quantity_to_invoice(*dates), - 'uom_id': self.uom_id.id, - 'discount': self.discount, - 'contract_line_id': self.id, - 'display_type': self.display_type, + "product_id": self.product_id.id, + "product_uom_qty": self._get_quantity_to_invoice(*dates), + "uom_id": self.uom_id.id, + "discount": self.discount, + "contract_line_id": self.id, + "display_type": self.display_type, } if order_id: - sale_line_vals['order_id'] = order_id.id - order_line = self.env['sale.order.line'].with_context( - force_company=self.contract_id.company_id.id, - ).new(sale_line_vals) - if sale_values and not order_id: - sale = self.env['sale.order'].with_context( + sale_line_vals["order_id"] = order_id.id + order_line = ( + self.env["sale.order.line"] + .with_context( force_company=self.contract_id.company_id.id, - ).new(sale_values) + ) + .new(sale_line_vals) + ) + if sale_values and not order_id: + sale = ( + self.env["sale.order"] + .with_context( + force_company=self.contract_id.company_id.id, + ) + .new(sale_values) + ) order_line.order_id = sale # Get other order line values from product onchange order_line.product_id_change() @@ -38,10 +46,10 @@ def _prepare_sale_line(self, order_id=False, sale_values=False): name = self._insert_markers(dates[0], dates[1]) sale_line_vals.update( { - 'sequence': self.sequence, - 'name': name, - 'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)], - 'price_unit': self.price_unit, + "sequence": self.sequence, + "name": name, + "analytic_tag_ids": [(6, 0, self.analytic_tag_ids.ids)], + "price_unit": self.price_unit, } ) return sale_line_vals diff --git a/contract_sale_generation/models/sale_order_line.py b/contract_sale_generation/models/sale_order_line.py index 08abb1332c..cb9451ce8c 100644 --- a/contract_sale_generation/models/sale_order_line.py +++ b/contract_sale_generation/models/sale_order_line.py @@ -5,8 +5,8 @@ class SaleOrderLine(models.Model): - _inherit = 'sale.order.line' + _inherit = "sale.order.line" contract_line_id = fields.Many2one( - 'contract.line', string='Contract Line', index=True + "contract.line", string="Contract Line", index=True ) diff --git a/contract_sale_generation/readme/DESCRIPTION.rst b/contract_sale_generation/readme/DESCRIPTION.rst index 2ea92d9eb8..f8ff4d1939 100644 --- a/contract_sale_generation/readme/DESCRIPTION.rst +++ b/contract_sale_generation/readme/DESCRIPTION.rst @@ -1,2 +1,2 @@ -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. diff --git a/contract_sale_generation/tests/test_contract_sale.py b/contract_sale_generation/tests/test_contract_sale.py index 1f83a4e933..14f8aa5ae5 100644 --- a/contract_sale_generation/tests/test_contract_sale.py +++ b/contract_sale_generation/tests/test_contract_sale.py @@ -3,8 +3,8 @@ # Copyright 2017 Angel Moya # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.exceptions import ValidationError from odoo import fields +from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase @@ -17,95 +17,95 @@ class TestContractSale(TransactionCase): def setUp(self): super(TestContractSale, self).setUp() - self.pricelist = self.env['product.pricelist'].create({ - 'name': 'pricelist for contract test', - }) - self.partner = self.env['res.partner'].create({ - 'name': 'partner test contract', - 'property_product_pricelist': self.pricelist.id, - }) - self.product_1 = self.env.ref('product.product_product_1') - self.product_1.taxes_id += self.env['account.tax'].search( - [('type_tax_use', '=', 'sale')], limit=1 + self.pricelist = self.env["product.pricelist"].create( + { + "name": "pricelist for contract test", + } + ) + self.partner = self.env["res.partner"].create( + { + "name": "partner test contract", + "property_product_pricelist": self.pricelist.id, + } ) - self.product_1.description_sale = 'Test description sale' + self.product_1 = self.env.ref("product.product_product_1") + self.product_1.taxes_id += self.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, - 'name': 'Test Contract Template', - 'quantity': 1, - 'uom_id': self.product_1.uom_id.id, - 'price_unit': 100, - 'discount': 50, - 'recurring_rule_type': 'yearly', - 'recurring_interval': 1, + "product_id": self.product_1.id, + "name": "Test Contract Template", + "quantity": 1, + "uom_id": self.product_1.uom_id.id, + "price_unit": 100, + "discount": 50, + "recurring_rule_type": "yearly", + "recurring_interval": 1, } self.template_vals = { - 'name': 'Test Contract Template', - 'contract_line_ids': [ + "name": "Test Contract Template", + "contract_line_ids": [ (0, 0, self.line_template_vals), ], } - self.template = self.env['contract.template'].create( - self.template_vals - ) + self.template = self.env["contract.template"].create(self.template_vals) # For being sure of the applied price - self.env['product.pricelist.item'].create( + self.env["product.pricelist.item"].create( { - 'pricelist_id': self.partner.property_product_pricelist.id, - 'product_id': self.product_1.id, - 'compute_price': 'formula', - 'base': 'list_price', + "pricelist_id": self.partner.property_product_pricelist.id, + "product_id": self.product_1.id, + "compute_price": "formula", + "base": "list_price", } ) - self.contract = self.env['contract.contract'].create( + self.contract = self.env["contract.contract"].create( { - 'name': 'Test Contract', - 'partner_id': self.partner.id, - 'pricelist_id': self.partner.property_product_pricelist.id, - 'type': 'sale', - 'sale_autoconfirm': False + "name": "Test Contract", + "partner_id": self.partner.id, + "pricelist_id": self.partner.property_product_pricelist.id, + "type": "sale", + "sale_autoconfirm": False, } ) self.line_vals = { - 'contract_id': self.contract.id, - 'product_id': self.product_1.id, - 'name': 'Services from #START# to #END#', - 'quantity': 1, - 'uom_id': self.product_1.uom_id.id, - 'price_unit': 100, - 'discount': 50, - 'recurring_rule_type': 'monthly', - 'recurring_interval': 1, - 'date_start': '2020-01-01', - 'recurring_next_date': '2020-01-15', + "contract_id": self.contract.id, + "product_id": self.product_1.id, + "name": "Services from #START# to #END#", + "quantity": 1, + "uom_id": self.product_1.uom_id.id, + "price_unit": 100, + "discount": 50, + "recurring_rule_type": "monthly", + "recurring_interval": 1, + "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( + self.contract_line = self.env["contract.line"].create(self.line_vals) + self.contract2 = self.env["contract.contract"].create( { - 'name': 'Test Contract 2', - 'type': 'sale', - 'partner_id': self.partner.id, - 'pricelist_id': self.partner.property_product_pricelist.id, - 'contract_type': 'purchase', - 'contract_line_ids': [ + "name": "Test Contract 2", + "type": "sale", + "partner_id": self.partner.id, + "pricelist_id": self.partner.property_product_pricelist.id, + "contract_type": "purchase", + "contract_line_ids": [ ( 0, 0, { - 'product_id': self.product_1.id, - 'name': 'Services from #START# to #END#', - 'quantity': 1, - 'uom_id': self.product_1.uom_id.id, - 'price_unit': 100, - 'discount': 50, - 'recurring_rule_type': 'monthly', - 'recurring_interval': 1, - 'date_start': '2018-02-15', - 'recurring_next_date': '2018-02-22', + "product_id": self.product_1.id, + "name": "Services from #START# to #END#", + "quantity": 1, + "uom_id": self.product_1.uom_id.id, + "price_unit": 100, + "discount": 50, + "recurring_rule_type": "monthly", + "recurring_interval": 1, + "date_start": "2018-02-15", + "recurring_next_date": "2018-02-22", }, ) ], @@ -114,40 +114,36 @@ def setUp(self): def test_check_discount(self): with self.assertRaises(ValidationError): - self.contract_line.write({'discount': 120}) + self.contract_line.write({"discount": 120}) def test_contract(self): - recurring_next_date = to_date('2020-02-15') + recurring_next_date = to_date("2020-02-15") self.assertAlmostEqual(self.contract_line.price_subtotal, 50.0) res = self.contract_line._onchange_product_id() - self.assertIn('uom_id', res['domain']) + self.assertIn("uom_id", res["domain"]) self.contract_line.price_unit = 100.0 self.contract.partner_id = self.partner.id self.contract.recurring_create_sale() self.sale_monthly = self.contract._get_related_sales() self.assertTrue(self.sale_monthly) - self.assertEqual( - self.contract_line.recurring_next_date, recurring_next_date - ) + self.assertEqual(self.contract_line.recurring_next_date, recurring_next_date) self.order_line = self.sale_monthly.order_line[0] self.assertTrue(self.order_line.tax_id) self.assertAlmostEqual(self.order_line.price_subtotal, 50.0) self.assertEqual(self.contract.user_id, self.sale_monthly.user_id) def test_contract_autoconfirm(self): - recurring_next_date = to_date('2020-02-15') + recurring_next_date = to_date("2020-02-15") self.contract.sale_autoconfirm = True self.assertAlmostEqual(self.contract_line.price_subtotal, 50.0) res = self.contract_line._onchange_product_id() - self.assertIn('uom_id', res['domain']) + self.assertIn("uom_id", res["domain"]) self.contract_line.price_unit = 100.0 self.contract.partner_id = self.partner.id self.contract.recurring_create_sale() self.sale_monthly = self.contract._get_related_sales() self.assertTrue(self.sale_monthly) - self.assertEqual( - self.contract_line.recurring_next_date, recurring_next_date - ) + self.assertEqual(self.contract_line.recurring_next_date, recurring_next_date) self.order_line = self.sale_monthly.order_line[0] self.assertTrue(self.order_line.tax_id) self.assertAlmostEqual(self.order_line.price_subtotal, 50.0) @@ -160,19 +156,24 @@ def test_onchange_contract_template_id(self): self.contract.contract_template_id = self.template self.contract._onchange_contract_template_id() res = { - 'contract_line_ids': - [(0, 0, { - 'product_id': self.product_1.id, - 'name': 'Test Contract Template', - 'quantity': 1, - 'uom_id': self.product_1.uom_id.id, - 'price_unit': 100, - 'discount': 50, - 'recurring_rule_type': 'yearly', - 'recurring_interval': 1, - })] + "contract_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product_1.id, + "name": "Test Contract Template", + "quantity": 1, + "uom_id": self.product_1.uom_id.id, + "price_unit": 100, + "discount": 50, + "recurring_rule_type": "yearly", + "recurring_interval": 1, + }, + ) + ] } - del self.template_vals['name'] + del self.template_vals["name"] self.assertDictEqual(res, self.template_vals) def test_contract_count_sale(self): @@ -183,27 +184,26 @@ def test_contract_count_sale(self): self.assertEqual(self.contract.sale_count, 3) def test_contract_count_sale_2(self): - orders = self.env['sale.order'] + orders = self.env["sale.order"] orders |= self.contract.recurring_create_sale() orders |= self.contract.recurring_create_sale() orders |= self.contract.recurring_create_sale() action = self.contract.action_show_sales() - self.assertEqual(set(action['domain'][0][2]), set(orders.ids)) + self.assertEqual(set(action["domain"][0][2]), set(orders.ids)) def test_cron_recurring_create_sale(self): - 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.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() contracts = self.contract2 for _i in range(10): - contracts |= self.contract.copy({'type': 'sale'}) - self.env['contract.contract'].cron_recurring_create_sale() - order_lines = self.env['sale.order.line'].search( - [('contract_line_id', 'in', - contracts.mapped('contract_line_ids').ids)] + contracts |= self.contract.copy({"type": "sale"}) + self.env["contract.contract"].cron_recurring_create_sale() + order_lines = self.env["sale.order.line"].search( + [("contract_line_id", "in", contracts.mapped("contract_line_ids").ids)] ) self.assertEqual( - len(contracts.mapped('contract_line_ids')), + len(contracts.mapped("contract_line_ids")), len(order_lines), ) diff --git a/contract_sale_generation/views/contract.xml b/contract_sale_generation/views/contract.xml index 647a8906c9..a22babd61d 100644 --- a/contract_sale_generation/views/contract.xml +++ b/contract_sale_generation/views/contract.xml @@ -3,38 +3,58 @@ contract.contract.form.recurring.sale.form contract.contract - + - - - + + + - - {'invisible': ['|', ('create_invoice_visibility', '=', False),('type','!=','invoice')]} - + + {'invisible': ['|', ('create_invoice_visibility', '=', False),('type','!=','invoice')]} + - - + diff --git a/contract_sale_generation/views/contract_template.xml b/contract_sale_generation/views/contract_template.xml index 9a4707c5a7..129da21c7c 100644 --- a/contract_sale_generation/views/contract_template.xml +++ b/contract_sale_generation/views/contract_template.xml @@ -3,10 +3,10 @@ contract.template form view (in contract) contract.template - + - + From 1e05e53b4ade9b9f124e6e55564297156ae012c3 Mon Sep 17 00:00:00 2001 From: Freni-OSI Date: Wed, 21 Apr 2021 13:42:13 +0530 Subject: [PATCH 17/69] [14.0][MIG] contract_sale_generation --- contract_sale_generation/__manifest__.py | 2 +- contract_sale_generation/models/contract.py | 9 +----- .../models/contract_line.py | 13 +++------ contract_sale_generation/views/contract.xml | 29 ++++++++----------- .../views/contract_template.xml | 2 -- 5 files changed, 18 insertions(+), 37 deletions(-) diff --git a/contract_sale_generation/__manifest__.py b/contract_sale_generation/__manifest__.py index 053a252392..9a492577c3 100644 --- a/contract_sale_generation/__manifest__.py +++ b/contract_sale_generation/__manifest__.py @@ -10,7 +10,7 @@ "license": "AGPL-3", "author": "PESOL, " "Odoo Community Association (OCA)", "website": "https://github.com/OCA/contract", - "depends": ["contract", "sale"], + "depends": ["contract_sale"], "data": [ "data/contract_cron.xml", "views/contract.xml", diff --git a/contract_sale_generation/models/contract.py b/contract_sale_generation/models/contract.py index d8d966e5d6..ed048091c1 100644 --- a/contract_sale_generation/models/contract.py +++ b/contract_sale_generation/models/contract.py @@ -16,7 +16,6 @@ class ContractContract(models.Model): sale_count = fields.Integer(compute="_compute_sale_count") - @api.multi def _prepare_sale(self, date_ref): self.ensure_one() sale = self.env["sale.order"].new( @@ -36,7 +35,6 @@ def _prepare_sale(self, date_ref): sale.onchange_partner_id() return sale._convert_to_write(sale._cache) - @api.multi def _get_related_sales(self): self.ensure_one() sales = ( @@ -46,12 +44,10 @@ def _get_related_sales(self): ) return sales - @api.multi def _compute_sale_count(self): for rec in self: rec.sale_count = len(rec._get_related_sales()) - @api.multi def action_show_sales(self): self.ensure_one() tree_view = self.env.ref("sale.view_order_tree", raise_if_not_found=False) @@ -68,7 +64,6 @@ def action_show_sales(self): action["views"] = [(tree_view.id, "tree"), (form_view.id, "form")] return action - @api.multi def recurring_create_sale(self): """ This method triggers the creation of the next sale order of the @@ -87,7 +82,6 @@ def recurring_create_sale(self): ) return sales - @api.multi def _prepare_recurring_sales_values(self, date_ref=False): """ This method builds the list of sales values to create, based on @@ -118,7 +112,6 @@ def _prepare_recurring_sales_values(self, date_ref=False): contract_lines._update_recurring_next_date() return sales_values - @api.multi 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) @@ -148,7 +141,7 @@ def cron_recurring_create_invoice(self, date_ref=None): date_ref = fields.Date.context_today(self) domain = self._get_contracts_to_invoice_domain(date_ref) domain.extend([("type", "=", "invoice")]) - invoices = self.env["account.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: diff --git a/contract_sale_generation/models/contract_line.py b/contract_sale_generation/models/contract_line.py index bc9df45af3..98b3cb3522 100644 --- a/contract_sale_generation/models/contract_line.py +++ b/contract_sale_generation/models/contract_line.py @@ -1,13 +1,12 @@ # Copyright (C) 2020 Open Source Integrators # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, models +from odoo import models class ContractLine(models.Model): _inherit = "contract.line" - @api.multi def _prepare_sale_line(self, order_id=False, sale_values=False): self.ensure_one() dates = self._get_period_to_invoice( @@ -16,7 +15,7 @@ def _prepare_sale_line(self, order_id=False, sale_values=False): sale_line_vals = { "product_id": self.product_id.id, "product_uom_qty": self._get_quantity_to_invoice(*dates), - "uom_id": self.uom_id.id, + "product_uom": self.uom_id.id, "discount": self.discount, "contract_line_id": self.id, "display_type": self.display_type, @@ -25,17 +24,13 @@ def _prepare_sale_line(self, order_id=False, sale_values=False): sale_line_vals["order_id"] = order_id.id order_line = ( self.env["sale.order.line"] - .with_context( - force_company=self.contract_id.company_id.id, - ) + .with_company(self.contract_id.company_id.id) .new(sale_line_vals) ) if sale_values and not order_id: sale = ( self.env["sale.order"] - .with_context( - force_company=self.contract_id.company_id.id, - ) + .with_company(self.contract_id.company_id.id) .new(sale_values) ) order_line.order_id = sale diff --git a/contract_sale_generation/views/contract.xml b/contract_sale_generation/views/contract.xml index a22babd61d..7b44541622 100644 --- a/contract_sale_generation/views/contract.xml +++ b/contract_sale_generation/views/contract.xml @@ -1,5 +1,4 @@ - contract.contract.form.recurring.sale.form contract.contract @@ -7,18 +6,18 @@ - @@ -28,34 +27,30 @@ - diff --git a/contract_sale_generation/views/contract_template.xml b/contract_sale_generation/views/contract_template.xml index 129da21c7c..cf821dcdec 100644 --- a/contract_sale_generation/views/contract_template.xml +++ b/contract_sale_generation/views/contract_template.xml @@ -1,5 +1,4 @@ - contract.template form view (in contract) contract.template @@ -10,5 +9,4 @@ - From 97e1675b129e7a020ec09888b2059022c23b32d9 Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Sun, 7 Nov 2021 10:08:41 +0100 Subject: [PATCH 18/69] [14.0][IMP] contract_sale_generation Use the generation_type field defined now in contract base module. Improve tests --- contract_sale_generation/README.rst | 14 +-- contract_sale_generation/__manifest__.py | 3 +- contract_sale_generation/models/__init__.py | 1 + .../models/abstract_contract.py | 14 +-- contract_sale_generation/models/contract.py | 40 ++------ contract_sale_generation/models/sale_order.py | 24 +++++ .../readme/CONTRIBUTORS.rst | 1 + .../static/description/index.html | 10 +- .../tests/test_contract_sale.py | 97 +++++++++++-------- contract_sale_generation/views/contract.xml | 13 +-- .../views/contract_template.xml | 12 --- 11 files changed, 119 insertions(+), 110 deletions(-) create mode 100644 contract_sale_generation/models/sale_order.py delete mode 100644 contract_sale_generation/views/contract_template.xml diff --git a/contract_sale_generation/README.rst b/contract_sale_generation/README.rst index 24e5d22839..1ad37d0857 100644 --- a/contract_sale_generation/README.rst +++ b/contract_sale_generation/README.rst @@ -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 `_. 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 `_. +`feedback `_. 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 * Florent THOMAS * Serpent Consulting Services Pvt. Ltd. +* Denis Roussel 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 `_ project on GitHub. +This module is part of the `OCA/contract `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/contract_sale_generation/__manifest__.py b/contract_sale_generation/__manifest__.py index 9a492577c3..758a23e0c7 100644 --- a/contract_sale_generation/__manifest__.py +++ b/contract_sale_generation/__manifest__.py @@ -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, } diff --git a/contract_sale_generation/models/__init__.py b/contract_sale_generation/models/__init__.py index 5a5b6e24bb..69f40465fa 100644 --- a/contract_sale_generation/models/__init__.py +++ b/contract_sale_generation/models/__init__.py @@ -2,5 +2,6 @@ from . import abstract_contract from . import contract +from . import sale_order from . import sale_order_line from . import contract_line diff --git a/contract_sale_generation/models/abstract_contract.py b/contract_sale_generation/models/abstract_contract.py index e5c4a60c32..e5452dca5a 100644 --- a/contract_sale_generation/models/abstract_contract.py +++ b/contract_sale_generation/models/abstract_contract.py @@ -2,16 +2,16 @@ # Copyright 2017 Angel Moya # 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 diff --git a/contract_sale_generation/models/contract.py b/contract_sale_generation/models/contract.py index ed048091c1..030cbdc46f 100644 --- a/contract_sale_generation/models/contract.py +++ b/contract_sale_generation/models/contract.py @@ -114,39 +114,13 @@ def _prepare_recurring_sales_values(self, date_ref=False): 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") diff --git a/contract_sale_generation/models/sale_order.py b/contract_sale_generation/models/sale_order.py new file mode 100644 index 0000000000..fb94846778 --- /dev/null +++ b/contract_sale_generation/models/sale_order.py @@ -0,0 +1,24 @@ +# Copyright 2021 ACSONE SA/NV () +# 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 diff --git a/contract_sale_generation/readme/CONTRIBUTORS.rst b/contract_sale_generation/readme/CONTRIBUTORS.rst index 4c26c04804..21cb886478 100644 --- a/contract_sale_generation/readme/CONTRIBUTORS.rst +++ b/contract_sale_generation/readme/CONTRIBUTORS.rst @@ -1,3 +1,4 @@ * Angel Moya * Florent THOMAS * Serpent Consulting Services Pvt. Ltd. +* Denis Roussel diff --git a/contract_sale_generation/static/description/index.html b/contract_sale_generation/static/description/index.html index 74937050d5..62720c8c8f 100644 --- a/contract_sale_generation/static/description/index.html +++ b/contract_sale_generation/static/description/index.html @@ -3,7 +3,7 @@ - + Contracts Management - Recurring Sales -
-

Contracts Management - Recurring Sales

+
+ + +Odoo Community Association + +
+

Contracts Management - Recurring Sales

-

Beta License: AGPL-3 OCA/contract Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/contract Translate me on Weblate Try me on Runboat

This module extends functionality of contracts to be able to generate sales orders instead of invoices.

Table of contents

@@ -386,7 +391,7 @@

Contracts Management - Recurring Sales

-

Usage

+

Usage

To use this module, you need to:

  1. Go to Sales -> Contracts and select or create a new contract.
  2. @@ -399,7 +404,7 @@

    Usage

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -407,16 +412,16 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • ACSONE SA/NV
  • PESOL
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -438,5 +443,6 @@

Maintainers

+
From 515d1dc723183cf97c440afd6df378aa2197f291 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Sat, 28 Feb 2026 18:11:20 +0100 Subject: [PATCH 62/69] [FIX] contract_sale_generation: Improve views and make it more similar to the current ones --- contract_sale_generation/views/contract.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contract_sale_generation/views/contract.xml b/contract_sale_generation/views/contract.xml index 779f92b5de..6afd794a0b 100644 --- a/contract_sale_generation/views/contract.xml +++ b/contract_sale_generation/views/contract.xml @@ -10,10 +10,9 @@