Subscription management

subscription_oca
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/19.0/subscription_oca
VERSION
VERSION 1.1.3
CATEGORY
CATEGORYSubscription Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Domatix, Onestein
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Domatix, Onestein
COMMITTERS
COMMITTERSWeblate, OCA-git-bot, oca-ci, stferraro, alvaro-domatix
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:40:47
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - sale_management
    - sale
    - sales_team
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - html_editor
    - account_payment
    - account
    - onboarding
    - product
    - uom
    - analytic
    - portal
    - http_routing
    - auth_signup
    - digest
    - resource
    - payment
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows creating subscriptions that generate recurring
invoices or orders. It also enables the sale of products that generate
subscriptions.

Code Analysis

Views touched (16)
XML IDNameModelTypeStatus
close_reason_wizard_view close.reason.wizard.view close.reason.wizard form New
product_template_form_view product.template.sub.form product.template xpath Inherits product.product_template_form_view
res_partner_view_form res.partner.form res.partner button Inherits base.view_partner_form
sale_subscription_form sale.subscription.form sale.subscription form New
sale_subscription_kanban sale.subscription.kanban sale.subscription kanban New
sale_subscription_template_form sale.subscription.template.form sale.subscription.template form New
sale_subscription_template_tree sale.subscription.template.list sale.subscription.template list New
sale_subscription_tree sale.subscription.list sale.subscription list New
view_move_form account.move xpath Inherits account.view_move_form
view_product_suscribable_filter product.suscribable.filter product.template search New
view_sale_order_form view.sale_order.form sale.order div Inherits sale.view_order_form
view_sale_order_pending_filter sale.order.pending.filter sale.subscription search New
view_sale_subscription_tag_tree view.sale.subscription.tag.list sale.subscription.tag list New
view_subscription_close_reason_tree view.subscription.close.reason.list sale.subscription.close.reason list New
view_subscription_stage_form view.subscription.stage.form sale.subscription.stage form New
view_subscription_stage_tree view.subscription.stage.list sale.subscription.stage list New
Models touched (12)

New fields (1)
  • subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
Public methods (1)
  • action_open_subscription(self)

New fields (1)
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Reason'
Public methods (1)
  • button_confirm(self)

New fields (2)
  • subscribable Boolean
    string='Subscribable product'
  • subscription_template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' string='Subscription template'
Public methods (0)

No public methods.

New fields (2)
  • subscription_count Integer
    compute='_compute_subscription_count' required=False
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='partner_id' string='Subscriptions'
Public methods (1)
  • action_view_subscription_ids(self)

New fields (3)
  • order_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='sale_order_id' string='Subscriptions'
  • subscriptions_count Integer
    compute='_compute_subscriptions_count'
Public methods (5)
  • action_confirm(self)
    Create a subscription per template from the Order's products
  • action_view_subscriptions(self)
  • create_subscription(self, lines, subscription_tmpl)
  • get_next_interval(self, type_interval, interval)
  • group_subscription_lines(self)
    Group Sale Order Lines by their product's subscription template

New fields (0)

No new fields.

Public methods (1)
  • get_subscription_line_values(self)

New fields (38)
  • account_invoice_ids_count Integer
    compute='_compute_account_invoice_ids_count' string='Invoice Count'
  • active Boolean
    default=True
  • amount_tax Monetary
    compute='_compute_total' store=True
  • amount_total Monetary
    compute='_compute_total' store=True
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Close Reason'
  • code Char
    default=<expr> string='Reference'
  • color Integer
    args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> index=True required=True args: 'res.company', 'Company'
  • crm_team_id Many2one → crm.team
    comodel_name='crm.team' string='Sale team'
  • currency_id Many2one
    depends=['pricelist_id'] ondelete='restrict' related='pricelist_id.currency_id' store=True
  • date Date
    compute='_compute_rule_boundary' readonly=False store=True string='Finish date'
  • date_start Date
    default=date.today() string='Start date'
  • description Text
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True domain="[('company_id', '=', company_id)]" string='Fiscal Position' args: 'account.fiscal.position'
  • image Binary
    related='user_id.image_512' store=True args: 'Image'
  • in_progress Boolean
    default=False string='In progress'
  • invoice_ids One2many → account.move
    comodel_name='account.move' inverse_name='subscription_id' string='Invoices'
  • journal_id Many2one → account.journal
    comodel_name='account.journal' string='Journal'
  • name Char
    compute='_compute_name' store=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True required=True string='Partner'
  • partner_invoice_id Many2one → res.partner
    comodel_name='res.partner' compute='_compute_partner_address_ids' help="Address the recurring invoices are addressed to. Defaults to the customer's invoice address." readonly=False store=True string='Invoice address'
  • partner_shipping_id Many2one → res.partner
    comodel_name='res.partner' compute='_compute_partner_address_ids' help="Delivery address used on the recurring invoices and orders. Defaults to the customer's delivery address." readonly=False store=True string='Delivery address'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' required=True string='Pricelist'
  • recurring_next_date Date
    default=date.today() string='Next invoice date'
  • recurring_rule_boundary Boolean
    compute='_compute_rule_boundary' store=True string='Boundary'
  • recurring_total Monetary
    compute='_compute_total' store=True string='Recurring price'
  • sale_order_id Many2one → sale.order
    comodel_name='sale.order' string='Origin sale order'
  • sale_order_ids One2many → sale.order
    comodel_name='sale.order' inverse_name='order_subscription_id' string='Orders'
  • sale_order_ids_count Integer
    compute='_compute_sale_order_ids_count' string='Sale orders'
  • sale_subscription_line_ids One2many → sale.subscription.line
    comodel_name='sale.subscription.line' inverse_name='sale_subscription_id'
  • sequence Integer
  • stage_id Many2one → sale.subscription.stage
    comodel_name='sale.subscription.stage' group_expand='_read_group_stage_ids' store=True string='Stage' tracking=True
  • stage_type Selection
    related='stage_id.type'
  • tag_ids Many2many → sale.subscription.tag
    comodel_name='sale.subscription.tag' string='Tags'
  • template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' required=True string='Subscription template'
  • terms Text
    compute='_compute_terms' readonly=False store=True string='Terms and conditions'
  • to_renew Boolean
    default=False string='To renew'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> string='Commercial agent'
