diff --git a/contract/tests/test_contract.py b/contract/tests/test_contract.py
index 4ce51aaa6..d427692fd 100644
--- a/contract/tests/test_contract.py
+++ b/contract/tests/test_contract.py
@@ -1,12 +1,18 @@
-# Copyright 2016 Tecnativa - Carlos Dauden
-# Copyright 2017 Tecnativa - Pedro M. Baeza
+# Copyright 2018 Tecnativa - Carlos Dauden
+# Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from datetime import timedelta
+from dateutil.relativedelta import relativedelta
from odoo import fields
from odoo.exceptions import ValidationError
from odoo.tests import common
+def to_date(date):
+ return fields.Date.to_date(date)
+
+
class TestContractBase(common.SavepointCase):
@classmethod
def setUpClass(cls):
@@ -14,52 +20,89 @@ class TestContractBase(common.SavepointCase):
cls.partner = cls.env.ref('base.res_partner_2')
cls.product = cls.env.ref('product.product_product_2')
cls.product.taxes_id += cls.env['account.tax'].search(
- [('type_tax_use', '=', 'sale')], limit=1)
- cls.product.description_sale = 'Test description sale'
- cls.template_vals = {
- 'recurring_rule_type': 'yearly',
- 'recurring_interval': 12345,
- 'name': 'Test Contract Template',
- }
- cls.template = cls.env['account.analytic.contract'].create(
- cls.template_vals,
+ [('type_tax_use', '=', 'sale')], limit=1
)
- # For being sure of the applied price
- cls.env['product.pricelist.item'].create({
- 'pricelist_id': cls.partner.property_product_pricelist.id,
- 'product_id': cls.product.id,
- 'compute_price': 'formula',
- 'base': 'list_price',
- })
- cls.contract = cls.env['account.analytic.account'].create({
- 'name': 'Test Contract',
- 'partner_id': cls.partner.id,
- 'pricelist_id': cls.partner.property_product_pricelist.id,
- 'recurring_invoices': True,
- 'date_start': '2016-02-15',
- 'recurring_next_date': '2016-02-29',
- })
- cls.contract2 = cls.env['account.analytic.account'].create({
- 'name': 'Test Contract 2',
- 'partner_id': cls.partner.id,
- 'pricelist_id': cls.partner.property_product_pricelist.id,
- 'recurring_invoices': True,
- 'date_start': '2016-02-15',
- 'recurring_next_date': '2016-02-29',
- 'contract_type': 'purchase',
- })
- cls.line_vals = {
- 'analytic_account_id': cls.contract.id,
+ cls.product.description_sale = 'Test description sale'
+ cls.line_template_vals = {
'product_id': cls.product.id,
'name': 'Services from #START# to #END#',
'quantity': 1,
'uom_id': cls.product.uom_id.id,
'price_unit': 100,
'discount': 50,
+ 'recurring_rule_type': 'yearly',
+ 'recurring_interval': 1,
+ }
+ cls.template_vals = {
+ 'name': 'Test Contract Template',
+ 'recurring_invoice_line_ids': [(0, 0, cls.line_template_vals)],
+ }
+ cls.template = cls.env['account.analytic.contract'].create(
+ cls.template_vals
+ )
+ # For being sure of the applied price
+ cls.env['product.pricelist.item'].create(
+ {
+ 'pricelist_id': cls.partner.property_product_pricelist.id,
+ 'product_id': cls.product.id,
+ 'compute_price': 'formula',
+ 'base': 'list_price',
+ }
+ )
+ cls.contract = cls.env['account.analytic.account'].create(
+ {
+ 'name': 'Test Contract',
+ 'partner_id': cls.partner.id,
+ 'pricelist_id': cls.partner.property_product_pricelist.id,
+ 'recurring_invoices': True,
+ }
+ )
+ cls.contract2 = cls.env['account.analytic.account'].create(
+ {
+ 'name': 'Test Contract 2',
+ 'partner_id': cls.partner.id,
+ 'pricelist_id': cls.partner.property_product_pricelist.id,
+ 'recurring_invoices': True,
+ 'contract_type': 'purchase',
+ 'recurring_invoice_line_ids': [
+ (
+ 0,
+ 0,
+ {
+ 'product_id': cls.product.id,
+ 'name': 'Services from #START# to #END#',
+ 'quantity': 1,
+ 'uom_id': cls.product.uom_id.id,
+ 'price_unit': 100,
+ 'discount': 50,
+ 'recurring_rule_type': 'monthly',
+ 'recurring_interval': 1,
+ 'date_start': '2018-02-15',
+ 'recurring_next_date': '2018-02-22',
+ },
+ )
+ ],
+ }
+ )
+ cls.line_vals = {
+ 'contract_id': cls.contract.id,
+ 'product_id': cls.product.id,
+ 'name': 'Services from #START# to #END#',
+ 'quantity': 1,
+ 'uom_id': cls.product.uom_id.id,
+ 'price_unit': 100,
+ 'discount': 50,
+ 'recurring_rule_type': 'monthly',
+ 'recurring_interval': 1,
+ 'date_start': '2018-01-01',
+ 'date_end': '2019-01-01',
+ 'recurring_next_date': '2018-01-15',
+ 'is_auto_renew': True,
}
cls.acct_line = cls.env['account.analytic.invoice.line'].create(
- cls.line_vals,
+ cls.line_vals
)
+ cls.acct_line.product_id.is_auto_renew = True
class TestContract(TestContractBase):
@@ -67,7 +110,10 @@ class TestContract(TestContractBase):
if overrides is None:
overrides = {}
vals = self.line_vals.copy()
- vals['analytic_account_id'] = self.template.id
+ del vals['contract_id']
+ del vals['date_start']
+ del vals['date_end']
+ vals['contract_id'] = self.template.id
vals.update(overrides)
return self.env['account.analytic.contract.line'].create(vals)
@@ -90,7 +136,7 @@ class TestContract(TestContractBase):
self.assertEqual(self.acct_line.price_unit, 10)
def test_contract(self):
- recurring_next_date = fields.Date.to_date('2016-03-29')
+ recurring_next_date = to_date('2018-02-15')
self.assertAlmostEqual(self.acct_line.price_subtotal, 50.0)
res = self.acct_line._onchange_product_id()
self.assertIn('uom_id', res['domain'])
@@ -100,81 +146,242 @@ class TestContract(TestContractBase):
self.contract.partner_id = self.partner.id
self.contract.recurring_create_invoice()
self.invoice_monthly = self.env['account.invoice'].search(
- [('contract_id', '=', self.contract.id)])
+ [('contract_id', '=', self.contract.id)]
+ )
self.assertTrue(self.invoice_monthly)
- self.assertEqual(self.contract.recurring_next_date,
- recurring_next_date)
+ 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.assertAlmostEqual(self.inv_line.price_subtotal, 50.0)
- self.assertEqual(self.contract.partner_id.user_id,
- self.invoice_monthly.user_id)
+ self.assertEqual(
+ self.contract.partner_id.user_id, self.invoice_monthly.user_id
+ )
+
+ def test_contract_recurring_next_date(self):
+ recurring_next_date = to_date('2018-01-15')
+ self.assertEqual(
+ self.contract.recurring_next_date, recurring_next_date
+ )
+ contract_line = self.acct_line.copy(
+ {'recurring_next_date': '2018-01-14'}
+ )
+ recurring_next_date = to_date('2018-01-14')
+ self.assertEqual(
+ self.contract.recurring_next_date, recurring_next_date
+ )
+ contract_line.cancel()
+ recurring_next_date = to_date('2018-01-15')
+ self.assertEqual(
+ self.contract.recurring_next_date, recurring_next_date
+ )
def test_contract_daily(self):
- recurring_next_date = fields.Date.to_date('2016-03-01')
- self.contract.recurring_next_date = '2016-02-29'
- self.contract.recurring_rule_type = 'daily'
+ recurring_next_date = to_date('2018-02-23')
+ last_date_invoiced = to_date('2018-02-22')
+ self.acct_line.recurring_next_date = '2018-02-22'
+ self.acct_line.recurring_rule_type = 'daily'
self.contract.pricelist_id = False
- self.contract.cron_recurring_create_invoice()
+ self.contract.recurring_create_invoice()
invoice_daily = self.env['account.invoice'].search(
- [('contract_id', '=', self.contract.id)])
+ [('contract_id', '=', self.contract.id)]
+ )
self.assertTrue(invoice_daily)
- self.assertEqual(self.contract.recurring_next_date,
- recurring_next_date)
+ self.assertEqual(
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
+ self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
- def test_contract_weekly(self):
- recurring_next_date = fields.Date.to_date('2016-03-07')
- self.contract.recurring_next_date = '2016-02-29'
- self.contract.recurring_rule_type = 'weekly'
- self.contract.recurring_invoicing_type = 'post-paid'
+ def test_contract_weekly_post_paid(self):
+ recurring_next_date = to_date('2018-03-01')
+ last_date_invoiced = to_date('2018-02-21')
+ self.acct_line.recurring_next_date = '2018-02-22'
+ self.acct_line.recurring_rule_type = 'weekly'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
self.contract.recurring_create_invoice()
invoices_weekly = self.env['account.invoice'].search(
- [('contract_id', '=', self.contract.id)])
+ [('contract_id', '=', self.contract.id)]
+ )
self.assertTrue(invoices_weekly)
self.assertEqual(
- self.contract.recurring_next_date, recurring_next_date)
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
+ self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
- def test_contract_yearly(self):
- recurring_next_date = fields.Date.to_date('2017-02-28')
- self.contract.recurring_next_date = '2016-02-29'
- self.contract.recurring_rule_type = 'yearly'
+ def test_contract_weekly_pre_paid(self):
+ recurring_next_date = to_date('2018-03-01')
+ last_date_invoiced = to_date('2018-02-28')
+ self.acct_line.recurring_next_date = '2018-02-22'
+ self.acct_line.recurring_rule_type = 'weekly'
+ self.acct_line.recurring_invoicing_type = 'pre-paid'
self.contract.recurring_create_invoice()
invoices_weekly = self.env['account.invoice'].search(
- [('contract_id', '=', self.contract.id)])
+ [('contract_id', '=', self.contract.id)]
+ )
self.assertTrue(invoices_weekly)
self.assertEqual(
- self.contract.recurring_next_date, recurring_next_date)
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
+ self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
+
+ def test_contract_yearly_post_paid(self):
+ recurring_next_date = to_date('2019-02-22')
+ last_date_invoiced = to_date('2018-02-21')
+ self.acct_line.recurring_next_date = '2018-02-22'
+ self.acct_line.recurring_rule_type = 'yearly'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.contract.recurring_create_invoice()
+ invoices_weekly = self.env['account.invoice'].search(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.assertTrue(invoices_weekly)
+ self.assertEqual(
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
+ self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
+
+ def test_contract_yearly_pre_paid(self):
+ recurring_next_date = to_date('2019-02-22')
+ last_date_invoiced = to_date('2019-02-21')
+ self.acct_line.date_end = '2020-02-22'
+ self.acct_line.recurring_next_date = '2018-02-22'
+ self.acct_line.recurring_rule_type = 'yearly'
+ self.acct_line.recurring_invoicing_type = 'pre-paid'
+ self.contract.recurring_create_invoice()
+ invoices_weekly = self.env['account.invoice'].search(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.assertTrue(invoices_weekly)
+ self.assertEqual(
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
+ self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
def test_contract_monthly_lastday(self):
- recurring_next_date = fields.Date.to_date('2016-03-31')
- self.contract.recurring_next_date = '2016-02-29'
- self.contract.recurring_invoicing_type = 'post-paid'
- self.contract.recurring_rule_type = 'monthlylastday'
+ recurring_next_date = to_date('2018-03-31')
+ last_date_invoiced = to_date('2018-02-22')
+ self.acct_line.recurring_next_date = '2018-02-22'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.recurring_rule_type = 'monthlylastday'
self.contract.recurring_create_invoice()
invoices_monthly_lastday = self.env['account.invoice'].search(
- [('contract_id', '=', self.contract.id)])
+ [('contract_id', '=', self.contract.id)]
+ )
self.assertTrue(invoices_monthly_lastday)
- self.assertEqual(self.contract.recurring_next_date,
- recurring_next_date)
+ self.assertEqual(
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
+ self.assertEqual(self.acct_line.last_date_invoiced, last_date_invoiced)
+
+ def test_last_invoice_post_paid(self):
+ self.acct_line.date_start = '2018-01-01'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.date_end = '2018-03-15'
+ self.acct_line._onchange_date_start()
+ self.assertTrue(self.acct_line.create_invoice_visibility)
+ self.assertEqual(
+ self.acct_line.recurring_next_date, to_date('2018-02-01')
+ )
+ self.assertFalse(self.acct_line.last_date_invoiced)
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.acct_line.recurring_next_date, to_date('2018-03-01')
+ )
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-01-31')
+ )
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.acct_line.recurring_next_date, to_date('2018-04-01')
+ )
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-02-28')
+ )
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-03-15')
+ )
+ self.assertFalse(self.acct_line.recurring_next_date)
+ self.assertFalse(self.acct_line.create_invoice_visibility)
+ invoices = self.env['account.invoice'].search(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.contract.recurring_create_invoice()
+ new_invoices = self.env['account.invoice'].search(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.assertEqual(
+ invoices,
+ new_invoices,
+ "Should not create a new invoice after the last one",
+ )
+
+ def test_last_invoice_pre_paid(self):
+ self.acct_line.date_start = '2018-01-01'
+ self.acct_line.recurring_invoicing_type = 'pre-paid'
+ self.acct_line.date_end = '2018-03-15'
+ self.acct_line._onchange_date_start()
+ self.assertTrue(self.acct_line.create_invoice_visibility)
+ self.assertEqual(
+ self.acct_line.recurring_next_date, to_date('2018-01-01')
+ )
+ self.assertFalse(self.acct_line.last_date_invoiced)
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.acct_line.recurring_next_date, to_date('2018-02-01')
+ )
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-01-31')
+ )
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-02-28')
+ )
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-02-28')
+ )
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.acct_line.last_date_invoiced, to_date('2018-03-15')
+ )
+ self.assertFalse(self.acct_line.recurring_next_date)
+ self.assertFalse(self.acct_line.create_invoice_visibility)
+ invoices = self.env['account.invoice'].search(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.contract.recurring_create_invoice()
+ new_invoices = self.env['account.invoice'].search(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.assertEqual(
+ invoices,
+ new_invoices,
+ "Should not create a new invoice after the last one",
+ )
def test_onchange_partner_id(self):
self.contract._onchange_partner_id()
- self.assertEqual(self.contract.pricelist_id,
- self.contract.partner_id.property_product_pricelist)
+ self.assertEqual(
+ self.contract.pricelist_id,
+ self.contract.partner_id.property_product_pricelist,
+ )
def test_onchange_date_start(self):
- recurring_next_date = fields.Date.to_date('2016-01-01')
- self.contract.date_start = recurring_next_date
- self.contract._onchange_date_start()
- self.assertEqual(self.contract.recurring_next_date,
- recurring_next_date)
+ recurring_next_date = to_date('2018-01-01')
+ self.acct_line.date_start = recurring_next_date
+ self.acct_line._onchange_date_start()
+ self.assertEqual(
+ self.acct_line.recurring_next_date, recurring_next_date
+ )
def test_uom(self):
uom_litre = self.env.ref('uom.product_uom_litre')
self.acct_line.uom_id = uom_litre.id
self.acct_line._onchange_product_id()
- self.assertEqual(self.acct_line.uom_id,
- self.acct_line.product_id.uom_id)
+ self.assertEqual(
+ self.acct_line.uom_id, self.acct_line.product_id.uom_id
+ )
def test_onchange_product_id(self):
line = self.env['account.analytic.invoice.line'].new()
@@ -187,66 +394,74 @@ class TestContract(TestContractBase):
self.assertAlmostEqual(self.acct_line.price_subtotal, 100.0)
def test_check_journal(self):
- contract_no_journal = self.contract.copy()
- contract_no_journal.journal_id = False
journal = self.env['account.journal'].search([('type', '=', 'sale')])
journal.write({'type': 'general'})
with self.assertRaises(ValidationError):
- contract_no_journal.recurring_create_invoice()
+ self.contract.recurring_create_invoice()
def test_check_date_end(self):
with self.assertRaises(ValidationError):
- self.contract.date_end = '2015-12-31'
+ self.acct_line.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',
- })
+ self.acct_line.write(
+ {
+ 'date_start': '2018-01-01',
+ 'recurring_next_date': '2017-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,
- })
+ self.contract.write({'recurring_invoices': True})
+ self.acct_line.write({'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,
- })
+ self.contract.write({'recurring_invoices': True})
+ self.acct_line.write({'date_start': False})
def test_onchange_contract_template_id(self):
"""It should change the contract values to match the template."""
self.contract.contract_template_id = self.template
self.contract._onchange_contract_template_id()
res = {
- 'recurring_rule_type': self.contract.recurring_rule_type,
- 'recurring_interval': self.contract.recurring_interval,
+ 'recurring_invoice_line_ids': [
+ (
+ 0,
+ 0,
+ {
+ 'product_id': self.product.id,
+ 'name': 'Services from #START# to #END#',
+ 'quantity': 1,
+ 'uom_id': self.product.uom_id.id,
+ 'price_unit': 100,
+ 'discount': 50,
+ 'recurring_rule_type': 'yearly',
+ 'recurring_interval': 1,
+ },
+ )
+ ]
}
del self.template_vals['name']
self.assertDictEqual(res, self.template_vals)
def test_onchange_contract_template_id_lines(self):
"""It should create invoice lines for the contract lines."""
-
+ self.acct_line.cancel()
self.acct_line.unlink()
- self.line_vals['analytic_account_id'] = self.template.id
- self.env['account.analytic.contract.line'].create(self.line_vals)
self.contract.contract_template_id = self.template
- self.assertFalse(self.contract.recurring_invoice_line_ids,
- 'Recurring lines were not removed.')
-
+ self.assertFalse(
+ self.contract.recurring_invoice_line_ids,
+ 'Recurring lines were not removed.',
+ )
+ self.contract.contract_template_id = self.template
self.contract._onchange_contract_template_id()
- del self.line_vals['analytic_account_id']
-
self.assertEqual(len(self.contract.recurring_invoice_line_ids), 1)
- for key, value in self.line_vals.items():
+ for key, value in self.line_template_vals.items():
test_value = self.contract.recurring_invoice_line_ids[0][key]
try:
test_value = test_value.id
@@ -262,7 +477,8 @@ class TestContract(TestContractBase):
self.contract._onchange_contract_type()
self.assertEqual(self.contract.journal_id.type, 'sale')
self.assertEqual(
- self.contract.journal_id.company_id, self.contract.company_id)
+ self.contract.journal_id.company_id, self.contract.company_id
+ )
def test_contract_onchange_product_id_domain_blank(self):
"""It should return a blank UoM domain when no product."""
@@ -286,18 +502,19 @@ class TestContract(TestContractBase):
)
line.product_id.uom_id = self.env.ref('uom.product_uom_day').id
line._onchange_product_id()
- self.assertEqual(line.uom_id,
- line.product_id.uom_id)
+ self.assertEqual(line.uom_id, line.product_id.uom_id)
def test_contract_onchange_product_id_name(self):
"""It should update the name for the line."""
line = self._add_template_line()
line.product_id.description_sale = 'Test'
line._onchange_product_id()
- self.assertEqual(line.name,
- '\n'.join([line.product_id.name,
- line.product_id.description_sale,
- ]))
+ self.assertEqual(
+ line.name,
+ '\n'.join(
+ [line.product_id.name, line.product_id.description_sale]
+ ),
+ )
def test_contract_count(self):
"""It should return sale contract count."""
@@ -313,48 +530,32 @@ class TestContract(TestContractBase):
def test_same_date_start_and_date_end(self):
"""It should create one invoice with same start and end date."""
account_invoice_model = self.env['account.invoice']
- self.contract.write({
- 'date_start': fields.Date.today(),
- 'date_end': fields.Date.today(),
- 'recurring_next_date': fields.Date.today(),
- })
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today(),
+ 'date_end': fields.Date.today(),
+ 'recurring_next_date': fields.Date.today(),
+ }
+ )
+ self.contract._compute_recurring_next_date()
init_count = account_invoice_model.search_count(
- [('contract_id', '=', self.contract.id)])
- self.contract.cron_recurring_create_invoice()
- last_count = account_invoice_model.search_count(
- [('contract_id', '=', self.contract.id)])
- self.assertEqual(last_count, init_count + 1)
- with self.assertRaises(ValidationError):
- 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)
-
- def test_extend_invoice(self):
- account_invoice_model = self.env['account.invoice']
+ [('contract_id', '=', self.contract.id)]
+ )
self.contract.recurring_create_invoice()
- invoice = account_invoice_model.search(
- [('contract_id', '=', self.contract.id)])
- invoice.origin = 'Orig Invoice'
- self.contract._create_invoice(invoice)
- self.assertEqual(invoice.origin, 'Orig Invoice Test Contract')
- invoice_count = account_invoice_model.search_count(
- [('contract_id', '=', self.contract.id)])
- self.assertEqual(invoice_count, 1)
- self.assertEqual(len(invoice.invoice_line_ids), 2)
+ last_count = account_invoice_model.search_count(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.assertEqual(last_count, init_count + 1)
+ self.contract.recurring_create_invoice()
+ last_count = account_invoice_model.search_count(
+ [('contract_id', '=', self.contract.id)]
+ )
+ self.assertEqual(last_count, init_count + 1)
def test_act_show_contract(self):
- show_contract = self.partner.\
- with_context(contract_type='sale').act_show_contract()
+ show_contract = self.partner.with_context(
+ contract_type='sale'
+ ).act_show_contract()
self.assertDictContainsSubset(
{
'name': 'Customer Contracts',
@@ -364,5 +565,860 @@ class TestContract(TestContractBase):
'xml_id': 'contract.action_account_analytic_sale_overdue_all',
},
show_contract,
- 'There was an error and the view couldn\'t be opened.'
+ 'There was an error and the view couldn\'t be opened.',
)
+
+ def test_compute_first_recurring_next_date(self):
+ """Test different combination to compute recurring_next_date
+ Combination format
+ {
+ 'recurring_next_date': ( # date
+ date_start, # date
+ recurring_invoicing_type, # ('pre-paid','post-paid',)
+ recurring_rule_type, # ('daily', 'weekly', 'monthly',
+ # 'monthlylastday', 'yearly'),
+ recurring_interval, # integer
+ ),
+ }
+ """
+
+ def error_message(
+ date_start,
+ recurring_invoicing_type,
+ recurring_rule_type,
+ recurring_interval,
+ ):
+ return "Error in %s every %d %s case, start with %s " % (
+ recurring_invoicing_type,
+ recurring_interval,
+ recurring_rule_type,
+ date_start,
+ )
+
+ combinations = [
+ (
+ to_date('2018-01-01'),
+ (to_date('2018-01-01'), 'pre-paid', 'monthly', 1),
+ ),
+ (
+ to_date('2018-01-01'),
+ (to_date('2018-01-01'), 'pre-paid', 'monthly', 2),
+ ),
+ (
+ to_date('2018-02-01'),
+ (to_date('2018-01-01'), 'post-paid', 'monthly', 1),
+ ),
+ (
+ to_date('2018-03-01'),
+ (to_date('2018-01-01'), 'post-paid', 'monthly', 2),
+ ),
+ (
+ to_date('2018-01-31'),
+ (to_date('2018-01-05'), 'post-paid', 'monthlylastday', 1),
+ ),
+ (
+ to_date('2018-01-31'),
+ (to_date('2018-01-06'), 'pre-paid', 'monthlylastday', 1),
+ ),
+ (
+ to_date('2018-02-28'),
+ (to_date('2018-01-05'), 'pre-paid', 'monthlylastday', 2),
+ ),
+ (
+ to_date('2018-01-05'),
+ (to_date('2018-01-05'), 'pre-paid', 'yearly', 1),
+ ),
+ (
+ to_date('2019-01-05'),
+ (to_date('2018-01-05'), 'post-paid', 'yearly', 1),
+ ),
+ ]
+ contract_line_env = self.env['account.analytic.invoice.line']
+ for recurring_next_date, combination in combinations:
+ self.assertEqual(
+ recurring_next_date,
+ contract_line_env._compute_first_recurring_next_date(
+ *combination
+ ),
+ error_message(*combination),
+ )
+
+ def test_recurring_next_date(self):
+ """recurring next date for a contract is the min for all lines"""
+ self.contract.recurring_create_invoice()
+ self.assertEqual(
+ self.contract.recurring_next_date,
+ min(
+ self.contract.recurring_invoice_line_ids.mapped(
+ 'recurring_next_date'
+ )
+ ),
+ )
+
+ def test_date_end(self):
+ """recurring next date for a contract is the min for all lines"""
+ self.assertEqual(self.acct_line.date_end, to_date('2019-01-01'))
+ self.acct_line.date_end = '2018-01-01'
+ self.assertEqual(self.acct_line.date_end, to_date('2018-01-01'))
+ self.acct_line.copy()
+ self.acct_line.write({'date_end': False, 'is_auto_renew': False})
+ self.assertFalse(self.contract.date_end)
+
+ def test_last_date_invoiced_prepaid(self):
+ self.contract.recurring_create_invoice()
+ self
+
+ def test_stop_contract_line(self):
+ """It should put end to the contract line"""
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today(),
+ 'recurring_next_date': fields.Date.today(),
+ 'date_end': fields.Date.today() + relativedelta(months=7),
+ 'is_auto_renew': True,
+ }
+ )
+ self.acct_line.stop(fields.Date.today() + relativedelta(months=5))
+ self.assertEqual(
+ self.acct_line.date_end,
+ fields.Date.today() + relativedelta(months=5),
+ )
+
+ def test_stop_upcoming_contract_line(self):
+ """It should put end to the contract line"""
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today() + relativedelta(months=3),
+ 'recurring_next_date': fields.Date.today()
+ + relativedelta(months=3),
+ 'date_end': fields.Date.today() + relativedelta(months=7),
+ 'is_auto_renew': True,
+ }
+ )
+ self.acct_line.stop(fields.Date.today())
+ self.assertEqual(
+ self.acct_line.date_end,
+ fields.Date.today() + relativedelta(months=7),
+ )
+ self.assertTrue(self.acct_line.is_canceled)
+
+ def test_stop_past_contract_line(self):
+ """Past contract line are ignored on stop"""
+ self.acct_line.write(
+ {
+ 'date_end': fields.Date.today() + relativedelta(months=5),
+ 'is_auto_renew': True,
+ }
+ )
+ self.acct_line.stop(fields.Date.today() + relativedelta(months=7))
+ self.assertEqual(
+ self.acct_line.date_end,
+ fields.Date.today() + relativedelta(months=5),
+ )
+
+ def test_stop_contract_line_without_date_end(self):
+ """Past contract line are ignored on stop"""
+ self.acct_line.write({'date_end': False, 'is_auto_renew': False})
+ self.acct_line.stop(fields.Date.today() + relativedelta(months=7))
+ self.assertEqual(
+ self.acct_line.date_end,
+ fields.Date.today() + relativedelta(months=7),
+ )
+
+ def test_stop_plan_successor_wizard(self):
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today(),
+ 'recurring_next_date': fields.Date.today(),
+ 'date_end': fields.Date.today() + relativedelta(months=5),
+ 'is_auto_renew': True,
+ }
+ )
+ wizard = self.env['account.analytic.invoice.line.wizard'].create(
+ {
+ 'date_end': fields.Date.today() + relativedelta(months=7),
+ 'contract_line_id': self.acct_line.id,
+ }
+ )
+ wizard.stop()
+ self.assertEqual(
+ self.acct_line.date_end,
+ fields.Date.today() + relativedelta(months=7),
+ )
+ self.assertFalse(self.acct_line.is_auto_renew)
+
+ def test_stop_plan_successor_contract_line_1(self):
+ """
+ * contract line end's before the suspension period:
+ -> apply stop
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=5)
+ suspension_end = fields.Date.today() + relativedelta(months=6)
+ start_date = fields.Date.today()
+ end_date = fields.Date.today() + relativedelta(months=4)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(self.acct_line.date_end, end_date)
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_stop_plan_successor_contract_line_2(self):
+ """
+ * contract line start before the suspension period and end in it
+ -> apply stop at suspension start date
+ -> apply plan successor:
+ - date_start: suspension.date_end
+ - date_end: suspension.date_end + (contract_line.date_end
+ - suspension.date_start)
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=3)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today()
+ end_date = fields.Date.today() + relativedelta(months=4)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_end, suspension_start - relativedelta(days=1)
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertTrue(new_line)
+ new_date_end = (
+ suspension_end
+ + (end_date - suspension_start)
+ + relativedelta(days=1)
+ )
+ self.assertEqual(
+ new_line.date_start, suspension_end + relativedelta(days=1)
+ )
+ self.assertEqual(new_line.date_end, new_date_end)
+
+ def test_stop_plan_successor_contract_line_3(self):
+ """
+ * contract line start before the suspension period and end after it
+ -> apply stop at suspension start date
+ -> apply plan successor:
+ - date_start: suspension.date_end
+ - date_end: suspension.date_end + (suspension.date_end
+ - suspension.date_start)
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=3)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today()
+ end_date = fields.Date.today() + relativedelta(months=6)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_end, suspension_start - relativedelta(days=1)
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertTrue(new_line)
+ new_date_end = (
+ end_date
+ + (suspension_end - suspension_start)
+ + relativedelta(days=1)
+ )
+ self.assertEqual(
+ new_line.date_start, suspension_end + relativedelta(days=1)
+ )
+ self.assertEqual(new_line.date_end, new_date_end)
+
+ def test_stop_plan_successor_contract_line_3_without_end_date(self):
+ """
+ * contract line start before the suspension period and end after it
+ -> apply stop at suspension start date
+ -> apply plan successor:
+ - date_start: suspension.date_end
+ - date_end: suspension.date_end + (suspension.date_end
+ - suspension.date_start)
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=3)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today()
+ end_date = False
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ 'is_auto_renew': False,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, False
+ )
+ self.assertEqual(
+ self.acct_line.date_end, suspension_start - relativedelta(days=1)
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertTrue(new_line)
+ self.assertEqual(
+ new_line.date_start, suspension_end + relativedelta(days=1)
+ )
+ self.assertFalse(new_line.date_end)
+
+ def test_stop_plan_successor_contract_line_4(self):
+ """
+ * contract line start and end's in the suspension period
+ -> apply delay
+ - delay: suspension.date_end - contract_line.end_date
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=2)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today() + relativedelta(months=3)
+ end_date = fields.Date.today() + relativedelta(months=4)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_start,
+ start_date + (suspension_end - start_date) + timedelta(days=1),
+ )
+ self.assertEqual(
+ self.acct_line.date_end,
+ end_date + (suspension_end - start_date) + timedelta(days=1),
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_stop_plan_successor_contract_line_5(self):
+ """
+ * contract line start in the suspension period and end after it
+ -> apply delay
+ - delay: suspension.date_end - contract_line.date_start
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=2)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today() + relativedelta(months=3)
+ end_date = fields.Date.today() + relativedelta(months=6)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_start,
+ start_date + (suspension_end - start_date) + timedelta(days=1),
+ )
+ self.assertEqual(
+ self.acct_line.date_end,
+ end_date + (suspension_end - start_date) + timedelta(days=1),
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_stop_plan_successor_contract_line_5_without_date_end(self):
+ """
+ * contract line start in the suspension period and end after it
+ -> apply delay
+ - delay: suspension.date_end - contract_line.date_start
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=2)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today() + relativedelta(months=3)
+ end_date = False
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ 'is_auto_renew': False,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_start,
+ start_date + (suspension_end - start_date) + timedelta(days=1),
+ )
+ self.assertFalse(self.acct_line.date_end)
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_stop_plan_successor_contract_line_6(self):
+ """
+ * contract line start and end after the suspension period
+ -> apply delay
+ - delay: suspension.date_end - suspension.start_date
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=2)
+ suspension_end = fields.Date.today() + relativedelta(months=3)
+ start_date = fields.Date.today() + relativedelta(months=4)
+ end_date = fields.Date.today() + relativedelta(months=6)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_start,
+ start_date
+ + (suspension_end - suspension_start)
+ + timedelta(days=1),
+ )
+ self.assertEqual(
+ self.acct_line.date_end,
+ end_date + (suspension_end - suspension_start) + timedelta(days=1),
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_stop_plan_successor_contract_line_6_without_date_end(self):
+ """
+ * contract line start and end after the suspension period
+ -> apply delay
+ - delay: suspension.date_end - suspension.start_date
+ """
+ suspension_start = fields.Date.today() + relativedelta(months=2)
+ suspension_end = fields.Date.today() + relativedelta(months=3)
+ start_date = fields.Date.today() + relativedelta(months=4)
+ end_date = False
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ 'is_auto_renew': False,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_start,
+ start_date
+ + (suspension_end - suspension_start)
+ + timedelta(days=1),
+ )
+ self.assertFalse(self.acct_line.date_end)
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_stop_plan_successor_wizard(self):
+ suspension_start = fields.Date.today() + relativedelta(months=2)
+ suspension_end = fields.Date.today() + relativedelta(months=3)
+ start_date = fields.Date.today() + relativedelta(months=4)
+ end_date = fields.Date.today() + relativedelta(months=6)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ wizard = self.env['account.analytic.invoice.line.wizard'].create(
+ {
+ 'date_start': suspension_start,
+ 'date_end': suspension_end,
+ 'is_auto_renew': False,
+ 'contract_line_id': self.acct_line.id,
+ }
+ )
+ wizard.stop_plan_successor()
+ self.assertEqual(
+ self.acct_line.date_start,
+ start_date
+ + (suspension_end - suspension_start)
+ + timedelta(days=1),
+ )
+ self.assertEqual(
+ self.acct_line.date_end,
+ end_date + (suspension_end - suspension_start) + timedelta(days=1),
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(new_line)
+
+ def test_plan_successor_contract_line(self):
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today(),
+ 'recurring_next_date': fields.Date.today(),
+ 'date_end': fields.Date.today() + relativedelta(months=3),
+ 'is_auto_renew': False,
+ }
+ )
+ self.acct_line.plan_successor(
+ fields.Date.today() + relativedelta(months=5),
+ fields.Date.today() + relativedelta(months=7),
+ True,
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(self.acct_line.is_auto_renew)
+ self.assertTrue(new_line.is_auto_renew)
+ self.assertTrue(new_line, "should create a new contract line")
+ self.assertEqual(
+ new_line.date_start, fields.Date.today() + relativedelta(months=5)
+ )
+ self.assertEqual(
+ new_line.date_end, fields.Date.today() + relativedelta(months=7)
+ )
+
+ def test_overlap(self):
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today(),
+ 'recurring_next_date': fields.Date.today(),
+ 'date_end': fields.Date.today() + relativedelta(months=3),
+ 'is_auto_renew': False,
+ }
+ )
+ self.acct_line.plan_successor(
+ fields.Date.today() + relativedelta(months=5),
+ fields.Date.today() + relativedelta(months=7),
+ True,
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ with self.assertRaises(ValidationError):
+ new_line.date_start = fields.Date.today() + relativedelta(months=2)
+ with self.assertRaises(ValidationError):
+ self.acct_line.date_end = fields.Date.today() + relativedelta(
+ months=6
+ )
+
+ def test_plan_successor_wizard(self):
+ self.acct_line.write(
+ {
+ 'date_start': fields.Date.today(),
+ 'recurring_next_date': fields.Date.today(),
+ 'date_end': fields.Date.today() + relativedelta(months=2),
+ 'is_auto_renew': False,
+ }
+ )
+ wizard = self.env['account.analytic.invoice.line.wizard'].create(
+ {
+ 'date_start': fields.Date.today() + relativedelta(months=3),
+ 'date_end': fields.Date.today() + relativedelta(months=5),
+ 'is_auto_renew': True,
+ 'contract_line_id': self.acct_line.id,
+ }
+ )
+ wizard.plan_successor()
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertFalse(self.acct_line.is_auto_renew)
+ self.assertTrue(new_line.is_auto_renew)
+ self.assertTrue(new_line, "should create a new contract line")
+ self.assertEqual(
+ new_line.date_start, fields.Date.today() + relativedelta(months=3)
+ )
+ self.assertEqual(
+ new_line.date_end, fields.Date.today() + relativedelta(months=5)
+ )
+
+ def test_cancel(self):
+ self.acct_line.cancel()
+ self.assertTrue(self.acct_line.is_canceled)
+ self.acct_line.uncancel(fields.Date.today())
+ self.assertFalse(self.acct_line.is_canceled)
+
+ def test_cancel_uncancel_with_predecessor(self):
+ suspension_start = fields.Date.today() + relativedelta(months=3)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ start_date = fields.Date.today()
+ end_date = fields.Date.today() + relativedelta(months=4)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ self.assertEqual(
+ self.acct_line.date_end, suspension_start - relativedelta(days=1)
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ self.assertEqual(self.acct_line.successor_contract_line_id, new_line)
+ new_line.cancel()
+ self.assertTrue(new_line.is_canceled)
+ self.assertFalse(self.acct_line.successor_contract_line_id)
+ self.assertEqual(new_line.predecessor_contract_line_id, self.acct_line)
+ new_line.uncancel(suspension_end + relativedelta(days=1))
+ self.assertFalse(new_line.is_canceled)
+ self.assertEqual(self.acct_line.successor_contract_line_id, new_line)
+ self.assertEqual(
+ new_line.recurring_next_date,
+ suspension_end + relativedelta(days=1),
+ )
+
+ def test_cancel_uncancel_with_predecessor_has_successor(self):
+ suspension_start = fields.Date.today() + relativedelta(months=6)
+ suspension_end = fields.Date.today() + relativedelta(months=7)
+ start_date = fields.Date.today()
+ end_date = fields.Date.today() + relativedelta(months=8)
+ self.acct_line.write(
+ {
+ 'date_start': start_date,
+ 'recurring_next_date': start_date,
+ 'date_end': end_date,
+ }
+ )
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ new_line = self.env['account.analytic.invoice.line'].search(
+ [('predecessor_contract_line_id', '=', self.acct_line.id)]
+ )
+ new_line.cancel()
+ suspension_start = fields.Date.today() + relativedelta(months=4)
+ suspension_end = fields.Date.today() + relativedelta(months=5)
+ self.acct_line.stop_plan_successor(
+ suspension_start, suspension_end, True
+ )
+ with self.assertRaises(ValidationError):
+ new_line.uncancel(suspension_end)
+
+ def test_check_has_not_date_end_has_successor(self):
+ self.acct_line.write({'date_end': False, 'is_auto_renew': False})
+ with self.assertRaises(ValidationError):
+ self.acct_line.plan_successor(
+ to_date('2016-03-01'), to_date('2016-09-01'), False
+ )
+
+ def test_check_has_not_date_end_is_auto_renew(self):
+ with self.assertRaises(ValidationError):
+ self.acct_line.write({'date_end': False, 'is_auto_renew': True})
+
+ def test_check_has_successor_is_auto_renew(self):
+ with self.assertRaises(ValidationError):
+ self.acct_line.plan_successor(
+ to_date('2016-03-01'), to_date('2018-09-01'), False
+ )
+
+ def test_search_contract_line_to_renew(self):
+ self.acct_line.write({'date_end': fields.Date.today()})
+ line_1 = self.acct_line.copy(
+ {'date_end': fields.Date.today() + relativedelta(months=1)}
+ )
+ line_2 = self.acct_line.copy(
+ {'date_end': fields.Date.today() - relativedelta(months=1)}
+ )
+ line_3 = self.acct_line.copy(
+ {'date_end': fields.Date.today() - relativedelta(months=2)}
+ )
+ self.acct_line.copy(
+ {'date_end': fields.Date.today() + relativedelta(months=2)}
+ )
+ to_renew = self.acct_line.search(
+ self.acct_line._contract_line_to_renew_domain()
+ )
+ self.assertEqual(
+ set(to_renew), set((self.acct_line, line_1, line_2, line_3))
+ )
+
+ def test_renew(self):
+ self.acct_line._onchange_is_auto_renew()
+ self.assertEqual(self.acct_line.date_end, to_date('2018-12-31'))
+ new_line = self.acct_line.renew()
+ self.assertFalse(self.acct_line.is_auto_renew)
+ self.assertTrue(new_line.is_auto_renew)
+ self.assertEqual(new_line.date_start, to_date('2019-01-01'))
+ self.assertEqual(new_line.date_end, to_date('2019-12-31'))
+
+ def test_cron_recurring_create_invoice(self):
+ self.acct_line.date_start = '2018-01-01'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.date_end = '2018-03-15'
+ self.acct_line._onchange_date_start()
+ contracts = self.contract
+ for i in range(10):
+ contracts |= self.contract.copy()
+ self.env['account.analytic.account'].cron_recurring_create_invoice()
+ invoices = self.env['account.invoice'].search(
+ [('contract_id', 'in', contracts.ids)]
+ )
+ self.assertEqual(len(contracts), len(invoices))
+
+ def test_get_invoiced_period_monthlylastday(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.recurring_rule_type = 'monthlylastday'
+ self.acct_line.date_end = '2018-03-15'
+ self.acct_line._onchange_date_start()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-01-05'))
+ self.assertEqual(last, to_date('2018-01-31'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-01'))
+ self.assertEqual(last, to_date('2018-02-28'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-03-01'))
+ self.assertEqual(last, to_date('2018-03-15'))
+
+ def test_get_invoiced_period_monthly_pre_paid_2(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'pre-paid'
+ self.acct_line.recurring_rule_type = 'monthly'
+ self.acct_line.date_end = '2018-08-15'
+ self.acct_line._onchange_date_start()
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-05'))
+ self.assertEqual(last, to_date('2018-03-04'))
+ self.acct_line.recurring_next_date = '2018-06-05'
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-05'))
+ self.assertEqual(last, to_date('2018-07-04'))
+
+ def test_get_invoiced_period_monthly_post_paid_2(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.recurring_rule_type = 'monthly'
+ self.acct_line.date_end = '2018-08-15'
+ self.acct_line._onchange_date_start()
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-05'))
+ self.assertEqual(last, to_date('2018-03-04'))
+ self.acct_line.recurring_next_date = '2018-06-05'
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-05'))
+ self.assertEqual(last, to_date('2018-06-04'))
+
+ def test_get_invoiced_period_monthly_post_paid(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.recurring_rule_type = 'monthly'
+ self.acct_line.date_end = '2018-03-15'
+ self.acct_line._onchange_date_start()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-01-05'))
+ self.assertEqual(last, to_date('2018-02-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-05'))
+ self.assertEqual(last, to_date('2018-03-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-03-05'))
+ self.assertEqual(last, to_date('2018-03-15'))
+
+ def test_get_invoiced_period_monthly_pre_paid(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'pre-paid'
+ self.acct_line.recurring_rule_type = 'monthly'
+ self.acct_line.date_end = '2018-03-15'
+ self.acct_line._onchange_date_start()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-01-05'))
+ self.assertEqual(last, to_date('2018-02-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-02-05'))
+ self.assertEqual(last, to_date('2018-03-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-03-05'))
+ self.assertEqual(last, to_date('2018-03-15'))
+
+ def test_get_invoiced_period_yearly_post_paid(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'post-paid'
+ self.acct_line.recurring_rule_type = 'yearly'
+ self.acct_line.date_end = '2020-03-15'
+ self.acct_line._onchange_date_start()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-01-05'))
+ self.assertEqual(last, to_date('2019-01-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2019-01-05'))
+ self.assertEqual(last, to_date('2020-01-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2020-01-05'))
+ self.assertEqual(last, to_date('2020-03-15'))
+
+ def test_get_invoiced_period_yearly_pre_paid(self):
+ self.acct_line.date_start = '2018-01-05'
+ self.acct_line.recurring_invoicing_type = 'pre-paid'
+ self.acct_line.recurring_rule_type = 'yearly'
+ self.acct_line.date_end = '2020-03-15'
+ self.acct_line._onchange_date_start()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2018-01-05'))
+ self.assertEqual(last, to_date('2019-01-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2019-01-05'))
+ self.assertEqual(last, to_date('2020-01-04'))
+ self.contract.recurring_create_invoice()
+ first, last = self.acct_line._get_invoiced_period()
+ self.assertEqual(first, to_date('2020-01-05'))
+ self.assertEqual(last, to_date('2020-03-15'))
+
+ def test_unlink(self):
+ with self.assertRaises(ValidationError):
+ self.acct_line.unlink()
diff --git a/contract/views/abstract_contract_line.xml b/contract/views/abstract_contract_line.xml
new file mode 100644
index 000000000..5e822fb1e
--- /dev/null
+++ b/contract/views/abstract_contract_line.xml
@@ -0,0 +1,71 @@
+
+
+
+
+ Account Abstract Analytic Contract Line Form View
+
+ account.abstract.analytic.contract.line
+
+
+
+
+
+
diff --git a/contract/views/account_analytic_account_view.xml b/contract/views/account_analytic_account_view.xml
deleted file mode 100644
index 07b640a75..000000000
--- a/contract/views/account_analytic_account_view.xml
+++ /dev/null
@@ -1,279 +0,0 @@
-
-
-
-
- Contract form
- account.analytic.account
-
- primary
-
-
-
- {'required': [('recurring_invoices', '=', True)]}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #START#: Start date of the invoiced period
- #END#: End date of the invoiced period
-
-
-
-
-
-
- account.analytic.account.sale.form
- account.analytic.account
-
- primary
-
-
-
- Customer
- [('customer', '=', True)]
- {'default_customer': True, 'default_supplier': False}
-
-
- [('type', '=', 'sale'),('company_id', '=', company_id)]
-
-
- [('sale_ok', '=', True)]
-
-
-
-
-
- account.analytic.account.purchase.form
- account.analytic.account
-
- primary
-
-
-
- Supplier
- [('supplier', '=', True)]
- {'default_customer': False, 'default_supplier': True}
-
-
- [('type', '=', 'purchase'),('company_id', '=', company_id)]
-
-
- [('purchase_ok', '=', True)]
-
-
- True
-
-
-
-
-
-
- Contract list
- account.analytic.account
-
- primary
-
-
-
-
-
-
-
-
-
-
-
-
-
- Contract search
- account.analytic.account
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Customer Contracts
- account.analytic.account
- form
- tree,form
- [('contract_type', '=', 'sale')]
- {'is_contract':1, 'search_default_not_finished':1, 'search_default_recurring_invoices':1, 'default_recurring_invoices': 1, 'default_contract_type': 'sale'}
-
-
-
- Click to create a new contract.
-
-
-
-
-
-
- tree
-
-
-
-
-
-
- form
-
-
-
-
-
-
-
-
- Supplier Contracts
- account.analytic.account
- form
- tree,form
- [('contract_type', '=', 'purchase')]
- {'is_contract':1, 'search_default_not_finished':1, 'search_default_recurring_invoices':1, 'default_recurring_invoices': 1, 'default_contract_type': 'purchase'}
-
-
-
- Click to create a new contract.
-
-
-
-
-
-
- tree
-
-
-
-
-
-
- form
-
-
-
-
-
-
-
diff --git a/contract/views/contract.xml b/contract/views/contract.xml
new file mode 100644
index 000000000..1a982b666
--- /dev/null
+++ b/contract/views/contract.xml
@@ -0,0 +1,314 @@
+
+
+
+
+ Contract form
+ account.analytic.account
+
+
+
+
+
+
+
+ account.analytic.account.sale.form
+ account.analytic.account
+
+ primary
+
+
+
+ Customer
+ [('customer', '=', True)]
+ {'default_customer': True,
+ 'default_supplier': False}
+
+
+
+ [('type', '=', 'sale'),('company_id', '=', company_id)]
+
+
+
+
+
+ account.analytic.account.purchase.form
+ account.analytic.account
+
+ primary
+
+
+
+ Supplier
+ [('supplier', '=', True)]
+ {'default_customer': False,
+ 'default_supplier': True}
+
+
+
+ [('type', '=', 'purchase'),('company_id', '=', company_id)]
+
+
+
+
+
+
+ Contract list
+ account.analytic.account
+
+ primary
+
+
+
+
+
+
+
+
+
+
+ Contract search
+ account.analytic.account
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Customer Contracts
+ account.analytic.account
+ form
+ tree,form
+ [('contract_type', '=', 'sale')]
+ {'is_contract':1,
+ 'search_default_not_finished':1,
+ 'search_default_recurring_invoices':1,
+ 'default_recurring_invoices': 1, 'default_contract_type': 'sale'}
+
+
+
+
+ Click to create a new contract.
+
+
+
+
+
+
+ tree
+
+
+
+
+
+
+ form
+
+
+
+
+
+
+
+
+ Supplier Contracts
+ account.analytic.account
+ form
+ tree,form
+ [('contract_type', '=', 'purchase')]
+ {'is_contract':1,
+ 'search_default_not_finished':1,
+ 'search_default_recurring_invoices':1,
+ 'default_recurring_invoices': 1, 'default_contract_type':
+ 'purchase'}
+
+
+
+
+ Click to create a new contract.
+
+
+
+
+
+
+ tree
+
+
+
+
+
+
+ form
+
+
+
+
+
+
+
diff --git a/contract/views/contract_line.xml b/contract/views/contract_line.xml
new file mode 100644
index 000000000..e89e352b8
--- /dev/null
+++ b/contract/views/contract_line.xml
@@ -0,0 +1,166 @@
+
+
+
+
+ account.analytic.invoice.line.form
+ account.analytic.invoice.line
+
+ primary
+
+
+
+
+
+ Contract Line
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ account.analytic.invoice.line.sale.form
+ account.analytic.invoice.line
+
+ primary
+
+
+
+ [('sale_ok', '=', True)]
+
+
+
+
+
+ account.analytic.invoice.line.purchase.form
+ account.analytic.invoice.line
+
+ primary
+
+
+
+ [('purchase_ok', '=', True)]
+
+
+
+ True
+
+
+
+
+
+ account.analytic.invoice.line.tree
+ account.analytic.invoice.line
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ account.analytic.invoice.line.purchase.tree
+ account.analytic.invoice.line
+ primary
+
+
+
+
+ True
+
+
+
+
+
diff --git a/contract/views/account_analytic_contract_view.xml b/contract/views/contract_template.xml
similarity index 76%
rename from contract/views/account_analytic_contract_view.xml
rename to contract/views/contract_template.xml
index 47f1f5812..6d6b4b1a2 100644
--- a/contract/views/account_analytic_contract_view.xml
+++ b/contract/views/contract_template.xml
@@ -16,24 +16,10 @@
-
-
-
-
-
-
-
-
-
+
@@ -44,6 +30,9 @@
+
+
+
@@ -64,9 +53,6 @@
-
-
-
@@ -79,23 +65,12 @@
-
-
-
-
-
+
+
+
+ account.analytic.contract.line.form
+ account.analytic.contract.line
+
+ primary
+
+
+ Contract Line Template
+
+
+
+
+
diff --git a/contract/wizards/__init__.py b/contract/wizards/__init__.py
new file mode 100644
index 000000000..146dcc66d
--- /dev/null
+++ b/contract/wizards/__init__.py
@@ -0,0 +1 @@
+from . import contract_line_wizard
diff --git a/contract/wizards/contract_line_wizard.py b/contract/wizards/contract_line_wizard.py
new file mode 100644
index 000000000..df84644d0
--- /dev/null
+++ b/contract/wizards/contract_line_wizard.py
@@ -0,0 +1,48 @@
+# Copyright 2018 ACSONE SA/NV
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import api, fields, models
+
+
+class AccountAnalyticInvoiceLineWizard(models.TransientModel):
+
+ _name = 'account.analytic.invoice.line.wizard'
+ _description = 'Contract Line Wizard'
+
+ date_start = fields.Date(string='Date Start')
+ date_end = fields.Date(string='Date End')
+ recurring_next_date = fields.Date(string='Next Invoice Date')
+ is_auto_renew = fields.Boolean(string="Auto Renew", default=False)
+ contract_line_id = fields.Many2one(
+ comodel_name="account.analytic.invoice.line",
+ string="Contract Line",
+ required=True,
+ )
+
+ @api.multi
+ def stop(self):
+ for wizard in self:
+ wizard.contract_line_id.stop(wizard.date_end)
+ return True
+
+ @api.multi
+ def plan_successor(self):
+ for wizard in self:
+ wizard.contract_line_id.plan_successor(
+ wizard.date_start, wizard.date_end, wizard.is_auto_renew
+ )
+ return True
+
+ @api.multi
+ def stop_plan_successor(self):
+ for wizard in self:
+ wizard.contract_line_id.stop_plan_successor(
+ wizard.date_start, wizard.date_end, wizard.is_auto_renew
+ )
+ return True
+
+ @api.multi
+ def uncancel(self):
+ for wizard in self:
+ wizard.contract_line_id.uncancel(wizard.recurring_next_date)
+ return True
diff --git a/contract/wizards/contract_line_wizard.xml b/contract/wizards/contract_line_wizard.xml
new file mode 100644
index 000000000..d6b58d9de
--- /dev/null
+++ b/contract/wizards/contract_line_wizard.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+ contract.line.stop.wizard.form (in contract)
+ account.analytic.invoice.line.wizard
+
+
+
+
+
+
+ contract.line.plan_successor.wizard.form (in contract)
+ account.analytic.invoice.line.wizard
+
+
+
+
+
+
+ contract.line.stop_plan_successor.wizard.form (in contract)
+ account.analytic.invoice.line.wizard
+
+
+
+
+
+
+ contract.line.stop_plan_successor.wizard.form (in contract)
+ account.analytic.invoice.line.wizard
+
+
+
+
+
+