Browse Source

[10.0][FIX+IMP] contract: Improve usability and don't fail on wrong data (#130)

* [FIX+IMP] contract: Improve usability and don't fail on wrong data

* Cron create invoices masked for avoiding silent errors
* New constraints for assuring data consistency
* UI helps for entering consistent data
* Spanish translation
* Remove double company_id field on form
pull/202/head
Pedro M. Baeza 7 years ago
parent
commit
9c3bf1cb03
  1. 2
      contract/__manifest__.py
  2. 117
      contract/i18n/es.po
  3. 77
      contract/models/account_analytic_account.py
  4. 73
      contract/tests/test_contract.py
  5. 22
      contract/views/account_analytic_account_view.xml
  6. 2
      contract/views/account_analytic_contract_view.xml
  7. 2
      contract/views/res_partner_view.xml

2
contract/__manifest__.py

@ -8,7 +8,7 @@
{ {
'name': 'Contracts Management - Recurring', 'name': 'Contracts Management - Recurring',
'version': '11.0.1.1.0',
'version': '11.0.1.2.0',
'category': 'Contract Management', 'category': 'Contract Management',
'license': 'AGPL-3', 'license': 'AGPL-3',
'author': "OpenERP SA, " 'author': "OpenERP SA, "

117
contract/i18n/es.po

@ -5,6 +5,8 @@
# Translators: # Translators:
# OCA Transbot <transbot@odoo-community.org>, 2017 # OCA Transbot <transbot@odoo-community.org>, 2017
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2017 # Pedro M. Baeza <pedro.baeza@gmail.com>, 2017
# * contract
#
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 11.0\n" "Project-Id-Version: Odoo Server 11.0\n"
@ -16,13 +18,11 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: \n"
#. module: contract #. module: contract
#: model:mail.template,body_html:contract.email_contract_template #: model:mail.template,body_html:contract.email_contract_template
msgid ""
"\n"
msgid "\n"
"<div style=\"font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; \">\n" "<div style=\"font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; \">\n"
" <p>Hello ${object.partner_id.name or ''},</p>\n" " <p>Hello ${object.partner_id.name or ''},</p>\n"
" <p>A new contract has been created: </p>\n" " <p>A new contract has been created: </p>\n"
@ -70,8 +70,7 @@ msgid ""
" </div>\n" " </div>\n"
"</div>\n" "</div>\n"
" " " "
msgstr ""
"\n"
msgstr "\n"
"<div style=\"font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; \">\n" "<div style=\"font-family: 'Lucida Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; \">\n"
" <p>Hola ${object.partner_id.name or ''},</p>\n" " <p>Hola ${object.partner_id.name or ''},</p>\n"
" <p>Se ha creado un nuevo contrato: </p>\n" " <p>Se ha creado un nuevo contrato: </p>\n"
@ -143,7 +142,7 @@ msgstr "<strong>Contrato: </strong>"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document #: model:ir.ui.view,arch_db:contract.report_contract_document
msgid "<strong>Date Start: </strong>" msgid "<strong>Date Start: </strong>"
msgstr "<strong>Fecha inicio: </strong>"
msgstr "<strong>Fecha de inicio: </strong>"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.report_contract_document #: model:ir.ui.view,arch_db:contract.report_contract_document
@ -200,15 +199,21 @@ msgstr "Cuenta analítica"
#. module: contract #. module: contract
#: model:ir.actions.act_window,help:contract.account_analytic_contract_action #: model:ir.actions.act_window,help:contract.account_analytic_contract_action
msgid "Click to create a new contract template." msgid "Click to create a new contract template."
msgstr "Pinche para crear una nueva plantilla de contrato"
msgstr "Pulse para crear una nueva plantilla de contrato."
#. module: contract #. module: contract
#: model:ir.actions.act_window,help:contract.action_account_analytic_overdue_all #: model:ir.actions.act_window,help:contract.action_account_analytic_overdue_all
msgid "Click to create a new contract." msgid "Click to create a new contract."
msgstr "Pinche para crear un contrato nuevo. "
msgstr "Pulse para crear un contrato nuevo. "
#. module: contract #. module: contract
#: code:addons/contract/models/account_analytic_account.py:264 #: code:addons/contract/models/account_analytic_account.py:264
#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_company_id
msgid "Company"
msgstr "Compañía"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:321
#, python-format #, python-format
msgid "Compose Email" msgid "Compose Email"
msgstr "Componer correo electrónico" msgstr "Componer correo electrónico"
@ -226,6 +231,12 @@ msgstr "Contacto"
msgid "Contract" msgid "Contract"
msgstr "Contrato" msgstr "Contrato"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:138
#, 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"
#. module: contract #. module: contract
#: model:ir.model,name:contract.model_account_analytic_contract_line #: model:ir.model,name:contract.model_account_analytic_contract_line
msgid "Contract Lines" msgid "Contract Lines"
@ -233,6 +244,7 @@ msgstr "Líneas de contrato"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_contract_template_id #: 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 #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form
msgid "Contract Template" msgid "Contract Template"
msgstr "Plantilla de contrato" msgstr "Plantilla de contrato"
@ -255,6 +267,12 @@ msgstr "Plantillas de contrato"
msgid "Contracts" msgid "Contracts"
msgstr "Contratos" 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"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form #: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form
msgid "Create invoices" msgid "Create invoices"
@ -276,6 +294,7 @@ msgstr "Creado en"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_date_end #: 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 #: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search
msgid "Date End" msgid "Date End"
msgstr "Fecha fin" msgstr "Fecha fin"
@ -283,10 +302,11 @@ msgstr "Fecha fin"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_date_start #: model:ir.model.fields,field_description:contract.field_account_analytic_account_date_start
msgid "Date Start" msgid "Date Start"
msgstr "Fecha inicio"
msgstr "Fecha de inicio"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_next_date #: 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" msgid "Date of Next Invoice"
msgstr "Próxima fecha de factura" msgstr "Próxima fecha de factura"
@ -317,12 +337,8 @@ msgstr "El descuento debería ser menor o igual a 100"
#. module: contract #. module: contract
#: model:ir.model.fields,help:contract.field_account_analytic_contract_line_discount #: model:ir.model.fields,help:contract.field_account_analytic_contract_line_discount
#: model:ir.model.fields,help:contract.field_account_analytic_invoice_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 #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_display_name #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_display_name
@ -345,6 +361,7 @@ msgstr "Generar facturas recurrentes desde los contratos"
#. module: contract #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_invoices #: 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" msgid "Generate recurring invoices automatically"
msgstr "Generar facturas recurrentes automáticamente." msgstr "Generar facturas recurrentes automáticamente."
@ -368,6 +385,7 @@ msgstr "Factura"
#. module: contract #. 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_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_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 #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form
msgid "Invoice Lines" msgid "Invoice Lines"
msgstr "Líneas de factura" msgstr "Líneas de factura"
@ -385,12 +403,15 @@ msgstr "Tipo Facturación"
#. module: contract #. 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_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_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" msgid "Invoicing type"
msgstr "Tipo de facturación" msgstr "Tipo de facturación"
#. module: contract #. 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_account_journal_id
#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_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 #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search
msgid "Journal" msgid "Journal"
msgstr "Diario" msgstr "Diario"
@ -420,8 +441,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_account_recurring_form_form
#: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_form
msgid "Legend (for the markers inside invoice lines description)" 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 #. module: contract
#: selection:account.analytic.account,recurring_rule_type:0 #: selection:account.analytic.account,recurring_rule_type:0
@ -445,16 +465,21 @@ msgstr "Nombre"
msgid "Next Invoice" msgid "Next Invoice"
msgstr "Próxima factura" msgstr "Próxima factura"
#. module: contract
#: model:ir.model,name:contract.model_res_partner
msgid "Partner"
msgstr "Empresa"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search #: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search
msgid "Partner and dependents" msgid "Partner and dependents"
msgstr "Empresa y contactos" msgstr "Empresa y contactos"
#. module: contract #. module: contract
#: code:addons/contract/models/account_analytic_account.py:170
#: code:addons/contract/models/account_analytic_account.py:224
#, python-format #, python-format
msgid "Please define a sale journal for the company '%s'." msgid "Please define a sale journal for the company '%s'."
msgstr "Por favor define un diario de ventas para la compañía '%s'."
msgstr "Por favor defina un diario de ventas para la compañía '%s'."
#. module: contract #. module: contract
#: selection:account.analytic.account,recurring_invoicing_type:0 #: selection:account.analytic.account,recurring_invoicing_type:0
@ -471,6 +496,7 @@ msgstr "Prepago"
#. module: contract #. 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_account_pricelist_id
#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_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 #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search
msgid "Pricelist" msgid "Pricelist"
msgstr "Lista de precios" msgstr "Lista de precios"
@ -490,6 +516,7 @@ msgstr "Cantidad"
#. module: contract #. 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_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_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 #: model:ir.ui.view,arch_db:contract.account_analytic_contract_view_search
msgid "Recurrence" msgid "Recurrence"
msgstr "Recurrencia" msgstr "Recurrencia"
@ -503,12 +530,14 @@ msgstr "Facturas recurrentes"
#. module: contract #. 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_account_recurring_interval
#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_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" msgid "Repeat Every"
msgstr "Repetir cada" msgstr "Repetir cada"
#. module: contract #. module: contract
#: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_interval #: 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_account_analytic_contract_recurring_interval
#: model:ir.model.fields,help:contract.field_project_project_recurring_interval
msgid "Repeat every (Days/Week/Month/Year)" msgid "Repeat every (Days/Week/Month/Year)"
msgstr "Repetir cada (días/semana/mes/año)" msgstr "Repetir cada (días/semana/mes/año)"
@ -532,20 +561,21 @@ msgstr "Secuencia"
#: model:ir.model.fields,help:contract.field_account_analytic_contract_line_sequence #: model:ir.model.fields,help:contract.field_account_analytic_contract_line_sequence
#: model:ir.model.fields,help:contract.field_account_analytic_invoice_line_sequence #: model:ir.model.fields,help:contract.field_account_analytic_invoice_line_sequence
msgid "Sequence of the contract line when displaying contracts" msgid "Sequence of the contract line when displaying contracts"
msgstr "Secuencia de la línea de contrato cuando se visualizan los contratos"
msgstr "Secuencia de la linea de contrato cuando se muestra en los contratos"
#. module: contract #. module: contract
#: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_rule_type #: 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_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." msgid "Specify Interval for automatic invoice generation."
msgstr "Especifica el intervalo para la generación de facturas automática." msgstr "Especifica el intervalo para la generación de facturas automática."
#. module: contract #. module: contract
#: model:ir.model.fields,help:contract.field_account_analytic_account_recurring_invoicing_type #: 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_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" 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 #. module: contract
#: model:ir.model.fields,field_description:contract.field_account_analytic_contract_line_price_subtotal #: model:ir.model.fields,field_description:contract.field_account_analytic_contract_line_price_subtotal
@ -573,7 +603,7 @@ msgstr "NIF:"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search #: model:ir.ui.view,arch_db:contract.view_account_analytic_account_contract_search
msgid "Valid" msgid "Valid"
msgstr "Vigente"
msgstr "Válido"
#. module: contract #. module: contract
#: selection:account.analytic.account,recurring_rule_type:0 #: selection:account.analytic.account,recurring_rule_type:0
@ -588,21 +618,43 @@ msgid "Year(s)"
msgstr "Año(s)" msgstr "Año(s)"
#. module: contract #. module: contract
#: code:addons/contract/models/account_analytic_account.py:162
#: code:addons/contract/models/account_analytic_account.py:111
#, 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'"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:216
#, python-format #, python-format
msgid "You must first select a Customer for Contract %s!" msgid "You must first select a Customer for Contract %s!"
msgstr "¡Seleccione un cliente para este contrato %s!" msgstr "¡Seleccione un cliente para este contrato %s!"
#. module: contract #. module: contract
#: code:addons/contract/models/account_analytic_account.py:217
#: code:addons/contract/models/account_analytic_account.py:273
#, python-format #, python-format
msgid ""
"You must review start and end dates!\n"
msgid "You must review start and end dates!\n"
"%s" "%s"
msgstr ""
"Debe revisar las fechas de inicio y de fin\n"
msgstr "Debe revisar las fechas de inicio y de fin\n"
"%s" "%s"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:102
#, python-format
msgid "You must supply a customer for the contract '%s'"
msgstr "Debe especificar un cliente para el contrato '%s'"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:120
#, python-format
msgid "You must supply a next invoicing date for contract '%s'"
msgstr "Debe suministrar una fecha de próxima factura para el contrato '%s'"
#. module: contract
#: code:addons/contract/models/account_analytic_account.py:129
#, python-format
msgid "You must supply a start date for contract '%s'"
msgstr "Debe suministrar una fecha de inicio para el contrato '%s'"
#. module: contract #. module: contract
#: model:ir.model,name:contract.model_account_analytic_contract #: model:ir.model,name:contract.model_account_analytic_contract
msgid "account.analytic.contract" msgid "account.analytic.contract"
@ -615,10 +667,11 @@ msgstr "account.analytic.invoice.line"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.view_partner_form #: model:ir.ui.view,arch_db:contract.view_partner_form
msgid "show the contracts for this partner"
msgstr "Mostrar los contratos de este partner"
msgid "Show the contracts for this partner"
msgstr "Muestra los contratos para esta empresa/contacto"
#. module: contract #. module: contract
#: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form #: model:ir.ui.view,arch_db:contract.account_analytic_account_recurring_form_form
msgid "⇒ Show recurring invoices" msgid "⇒ Show recurring invoices"
msgstr "⇒ Mostrar facturas recurrentes" msgstr "⇒ Mostrar facturas recurrentes"

77
contract/models/account_analytic_account.py

@ -50,6 +50,17 @@ class AccountAnalyticAccount(models.Model):
index=True, index=True,
default=lambda self: self.env.user, default=lambda self: self.env.user,
) )
create_invoice_visibility = fields.Boolean(
compute='_compute_create_invoice_visibility',
)
@api.depends('recurring_next_date', 'date_end')
def _compute_create_invoice_visibility(self):
for contract in self:
contract.create_invoice_visibility = (
not contract.date_end or
contract.recurring_next_date <= contract.date_end
)
@api.onchange('contract_template_id') @api.onchange('contract_template_id')
def _onchange_contract_template_id(self): def _onchange_contract_template_id(self):
@ -76,15 +87,60 @@ class AccountAnalyticAccount(models.Model):
)): )):
self[field_name] = self.contract_template_id[field_name] self[field_name] = self.contract_template_id[field_name]
@api.onchange('recurring_invoices')
def _onchange_recurring_invoices(self):
if self.date_start and self.recurring_invoices:
@api.onchange('date_start')
def _onchange_date_start(self):
if self.date_start:
self.recurring_next_date = self.date_start self.recurring_next_date = self.date_start
@api.onchange('partner_id') @api.onchange('partner_id')
def _onchange_partner_id(self): def _onchange_partner_id(self):
self.pricelist_id = self.partner_id.property_product_pricelist.id self.pricelist_id = self.partner_id.property_product_pricelist.id
@api.constrains('partner_id', 'recurring_invoices')
def _check_partner_id_recurring_invoices(self):
for contract in self.filtered('recurring_invoices'):
if not contract.partner_id:
raise ValidationError(
_("You must supply a customer for the contract '%s'") %
contract.name
)
@api.constrains('recurring_next_date', 'date_start')
def _check_recurring_next_date_start_date(self):
for contract in self.filtered('recurring_next_date'):
if contract.date_start > contract.recurring_next_date:
raise ValidationError(
_("You can't have a next invoicing date before the start "
"of the contract '%s'") % contract.name
)
@api.constrains('recurring_next_date', 'recurring_invoices')
def _check_recurring_next_date_recurring_invoices(self):
for contract in self.filtered('recurring_invoices'):
if not contract.recurring_next_date:
raise ValidationError(
_("You must supply a next invoicing date for contract "
"'%s'") % contract.name
)
@api.constrains('date_start', 'recurring_invoices')
def _check_date_start_recurring_invoices(self):
for contract in self.filtered('recurring_invoices'):
if not contract.date_start:
raise ValidationError(
_("You must supply a start date for contract '%s'") %
contract.name
)
@api.constrains('date_start', 'date_end')
def _check_start_end_dates(self):
for contract in self.filtered('date_end'):
if contract.date_start > contract.date_end:
raise ValidationError(
_("Contract '%s' start date can't be later than end date")
% contract.name
)
@api.multi @api.multi
def _convert_contract_lines(self, contract): def _convert_contract_lines(self, contract):
self.ensure_one() self.ensure_one()
@ -204,8 +260,8 @@ class AccountAnalyticAccount(models.Model):
@api.multi @api.multi
def recurring_create_invoice(self): def recurring_create_invoice(self):
"""
Create invoices from contracts
"""Create invoices from contracts
:return: invoices created :return: invoices created
""" """
invoices = self.env['account.invoice'] invoices = self.env['account.invoice']
@ -213,9 +269,12 @@ class AccountAnalyticAccount(models.Model):
ref_date = contract.recurring_next_date or fields.Date.today() ref_date = contract.recurring_next_date or fields.Date.today()
if (contract.date_start > ref_date or if (contract.date_start > ref_date or
contract.date_end and contract.date_end < ref_date): contract.date_end and contract.date_end < ref_date):
if self.env.context.get('cron'):
continue # Don't fail on cron jobs
raise ValidationError( raise ValidationError(
_("You must review start and end dates!\n%s") % _("You must review start and end dates!\n%s") %
contract.name)
contract.name
)
old_date = fields.Date.from_string(ref_date) old_date = fields.Date.from_string(ref_date)
new_date = old_date + self.get_relative_delta( new_date = old_date + self.get_relative_delta(
contract.recurring_rule_type, contract.recurring_interval) contract.recurring_rule_type, contract.recurring_interval)
@ -223,20 +282,20 @@ class AccountAnalyticAccount(models.Model):
ctx.update({ ctx.update({
'old_date': old_date, 'old_date': old_date,
'next_date': new_date, 'next_date': new_date,
# Force company for correct evaluate domain access rules
# Force company for correct evaluation of domain access rules
'force_company': contract.company_id.id, 'force_company': contract.company_id.id,
}) })
# Re-read contract with correct company # Re-read contract with correct company
invoices |= contract.with_context(ctx)._create_invoice() invoices |= contract.with_context(ctx)._create_invoice()
contract.write({ contract.write({
'recurring_next_date': new_date.strftime('%Y-%m-%d')
'recurring_next_date': fields.Date.to_string(new_date)
}) })
return invoices return invoices
@api.model @api.model
def cron_recurring_create_invoice(self): def cron_recurring_create_invoice(self):
today = fields.Date.today() today = fields.Date.today()
contracts = self.search([
contracts = self.with_context(cron=True).search([
('recurring_invoices', '=', True), ('recurring_invoices', '=', True),
('recurring_next_date', '<=', today), ('recurring_next_date', '<=', today),
'|', '|',

73
contract/tests/test_contract.py

@ -64,18 +64,14 @@ class TestContract(TestContractBase):
res = self.acct_line._onchange_product_id() res = self.acct_line._onchange_product_id()
self.assertIn('uom_id', res['domain']) self.assertIn('uom_id', res['domain'])
self.acct_line.price_unit = 100.0 self.acct_line.price_unit = 100.0
self.contract.partner_id = False
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.contract.recurring_create_invoice()
self.contract.partner_id = False
self.contract.partner_id = self.partner.id self.contract.partner_id = self.partner.id
self.contract.recurring_create_invoice() self.contract.recurring_create_invoice()
self.invoice_monthly = self.env['account.invoice'].search( self.invoice_monthly = self.env['account.invoice'].search(
[('contract_id', '=', self.contract.id)]) [('contract_id', '=', self.contract.id)])
self.assertTrue(self.invoice_monthly) self.assertTrue(self.invoice_monthly)
self.assertEqual(self.contract.recurring_next_date, '2016-03-29') self.assertEqual(self.contract.recurring_next_date, '2016-03-29')
self.inv_line = self.invoice_monthly.invoice_line_ids[0] self.inv_line = self.invoice_monthly.invoice_line_ids[0]
self.assertTrue(self.inv_line.invoice_line_tax_ids) self.assertTrue(self.inv_line.invoice_line_tax_ids)
self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0) self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0)
@ -128,11 +124,11 @@ class TestContract(TestContractBase):
self.assertEqual(self.contract.pricelist_id, self.assertEqual(self.contract.pricelist_id,
self.contract.partner_id.property_product_pricelist) self.contract.partner_id.property_product_pricelist)
def test_onchange_recurring_invoices(self):
self.contract.recurring_next_date = False
self.contract._onchange_recurring_invoices()
self.assertEqual(self.contract.recurring_next_date,
self.contract.date_start)
def test_onchange_date_start(self):
date = '2016-01-01'
self.contract.date_start = date
self.contract._onchange_date_start()
self.assertEqual(self.contract.recurring_next_date, date)
def test_uom(self): def test_uom(self):
uom_litre = self.env.ref('product.product_uom_litre') uom_litre = self.env.ref('product.product_uom_litre')
@ -159,6 +155,31 @@ class TestContract(TestContractBase):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
contract_no_journal.recurring_create_invoice() contract_no_journal.recurring_create_invoice()
def test_check_date_end(self):
with self.assertRaises(ValidationError):
self.contract.date_end = '2015-12-31'
def test_check_recurring_next_date_start_date(self):
with self.assertRaises(ValidationError):
self.contract.write({
'date_start': '2017-01-01',
'recurring_next_date': '2016-01-01',
})
def test_check_recurring_next_date_recurring_invoices(self):
with self.assertRaises(ValidationError):
self.contract.write({
'recurring_invoices': True,
'recurring_next_date': False,
})
def test_check_date_start_recurring_invoices(self):
with self.assertRaises(ValidationError):
self.contract.write({
'recurring_invoices': True,
'date_start': False,
})
def test_onchange_contract_template_id(self): def test_onchange_contract_template_id(self):
"""It should change the contract values to match the template.""" """It should change the contract values to match the template."""
self.contract.contract_template_id = self.template self.contract.contract_template_id = self.template
@ -240,24 +261,14 @@ class TestContract(TestContractBase):
self.contract.copy() self.contract.copy()
self.assertEqual(self.partner.contract_count, count) self.assertEqual(self.partner.contract_count, count)
def test_date_end(self):
"""It should don't create invoices from finished contract."""
AccountInvoice = self.env['account.invoice']
self.contract.date_end = '2015-12-31'
with self.assertRaises(ValidationError):
self.contract.recurring_create_invoice()
init_count = AccountInvoice.search_count(
[('contract_id', '=', self.contract.id)])
self.contract.cron_recurring_create_invoice()
last_count = AccountInvoice.search_count(
[('contract_id', '=', self.contract.id)])
self.assertEqual(last_count, init_count)
def test_same_date_start_and_date_end(self): def test_same_date_start_and_date_end(self):
"""It should create one invoice with same start and end date.""" """It should create one invoice with same start and end date."""
AccountInvoice = self.env['account.invoice'] AccountInvoice = self.env['account.invoice']
self.contract.date_start = self.contract.date_end = fields.Date.today()
self.contract.recurring_next_date = self.contract.date_start
self.contract.write({
'date_start': fields.Date.today(),
'date_end': fields.Date.today(),
'recurring_next_date': fields.Date.today(),
})
init_count = AccountInvoice.search_count( init_count = AccountInvoice.search_count(
[('contract_id', '=', self.contract.id)]) [('contract_id', '=', self.contract.id)])
self.contract.cron_recurring_create_invoice() self.contract.cron_recurring_create_invoice()
@ -266,3 +277,15 @@ class TestContract(TestContractBase):
self.assertEqual(last_count, init_count + 1) self.assertEqual(last_count, init_count + 1)
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.contract.recurring_create_invoice() self.contract.recurring_create_invoice()
def test_compute_create_invoice_visibility(self):
self.contract.write({
'recurring_next_date': '2017-01-01',
'date_start': '2016-01-01',
'date_end': False,
})
self.assertTrue(self.contract.create_invoice_visibility)
self.contract.date_end = '2017-01-01'
self.assertTrue(self.contract.create_invoice_visibility)
self.contract.date_end = '2016-01-01'
self.assertFalse(self.contract.create_invoice_visibility)

22
contract/views/account_analytic_account_view.xml

@ -8,6 +8,9 @@
<field name="mode">primary</field> <field name="mode">primary</field>
<field name="priority" eval="9999"/> <field name="priority" eval="9999"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="attrs">{'required': [('recurring_invoices', '=', True)]}</attribute>
</field>
<xpath expr="//div[@name='button_box']/.." position="before"> <xpath expr="//div[@name='button_box']/.." position="before">
<header> <header>
<button name="action_contract_send" type="object" string="Send by Email" groups="base.group_user"/> <button name="action_contract_send" type="object" string="Send by Email" groups="base.group_user"/>
@ -19,10 +22,11 @@
/> />
<div> <div>
<field name="recurring_invoices" class="oe_inline"/> <field name="recurring_invoices" class="oe_inline"/>
<field name="create_invoice_visibility" invisible="1"/>
<label for="recurring_invoices" /> <label for="recurring_invoices" />
<button name="recurring_create_invoice" <button name="recurring_create_invoice"
type="object" type="object"
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
attrs="{'invisible': ['|', ('recurring_invoices', '!=', True), ('create_invoice_visibility', '=', False)]}"
string="Create invoices" string="Create invoices"
class="oe_link" class="oe_link"
groups="base.group_no_one" groups="base.group_no_one"
@ -36,7 +40,9 @@
</div> </div>
<group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}"> <group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
<field name="contract_template_id" colspan="4"/> <field name="contract_template_id" colspan="4"/>
<field name="journal_id"/>
<field name="journal_id"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
<field name="pricelist_id"/> <field name="pricelist_id"/>
<label for="recurring_interval"/> <label for="recurring_interval"/>
<div> <div>
@ -49,10 +55,16 @@
attrs="{'required': [('recurring_invoices', '=', True)]}" attrs="{'required': [('recurring_invoices', '=', True)]}"
/> />
</div> </div>
<field name="recurring_invoicing_type"/>
<field name="date_start"/>
<field name="recurring_invoicing_type"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
<field name="date_start"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
<field name="date_end"/> <field name="date_end"/>
<field name="recurring_next_date"/>
<field name="recurring_next_date"
attrs="{'required': [('recurring_invoices', '=', True)]}"
/>
</group> </group>
<label for="recurring_invoice_line_ids" <label for="recurring_invoice_line_ids"
attrs="{'invisible': [('recurring_invoices','=',False)]}" attrs="{'invisible': [('recurring_invoices','=',False)]}"

2
contract/views/account_analytic_contract_view.xml

@ -79,7 +79,7 @@
<filter string="Recurrence" <filter string="Recurrence"
context="{'group_by': 'recurring_rule_type'}" context="{'group_by': 'recurring_rule_type'}"
/> />
<filter string="Invoicing Type"
<filter string="Invoicing type"
context="{'group_by': 'recurring_invoicing_type'}" context="{'group_by': 'recurring_invoicing_type'}"
/> />
<filter string="Pricelist" <filter string="Pricelist"

2
contract/views/res_partner_view.xml

@ -10,7 +10,7 @@
<xpath expr="//div[@name='button_box']" position="inside"> <xpath expr="//div[@name='button_box']" position="inside">
<button name="act_show_contract" type="object" class="oe_stat_button" <button name="act_show_contract" type="object" class="oe_stat_button"
icon="fa-book" icon="fa-book"
help="show the contracts for this partner">
help="Show the contracts for this partner">
<field name="contract_count" widget="statinfo" string="Contracts"/> <field name="contract_count" widget="statinfo" string="Contracts"/>
</button> </button>
</xpath> </xpath>

Loading…
Cancel
Save