# 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=True, 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=True, 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