Public methods (15)
  • action_close_subscription(self)
  • action_start_subscription(self)
  • action_view_account_invoice_ids(self)
  • action_view_sale_order_ids(self)
  • calculate_recurring_next_date(self, start_date)
  • close_subscription(self, close_reason_id=False)
  • create(self, vals_list)
    @api.model_create_multi
  • create_invoice(self)
  • create_sale_order(self)
  • cron_subscription_management(self)
    @api.model
  • generate_invoice(self)
  • manual_invoice(self)
  • onchange_partner_id(self)
    @api.onchange('partner_id')
  • onchange_partner_id_fpos(self)
    @api.onchange('partner_id', 'company_id')
  • write(self, values)

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (12)
  • amount_tax_line_amount Float
    compute='_compute_subtotal' store=True string='Taxes Amount'
  • company_id Many2one
    index=True related='sale_subscription_id.company_id' store=True string='Company'
  • currency_id Many2one → res.currency
    readonly=True related='sale_subscription_id.currency_id' store=True args: 'res.currency'
  • discount Float
    compute='_compute_discount' readonly=False store=True string='Discount (%)'
  • name Char
    compute='_compute_name' readonly=False store=True string='Description'
  • price_subtotal Monetary
    compute='_compute_subtotal' readonly=True store=True string='Subtotal'
  • price_total Monetary
    compute='_compute_subtotal' readonly=True store=True string='Total'
  • price_unit Float
    compute='_compute_price_unit' readonly=False store=True string='Unit price'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('sale_ok', '=', True)] string='Product'
  • product_uom_qty Float
    default=1.0 string='Quantity'
  • sale_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • tax_ids Many2many → account.tax
    column1='subscription_line_id' column2='tax_id' comodel_name='account.tax' compute='_compute_tax_ids' readonly=False relation='subscription_line_tax' store=True string='Taxes'
Public methods (0)

No public methods.

New fields (6)
  • description Text
    translate=True
  • fold Boolean
    string='Kanban folded'
  • in_progress Boolean
    default=False string='In progress'
  • name Char
    required=True translate=True
  • sequence Integer
  • type Selection
    default='pre' args: [('draft', 'Draft'), ('pre', 'Ready to start'), ('in_progress', 'In progress'), ('post', 'Closed')]
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True args: 'Tag name'
Public methods (0)

No public methods.

New fields (13)
  • code Char
  • description Text
    string='Terms and conditions'
  • invoice_mail_template_id Many2one → mail.template
    comodel_name='mail.template' domain="[('model', '=', 'account.move')]" string='Invoice Email'
  • invoicing_mode Selection
    default='draft' selection=[('draft', 'Draft'), ('invoice', 'Invoice'), ('invoice_send', 'Invoice & send'), ('sale_and_invoice', 'Sale order & Invoice')] string='Invoicing mode'
  • name Char
    required=True
  • product_ids One2many → product.template
    comodel_name='product.template' inverse_name='subscription_template_id' string='Products'
  • product_ids_count Integer
    compute='_compute_product_ids_count' string='product_ids'
  • recurring_interval Integer
    default=1 string='Repeat every'
  • recurring_rule_boundary Selection
    default='unlimited' string='Duration' args: [('unlimited', 'Forever'), ('limited', 'Fixed')]
  • recurring_rule_count Integer
    default=1 string='Rule count'
  • recurring_rule_type Selection
    default='months' string='Recurrence' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)'), ('years', 'Year(s)')]
  • subscription_count Integer
    compute='_compute_subscription_count' string='subscription_ids'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='template_id' string='Subscriptions'
Public methods (2)
  • action_view_product_ids(self)
  • action_view_subscription_ids(self)
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/18.0/subscription_oca
VERSION
VERSION 1.0.0
CATEGORY
CATEGORYSubscription Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Domatix, Onestein
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Domatix, Onestein
COMMITTERS
COMMITTERSWeblate, OCA-git-bot, tarteo, oca-ci
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:30:10
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - sale_management
    - sale
    - sales_team
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - html_editor
    - account_payment
    - account
    - onboarding
    - product
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - payment
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows creating subscriptions that generate recurring
invoices or orders. It also enables the sale of products that generate
subscriptions.

Code Analysis

Views touched (16)
XML IDNameModelTypeStatus
close_reason_wizard_view close.reason.wizard.view close.reason.wizard form New
product_template_form_view product.template.sub.form product.template xpath Inherits product.product_template_form_view
res_partner_view_form res.partner.form res.partner button Inherits base.view_partner_form
sale_subscription_form sale.subscription.form sale.subscription form New
sale_subscription_kanban sale.subscription.kanban sale.subscription kanban New
sale_subscription_template_form sale.subscription.template.form sale.subscription.template form New
sale_subscription_template_tree sale.subscription.template.list sale.subscription.template list New
sale_subscription_tree sale.subscription.list sale.subscription list New
view_move_form account.move xpath Inherits account.view_move_form
view_product_suscribable_filter product.suscribable.filter product.template search New
view_sale_order_form view.sale_order.form sale.order div Inherits sale.view_order_form
view_sale_order_pending_filter sale.order.pending.filter sale.subscription search New
view_sale_subscription_tag_tree view.sale.subscription.tag.list sale.subscription.tag list New
view_subscription_close_reason_tree view.subscription.close.reason.list sale.subscription.close.reason list New
view_subscription_stage_form view.subscription.stage.form sale.subscription.stage form New
view_subscription_stage_tree view.subscription.stage.list sale.subscription.stage list New
Models touched (12)

New fields (1)
  • subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
Public methods (1)
  • action_open_subscription(self)

New fields (1)
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Reason'
Public methods (1)
  • button_confirm(self)

New fields (2)
  • subscribable Boolean
    string='Subscribable product'
  • subscription_template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' string='Subscription template'
Public methods (0)

No public methods.

New fields (2)
  • subscription_count Integer
    compute='_compute_subscription_count' required=False
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='partner_id' string='Subscriptions'
Public methods (1)
  • action_view_subscription_ids(self)

New fields (3)
  • order_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='sale_order_id' string='Subscriptions'
  • subscriptions_count Integer
    compute='_compute_subscriptions_count'
Public methods (5)
  • action_confirm(self)
    Create a subscription per template from the Order's products
  • action_view_subscriptions(self)
  • create_subscription(self, lines, subscription_tmpl)
  • get_next_interval(self, type_interval, interval)
  • group_subscription_lines(self)
    Group Sale Order Lines by their product's subscription template

New fields (0)

No new fields.

Public methods (1)
  • get_subscription_line_values(self)

New fields (36)
  • account_invoice_ids_count Integer
    compute='_compute_account_invoice_ids_count' string='Invoice Count'
  • active Boolean
    default=True
  • amount_tax Monetary
    compute='_compute_total' store=True
  • amount_total Monetary
    compute='_compute_total' store=True
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Close Reason'
  • code Char
    default=<expr> string='Reference'
  • color Integer
    args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> index=True required=True args: 'res.company', 'Company'
  • crm_team_id Many2one → crm.team
    comodel_name='crm.team' string='Sale team'
  • currency_id Many2one
    depends=['pricelist_id'] ondelete='restrict' related='pricelist_id.currency_id' store=True
  • date Date
    compute='_compute_rule_boundary' readonly=False store=True string='Finish date'
  • date_start Date
    default=date.today() string='Start date'
  • description Text
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True domain="[('company_id', '=', company_id)]" string='Fiscal Position' args: 'account.fiscal.position'
  • image Binary
    related='user_id.image_512' store=True args: 'Image'
  • in_progress Boolean
    default=False string='In progress'
  • invoice_ids One2many → account.move
    comodel_name='account.move' inverse_name='subscription_id' string='Invoices'
  • journal_id Many2one → account.journal
    comodel_name='account.journal' string='Journal'
  • name Char
    compute='_compute_name' store=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True required=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' required=True string='Pricelist'
  • recurring_next_date Date
    default=date.today() string='Next invoice date'
  • recurring_rule_boundary Boolean
    compute='_compute_rule_boundary' store=True string='Boundary'
  • recurring_total Monetary
    compute='_compute_total' store=True string='Recurring price'
  • sale_order_id Many2one → sale.order
    comodel_name='sale.order' string='Origin sale order'
  • sale_order_ids One2many → sale.order
    comodel_name='sale.order' inverse_name='order_subscription_id' string='Orders'
  • sale_order_ids_count Integer
    compute='_compute_sale_order_ids_count' string='Sale orders'
  • sale_subscription_line_ids One2many → sale.subscription.line
    comodel_name='sale.subscription.line' inverse_name='sale_subscription_id'
  • sequence Integer
  • stage_id Many2one → sale.subscription.stage
    comodel_name='sale.subscription.stage' group_expand='_read_group_stage_ids' store=True string='Stage' tracking=True
  • stage_type Selection
    related='stage_id.type'
  • tag_ids Many2many → sale.subscription.tag
    comodel_name='sale.subscription.tag' string='Tags'
  • template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' required=True string='Subscription template'
  • terms Text
    compute='_compute_terms' readonly=False store=True string='Terms and conditions'
  • to_renew Boolean
    default=False string='To renew'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> string='Commercial agent'
