Recurring - Contracts Management

contract
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/19.0/contract
VERSION
VERSION 1.0.2
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSWeblate, OCA-git-bot, oca-ci, bosd, eduezerouali-tecnativa, Bhavesh Heliconia, Pilar Vargas
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:40:47
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - onboarding
    - product
    - mail
    - bus
    - web_tour
    - html_editor
    - uom
    - analytic
    - portal
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module enables contracts management with recurring invoicing
functions. Also you can print and send by email contract report.

It works for customer contract and supplier contracts.

Contracts are shown in portal.

Code Analysis

Views touched (31)
XML IDNameModelTypeStatus
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_tree_view contract.contract list view (in contract) contract.contract list New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line xpath Inherits contract_template_line_form_view
contract_line_report_tree_view contract.line report tree view (in contract) contract.line list New
contract_line_search_view contract.line search view (in contract) contract.line search New
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier list view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line list view (in contract) contract.line list New
contract_line_view_pivot contract.line.view.pivot contract.line pivot New
contract_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag list New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form New
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template list view (in contract) contract.template list New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_layout
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Show Contracts ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
report_contract_template report_contract_template ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (10)

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (21)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' compute='_compute_group_id' ondelete='restrict' readonly=False store=True string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' domain="['|',('id', 'parent_of', partner_id), ('id', 'child_of', partner_id)]" ondelete='restrict' string='Invoicing contact'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • name Char
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (8)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    Button action This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (8)
  • active Boolean
    readonly=True related='contract_id.active' store=True string='Active'
  • contract_id Many2one → contract.contract
    bypass_search_access=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one
    related='contract_id.currency_id' store=True
  • monthly_recurring Monetary
    aggregator='sum' compute='_compute_monthly_recurring' currency_field='currency_id' store=True
  • partner_id Many2one
    store=True
  • product_id Many2one
    index=True
  • sequence Integer
Public methods (1)
  • get_view(self, view_id=None, view_type='form', **options)
    @api.model

New fields (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True
  • description Text
    required=True
  • sent Boolean
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (10)
  • date_end Date
    help='Optional contract termination date (limits recurrence)' index=True
  • date_start Date
    default=<expr> help='Contract activation date (first recurrence starts here)' index=True
  • last_date_invoiced Date
    copy=False readonly=True
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
    Compute the date of the next invoice based on all parameters.
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period based on rule type.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (9)
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=True string='Company'
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • generation_type Selection
    default=<expr> help='Defines what document is automatically generated by the cron.' selection=[('invoice', 'Invoice')]
  • journal_id Many2one → account.journal
    check_company=True comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Check this if you want to control recurrence at the line level instead of for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (23)
  • allowed_uom_ids Many2many → uom.uom
    comodel_name='uom.uom' compute='_compute_allowed_uom_ids'
  • automatic_price Boolean
    compute='_compute_automatic_price' help='If checked, the price will be taken from the pricelist. Otherwise, it must be set manually.' readonly=False store=True string='Auto-price?'
  • company_id Many2one
    readonly=True related='contract_id.company_id' store=True
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
  • currency_id Many2one → res.currency
    args: 'res.currency'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount to apply on generated invoices. Must be ≤ 100.' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purposes.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note' string='Recurring Note'
  • name Text
    compute='_compute_name' readonly=False required=True store=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='When to invoice this note line relative to others.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • partner_id Many2one → res.partner
    comodel_name='res.partner' related='contract_id.partner_id'
  • price_subtotal Monetary
    compute='_compute_price_subtotal' string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    domain=[('active', '=', True)] string='Product' args: 'product.product'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Defines line ordering in the contract.'
  • specific_price Float
  • uom_id Many2one → uom.uom
    comodel_name='uom.uom' compute='_compute_uom_id' domain="[('id', 'in', allowed_uom_ids)]" readonly=False store=True string='Unit of Measure'
Public methods (0)

No public methods.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/18.0/contract
VERSION
VERSION 2.4.1
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSPedro M. Baeza, Jacques-Etienne Baudoux, Denis Roussel, Enric Tobella, Carlos Lopez, sbejaoui, Miquel Raïch, Víctor Martínez, Florian da Costa, Weblate, OCA-git-bot, Quentin Groulard, oca-ci, Benoit Aimont, Tobias Zehntner, hda, Christopher Rogos, Marie Lejeune, Angel Rivas, Ricard Calvo, cristina-hidalgo-tecnativa
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:30:10
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - onboarding
    - product
    - mail
    - bus
    - web_tour
    - html_editor
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module enables contracts management with recurring invoicing
functions. Also you can print and send by email contract report.

It works for customer contract and supplier contracts.

Contracts are shown in portal.

Code Analysis

Views touched (31)
XML IDNameModelTypeStatus
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_tree_view contract.contract list view (in contract) contract.contract list New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line xpath Inherits contract_template_line_form_view
contract_line_report_tree_view contract.line report tree view (in contract) contract.line list New
contract_line_search_view contract.line search view (in contract) contract.line search New
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier list view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line list view (in contract) contract.line list New
contract_line_view_pivot contract.line.view.pivot contract.line pivot New
contract_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag list New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form New
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template list view (in contract) contract.template list New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_layout
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Show Contracts ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
report_contract_template report_contract_template ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (10)

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (21)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' compute='_compute_group_id' ondelete='restrict' readonly=False store=True string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' domain="['|',('id', 'parent_of', partner_id), ('id', 'child_of', partner_id)]" ondelete='restrict' string='Invoicing contact'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • name Char
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (8)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    Button action This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (8)
  • active Boolean
    readonly=True related='contract_id.active' store=True string='Active'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one
    related='contract_id.currency_id'
  • monthly_recurring Monetary
    compute='_compute_monthly_recurring' currency_field='currency_id' store=True
  • partner_id Many2one
    store=True
  • product_id Many2one
    index=True
  • sequence Integer
Public methods (1)
  • get_view(self, view_id=None, view_type='form', **options)
    @api.model

New fields (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True
  • description Text
    required=True
  • sent Boolean
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (10)
  • date_end Date
    help='Optional contract termination date (limits recurrence)' index=True
  • date_start Date
    default=<expr> help='Contract activation date (first recurrence starts here)' index=True
  • last_date_invoiced Date
    copy=False readonly=True
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
    Compute the date of the next invoice based on all parameters.
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period based on rule type.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (9)
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=True string='Company'
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • generation_type Selection
    default=<expr> help='Defines what document is automatically generated by the cron.' selection=[('invoice', 'Invoice')]
  • journal_id Many2one → account.journal
    check_company=True comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Check this if you want to control recurrence at the line level instead of for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (23)
  • automatic_price Boolean
    compute='_compute_automatic_price' help='If checked, the price will be taken from the pricelist. Otherwise, it must be set manually.' readonly=False store=True string='Auto-price?'
  • company_id Many2one
    readonly=True related='contract_id.company_id' store=True
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
  • currency_id Many2one → res.currency
    args: 'res.currency'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount to apply on generated invoices. Must be ≤ 100.' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purposes.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note' string='Recurring Note'
  • name Text
    compute='_compute_name' readonly=False required=True store=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='When to invoice this note line relative to others.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • partner_id Many2one → res.partner
    comodel_name='res.partner' related='contract_id.partner_id'
  • price_subtotal Monetary
    compute='_compute_price_subtotal' string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • product_uom_category_id Many2one → uom.category
    comodel_name='uom.category' readonly=True related='product_id.uom_id.category_id'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Defines line ordering in the contract.'
  • specific_price Float
  • uom_id Many2one → uom.uom
    comodel_name='uom.uom' compute='_compute_uom_id' domain="[('category_id', '=', product_uom_category_id)]" readonly=False store=True string='Unit of Measure'
Public methods (0)

No public methods.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/17.0/contract
VERSION
VERSION 1.5.4
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSPedro M. Baeza, Enric Tobella, Carlos Lopez, sergio-teruel, Víctor Martínez, Florian da Costa, Weblate, OCA-git-bot, oca-ci, pilarvargas-tecnativa, Carolina Fernandez, Adasat Torres de León, Christopher Rogos, Antoni Marroig Campomar, eduezerouali-tecnativa, Ariel Barreiros, Alicia Garzo Moreno
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:20:04
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - onboarding
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module enables contracts management with recurring invoicing
functions. Also you can print and send by email contract report.

It works for customer contract and supplier contracts.

Contracts are shown in portal.

Code Analysis

Views touched (39)
XML IDNameModelTypeStatus
contract_abstract_contract_line_form_view contract.abstract.contract.line form view (in contract) contract.abstract.contract.line form New
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_terminate_form_view contract.contract.terminate form New
contract_contract_tree_view contract.contract tree view (in contract) contract.contract tree New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line form view (in contract) contract.line header Inherits contract_abstract_contract_line_form_view
contract_line_report_tree_view contract.line report tree view (in contract) contract.line tree New
contract_line_search_view contract.line search view (in contract) contract.line search New
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier tree view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line tree view (in contract) contract.line tree New
contract_line_view_pivot contract.line.view.pivot contract.line pivot New
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_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag tree New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form view (in contract) contract.template.line form Inherits contract_abstract_contract_line_form_view
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template tree view (in contract) contract.template tree New
contract_terminate_reason_form_view contract.terminate.reason form New
contract_terminate_reason_tree_view contract.terminate.reason tree New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_layout
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Show Contracts ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
report_contract_template report_contract_template ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (19)

New fields (1)
  • old_contract_id Many2one → contract.contract
    args: 'contract.contract'
Public methods (0)

No public methods.

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (8)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • generation_type Selection
    default=<expr> help='Choose the document that will be automatically generated by cron.' selection=[('invoice', 'Invoice')]
  • journal_id Many2one → account.journal
    check_company=True comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Mark this check if you want to control recurrrence at line level instead of all together for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (29)
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Week/Month/Year)' 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)')]
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • company_id Many2one
    related='contract_id.company_id' store=True
  • contract_id Many2one → contract.abstract.contract
    comodel_name='contract.abstract.contract' ondelete='cascade' required=True string='Contract'
  • currency_id Many2one → res.currency
    args: 'res.currency'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purpose.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note'
  • last_date_invoiced Date
  • name Text
    required=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='Defines when the Note is invoiced:\n- With previous line: If the previous line can be invoiced.\n- With next line: If the next line can be invoiced.\n- Custom: Depending on the recurrence to be define.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • partner_id Many2one → res.partner
    comodel_name='res.partner' related='contract_id.partner_id'
  • price_subtotal Monetary
    compute='_compute_price_subtotal' string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • product_uom_category_id Many2one → uom.category
    comodel_name='uom.category' related='product_id.uom_id.category_id'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts'
  • specific_price Float
  • 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)')]
  • uom_id Many2one → uom.uom
    comodel_name='uom.uom' domain="[('category_id', '=', product_uom_category_id)]" string='Unit of Measure'
