1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/sale_subscription/models/sale_subscription_plan.py
2024-12-10 09:04:09 +07:00

127 lines
6.9 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _, _lt, Command
from odoo.tools import get_timedelta
from odoo.exceptions import ValidationError
class SaleSubscriptionPlan(models.Model):
_name = 'sale.subscription.plan'
_description = 'Subscription Plan'
active = fields.Boolean(default=True)
name = fields.Char(translate=True, required=True, default="Monthly")
company_id = fields.Many2one('res.company')
# Billing Period, use billing_period property for access to the timedelta
billing_period_value = fields.Integer(string="Duration", required=True, default=1)
billing_period_unit = fields.Selection([("week", "Weeks"), ("month", "Months"), ('year', 'Years')],
string="Unit", required=True, default='month')
billing_period_display = fields.Char(compute='_compute_billing_period_display', string="Billing Period")
billing_period_display_sentence = fields.Char(compute='_compute_billing_period_display_sentence', string="Billing Period Display")
# Self Service
user_closable = fields.Boolean(string="Closable", default=False,
help="Customer can close their subscriptions.")
user_extend = fields.Boolean("Renew", default=False,
help="Customer can create a renewal quotation for their subscription.")
user_quantity = fields.Boolean("Add Products", default=False,
help="Allow customers to create an Upsell quote to adjust the quantity of products in their subscription."
"Only products that are listed as \"optional products\" can be modified.")
related_plan_id = fields.Many2many("sale.subscription.plan", "sale_subscription_plan_related_plan",
"plan_id", "related_plan_id", string="Optional Plans",
help="Allow your customers to switch from this plan to "
"another on quotation (new subscription or renewal)")
# Invoicing
auto_close_limit = fields.Integer(string="Automatic Closing", default=15,
help="Unpaid subscription after the due date majored by this number of days will be automatically closed by "
"the subscriptions expiration scheduled action. \n"
"If the chosen payment method has failed to renew the subscription after this time, "
"the subscription is automatically closed.")
auto_close_limit_display = fields.Char(string="Automatic Closing After", compute="_compute_auto_close_limit_display")
invoice_mail_template_id = fields.Many2one('mail.template', string='Invoice Email Template',
domain=[('model', '=', 'account.move')],
default=lambda self: self.env.ref('account.email_template_edi_invoice', raise_if_not_found=False),
help="Email template used to send invoicing email automatically.\n"
"Leave it empty if you don't want to send email automatically.")
product_subscription_pricing_ids = fields.One2many('sale.subscription.pricing', 'plan_id', string="Recurring Pricing",
domain=['|', ('product_template_id', '=', None), ('product_template_id.active', '=', True)])
# UX
active_subs_count = fields.Integer(compute="_compute_active_subs_count", string="Subscriptions")
def write(self, values):
if "related_plan_id" in values:
old_related = {plan.id: plan.related_plan_id for plan in self}
res = super().write(values)
if "related_plan_id" in values:
for plan in self:
if to_remove := old_related[plan.id] - plan.related_plan_id:
to_remove.related_plan_id = [Command.unlink(plan.id)]
if to_add := plan.related_plan_id - old_related[plan.id]:
to_add.related_plan_id = [Command.link(plan.id)]
return res
def _compute_active_subs_count(self):
self.active_subs_count = 0
res = self.env['sale.order'].read_group(
[('plan_id', 'in', self.ids), ('is_subscription', '=', True), ('subscription_state', 'in', ['3_progress', '4_paused'])],
['__count'], ['plan_id'],
)
for template in res:
if template['plan_id']:
self.browse(template['plan_id'][0]).active_subs_count = template['plan_id_count']
def action_open_active_sub(self):
return {
'name': _('Subscriptions'),
'view_mode': 'tree,form',
'domain': [('plan_id', 'in', self.ids), ('is_subscription', '=', True), ('subscription_state', 'in', ['3_progress', '4_paused'])],
'res_model': 'sale.order',
'type': 'ir.actions.act_window',
}
@property
def billing_period(self):
if not self.billing_period_unit or not self.billing_period_value:
return False
return get_timedelta(self.billing_period_value, self.billing_period_unit)
@api.depends('billing_period_value', 'billing_period_unit')
def _compute_billing_period_display(self):
labels = dict(self._fields['billing_period_unit']._description_selection(self.env))
for plan in self:
plan.billing_period_display = f"{plan.billing_period_value} {labels[plan.billing_period_unit]}"
@api.depends('billing_period_value', 'billing_period_unit')
def _compute_billing_period_display_sentence(self):
for plan in self:
value = plan.billing_period_value
if plan.billing_period_unit == 'week':
sentence = _('per %d weeks', value) if value > 1 else _('per week')
elif plan.billing_period_unit == 'month':
sentence = _('per %d months', value) if value > 1 else _('per month')
elif plan.billing_period_unit == 'year':
sentence = _('per %d years', value) if value > 1 else _('per year')
else:
raise ValueError(f"Invalid Billing Period Unit {plan.billing_period_unit!r}")
plan.billing_period_display_sentence = sentence
@api.depends('auto_close_limit')
def _compute_auto_close_limit_display(self):
for plan in self:
plan.auto_close_limit_display = _lt('%s days', plan.auto_close_limit)
@api.constrains('billing_period_value')
def _check_not_zero_billing_period(self):
for plan in self:
if plan.billing_period_value < 1:
raise ValidationError(
_('Recurring period must be a positive number. Please ensure the input is a valid positive numeric value.')
)