diff --git a/contract/README.rst b/contract/README.rst index 80b3b2058..320ce0888 100644 --- a/contract/README.rst +++ b/contract/README.rst @@ -14,13 +14,13 @@ Recurring - Contracts Management :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 + :target: https://github.com/OCA/contract/tree/13.0/contract :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 + :target: https://translation.odoo-community.org/projects/contract-13-0/contract-13-0-contract :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/13.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -74,7 +74,6 @@ Known issues / Roadmap ====================== * Recover states and others functional fields in Contracts. -* Remove ``models/ir_ui_view.py`` in v13, where the workaround it contains is supported upstream. Bug Tracker =========== @@ -82,7 +81,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. @@ -92,9 +91,8 @@ Credits Authors ~~~~~~~ -* OpenERP SA * Tecnativa -* LasLabs +* ACSONE SA/NV Contributors ~~~~~~~~~~~~ @@ -124,6 +122,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/__manifest__.py b/contract/__manifest__.py index b32d652e7..5b84789e2 100644 --- a/contract/__manifest__.py +++ b/contract/__manifest__.py @@ -5,17 +5,15 @@ # Copyright 2017 Tecnativa - Vicent Cubells # Copyright 2016-2017 LasLabs Inc. # Copyright 2018-2019 ACSONE SA/NV +# Copyright 2020 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Recurring - Contracts Management", - "version": "12.0.7.2.2", + "version": "13.0.1.0.0", "category": "Contract Management", "license": "AGPL-3", - "author": "OpenERP SA, " - "Tecnativa, " - "LasLabs, " - "Odoo Community Association (OCA)", + "author": "Tecnativa, ACSONE SA/NV, Odoo Community Association (OCA)", "website": "https://github.com/oca/contract", "depends": ["base", "account", "product"], "external_dependencies": {"python": ["dateutil"]}, diff --git a/contract/migrations/12.0.2.0.0/pre-migration.py b/contract/migrations/12.0.2.0.0/pre-migration.py deleted file mode 100644 index 87de67041..000000000 --- a/contract/migrations/12.0.2.0.0/pre-migration.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2018 ACSONE SA/NV -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import logging - -from openupgradelib import openupgrade - -_logger = logging.getLogger(__name__) - - -def _set_finished_contract(cr): - _logger.info("set recurring_next_date to false for finished contract") - openupgrade.logged_query( - cr, - """ - UPDATE account_analytic_account - SET recurring_next_date=NULL - WHERE recurring_next_date > date_end - """, - ) - - -def _move_contract_recurrence_info_to_contract_line(cr): - _logger.info("Move contract data to line level") - openupgrade.logged_query( - cr, - """ - ALTER TABLE account_analytic_invoice_line - ADD COLUMN IF NOT EXISTS recurring_rule_type VARCHAR(255), - ADD COLUMN IF NOT EXISTS recurring_invoicing_type VARCHAR(255), - ADD COLUMN IF NOT EXISTS recurring_interval INTEGER, - ADD COLUMN IF NOT EXISTS recurring_next_date DATE, - ADD COLUMN IF NOT EXISTS date_start DATE, - ADD COLUMN IF NOT EXISTS date_end DATE - """, - ) - - openupgrade.logged_query( - cr, - """ - UPDATE account_analytic_invoice_line AS contract_line - SET - recurring_rule_type=contract.recurring_rule_type, - recurring_invoicing_type=contract.recurring_invoicing_type, - recurring_interval=contract.recurring_interval, - recurring_next_date=contract.recurring_next_date, - date_start=contract.date_start, - date_end=contract.date_end - FROM - account_analytic_account AS contract - WHERE - contract.id=contract_line.analytic_account_id - """, - ) - - -def _move_contract_template_recurrence_info_to_contract_template_line(cr): - _logger.info("Move contract template data to line level") - openupgrade.logged_query( - cr, - """ - ALTER TABLE account_analytic_contract_line - ADD COLUMN IF NOT EXISTS recurring_rule_type VARCHAR(255), - ADD COLUMN IF NOT EXISTS recurring_invoicing_type VARCHAR(255), - ADD COLUMN IF NOT EXISTS recurring_interval INTEGER - """, - ) - - openupgrade.logged_query( - cr, - """ - UPDATE account_analytic_contract_line AS contract_template_line - SET - recurring_rule_type=contract_template.recurring_rule_type, - recurring_invoicing_type=contract_template.recurring_invoicing_type, - recurring_interval=contract_template.recurring_interval - FROM - account_analytic_contract AS contract_template - WHERE - contract_template.id=contract_template_line.analytic_account_id - """, - ) - - -@openupgrade.migrate() -def migrate(env, version): - """ - set recurring_next_date to false for finished contract - """ - _logger.info(">> Pre-Migration 12.0.2.0.0") - cr = env.cr - _set_finished_contract(cr) - _move_contract_recurrence_info_to_contract_line(cr) - _move_contract_template_recurrence_info_to_contract_template_line(cr) diff --git a/contract/migrations/12.0.4.0.0/post-migration.py b/contract/migrations/12.0.4.0.0/post-migration.py deleted file mode 100644 index 02d2895f7..000000000 --- a/contract/migrations/12.0.4.0.0/post-migration.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2019 ACSONE SA/NV -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import logging - -from openupgradelib import openupgrade - -from odoo.tools import parse_version - -_logger = logging.getLogger(__name__) - - -def _update_no_update_ir_cron(env): - # Update ir.cron - env.ref("contract.contract_cron_for_invoice").model_id = env.ref( - "contract.model_contract_contract" - ) - env.ref("contract.contract_line_cron_for_renew").model_id = env.ref( - "contract.model_contract_line" - ) - env.ref("contract.email_contract_template").model_id = env.ref( - "contract.model_contract_contract" - ) - - -def _init_last_date_invoiced_on_contract_lines(env): - _logger.info("init last_date_invoiced field for contract lines") - contract_lines = env["contract.line"].search([("recurring_next_date", "!=", False)]) - contract_lines._init_last_date_invoiced() - - -def _init_invoicing_partner_id_on_contracts(env): - _logger.info("Populate invoicing partner field on contracts") - contracts = env["contract.contract"].search([]) - contracts._inverse_partner_id() - - -def assign_salesman(env): - """As v11 takes salesman from linked partner and now the salesman is a - field in the contract that is initialized to current user, we need - to assign to the recently converted contracts following old logic, or they - will have admin as responsible. - """ - openupgrade.logged_query( - env.cr, - """ - UPDATE contract_contract cc - SET user_id = rp.user_id - FROM res_partner rp - WHERE rp.id = cc.partner_id""", - ) - - -@openupgrade.migrate() -def migrate(env, version): - _update_no_update_ir_cron(env) - if parse_version(version) < parse_version("12.0.2.0.0"): - # We check the version here as this post-migration script was in - # 12.0.2.0.0 and already done for those who used the module when - # it was a PR - _init_last_date_invoiced_on_contract_lines(env) - _init_invoicing_partner_id_on_contracts(env) - assign_salesman(env) diff --git a/contract/migrations/12.0.4.0.0/pre-migration.py b/contract/migrations/12.0.4.0.0/pre-migration.py deleted file mode 100644 index 306206ea6..000000000 --- a/contract/migrations/12.0.4.0.0/pre-migration.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2019 ACSONE SA/NV -# Copyright 2019 Tecnativa 2019 - Pedro M. Baeza -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -import logging - -from openupgradelib import openupgrade -from psycopg2 import sql - -_logger = logging.getLogger(__name__) - -models_to_rename = [ - # Contract Line Wizard - ("account.analytic.invoice.line.wizard", "contract.line.wizard"), - # Abstract Contract - ("account.abstract.analytic.contract", "contract.abstract.contract"), - # Abstract Contract Line - ("account.abstract.analytic.contract.line", "contract.abstract.contract.line",), - # Contract Line - ("account.analytic.invoice.line", "contract.line"), - # Contract Template - ("account.analytic.contract", "contract.template"), - # Contract Template Line - ("account.analytic.contract.line", "contract.template.line"), -] -tables_to_rename = [ - # Contract Line - ("account_analytic_invoice_line", "contract_line"), - # Contract Template - ("account_analytic_contract", "contract_template"), - # Contract Template Line - ("account_analytic_contract_line", "contract_template_line"), -] -columns_to_copy = { - "contract_line": [("analytic_account_id", "contract_id", None),], -} -xmlids_to_rename = [ - ( - "contract.account_analytic_cron_for_invoice", - "contract.contract_cron_for_invoice", - ), - ( - "contract.account_analytic_contract_manager", - "contract.contract_template_manager", - ), - ("contract.account_analytic_contract_user", "contract.contract_template_user",), - ( - "contract.account_analytic_invoice_line_manager", - "contract.contract_line_manager", - ), - ("contract.account_analytic_invoice_line_user", "contract.contract_line_user",), - ( - "contract.account_analytic_contract_line_manager", - "contract.contract_template_line_manager", - ), - ( - "contract.account_analytic_contract_line_user", - "contract.contract_template_line_user", - ), -] - - -def _get_contract_field_name(cr): - """ - Contract field changed the name from analytic_account_id to contract_id - in 12.0.2.0.0. This method used to get the contract field name in - account_analytic_invoice_line""" - return ( - "contract_id" - if openupgrade.column_exists(cr, "account_analytic_invoice_line", "contract_id") - else "analytic_account_id" - ) - - -def create_contract_records(cr): - contract_field_name = _get_contract_field_name(cr) - openupgrade.logged_query( - cr, - """ - CREATE TABLE contract_contract - (LIKE account_analytic_account INCLUDING ALL)""", - ) - openupgrade.logged_query( - cr, - sql.SQL( - """ - INSERT INTO contract_contract - SELECT * FROM account_analytic_account - WHERE id IN (SELECT DISTINCT {} FROM contract_line) - """ - ).format(sql.Identifier(contract_field_name),), - ) - # Deactivate disabled contracts - openupgrade.logged_query( - cr, - """UPDATE contract_contract cc - SET active = False - FROM account_analytic_account aaa - WHERE aaa.id = cc.id - AND NOT aaa.recurring_invoices""", - ) - # Handle id sequence - cr.execute("CREATE SEQUENCE IF NOT EXISTS contract_contract_id_seq") - cr.execute( - "SELECT setval('contract_contract_id_seq', " - "(SELECT MAX(id) FROM contract_contract))" - ) - cr.execute( - "ALTER TABLE contract_contract ALTER id " - "SET DEFAULT NEXTVAL('contract_contract_id_seq')" - ) - # Move common stuff from one table to the other - mapping = [ - ("ir_attachment", "res_model", "res_id"), - ("mail_message", "model", "res_id"), - ("mail_activity", "res_model", "res_id"), - ("mail_followers", "res_model", "res_id"), - ] - for table, model_column, id_column in mapping: - openupgrade.logged_query( - cr, - sql.SQL( - """ - UPDATE {table} SET {model_column}='contract.contract' - WHERE {model_column}='account.analytic.account' - AND {id_column} IN (SELECT DISTINCT {col} FROM contract_line) - """ - ).format( - table=sql.Identifier(table), - model_column=sql.Identifier(model_column), - id_column=sql.Identifier(id_column), - col=sql.Identifier(contract_field_name), - ), - ) - - -@openupgrade.migrate() -def migrate(env, version): - cr = env.cr - openupgrade.rename_models(cr, models_to_rename) - openupgrade.rename_tables(cr, tables_to_rename) - openupgrade.rename_xmlids(cr, xmlids_to_rename) - openupgrade.copy_columns(cr, columns_to_copy) - create_contract_records(cr) diff --git a/contract/migrations/12.0.5.0.0/pre-migration.py b/contract/migrations/12.0.5.0.0/pre-migration.py deleted file mode 100644 index ca208e9dd..000000000 --- a/contract/migrations/12.0.5.0.0/pre-migration.py +++ /dev/null @@ -1,10 +0,0 @@ -def migrate(cr, version): - # pre-paid/post-paid becomes significant for monthlylastday too, - # make sure it has the value that was implied for previous versions. - cr.execute( - """\ - UPDATE contract_line - SET recurring_invoicing_type = 'post-paid' - WHERE recurring_rule_type = 'monthlylastday' - """ - ) diff --git a/contract/migrations/12.0.5.0.1/post-migration.py b/contract/migrations/12.0.5.0.1/post-migration.py deleted file mode 100644 index 9e3ada143..000000000 --- a/contract/migrations/12.0.5.0.1/post-migration.py +++ /dev/null @@ -1,7 +0,0 @@ -def migrate(cr, version): - cr.execute( - """\ - UPDATE res_company - SET create_new_line_at_contract_line_renew = true - """ - ) diff --git a/contract/migrations/13.0.1.0.0/noupdate_changes.xml b/contract/migrations/13.0.1.0.0/noupdate_changes.xml new file mode 100644 index 000000000..468506ed9 --- /dev/null +++ b/contract/migrations/13.0.1.0.0/noupdate_changes.xml @@ -0,0 +1,28 @@ + + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + diff --git a/contract/migrations/13.0.1.0.0/post-migration.py b/contract/migrations/13.0.1.0.0/post-migration.py new file mode 100644 index 000000000..23c29c718 --- /dev/null +++ b/contract/migrations/13.0.1.0.0/post-migration.py @@ -0,0 +1,11 @@ +# Copyright 2020 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openupgradelib import openupgrade # pylint: disable=W7936 + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.load_data( + env.cr, "contract", "migrations/13.0.1.0.0/noupdate_changes.xml" + ) diff --git a/contract/models/__init__.py b/contract/models/__init__.py index 89a5171d1..a8107a94f 100644 --- a/contract/models/__init__.py +++ b/contract/models/__init__.py @@ -6,11 +6,9 @@ from . import contract_template from . import contract from . import contract_template_line from . import contract_line -from . import account_invoice -from . import account_invoice_line +from . import account_move from . import res_partner from . import contract_tag from . import res_company from . import res_config_settings from . import contract_terminate_reason -from . import ir_ui_view diff --git a/contract/models/abstract_contract.py b/contract/models/abstract_contract.py index d8c00fae7..18753c3bb 100644 --- a/contract/models/abstract_contract.py +++ b/contract/models/abstract_contract.py @@ -1,6 +1,6 @@ # Copyright 2004-2010 OpenERP SA # Copyright 2014 Angel Moya -# Copyright 2015 Pedro M. Baeza +# Copyright 2015-2020 Tecnativa - Pedro M. Baeza # Copyright 2016-2018 Carlos Dauden # Copyright 2016-2017 LasLabs Inc. # Copyright 2018 ACSONE SA/NV @@ -39,7 +39,7 @@ class ContractAbstractContract(models.AbstractModel): "res.company", string="Company", required=True, - default=lambda self: self.env["res.company"]._company_default_get(self._name), + default=lambda self: self.env.company.id, ) @api.onchange("contract_type") diff --git a/contract/models/abstract_contract_line.py b/contract/models/abstract_contract_line.py index fc2c05082..fb3b80ac9 100644 --- a/contract/models/abstract_contract_line.py +++ b/contract/models/abstract_contract_line.py @@ -10,8 +10,6 @@ from odoo import api, fields, models from odoo.exceptions import ValidationError from odoo.tools.translate import _ -from odoo.addons import decimal_precision as dp - class ContractAbstractContractLine(models.AbstractModel): _name = "contract.abstract.contract.line" @@ -35,13 +33,11 @@ class ContractAbstractContractLine(models.AbstractModel): inverse="_inverse_price_unit", ) price_subtotal = fields.Float( - compute="_compute_price_subtotal", - digits=dp.get_precision("Account"), - string="Sub Total", + compute="_compute_price_subtotal", digits="Account", string="Sub Total", ) discount = fields.Float( string="Discount (%)", - digits=dp.get_precision("Discount"), + digits="Discount", help="Discount that is applied in generated invoices." " It should be less or equal to 100", ) @@ -123,7 +119,7 @@ class ContractAbstractContractLine(models.AbstractModel): ondelete="cascade", ) display_type = fields.Selection( - selection=[("line_section", "Section"), ("line_note", "Note"),], + selection=[("line_section", "Section"), ("line_note", "Note")], default=False, help="Technical field for UX purpose.", ) @@ -140,6 +136,7 @@ class ContractAbstractContractLine(models.AbstractModel): "- Custom: Depending on the recurrence to be define.", ) is_recurring_note = fields.Boolean(compute="_compute_is_recurring_note") + company_id = fields.Many2one(related="contract_id.company_id", store=True) @api.model def _get_default_recurring_invoicing_offset( @@ -153,7 +150,8 @@ class ContractAbstractContractLine(models.AbstractModel): else: return 1 - def is_recurring_note(self): + @api.depends("display_type", "note_invoicing_mode") + def _compute_is_recurring_note(self): for record in self: record.is_recurring_note = ( record.display_type == "line_note" @@ -163,7 +161,8 @@ class ContractAbstractContractLine(models.AbstractModel): @api.depends("recurring_invoicing_type", "recurring_rule_type") def _compute_recurring_invoicing_offset(self): for rec in self: - rec.recurring_invoicing_offset = self._get_default_recurring_invoicing_offset( + method = self._get_default_recurring_invoicing_offset + rec.recurring_invoicing_offset = method( rec.recurring_invoicing_type, rec.recurring_rule_type ) @@ -206,7 +205,6 @@ class ContractAbstractContractLine(models.AbstractModel): for line in self.filtered(lambda x: not x.automatic_price): line.specific_price = line.price_unit - @api.multi @api.depends("quantity", "price_unit", "discount") def _compute_price_subtotal(self): for line in self: @@ -219,14 +217,12 @@ class ContractAbstractContractLine(models.AbstractModel): else: line.price_subtotal = subtotal - @api.multi @api.constrains("discount") def _check_discount(self): for line in self: if line.discount > 100: raise ValidationError(_("Discount should be less or equal to 100")) - @api.multi @api.onchange("product_id") def _onchange_product_id(self): if not self.product_id: diff --git a/contract/models/account_invoice.py b/contract/models/account_invoice.py deleted file mode 100644 index faaa009cc..000000000 --- a/contract/models/account_invoice.py +++ /dev/null @@ -1,11 +0,0 @@ -# © 2016 Carlos Dauden -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import fields, models - - -class AccountInvoice(models.Model): - _inherit = "account.invoice" - - # We keep this field for migration purpose - old_contract_id = fields.Many2one("contract.contract", oldname="contract_id") diff --git a/contract/models/account_invoice_line.py b/contract/models/account_invoice_line.py deleted file mode 100644 index 262d0c1b5..000000000 --- a/contract/models/account_invoice_line.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright 2018 ACSONE SA/NV. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import fields, models - - -class AccountInvoiceLine(models.Model): - _inherit = "account.invoice.line" - - contract_line_id = fields.Many2one( - "contract.line", string="Contract Line", index=True - ) diff --git a/contract/models/account_move.py b/contract/models/account_move.py new file mode 100644 index 000000000..ba2528cb8 --- /dev/null +++ b/contract/models/account_move.py @@ -0,0 +1,21 @@ +# Copyright 2016 Tecnativa - Carlos Dauden +# Copyright 2018 ACSONE SA/NV. +# Copyright 2020 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountInvoice(models.Model): + _inherit = "account.move" + + # We keep this field for migration purpose + old_contract_id = fields.Many2one("contract.contract") + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + contract_line_id = fields.Many2one( + "contract.line", string="Contract Line", index=True + ) diff --git a/contract/models/contract.py b/contract/models/contract.py index 5f97581f4..b381d5dc5 100644 --- a/contract/models/contract.py +++ b/contract/models/contract.py @@ -1,6 +1,6 @@ # Copyright 2004-2010 OpenERP SA # Copyright 2014 Angel Moya -# Copyright 2015 Pedro M. Baeza +# Copyright 2015-2020 Tecnativa - Pedro M. Baeza # Copyright 2016-2018 Carlos Dauden # Copyright 2016-2017 LasLabs Inc. # Copyright 2018 ACSONE SA/NV @@ -8,6 +8,7 @@ from odoo import api, fields, models from odoo.exceptions import UserError, ValidationError +from odoo.tests import Form from odoo.tools.translate import _ @@ -106,7 +107,6 @@ class ContractContract(models.Model): track_visibility="onchange", ) - @api.multi def _inverse_partner_id(self): for rec in self: if not rec.invoice_partner_id: @@ -114,18 +114,15 @@ class ContractContract(models.Model): "invoice" ] - @api.multi def _get_related_invoices(self): self.ensure_one() invoices = ( - self.env["account.invoice.line"] + self.env["account.move.line"] .search([("contract_line_id", "in", self.contract_line_ids.ids,)]) - .mapped("invoice_id") - ) - invoices |= self.env["account.invoice"].search( - [("old_contract_id", "=", self.id)] + .mapped("move_id") ) + invoices |= self.env["account.move"].search([("old_contract_id", "=", self.id)]) return invoices def _get_computed_currency(self): @@ -162,31 +159,18 @@ class ContractContract(models.Model): else: rec.manual_currency_id = False - @api.multi def _compute_invoice_count(self): for rec in self: rec.invoice_count = len(rec._get_related_invoices()) - @api.multi def action_show_invoices(self): self.ensure_one() - tree_view_ref = ( - "account.invoice_supplier_tree" - if self.contract_type == "purchase" - else "account.invoice_tree_with_onboarding" - ) - form_view_ref = ( - "account.invoice_supplier_form" - if self.contract_type == "purchase" - else "account.invoice_form" - ) - tree_view = self.env.ref(tree_view_ref, raise_if_not_found=False) - form_view = self.env.ref(form_view_ref, raise_if_not_found=False) + tree_view = self.env.ref("account.view_invoice_tree", raise_if_not_found=False) + form_view = self.env.ref("account.view_move_form", raise_if_not_found=False) action = { "type": "ir.actions.act_window", "name": "Invoices", - "res_model": "account.invoice", - "view_type": "form", + "res_model": "account.move", "view_mode": "tree,kanban,form,calendar,pivot,graph,activity", "domain": [("id", "in", self._get_related_invoices().ids)], } @@ -216,6 +200,8 @@ class ContractContract(models.Model): ).mapped("recurring_next_date") if recurring_next_date: contract.recurring_next_date = min(recurring_next_date) + else: + contract.recurring_next_date = False @api.depends("contract_line_ids.create_invoice_visibility") def _compute_create_invoice_visibility(self): @@ -279,7 +265,6 @@ class ContractContract(models.Model): } } - @api.multi def _convert_contract_lines(self, contract): self.ensure_one() new_lines = self.env["contract.line"] @@ -295,8 +280,12 @@ class ContractContract(models.Model): new_lines._onchange_is_auto_renew() return new_lines - @api.multi def _prepare_invoice(self, date_invoice, journal=None): + """Prepare in a Form the values for the generated invoice record. + + :return: A tuple with the vals dictionary and the Form with the + preloaded values for being used in lines. + """ self.ensure_one() if not journal: journal = ( @@ -318,36 +307,30 @@ class ContractContract(models.Model): invoice_type = "out_invoice" if self.contract_type == "purchase": invoice_type = "in_invoice" - vinvoice = ( - self.env["account.invoice"] - .with_context(force_company=self.company_id.id,) - .new( - { - "company_id": self.company_id.id, - "partner_id": self.invoice_partner_id.id, - "type": invoice_type, - } + move_form = Form( + self.env["account.move"].with_context( + force_company=self.company_id.id, default_type=invoice_type ) ) - vinvoice._onchange_partner_id() - invoice_vals = vinvoice._convert_to_write(vinvoice._cache) + move_form.partner_id = self.invoice_partner_id + if self.payment_term_id: + move_form.invoice_payment_term_id = self.payment_term_id + if self.fiscal_position_id: + move_form.fiscal_position_id = self.fiscal_position_id + invoice_vals = move_form._values_to_save(all_fields=True) invoice_vals.update( { - "name": self.code, + "ref": self.code, + "company_id": self.company_id.id, "currency_id": self.currency_id.id, - "date_invoice": date_invoice, + "invoice_date": date_invoice, "journal_id": journal.id, - "origin": self.name, + "invoice_origin": self.name, "user_id": self.user_id.id, } ) - if self.payment_term_id: - invoice_vals["payment_term_id"] = self.payment_term_id.id - if self.fiscal_position_id: - invoice_vals["fiscal_position_id"] = self.fiscal_position_id.id - return invoice_vals + return invoice_vals, move_form - @api.multi def action_contract_send(self): self.ensure_one() template = self.env.ref("contract.email_contract_template", False) @@ -362,7 +345,6 @@ class ContractContract(models.Model): return { "name": _("Compose Email"), "type": "ir.actions.act_window", - "view_type": "form", "view_mode": "form", "res_model": "mail.compose.message", "views": [(compose_form.id, "form")], @@ -371,40 +353,6 @@ class ContractContract(models.Model): "context": ctx, } - @api.model - def _finalize_invoice_values(self, invoice_values): - """Provided for keeping compatibility in this version.""" - # TODO: Must be removed in >=13.0 - return invoice_values - - @api.model - def _finalize_invoice_creation(self, invoices): - """This method is called right after the creation of the invoices. - - Override it when you need to do something after the records are created - in the DB. If you need to modify any value, better to do it on the - _prepare_* methods on contract or contract line. - """ - invoices.compute_taxes() - - @api.model - def _finalize_and_create_invoices(self, invoices_values): - """This method: - - - creates the invoices - - finalizes the created invoices (tax computation...) - - :param invoices_values: list of dictionaries (invoices values) - :return: created invoices (account.invoice) - """ - final_invoices_values = [] - # TODO: This call must be removed in >=13.0 - for invoice_values in invoices_values: - final_invoices_values.append(self._finalize_invoice_values(invoice_values)) - invoices = self.env["account.invoice"].create(final_invoices_values) - self._finalize_invoice_creation(invoices) - return invoices - @api.model def _get_contracts_to_invoice_domain(self, date_ref=None): """ @@ -419,7 +367,6 @@ class ContractContract(models.Model): domain.extend([("recurring_next_date", "<=", date_ref)]) return domain - @api.multi def _get_lines_to_invoice(self, date_ref): """ This method fetches and returns the lines to invoice on the contract @@ -460,7 +407,6 @@ class ContractContract(models.Model): previous = line return lines2invoice.sorted() - @api.multi def _prepare_recurring_invoices_values(self, date_ref=False): """ This method builds the list of invoices values to create, based on @@ -479,21 +425,15 @@ class ContractContract(models.Model): contract_lines = contract._get_lines_to_invoice(date_ref) if not contract_lines: continue - invoice_values = contract._prepare_invoice(date_ref) + invoice_vals, move_form = contract._prepare_invoice(date_ref) + invoice_vals["invoice_line_ids"] = [] for line in contract_lines: - invoice_values.setdefault("invoice_line_ids", []) - invoice_line_values = line._prepare_invoice_line( - invoice_values=invoice_values, - ) - if invoice_line_values: - invoice_values["invoice_line_ids"].append( - (0, 0, invoice_line_values) - ) - invoices_values.append(invoice_values) + invoice_line_vals = line._prepare_invoice_line(move_form=move_form) + invoice_vals["invoice_line_ids"].append((0, 0, invoice_line_vals)) + invoices_values.append(invoice_vals) contract_lines._update_recurring_next_date() return invoices_values - @api.multi def recurring_create_invoice(self): """ This method triggers the creation of the next invoices of the contracts @@ -511,17 +451,16 @@ class ContractContract(models.Model): ) return invoice - @api.multi def _recurring_create_invoice(self, date_ref=False): invoices_values = self._prepare_recurring_invoices_values(date_ref) - return self._finalize_and_create_invoices(invoices_values) + return self.env["account.move"].create(invoices_values) @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) - 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: @@ -531,7 +470,6 @@ class ContractContract(models.Model): invoices |= contracts_to_invoice._recurring_create_invoice(date_ref) return invoices - @api.multi def action_terminate_contract(self): self.ensure_one() context = {"default_contract_id": self.id} @@ -539,13 +477,11 @@ class ContractContract(models.Model): "type": "ir.actions.act_window", "name": _("Terminate Contract"), "res_model": "contract.contract.terminate", - "view_type": "form", "view_mode": "form", "target": "new", "context": context, } - @api.multi def _terminate_contract( self, terminate_reason_id, terminate_comment, terminate_date ): @@ -563,7 +499,6 @@ class ContractContract(models.Model): ) return True - @api.multi def action_cancel_contract_termination(self): self.ensure_one() self.write( diff --git a/contract/models/contract_line.py b/contract/models/contract_line.py index 762bd62cd..3be185e92 100644 --- a/contract/models/contract_line.py +++ b/contract/models/contract_line.py @@ -1,5 +1,6 @@ # Copyright 2017 LasLabs Inc. # Copyright 2018 ACSONE SA/NV. +# Copyright 2020 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from datetime import timedelta @@ -118,7 +119,6 @@ class ContractLine(models.Model): default=True, ) - @api.multi @api.depends( "date_end", "termination_notice_rule_type", "termination_notice_interval", ) @@ -128,14 +128,15 @@ class ContractLine(models.Model): rec.termination_notice_date = rec.date_end - self.get_relative_delta( rec.termination_notice_rule_type, rec.termination_notice_interval, ) + else: + rec.termination_notice_date = False - @api.multi @api.depends("is_canceled", "date_start", "date_end", "is_auto_renew") def _compute_state(self): today = fields.Date.context_today(self) for rec in self: + rec.state = False if rec.display_type: - rec.state = False continue if rec.is_canceled: rec.state = "canceled" @@ -192,8 +193,8 @@ class ContractLine(models.Model): ("date_end", ">=", today), ("date_end", "=", False), "|", - "&", ("is_auto_renew", "=", True), + "&", ("is_auto_renew", "=", False), ("termination_notice_date", ">", today), ] @@ -290,16 +291,16 @@ class ContractLine(models.Model): ) def _compute_allowed(self): for rec in self: + rec.update( + { + "is_plan_successor_allowed": False, + "is_stop_plan_successor_allowed": False, + "is_stop_allowed": False, + "is_cancel_allowed": False, + "is_un_cancel_allowed": False, + } + ) if rec.contract_id.is_terminated: - rec.update( - { - "is_plan_successor_allowed": False, - "is_stop_plan_successor_allowed": False, - "is_stop_allowed": False, - "is_cancel_allowed": False, - "is_un_cancel_allowed": False, - } - ) continue if rec.date_start: allowed = get_allowed( @@ -315,7 +316,9 @@ class ContractLine(models.Model): rec.update( { "is_plan_successor_allowed": allowed.plan_successor, - "is_stop_plan_successor_allowed": allowed.stop_plan_successor, + "is_stop_plan_successor_allowed": ( + allowed.stop_plan_successor + ), "is_stop_allowed": allowed.stop, "is_cancel_allowed": allowed.cancel, "is_un_cancel_allowed": allowed.uncancel, @@ -618,7 +621,13 @@ class ContractLine(models.Model): % line.name ) - @api.depends("recurring_next_date", "date_start", "date_end") + @api.depends( + "display_type", + "is_recurring_note", + "recurring_next_date", + "date_start", + "date_end", + ) def _compute_create_invoice_visibility(self): # TODO: depending on the lines, and their order, some sections # have no meaning in certain invoices @@ -633,51 +642,31 @@ class ContractLine(models.Model): else: rec.create_invoice_visibility = False - @api.multi - def _prepare_invoice_line(self, invoice_id=False, invoice_values=False): + def _prepare_invoice_line(self, move_form): self.ensure_one() dates = self._get_period_to_invoice( self.last_date_invoiced, self.recurring_next_date ) - invoice_line_vals = { - "display_type": self.display_type, - "product_id": self.product_id.id, - "quantity": self._get_quantity_to_invoice(*dates), - "uom_id": self.uom_id.id, - "discount": self.discount, - "contract_line_id": self.id, - } - if invoice_id: - invoice_line_vals["invoice_id"] = invoice_id.id - invoice_line = ( - self.env["account.invoice.line"] - .with_context(force_company=self.contract_id.company_id.id,) - .new(invoice_line_vals) - ) - if invoice_values and not invoice_id: - invoice = ( - self.env["account.invoice"] - .with_context(force_company=self.contract_id.company_id.id,) - .new(invoice_values) - ) - invoice_line.invoice_id = invoice - # Get other invoice line values from product onchange - invoice_line._onchange_product_id() - invoice_line_vals = invoice_line._convert_to_write(invoice_line._cache) - # Insert markers + line_form = move_form.invoice_line_ids.new() + line_form.display_type = self.display_type + line_form.product_id = self.product_id + invoice_line_vals = line_form._values_to_save(all_fields=True) name = self._insert_markers(dates[0], dates[1]) invoice_line_vals.update( { + "quantity": self._get_quantity_to_invoice(*dates), + "product_uom_id": self.uom_id.id, + "discount": self.discount, + "contract_line_id": self.id, "sequence": self.sequence, "name": name, - "account_analytic_id": self.analytic_account_id.id, + "analytic_account_id": self.analytic_account_id.id, "analytic_tag_ids": [(6, 0, self.analytic_tag_ids.ids)], "price_unit": self.price_unit, } ) return invoice_line_vals - @api.multi def _get_period_to_invoice( self, last_date_invoiced, recurring_next_date, stop_at_date_end=True ): @@ -702,7 +691,6 @@ class ContractLine(models.Model): ) return first_date_invoiced, last_date_invoiced, recurring_next_date - @api.multi def _insert_markers(self, first_date_invoiced, last_date_invoiced): self.ensure_one() lang_obj = self.env["res.lang"] @@ -713,7 +701,6 @@ class ContractLine(models.Model): name = name.replace("#END#", last_date_invoiced.strftime(date_format)) return name - @api.multi def _update_recurring_next_date(self): for rec in self: last_date_invoiced = rec.next_period_date_end @@ -732,7 +719,6 @@ class ContractLine(models.Model): } ) - @api.multi def _init_last_date_invoiced(self): """Used to init last_date_invoiced for migration purpose""" for rec in self: @@ -778,7 +764,6 @@ class ContractLine(models.Model): else: return relativedelta(years=interval) - @api.multi def _delay(self, delay_delta): """ Delay a contract line @@ -811,7 +796,6 @@ class ContractLine(models.Model): } ) - @api.multi def _prepare_value_for_stop(self, date_end, manual_renew_needed): self.ensure_one() return { @@ -828,7 +812,6 @@ class ContractLine(models.Model): ), } - @api.multi def stop(self, date_end, manual_renew_needed=False, post_message=True): """ Put date_end on contract line @@ -868,7 +851,6 @@ class ContractLine(models.Model): ) return True - @api.multi def _prepare_value_for_plan_successor( self, date_start, date_end, is_auto_renew, recurring_next_date=False ): @@ -893,7 +875,6 @@ class ContractLine(models.Model): values["predecessor_contract_line_id"] = self.id return values - @api.multi def plan_successor( self, date_start, @@ -939,7 +920,6 @@ class ContractLine(models.Model): rec.contract_id.message_post(body=msg) return contract_line - @api.multi def stop_plan_successor(self, date_start, date_end, is_auto_renew): """ Stop a contract line for a defined period and start it later @@ -1035,7 +1015,6 @@ class ContractLine(models.Model): rec.contract_id.message_post(body=msg) return contract_line - @api.multi def cancel(self): if not all(self.mapped("is_cancel_allowed")): raise ValidationError(_("Cancel not allowed for this line")) @@ -1053,7 +1032,6 @@ class ContractLine(models.Model): ) return self.write({"is_canceled": True, "is_auto_renew": False}) - @api.multi def uncancel(self, recurring_next_date): if not all(self.mapped("is_un_cancel_allowed")): raise ValidationError(_("Un-cancel not allowed for this line")) @@ -1075,7 +1053,6 @@ class ContractLine(models.Model): rec.recurring_next_date = recurring_next_date return True - @api.multi def action_uncancel(self): self.ensure_one() context = { @@ -1088,14 +1065,12 @@ class ContractLine(models.Model): "type": "ir.actions.act_window", "name": "Un-Cancel Contract Line", "res_model": "contract.line.wizard", - "view_type": "form", "view_mode": "form", "views": [(view_id, "form")], "target": "new", "context": context, } - @api.multi def action_plan_successor(self): self.ensure_one() context = { @@ -1110,14 +1085,12 @@ class ContractLine(models.Model): "type": "ir.actions.act_window", "name": "Plan contract line successor", "res_model": "contract.line.wizard", - "view_type": "form", "view_mode": "form", "views": [(view_id, "form")], "target": "new", "context": context, } - @api.multi def action_stop(self): self.ensure_one() context = { @@ -1130,14 +1103,12 @@ class ContractLine(models.Model): "type": "ir.actions.act_window", "name": "Terminate contract line", "res_model": "contract.line.wizard", - "view_type": "form", "view_mode": "form", "views": [(view_id, "form")], "target": "new", "context": context, } - @api.multi def action_stop_plan_successor(self): self.ensure_one() context = { @@ -1152,14 +1123,12 @@ class ContractLine(models.Model): "type": "ir.actions.act_window", "name": "Suspend contract line", "res_model": "contract.line.wizard", - "view_type": "form", "view_mode": "form", "views": [(view_id, "form")], "target": "new", "context": context, } - @api.multi def _get_renewal_new_date_end(self): self.ensure_one() date_start = self.date_end + relativedelta(days=1) @@ -1168,7 +1137,6 @@ class ContractLine(models.Model): ) return date_end - @api.multi def _renew_create_line(self, date_end): self.ensure_one() date_start = self.date_end + relativedelta(days=1) @@ -1180,13 +1148,11 @@ class ContractLine(models.Model): new_line._onchange_date_start() return new_line - @api.multi def _renew_extend_line(self, date_end): self.ensure_one() self.date_end = date_end return self - @api.multi def renew(self): res = self.env["contract.line"] for rec in self: @@ -1240,7 +1206,6 @@ class ContractLine(models.Model): view_id = self.env.ref("contract.contract_line_customer_form_view").id return super().fields_view_get(view_id, view_type, toolbar, submenu) - @api.multi def unlink(self): """stop unlink uncnacled lines""" for record in self: @@ -1248,7 +1213,6 @@ class ContractLine(models.Model): raise ValidationError(_("Contract line must be canceled before delete")) return super().unlink() - @api.multi def _get_quantity_to_invoice( self, period_first_date, period_last_date, invoice_date ): diff --git a/contract/models/contract_tag.py b/contract/models/contract_tag.py index 2fb71ae6e..c45bf06c2 100644 --- a/contract/models/contract_tag.py +++ b/contract/models/contract_tag.py @@ -11,5 +11,5 @@ class ContractTag(models.Model): name = fields.Char(requirment=True) company_id = fields.Many2one( - "res.company", string="Company", default=lambda self: self.env.user.company_id, + "res.company", string="Company", default=lambda self: self.env.company.id, ) diff --git a/contract/models/contract_template_line.py b/contract/models/contract_template_line.py index cb7cb0ec7..9860f1c1a 100644 --- a/contract/models/contract_template_line.py +++ b/contract/models/contract_template_line.py @@ -20,5 +20,4 @@ class ContractTemplateLine(models.Model): comodel_name="contract.template", required=True, ondelete="cascade", - oldname="analytic_account_id", ) diff --git a/contract/models/ir_ui_view.py b/contract/models/ir_ui_view.py deleted file mode 100644 index 7b0f0c609..000000000 --- a/contract/models/ir_ui_view.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2020 Tecnativa - Jairo Llopis -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - -from odoo import api, models - - -class IrUiView(models.Model): - _inherit = "ir.ui.view" - - @api.model - def _prepare_qcontext(self): - """Patch context to use fw-compatible v13 company.""" - # TODO Delete this method in v13; it's upstream there - result = super()._prepare_qcontext() - if self.env.context.get("allowed_company_ids"): - result["res_company"] = ( - self.env["res.company"] - .browse(self.env.context["allowed_company_ids"][0]) - .sudo() - ) - return result diff --git a/contract/models/res_partner.py b/contract/models/res_partner.py index b4805492e..bbfda4a74 100644 --- a/contract/models/res_partner.py +++ b/contract/models/res_partner.py @@ -14,7 +14,7 @@ class ResPartner(models.Model): string="Purchase Contracts", compute="_compute_contract_count", ) contract_ids = fields.One2many( - comodel_name="contract.contract", inverse="partner_id", string="Contracts", + comodel_name="contract.contract", inverse_name="partner_id", string="Contracts", ) def _compute_contract_count(self): diff --git a/contract/readme/ROADMAP.rst b/contract/readme/ROADMAP.rst index 4420af044..9fcacdf41 100644 --- a/contract/readme/ROADMAP.rst +++ b/contract/readme/ROADMAP.rst @@ -1,2 +1 @@ * Recover states and others functional fields in Contracts. -* Remove ``models/ir_ui_view.py`` in v13, where the workaround it contains is supported upstream. diff --git a/contract/security/contract_security.xml b/contract/security/contract_security.xml index 796169942..9b5776aa8 100644 --- a/contract/security/contract_security.xml +++ b/contract/security/contract_security.xml @@ -1,3 +1,4 @@ + Contract contract multi-company @@ -5,7 +6,7 @@ ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])] + >['|',('company_id','=',False),('company_id','in',company_ids)] Contract line multi-company @@ -13,7 +14,7 @@ ['|', ('contract_id.company_id', '=', False), ('contract_id.company_id', 'child_of', [user.company_id.id])] + >['|',('company_id','=',False),('company_id','in',company_ids)] Contract template multi-company @@ -21,7 +22,7 @@ ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])] + >['|',('company_id','=',False),('company_id','in',company_ids)] Contract template line multi-company @@ -29,6 +30,6 @@ ['|', ('contract_id.company_id', '=', False), ('contract_id.company_id', 'child_of', [user.company_id.id])] + >['|',('company_id','=',False),('company_id','in',company_ids)] diff --git a/contract/security/contract_tag.xml b/contract/security/contract_tag.xml index 459c0e009..1462c6842 100644 --- a/contract/security/contract_tag.xml +++ b/contract/security/contract_tag.xml @@ -16,6 +16,6 @@ ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])] + >['|',('company_id','=',False),('company_id','in',company_ids)] diff --git a/contract/static/description/index.html b/contract/static/description/index.html index db1637220..97cc2b423 100644 --- a/contract/static/description/index.html +++ b/contract/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