Public methods (0)

No public methods.

New fields (24)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' compute='_compute_group_id' ondelete='restrict' readonly=False store=True string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' domain="['|',('id', 'parent_of', partner_id), ('id', 'child_of', partner_id)]" ondelete='restrict' string='Invoicing contact'
  • is_terminated Boolean
    copy=False readonly=True string='Terminated'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • terminate_comment Text
    copy=False readonly=True string='Termination Comment' tracking=True
  • terminate_date Date
    copy=False readonly=True string='Termination Date' tracking=True
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' copy=False ondelete='restrict' readonly=True string='Termination Reason' tracking=True
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (10)
  • action_cancel_contract_termination(self)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • action_terminate_contract(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (6)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' ondelete='cascade' required=True string='Contract'
  • terminate_comment Text
    string='Termination Comment'
  • terminate_comment_required Boolean
    related='terminate_reason_id.terminate_comment_required'
  • terminate_date Date
    required=True string='Termination Date'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' ondelete='cascade' required=True string='Termination Reason'
  • terminate_with_last_date_invoiced Boolean
    help='Terminate the contract lines with the last invoiced date if they cannot be terminated with the date reported in the wizard.' string='Terminate lines with last date invoiced'
Public methods (1)
  • terminate_contract(self)

New fields (18)
  • active Boolean
    readonly=True related='contract_id.active' store=True string='Active'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one
    related='contract_id.currency_id'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • date_start Date
    required=True
  • 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'
  • partner_id Many2one
    store=True
  • 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'
  • sequence Integer
  • 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 (13)
  • action_plan_successor(self)
  • action_stop(self)
  • action_stop_plan_successor(self)
  • action_uncancel(self)
  • cancel(self)
  • cron_renew_contract_line(self)
    @api.model
  • get_view(self, view_id=None, view_type='form', **options)
    @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 (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True
  • description Text
    required=True
  • sent Boolean
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (6)
  • date_start Date
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (6)
  • date_end Date
    index=True
  • date_start Date
    default=<expr>
  • last_date_invoiced Date
    copy=False readonly=True
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period. The next period normally depends on recurrence options only. It is however possible to provide it a next invoice date, in which case this method can adjust the next period based on that too. In that scenario it required the invoicing type and offset arguments.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period. When added to the first day of the period, it gives the first day of the next period.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (1)
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
Public methods (0)

No public methods.

New fields (2)
  • name Char
    required=True
  • terminate_comment_required Boolean
    default=True string='Require a termination comment'
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.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/16.0/contract
VERSION
VERSION 2.15.0
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Raphaël Valyi, Pedro M. Baeza, Enric Tobella, Jose Suniaga [Vauxoo], Víctor Martínez, Florian da Costa, Weblate, OCA-git-bot, oca-ci, fkantelberg, Eduardo De Miguel, Carolina Fernandez, Christopher Rogos, Antoni Marroig Campomar, Ruben Ortlam, Ariel Barreiros, Alicia Garzo Moreno, cristina.hidalgo
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:53:43
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (38)
XML IDNameModelTypeStatus
contract_abstract_contract_line_form_view contract.abstract.contract.line form view (in contract) contract.abstract.contract.line form New
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_terminate_form_view contract.contract.terminate form New
contract_contract_tree_view contract.contract tree view (in contract) contract.contract tree New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line form view (in contract) contract.line header Inherits contract_abstract_contract_line_form_view
contract_line_report_tree_view contract.line report tree view (in contract) contract.line tree New
contract_line_search_view contract.line search view (in contract) contract.line search New
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier tree view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line tree view (in contract) contract.line tree New
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_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag tree New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form view (in contract) contract.template.line form Inherits contract_abstract_contract_line_form_view
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template tree view (in contract) contract.template tree New
contract_terminate_reason_form_view contract.terminate.reason form New
contract_terminate_reason_tree_view contract.terminate.reason tree New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_layout
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Show Contracts ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
report_contract_template report_contract_template ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (19)

New fields (1)
  • old_contract_id Many2one → contract.contract
    args: 'contract.contract'
Public methods (0)

No public methods.

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (8)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • generation_type Selection
    default=<expr> help='Choose the document that will be automatically generated by cron.' selection=[('invoice', 'Invoice')]
  • journal_id Many2one → account.journal
    check_company=True comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Mark this check if you want to control recurrrence at line level instead of all together for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (29)
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Week/Month/Year)' 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)')]
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • company_id Many2one
    related='contract_id.company_id' store=True
  • contract_id Many2one → contract.abstract.contract
    comodel_name='contract.abstract.contract' ondelete='cascade' required=True string='Contract'
  • currency_id Many2one → res.currency
    args: 'res.currency'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purpose.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note'
  • last_date_invoiced Date
  • name Text
    required=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='Defines when the Note is invoiced:\n- With previous line: If the previous line can be invoiced.\n- With next line: If the next line can be invoiced.\n- Custom: Depending on the recurrence to be define.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • partner_id Many2one → res.partner
    comodel_name='res.partner' related='contract_id.partner_id'
  • price_subtotal Monetary
    compute='_compute_price_subtotal' string='Sub Total'
  • price_unit Monetary
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • product_uom_category_id Many2one → uom.category
    comodel_name='uom.category' related='product_id.uom_id.category_id'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts'
  • specific_price Monetary
  • 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)')]
  • uom_id Many2one → uom.uom
    comodel_name='uom.uom' domain="[('category_id', '=', product_uom_category_id)]" string='Unit of Measure'
Public methods (0)

No public methods.

