from odoo import models, fields, api, _ from odoo.exceptions import UserError from datetime import datetime, timedelta import logging _logger = logging.getLogger(__name__) class UserSubscription(models.Model): _name = 'user.subscription' _description = 'User Subscription' _inherit = ['mail.thread'] _rec_name = 'user_email' user_id = fields.Many2one('res.users', string='User', ondelete='cascade') user_email = fields.Char(string='Email', required=True) user_name = fields.Char(string='Full Name', required=True) company_name = fields.Char(string='Company Name', required=True) phone = fields.Char(string='Phone') country_id = fields.Many2one('res.country', string='Country') # Subscription details subscription_plan_id = fields.Many2one('subscription.plan', string='Subscription Plan') state = fields.Selection([ ('draft', 'Draft'), ('trial', 'Trial'), ('active', 'Active'), ('expired', 'Expired'), ('cancelled', 'Cancelled'), ], string='Status', default='draft', tracking=True) # Trial period trial_start_date = fields.Datetime(string='Trial Start Date') trial_end_date = fields.Datetime(string='Trial End Date') # Subscription period subscription_start_date = fields.Datetime(string='Subscription Start Date') subscription_end_date = fields.Datetime(string='Subscription End Date') # Flags is_trial = fields.Boolean(string='Is Trial', compute='_compute_is_trial') is_premium = fields.Boolean(string='Is Premium', default=False) days_remaining = fields.Integer(string='Days Remaining', compute='_compute_days_remaining') # Payment payment_reference = fields.Char(string='Payment Reference') payment_state = fields.Selection([ ('pending', 'Pending'), ('paid', 'Paid'), ('failed', 'Failed'), ], string='Payment Status', default='pending') # Database instance database_instance_id = fields.One2many('database.instance', 'subscription_id', string='Database Instances') active_database_id = fields.Many2one('database.instance', string='Active Database') # Selected apps selected_app_ids = fields.One2many('selected.apps', 'subscription_id', string='Selected Apps') max_apps_allowed = fields.Integer(related='subscription_plan_id.max_apps', string='Max Apps Allowed') @api.model def create(self, vals): """Create subscription with automatic trial setup""" subscription = super().create(vals) if subscription.state == 'trial' and not subscription.trial_start_date: trial_plan = self.env['subscription.plan'].get_trial_plan() trial_days = trial_plan.trial_days if trial_plan else 15 subscription.write({ 'subscription_plan_id': trial_plan.id if trial_plan else False, 'trial_start_date': fields.Datetime.now(), 'trial_end_date': fields.Datetime.now() + timedelta(days=trial_days), }) # Send verification email subscription._send_verification_email() return subscription def _compute_is_trial(self): for record in self: record.is_trial = record.state == 'trial' def _compute_days_remaining(self): now = fields.Datetime.now() for record in self: if record.state == 'trial' and record.trial_end_date: delta = record.trial_end_date - now record.days_remaining = max(0, delta.days) elif record.state == 'active' and record.subscription_end_date: delta = record.subscription_end_date - now record.days_remaining = max(0, delta.days) else: record.days_remaining = 0 def _send_verification_email(self): """Send email verification to user""" self.ensure_one() template = self.env.ref('odoo_subscription.email_verification_template', raise_if_not_found=False) if template: template.send_mail(self.id, force_send=True) def _send_credentials_email(self): """Send admin credentials to user""" self.ensure_one() template = self.env.ref('odoo_subscription.email_credentials_template', raise_if_not_found=False) if template: template.send_mail(self.id, force_send=True) def check_trial_expired(self): """Check if trial has expired""" self.ensure_one() if self.state == 'trial' and self.trial_end_date: if fields.Datetime.now() > self.trial_end_date: self.state = 'expired' return True return False def is_subscription_valid(self): """Check if subscription is valid""" self.ensure_one() if self.state == 'active': if self.subscription_end_date and fields.Datetime.now() <= self.subscription_end_date: return True elif self.state == 'trial': if not self.check_trial_expired(): return True return False def provision_database(self, app_list): """Provision database and install apps""" self.ensure_one() try: # Create database instance record db_instance_obj = self.env['database.instance'] # Generate unique subdomain subdomain = db_instance_obj.generate_unique_subdomain(self.company_name) database_name = subdomain.replace('-', '_') # Create database instance db_instance = db_instance_obj.create({ 'subscription_id': self.id, 'database_name': database_name, 'subdomain': subdomain, 'admin_email': self.user_email, 'db_state': 'pending', }) self.active_database_id = db_instance.id self.state = 'trial' self._cr.commit() # Create database (this may take time) if db_instance.create_database(): # Install selected apps if db_instance.install_apps(app_list): # Configure instance db_instance.configure_instance() # Send credentials self._send_credentials_email() return { 'success': True, 'database_url': db_instance.full_domain, 'admin_login': db_instance.admin_login, 'admin_password': db_instance.admin_password, } return { 'success': False, 'error': 'Database provisioning failed', } except Exception as e: _logger.error(f"Database provisioning error: {e}") return { 'success': False, 'error': str(e), } def activate_subscription(self, plan_id, payment_ref=None): """Activate paid subscription""" self.ensure_one() plan = self.env['subscription.plan'].browse(plan_id) self.write({ 'state': 'active', 'subscription_plan_id': plan.id, 'is_premium': True, 'subscription_start_date': fields.Datetime.now(), 'payment_reference': payment_ref, 'payment_state': 'paid', }) # Calculate end date based on plan duration if plan.plan_code == '3_months': self.subscription_end_date = fields.Datetime.now() + timedelta(days=90) elif plan.plan_code == '6_months': self.subscription_end_date = fields.Datetime.now() + timedelta(days=180) elif plan.plan_code == '1_year': self.subscription_end_date = fields.Datetime.now() + timedelta(days=365) # Update database instance limits if self.active_database_id: self.active_database_id.write({ 'workers': 4, 'memory_limit_mb': 1024, 'max_connections': 50, })