Public methods (15)
  • action_close_subscription(self)
  • action_start_subscription(self)
  • action_view_account_invoice_ids(self)
  • action_view_sale_order_ids(self)
  • calculate_recurring_next_date(self, start_date)
  • close_subscription(self, close_reason_id=False)
  • create(self, vals_list)
    @api.model_create_multi
  • create_invoice(self)
  • create_sale_order(self)
  • cron_subscription_management(self)
    @api.model
  • generate_invoice(self)
  • manual_invoice(self)
  • onchange_partner_id(self)
    @api.onchange('partner_id')
  • onchange_partner_id_fpos(self)
    @api.onchange('partner_id', 'company_id')
  • write(self, values)

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (12)
  • amount_tax_line_amount Float
    compute='_compute_subtotal' store=True string='Taxes Amount'
  • company_id Many2one
    index=True related='sale_subscription_id.company_id' store=True string='Company'
  • currency_id Many2one → res.currency
    readonly=True related='sale_subscription_id.currency_id' store=True args: 'res.currency'
  • discount Float
    compute='_compute_discount' readonly=False store=True string='Discount (%)'
  • name Char
    compute='_compute_name' readonly=False store=True string='Description'
  • price_subtotal Monetary
    compute='_compute_subtotal' readonly=True store=True string='Subtotal'
  • price_total Monetary
    compute='_compute_subtotal' readonly=True store=True string='Total'
  • price_unit Float
    compute='_compute_price_unit' readonly=False store=True string='Unit price'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('sale_ok', '=', True)] string='Product'
  • product_uom_qty Float
    default=1.0 string='Quantity'
  • sale_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • tax_ids Many2many → account.tax
    column1='subscription_line_id' column2='tax_id' comodel_name='account.tax' compute='_compute_tax_ids' readonly=False relation='subscription_line_tax' store=True string='Taxes'
Public methods (0)

No public methods.

New fields (6)
  • description Text
    translate=True
  • fold Boolean
    string='Kanban folded'
  • in_progress Boolean
    default=False string='In progress'
  • name Char
    required=True translate=True
  • sequence Integer
  • type Selection
    default='pre' args: [('draft', 'Draft'), ('pre', 'Ready to start'), ('in_progress', 'In progress'), ('post', 'Closed')]
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True args: 'Tag name'
Public methods (0)

No public methods.

New fields (13)
  • code Char
  • description Text
    string='Terms and conditions'
  • invoice_mail_template_id Many2one → mail.template
    comodel_name='mail.template' domain="[('model', '=', 'account.move')]" string='Invoice Email'
  • invoicing_mode Selection
    default='draft' selection=[('draft', 'Draft'), ('invoice', 'Invoice'), ('invoice_send', 'Invoice & send'), ('sale_and_invoice', 'Sale order & Invoice')] string='Invoicing mode'
  • name Char
    required=True
  • product_ids One2many → product.template
    comodel_name='product.template' inverse_name='subscription_template_id' string='Products'
  • product_ids_count Integer
    compute='_compute_product_ids_count' string='product_ids'
  • recurring_interval Integer
    default=1 string='Repeat every'
  • recurring_rule_boundary Selection
    default='unlimited' string='Duration' args: [('unlimited', 'Forever'), ('limited', 'Fixed')]
  • recurring_rule_count Integer
    default=1 string='Rule count'
  • recurring_rule_type Selection
    default='months' string='Recurrence' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)'), ('years', 'Year(s)')]
  • subscription_count Integer
    compute='_compute_subscription_count' string='subscription_ids'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='template_id' string='Subscriptions'
Public methods (2)
  • action_view_product_ids(self)
  • action_view_subscription_ids(self)
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/17.0/subscription_oca
VERSION
VERSION 1.0.0
CATEGORY
CATEGORYSubscription Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Domatix
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Domatix
COMMITTERS
COMMITTERSWeblate, OCA-git-bot, oca-ci, sygel
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:20:04
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - sale_management
    - sale
    - sales_team
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - account_payment
    - account
    - onboarding
    - product
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - payment
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows creating subscriptions that generate recurring
invoices or orders. It also enables the sale of products that generate
subscriptions.

Code Analysis

Views touched (15)
XML IDNameModelTypeStatus
close_reason_wizard_view close.reason.wizard.view close.reason.wizard form New
product_template_form_view product.template.sub.form product.template xpath Inherits product.product_template_form_view
res_partner_view_form res.partner.form res.partner button Inherits base.view_partner_form
sale_subscription_form sale.subscription.form sale.subscription form New
sale_subscription_kanban sale.subscription.kanban sale.subscription kanban New
sale_subscription_template_form sale.subscription.template.form sale.subscription.template form New
sale_subscription_template_tree sale.subscription.template.tree sale.subscription.template tree New
sale_subscription_tree sale.subscription.tree sale.subscription tree New
view_product_suscribable_filter product.suscribable.filter product.template search New
view_sale_order_form view.sale_order.form sale.order div Inherits sale.view_order_form
view_sale_order_pending_filter sale.order.pending.filter sale.subscription search New
view_sale_subscription_tag_tree view.sale.subscription.tag.tree sale.subscription.tag tree New
view_subscription_close_reason_tree view.subscription.close.reason.tree sale.subscription.close.reason tree New
view_subscription_stage_form view.subscription.stage.form sale.subscription.stage form New
view_subscription_stage_tree view.subscription.stage.tree sale.subscription.stage tree New
Models touched (12)

New fields (1)
  • subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
Public methods (0)

No public methods.

New fields (1)
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Reason'
Public methods (1)
  • button_confirm(self)

New fields (2)
  • subscribable Boolean
    string='Subscribable product'
  • subscription_template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' string='Subscription template'
Public methods (0)

No public methods.

New fields (2)
  • subscription_count Integer
    compute='_compute_subscription_count' required=False
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='partner_id' string='Subscriptions'
Public methods (1)
  • action_view_subscription_ids(self)

