Repository
OCA/contract · module folder · Try on Runboat
Module version
1.0.1
Category
Uncategorized
Folder size
0.29 MB
License
AGPL-3
Application
No
Auto-installable
No
Website
https://github.com/OCA/contract
Last tracking update
2026-08-07 08:43:01
Authors
ACSONE SA/NV, Odoo Community Association (OCA)
Maintainers
ACSONE SA/NV, Odoo Community Association (OCA)
Committers
Denis Roussel, Weblate, OCA-git-bot, oca-ci, Angel Rivas
Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
contract_forecast, contract_price_revision, contract_queue_job, contract_refund_on_stop, contract_termination
Description
**Contract Line Successor** extends `contract.line` model to support advanced
contract lifecycle management, including suspension, successor planning,
cancellation, and renewal.  
It provides a flexible and robust framework for managing complex contract
line scenarios in a clean and structured way.

## Features

- **Successor and Predecessor Management**
  - Link contract lines with successor and predecessor lines.
  - Plan successors automatically or manually after a stop or suspension.

- **Contract Line Lifecycle States**
  - Manage contract lines with the following computed states:
    - `Upcoming`
    - `In-Progress`
    - `To Renew`
    - `Upcoming Close`
    - `Closed`
    - `Canceled`

- **Lifecycle Operations**
  - Stop a contract line.
  - Plan a successor for a contract line.
  - Stop and plan a successor in one operation (useful for suspensions).
  - Cancel and un-cancel contract lines.
  - Renew contract lines automatically (new line or extension).

- **Auto-Renewal Handling**
  - Auto-renewal based on company settings (extend existing line or create a new one).
  - Cron job to automate renewal of eligible contract lines.

- **Data Integrity and Validation**
  - Prevent invalid successor or predecessor configurations.
  - Validate state transitions and date overlaps.
  - Ensure clean renewal and cancellation workflows.

- **Audit Trail**
  - Automatic posting of chatter messages for lifecycle events like stops, 
    renewals, suspensions, cancellations, etc.

Code Analysis

Views touched (12)
XML IDNameModelTypeStatus
contract_contract_form_view contract.contract form Inherits contract.contract_contract_form_view
contract_line_form_view contract.line form Inherits contract.contract_line_form_view
contract_line_report_tree_view contract.line tree Inherits contract.contract_line_report_tree_view
contract_line_search_view contract.line search Inherits contract.contract_line_search_view
contract_line_tree_view contract.line tree Inherits contract.contract_line_tree_view
contract_line_wizard_plan_successor_form_view contract.line.plan_successor.wizard.form (in contract) contract.line.wizard form New
contract_line_wizard_stop_form_view contract.line.stop.wizard.form (in contract) contract.line.wizard form New
contract_line_wizard_stop_plan_successor_form_view contract.line.stop_plan_successor.wizard.form (in contract) contract.line.wizard form New
contract_line_wizard_uncancel_form_view contract.line.stop_plan_successor.wizard.form (in contract) contract.line.wizard form New
contract_template_form_view contract.template form Inherits contract.contract_template_form_view
contract_template_line_form_view contract.template.line form Inherits contract.contract_template_line_form_view
res_config_settings_form_view res.config.settings form Inherits contract.res_config_settings_form_view
HTTP endpoints (0)

No HTTP endpoints found for this module.

Models touched (7)

New fields (1)
  • line_recurrence Boolean
    default=True
Public methods (0)

No public methods.

New fields (10)
  • is_cancel_allowed Boolean
    compute='_compute_allowed' string='Cancel allowed?'
  • is_plan_successor_allowed Boolean
    compute='_compute_allowed' string='Plan successor allowed?'
  • is_stop_allowed Boolean
    compute='_compute_allowed' string='Stop allowed?'
  • is_stop_plan_successor_allowed Boolean
    compute='_compute_allowed' string='Stop/Plan successor allowed?'
  • is_un_cancel_allowed Boolean
    compute='_compute_allowed' string='Un-Cancel allowed?'
  • manual_renew_needed Boolean
    default=False help='This flag is used to make a difference between a definitive stopand temporary one for which a user is not able to plan asuccessor in advance'
  • predecessor_contract_line_id Many2one → contract.line
    comodel_name='contract.line' copy=False help='Contract Line origin of this one.' index=True readonly=True required=False string='Predecessor Contract Line'
  • state Selection
    compute='_compute_state' search='_search_state' selection=[('upcoming', 'Upcoming'), ('in-progress', 'In-progress'), ('to-renew', 'To renew'), ('upcoming-close', 'Upcoming Close'), ('closed', 'Closed'), ('canceled', 'Canceled')]
  • successor_contract_line_id Many2one → contract.line
    comodel_name='contract.line' copy=False help='In case of restart after suspension, this field contain the new contract line created.' index=True readonly=True required=False string='Successor Contract Line'
  • termination_notice_date Date
    compute='_compute_termination_notice_date' copy=False store=True