New fields (24)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' ondelete='restrict' string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' domain="['|',('id', 'parent_of', partner_id), ('id', 'child_of', partner_id)]" ondelete='restrict' string='Invoicing contact'
  • is_terminated Boolean
    copy=False readonly=True string='Terminated'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • terminate_comment Text
    copy=False readonly=True string='Termination Comment' tracking=True
  • terminate_date Date
    copy=False readonly=True string='Termination Date' tracking=True
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' copy=False ondelete='restrict' readonly=True string='Termination Reason' tracking=True
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (10)
  • action_cancel_contract_termination(self)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • action_terminate_contract(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (5)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' ondelete='cascade' required=True string='Contract'
  • terminate_comment Text
    string='Termination Comment'
  • terminate_comment_required Boolean
    related='terminate_reason_id.terminate_comment_required'
  • terminate_date Date
    required=True string='Termination Date'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' ondelete='cascade' required=True string='Termination Reason'
Public methods (1)
  • terminate_contract(self)

New fields (19)
  • active Boolean
    readonly=True related='contract_id.active' store=True string='Active'
  • company_id Many2one
    related='contract_id.company_id'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one
    related='contract_id.currency_id'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • date_start Date
    required=True
  • 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'
  • monthly_recurring Monetary
    compute='_compute_monthly_recurring' currency_field='currency_id' store=True
  • 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'
  • sequence Integer
  • 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 (13)
  • action_plan_successor(self)
  • action_stop(self)
  • action_stop_plan_successor(self)
  • action_uncancel(self)
  • cancel(self)
  • cron_renew_contract_line(self)
    @api.model
  • get_view(self, view_id=None, view_type='form', **options)
    @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 (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True
  • description Text
    required=True
  • sent Boolean
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (6)
  • date_start Date
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (6)
  • date_end Date
    index=True
  • date_start Date
    default=<expr>
  • last_date_invoiced Date
    copy=False readonly=True
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period. The next period normally depends on recurrence options only. It is however possible to provide it a next invoice date, in which case this method can adjust the next period based on that too. In that scenario it required the invoicing type and offset arguments.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period. When added to the first day of the period, it gives the first day of the next period.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (1)
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
Public methods (0)

No public methods.

New fields (2)
  • name Char
    required=True
  • terminate_comment_required Boolean
    default=True string='Require a termination comment'
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.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/15.0/contract
VERSION
VERSION 1.13.0
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSPedro M. Baeza, Denis Roussel, OCA Transbot, Miquel Raïch, Víctor Martínez, Weblate, OCA-git-bot, oca-ci, fkantelberg, Carlos Roca, chandni299, Carolina Fernandez, Jean-Charles Drubay, Joan Mateu Jordi, oca-git-bot, Christopher Rogos, Antoni Marroig Campomar, extrememicro, ozoromo
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:46:32
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (39)
XML IDNameModelTypeStatus
contract_abstract_contract_line_form_view contract.abstract.contract.line form view (in contract) contract.abstract.contract.line form New
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_terminate_form_view contract.contract.terminate form New
contract_contract_tree_view contract.contract tree view (in contract) contract.contract tree New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line form view (in contract) contract.line header Inherits contract_abstract_contract_line_form_view
contract_line_report_tree_view contract.line report tree view (in contract) contract.line tree New
contract_line_search_view contract.line search view (in contract) contract.line search New
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier tree view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line tree view (in contract) contract.line tree New
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_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag tree New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form view (in contract) contract.template.line form Inherits contract_abstract_contract_line_form_view
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template tree view (in contract) contract.template tree New
contract_terminate_reason_form_view contract.terminate.reason form New
contract_terminate_reason_tree_view contract.terminate.reason tree New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_paynow
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Portal My Home : Contract entries ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
report_contract_template report_contract_template ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_account_move_contract_helper_form account.move form Inherits account.view_move_form
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (19)

New fields (1)
  • old_contract_id Many2one → contract.contract
    args: 'contract.contract'
Public methods (0)

No public methods.

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (8)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • generation_type Selection
    default=<expr> help='Choose the document that will be automatically generated by cron.' selection=<expr>
  • journal_id Many2one → account.journal
    comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type),('company_id', '=', company_id)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Mark this check if you want to control recurrrence at line level instead of all together for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (28)
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Week/Month/Year)' 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)')]
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • company_id Many2one
    related='contract_id.company_id' store=True
  • contract_id Many2one → contract.abstract.contract
    comodel_name='contract.abstract.contract' ondelete='cascade' required=True string='Contract'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purpose.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note'
  • last_date_invoiced Date
  • name Text
    required=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='Defines when the Note is invoiced:\n- With previous line: If the previous line can be invoiced.\n- With next line: If the next line can be invoiced.\n- Custom: Depending on the recurrence to be define.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • partner_id Many2one → res.partner
    comodel_name='res.partner' related='contract_id.partner_id'
  • price_subtotal Float
    compute='_compute_price_subtotal' digits='Account' string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • product_uom_category_id Many2one → uom.category
    comodel_name='uom.category' related='product_id.uom_id.category_id'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts'
  • specific_price Float
  • 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)')]
  • uom_id Many2one → uom.uom
    comodel_name='uom.uom' domain="[('category_id', '=', product_uom_category_id)]" string='Unit of Measure'
Public methods (0)

No public methods.

New fields (24)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' context={'active_test': False} copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' ondelete='restrict' string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' domain="['|',('id', 'parent_of', partner_id), ('id', 'child_of', partner_id)]" ondelete='restrict' string='Invoicing contact'
  • is_terminated Boolean
    copy=False readonly=True string='Terminated'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • terminate_comment Text
    copy=False readonly=True string='Termination Comment' tracking=True
  • terminate_date Date
    copy=False readonly=True string='Termination Date' tracking=True
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' copy=False ondelete='restrict' readonly=True string='Termination Reason' tracking=True
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (10)
  • action_cancel_contract_termination(self)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • action_terminate_contract(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (5)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' ondelete='cascade' required=True string='Contract'
  • terminate_comment Text
    string='Termination Comment'
  • terminate_comment_required Boolean
    related='terminate_reason_id.terminate_comment_required'
  • terminate_date Date
    required=True string='Termination Date'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' ondelete='cascade' required=True string='Termination Reason'
Public methods (1)
  • terminate_contract(self)

New fields (18)
  • active Boolean
    readonly=True related='contract_id.active' store=True string='Active'
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' string='Analytic account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • date_start Date
    required=True
  • 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'
  • sequence Integer
  • 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 (13)
  • action_plan_successor(self)
  • action_stop(self)
  • action_stop_plan_successor(self)
  • action_uncancel(self)
  • cancel(self)
  • cron_renew_contract_line(self)
    @api.model
  • fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False)
    @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 (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True
  • description Text
    required=True
  • sent Boolean
    default=False
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (6)
  • date_start Date
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (6)
  • date_end Date
    index=True
  • date_start Date
    default=<expr>
  • last_date_invoiced Date
    copy=False readonly=True
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period. The next period normally depends on recurrence options only. It is however possible to provide it a next invoice date, in which case this method can adjust the next period based on that too. In that scenario it required the invoicing type and offset arguments.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period. When added to the first day of the period, it gives the first day of the next period.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (1)
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
Public methods (0)

No public methods.

New fields (2)
  • name Char
    required=True
  • terminate_comment_required Boolean
    default=True string='Require a termination comment'
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.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/14.0/contract
VERSION
VERSION 2.14.1
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSAlexis de Lattre, Pedro M. Baeza, Denis Roussel, OCA Transbot, Miquel Raïch, Víctor Martínez, Ernesto Tejeda, João Marques, niyasraphy, Damien Crier, oca-travis, Weblate, OCA-git-bot, Francisco Ivan Anton Prieto, Eric Antones, Michael Tietz, oca-ci, mariadforgeflow, Eduardo De Miguel, Marcel Savegnago, chandni299, stenex, Ilyas, Jean-Charles Drubay, oca-git-bot, sistecem, Maximilien TANTIN, Christopher Rogos
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:40:55
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (41)
XML IDNameModelTypeStatus
assets_backend contract assets ir.ui.view qweb Inherits web.assets_backend
assets_frontend contract assets ir.ui.view qweb Inherits web.assets_frontend
assets_tests assets_tests ir.ui.view qweb Inherits web.assets_tests
contract_abstract_contract_line_form_view contract.abstract.contract.line form view (in contract) contract.abstract.contract.line form New
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_terminate_form_view contract.contract.terminate form New
contract_contract_tree_view contract.contract tree view (in contract) contract.contract tree New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line form view (in contract) contract.line header Inherits contract_abstract_contract_line_form_view
contract_line_report_tree_view contract.line report tree view (in contract) contract.line tree New
contract_line_search_view contract.line search view (in contract) contract.line search New
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier tree view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line tree view (in contract) contract.line tree New
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_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag tree New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form view (in contract) contract.template.line form Inherits contract_abstract_contract_line_form_view
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template tree view (in contract) contract.template tree New
contract_terminate_reason_form_view contract.terminate.reason form New
contract_terminate_reason_tree_view contract.terminate.reason tree New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_paynow
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Portal My Home : Contract entries ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_account_move_contract_helper_form account.move form Inherits account.view_move_form
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (19)

New fields (1)
  • old_contract_id Many2one → contract.contract
    args: 'contract.contract'
Public methods (0)

No public methods.

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (8)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • generation_type Selection
    default=<expr> help='Choose the document that will be automatically generated by cron.' selection=<expr> string='Generation Type'
  • journal_id Many2one → account.journal
    check_company=True comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type),('company_id', '=', company_id)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Mark this check if you want to control recurrrence at line level instead of all together for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    check_company=True comodel_name='product.pricelist' domain="[('company_id', '=', company_id)]" string='Pricelist'
