mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
Merge pull request #36 from Tecnativa/9.0-contract-IMP-advanced-past
[IMP] contract: Add pre-paid invoicing type. Fix yearly
This commit is contained in:
@@ -21,9 +21,20 @@ To use this module, you need to:
|
|||||||
|
|
||||||
#. Go to Sales -> Contracts and select or create a new contract.
|
#. Go to Sales -> Contracts and select or create a new contract.
|
||||||
#. Check *Generate recurring invoices automatically*.
|
#. Check *Generate recurring invoices automatically*.
|
||||||
#. Fill fields and add new lines. You have the possibility to use markers in
|
#. Fill fields for selecting the recurrency and invoice parameters:
|
||||||
the description field to show the start and end date of the invoiced period.
|
* Journal
|
||||||
#. A cron is created with daily interval, but if you are in debug mode can
|
* Pricelist
|
||||||
|
* Period. It can be any interval of days, weeks, months, months last day or
|
||||||
|
years.
|
||||||
|
* Start date and next invoice date.
|
||||||
|
* Invoicing type: pre-paid or post-paid.
|
||||||
|
#. Add the lines to be invoiced with the product, description, quantity and
|
||||||
|
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
|
||||||
|
with the markers.
|
||||||
|
#. A cron is created with daily interval, but if you are in debug mode, you can
|
||||||
click on *Create invoices* to force this action.
|
click on *Create invoices* to force this action.
|
||||||
#. Click *Show recurring invoices* link to show all invoices created by the
|
#. Click *Show recurring invoices* link to show all invoices created by the
|
||||||
contract.
|
contract.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Contracts Management recurring',
|
'name': 'Contracts Management recurring',
|
||||||
'version': '9.0.1.0.0',
|
'version': '9.0.1.1.0',
|
||||||
'category': 'Contract Management',
|
'category': 'Contract Management',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'author': "OpenERP SA,"
|
'author': "OpenERP SA,"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<field name="interval_type">days</field>
|
<field name="interval_type">days</field>
|
||||||
<field name="numbercall">-1</field>
|
<field name="numbercall">-1</field>
|
||||||
<field name="model" eval="'account.analytic.account'"/>
|
<field name="model" eval="'account.analytic.account'"/>
|
||||||
<field name="function" eval="'recurring_create_invoice'"/>
|
<field name="function" eval="'cron_recurring_create_invoice'"/>
|
||||||
<field name="args" eval="'()'"/>
|
<field name="args" eval="'()'"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,17 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: contract (9.0)\n"
|
"Project-Id-Version: contract (9.0)\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2016-09-11 02:47+0000\n"
|
"POT-Creation-Date: 2016-09-25 22:56+0000\n"
|
||||||
"PO-Revision-Date: 2016-09-16 21:45+0000\n"
|
"PO-Revision-Date: 2016-09-26 00:56+0100\n"
|
||||||
"Last-Translator: OCA Transbot <transbot@odoo-community.org>\n"
|
"Last-Translator: Carlos Incaser <carlos@incaser.es>\n"
|
||||||
"Language-Team: Spanish (http://www.transifex.com/oca/OCA-contract-9-0/language/es/)\n"
|
"Language-Team: Spanish (http://www.transifex.com/oca/OCA-contract-9-0/"
|
||||||
|
"language/es/)\n"
|
||||||
|
"Language: es\n"
|
||||||
"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: 8bit\n"
|
||||||
"Language: es\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
"X-Generator: Poedit 1.5.4\n"
|
||||||
|
|
||||||
#. 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
|
||||||
@@ -51,7 +53,6 @@ msgstr "Contrato"
|
|||||||
#. module: contract
|
#. module: contract
|
||||||
#: model:ir.actions.act_window,name:contract.action_account_analytic_overdue_all
|
#: model:ir.actions.act_window,name:contract.action_account_analytic_overdue_all
|
||||||
#: model:ir.ui.menu,name:contract.menu_action_account_analytic_overdue_all
|
#: model:ir.ui.menu,name:contract.menu_action_account_analytic_overdue_all
|
||||||
#: model:ir.ui.menu,name:contract.menu_config_contract
|
|
||||||
msgid "Contracts"
|
msgid "Contracts"
|
||||||
msgstr "Contratos"
|
msgstr "Contratos"
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ msgid "Discount (%)"
|
|||||||
msgstr "Descuento (%)"
|
msgstr "Descuento (%)"
|
||||||
|
|
||||||
#. module: contract
|
#. module: contract
|
||||||
#: code:addons/contract/models/contract.py:59
|
#: code:addons/contract/models/contract.py:60
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Discount should be less or equal to 100"
|
msgid "Discount should be less or equal to 100"
|
||||||
msgstr "El descuento debería ser menor o igual a 100"
|
msgstr "El descuento debería ser menor o igual a 100"
|
||||||
@@ -106,7 +107,9 @@ msgstr "El descuento debería ser menor o igual a 100"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Discount that is applied in generated invoices. It should be less or equal "
|
"Discount that is applied in generated invoices. It should be less or equal "
|
||||||
"to 100"
|
"to 100"
|
||||||
msgstr "Descuento que es aplicado en las facturas generadas. Debería ser menor o igual a 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_invoice_line_display_name
|
#: model:ir.model.fields,field_description:contract.field_account_analytic_invoice_line_display_name
|
||||||
@@ -166,24 +169,40 @@ msgstr "Última actualización en"
|
|||||||
#. 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 "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
|
||||||
msgid "Month(s)"
|
msgid "Month(s)"
|
||||||
msgstr "Mes(es)"
|
msgstr "Mes(es)"
|
||||||
|
|
||||||
|
#. module: contract
|
||||||
|
#: selection:account.analytic.account,recurring_rule_type:0
|
||||||
|
msgid "Month(s) last day"
|
||||||
|
msgstr "Mes(es) último día"
|
||||||
|
|
||||||
#. 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 "Next Invoice"
|
msgid "Next Invoice"
|
||||||
msgstr "Próxima factura"
|
msgstr "Próxima factura"
|
||||||
|
|
||||||
#. module: contract
|
#. module: contract
|
||||||
#: code:addons/contract/models/contract.py:196
|
#: code:addons/contract/models/contract.py:230
|
||||||
#, 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 define un diario de ventas para la compañía '%s'."
|
||||||
|
|
||||||
|
#. module: contract
|
||||||
|
#: selection:account.analytic.account,recurring_invoicing_type:0
|
||||||
|
msgid "Post-paid"
|
||||||
|
msgstr "Pospago"
|
||||||
|
|
||||||
|
#. module: contract
|
||||||
|
#: selection:account.analytic.account,recurring_invoicing_type:0
|
||||||
|
msgid "Pre-paid"
|
||||||
|
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
|
||||||
msgid "Pricelist"
|
msgid "Pricelist"
|
||||||
@@ -199,6 +218,11 @@ msgstr "Producto"
|
|||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr "Cantidad"
|
msgstr "Cantidad"
|
||||||
|
|
||||||
|
#. module: contract
|
||||||
|
#: model:ir.model.fields,field_description:contract.field_account_analytic_account_recurring_invoicing_type
|
||||||
|
msgid "Invoicing type"
|
||||||
|
msgstr "Tipo de facturación"
|
||||||
|
|
||||||
#. 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
|
||||||
msgid "Recurrency"
|
msgid "Recurrency"
|
||||||
@@ -225,6 +249,12 @@ msgstr "Repetir cada (días/semana/mes/año)"
|
|||||||
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
|
||||||
|
#: model:ir.model.fields,help:contract.field_account_analytic_account_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"
|
||||||
|
|
||||||
#. module: contract
|
#. module: contract
|
||||||
#: model:ir.model.fields,field_description:contract.field_account_analytic_invoice_line_price_subtotal
|
#: model:ir.model.fields,field_description:contract.field_account_analytic_invoice_line_price_subtotal
|
||||||
msgid "Sub Total"
|
msgid "Sub Total"
|
||||||
@@ -251,7 +281,7 @@ msgid "Year(s)"
|
|||||||
msgstr "Año(s)"
|
msgstr "Año(s)"
|
||||||
|
|
||||||
#. module: contract
|
#. module: contract
|
||||||
#: code:addons/contract/models/contract.py:188
|
#: code:addons/contract/models/contract.py:222
|
||||||
#, 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!"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
|
|
||||||
from openerp import api, fields, models
|
from openerp import api, fields, models
|
||||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||||
@@ -52,11 +51,13 @@ class AccountAnalyticInvoiceLine(models.Model):
|
|||||||
else:
|
else:
|
||||||
line.price_subtotal = subtotal
|
line.price_subtotal = subtotal
|
||||||
|
|
||||||
@api.one
|
@api.multi
|
||||||
@api.constrains('discount')
|
@api.constrains('discount')
|
||||||
def _check_discount(self):
|
def _check_discount(self):
|
||||||
if self.discount > 100:
|
for line in self:
|
||||||
raise ValidationError(_("Discount should be less or equal to 100"))
|
if line.discount > 100:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Discount should be less or equal to 100"))
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
@api.onchange('product_id')
|
@api.onchange('product_id')
|
||||||
@@ -109,6 +110,7 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
recurring_invoice_line_ids = fields.One2many(
|
recurring_invoice_line_ids = fields.One2many(
|
||||||
comodel_name='account.analytic.invoice.line',
|
comodel_name='account.analytic.invoice.line',
|
||||||
inverse_name='analytic_account_id',
|
inverse_name='analytic_account_id',
|
||||||
|
copy=True,
|
||||||
string='Invoice Lines')
|
string='Invoice Lines')
|
||||||
recurring_invoices = fields.Boolean(
|
recurring_invoices = fields.Boolean(
|
||||||
string='Generate recurring invoices automatically')
|
string='Generate recurring invoices automatically')
|
||||||
@@ -116,11 +118,19 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
[('daily', 'Day(s)'),
|
[('daily', 'Day(s)'),
|
||||||
('weekly', 'Week(s)'),
|
('weekly', 'Week(s)'),
|
||||||
('monthly', 'Month(s)'),
|
('monthly', 'Month(s)'),
|
||||||
|
('monthlylastday', 'Month(s) last day'),
|
||||||
('yearly', 'Year(s)'),
|
('yearly', 'Year(s)'),
|
||||||
],
|
],
|
||||||
default='monthly',
|
default='monthly',
|
||||||
string='Recurrency',
|
string='Recurrency',
|
||||||
help="Specify Interval for automatic invoice generation.")
|
help="Specify Interval for automatic invoice generation.")
|
||||||
|
recurring_invoicing_type = fields.Selection(
|
||||||
|
[('pre-paid', 'Pre-paid'),
|
||||||
|
('post-paid', 'Post-paid'),
|
||||||
|
],
|
||||||
|
default='pre-paid',
|
||||||
|
string='Invoicing type',
|
||||||
|
help="Specify if process date is 'from' or 'to' invoicing date")
|
||||||
recurring_interval = fields.Integer(
|
recurring_interval = fields.Integer(
|
||||||
default=1,
|
default=1,
|
||||||
string='Repeat Every',
|
string='Repeat Every',
|
||||||
@@ -144,12 +154,35 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
if self.date_start and self.recurring_invoices:
|
if self.date_start and self.recurring_invoices:
|
||||||
self.recurring_next_date = self.date_start
|
self.recurring_next_date = self.date_start
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def get_relalive_delta(self, recurring_rule_type, interval):
|
||||||
|
if recurring_rule_type == 'daily':
|
||||||
|
return relativedelta(days=interval)
|
||||||
|
elif recurring_rule_type == 'weekly':
|
||||||
|
return relativedelta(weeks=interval)
|
||||||
|
elif recurring_rule_type == 'monthly':
|
||||||
|
return relativedelta(months=interval)
|
||||||
|
elif recurring_rule_type == 'monthlylastday':
|
||||||
|
return relativedelta(months=interval, day=31)
|
||||||
|
else:
|
||||||
|
return relativedelta(years=interval)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _insert_markers(self, line, date_start, next_date, date_format):
|
def _insert_markers(self, line, date_start, next_date, date_format):
|
||||||
line = line.replace('#START#', date_start.strftime(date_format))
|
contract = line.analytic_account_id
|
||||||
date_end = next_date - relativedelta(days=1)
|
if contract.recurring_invoicing_type == 'pre-paid':
|
||||||
line = line.replace('#END#', date_end.strftime(date_format))
|
date_from = date_start
|
||||||
return line
|
date_to = next_date - relativedelta(days=1)
|
||||||
|
else:
|
||||||
|
date_from = (date_start -
|
||||||
|
self.get_relalive_delta(contract.recurring_rule_type,
|
||||||
|
contract.recurring_interval) +
|
||||||
|
relativedelta(days=1))
|
||||||
|
date_to = date_start
|
||||||
|
name = line.name
|
||||||
|
name = name.replace('#START#', date_from.strftime(date_format))
|
||||||
|
name = name.replace('#END#', date_to.strftime(date_format))
|
||||||
|
return name
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _prepare_invoice_line(self, line, invoice_id):
|
def _prepare_invoice_line(self, line, invoice_id):
|
||||||
@@ -172,7 +205,7 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
[('code', '=', contract.partner_id.lang)])
|
[('code', '=', contract.partner_id.lang)])
|
||||||
date_format = lang.date_format or '%m/%d/%Y'
|
date_format = lang.date_format or '%m/%d/%Y'
|
||||||
name = self._insert_markers(
|
name = self._insert_markers(
|
||||||
name, self.env.context['old_date'],
|
line, self.env.context['old_date'],
|
||||||
self.env.context['next_date'], date_format)
|
self.env.context['next_date'], date_format)
|
||||||
invoice_line_vals.update({
|
invoice_line_vals.update({
|
||||||
'name': name,
|
'name': name,
|
||||||
@@ -181,68 +214,61 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
})
|
})
|
||||||
return invoice_line_vals
|
return invoice_line_vals
|
||||||
|
|
||||||
@api.model
|
@api.multi
|
||||||
def _prepare_invoice(self, contract):
|
def _prepare_invoice(self):
|
||||||
if not contract.partner_id:
|
self.ensure_one()
|
||||||
|
if not self.partner_id:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
_("You must first select a Customer for Contract %s!") %
|
_("You must first select a Customer for Contract %s!") %
|
||||||
contract.name)
|
self.name)
|
||||||
journal = contract.journal_id or self.env['account.journal'].search(
|
journal = self.journal_id or self.env['account.journal'].search(
|
||||||
[('type', '=', 'sale'),
|
[('type', '=', 'sale'),
|
||||||
('company_id', '=', contract.company_id.id)],
|
('company_id', '=', self.company_id.id)],
|
||||||
limit=1)
|
limit=1)
|
||||||
if not journal:
|
if not journal:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
_("Please define a sale journal for the company '%s'.") %
|
_("Please define a sale journal for the company '%s'.") %
|
||||||
(contract.company_id.name or '',))
|
(self.company_id.name or '',))
|
||||||
currency = (
|
currency = (
|
||||||
contract.pricelist_id.currency_id or
|
self.pricelist_id.currency_id or
|
||||||
contract.partner_id.property_product_pricelist.currency_id or
|
self.partner_id.property_product_pricelist.currency_id or
|
||||||
contract.company_id.currency_id
|
self.company_id.currency_id
|
||||||
)
|
)
|
||||||
invoice = self.env['account.invoice'].new({
|
invoice = self.env['account.invoice'].new({
|
||||||
'reference': contract.code,
|
'reference': self.code,
|
||||||
'type': 'out_invoice',
|
'type': 'out_invoice',
|
||||||
'partner_id': contract.partner_id.address_get(
|
'partner_id': self.partner_id.address_get(
|
||||||
['invoice'])['invoice'],
|
['invoice'])['invoice'],
|
||||||
'currency_id': currency.id,
|
'currency_id': currency.id,
|
||||||
'journal_id': journal.id,
|
'journal_id': journal.id,
|
||||||
'date_invoice': contract.recurring_next_date,
|
'date_invoice': self.recurring_next_date,
|
||||||
'origin': contract.name,
|
'origin': self.name,
|
||||||
'company_id': contract.company_id.id,
|
'company_id': self.company_id.id,
|
||||||
'contract_id': contract.id,
|
'contract_id': self.id,
|
||||||
|
'user_id': self.partner_id.user_id.id,
|
||||||
})
|
})
|
||||||
# Get other invoice values from partner onchange
|
# Get other invoice values from partner onchange
|
||||||
invoice._onchange_partner_id()
|
invoice._onchange_partner_id()
|
||||||
return invoice._convert_to_write(invoice._cache)
|
return invoice._convert_to_write(invoice._cache)
|
||||||
|
|
||||||
@api.model
|
@api.multi
|
||||||
def _create_invoice(self, contract):
|
def _create_invoice(self):
|
||||||
invoice_vals = self._prepare_invoice(contract)
|
self.ensure_one()
|
||||||
|
invoice_vals = self._prepare_invoice()
|
||||||
invoice = self.env['account.invoice'].create(invoice_vals)
|
invoice = self.env['account.invoice'].create(invoice_vals)
|
||||||
for line in contract.recurring_invoice_line_ids:
|
for line in self.recurring_invoice_line_ids:
|
||||||
invoice_line_vals = self._prepare_invoice_line(line, invoice.id)
|
invoice_line_vals = self._prepare_invoice_line(line, invoice.id)
|
||||||
self.env['account.invoice.line'].create(invoice_line_vals)
|
self.env['account.invoice.line'].create(invoice_line_vals)
|
||||||
invoice.compute_taxes()
|
invoice.compute_taxes()
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
@api.model
|
@api.multi
|
||||||
def recurring_create_invoice(self, automatic=False):
|
def recurring_create_invoice(self):
|
||||||
current_date = time.strftime('%Y-%m-%d')
|
for contract in self:
|
||||||
contracts = self.search(
|
|
||||||
[('recurring_next_date', '<=', current_date),
|
|
||||||
('account_type', '=', 'normal'),
|
|
||||||
('recurring_invoices', '=', True)])
|
|
||||||
for contract in contracts:
|
|
||||||
old_date = fields.Date.from_string(
|
old_date = fields.Date.from_string(
|
||||||
contract.recurring_next_date or fields.Date.today())
|
contract.recurring_next_date or fields.Date.today())
|
||||||
interval = contract.recurring_interval
|
new_date = old_date + self.get_relalive_delta(
|
||||||
if contract.recurring_rule_type == 'daily':
|
contract.recurring_rule_type, contract.recurring_interval)
|
||||||
new_date = old_date + relativedelta(days=interval)
|
|
||||||
elif contract.recurring_rule_type == 'weekly':
|
|
||||||
new_date = old_date + relativedelta(weeks=interval)
|
|
||||||
else:
|
|
||||||
new_date = old_date + relativedelta(months=interval)
|
|
||||||
ctx = self.env.context.copy()
|
ctx = self.env.context.copy()
|
||||||
ctx.update({
|
ctx.update({
|
||||||
'old_date': old_date,
|
'old_date': old_date,
|
||||||
@@ -251,9 +277,16 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
'force_company': contract.company_id.id,
|
'force_company': contract.company_id.id,
|
||||||
})
|
})
|
||||||
# Re-read contract with correct company
|
# Re-read contract with correct company
|
||||||
contract = contract.with_context(ctx)
|
contract.with_context(ctx)._create_invoice()
|
||||||
self.with_context(ctx)._create_invoice(contract)
|
|
||||||
contract.write({
|
contract.write({
|
||||||
'recurring_next_date': new_date.strftime('%Y-%m-%d')
|
'recurring_next_date': new_date.strftime('%Y-%m-%d')
|
||||||
})
|
})
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def cron_recurring_create_invoice(self):
|
||||||
|
contracts = self.search(
|
||||||
|
[('recurring_next_date', '<=', fields.date.today()),
|
||||||
|
('account_type', '=', 'normal'),
|
||||||
|
('recurring_invoices', '=', True)])
|
||||||
|
return contracts.recurring_create_invoice()
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
# © 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from openerp.exceptions import ValidationError
|
from openerp.exceptions import ValidationError
|
||||||
from openerp.tests.common import TransactionCase
|
from openerp.tests.common import TransactionCase
|
||||||
|
|
||||||
@@ -15,14 +12,14 @@ class TestContract(TransactionCase):
|
|||||||
super(TestContract, self).setUp()
|
super(TestContract, self).setUp()
|
||||||
self.partner = self.env.ref('base.res_partner_2')
|
self.partner = self.env.ref('base.res_partner_2')
|
||||||
self.product = self.env.ref('product.product_product_2')
|
self.product = self.env.ref('product.product_product_2')
|
||||||
self.tax = self.env.ref('l10n_generic_coa.sale_tax_template')
|
|
||||||
self.product.taxes_id = self.tax.ids
|
|
||||||
self.product.description_sale = 'Test description sale'
|
self.product.description_sale = 'Test description sale'
|
||||||
self.contract = self.env['account.analytic.account'].create({
|
self.contract = self.env['account.analytic.account'].create({
|
||||||
'name': 'Test Contract',
|
'name': 'Test Contract',
|
||||||
'partner_id': self.partner.id,
|
'partner_id': self.partner.id,
|
||||||
'pricelist_id': self.partner.property_product_pricelist.id,
|
'pricelist_id': self.partner.property_product_pricelist.id,
|
||||||
'recurring_invoices': True,
|
'recurring_invoices': True,
|
||||||
|
'date_start': '2016-02-15',
|
||||||
|
'recurring_next_date': '2016-02-29',
|
||||||
})
|
})
|
||||||
self.contract_line = self.env['account.analytic.invoice.line'].create({
|
self.contract_line = self.env['account.analytic.invoice.line'].create({
|
||||||
'analytic_account_id': self.contract.id,
|
'analytic_account_id': self.contract.id,
|
||||||
@@ -33,11 +30,6 @@ class TestContract(TransactionCase):
|
|||||||
'price_unit': 100,
|
'price_unit': 100,
|
||||||
'discount': 50,
|
'discount': 50,
|
||||||
})
|
})
|
||||||
self.current_date = datetime.date.today()
|
|
||||||
self.contract_daily = self.contract.copy()
|
|
||||||
self.contract_daily.recurring_rule_type = 'daily'
|
|
||||||
self.contract_weekly = self.contract.copy()
|
|
||||||
self.contract_weekly.recurring_rule_type = 'weekly'
|
|
||||||
|
|
||||||
def test_check_discount(self):
|
def test_check_discount(self):
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
@@ -58,35 +50,53 @@ class TestContract(TransactionCase):
|
|||||||
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)
|
||||||
new_date = self.current_date + relativedelta(
|
self.assertEqual(self.contract.recurring_next_date, '2016-03-29')
|
||||||
months=self.contract.recurring_interval)
|
|
||||||
self.assertEqual(self.contract.recurring_next_date,
|
|
||||||
new_date.strftime('%Y-%m-%d'))
|
|
||||||
|
|
||||||
self.inv_line = self.invoice_monthly.invoice_line_ids[0]
|
self.inv_line = self.invoice_monthly.invoice_line_ids[0]
|
||||||
self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0)
|
self.assertAlmostEqual(self.inv_line.price_subtotal, 50.0)
|
||||||
self.assertTrue(self.inv_line.invoice_line_tax_ids)
|
self.assertEqual(self.contract.partner_id.user_id,
|
||||||
|
self.invoice_monthly.user_id)
|
||||||
|
|
||||||
def test_contract_daily(self):
|
def test_contract_daily(self):
|
||||||
self.contract_daily.pricelist_id = False
|
self.contract.recurring_next_date = '2016-02-29'
|
||||||
self.contract_daily.recurring_create_invoice()
|
self.contract.recurring_rule_type = 'daily'
|
||||||
|
self.contract.pricelist_id = False
|
||||||
|
self.contract.cron_recurring_create_invoice()
|
||||||
invoice_daily = self.env['account.invoice'].search(
|
invoice_daily = self.env['account.invoice'].search(
|
||||||
[('contract_id', '=', self.contract_daily.id)])
|
[('contract_id', '=', self.contract.id)])
|
||||||
self.assertTrue(invoice_daily)
|
self.assertTrue(invoice_daily)
|
||||||
new_date = self.current_date + relativedelta(
|
self.assertEqual(self.contract.recurring_next_date, '2016-03-01')
|
||||||
days=self.contract_daily.recurring_interval)
|
|
||||||
self.assertEqual(self.contract_daily.recurring_next_date,
|
|
||||||
new_date.strftime('%Y-%m-%d'))
|
|
||||||
|
|
||||||
def test_contract_weekly(self):
|
def test_contract_weekly(self):
|
||||||
self.contract_weekly.recurring_create_invoice()
|
self.contract.recurring_next_date = '2016-02-29'
|
||||||
|
self.contract.recurring_rule_type = 'weekly'
|
||||||
|
self.contract.recurring_invoicing_type = 'post-paid'
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
invoices_weekly = self.env['account.invoice'].search(
|
invoices_weekly = self.env['account.invoice'].search(
|
||||||
[('contract_id', '=', self.contract_weekly.id)])
|
[('contract_id', '=', self.contract.id)])
|
||||||
self.assertTrue(invoices_weekly)
|
self.assertTrue(invoices_weekly)
|
||||||
new_date = self.current_date + relativedelta(
|
self.assertEqual(
|
||||||
weeks=self.contract_weekly.recurring_interval)
|
self.contract.recurring_next_date, '2016-03-07')
|
||||||
self.assertEqual(self.contract_weekly.recurring_next_date,
|
|
||||||
new_date.strftime('%Y-%m-%d'))
|
def test_contract_yearly(self):
|
||||||
|
self.contract.recurring_next_date = '2016-02-29'
|
||||||
|
self.contract.recurring_rule_type = 'yearly'
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
invoices_weekly = self.env['account.invoice'].search(
|
||||||
|
[('contract_id', '=', self.contract.id)])
|
||||||
|
self.assertTrue(invoices_weekly)
|
||||||
|
self.assertEqual(
|
||||||
|
self.contract.recurring_next_date, '2017-02-28')
|
||||||
|
|
||||||
|
def test_contract_monthly_lastday(self):
|
||||||
|
self.contract.recurring_next_date = '2016-02-29'
|
||||||
|
self.contract.recurring_invoicing_type = 'post-paid'
|
||||||
|
self.contract.recurring_rule_type = 'monthlylastday'
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
invoices_monthly_lastday = self.env['account.invoice'].search(
|
||||||
|
[('contract_id', '=', self.contract.id)])
|
||||||
|
self.assertTrue(invoices_monthly_lastday)
|
||||||
|
self.assertEqual(self.contract.recurring_next_date, '2016-03-31')
|
||||||
|
|
||||||
def test_onchange_partner_id(self):
|
def test_onchange_partner_id(self):
|
||||||
self.contract._onchange_partner_id()
|
self.contract._onchange_partner_id()
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
attrs="{'invisible': [('recurring_invoices','!=',True)]}"
|
||||||
string="⇒ Show recurring invoices" class="oe_link"/>
|
string="⇒ Show recurring invoices" class="oe_link"/>
|
||||||
</div>
|
</div>
|
||||||
<group attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
<group col="4" attrs="{'invisible': [('recurring_invoices','!=',True)]}">
|
||||||
<field name="journal_id"/>
|
<field name="journal_id"/>
|
||||||
<field name="pricelist_id"/>
|
<field name="pricelist_id"/>
|
||||||
<label for="recurring_interval"/>
|
<label for="recurring_interval"/>
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
<field name="recurring_interval" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
<field name="recurring_interval" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
||||||
<field name="recurring_rule_type" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
<field name="recurring_rule_type" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/>
|
||||||
</div>
|
</div>
|
||||||
|
<field name="recurring_invoicing_type"/>
|
||||||
<field name="date_start"/>
|
<field name="date_start"/>
|
||||||
<field name="recurring_next_date"/>
|
<field name="recurring_next_date"/>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class TestContractVariableQuantity(common.SavepointCase):
|
|||||||
self.formula.code = "user.id"
|
self.formula.code = "user.id"
|
||||||
|
|
||||||
def test_check_variable_quantity(self):
|
def test_check_variable_quantity(self):
|
||||||
self.contract._create_invoice(self.contract)
|
self.contract._create_invoice()
|
||||||
invoice = self.env['account.invoice'].search(
|
invoice = self.env['account.invoice'].search(
|
||||||
[('contract_id', '=', self.contract.id)])
|
[('contract_id', '=', self.contract.id)])
|
||||||
self.assertEqual(invoice.invoice_line_ids[0].quantity, 12)
|
self.assertEqual(invoice.invoice_line_ids[0].quantity, 12)
|
||||||
|
|||||||
Reference in New Issue
Block a user