New fields (3)
  • order_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='sale_order_id' string='Subscriptions'
  • subscriptions_count Integer
    compute='_compute_subscriptions_count'
Public methods (5)
  • action_confirm(self)
  • action_view_subscriptions(self)
  • create_subscription(self, lines, subscription_tmpl)
  • get_next_interval(self, type_interval, interval)
  • group_subscription_lines(self)

New fields (0)

No new fields.

Public methods (1)
  • get_subscription_line_values(self)

New fields (35)
  • account_invoice_ids_count Integer
    compute='_compute_account_invoice_ids_count' string='Invoice Count'
  • active Boolean
    default=True
  • amount_tax Monetary
    compute='_compute_total' store=True
  • amount_total Monetary
    compute='_compute_total' store=True
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Close Reason'
  • code Char
    default=<expr> string='Reference'
  • color Integer
    args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> index=True required=True args: 'res.company', 'Company'
  • crm_team_id Many2one → crm.team
    comodel_name='crm.team' string='Sale team'
  • currency_id Many2one
    depends=['pricelist_id'] ondelete='restrict' related='pricelist_id.currency_id' store=True
  • date Date
    compute='_compute_rule_boundary' readonly=False store=True string='Finish date'
  • date_start Date
    default=date.today() string='Start date'
  • description Text
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True domain="[('company_id', '=', company_id)]" string='Fiscal Position' args: 'account.fiscal.position'
  • image Binary
    related='user_id.image_512' store=True args: 'Image'
  • in_progress Boolean
    default=False string='In progress'
  • invoice_ids One2many → account.move
    comodel_name='account.move' inverse_name='subscription_id' string='Invoices'
  • journal_id Many2one → account.journal
    comodel_name='account.journal' string='Journal'
  • name Char
    compute='_compute_name' store=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True required=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' required=True string='Pricelist'
  • recurring_next_date Date
    default=date.today() string='Next invoice date'
  • recurring_rule_boundary Boolean
    compute='_compute_rule_boundary' store=True string='Boundary'
  • recurring_total Monetary
    compute='_compute_total' store=True string='Recurring price'
  • sale_order_id Many2one → sale.order
    comodel_name='sale.order' string='Origin sale order'
  • sale_order_ids One2many → sale.order
    comodel_name='sale.order' inverse_name='order_subscription_id' string='Orders'
  • sale_order_ids_count Integer
    compute='_compute_sale_order_ids_count' string='Sale orders'
  • sale_subscription_line_ids One2many → sale.subscription.line
    comodel_name='sale.subscription.line' inverse_name='sale_subscription_id'
  • sequence Integer
  • stage_id Many2one → sale.subscription.stage
    comodel_name='sale.subscription.stage' group_expand='_read_group_stage_ids' store=True string='Stage' tracking=True
  • tag_ids Many2many → sale.subscription.tag
    comodel_name='sale.subscription.tag' string='Tags'
  • template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' required=True string='Subscription template'
  • terms Text
    compute='_compute_terms' readonly=False store=True string='Terms and conditions'
  • to_renew Boolean
    default=False string='To renew'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> string='Commercial agent'
Public methods (14)
  • action_close_subscription(self)
  • action_start_subscription(self)
  • action_view_account_invoice_ids(self)
  • action_view_sale_order_ids(self)
  • calculate_recurring_next_date(self, start_date)
  • create(self, vals_list)
    @api.model_create_multi
  • create_invoice(self)
  • create_sale_order(self)
  • cron_subscription_management(self)
  • generate_invoice(self)
  • manual_invoice(self)
  • onchange_partner_id(self)
    @api.onchange('partner_id')
  • onchange_partner_id_fpos(self)
    @api.onchange('partner_id', 'company_id')
  • write(self, values)

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (12)
  • amount_tax_line_amount Float
    compute='_compute_subtotal' store=True string='Taxes Amount'
  • company_id Many2one
    index=True related='sale_subscription_id.company_id' store=True string='Company'
  • currency_id Many2one → res.currency
    readonly=True related='sale_subscription_id.currency_id' store=True args: 'res.currency'
  • discount Float
    compute='_compute_discount' readonly=False store=True string='Discount (%)'
  • name Char
    compute='_compute_name' readonly=False store=True string='Description'
  • price_subtotal Monetary
    compute='_compute_subtotal' readonly=True store=True string='Subtotal'
  • price_total Monetary
    compute='_compute_subtotal' readonly=True store=True string='Total'
  • price_unit Float
    compute='_compute_price_unit' readonly=False store=True string='Unit price'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('sale_ok', '=', True)] string='Product'
  • product_uom_qty Float
    default=1.0 string='Quantity'
  • sale_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • tax_ids Many2many → account.tax
    column1='subscription_line_id' column2='tax_id' comodel_name='account.tax' compute='_compute_tax_ids' readonly=False relation='subscription_line_tax' store=True string='Taxes'
Public methods (0)

No public methods.

New fields (7)
  • description Text
    translate=True
  • display_name Char
    compute='_compute_display_name' string='Display name'
  • fold Boolean
    string='Kanban folded'
  • in_progress Boolean
    default=False string='In progress'
  • name Char
    required=True translate=True
  • sequence Integer
  • type Selection
    default='pre' args: [('pre', 'Ready to start'), ('in_progress', 'In progress'), ('post', 'Closed')]
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True args: 'Tag name'
Public methods (0)

No public methods.

New fields (13)
  • code Char
  • description Text
    string='Terms and conditions'
  • invoice_mail_template_id Many2one → mail.template
    comodel_name='mail.template' domain="[('model', '=', 'account.move')]" string='Invoice Email'
  • invoicing_mode Selection
    default='draft' selection=[('draft', 'Draft'), ('invoice', 'Invoice'), ('invoice_send', 'Invoice & send'), ('sale_and_invoice', 'Sale order & Invoice')] string='Invoicing mode'
  • name Char
    required=True
  • product_ids One2many → product.template
    comodel_name='product.template' inverse_name='subscription_template_id' string='Products'
  • product_ids_count Integer
    compute='_compute_product_ids_count' string='product_ids'
  • recurring_interval Integer
    default=1 string='Repeat every'
  • recurring_rule_boundary Selection
    default='unlimited' string='Duration' args: [('unlimited', 'Forever'), ('limited', 'Fixed')]
  • recurring_rule_count Integer
    default=1 string='Rule count'
  • recurring_rule_type Selection
    default='months' string='Recurrence' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)'), ('years', 'Year(s)')]
  • subscription_count Integer
    compute='_compute_subscription_count' string='subscription_ids'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='template_id' string='Subscriptions'