Public methods (0)

No public methods.

New fields (28)
  • allowed_uom_categ_id Many2one
    related='product_id.uom_id.category_id'
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Week/Month/Year)' 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)')]
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • company_id Many2one
    related='contract_id.company_id' store=True
  • contract_id Many2one → contract.abstract.contract
    comodel_name='contract.abstract.contract' ondelete='cascade' required=True string='Contract'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purpose.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note'
  • last_date_invoiced Date
    string='Last Date Invoiced'
  • name Text
    required=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='Defines when the Note is invoiced:\n- With previous line: If the previous line can be invoiced.\n- With next line: If the next line can be invoiced.\n- Custom: Depending on the recurrence to be define.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • partner_id Many2one → res.partner
    comodel_name='res.partner' related='contract_id.partner_id'
  • price_subtotal Float
    compute='_compute_price_subtotal' digits='Account' string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' digits='Product Price' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts' string='Sequence'
  • specific_price Float
    string='Specific Price'
  • 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)')]
  • uom_id Many2one → uom.uom
    domain="[('category_id', '=?', allowed_uom_categ_id)]" string='Unit of Measure' args: 'uom.uom'
Public methods (0)

No public methods.

New fields (24)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True comodel_name='account.fiscal.position' domain="[('company_id', '=', company_id)]" ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    check_company=True comodel_name='account.analytic.account' domain="[('company_id', '=', company_id)]" ondelete='restrict' string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' domain="['|', ('id', 'parent_of', partner_id), ('id', 'child_of', partner_id)]" ondelete='restrict' string='Invoicing contact'
  • is_terminated Boolean
    copy=False readonly=True string='Terminated'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    check_company=True comodel_name='account.payment.term' domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]" index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • terminate_comment Text
    copy=False readonly=True string='Termination Comment' tracking=True
  • terminate_date Date
    copy=False readonly=True string='Termination Date' tracking=True
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' copy=False ondelete='restrict' readonly=True string='Termination Reason' tracking=True
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (10)
  • action_cancel_contract_termination(self)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • action_terminate_contract(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (5)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' ondelete='cascade' required=True string='Contract'
  • terminate_comment Text
    string='Termination Comment'
  • terminate_comment_required Boolean
    related='terminate_reason_id.terminate_comment_required'
  • terminate_date Date
    required=True string='Termination Date'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' ondelete='cascade' required=True string='Termination Reason'
Public methods (1)
  • terminate_contract(self)

New fields (18)
  • active Boolean
    default=True readonly=True related='contract_id.active' store=True string='Active'
  • analytic_account_id Many2one → account.analytic.account
    check_company=True comodel_name='account.analytic.account' domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]" string='Analytic account'
  • analytic_tag_ids Many2many → account.analytic.tag
    check_company=True comodel_name='account.analytic.tag' domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]" string='Analytic Tags'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • date_start Date
    required=True
  • 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' string='Manual renew needed'
  • predecessor_contract_line_id Many2one → contract.line
    check_company=True comodel_name='contract.line' copy=False help='Contract Line origin of this one.' index=True readonly=True required=False string='Predecessor Contract Line'
  • sequence Integer
    string='Sequence'
  • 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')] string='State'
  • successor_contract_line_id Many2one → contract.line
    check_company=True 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 string='Termination notice date'
Public methods (13)
  • action_plan_successor(self)
  • action_stop(self)
  • action_stop_plan_successor(self)
  • action_uncancel(self)
  • cancel(self)
  • cron_renew_contract_line(self)
    @api.model
  • fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False)
    @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
    string='Date End'
  • date_start Date
    string='Date Start'
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • 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' string='Manual renew needed'
  • recurring_next_date Date
    string='Next Invoice Date'
Public methods (4)
  • plan_successor(self)
  • stop(self)
  • stop_plan_successor(self)
  • uncancel(self)

New fields (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True string='Invoice Date'
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True string='Date'
  • description Text
    required=True string='Description'
  • sent Boolean
    default=False string='Sent'
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (6)
  • date_start Date
    string='Date Start'
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (6)
  • date_end Date
    index=True string='Date End'
  • date_start Date
    default=<expr>
  • last_date_invoiced Date
    copy=False readonly=True string='Last Date Invoiced'
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period. The next period normally depends on recurrence options only. It is however possible to provide it a next invoice date, in which case this method can adjust the next period based on that too. In that scenario it required the invoicing type and offset arguments.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period. When added to the first day of the period, it gives the first day of the next period.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (1)
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
Public methods (0)

No public methods.

New fields (2)
  • name Char
    required=True
  • terminate_comment_required Boolean
    default=True string='Require a termination comment'
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' string='Create New Line At Contract Line Renew'
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.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/13.0/contract
VERSION
VERSION 2.10.0
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSPedro M. Baeza, Denis Roussel, nans, OCA Transbot, Miquel Raïch, Víctor Martínez, João Marques, oca-travis, Weblate, OCA-git-bot, oca-ci, newtratip, Carlos Roca, Alba Riera, chandni299
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:34:11
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES python-dateutil
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (42)
XML IDNameModelTypeStatus
assets_backend contract assets ir.ui.view qweb Inherits web.assets_backend
assets_frontend contract assets ir.ui.view qweb Inherits web.assets_frontend
assets_tests assets_tests ir.ui.view qweb Inherits web.assets_tests
contract_abstract_contract_line_form_view contract.abstract.contract.line form view (in contract) contract.abstract.contract.line form New
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_terminate_form_view contract.contract.terminate form New
contract_contract_tree_view contract.contract tree view (in contract) contract.contract tree New
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line form view (in contract) contract.line header Inherits contract_abstract_contract_line_form_view
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier tree view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line tree view (in contract) contract.line tree New
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_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag tree New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form view (in contract) contract.template.line form Inherits contract_abstract_contract_line_form_view
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template tree view (in contract) contract.template tree New
contract_terminate_reason_form_view contract.terminate.reason form New
contract_terminate_reason_tree_view contract.terminate.reason tree New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_paynow
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Portal My Home : Contract entries ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_contract_contract_calendar contract.contract.calendar contract.contract calendar New
view_contract_contract_graph contract.contract.graph contract.contract graph New
view_contract_contract_kanban contract.contract.kanban contract.contract kanban New
view_contract_contract_pivot contract.contract.pivot contract.contract pivot New
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (19)

New fields (1)
  • old_contract_id Many2one → contract.contract
    args: 'contract.contract'
Public methods (0)

No public methods.

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (8)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • date Date
    default=<expr> help='This is the date the contract is taken into account (e.g.: signature date)' required=True
  • journal_id Many2one → account.journal
    comodel_name='account.journal' compute='_compute_journal_id' domain="[('type', '=', contract_type),('company_id', '=', company_id)]" index=True readonly=False store=True string='Journal'
  • line_recurrence Boolean
    help='Mark this check if you want to control recurrrence at line level instead of all together for the whole contract.' string='Recurrence at line level?'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (26)
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Week/Month/Year)' 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)')]
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • company_id Many2one
    related='contract_id.company_id' store=True
  • contract_id Many2one → contract.abstract.contract
    comodel_name='contract.abstract.contract' ondelete='cascade' required=True string='Contract'
  • date_start Date
    compute='_compute_date_start' copy=True readonly=False store=True
  • discount Float
    digits='Discount' help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purpose.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note'
  • last_date_invoiced Date
    string='Last Date Invoiced'
  • name Text
    required=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='Defines when the Note is invoiced:\n- With previous line: If the previous line can be invoiced.\n- With next line: If the next line can be invoiced.\n- Custom: Depending on the recurrence to be define.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • price_subtotal Float
    compute='_compute_price_subtotal' digits='Account' string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    compute='_compute_recurring_interval' copy=True readonly=False required=True store=True
  • recurring_invoicing_type Selection
    compute='_compute_recurring_invoicing_type' copy=True readonly=False required=True store=True
  • recurring_rule_type Selection
    compute='_compute_recurring_rule_type' copy=True readonly=False required=True store=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts' string='Sequence'
  • specific_price Float
    string='Specific Price'
  • 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)')]
  • uom_id Many2one → uom.uom
    string='Unit of Measure' args: 'uom.uom'
