mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[IMP] contract: support pre-paid for monthlylastday
monthlylastday is (almost) not a special case anymore \o/. montlylastday is simply a montly period where the periods are aligned on month boundaries. The last bit of special casing is that postpaid generates invoice the day after the last dasy of the period, except for monthlylastday where the invoice is generated on the last day of the period. This last exception will disappear when we put the offset under user control. This is a breaking change because the post-paid/pre-paid mode becomes relevant for monthlylastday invoicing. The field becomes visible in the UI. Code that generate monthlylastday contract lines must now correctly set the pre-paid/post-paid mode too. Some tests have had to be adapted to reflect that.
This commit is contained in:
10
contract/migrations/12.0.5.0.0/pre-migration.py
Normal file
10
contract/migrations/12.0.5.0.0/pre-migration.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
def migrate(cr, version):
|
||||||
|
# pre-paid/post-paid becomes significant for monthlylastday too,
|
||||||
|
# make sure it has the value that was implied for previous versions.
|
||||||
|
cr.execute(
|
||||||
|
"""\
|
||||||
|
UPDATE contract_line
|
||||||
|
SET recurring_invoicing_type = 'post-paid'
|
||||||
|
WHERE recurring_rule_type = 'monthlylastday'
|
||||||
|
"""
|
||||||
|
)
|
||||||
@@ -380,6 +380,22 @@ class ContractLine(models.Model):
|
|||||||
max_date_end=False,
|
max_date_end=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_offset(self, recurring_invoicing_type, recurring_rule_type):
|
||||||
|
"""Return a relativedelta to offset the invoice date compared
|
||||||
|
to the period start or end date.
|
||||||
|
|
||||||
|
This method will disappear when the offset becomes user controlled.
|
||||||
|
"""
|
||||||
|
if (
|
||||||
|
recurring_invoicing_type == 'pre-paid'
|
||||||
|
or recurring_rule_type == 'monthlylastday'
|
||||||
|
):
|
||||||
|
offset = 0
|
||||||
|
else:
|
||||||
|
offset = 1
|
||||||
|
return relativedelta(days=offset)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_recurring_next_date(
|
def _get_recurring_next_date(
|
||||||
self,
|
self,
|
||||||
@@ -398,12 +414,11 @@ class ContractLine(models.Model):
|
|||||||
)
|
)
|
||||||
if not next_period_date_end:
|
if not next_period_date_end:
|
||||||
return False
|
return False
|
||||||
if recurring_rule_type == 'monthlylastday':
|
offset = self._get_offset(recurring_invoicing_type, recurring_rule_type)
|
||||||
recurring_next_date = next_period_date_end
|
if recurring_invoicing_type == 'pre-paid':
|
||||||
elif recurring_invoicing_type == 'pre-paid':
|
recurring_next_date = next_period_date_start + offset
|
||||||
recurring_next_date = next_period_date_start
|
|
||||||
else: # post-paid
|
else: # post-paid
|
||||||
recurring_next_date = next_period_date_end + relativedelta(days=1)
|
recurring_next_date = next_period_date_end + offset
|
||||||
return recurring_next_date
|
return recurring_next_date
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
@@ -433,20 +448,18 @@ class ContractLine(models.Model):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# special algorithm when the next invoice date is forced
|
# special algorithm when the next invoice date is forced
|
||||||
if recurring_rule_type == 'monthlylastday':
|
offset = self._get_offset(recurring_invoicing_type, recurring_rule_type)
|
||||||
next_period_date_end = next_invoice_date
|
if recurring_invoicing_type == 'pre-paid':
|
||||||
elif recurring_invoicing_type == 'pre-paid':
|
|
||||||
next_period_date_end = (
|
next_period_date_end = (
|
||||||
next_invoice_date
|
next_invoice_date
|
||||||
|
- offset
|
||||||
+ self.get_relative_delta(
|
+ self.get_relative_delta(
|
||||||
recurring_rule_type, recurring_interval
|
recurring_rule_type, recurring_interval
|
||||||
)
|
)
|
||||||
- relativedelta(days=1)
|
- relativedelta(days=1)
|
||||||
)
|
)
|
||||||
else: # post-paid
|
else: # post-paid
|
||||||
next_period_date_end = next_invoice_date - relativedelta(
|
next_period_date_end = next_invoice_date - offset
|
||||||
days=1
|
|
||||||
)
|
|
||||||
if max_date_end and next_period_date_end > max_date_end:
|
if max_date_end and next_period_date_end > max_date_end:
|
||||||
# end date is past max_date_end: trim it
|
# end date is past max_date_end: trim it
|
||||||
next_period_date_end = max_date_end
|
next_period_date_end = max_date_end
|
||||||
|
|||||||
@@ -614,12 +614,17 @@ class TestContract(TestContractBase):
|
|||||||
False),
|
False),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
to_date('2018-01-31'),
|
to_date('2018-01-06'),
|
||||||
(to_date('2018-01-06'), 'pre-paid', 'monthlylastday', 1,
|
(to_date('2018-01-06'), 'pre-paid', 'monthlylastday', 1,
|
||||||
False),
|
False),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
to_date('2018-02-28'),
|
to_date('2018-02-28'),
|
||||||
|
(to_date('2018-01-05'), 'post-paid', 'monthlylastday', 2,
|
||||||
|
False),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
to_date('2018-01-05'),
|
||||||
(to_date('2018-01-05'), 'pre-paid', 'monthlylastday', 2,
|
(to_date('2018-01-05'), 'pre-paid', 'monthlylastday', 2,
|
||||||
False),
|
False),
|
||||||
),
|
),
|
||||||
@@ -1363,7 +1368,7 @@ class TestContract(TestContractBase):
|
|||||||
len(invoice_lines),
|
len(invoice_lines),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_period_to_invoice_monthlylastday(self):
|
def test_get_period_to_invoice_monthlylastday_postpaid(self):
|
||||||
self.acct_line.date_start = '2018-01-05'
|
self.acct_line.date_start = '2018-01-05'
|
||||||
self.acct_line.recurring_invoicing_type = 'post-paid'
|
self.acct_line.recurring_invoicing_type = 'post-paid'
|
||||||
self.acct_line.recurring_rule_type = 'monthlylastday'
|
self.acct_line.recurring_rule_type = 'monthlylastday'
|
||||||
@@ -1394,6 +1399,37 @@ class TestContract(TestContractBase):
|
|||||||
self.assertEqual(last, to_date('2018-03-15'))
|
self.assertEqual(last, to_date('2018-03-15'))
|
||||||
self.acct_line.manual_renew_needed = True
|
self.acct_line.manual_renew_needed = True
|
||||||
|
|
||||||
|
def test_get_period_to_invoice_monthlylastday_prepaid(self):
|
||||||
|
self.acct_line.date_start = '2018-01-05'
|
||||||
|
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
||||||
|
self.acct_line.recurring_rule_type = 'monthlylastday'
|
||||||
|
self.acct_line.date_end = '2018-03-15'
|
||||||
|
self.acct_line._onchange_date_start()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertEqual(first, to_date('2018-01-05'))
|
||||||
|
self.assertEqual(last, to_date('2018-01-31'))
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertEqual(first, to_date('2018-02-01'))
|
||||||
|
self.assertEqual(last, to_date('2018-02-28'))
|
||||||
|
self.contract.recurring_create_invoice()
|
||||||
|
first, last, recurring_next_date = \
|
||||||
|
self.acct_line._get_period_to_invoice(
|
||||||
|
self.acct_line.last_date_invoiced,
|
||||||
|
self.acct_line.recurring_next_date,
|
||||||
|
)
|
||||||
|
self.assertEqual(first, to_date('2018-03-01'))
|
||||||
|
self.assertEqual(last, to_date('2018-03-15'))
|
||||||
|
self.acct_line.manual_renew_needed = True
|
||||||
|
|
||||||
def test_get_period_to_invoice_monthly_pre_paid_2(self):
|
def test_get_period_to_invoice_monthly_pre_paid_2(self):
|
||||||
self.acct_line.date_start = '2018-01-05'
|
self.acct_line.date_start = '2018-01-05'
|
||||||
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
self.acct_line.recurring_invoicing_type = 'pre-paid'
|
||||||
|
|||||||
@@ -59,8 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="recurring_invoicing_type"
|
<field name="recurring_invoicing_type"/>
|
||||||
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
|
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class TestContractSaleMandate(TestContractBase):
|
|||||||
'is_contract': True,
|
'is_contract': True,
|
||||||
'default_qty': 12,
|
'default_qty': 12,
|
||||||
'recurring_rule_type': "monthlylastday",
|
'recurring_rule_type': "monthlylastday",
|
||||||
|
'recurring_invoicing_type': "post-paid",
|
||||||
'contract_template_id': cls.contract_template1.id,
|
'contract_template_id': cls.contract_template1.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class TestSaleOrder(TransactionCase):
|
|||||||
'is_contract': True,
|
'is_contract': True,
|
||||||
'default_qty': 12,
|
'default_qty': 12,
|
||||||
'recurring_rule_type': "monthlylastday",
|
'recurring_rule_type': "monthlylastday",
|
||||||
|
'recurring_invoicing_type': "post-paid",
|
||||||
'contract_template_id': self.contract_template1.id,
|
'contract_template_id': self.contract_template1.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,8 +33,7 @@
|
|||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="default_qty"/>
|
<field name="default_qty"/>
|
||||||
<field name="recurring_invoicing_type"
|
<field name="recurring_invoicing_type"/>
|
||||||
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
|
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
|
|||||||
@@ -58,8 +58,7 @@
|
|||||||
<field name="recurring_rule_type"/>
|
<field name="recurring_rule_type"/>
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
||||||
<field name="recurring_invoicing_type"
|
<field name="recurring_invoicing_type"/>
|
||||||
attrs="{'invisible': [('recurring_rule_type', '=', 'monthlylastday')]}"/>
|
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
<group attrs="{'invisible': [('is_contract', '=', False)]}">
|
||||||
<field name="date_start"
|
<field name="date_start"
|
||||||
|
|||||||
Reference in New Issue
Block a user