from odoo import http, _ from odoo.http import request, route from odoo.exceptions import UserError, AccessError from datetime import datetime import json import logging _logger = logging.getLogger(__name__) class SubscriptionController(http.Controller): # ========== FLOW 1: User Registration & App Selection ========== @route('/trial', type='http', auth='public', website=True) def trial_signup(self, **kwargs): """Step 1: Show app selection and registration form""" apps = self._get_available_apps() values = { 'apps': apps, 'countries': request.env['res.country'].sudo().search([]), } return request.render('odoo_subscription.trial_signup_page', values) @route('/trial/register', type='http', auth='public', website=True, methods=['POST']) def trial_register(self, **kwargs): """Step 2: Process registration and create subscription""" # Get form data email = kwargs.get('email') name = kwargs.get('name') company_name = kwargs.get('company_name') phone = kwargs.get('phone') country_id = kwargs.get('country_id') selected_apps = kwargs.getlist('selected_apps') # Validation if not all([email, name, company_name, selected_apps]): return request.render('odoo_subscription.trial_signup_page', { 'error': 'All required fields must be filled', 'apps': self._get_available_apps(), }) # Check if user exists user = request.env['res.users'].sudo().search([('login', '=', email)], limit=1) # Create or get user if not user: user = request.env['res.users'].sudo().create({ 'name': name, 'login': email, 'email': email, }) # Create subscription subscription = request.env['user.subscription'].sudo().create({ 'user_id': user.id, 'user_email': email, 'user_name': name, 'company_name': company_name, 'phone': phone, 'country_id': int(country_id) if country_id else False, 'state': 'trial', }) # Save selected apps apps_data = self._get_available_apps() for app_name in selected_apps: app_data = next((a for a in apps_data if a['name'] == app_name), None) if app_data: request.env['selected.apps'].sudo().create({ 'subscription_id': subscription.id, 'app_name': app_data['name'], 'app_technical_name': app_data.get('technical_name', ''), 'app_icon': app_data.get('icon', ''), 'app_category': app_data.get('category', 'other'), }) # Send verification email subscription._send_verification_email() # Redirect to verification page return request.redirect(f'/trial/verify?subscription={subscription.id}') @route('/trial/verify', type='http', auth='public', website=True) def trial_verify(self, **kwargs): """Step 3: Email verification page""" subscription_id = kwargs.get('subscription') values = { 'subscription_id': subscription_id, } return request.render('odoo_subscription.email_verification_page', values) @route('/trial/verify-email', type='http', auth='public', website=True) def verify_email(self, **kwargs): """Step 4: Verify email token""" subscription_id = kwargs.get('subscription') token = kwargs.get('token') subscription = request.env['user.subscription'].sudo().browse(int(subscription_id)) if subscription and subscription.state == 'trial': # In production, verify token # For now, just proceed return request.redirect(f'/trial/provision?subscription={subscription.id}') return request.redirect('/trial') @route('/trial/provision', type='http', auth='public', website=True) def trial_provision(self, **kwargs): """Step 5: Provision database and show progress""" subscription_id = kwargs.get('subscription') subscription = request.env['user.subscription'].sudo().browse(int(subscription_id)) if not subscription or subscription.state != 'trial': return request.redirect('/trial') # Get selected apps selected_apps = [app.app_technical_name for app in subscription.selected_app_ids] # Provision database (this runs asynchronously in production) result = subscription.provision_database(selected_apps) values = { 'subscription': subscription, 'provisioning_result': result, } if result.get('success'): return request.render('odoo_subscription.provisioning_success', values) else: return request.render('odoo_subscription.provisioning_failed', values) # ========== FLOW 2: Database & Instance Routing ========== @route('/database/info', type='json', auth='user', website=True) def get_database_info(self, **kwargs): """Get current database information""" user = request.env.user subscription = request.env['user.subscription'].search( [('user_id', '=', user.id)], limit=1 ) if subscription and subscription.active_database_id: db = subscription.active_database_id return { 'database_name': db.database_name, 'subdomain': db.subdomain, 'full_domain': db.full_domain, 'state': db.db_state, 'installed_apps': db.installed_apps, } return {} # ========== FLOW 3: Subscription & Payment ========== @route('/subscription/upgrade', type='http', auth='user', website=True) def subscription_upgrade(self, **kwargs): """Show subscription plans for upgrade""" user = request.env.user subscription = request.env['user.subscription'].search( [('user_id', '=', user.id)], limit=1 ) plans = request.env['subscription.plan'].get_paid_plans() values = { 'subscription': subscription, 'plans': plans, 'currency': request.env.company.currency_id, } return request.render('odoo_subscription.subscription_plans', values) @route('/subscription/checkout', type='http', auth='user', website=True, methods=['POST']) def subscription_checkout(self, **kwargs): """Process subscription checkout""" plan_id = kwargs.get('plan_id') payment_method = kwargs.get('payment_method') # aba, stripe, paypal user = request.env.user subscription = request.env['user.subscription'].search( [('user_id', '=', user.id)], limit=1 ) if not subscription or not plan_id: return request.redirect('/subscription/upgrade') # Create payment transaction # In production, integrate with payment gateway payment_reference = f"SUB-{datetime.now().strftime('%Y%m%d%H%M%S')}-{user.id}" # For demo, activate directly subscription.activate_subscription(int(plan_id), payment_reference) return request.redirect('/subscription/success') @route('/subscription/success', type='http', auth='user', website=True) def subscription_success(self, **kwargs): """Subscription success page""" return request.render('odoo_subscription.subscription_success') @route('/subscription/webhook/', type='json', auth='public', methods=['POST']) def payment_webhook(self, provider, **kwargs): """Payment gateway webhook handler""" data = request.jsonrequest # Handle different payment providers if provider == 'aba_payway': return self._handle_aba_webhook(data) elif provider == 'stripe': return self._handle_stripe_webhook(data) elif provider == 'paypal': return self._handle_paypal_webhook(data) return {'status': 'error', 'message': 'Unknown provider'} def _handle_aba_webhook(self, data): """Handle ABA PayWay webhook""" # Implement ABA PayWay webhook logic return {'status': 'success'} def _handle_stripe_webhook(self, data): """Handle Stripe webhook""" # Implement Stripe webhook logic return {'status': 'success'} def _handle_paypal_webhook(self, data): """Handle PayPal webhook""" # Implement PayPal webhook logic return {'status': 'success'} # ========== Helper Methods ========== def _get_available_apps(self): """Get list of available Odoo apps""" return [ # Sales {'name': 'CRM', 'technical_name': 'crm', 'icon': 'fa-handshake-o', 'category': 'sales'}, {'name': 'Sales', 'technical_name': 'sale_management', 'icon': 'fa-shopping-cart', 'category': 'sales'}, {'name': 'Point of Sale', 'technical_name': 'point_of_sale', 'icon': 'fa-th', 'category': 'sales'}, {'name': 'Subscriptions', 'technical_name': 'subscription', 'icon': 'fa-refresh', 'category': 'sales'}, # Finance {'name': 'Invoicing', 'technical_name': 'account', 'icon': 'fa-file-text', 'category': 'finance'}, {'name': 'Accounting', 'technical_name': 'account_accountant', 'icon': 'fa-calculator', 'category': 'finance'}, {'name': 'Expenses', 'technical_name': 'hr_expense', 'icon': 'fa-money', 'category': 'finance'}, # Services {'name': 'Project', 'technical_name': 'project', 'icon': 'fa-tasks', 'category': 'services'}, {'name': 'Timesheets', 'technical_name': 'hr_timesheet', 'icon': 'fa-clock-o', 'category': 'services'}, {'name': 'Field Service', 'technical_name': 'hr_field_service', 'icon': 'fa-wrench', 'category': 'services'}, # Marketing {'name': 'Website', 'technical_name': 'website', 'icon': 'fa-globe', 'category': 'marketing'}, {'name': 'eCommerce', 'technical_name': 'website_sale', 'icon': 'fa-shopping-bag', 'category': 'marketing'}, {'name': 'Blog', 'technical_name': 'website_blog', 'icon': 'fa-pencil', 'category': 'marketing'}, {'name': 'Forum', 'technical_name': 'website_forum', 'icon': 'fa-comments', 'category': 'marketing'}, ]