Full backend implementation with custom Odoo modules: - encoach_api: Core API, user management, JWT auth - encoach_exam: Exam generation (reading, writing, listening, speaking) - encoach_evaluate: AI-powered evaluation (writing, speaking) - encoach_training: Training tips and walkthrough - encoach_storage: File storage management - encoach_payment: Stripe, PayPal, Paymob integration - encoach_mail: Email notifications Made-with: Cursor
133 lines
4.2 KiB
Python
133 lines
4.2 KiB
Python
import logging
|
|
|
|
from odoo import models, fields, api
|
|
from odoo.exceptions import ValidationError
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class EncoachRegistrationMixin(models.AbstractModel):
|
|
_name = "encoach.registration.mixin"
|
|
_description = "EnCoach Registration Service"
|
|
|
|
@api.model
|
|
def register_individual(self, email, password, name, code=None):
|
|
if self.env["res.users"].sudo().search([("login", "=", email)], limit=1):
|
|
raise ValidationError(f"A user with email {email} already exists.")
|
|
|
|
user = self.env["res.users"].sudo().create({
|
|
"login": email,
|
|
"password": password,
|
|
"name": name,
|
|
"encoach_type": "student",
|
|
})
|
|
|
|
if code:
|
|
self._apply_code(user, code)
|
|
|
|
_logger.info("Registered individual user: %s (%s)", name, email)
|
|
return user
|
|
|
|
@api.model
|
|
def register_corporate(self, email, password, name, code):
|
|
if not code:
|
|
raise ValidationError("Corporate registration requires a code.")
|
|
|
|
if self.env["res.users"].sudo().search([("login", "=", email)], limit=1):
|
|
raise ValidationError(f"A user with email {email} already exists.")
|
|
|
|
result = self.env["encoach.code"].sudo().validate_code(code)
|
|
if not result.get("valid"):
|
|
raise ValidationError(result.get("error", "Invalid code."))
|
|
|
|
code_rec = self.env["encoach.code"].sudo().search([("code", "=", code)], limit=1)
|
|
entity = code_rec.entity_id
|
|
if not entity:
|
|
raise ValidationError("Code is not linked to any entity.")
|
|
|
|
user = self.env["res.users"].sudo().create({
|
|
"login": email,
|
|
"password": password,
|
|
"name": name,
|
|
"encoach_type": code_rec.user_type or "corporate",
|
|
})
|
|
|
|
self.env["encoach.user.entity.rel"].sudo().create({
|
|
"user_id": user.id,
|
|
"entity_id": entity.id,
|
|
})
|
|
|
|
code_rec.sudo().write({"uses": code_rec.uses + 1})
|
|
|
|
_logger.info(
|
|
"Registered corporate user: %s (%s) -> entity %s",
|
|
name, email, entity.name,
|
|
)
|
|
return user
|
|
|
|
@api.model
|
|
def batch_import(self, users_data, maker_id):
|
|
created = []
|
|
errors = []
|
|
|
|
for idx, udata in enumerate(users_data):
|
|
try:
|
|
email = udata.get("email")
|
|
password = udata.get("password", "")
|
|
name = udata.get("name", email)
|
|
user_type = udata.get("type", "student")
|
|
code = udata.get("code")
|
|
|
|
if self.env["res.users"].sudo().search(
|
|
[("login", "=", email)], limit=1
|
|
):
|
|
errors.append({
|
|
"index": idx,
|
|
"email": email,
|
|
"error": "User already exists",
|
|
})
|
|
continue
|
|
|
|
user = self.env["res.users"].sudo().create({
|
|
"login": email,
|
|
"password": password,
|
|
"name": name,
|
|
"encoach_type": user_type,
|
|
})
|
|
|
|
if code:
|
|
self._apply_code(user, code)
|
|
|
|
created.append(user.id)
|
|
except Exception as e:
|
|
errors.append({
|
|
"index": idx,
|
|
"email": udata.get("email", ""),
|
|
"error": str(e),
|
|
})
|
|
|
|
_logger.info(
|
|
"Batch import by user %s: %d created, %d errors",
|
|
maker_id, len(created), len(errors),
|
|
)
|
|
return {"created": created, "errors": errors}
|
|
|
|
def _apply_code(self, user, code_str):
|
|
result = self.env["encoach.code"].sudo().validate_code(code_str)
|
|
if not result.get("valid"):
|
|
return
|
|
|
|
code_rec = self.env["encoach.code"].sudo().search(
|
|
[("code", "=", code_str)], limit=1,
|
|
)
|
|
if not code_rec:
|
|
return
|
|
|
|
if code_rec.entity_id:
|
|
self.env["encoach.user.entity.rel"].sudo().create({
|
|
"user_id": user.id,
|
|
"entity_id": code_rec.entity_id.id,
|
|
})
|
|
|
|
code_rec.sudo().write({"uses": code_rec.uses + 1})
|