first push message

This commit is contained in:
2026-07-01 14:41:49 +07:00
parent 6667dec2bf
commit 58b5f46cc4
2951 changed files with 316619 additions and 0 deletions
@@ -0,0 +1,265 @@
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/<provider>', 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'},
]