Public methods (2)
  • action_view_product_ids(self)
  • action_view_subscription_ids(self)
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/16.0/subscription_oca
VERSION
VERSION 1.3.1
CATEGORY
CATEGORYSubscription Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Domatix
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Domatix
COMMITTERS
COMMITTERSeLBati, Enric Tobella, Weblate, OCA-git-bot, tarteo, oca-ci, Carol, Ivan Vilata-i-Balaguer, Quentin Mondot
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:53:43
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - sale_management
    - sale
    - sales_team
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - account_payment
    - account
    - product
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - payment
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (16)
XML IDNameModelTypeStatus
close_reason_wizard_view close.reason.wizard.view close.reason.wizard form New
product_template_form_view product.template.sub.form product.template xpath Inherits product.product_template_form_view
res_partner_view_form res.partner.form res.partner button Inherits base.view_partner_form
sale_subscription_form sale.subscription.form sale.subscription form New
sale_subscription_kanban sale.subscription.kanban sale.subscription kanban New
sale_subscription_template_form sale.subscription.template.form sale.subscription.template form New
sale_subscription_template_tree sale.subscription.template.tree sale.subscription.template tree New
sale_subscription_tree sale.subscription.tree sale.subscription tree New
view_move_form account.move xpath Inherits account.view_move_form
view_product_suscribable_filter product.suscribable.filter product.template search New
view_sale_order_form view.sale_order.form sale.order div Inherits sale.view_order_form
view_sale_order_pending_filter sale.order.pending.filter sale.subscription search New
view_sale_subscription_tag_tree view.sale.subscription.tag.tree sale.subscription.tag tree New
view_subscription_close_reason_tree view.subscription.close.reason.tree sale.subscription.close.reason tree New
view_subscription_stage_form view.subscription.stage.form sale.subscription.stage form New
view_subscription_stage_tree view.subscription.stage.tree sale.subscription.stage tree New
Models touched (12)

New fields (1)
  • subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
Public methods (1)
  • action_open_subscription(self)

New fields (1)
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Reason'
Public methods (1)
  • button_confirm(self)

New fields (2)
  • subscribable Boolean
    string='Subscribable product'
  • subscription_template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' string='Subscription template'
Public methods (0)

No public methods.

New fields (2)
  • subscription_count Integer
    compute='_compute_subscription_count' required=False
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='partner_id' string='Subscriptions'
Public methods (1)
  • action_view_subscription_ids(self)

New fields (3)
  • order_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='sale_order_id' string='Subscriptions'
  • subscriptions_count Integer
    compute='_compute_subscriptions_count'
Public methods (5)
  • action_confirm(self)
  • action_view_subscriptions(self)
  • create_subscription(self, lines, subscription_tmpl)
  • get_next_interval(self, type_interval, interval)
  • group_subscription_lines(self)

New fields (0)

No new fields.

Public methods (1)
  • get_subscription_line_values(self)

New fields (36)
  • account_invoice_ids_count Integer
    compute='_compute_account_invoice_ids_count' string='Invoice Count'
  • active Boolean
    default=True
  • amount_tax Monetary
    compute='_compute_total' store=True
  • amount_total Monetary
    compute='_compute_total' store=True
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Close Reason'
  • code Char
    default=<expr> string='Reference'
  • color Integer
    args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> index=True required=True args: 'res.company', 'Company'
  • crm_team_id Many2one → crm.team
    comodel_name='crm.team' string='Sale team'
  • currency_id Many2one
    depends=['pricelist_id'] ondelete='restrict' related='pricelist_id.currency_id' store=True
  • date Date
    compute='_compute_rule_boundary' readonly=False store=True string='Finish date'
  • date_start Date
    default=date.today() string='Start date'
  • description Text
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True domain="[('company_id', '=', company_id)]" string='Fiscal Position' args: 'account.fiscal.position'
  • image Binary
    related='user_id.image_512' store=True args: 'Image'
  • in_progress Boolean
    default=False string='In progress'
  • invoice_ids One2many → account.move
    comodel_name='account.move' inverse_name='subscription_id' string='Invoices'
  • journal_id Many2one → account.journal
    comodel_name='account.journal' string='Journal'
  • name Char
    compute='_compute_name' store=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True required=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' required=True string='Pricelist'
  • recurring_next_date Date
    default=date.today() string='Next invoice date'
  • recurring_rule_boundary Boolean
    compute='_compute_rule_boundary' store=True string='Boundary'
  • recurring_total Monetary
    compute='_compute_total' store=True string='Recurring price'
  • sale_order_id Many2one → sale.order
    comodel_name='sale.order' string='Origin sale order'
  • sale_order_ids One2many → sale.order
    comodel_name='sale.order' inverse_name='order_subscription_id' string='Orders'
  • sale_order_ids_count Integer
    compute='_compute_sale_order_ids_count' string='Sale orders'
  • sale_subscription_line_ids One2many → sale.subscription.line
    comodel_name='sale.subscription.line' inverse_name='sale_subscription_id'
  • sequence Integer
  • stage_id Many2one → sale.subscription.stage
    comodel_name='sale.subscription.stage' group_expand='_read_group_stage_ids' store=True string='Stage' tracking=True
  • stage_str Char
    related='stage_id.name' store=True string='Etapa'
  • tag_ids Many2many → sale.subscription.tag
    comodel_name='sale.subscription.tag' string='Tags'
  • template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' required=True string='Subscription template'
  • terms Text
    compute='_compute_terms' readonly=False store=True string='Terms and conditions'
  • to_renew Boolean
    default=False string='To renew'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> string='Commercial agent'
Public methods (15)
  • action_close_subscription(self)
  • action_start_subscription(self)
  • action_view_account_invoice_ids(self)
  • action_view_sale_order_ids(self)
  • calculate_recurring_next_date(self, start_date)
  • close_subscription(self, close_reason_id=False)
  • create(self, values)
    @api.model
  • create_invoice(self)
  • create_sale_order(self)
  • cron_subscription_management(self)
  • generate_invoice(self)
  • manual_invoice(self)
  • onchange_partner_id(self)
    @api.onchange('partner_id')
  • onchange_partner_id_fpos(self)
    @api.onchange('partner_id', 'company_id')
  • write(self, values)

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (12)
  • amount_tax_line_amount Float
    compute='_compute_subtotal' store=True string='Taxes Amount'
  • company_id Many2one
    index=True related='sale_subscription_id.company_id' store=True string='Company'
  • currency_id Many2one → res.currency
    readonly=True related='sale_subscription_id.currency_id' store=True args: 'res.currency'
  • discount Float
    compute='_compute_discount' readonly=False store=True string='Discount (%)'
  • name Char
    compute='_compute_name' readonly=False store=True string='Description'
  • price_subtotal Monetary
    compute=_compute_subtotal readonly='True' store=True string='Subtotal'
  • price_total Monetary
    compute=_compute_subtotal readonly='True' store=True string='Total'
  • price_unit Float
    compute='_compute_price_unit' readonly=False store=True string='Unit price'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('sale_ok', '=', True)] string='Product'
  • product_uom_qty Float
    default=1.0 string='Quantity'
  • sale_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • tax_ids Many2many → account.tax
    column1='subscription_line_id' column2='tax_id' comodel_name='account.tax' compute='_compute_tax_ids' readonly=False relation='subscription_line_tax' store=True string='Taxes'
Public methods (0)

No public methods.

New fields (7)
  • description Text
    translate=True
  • display_name Char
    compute='_compute_display_name' string='Display name'
  • fold Boolean
    string='Kanban folded'
  • in_progress Boolean
    default=False string='In progress'
  • name Char
    required=True translate=True
  • sequence Integer
  • type Selection
    default='pre' args: [('draft', 'Draft'), ('pre', 'Ready to start'), ('in_progress', 'In progress'), ('post', 'Closed')]
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True args: 'Tag name'
Public methods (0)

