first push message
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
class SubscriptionTemplate(models.Model):
|
||||
_name = 'subscription.template'
|
||||
_description = 'Subscription Template'
|
||||
_order = 'sequence, name'
|
||||
|
||||
name = fields.Char(string='Template Name', required=True)
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
interval_number = fields.Integer(string='Invoice Every', default=1, required=True)
|
||||
interval_type = fields.Selection([
|
||||
('days', 'Days'),
|
||||
('weeks', 'Weeks'),
|
||||
('months', 'Months'),
|
||||
('years', 'Years'),
|
||||
], string='Interval Type', default='months', required=True)
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
|
||||
product_id = fields.Many2one('product.product', string='Product', required=True)
|
||||
quantity = fields.Float(string='Quantity', default=1.0)
|
||||
|
||||
# FIX: Changed to Float because list_price is Float
|
||||
price_unit = fields.Float(string='Price', related='product_id.list_price')
|
||||
currency_id = fields.Many2one(related='product_id.currency_id')
|
||||
|
||||
description = fields.Text(string='Description')
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
for record in self:
|
||||
name = f"{record.name} ({record.interval_number} {record.interval_type})"
|
||||
result.append((record.id, name))
|
||||
return result
|
||||
|
||||
|
||||
class Subscription(models.Model):
|
||||
_name = 'subscription.subscription'
|
||||
_description = 'Subscription'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'create_date desc'
|
||||
|
||||
name = fields.Char(string='Reference', required=True, copy=False, readonly=True, default='New')
|
||||
template_id = fields.Many2one('subscription.template', string='Subscription Template', required=True)
|
||||
partner_id = fields.Many2one('res.partner', string='Customer', required=True)
|
||||
company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company)
|
||||
|
||||
# Dates
|
||||
start_date = fields.Date(string='Start Date', required=True, default=fields.Date.context_today)
|
||||
next_invoice_date = fields.Date(string='Next Invoice Date', required=True, copy=False)
|
||||
end_date = fields.Date(string='End Date')
|
||||
last_invoice_date = fields.Date(string='Last Invoice Date', copy=False)
|
||||
|
||||
# Status
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('active', 'Active'),
|
||||
('closed', 'Closed'),
|
||||
('cancelled', 'Cancelled'),
|
||||
], string='Status', default='draft', tracking=True, copy=False)
|
||||
|
||||
# Pricing
|
||||
currency_id = fields.Many2one(related='template_id.currency_id')
|
||||
|
||||
# FIX: Changed to Float to match template
|
||||
price_unit = fields.Float(related='template_id.price_unit')
|
||||
|
||||
# FIX: Changed to Float
|
||||
quantity = fields.Float(related='template_id.quantity')
|
||||
recurring_total = fields.Float(string='Recurring Price', compute='_compute_recurring_total', store=True)
|
||||
|
||||
# Invoicing
|
||||
invoice_count = fields.Integer(string='Invoice Count', compute='_compute_invoice_count')
|
||||
invoice_ids = fields.One2many('account.move', 'subscription_id', string='Invoices')
|
||||
|
||||
# Additional info
|
||||
note = fields.Text(string='Notes')
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('name', 'New') == 'New':
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('subscription.subscription') or 'New'
|
||||
return super().create(vals)
|
||||
|
||||
def _compute_recurring_total(self):
|
||||
for sub in self:
|
||||
sub.recurring_total = sub.price_unit * sub.quantity
|
||||
|
||||
def _compute_invoice_count(self):
|
||||
for sub in self:
|
||||
sub.invoice_count = len(sub.invoice_ids)
|
||||
|
||||
def action_start_subscription(self):
|
||||
self.write({
|
||||
'state': 'active',
|
||||
'next_invoice_date': self.start_date
|
||||
})
|
||||
return True
|
||||
|
||||
def action_close_subscription(self):
|
||||
self.write({'state': 'closed'})
|
||||
return True
|
||||
|
||||
def action_cancel_subscription(self):
|
||||
self.write({'state': 'cancelled'})
|
||||
return True
|
||||
|
||||
def action_draft_subscription(self):
|
||||
self.write({'state': 'draft'})
|
||||
return True
|
||||
|
||||
def action_view_invoices(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _('Invoices'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.move',
|
||||
'view_mode': 'tree,form',
|
||||
'domain': [('subscription_id', '=', self.id)],
|
||||
'context': {'default_subscription_id': self.id}
|
||||
}
|
||||
|
||||
def generate_invoice(self):
|
||||
"""Generate invoice for active subscriptions"""
|
||||
for sub in self:
|
||||
if sub.state != 'active':
|
||||
continue
|
||||
|
||||
if sub.end_date and sub.next_invoice_date > sub.end_date:
|
||||
sub.write({'state': 'closed'})
|
||||
continue
|
||||
|
||||
# Create invoice
|
||||
invoice_vals = {
|
||||
'move_type': 'out_invoice',
|
||||
'partner_id': sub.partner_id.id,
|
||||
'company_id': sub.company_id.id,
|
||||
'currency_id': sub.currency_id.id,
|
||||
'subscription_id': sub.id,
|
||||
'invoice_date': sub.next_invoice_date,
|
||||
'invoice_origin': f"Subscription: {sub.name}",
|
||||
'invoice_line_ids': [(0, 0, {
|
||||
'product_id': sub.template_id.product_id.id,
|
||||
'name': sub.template_id.description or sub.template_id.product_id.name,
|
||||
'quantity': sub.quantity,
|
||||
'price_unit': sub.price_unit,
|
||||
'account_id': sub.template_id.product_id.property_account_income_id.id or
|
||||
sub.template_id.product_id.categ_id.property_account_income_categ_id.id,
|
||||
})]
|
||||
}
|
||||
|
||||
invoice = self.env['account.move'].create(invoice_vals)
|
||||
|
||||
# Update subscription
|
||||
next_date = sub.next_invoice_date
|
||||
if sub.template_id.interval_type == 'days':
|
||||
next_date += timedelta(days=sub.template_id.interval_number)
|
||||
elif sub.template_id.interval_type == 'weeks':
|
||||
next_date += timedelta(weeks=sub.template_id.interval_number)
|
||||
elif sub.template_id.interval_type == 'months':
|
||||
next_date += relativedelta(months=sub.template_id.interval_number)
|
||||
elif sub.template_id.interval_type == 'years':
|
||||
next_date += relativedelta(years=sub.template_id.interval_number)
|
||||
|
||||
sub.write({
|
||||
'last_invoice_date': sub.next_invoice_date,
|
||||
'next_invoice_date': next_date,
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
subscription_id = fields.Many2one('subscription.subscription', string='Subscription', ondelete='set null',
|
||||
copy=False)
|
||||
Reference in New Issue
Block a user