EnCoach Odoo 19 custom modules

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
This commit is contained in:
Talal Sharabi
2026-03-14 16:46:46 +04:00
commit f5b627256f
168 changed files with 13428 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import registration

View File

@@ -0,0 +1,132 @@
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})