mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[IMP] contract: Make recurrence mechanism on contract line
Make recurrence mechanism on contract line and some other refactoring [FIX] - Keep contract_cron on account_analytic_account model contract_cron defined with no_update option. Changing it, will cause issue to past version installation. [IMP] - Fix recurring_next_date default value recurring_next_date should have start_date as default value in prepaid policy and start_date + invoicing_interval if postpaid [FIX] - Fix test check no journal [IMP] - Return created invoices on recurring_create_invoice [IMP] - Specific process to compute recurring_next_date for monthly-last-day fixes: #198 [ADD] - Add Post-migration script to bring recurrence info from contract to contract lines [ADD] - Add search filter based on date_end and recurring_next_date - not_finished filter in contract search view - finished filter in contract search view - Next Invoice group by in contract search view [ADD] - Add unit tests - cases to compute first recurring next date - contract recurring_next_date - contract date_end [IMP] - Improve Unit tests [12.0][IMP] - Add strat/stop wizard to contract line [12.0][IMP] - Add pause button to contract line [IMP] - Add state filed in contract line form [FIX] - stop don't change date_end for finished contract line [IMP] - Change contract line buttons visibility Add renewal process with termination notice [FIX] - don't consider stop_date If it is after the contract line end_date [IMP] - consider more cases in stop_plan_successor [IMP] - cancel upcoming line on stop [IMP] - Chnage next invoice date on un-cancel [IMP] - Post message in contract on contract line actions [IMP] - check contract line overlap [FIX] - invoice last period for post-paid case [IMP] - Add primary views for contract [IMP] - don't use related filed for partner_id and pricelist_id [FIX] - fix stop_plan_successor case 5 contract line start in the suspension period and end after it [IMP] - improve cancel/uncancel process [FIX] - Test if start_date is set before compute [FIX] - date_end include in the period in auto_renew case [FIX] - in suspension case, contract line should start a day after the end [IMP] - confirm message on contract line cancel [IMP] - hide recurring_invoicing_type if recurring_rule_type is monthlylastday for the monthlylastday case, pre-paid is logicly impossible, if monthlylastday is set, we consider only post-paid case [IMP] - Improve unit tests [IMP] - store last_date_invoiced on contract_line Improve CRITERIA_ALLOWED_DICT [IMP] - code improvement [IMP] - Use last_date_invoiced to set marker in invoice description [IMP] - add migration script to init last_day_invoiced and some other improvement [FIX] - a contract line suspended should start a day after the suspension end [IMP] - don't allow to unlink uncnaceled contrac line [FIX] - check date_start before onchange [FIX] - compute recurring_next_date for contract [IMP] - get contract line default data onchange product_id [IMP] - Add responsible to contract form view [FIX] - contract recurring_next_date ignore canceled lines [FIX] - fix _get_invoiced_period if recurring_next_date manually updated [IMP] - archive contract_line on contract archive
This commit is contained in:
428
contract/models/contract_line_constraints.py
Normal file
428
contract/models/contract_line_constraints.py
Normal file
@@ -0,0 +1,428 @@
|
||||
# Copyright 2018 ACSONE SA/NV.
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import itertools
|
||||
from collections import namedtuple
|
||||
from odoo.fields import Date
|
||||
|
||||
Criteria = namedtuple(
|
||||
'Criteria',
|
||||
[
|
||||
'when', # Contract line relatively to today (BEFORE, IN, AFTER)
|
||||
'has_date_end', # Is date_end set on contract line (bool)
|
||||
'has_last_date_invoiced', # Is last_date_invoiced set on contract line
|
||||
'is_auto_renew', # Is is_auto_renew set on contract line (bool)
|
||||
'has_successor', # Is contract line has_successor (bool)
|
||||
'predecessor_has_successor',
|
||||
# Is contract line predecessor has successor (bool)
|
||||
# In almost of the cases
|
||||
# contract_line.predecessor.successor == contract_line
|
||||
# But at cancel action,
|
||||
# contract_line.predecessor.successor == False
|
||||
# This is to permit plan_successor on predecessor
|
||||
# If contract_line.predecessor.successor != False
|
||||
# and contract_line is canceled, we don't allow uncancel
|
||||
# else we re-link contract_line and its predecessor
|
||||
'canceled', # Is contract line canceled (bool)
|
||||
],
|
||||
)
|
||||
Allowed = namedtuple(
|
||||
'Allowed',
|
||||
['plan_successor', 'stop_plan_successor', 'stop', 'cancel', 'uncancel'],
|
||||
)
|
||||
|
||||
|
||||
def _expand_none(criteria):
|
||||
variations = []
|
||||
for attribute, value in criteria._asdict().items():
|
||||
if value is None:
|
||||
if attribute == 'when':
|
||||
variations.append(['BEFORE', 'IN', 'AFTER'])
|
||||
else:
|
||||
variations.append([True, False])
|
||||
else:
|
||||
variations.append([value])
|
||||
return itertools.product(*variations)
|
||||
|
||||
|
||||
def _add(matrix, criteria, allowed):
|
||||
""" Expand None values to True/False combination """
|
||||
for c in _expand_none(criteria):
|
||||
matrix[c] = allowed
|
||||
|
||||
|
||||
CRITERIA_ALLOWED_DICT = {
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=True,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=False,
|
||||
has_successor=True,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=True,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=False,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=True,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=False,
|
||||
has_successor=True,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=True,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=False,
|
||||
has_last_date_invoiced=False,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=True,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=True,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=False,
|
||||
has_successor=True,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=True,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='BEFORE',
|
||||
has_date_end=False,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=True,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=False,
|
||||
has_successor=True,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=True,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='IN',
|
||||
has_date_end=False,
|
||||
has_last_date_invoiced=True,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=True,
|
||||
stop=True,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='AFTER',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=None,
|
||||
is_auto_renew=True,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=False,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='AFTER',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=None,
|
||||
is_auto_renew=False,
|
||||
has_successor=True,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=False,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when='AFTER',
|
||||
has_date_end=True,
|
||||
has_last_date_invoiced=None,
|
||||
is_auto_renew=False,
|
||||
has_successor=False,
|
||||
predecessor_has_successor=None,
|
||||
canceled=False,
|
||||
): Allowed(
|
||||
plan_successor=True,
|
||||
stop_plan_successor=False,
|
||||
stop=False,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
Criteria(
|
||||
when=None,
|
||||
has_date_end=None,
|
||||
has_last_date_invoiced=None,
|
||||
is_auto_renew=None,
|
||||
has_successor=None,
|
||||
predecessor_has_successor=False,
|
||||
canceled=True,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=False,
|
||||
cancel=False,
|
||||
uncancel=True,
|
||||
),
|
||||
Criteria(
|
||||
when=None,
|
||||
has_date_end=None,
|
||||
has_last_date_invoiced=None,
|
||||
is_auto_renew=None,
|
||||
has_successor=None,
|
||||
predecessor_has_successor=True,
|
||||
canceled=True,
|
||||
): Allowed(
|
||||
plan_successor=False,
|
||||
stop_plan_successor=False,
|
||||
stop=False,
|
||||
cancel=False,
|
||||
uncancel=False,
|
||||
),
|
||||
}
|
||||
criteria_allowed_dict = {}
|
||||
|
||||
for c in CRITERIA_ALLOWED_DICT:
|
||||
_add(criteria_allowed_dict, c, CRITERIA_ALLOWED_DICT[c])
|
||||
|
||||
|
||||
def compute_when(date_start, date_end):
|
||||
today = Date.today()
|
||||
if today < date_start:
|
||||
return 'BEFORE'
|
||||
if date_end and today > date_end:
|
||||
return 'AFTER'
|
||||
return 'IN'
|
||||
|
||||
|
||||
def compute_criteria(
|
||||
date_start,
|
||||
date_end,
|
||||
has_last_date_invoiced,
|
||||
is_auto_renew,
|
||||
successor_contract_line_id,
|
||||
predecessor_contract_line_id,
|
||||
is_canceled,
|
||||
):
|
||||
return Criteria(
|
||||
when=compute_when(date_start, date_end),
|
||||
has_date_end=bool(date_end),
|
||||
has_last_date_invoiced=bool(has_last_date_invoiced),
|
||||
is_auto_renew=is_auto_renew,
|
||||
has_successor=bool(successor_contract_line_id),
|
||||
predecessor_has_successor=bool(
|
||||
predecessor_contract_line_id.successor_contract_line_id
|
||||
),
|
||||
canceled=is_canceled,
|
||||
)
|
||||
|
||||
|
||||
def get_allowed(
|
||||
date_start,
|
||||
date_end,
|
||||
has_last_date_invoiced,
|
||||
is_auto_renew,
|
||||
successor_contract_line_id,
|
||||
predecessor_contract_line_id,
|
||||
is_canceled,
|
||||
):
|
||||
criteria = compute_criteria(
|
||||
date_start,
|
||||
date_end,
|
||||
has_last_date_invoiced,
|
||||
is_auto_renew,
|
||||
successor_contract_line_id,
|
||||
predecessor_contract_line_id,
|
||||
is_canceled,
|
||||
)
|
||||
if criteria in criteria_allowed_dict:
|
||||
return criteria_allowed_dict[criteria]
|
||||
return False
|
||||
Reference in New Issue
Block a user