Public methods (0)

No public methods.

New fields (24)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_fixed_ids One2many → contract.line
    comodel_name='contract.line' inverse_name='contract_id' string='Contract lines (fixed)'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' ondelete='restrict' string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' ondelete='restrict' string='Invoicing contact'
  • is_terminated Boolean
    copy=False readonly=True string='Terminated'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • terminate_comment Text
    copy=False readonly=True string='Termination Comment' tracking=True
  • terminate_date Date
    copy=False readonly=True string='Termination Date' tracking=True
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' copy=False ondelete='restrict' readonly=True string='Termination Reason' tracking=True
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (10)
  • action_cancel_contract_termination(self)
  • action_contract_send(self)
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
  • action_terminate_contract(self)
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (5)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' ondelete='cascade' required=True string='Contract'
  • terminate_comment Text
    string='Termination Comment'
  • terminate_comment_required Boolean
    related='terminate_reason_id.terminate_comment_required'
  • terminate_date Date
    required=True string='Termination Date'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' ondelete='cascade' required=True string='Termination Reason'
Public methods (1)
  • terminate_contract(self)

New fields (18)
  • active Boolean
    default=True readonly=True related='contract_id.active' store=True string='Active'
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' string='Analytic account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • date_end Date
    compute='_compute_date_end' readonly=False store=True
  • date_start Date
    required=True
  • 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' string='Manual renew needed'
  • 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'
  • sequence Integer
    string='Sequence'
  • 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')] string='State'
  • 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 string='Termination notice date'
Public methods (13)
  • action_plan_successor(self)
  • action_stop(self)
  • action_stop_plan_successor(self)
  • action_uncancel(self)
  • cancel(self)
  • cron_renew_contract_line(self)
    @api.model
  • fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False)
    @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
    string='Date End'
  • date_start Date
    string='Date Start'
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • 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' string='Manual renew needed'
  • recurring_next_date Date
    string='Next Invoice Date'
Public methods (4)
  • plan_successor(self)
  • stop(self)
  • stop_plan_successor(self)
  • uncancel(self)

New fields (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True string='Invoice Date'
Public methods (2)
  • action_show_contract_to_invoice(self)
  • create_invoice(self)

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True string='Date'
  • description Text
    required=True string='Description'
  • sent Boolean
    default=False string='Sent'
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (6)
  • date_start Date
    string='Date Start'
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (6)
  • date_end Date
    index=True string='Date End'
  • date_start Date
    default=<expr>
  • last_date_invoiced Date
    copy=False readonly=True string='Last Date Invoiced'
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • recurring_next_date Date
    compute='_compute_recurring_next_date' copy=True readonly=False store=True
Public methods (3)
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period. The next period normally depends on recurrence options only. It is however possible to provide it a next invoice date, in which case this method can adjust the next period based on that too. In that scenario it required the invoicing type and offset arguments.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period. When added to the first day of the period, it gives the first day of the next period.

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (1)
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → contract.template
    comodel_name='contract.template' ondelete='cascade' required=True string='Contract'
Public methods (0)

No public methods.

New fields (2)
  • name Char
    required=True
  • terminate_comment_required Boolean
    default=True string='Require a termination comment'
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' string='Create New Line At Contract Line Renew'
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.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/12.0/contract
VERSION
VERSION 8.7.0
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), LasLabs, OpenERP SA
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), LasLabs, OpenERP SA
COMMITTERS
COMMITTERSStefan Rijnhart, Holger Brunn, Pedro M. Baeza, GitHub, Jairo Llopis, mreficent, Denis Roussel, Stéphane Bidoul (ACSONE), remi-filament, sbejaoui, nans, manu, OCA Transbot, Miquel Raïch, Víctor Martínez, Ernesto Tejeda, Sergio Teruel, oca-travis, Weblate, OCA-git-bot, hparfr, Quentin Groulard, oca-ci, Enrique, Yu Weng, newtratip, Harshad, chandni299, Stéphane Valaeys
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:29:15
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - http_routing
    - digest
    - auth_signup
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES python-dateutil
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (42)
XML IDNameModelTypeStatus
assets_backend contract assets ir.ui.view qweb Inherits web.assets_backend
assets_frontend contract assets ir.ui.view qweb Inherits web.assets_frontend
contract_abstract_contract_line_form_view contract.abstract.contract.line form view (in contract) contract.abstract.contract.line form New
contract_contract_customer_form_view contract.contract customer form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_form_view contract.contract form view (in contract) contract.contract form New
contract_contract_search_view contract.contract search view (in contract) contract.contract search New
contract_contract_supplier_form_view contract.contract supplier form view (in contract) contract.contract field Inherits contract_contract_form_view
contract_contract_terminate_form_view contract.contract.terminate form New
contract_contract_tree_view contract.contract tree view (in contract) contract.contract tree New
contract_frontend_demo contract_frontend_demo ir.ui.view qweb Inherits web.assets_frontend
contract_line_customer_form_view contract.line customer form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_form_view contract.line form view (in contract) contract.line header Inherits contract_abstract_contract_line_form_view
contract_line_supplier_form_view contract.line supplier form view (in contract) contract.line field Inherits contract_line_form_view
contract_line_supplier_tree_view contract.line supplier tree view (in contract) contract.line field Inherits contract_line_tree_view
contract_line_tree_view contract.line tree view (in contract) contract.line tree New
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_manually_create_invoice_form_view contract.manually.create.invoice form New
contract_tag_form_view contract.tag form New
contract_tag_tree_view contract.tag tree New
contract_template_form_view contract.template form view (in contract) contract.template form New
contract_template_line_form_view contract.template.line form view (in contract) contract.template.line form Inherits contract_abstract_contract_line_form_view
contract_template_search_view contract.template search view (in contract) contract.template search New
contract_template_tree_view contract.template tree view (in contract) contract.template tree New
contract_terminate_reason_form_view contract.terminate.reason form New
contract_terminate_reason_tree_view contract.terminate.reason tree New
mail_notification_contract mail_notification_contract ir.ui.view qweb Inherits mail.mail_notification_paynow
portal_contract_page My Contract ir.ui.view qweb New
portal_my_contracts My Contracts ir.ui.view qweb New
portal_my_home_contract Portal My Home : Contract entries ir.ui.view qweb Inherits portal.portal_my_home
portal_my_home_menu_contract Portal layout : Contract menu entries ir.ui.view qweb Inherits portal.portal_breadcrumbs
report_contract_document report_contract_document ir.ui.view qweb New
res_config_settings_form_view res.config.settings xpath Inherits account.res_config_settings_view_form
template_contract_modification Contract Modification ir.ui.view qweb New
view_contract_contract_calendar contract.contract.calendar contract.contract calendar New
view_contract_contract_graph contract.contract.graph contract.contract graph New
view_contract_contract_kanban contract.contract.kanban contract.contract kanban New
view_contract_contract_pivot contract.contract.pivot contract.contract pivot New
view_partner_form res.partner xpath Inherits base.view_partner_form
view_res_partner_filter res.partner filter Inherits base.view_res_partner_filter
Models touched (18)

New fields (1)
  • old_contract_id Many2one → contract.contract
    oldname='contract_id' args: 'contract.contract'
Public methods (0)

No public methods.