No public methods.

New fields (13)
  • code Char
  • description Text
    string='Terms and conditions'
  • invoice_mail_template_id Many2one → mail.template
    comodel_name='mail.template' domain="[('model', '=', 'account.move')]" string='Invoice Email'
  • invoicing_mode Selection
    default='draft' selection=[('draft', 'Draft'), ('invoice', 'Invoice'), ('invoice_send', 'Invoice & send'), ('sale_and_invoice', 'Sale order & Invoice')] string='Invoicing mode'
  • name Char
    required=True
  • product_ids One2many → product.template
    comodel_name='product.template' inverse_name='subscription_template_id' string='Products'
  • product_ids_count Integer
    compute='_compute_product_ids_count' string='product_ids'
  • recurring_interval Integer
    default=1 string='Repeat every'
  • recurring_rule_boundary Selection
    default='unlimited' string='Duration' args: [('unlimited', 'Forever'), ('limited', 'Fixed')]
  • recurring_rule_count Integer
    default=1 string='Rule count'
  • recurring_rule_type Selection
    default='months' string='Recurrence' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)'), ('years', 'Year(s)')]
  • subscription_count Integer
    compute='_compute_subscription_count' string='subscription_ids'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='template_id' string='Subscriptions'
Public methods (2)
  • action_view_product_ids(self)
  • action_view_subscription_ids(self)
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/15.0/subscription_oca
VERSION
VERSION 1.1.1
CATEGORY
CATEGORYSubscription Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Domatix
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Domatix
COMMITTERS
COMMITTERSVíctor Martínez, Weblate, OCA-git-bot, oca-ci, Carlos, Ilyas, David García
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:46:32
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - sale_management
    - sale
    - sales_team
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - payment
    - account
    - product
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (15)
XML IDNameModelTypeStatus
close_reason_wizard_view close.reason.wizard.view close.reason.wizard form New
product_template_form_view product.template.sub.form product.template xpath Inherits product.product_template_form_view
res_partner_view_form res.partner.form res.partner div Inherits base.view_partner_form
sale_subscription_form sale.subscription.form sale.subscription form New
sale_subscription_kanban sale.subscription.kanban sale.subscription kanban New
sale_subscription_template_form sale.subscription.template.form sale.subscription.template form New
sale_subscription_template_tree sale.subscription.template.tree sale.subscription.template tree New
sale_subscription_tree sale.subscription.tree sale.subscription tree New
view_product_suscribable_filter product.suscribable.filter product.template search New
view_sale_order_form view.sale_order.form sale.order div Inherits sale.view_order_form
view_sale_order_pending_filter sale.order.pending.filter sale.subscription search New
view_sale_subscription_tag_tree view.sale.subscription.tag.tree sale.subscription.tag tree New
view_subscription_close_reason_tree view.subscription.close.reason.tree sale.subscription.close.reason tree New
view_subscription_stage_form view.subscription.stage.form sale.subscription.stage form New
view_subscription_stage_tree view.subscription.stage.tree sale.subscription.stage tree New
Models touched (12)

New fields (1)
  • subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
Public methods (0)

No public methods.

New fields (1)
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Reason'
Public methods (1)
  • button_confirm(self)

New fields (2)
  • subscribable Boolean
    string='Subscribable product'
  • subscription_template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' string='Subscription template'
Public methods (0)

No public methods.

New fields (2)
  • subscription_count Integer
    compute='_compute_subscription_count' required=False
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='partner_id' string='Subscriptions'
Public methods (1)
  • action_view_subscription_ids(self)

New fields (3)
  • order_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='sale_order_id' string='Subscriptions'
  • subscriptions_count Integer
    compute='_compute_subscriptions_count'
Public methods (5)
  • action_confirm(self)
  • action_view_subscriptions(self)
  • create_subscription(self, lines, subscription_tmpl)
  • get_next_interval(self, type_interval, interval)
  • group_subscription_lines(self)

New fields (0)

No new fields.

Public methods (1)
  • get_subscription_line_values(self)

New fields (36)
  • account_invoice_ids_count Integer
    compute='_compute_account_invoice_ids_count' string='Invoice Count'
  • active Boolean
    default=True
  • amount_tax Monetary
    compute='_compute_total' store=True
  • amount_total Monetary
    compute='_compute_total' store=True
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Close Reason'
  • code Char
    default=<expr> string='Reference'
  • color Integer
    args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> index=True required=True args: 'res.company', 'Company'
  • crm_team_id Many2one → crm.team
    comodel_name='crm.team' string='Sale team'
  • currency_id Many2one
    depends=['pricelist_id'] ondelete='restrict' related='pricelist_id.currency_id' store=True
  • date Date
    compute='_compute_rule_boundary' readonly=False store=True string='Finish date'
  • date_start Date
    default=date.today() string='Start date'
  • description Text
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True domain="[('company_id', '=', company_id)]" string='Fiscal Position' args: 'account.fiscal.position'
  • image Binary
    related='user_id.image_512' store=True args: 'Image'
  • in_progress Boolean
    default=False string='In progress'
  • invoice_ids One2many → account.move
    comodel_name='account.move' inverse_name='subscription_id' string='Invoices'
  • journal_id Many2one → account.journal
    comodel_name='account.journal' string='Journal'
  • name Char
    compute='_compute_name' store=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True required=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' required=True string='Pricelist'
  • recurring_next_date Date
    default=date.today() string='Next invoice date'
  • recurring_rule_boundary Boolean
    compute='_compute_rule_boundary' store=True string='Boundary'
  • recurring_total Monetary
    compute='_compute_total' store=True string='Recurring price'
  • sale_order_id Many2one → sale.order
    comodel_name='sale.order' string='Origin sale order'
  • sale_order_ids One2many → sale.order
    comodel_name='sale.order' inverse_name='order_subscription_id' string='Orders'
  • sale_order_ids_count Integer
    compute='_compute_sale_order_ids_count' string='Sale orders'
  • sale_subscription_line_ids One2many → sale.subscription.line
    comodel_name='sale.subscription.line' inverse_name='sale_subscription_id'
  • sequence Integer
  • stage_id Many2one → sale.subscription.stage
    comodel_name='sale.subscription.stage' group_expand='_read_group_stage_ids' store='true' string='Stage' tracking=True
  • stage_str Char
    related='stage_id.name' store=True string='Etapa'
  • tag_ids Many2many → sale.subscription.tag
    comodel_name='sale.subscription.tag' string='Tags'
  • template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' required=True string='Subscription template'
  • terms Text
    compute='_compute_terms' readonly=False store=True string='Terms and conditions'
  • to_renew Boolean
    default=False string='To renew'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> string='Commercial agent'