This module enables contracts management with recurring invoicing functions. Also you can print and send by email contract report.

It works for customer contract and supplier contracts.

@@ -425,7 +425,6 @@ To use it, just select the template on the contract and fields will be filled au

Known issues / Roadmap

  • Recover states and others functional fields in Contracts.
  • -
  • Remove models/ir_ui_view.py in v13, where the workaround it contains is supported upstream.
@@ -433,7 +432,7 @@ To use it, just select the template on the contract and fields will be filled au

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.

@@ -441,9 +440,8 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

Authors

    -
  • OpenERP SA
  • Tecnativa
  • -
  • LasLabs
  • +
  • ACSONE SA/NV
@@ -469,7 +467,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

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/static/src/js/section_and_note_fields_backend.js b/contract/static/src/js/section_and_note_fields_backend.js index 1ad69ad94..957655703 100644 --- a/contract/static/src/js/section_and_note_fields_backend.js +++ b/contract/static/src/js/section_and_note_fields_backend.js @@ -19,7 +19,7 @@ odoo.define("contract.section_and_note_backend", function(require) { var result = this._super.apply(this, arguments); if (this.view.arch.tag === "tree") { result.include({ - _renderBodyCell: function(record, node, index, options) { + _renderBodyCell: function(record) { var $cell = this._super.apply(this, arguments); var isSection = record.data.display_type === "line_section"; diff --git a/contract/tests/__init__.py b/contract/tests/__init__.py index a2982fdc0..d2563fa7a 100644 --- a/contract/tests/__init__.py +++ b/contract/tests/__init__.py @@ -1,4 +1,3 @@ -# © 2016 Carlos Dauden # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import test_contract diff --git a/contract/tests/test_contract.py b/contract/tests/test_contract.py index e3e6b0524..22476ddee 100644 --- a/contract/tests/test_contract.py +++ b/contract/tests/test_contract.py @@ -1,5 +1,5 @@ # Copyright 2018 Tecnativa - Carlos Dauden -# Copyright 2018 Tecnativa - Pedro M. Baeza +# Copyright 2018-2020 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from collections import namedtuple @@ -22,7 +22,7 @@ class TestContractBase(common.SavepointCase): super().setUpClass() cls.today = fields.Date.today() cls.pricelist = cls.env["product.pricelist"].create( - {"name": "pricelist for contract test",} + {"name": "pricelist for contract test"} ) cls.partner = cls.env["res.partner"].create( { @@ -163,7 +163,7 @@ class TestContract(TestContractBase): self.assertTrue(self.invoice_monthly) self.assertEqual(self.acct_line.recurring_next_date, recurring_next_date) self.inv_line = self.invoice_monthly.invoice_line_ids[0] - self.assertTrue(self.inv_line.invoice_line_tax_ids) + self.assertTrue(self.inv_line.tax_ids) self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0) self.assertEqual(self.contract.user_id, self.invoice_monthly.user_id) @@ -398,7 +398,7 @@ class TestContract(TestContractBase): def test_check_recurring_next_date_start_date(self): with self.assertRaises(ValidationError): self.acct_line.write( - {"date_start": "2018-01-01", "recurring_next_date": "2017-01-01",} + {"date_start": "2018-01-01", "recurring_next_date": "2017-01-01"} ) def test_onchange_contract_template_id(self): @@ -409,7 +409,7 @@ class TestContract(TestContractBase): self.contract._onchange_contract_template_id() res = { "contract_line_ids": [ - (0, 0, {"display_type": "line_section", "name": "Test section",}), + (0, 0, {"display_type": "line_section", "name": "Test section"}), ( 0, 0, @@ -536,7 +536,6 @@ class TestContract(TestContractBase): { "name": "Customer Contracts", "type": "ir.actions.act_window", - "view_type": "form", "res_model": "contract.contract", "xml_id": "contract.action_customer_contract", }, @@ -731,7 +730,6 @@ class TestContract(TestContractBase): "recurring_invoicing_type": recurring_invoicing_type, "recurring_rule_type": recurring_rule_type, "recurring_interval": recurring_interval, - "max_date_end": max_date_end, } ) @@ -777,7 +775,7 @@ class TestContract(TestContractBase): Result = namedtuple( "Result", - ["recurring_next_date", "next_period_date_start", "next_period_date_end",], + ["recurring_next_date", "next_period_date_start", "next_period_date_end"], ) Combination = namedtuple( "Combination", @@ -1045,7 +1043,7 @@ class TestContract(TestContractBase): def test_stop_past_contract_line(self): """Past contract line are ignored on stop""" self.acct_line.write( - {"date_end": self.today + relativedelta(months=5), "is_auto_renew": True,} + {"date_end": self.today + relativedelta(months=5), "is_auto_renew": True} ) self.acct_line.stop(self.today + relativedelta(months=7)) self.assertEqual(self.acct_line.date_end, self.today + relativedelta(months=5)) @@ -1479,7 +1477,7 @@ class TestContract(TestContractBase): def test_cancel(self): self.acct_line.write( - {"date_end": self.today + relativedelta(months=5), "is_auto_renew": True,} + {"date_end": self.today + relativedelta(months=5), "is_auto_renew": True} ) self.acct_line.cancel() self.assertTrue(self.acct_line.is_canceled) @@ -1493,7 +1491,7 @@ class TestContract(TestContractBase): self.acct_line.cancel() self.assertTrue(self.acct_line.is_canceled) wizard = self.env["contract.line.wizard"].create( - {"recurring_next_date": self.today, "contract_line_id": self.acct_line.id,} + {"recurring_next_date": self.today, "contract_line_id": self.acct_line.id} ) wizard.uncancel() self.assertFalse(self.acct_line.is_canceled) @@ -1630,10 +1628,10 @@ class TestContract(TestContractBase): self.acct_line.date_end = "2018-03-15" self.acct_line._onchange_date_start() contracts = self.contract2 - for i in range(10): + for _i in range(10): contracts |= self.contract.copy() self.env["contract.contract"].cron_recurring_create_invoice() - invoice_lines = self.env["account.invoice.line"].search( + invoice_lines = self.env["account.move.line"].search( [("contract_line_id", "in", contracts.mapped("contract_line_ids").ids)] ) self.assertEqual( @@ -1647,28 +1645,28 @@ class TestContract(TestContractBase): self.acct_line._onchange_date_start() self.contract2.unlink() contracts = self.contract - for i in range(10): + for _i in range(10): contracts |= self.contract.copy() wizard = self.env["contract.manually.create.invoice"].create( {"invoice_date": self.today} ) wizard.action_show_contract_to_invoice() contract_to_invoice_count = wizard.contract_to_invoice_count - self.assertEqual( - contracts, - self.env["contract.contract"].search( + self.assertFalse( + contracts + - self.env["contract.contract"].search( wizard.action_show_contract_to_invoice()["domain"] ), ) action = wizard.create_invoice() - invoice_lines = self.env["account.invoice.line"].search( + invoice_lines = self.env["account.move.line"].search( [("contract_line_id", "in", contracts.mapped("contract_line_ids").ids)] ) self.assertEqual( len(contracts.mapped("contract_line_ids")), len(invoice_lines), ) - invoices = self.env["account.invoice"].search(action["domain"]) - self.assertEqual(invoice_lines.mapped("invoice_id"), invoices) + invoices = self.env["account.move"].search(action["domain"]) + self.assertFalse(invoice_lines.mapped("move_id") - invoices) self.assertEqual(len(invoices), contract_to_invoice_count) def test_get_period_to_invoice_monthlylastday_postpaid(self): @@ -1957,6 +1955,7 @@ class TestContract(TestContractBase): ] self.assertEqual(set(lines.mapped("state")), set(states)) # Test search method + lines.flush() # Needed for computed stored fields like termination_notice_date for state in states: lines = self.env["contract.line"].search([("state", "=", state)]) self.assertTrue(lines, state) @@ -2036,10 +2035,10 @@ class TestContract(TestContractBase): } ) line_prepaid = self.acct_line.copy( - {"recurring_invoicing_type": "pre-paid", "recurring_rule_type": "monthly",} + {"recurring_invoicing_type": "pre-paid", "recurring_rule_type": "monthly"} ) line_postpaid = self.acct_line.copy( - {"recurring_invoicing_type": "post-paid", "recurring_rule_type": "monthly",} + {"recurring_invoicing_type": "post-paid", "recurring_rule_type": "monthly"} ) lines = line_monthlylastday | line_prepaid | line_postpaid lines.write({"last_date_invoiced": False}) @@ -2101,7 +2100,7 @@ class TestContract(TestContractBase): def test_multicompany_partner_edited(self): """Editing a partner with contracts in several companies works.""" - company2 = self.env["res.company"].create({"name": "Company 2",}) + company2 = self.env["res.company"].create({"name": "Company 2"}) unprivileged_user = self.env["res.users"].create( { "name": "unprivileged test user", @@ -2111,16 +2110,14 @@ class TestContract(TestContractBase): } ) parent_partner = self.env["res.partner"].create( - {"name": "parent partner", "is_company": True,} + {"name": "parent partner", "is_company": True} ) # Assume contract 2 is for company 2 self.contract2.company_id = company2 # Update the partner attached to both contracts - self.partner.sudo(unprivileged_user).with_context( + self.partner.with_user(unprivileged_user).with_context( company_id=company2.id, force_company=company2.id - ).write( - {"is_company": False, "parent_id": parent_partner.id,} - ) + ).write({"is_company": False, "parent_id": parent_partner.id}) def test_sale_fields_view_get(self): sale_form_view = self.env.ref("contract.contract_line_customer_form_view") @@ -2137,7 +2134,7 @@ class TestContract(TestContractBase): self.assertEqual(self.contract.invoice_count, 3) def test_contract_count_invoice_2(self): - invoices = self.env["account.invoice"] + invoices = self.env["account.move"] invoices |= self.contract.recurring_create_invoice() invoices |= self.contract.recurring_create_invoice() invoices |= self.contract.recurring_create_invoice() @@ -2260,7 +2257,7 @@ class TestContract(TestContractBase): self.assertEqual(self.contract2.currency_id, currency_cad) # Get currency from contract pricelist pricelist = self.env["product.pricelist"].create( - {"name": "Test pricelist", "currency_id": currency_eur.id,} + {"name": "Test pricelist", "currency_id": currency_eur.id} ) self.contract2.pricelist_id = pricelist.id self.contract2.contract_line_ids.automatic_price = True diff --git a/contract/views/contract.xml b/contract/views/contract.xml index 1e079017e..a677e3713 100644 --- a/contract/views/contract.xml +++ b/contract/views/contract.xml @@ -68,19 +68,14 @@ /> + +
- +