New fields (1)
  • contract_line_id Many2one → contract.line
    index=True string='Contract Line' args: 'contract.line'
Public methods (0)

No public methods.

New fields (6)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' index=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • journal_id Many2one → account.journal
    default=<expr> domain="[('type', '=', contract_type),('company_id', '=', company_id)]" index=True string='Journal' args: 'account.journal'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
Public methods (0)

No public methods.

New fields (27)
  • auto_renew_interval Integer
    default=1 help='Renew every (Days/Week/Month/Year)' 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)')]
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • contract_id Many2one → contract.abstract.contract
    comodel_name='contract.abstract.contract' ondelete='cascade' required=True string='Contract'
  • date_start Date
    string='Date Start'
  • discount Float
    digits=dp.get_precision('Discount') help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • display_type Selection
    default=False help='Technical field for UX purpose.' selection=[('line_section', 'Section'), ('line_note', 'Note')]
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • is_canceled Boolean
    default=False string='Canceled'
  • is_recurring_note Boolean
    compute='_compute_is_recurring_note'
  • last_date_invoiced Date
    string='Last Date Invoiced'
  • name Text
    required=True string='Description'
  • note_invoicing_mode Selection
    default='with_previous_line' help='Defines when the Note is invoiced:\n- With previous line: If the previous line can be invoiced.\n- With next line: If the next line can be invoiced.\n- Custom: Depending on the recurrence to be define.' selection=[('with_previous_line', 'With previous line'), ('with_next_line', 'With next line'), ('custom', 'Custom')]
  • price_subtotal Float
    compute='_compute_price_subtotal' digits=dp.get_precision('Account') string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    string='Product' args: 'product.product'
  • quantity Float
    default=1.0 required=True
  • recurring_interval Integer
    default=1 help='Invoice every (Days/Week/Month/Year)' required=True string='Invoice Every'
  • recurring_invoicing_offset Integer
    compute='_compute_recurring_invoicing_offset' help='Number of days to offset the invoice from the period end date (in post-paid mode) or start date (in pre-paid mode).' string='Invoicing offset'
  • recurring_invoicing_type Selection
    default='pre-paid' help='Specify if the invoice must be generated at the beginning (pre-paid) or end (post-paid) of the period.' required=True string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' required=True string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('quarterly', 'Quarter(s)'), ('semesterly', 'Semester(s)'), ('yearly', 'Year(s)')]
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts' string='Sequence'
  • specific_price Float
    string='Specific Price'
  • 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)')]
  • uom_id Many2one → uom.uom
    string='Unit of Measure' args: 'uom.uom'
Public methods (0)

No public methods.

New fields (25)
  • active Boolean
    default=True
  • code Char
    string='Reference'
  • commercial_partner_id Many2one → res.partner
    compute_sudo=True index=True related='partner_id.commercial_partner_id' store=True string='Commercial Entity' args: 'res.partner'
  • contract_line_ids One2many → contract.line
    comodel_name='contract.line' copy=True inverse_name='contract_id' string='Contract lines'
  • contract_template_id Many2one → contract.template
    comodel_name='contract.template' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' compute='_compute_currency_id' inverse='_inverse_currency_id' string='Currency'
  • date_end Date
    compute='_compute_date_end' store=True string='Date End'
  • date_start Date
    compute='_compute_date_end' store=True string='Date Start'
  • fiscal_position_id Many2one → account.fiscal.position
    comodel_name='account.fiscal.position' ondelete='restrict' string='Fiscal Position'
  • group_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' ondelete='restrict' string='Group'
  • invoice_count Integer
    compute='_compute_invoice_count'
  • invoice_partner_id Many2one → res.partner
    comodel_name='res.partner' ondelete='restrict' string='Invoicing contact'
  • is_terminated Boolean
    copy=False readonly=True string='Terminated'
  • manual_currency_id Many2one → res.currency
    comodel_name='res.currency' readonly=True
  • modification_ids One2many → contract.modification
    comodel_name='contract.modification' inverse_name='contract_id' string='Modifications'
  • note Text
    string='Notes'
  • partner_id Many2one → res.partner
    comodel_name='res.partner' inverse='_inverse_partner_id' required=True
  • payment_term_id Many2one → account.payment.term
    comodel_name='account.payment.term' index=True string='Payment Terms'
  • recurring_next_date Date
    compute='_compute_recurring_next_date' store=True string='Date of Next Invoice'
  • tag_ids Many2many → contract.tag
    comodel_name='contract.tag' string='Tags'
  • terminate_comment Text
    copy=False readonly=True string='Termination Comment' track_visibility='onchange'
  • terminate_date Date
    copy=False readonly=True string='Termination Date' track_visibility='onchange'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' copy=False ondelete='restrict' readonly=True string='Termination Reason' track_visibility='onchange'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (10)
  • action_cancel_contract_termination(self)
    @api.multi
  • action_contract_send(self)
    @api.multi
  • action_preview(self)
    Invoked when 'Preview' button in contract form view is clicked.
  • action_show_invoices(self)
    @api.multi
  • action_terminate_contract(self)
    @api.multi
  • create(self, vals_list)
    @api.model_create_multi
  • cron_recurring_create_invoice(self, date_ref=None)
    @api.model
  • get_formview_id(self, access_uid=None)
  • recurring_create_invoice(self)
    @api.multi
    This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future.
  • write(self, vals)

New fields (5)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' ondelete='cascade' required=True string='Contract'
  • terminate_comment Text
    string='Termination Comment'
  • terminate_comment_required Boolean
    related='terminate_reason_id.terminate_comment_required'
  • terminate_date Date
    required=True string='Termination Date'
  • terminate_reason_id Many2one → contract.terminate.reason
    comodel_name='contract.terminate.reason' ondelete='cascade' required=True string='Termination Reason'
Public methods (1)
  • terminate_contract(self)
    @api.multi

New fields (22)
  • active Boolean
    default=True readonly=True related='contract_id.active' store=True string='Active'
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' string='Analytic account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • contract_id Many2one → contract.contract
    auto_join=True comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • date_end Date
    index=True string='Date End'
  • date_start Date
    default=<expr> required=True string='Date Start'
  • 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?'
  • last_date_invoiced Date
    copy=False readonly=True string='Last Date Invoiced'
  • 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' string='Manual renew needed'
  • next_period_date_end Date
    compute='_compute_next_period_date_end' string='Next Period End'
  • next_period_date_start Date
    compute='_compute_next_period_date_start' string='Next Period Start'
  • 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'
  • recurring_next_date Date
    string='Date of Next Invoice'
  • sequence Integer
    string='Sequence'
  • 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')] string='State'
  • 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 string='Termination notice date'
Public methods (16)
  • action_plan_successor(self)
    @api.multi
  • action_stop(self)
    @api.multi
  • action_stop_plan_successor(self)
    @api.multi
  • action_uncancel(self)
    @api.multi
  • cancel(self)
    @api.multi
  • cron_renew_contract_line(self)
    @api.model
  • fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False)
    @api.model
  • get_next_invoice_date(self, next_period_date_start, recurring_invoicing_type, recurring_invoicing_offset, recurring_rule_type, recurring_interval, max_date_end)
    @api.model
  • get_next_period_date_end(self, next_period_date_start, recurring_rule_type, recurring_interval, max_date_end, next_invoice_date=False, recurring_invoicing_type=False, recurring_invoicing_offset=False)
    @api.model
    Compute the end date for the next period. The next period normally depends on recurrence options only. It is however possible to provide it a next invoice date, in which case this method can adjust the next period based on that too. In that scenario it required the invoicing type and offset arguments.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
    Return a relativedelta for one period. When added to the first day of the period, it gives the first day of the next period.
  • plan_successor(self, date_start, date_end, is_auto_renew, recurring_next_date=False, post_message=True)
    @api.multi
    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)
    @api.multi
  • stop(self, date_end, manual_renew_needed=False, post_message=True)
    @api.multi
    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)
    @api.multi
    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)
    @api.multi
  • unlink(self)
    @api.multi
    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
    string='Date End'
  • date_start Date
    string='Date Start'
  • is_auto_renew Boolean
    default=False string='Auto Renew'
  • 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' string='Manual renew needed'
  • recurring_next_date Date
    string='Next Invoice Date'
Public methods (4)
  • plan_successor(self)
    @api.multi
  • stop(self)
    @api.multi
  • stop_plan_successor(self)
    @api.multi
  • uncancel(self)
    @api.multi