Public methods (14)
  • action_close_subscription(self)
  • action_start_subscription(self)
  • action_view_account_invoice_ids(self)
  • action_view_sale_order_ids(self)
  • calculate_recurring_next_date(self, start_date)
  • create(self, values)
    @api.model
  • create_invoice(self)
  • create_sale_order(self)
  • cron_subscription_management(self)
  • generate_invoice(self)
  • manual_invoice(self)
  • onchange_partner_id(self)
    @api.onchange('partner_id')
  • onchange_partner_id_fpos(self)
    @api.onchange('partner_id', 'company_id')
  • write(self, values)

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (12)
  • amount_tax_line_amount Float
    compute='_compute_subtotal' store=True string='Taxes Amount'
  • company_id Many2one
    index=True related='sale_subscription_id.company_id' store=True string='Company'
  • currency_id Many2one → res.currency
    readonly=True related='sale_subscription_id.currency_id' store=True args: 'res.currency'
  • discount Float
    compute='_compute_discount' readonly=False store=True string='Discount (%)'
  • name Char
    compute='_compute_name' readonly=False store=True string='Description'
  • price_subtotal Monetary
    compute=_compute_subtotal readonly='True' store=True string='Subtotal'
  • price_total Monetary
    compute=_compute_subtotal readonly='True' store=True string='Total'
  • price_unit Float
    compute='_compute_price_unit' readonly=False store=True string='Unit price'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('sale_ok', '=', True)] string='Product'
  • product_uom_qty Float
    default=1.0 string='Quantity'
  • sale_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • tax_ids Many2many → account.tax
    column1='subscription_line_id' column2='tax_id' comodel_name='account.tax' compute='_compute_tax_ids' readonly=False relation='subscription_line_tax' store=True string='Taxes'
Public methods (0)

No public methods.

New fields (7)
  • description Text
    translate=True
  • display_name Char
    string='Display name'
  • fold Boolean
    string='Kanban folded'
  • in_progress Boolean
    default=False string='In progress'
  • name Char
    required=True translate=True
  • sequence Integer
  • type Selection
    default='pre' args: [('pre', 'Ready to start'), ('in_progress', 'In progress'), ('post', 'Closed')]
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True args: 'Tag name'
Public methods (0)

No public methods.

New fields (13)
  • code Char
  • description Text
    string='Terms and conditions'
  • invoice_mail_template_id Many2one → mail.template
    comodel_name='mail.template' domain="[('model', '=', 'account.move')]" string='Invoice Email'
  • invoicing_mode Selection
    default='draft' selection=[('draft', 'Draft'), ('invoice', 'Invoice'), ('invoice_send', 'Invoice & send'), ('sale_and_invoice', 'Sale order & Invoice')] string='Invoicing mode'
  • name Char
    required=True
  • product_ids One2many → product.template
    comodel_name='product.template' inverse_name='subscription_template_id' string='Products'
  • product_ids_count Integer
    compute='_compute_product_ids_count' string='product_ids'
  • recurring_interval Integer
    default=1 string='Repeat every'
  • recurring_rule_boundary Selection
    default='unlimited' string='Duration' args: [('unlimited', 'Forever'), ('limited', 'Fixed')]
  • recurring_rule_count Integer
    default=1 string='Rule count'
  • recurring_rule_type Selection
    default='months' string='Recurrence' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)'), ('years', 'Year(s)')]
  • subscription_count Integer
    compute='_compute_subscription_count' string='subscription_ids'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='template_id' string='Subscriptions'
Public methods (2)
  • action_view_product_ids(self)
  • action_view_subscription_ids(self)
REPOSITORY
REPOSITORYOCA/contract
GIT
GIThttps://github.com/OCA/contract.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/contract/tree/14.0/subscription_oca
VERSION
VERSION 2.0.0
CATEGORY
CATEGORYSubscription Management
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Domatix
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Domatix
COMMITTERS
COMMITTERSPedro M. Baeza, Weblate, OCA-git-bot, oca-ci, Giovanni, Alessandro Uffreduzzi, Ilyas, Alessio Renda, PicchiSeba
WEBSITE
WEBSITEhttps://github.com/OCA/contract
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:40:55
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - sale_management
    - sale
    - sales_team
    - base
    - mail
    - base_setup
    - web
    - bus
    - web_tour
    - payment
    - account
    - product
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (16)
XML IDNameModelTypeStatus
close_reason_wizard_view close.reason.wizard.view close.reason.wizard form New
product_template_form_view product.template.sub.form product.template xpath Inherits product.product_template_form_view
res_partner_view_form res.partner.form res.partner button Inherits account.partner_view_buttons
sale_subscription_form sale.subscription.form sale.subscription form New
sale_subscription_kanban sale.subscription.kanban sale.subscription kanban New
sale_subscription_template_form sale.subscription.template.form sale.subscription.template form New
sale_subscription_template_tree sale.subscription.template.tree sale.subscription.template tree New
sale_subscription_tree sale.subscription.tree sale.subscription tree New
view_product_suscribable_filter product.suscribable.filter product.template search New
view_sale_order_form view.sale_order.form sale.order div Inherits sale.view_order_form
view_sale_order_pending_filter sale.order.pending.filter sale.subscription search New
view_sale_subscription_tag_tree view.sale.subscription.tag.tree sale.subscription.tag tree New
view_sale_subscription_template_filter sale.subscription.template.filter sale.subscription.template search New
view_subscription_close_reason_tree view.subscription.close.reason.tree sale.subscription.close.reason tree New
view_subscription_stage_form view.subscription.stage.form sale.subscription.stage form New
view_subscription_stage_tree view.subscription.stage.tree sale.subscription.stage tree New
Models touched (12)

New fields (1)
  • subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
Public methods (0)

No public methods.

New fields (1)
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Reason'
Public methods (1)
  • button_confirm(self)

New fields (2)
  • subscribable Boolean
    string='Subscribable product'
  • subscription_template_id Many2one → sale.subscription.template
    comodel_name='sale.subscription.template' company_dependent=True string='Subscription template'
Public methods (0)

No public methods.

New fields (2)
  • subscription_count Integer
    compute='_compute_subscription_count' required=False
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='partner_id' string='Subscriptions'
Public methods (1)
  • action_view_subscription_ids(self)

New fields (3)
  • order_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='sale_order_id' string='Subscriptions'
  • subscriptions_count Integer
    compute='_compute_subscriptions_count'
Public methods (5)
  • action_confirm(self)
  • action_view_subscriptions(self)
  • create_subscription(self, lines, subscription_tmpl)
  • get_next_interval(self, type_interval, interval)
  • group_subscription_lines(self)

New fields (0)

No new fields.

Public methods (1)
  • get_subscription_line_values(self)