Public methods (12)
  • action_plan_successor(self)
  • action_stop(self)
  • action_stop_plan_successor(self)
  • action_uncancel(self)
  • cancel(self)
  • cron_renew_contract_line(self)
    @api.model
  • plan_successor(self, date_start, date_end, is_auto_renew, recurring_next_date=False, post_message=True)
    Create a copy of a contract line in a new interval :param date_start: date_start for the successor_contract_line :param date_end: date_end for the successor_contract_line :param is_auto_renew: is_auto_renew option for successor_contract_line :param recurring_next_date: recurring_next_date for the successor_contract_line :return: successor_contract_line
  • renew(self)
  • stop(self, date_end, manual_renew_needed=False, post_message=True)
    Put date_end on contract line We don't consider contract lines that end's before the new end date :param date_end: new date end for contract line :return: True
  • stop_plan_successor(self, date_start, date_end, is_auto_renew)
    Stop a contract line for a defined period and start it later Cases to consider: * contract line end's before the suspension period: -> apply stop * 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: date_end + (contract_line.date_end - suspension.date_start) * 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: date_end + (suspension.date_end - suspension.date_start) * contract line start and end's in the suspension period -> apply delay - delay: suspension.date_end - contract_line.date_start * contract line start in the suspension period and end after it -> apply delay - delay: suspension.date_end - contract_line.date_start * contract line start and end after the suspension period -> apply delay - delay: suspension.date_end - suspension.start_date :param date_start: suspension start date :param date_end: suspension end date :param is_auto_renew: is the new line is set to auto_renew :return: created contract line
  • uncancel(self, recurring_next_date)
  • unlink(self)
    stop unlink uncnacled lines

New fields (6)
  • contract_line_id Many2one → contract.line
    comodel_name='contract.line' index=True ondelete='cascade' required=True string='Contract Line'
  • date_end Date
  • date_start Date
  • is_auto_renew Boolean
    default=False
  • manual_renew_needed Boolean
    default=False help='This flag is used to make a difference between a definitive stopand temporary one for which a user is not able to plan asuccessor in advance'
  • recurring_next_date Date
    string='Next Invoice Date'
Public methods (4)
  • plan_successor(self)
  • stop(self)
  • stop_plan_successor(self)
  • uncancel(self)

New fields (1)
  • is_auto_renew Boolean
    compute='_compute_is_auto_renew'
Public methods (0)

No public methods.

New fields (5)
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Weeks/Months/Years)' string='Renew Every'
  • auto_renew_rule_type Selection
    default='yearly' help='Specify interval for automatic renewal.' string='Renewal type' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('yearly', 'Year(s)')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • termination_notice_interval Integer
    default=1 string='Termination Notice Before'
  • termination_notice_rule_type Selection
    default='monthly' string='Termination Notice type' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)')]
Public methods (0)

No public methods.

New fields (1)
  • create_new_line_at_contract_line_renew Boolean
    help='If checked, a new line will be generated at contract line renew and linked to the original one as successor. The default behavior is to extend the end date of the contract by a new subscription period'
Public methods (0)

No public methods.

New fields (1)
  • create_new_line_at_contract_line_renew Boolean
    help='If checked, a new line will be generated at contract line renew and linked to the original one as successor. The default behavior is to extend the end date of the contract by a new subscription period' readonly=False related='company_id.create_new_line_at_contract_line_renew' string='Create New Line At Contract Line Renew'
Public methods (0)

No public methods.

Status
Open migration PR — not merged yet for this version
CI status
green — ready to merge
Open since
234 days ago
Last activity
16 days ago
Repository
OCA/contract
Pull request
[19.0][MIG] contract_line_successor (#1370)