New fields (4)
  • contract_to_invoice_count Integer
    compute='_compute_contract_to_invoice_ids'
  • contract_to_invoice_ids Many2many → contract.contract
    comodel_name='contract.contract' compute='_compute_contract_to_invoice_ids'
  • contract_type Selection
    default='sale' required=True selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • invoice_date Date
    required=True string='Invoice Date'
Public methods (2)
  • action_show_contract_to_invoice(self)
    @api.multi
  • create_invoice(self)
    @api.multi

New fields (4)
  • contract_id Many2one → contract.contract
    comodel_name='contract.contract' index=True ondelete='cascade' required=True string='Contract'
  • date Date
    required=True string='Date'
  • description Text
    required=True string='Description'
  • sent Boolean
    default=False string='Sent'
Public methods (3)
  • check_modification_ids_need_sent(self)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (3)
  • color Integer
    default=0 args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> string='Company' args: 'res.company'
  • name Char
    requirment=True
Public methods (0)

No public methods.

New fields (1)
  • contract_line_ids One2many → contract.template.line
    comodel_name='contract.template.line' copy=True inverse_name='contract_id' string='Contract template lines'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → contract.template
    comodel_name='contract.template' oldname='analytic_account_id' ondelete='cascade' required=True string='Contract'
Public methods (0)

No public methods.

New fields (2)
  • name Char
    required=True
  • terminate_comment_required Boolean
    default=True string='Require a termination comment'
Public methods (0)

No public methods.

New fields (0)

No new fields.

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' string='Create New Line At Contract Line Renew'
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.

New fields (3)
  • contract_ids One2many → contract.contract
    comodel_name='contract.contract' inverse_name='partner_id' string='Contracts'
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/11.0/contract
VERSION
VERSION 4.1.0
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), LasLabs, OpenERP SA
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), LasLabs, OpenERP SA
COMMITTERS
COMMITTERSPedro M. Baeza, GitHub, Jairo Llopis, mreficent, Carlos Dauden, OCA Transbot, Dmytro Katyukha, oca-travis, Weblate, OCA-git-bot, OCA Git Bot, Aitor Bouzas, Daniel Palomar, Jon Zaballa, Jon Erik Ceberio
WEBSITE
WEBSITEhttps://github.com/oca/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:23:56
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - web_tour
    - analytic
    - web_planner
    - portal
    - http_routing
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (11)
XML IDNameModelTypeStatus
account_analytic_account_purchase_form account.analytic.account.purchase.form account.analytic.account field Inherits account_analytic_account_recurring_form_form
account_analytic_account_recurring_form_form Contract form account.analytic.account field Inherits analytic.view_account_analytic_account_form
account_analytic_account_sale_form account.analytic.account.sale.form account.analytic.account field Inherits account_analytic_account_recurring_form_form
account_analytic_contract_view_form Account Analytic Contract Form View account.analytic.contract form New
account_analytic_contract_view_search Account Analytic Contract Search View account.analytic.contract search New
account_analytic_contract_view_tree Account Analytic Contract Tree View account.analytic.contract tree New
report_contract_document report_contract_document ir.ui.view qweb New
view_account_analytic_account_contract_search Contract search account.analytic.account field Inherits analytic.view_account_analytic_account_search
view_account_analytic_account_journal_tree Contract list account.analytic.account field Inherits analytic.view_account_analytic_account_list
view_account_invoice_filter_contract account.invoice.select.contract account.invoice field Inherits account.view_account_invoice_filter
view_partner_form res.partner xpath Inherits base.view_partner_form
Models touched (6)

New fields (8)
  • contract_template_id Many2one → account.analytic.contract
    comodel_name='account.analytic.contract' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • date_end Date
    index=True string='Date End'
  • date_start Date
    default=fields.Date.context_today string='Date Start'
  • recurring_invoice_line_ids One2many → account.analytic.invoice.line
    comodel_name='account.analytic.invoice.line' copy=True inverse_name='analytic_account_id' string='Invoice Lines'
  • recurring_invoices Boolean
    string='Generate recurring invoices automatically'
  • recurring_next_date Date
    copy=False default=fields.Date.context_today string='Date of Next Invoice'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (5)
  • action_contract_send(self)
    @api.multi
  • button_show_recurring_invoices(self)
    @api.multi
  • cron_recurring_create_invoice(self, limit=None)
    @api.model
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
  • recurring_create_invoice(self, limit=None)
    @api.multi
    Create invoices from contracts :param int limit: Max of invoices to create. :return: invoices created

New fields (10)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • contract_type Selection
    default='sale' selection=[('sale', 'Customer'), ('purchase', 'Supplier')]
  • journal_id Many2one → account.journal
    default=<expr> domain="[('type', '=', contract_type),('company_id', '=', company_id)]" string='Journal' args: 'account.journal'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' string='Partner (always False)'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
  • recurring_interval Integer
    default=1 help='Repeat every (Days/Week/Month/Year)' string='Repeat Every'
  • recurring_invoice_line_ids One2many → account.analytic.contract.line
    comodel_name='account.analytic.contract.line' copy=True inverse_name='analytic_account_id' string='Invoice Lines'
  • recurring_invoicing_type Selection
    default='pre-paid' help="Specify if process date is 'from' or 'to' invoicing date" string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (13)
  • analytic_account_id Many2one → account.analytic.contract
    comodel_name='account.analytic.contract' ondelete='cascade' required=True string='Contract'
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • date_from Date
    compute='_compute_date_from' help='Date from invoiced period' string='Date From'
  • date_to Date
    compute='_compute_date_to' help='Date to invoiced period' string='Date To'
  • discount Float
    digits=dp.get_precision('Discount') help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • name Text
    required=True string='Description'
  • price_subtotal Float
    compute='_compute_price_subtotal' digits=dp.get_precision('Account') string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    required=True string='Product' args: 'product.product'
  • quantity Float
    default=1.0 digits=dp.get_precision('Product Unit of Measure') required=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts' string='Sequence'
  • specific_price Float
    string='Specific Price'
  • uom_id Many2one → product.uom
    required=True string='Unit of Measure' args: 'product.uom'
Public methods (0)

No public methods.

New fields (1)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' ondelete='cascade' required=True string='Analytic Account'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → account.analytic.account
    string='Contract' args: 'account.analytic.account'
Public methods (0)

No public methods.

New fields (2)
  • purchase_contract_count Integer
    compute='_compute_contract_count' string='Purchase Contracts'
  • sale_contract_count Integer
    compute='_compute_contract_count' string='Sale Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/10.0/contract
VERSION
VERSION 4.3.2
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), LasLabs, OpenERP SA
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), LasLabs, OpenERP SA
COMMITTERS
COMMITTERSStefan Rijnhart, Ronald Portier, Pedro M. Baeza, GitHub, Jairo Llopis, Andrea, OCA Transbot, Дмитро Катюха, Dave Lasley, oca-travis, Weblate, Rafael Blasco, OCA-git-bot, sergiocorato, Sunny Sheth
WEBSITE
WEBSITEhttps://github.com/oca/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:19:54
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web_kanban
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - web_tour
    - report
    - analytic
    - web_planner
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (10)
XML IDNameModelTypeStatus
account_analytic_account_recurring_form_form Contract form account.analytic.account field Inherits analytic.view_account_analytic_account_form
account_analytic_contract_view_form Account Analytic Contract Form View account.analytic.contract form New
account_analytic_contract_view_search Account Analytic Contract Search View account.analytic.contract search New
account_analytic_contract_view_tree Account Analytic Contract Tree View account.analytic.contract tree New
report_contract_document report_contract_document ir.ui.view qweb New
view_account_analytic_account_contract_search Contract search account.analytic.account field Inherits analytic.view_account_analytic_account_search
view_account_analytic_account_journal_tree Contract list account.analytic.account field Inherits analytic.view_account_analytic_account_list
view_account_invoice_filter_contract account.invoice.select.contract account.invoice field Inherits account.view_account_invoice_filter
view_company_form res.company field Inherits base.view_company_form
view_partner_form res.partner xpath Inherits base.view_partner_form
Models touched (7)