New fields (37)
  • account_invoice_ids_count Integer
    compute='_compute_account_invoice_ids_count' string='Invoice Count'
  • active Boolean
    default=True
  • amount_tax Monetary
    compute='_compute_total' store=True
  • amount_total Monetary
    compute='_compute_total' store=True
  • close_reason_id Many2one → sale.subscription.close.reason
    comodel_name='sale.subscription.close.reason' string='Close Reason'
  • code Char
    default=<expr> string='Reference'
  • color Integer
    args: 'Color Index'
  • company_id Many2one → res.company
    default=<expr> index=True readonly=True required=True args: 'res.company', 'Company'
  • crm_team_id Many2one → crm.team
    comodel_name='crm.team' string='Sale team'
  • currency_id Many2one
    depends=['pricelist_id'] ondelete='restrict' related='pricelist_id.currency_id' store=True
  • date Date
    compute='_compute_rule_boundary' readonly=False store=True string='Finish date'
  • date_start Date
    default=date.today() string='Start date'
  • description Text
  • fiscal_position_id Many2one → account.fiscal.position
    check_company=True domain="[('company_id', '=', company_id)]" string='Fiscal Position' args: 'account.fiscal.position'
  • image Binary
    related='user_id.image_512' store=True args: 'Image'
  • in_progress Boolean
    default=False string='In progress'
  • invoice_ids One2many → account.move
    comodel_name='account.move' inverse_name='subscription_id' string='Invoices'
  • journal_id Many2one → account.journal
    comodel_name='account.journal' string='Journal'
  • name Char
    compute='_compute_name' store=True
  • partner_id Many2one → res.partner
    comodel_name='res.partner' index=True required=True string='Partner'
  • pricelist_id Many2one → product.pricelist
    comodel_name='product.pricelist' required=True string='Pricelist'
  • recurring_next_date Date
    default=date.today() string='Next invoice date'
  • recurring_rule_boundary Boolean
    compute='_compute_rule_boundary' store=True string='Boundary'
  • recurring_total Monetary
    compute='_compute_total' store=True string='Recurring price'
  • sale_order_id Many2one → sale.order
    comodel_name='sale.order' string='Origin sale order'
  • sale_order_ids One2many → sale.order
    comodel_name='sale.order' inverse_name='order_subscription_id' string='Orders'
  • sale_order_ids_count Integer
    compute='_compute_sale_order_ids_count' string='Sale orders'
  • sale_subscription_line_ids One2many → sale.subscription.line
    comodel_name='sale.subscription.line' inverse_name='sale_subscription_id'
  • sequence Integer
  • stage_id Many2one → sale.subscription.stage
    comodel_name='sale.subscription.stage' group_expand='_read_group_stage_ids' store='true' string='Stage' tracking=True
  • stage_str Char
    related='stage_id.name' store=True string='Stage'
  • tag_ids Many2many → sale.subscription.tag
    comodel_name='sale.subscription.tag' string='Tags'
  • template_id Many2one → sale.subscription.template
    check_company=True comodel_name='sale.subscription.template' required=True string='Subscription template'
  • template_invoicing_mode Selection
    readonly=True related='template_id.invoicing_mode'
  • terms Text
    compute='_compute_terms' readonly=False store=True string='Terms and conditions'
  • to_renew Boolean
    default=False string='To renew'
  • user_id Many2one → res.users
    comodel_name='res.users' default=<expr> string='Commercial agent'
Public methods (17)
  • action_close_subscription(self)
  • action_start_subscription(self)
  • action_view_account_invoice_ids(self)
  • action_view_sale_order_ids(self)
  • calculate_recurring_next_date(self, start_date)
  • create(self, values)
    @api.model
  • create_invoice(self)
  • create_sale_order(self)
  • cron_subscription_management(self)
  • generate_invoice(self)
  • manual_invoice(self)
  • manual_invoice_and_sale_order(self)
  • manual_sale_order(self)
  • onchange_partner_id(self)
    @api.onchange('partner_id')
  • onchange_partner_id_fpos(self)
    @api.onchange('partner_id', 'company_id')
  • send_invoice(self, invoice)
  • write(self, values)

New fields (1)
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (12)
  • amount_tax_line_amount Float
    compute='_compute_subtotal' store=True string='Taxes Amount'
  • company_id Many2one
    index=True related='sale_subscription_id.company_id' store=True string='Company'
  • currency_id Many2one → res.currency
    readonly=True related='sale_subscription_id.currency_id' store=True args: 'res.currency'
  • discount Float
    compute='_compute_discount' readonly=False store=True string='Discount (%)'
  • name Char
    compute='_compute_name' readonly=False store=True string='Description'
  • price_subtotal Monetary
    compute=_compute_subtotal readonly='True' store=True string='Subtotal'
  • price_total Monetary
    compute=_compute_subtotal readonly='True' store=True string='Total'
  • price_unit Float
    compute='_compute_price_unit' readonly=False store=True string='Unit price'
  • product_id Many2one → product.product
    comodel_name='product.product' domain=[('sale_ok', '=', True)] string='Product'
  • product_uom_qty Float
    default=1.0 string='Quantity'
  • sale_subscription_id Many2one → sale.subscription
    comodel_name='sale.subscription' string='Subscription'
  • tax_ids Many2many → account.tax
    column1='subscription_line_id' column2='tax_id' comodel_name='account.tax' compute='_compute_tax_ids' readonly=False relation='subscription_line_tax' store=True string='Taxes'
Public methods (0)

No public methods.

New fields (7)
  • description Text
    translate=True
  • display_name Char
    string='Display name'
  • fold Boolean
    string='Kanban folded'
  • in_progress Boolean
    default=False string='In progress'
  • name Char
    required=True translate=True
  • sequence Integer
  • type Selection
    default='pre' args: [('pre', 'Ready to start'), ('in_progress', 'In progress'), ('post', 'Closed')]
Public methods (0)

No public methods.

New fields (1)
  • name Char
    required=True args: 'Tag name'
Public methods (0)

No public methods.

New fields (14)
  • code Char
  • company_id Many2one → res.company
    default=<expr> domain=<expr> required=True args: 'res.company', 'Company'
  • description Text
    string='Terms and conditions'
  • invoice_mail_template_id Many2one → mail.template
    comodel_name='mail.template' domain="[('model', '=', 'account.move')]" string='Invoice Email'
  • invoicing_mode Selection
    default='draft' selection=[('draft', 'Draft'), ('invoice', 'Invoice'), ('invoice_send', 'Invoice & send'), ('sale_and_invoice', 'Sale Order & Invoice'), ('sale_and_invoice_draft', 'Sale Order & Invoice Draft'), ('sale_and_invoice_send', 'Sale Order & Invoice send'), ('sale_draft', 'Sale Order Draft'), ('sale_confirmed', 'Sale Order Confirmed')] string='Invoicing mode'
  • name Char
    required=True
  • product_ids One2many → product.template
    comodel_name='product.template' inverse_name='subscription_template_id' string='Products'
  • product_ids_count Integer
    compute='_compute_product_ids_count' string='product_ids'
  • recurring_interval Integer
    default=1 string='Repeat every'
  • recurring_rule_boundary Selection
    default='unlimited' string='Duration' args: [('unlimited', 'Forever'), ('limited', 'Fixed')]
  • recurring_rule_count Integer
    default=1 string='Rule count'
  • recurring_rule_type Selection
    default='months' string='Recurrence' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)'), ('years', 'Year(s)')]
  • subscription_count Integer
    compute='_compute_subscription_count' string='subscription_ids'
  • subscription_ids One2many → sale.subscription
    comodel_name='sale.subscription' inverse_name='template_id' string='Subscriptions'
Public methods (3)
  • action_view_product_ids(self)
  • action_view_subscription_ids(self)
  • get_relative_delta(self)