From 5acff0efbee55d6bcc4a083738ecc13fdee4834d Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sat, 23 Dec 2017 02:04:26 +0100 Subject: [PATCH] [IMP] contract: Automatic prices for lines --- contract/README.rst | 2 + contract/__manifest__.py | 2 +- contract/i18n/es.po | 93 ++++++++++++------- .../migrations/10.0.4.0.0/pre-migration.py | 13 +++ contract/models/account_analytic_contract.py | 14 ++- .../models/account_analytic_invoice_line.py | 55 +++++++++-- contract/tests/test_contract.py | 14 +++ .../views/account_analytic_account_view.xml | 4 +- .../views/account_analytic_contract_view.xml | 6 +- 9 files changed, 151 insertions(+), 52 deletions(-) create mode 100644 contract/migrations/10.0.4.0.0/pre-migration.py diff --git a/contract/README.rst b/contract/README.rst index e2aa831e..267baaef 100644 --- a/contract/README.rst +++ b/contract/README.rst @@ -33,6 +33,8 @@ To use this module, you need to: * Invoicing type: pre-paid or post-paid. #. Add the lines to be invoiced with the product, description, quantity and price. +#. You can mark Auto-price? for having a price automatically obtained applying + the pricelist to the product price. #. You have the possibility to use the markers #START# or #END# in the description field to show the start and end date of the invoiced period. #. Choosing between pre-paid and post-paid, you modify the dates that are shown diff --git a/contract/__manifest__.py b/contract/__manifest__.py index 9d9476c2..ba9acff6 100644 --- a/contract/__manifest__.py +++ b/contract/__manifest__.py @@ -9,7 +9,7 @@ { 'name': 'Contracts Management - Recurring', - 'version': '10.0.3.3.0', + 'version': '10.0.4.0.0', 'category': 'Contract Management', 'license': 'AGPL-3', 'author': "OpenERP SA, " diff --git a/contract/i18n/es.po b/contract/i18n/es.po index 27c07d2f..e9910525 100644 --- a/contract/i18n/es.po +++ b/contract/i18n/es.po @@ -1,27 +1,23 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * contract -# -# Translators: -# OCA Transbot , 2017 +# * contract +# msgid "" msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-12-08 01:46+0000\n" -"PO-Revision-Date: 2017-12-08 01:46+0000\n" -"Last-Translator: OCA Transbot , 2017\n" -"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"POT-Creation-Date: 2017-12-23 01:05+0000\n" +"PO-Revision-Date: 2017-12-23 01:05+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: \n" #. module: contract #: model:mail.template,body_html:contract.email_contract_template -msgid "" -"\n" +msgid "\n" "
\n" "

Hello ${object.partner_id.name or ''},

\n" "

A new contract has been created:

\n" @@ -69,8 +65,7 @@ msgid "" "
\n" "\n" " " -msgstr "" -"\n" +msgstr "\n" "
\n" "

Hola ${object.partner_id.name or ''},

\n" "

Se ha creado un nuevo contrato:

\n" @@ -196,6 +191,12 @@ msgstr "Ver líneas contables analíticas" msgid "Analytic Account" msgstr "Cuenta analítica" +#. module: contract +#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_line_automatic_price +#: model:ir.model.fields,field_description:contract.field_account_analytic_invoice_line_automatic_price +msgid "Auto-price?" +msgstr "¿Precio automático?" + #. module: contract #: model:ir.actions.act_window,help:contract.account_analytic_contract_action msgid "Click to create a new contract template." @@ -229,8 +230,7 @@ msgstr "Contrato" #: code:addons/contract/models/account_analytic_account.py:139 #, python-format msgid "Contract '%s' start date can't be later than end date" -msgstr "" -"La fecha de inicio del contrato '%s' no puede ser superior a la fecha de fin" +msgstr "La fecha de inicio del contrato '%s' no puede ser superior a la fecha de fin" #. module: contract #: model:ir.model,name:contract.model_account_analytic_contract_line @@ -239,6 +239,7 @@ msgstr "Lineas de contrato" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_contract_template_id +#: model:ir.model.fields,field_description:contract.field_project_project_contract_template_id #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form msgid "Contract Template" msgstr "Plantilla de contrato" @@ -263,6 +264,7 @@ msgstr "Contratos" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_create_invoice_visibility +#: model:ir.model.fields,field_description:contract.field_project_project_create_invoice_visibility msgid "Create invoice visibility" msgstr "Visibilidad de crear factura" @@ -287,6 +289,7 @@ msgstr "Creado en" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_date_end +#: model:ir.model.fields,field_description:contract.field_project_project_date_end #: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search msgid "Date End" msgstr "Fecha fin" @@ -298,6 +301,7 @@ msgstr "Fecha de inicio" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_next_date +#: model:ir.model.fields,field_description:contract.field_project_project_recurring_next_date msgid "Date of Next Invoice" msgstr "Próxima fecha de factura" @@ -320,7 +324,7 @@ msgid "Discount (%)" msgstr "Descuento (%)" #. module: contract -#: code:addons/contract/models/account_analytic_invoice_line.py:83 +#: code:addons/contract/models/account_analytic_invoice_line.py:126 #, python-format msgid "Discount should be less or equal to 100" msgstr "El descuento debería ser menor o igual a 100" @@ -328,12 +332,8 @@ msgstr "El descuento debería ser menor o igual a 100" #. module: contract #: model:ir.model.fields,help:contract.field_account_analytic_contract_line_discount #: model:ir.model.fields,help:contract.field_account_analytic_invoice_line_discount -msgid "" -"Discount that is applied in generated invoices. It should be less or equal " -"to 100" -msgstr "" -"Descuento que es aplicado en las facturas generadas. Debería ser menor o " -"igual a 100" +msgid "Discount that is applied in generated invoices. It should be less or equal to 100" +msgstr "Descuento que es aplicado en las facturas generadas. Debería ser menor o igual a 100" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_display_name @@ -349,6 +349,7 @@ msgstr "Finalizado" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_invoices +#: model:ir.model.fields,field_description:contract.field_project_project_recurring_invoices msgid "Generate recurring invoices automatically" msgstr "Generar facturas recurrentes automáticamente." @@ -364,6 +365,12 @@ msgstr "Agrupar por..." msgid "ID" msgstr "ID (identificación)" +#. module: contract +#: model:ir.model.fields,help:contract.field_account_analytic_contract_line_automatic_price +#: model:ir.model.fields,help:contract.field_account_analytic_invoice_line_automatic_price +msgid "If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price" +msgstr "Si está marcado, el precio se obtendrá automáticamente aplicando la tarifa al producto. Si no, podrá introducir un precio manual" + #. module: contract #: model:ir.model,name:contract.model_account_invoice msgid "Invoice" @@ -372,6 +379,7 @@ msgstr "Factura" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_invoice_line_ids #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_recurring_invoice_line_ids +#: model:ir.model.fields,field_description:contract.field_project_project_recurring_invoice_line_ids #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form msgid "Invoice Lines" msgstr "Líneas de factura" @@ -384,6 +392,7 @@ msgstr "Facturas" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_invoicing_type #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_recurring_invoicing_type +#: model:ir.model.fields,field_description:contract.field_project_project_recurring_invoicing_type #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search msgid "Invoicing type" msgstr "Tipo de facturación" @@ -391,6 +400,7 @@ msgstr "Tipo de facturación" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_journal_id #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_journal_id +#: model:ir.model.fields,field_description:contract.field_project_project_journal_id #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search msgid "Journal" msgstr "Diario" @@ -420,8 +430,7 @@ msgstr "Última actualización en" #: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form msgid "Legend (for the markers inside invoice lines description)" -msgstr "" -"Leyenda (para los marcadores dentro de descripción en lineas de factura)" +msgstr "Leyenda (para los marcadores dentro de descripción en lineas de factura)" #. module: contract #: selection:account.analytic.account,recurring_rule_type:0 @@ -450,6 +459,11 @@ msgstr "Próxima factura" msgid "Partner" msgstr "Empresa" +#. module: contract +#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_partner_id +msgid "Partner (always False)" +msgstr "Empresa (siempre Falso)" + #. module: contract #: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search msgid "Partner and dependents" @@ -476,6 +490,7 @@ msgstr "Prepago" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_pricelist_id #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_pricelist_id +#: model:ir.model.fields,field_description:contract.field_project_project_pricelist_id #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search msgid "Pricelist" msgstr "Lista de precios" @@ -495,6 +510,7 @@ msgstr "Cantidad" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_rule_type #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_recurring_rule_type +#: model:ir.model.fields,field_description:contract.field_project_project_recurring_rule_type #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search msgid "Recurrence" msgstr "Recurrencia" @@ -508,12 +524,14 @@ msgstr "Facturas recurrentes" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_interval #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_recurring_interval +#: model:ir.model.fields,field_description:contract.field_project_project_recurring_interval msgid "Repeat Every" msgstr "Repetir cada" #. module: contract #: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_interval #: model:ir.model.fields,help:contract.field_account_analytic_contract_recurring_interval +#: model:ir.model.fields,help:contract.field_project_project_recurring_interval msgid "Repeat every (Days/Week/Month/Year)" msgstr "Repetir cada (días/semana/mes/año)" @@ -544,18 +562,25 @@ msgstr "Secuencia de la linea de contrato cuando se muestra en los contratos" msgid "Show the contracts for this partner" msgstr "Muestra los contratos para esta empresa/contacto" +#. module: contract +#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_line_specific_price +#: model:ir.model.fields,field_description:contract.field_account_analytic_invoice_line_specific_price +msgid "Specific Price" +msgstr "Precio específico" + #. module: contract #: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_rule_type #: model:ir.model.fields,help:contract.field_account_analytic_contract_recurring_rule_type +#: model:ir.model.fields,help:contract.field_project_project_recurring_rule_type msgid "Specify Interval for automatic invoice generation." msgstr "Especifica el intervalo para la generación de facturas automática." #. module: contract #: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_invoicing_type #: model:ir.model.fields,help:contract.field_account_analytic_contract_recurring_invoicing_type +#: model:ir.model.fields,help:contract.field_project_project_recurring_invoicing_type msgid "Specify if process date is 'from' or 'to' invoicing date" -msgstr "" -"Especifica si la fecha de proceso es desde o hasta la fecha de facturación" +msgstr "Especifica si la fecha de proceso es desde o hasta la fecha de facturación" #. module: contract #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_line_price_subtotal @@ -600,11 +625,8 @@ msgstr "Año(s)" #. module: contract #: code:addons/contract/models/account_analytic_account.py:112 #, python-format -msgid "" -"You can't have a next invoicing date before the start of the contract '%s'" -msgstr "" -"No puede tener una fecha de próxima factura anterior a la fecha de inicio " -"del contrato '%s'" +msgid "You can't have a next invoicing date before the start of the contract '%s'" +msgstr "No puede tener una fecha de próxima factura anterior a la fecha de inicio del contrato '%s'" #. module: contract #: code:addons/contract/models/account_analytic_account.py:217 @@ -615,11 +637,9 @@ msgstr "¡Seleccione un cliente para este contrato %s!" #. module: contract #: code:addons/contract/models/account_analytic_account.py:274 #, python-format -msgid "" -"You must review start and end dates!\n" +msgid "You must review start and end dates!\n" "%s" -msgstr "" -"Debe revisar las fechas de inicio y de fin\n" +msgstr "Debe revisar las fechas de inicio y de fin\n" "%s" #. module: contract @@ -654,3 +674,4 @@ msgstr "account.analytic.invoice.line" #: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form msgid "⇒ Show recurring invoices" msgstr "⇒ Mostrar facturas recurrentes" + diff --git a/contract/migrations/10.0.4.0.0/pre-migration.py b/contract/migrations/10.0.4.0.0/pre-migration.py new file mode 100644 index 00000000..b97bb7a0 --- /dev/null +++ b/contract/migrations/10.0.4.0.0/pre-migration.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Copyright 2015-2017 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +def migrate(cr, version): + """Rename column for specific price for keeping backwards compatibility.""" + if not version: + return + cr.execute( + "ALTER TABLE account_analytic_invoice_line " + "RENAME price_unit TO specific_price" + ) diff --git a/contract/models/account_analytic_contract.py b/contract/models/account_analytic_contract.py index 87afdee9..6f04a9e5 100644 --- a/contract/models/account_analytic_contract.py +++ b/contract/models/account_analytic_contract.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -# © 2004-2010 OpenERP SA -# © 2014 Angel Moya -# © 2015 Pedro M. Baeza -# © 2016 Carlos Dauden +# Copyright 2004-2010 OpenERP SA +# Copyright 2014 Angel Moya +# Copyright 2016 Carlos Dauden # Copyright 2016-2017 LasLabs Inc. +# Copyright 2015-2017 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models @@ -15,11 +15,17 @@ class AccountAnalyticContract(models.Model): # These fields will not be synced to the contract NO_SYNC = [ 'name', + 'partner_id', ] name = fields.Char( required=True, ) + # Needed for avoiding errors on several inherited behaviors + partner_id = fields.Many2one( + comodel_name="res.partner", + string="Partner (always False)", + ) pricelist_id = fields.Many2one( comodel_name='product.pricelist', string='Pricelist', diff --git a/contract/models/account_analytic_invoice_line.py b/contract/models/account_analytic_invoice_line.py index 12a61c65..760e3f88 100644 --- a/contract/models/account_analytic_invoice_line.py +++ b/contract/models/account_analytic_invoice_line.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -# © 2004-2010 OpenERP SA -# © 2014 Angel Moya -# © 2015 Pedro M. Baeza -# © 2016 Carlos Dauden +# Copyright 2004-2010 OpenERP SA +# Copyright 2014 Angel Moya +# Copyright 2016 Carlos Dauden # Copyright 2016-2017 LasLabs Inc. +# Copyright 2015-2017 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models @@ -40,9 +40,19 @@ class AccountAnalyticInvoiceLine(models.Model): string='Unit of Measure', required=True, ) + automatic_price = fields.Boolean( + string="Auto-price?", + help="If this is marked, the price will be obtained automatically " + "applying the pricelist to the product. If not, you will be " + "able to introduce a manual price", + ) + specific_price = fields.Float( + string='Specific Price', + ) price_unit = fields.Float( - 'Unit Price', - required=True, + string='Unit Price', + compute="_compute_price_unit", + inverse="_inverse_price_unit", ) price_subtotal = fields.Float( compute='_compute_price_subtotal', @@ -61,6 +71,35 @@ class AccountAnalyticInvoiceLine(models.Model): help="Sequence of the contract line when displaying contracts", ) + @api.depends( + 'automatic_price', + 'specific_price', + 'product_id', + 'quantity', + 'analytic_account_id.pricelist_id', + 'analytic_account_id.partner_id', + ) + def _compute_price_unit(self): + """Get the specific price if no auto-price, and the price obtained + from the pricelist otherwise. + """ + for line in self: + if line.automatic_price: + product = line.product_id.with_context( + quantity=line.quantity, + pricelist=line.analytic_account_id.pricelist_id.id, + partner=line.analytic_account_id.partner_id.id, + date=line.env.context.get('old_date', fields.Date.today()), + ) + line.price_unit = product.price + else: + line.price_unit = line.specific_price + + def _inverse_price_unit(self): + """Store the specific price in the no auto-price records.""" + for line in self.filtered(lambda x: not x.automatic_price): + line.specific_price = self.price_unit + @api.multi @api.depends('quantity', 'price_unit', 'discount') def _compute_price_subtotal(self): @@ -98,12 +137,12 @@ class AccountAnalyticInvoiceLine(models.Model): if self.analytic_account_id._name == 'account.analytic.account': date = ( self.analytic_account_id.recurring_next_date or - fields.Datetime.now() + fields.Date.today() ) partner = self.analytic_account_id.partner_id else: - date = fields.Datetime.now() + date = fields.Date.today() partner = self.env.user.partner_id product = self.product_id.with_context( diff --git a/contract/tests/test_contract.py b/contract/tests/test_contract.py index 45f3223d..b622f7dc 100644 --- a/contract/tests/test_contract.py +++ b/contract/tests/test_contract.py @@ -60,6 +60,20 @@ class TestContract(TestContractBase): with self.assertRaises(ValidationError): self.acct_line.write({'discount': 120}) + def test_automatic_price(self): + self.acct_line.automatic_price = True + self.product.list_price = 1100 + self.assertEqual(self.acct_line.price_unit, 1100) + # Try to write other price + self.acct_line.price_unit = 10 + self.acct_line.refresh() + self.assertEqual(self.acct_line.price_unit, 1100) + # Now disable automatic price + self.acct_line.automatic_price = False + self.acct_line.price_unit = 10 + self.acct_line.refresh() + self.assertEqual(self.acct_line.price_unit, 10) + def test_contract(self): self.assertAlmostEqual(self.acct_line.price_subtotal, 50.0) res = self.acct_line._onchange_product_id() diff --git a/contract/views/account_analytic_account_view.xml b/contract/views/account_analytic_account_view.xml index 1850afd3..6a47a0d0 100644 --- a/contract/views/account_analytic_account_view.xml +++ b/contract/views/account_analytic_account_view.xml @@ -77,7 +77,9 @@ - + + + diff --git a/contract/views/account_analytic_contract_view.xml b/contract/views/account_analytic_contract_view.xml index e5a43111..0071d9f1 100644 --- a/contract/views/account_analytic_contract_view.xml +++ b/contract/views/account_analytic_contract_view.xml @@ -29,14 +29,16 @@ - + - + + +