New fields (8)
  • contract_template_id Many2one → account.analytic.contract
    comodel_name='account.analytic.contract' string='Contract Template'
  • create_invoice_visibility Boolean
    compute='_compute_create_invoice_visibility'
  • date_end Date
    index=True string='Date End'
  • date_start Date
    default=fields.Date.context_today string='Date Start'
  • recurring_invoice_line_ids One2many → account.analytic.invoice.line
    comodel_name='account.analytic.invoice.line' copy=True inverse_name='analytic_account_id' string='Invoice Lines'
  • recurring_invoices Boolean
    string='Generate recurring invoices automatically'
  • recurring_next_date Date
    copy=False default=fields.Date.context_today string='Date of Next Invoice'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (6)
  • action_contract_send(self)
    @api.multi
  • check_dates_valid(self)
    @api.multi
    Check start and end dates.
  • cron_recurring_create_invoice(self, limit=None)
    @api.model
    Generate invoices. Invoices can be generated a specified number of days before the invoice date, to allow the user to check the invoices before confirmation, or to send out the invoices to the customers before the invoice date.
  • get_invoice_context(self)
    @api.multi
    Compute context for invoice creation.
  • get_relative_delta(self, recurring_rule_type, interval)
    @api.model
  • recurring_create_invoice(self, limit=None)
    @api.multi
    Create invoices from contracts :param int limit: Max of invoices to create. :return: invoices created

New fields (9)
  • company_id Many2one → res.company
    default=<expr> required=True string='Company' args: 'res.company'
  • journal_id Many2one → account.journal
    default=<expr> domain="[('type', '=', 'sale'),('company_id', '=', company_id)]" string='Journal' args: 'account.journal'
  • name Char
    required=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' string='Partner (always False)'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
  • recurring_interval Integer
    default=1 help='Repeat every (Days/Week/Month/Year)' string='Repeat Every'
  • recurring_invoice_line_ids One2many → account.analytic.contract.line
    comodel_name='account.analytic.contract.line' copy=True inverse_name='analytic_account_id' string='Invoice Lines'
  • recurring_invoicing_type Selection
    default='pre-paid' help="Specify if process date is 'from' or 'to' invoicing date" string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrence' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('yearly', 'Year(s)')]
Public methods (0)

No public methods.

New fields (12)
  • analytic_account_id Many2one → account.analytic.contract
    comodel_name='account.analytic.contract' ondelete='cascade' required=True string='Contract'
  • analytic_tag_ids Many2many → account.analytic.tag
    string='Analytic Tags' args: 'account.analytic.tag'
  • automatic_price Boolean
    help='If this is marked, the price will be obtained automatically applying the pricelist to the product. If not, you will be able to introduce a manual price' string='Auto-price?'
  • discount Float
    digits=dp.get_precision('Discount') help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • name Text
    required=True string='Description'
  • price_subtotal Float
    compute='_compute_price_subtotal' digits=dp.get_precision('Account') string='Sub Total'
  • price_unit Float
    compute='_compute_price_unit' inverse='_inverse_price_unit' string='Unit Price'
  • product_id Many2one → product.product
    required=True string='Product' args: 'product.product'
  • quantity Float
    default=1.0 required=True
  • sequence Integer
    default=10 help='Sequence of the contract line when displaying contracts' string='Sequence'
  • specific_price Float
    string='Specific Price'
  • uom_id Many2one → product.uom
    required=True string='Unit of Measure' args: 'product.uom'
Public methods (0)

No public methods.

New fields (1)
  • analytic_account_id Many2one → account.analytic.account
    ondelete='cascade' required=True string='Analytic Account' args: 'account.analytic.account'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → account.analytic.account
    string='Contract' args: 'account.analytic.account'
Public methods (0)

No public methods.

New fields (1)
  • contract_pregenerate_days Integer
    help='Days before next invoice date to generate draft invoices.\nThis allows users to check the invoices before confirmation,\n and to send invoices to customers, before the invoice date.' string='Days to prepare invoices'
Public methods (0)

No public methods.

New fields (1)
  • contract_count Integer
    compute='_compute_contract_count' string='Contracts'
Public methods (1)
  • act_show_contract(self)
    This opens contract view @return: the contract view
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/9.0/contract
VERSION
VERSION 1.3.0
CATEGORY
CATEGORYContract Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSTecnativa, Odoo Community Association (OCA), OpenERP SA
MAINTAINERS
MAINTAINERSTecnativa, Odoo Community Association (OCA), OpenERP SA
COMMITTERS
COMMITTERSAlexandre Fayolle, Stefan Rijnhart, Pedro M. Baeza, GitHub, Carlos Dauden, Daniel Reis, Stéphane Bidoul (ACSONE), unknown, OCA Transbot, moylop260, Dmytro Katyukha, Federico Cruz, oca-travis, Weblate, Rafael Blasco, OCA-git-bot, Carlos Incaser
WEBSITE
WEBSITEhttp://openerp.com
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:15:19
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - base
    - account
    - base_setup
    - web_kanban
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - report
    - analytic
    - web_tip
    - web_planner
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (6)
XML IDNameModelTypeStatus
account_analytic_account_recurring_form_form account.analytic.account.invoice.recurring.form.inherit account.analytic.account xpath Inherits analytic.view_account_analytic_account_form
report_contract_document report_contract_document ir.ui.view qweb New
view_account_analytic_account_contract_search account.analytic.account.contract.search account.analytic.account field Inherits analytic.view_account_analytic_account_search
view_account_analytic_account_journal_tree account.analytic.account.journal.list account.analytic.account field Inherits analytic.view_account_analytic_account_list
view_account_invoice_filter_contract account.invoice.select.contract account.invoice field Inherits account.view_account_invoice_filter
view_partner_form res.partner.view.contract res.partner div Inherits base.view_partner_form
Models touched (4)

New fields (10)
  • date_start Date
    default=fields.Date.context_today
  • journal_id Many2one → account.journal
    default=_default_journal domain="[('type', '=', 'sale'),('company_id', '=', company_id)]" string='Journal' args: 'account.journal'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' string='Pricelist'
  • recurring_interval Integer
    default=1 help='Repeat every (Days/Week/Month/Year)' string='Repeat Every'
  • recurring_invoice_line_ids One2many → account.analytic.invoice.line
    comodel_name='account.analytic.invoice.line' copy=True inverse_name='analytic_account_id' string='Invoice Lines'
  • recurring_invoices Boolean
    string='Generate recurring invoices automatically'
  • recurring_invoicing_type Selection
    default='pre-paid' help="Specify if process date is 'from' or 'to' invoicing date" string='Invoicing type' args: [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')]
  • recurring_next_date Date
    copy=False default=fields.Date.context_today string='Date of Next Invoice'
  • recurring_rule_type Selection
    default='monthly' help='Specify Interval for automatic invoice generation.' string='Recurrency' args: [('daily', 'Day(s)'), ('weekly', 'Week(s)'), ('monthly', 'Month(s)'), ('monthlylastday', 'Month(s) last day'), ('yearly', 'Year(s)')]
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> index=True string='Responsible'
Public methods (4)
  • action_contract_send(self)
    @api.multi
  • cron_recurring_create_invoice(self)
    @api.model
  • get_relalive_delta(self, recurring_rule_type, interval)
    @api.model
  • recurring_create_invoice(self)
    @api.multi

New fields (8)
  • analytic_account_id Many2one → account.analytic.account
    string='Analytic Account' args: 'account.analytic.account'
  • discount Float
    digits=dp.get_precision('Discount') help='Discount that is applied in generated invoices. It should be less or equal to 100' string='Discount (%)'
  • name Text
    required=True string='Description'
  • price_subtotal Float
    compute='_compute_price_subtotal' digits_compute=dp.get_precision('Account') string='Sub Total'
  • price_unit Float
    required=True args: 'Unit Price'
  • product_id Many2one → product.product
    required=True string='Product' args: 'product.product'
  • quantity Float
    default=1.0 required=True
  • uom_id Many2one → product.uom
    required=True string='Unit of Measure' args: 'product.uom'
Public methods (0)

No public methods.

New fields (1)
  • contract_id Many2one → account.analytic.account
    string='Contract' args: 'account.analytic.account'
Public methods (0)

No public methods.

New fields (2)
  • contract_count Integer
    compute='_compute_contract_count' string='# of Contracts'
  • contract_ids One2many → account.analytic.account
    comodel_name='account.analytic.account' inverse_name='partner_id' string='Contracts'
Public methods (0)

No public methods.