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,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_encoach_code_tree" model="ir.ui.view">
<field name="name">encoach.code.tree</field>
<field name="model">encoach.code</field>
<field name="arch" type="xml">
<list string="Registration Codes" editable="bottom">
<field name="code"/>
<field name="entity_id"/>
<field name="creator_id"/>
<field name="code_type"/>
<field name="user_type"/>
<field name="max_uses"/>
<field name="uses"/>
<field name="expiry_date"/>
</list>
</field>
</record>
<record id="view_encoach_code_form" model="ir.ui.view">
<field name="name">encoach.code.form</field>
<field name="model">encoach.code</field>
<field name="arch" type="xml">
<form string="Registration Code">
<sheet>
<group>
<group>
<field name="code" readonly="id"/>
<field name="entity_id"/>
<field name="creator_id"/>
<field name="expiry_date"/>
</group>
<group>
<field name="code_type"/>
<field name="user_type"/>
<field name="max_uses"/>
<field name="uses"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_encoach_code" model="ir.actions.act_window">
<field name="name">Registration Codes</field>
<field name="res_model">encoach.code</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first registration code.
</p>
<p>
Registration codes allow users to join entities or register
with a specific user type.
</p>
</field>
</record>
<menuitem id="menu_encoach_code"
name="Registration Codes"
parent="encoach_core.menu_encoach_users"
action="action_encoach_code"
sequence="20"/>
</odoo>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_encoach_entity_tree" model="ir.ui.view">
<field name="name">encoach.entity.tree</field>
<field name="model">encoach.entity</field>
<field name="arch" type="xml">
<list string="Entities" editable="bottom">
<field name="name"/>
<field name="label"/>
<field name="licenses"/>
<field name="expiry_date"/>
<field name="payment_currency"/>
<field name="payment_price"/>
</list>
</field>
</record>
<record id="view_encoach_entity_form" model="ir.ui.view">
<field name="name">encoach.entity.form</field>
<field name="model">encoach.entity</field>
<field name="arch" type="xml">
<form string="Entity">
<sheet>
<group>
<group>
<field name="name"/>
<field name="label"/>
</group>
<group>
<field name="licenses"/>
<field name="expiry_date"/>
</group>
<group>
<field name="payment_currency"/>
<field name="payment_price"/>
</group>
</group>
<notebook>
<page string="Roles" name="roles">
<field name="role_ids">
<list editable="bottom">
<field name="name"/>
<field name="permission_ids" widget="many2many_tags"/>
</list>
</field>
</page>
<page string="Members" name="members">
<field name="user_rel_ids">
<list editable="bottom">
<field name="user_id"/>
<field name="role_id"/>
</list>
</field>
</page>
</notebook>
</sheet>
<chatter/>
</form>
</field>
</record>
<record id="action_encoach_entity" model="ir.actions.act_window">
<field name="name">Entities</field>
<field name="res_model">encoach.entity</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first entity (organization).
</p>
<p>
Entities represent organizations such as schools or companies.
Each entity has licenses, members, and roles.
</p>
</field>
</record>
<menuitem id="menu_encoach_entity"
name="Entities"
parent="encoach_core.menu_encoach_users"
action="action_encoach_entity"
sequence="10"/>
</odoo>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_encoach_invite_tree" model="ir.ui.view">
<field name="name">encoach.invite.tree</field>
<field name="model">encoach.invite</field>
<field name="arch" type="xml">
<list string="Invites" editable="bottom">
<field name="from_user_id"/>
<field name="to_user_id"/>
<field name="entity_id"/>
<field name="status"/>
</list>
</field>
</record>
<record id="view_encoach_invite_form" model="ir.ui.view">
<field name="name">encoach.invite.form</field>
<field name="model">encoach.invite</field>
<field name="arch" type="xml">
<form string="Invite">
<header>
<button name="action_accept" string="Accept" type="object"
class="btn-primary" invisible="status != 'pending'"/>
<button name="action_decline" string="Decline" type="object"
invisible="status != 'pending'"/>
</header>
<sheet>
<group>
<field name="from_user_id"/>
<field name="to_user_id"/>
<field name="entity_id"/>
<field name="status"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_encoach_invite" model="ir.actions.act_window">
<field name="name">Invites</field>
<field name="res_model">encoach.invite</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No invites yet.
</p>
<p>
Invites allow users to join entities.
Pending invites can be accepted or declined.
</p>
</field>
</record>
<menuitem id="menu_encoach_invite"
name="Invites"
parent="encoach_core.menu_encoach_users"
action="action_encoach_invite"
sequence="30"/>
</odoo>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<menuitem id="menu_encoach_root" name="EnCoach" sequence="100"/>
<menuitem id="menu_encoach_users" name="Users &amp; Entities" parent="menu_encoach_root" sequence="10"/>
<menuitem id="menu_encoach_exams" name="Exams" parent="menu_encoach_root" sequence="20"/>
<menuitem id="menu_encoach_classroom" name="Classroom" parent="menu_encoach_root" sequence="30"/>
<menuitem id="menu_encoach_ai" name="AI &amp; Grading" parent="menu_encoach_root" sequence="40"/>
<menuitem id="menu_encoach_training" name="Training" parent="menu_encoach_root" sequence="50"/>
<menuitem id="menu_encoach_subscription" name="Subscriptions" parent="menu_encoach_root" sequence="60"/>
<menuitem id="menu_encoach_support" name="Support" parent="menu_encoach_root" sequence="70"/>
<menuitem id="menu_encoach_config" name="Configuration" parent="menu_encoach_root" sequence="90"/>
</odoo>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_encoach_permission_tree" model="ir.ui.view">
<field name="name">encoach.permission.tree</field>
<field name="model">encoach.permission</field>
<field name="arch" type="xml">
<list string="Permissions" editable="bottom">
<field name="topic"/>
<field name="perm_type"/>
</list>
</field>
</record>
<record id="view_encoach_permission_form" model="ir.ui.view">
<field name="name">encoach.permission.form</field>
<field name="model">encoach.permission</field>
<field name="arch" type="xml">
<form string="Permission">
<sheet>
<group>
<field name="topic"/>
<field name="perm_type"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_encoach_permission" model="ir.actions.act_window">
<field name="name">Permissions</field>
<field name="res_model">encoach.permission</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first permission.
</p>
<p>
Permissions define what actions can be performed on each topic.
Assign permissions to roles.
</p>
</field>
</record>
<menuitem id="menu_encoach_permission"
name="Permissions"
parent="encoach_core.menu_encoach_config"
action="action_encoach_permission"
sequence="20"/>
</odoo>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_res_users_form_encoach" model="ir.ui.view">
<field name="name">res.users.form.encoach</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<page string="EnCoach" name="encoach">
<group>
<group>
<field name="encoach_type"/>
<field name="focus"/>
<field name="levels" widget="json"/>
<field name="desired_levels" widget="json"/>
<field name="is_verified"/>
<field name="subscription_expiration"/>
<field name="registration_date"/>
</group>
<group>
<field name="bio"/>
<field name="profile_picture"/>
<field name="encoach_status"/>
<field name="is_first_login"/>
<field name="last_login"/>
<field name="legacy_id"/>
</group>
</group>
<field name="entity_rel_ids">
<list editable="bottom">
<field name="entity_id"/>
<field name="role_id"/>
</list>
</field>
</page>
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_encoach_role_tree" model="ir.ui.view">
<field name="name">encoach.role.tree</field>
<field name="model">encoach.role</field>
<field name="arch" type="xml">
<list string="Roles" editable="bottom">
<field name="name"/>
<field name="entity_id"/>
</list>
</field>
</record>
<record id="view_encoach_role_form" model="ir.ui.view">
<field name="name">encoach.role.form</field>
<field name="model">encoach.role</field>
<field name="arch" type="xml">
<form string="Role">
<sheet>
<group>
<field name="name"/>
<field name="entity_id"/>
<field name="permission_ids" widget="many2many_checkboxes"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_encoach_role" model="ir.actions.act_window">
<field name="name">Roles</field>
<field name="res_model">encoach.role</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first role.
</p>
<p>
Roles define permissions within an entity.
Assign permissions to roles to control what users can do.
</p>
</field>
</record>
<menuitem id="menu_encoach_role"
name="Roles"
parent="encoach_core.menu_encoach_config"
action="action_encoach_role"
sequence="10"/>
</odoo>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_encoach_user_entity_rel_tree" model="ir.ui.view">
<field name="name">encoach.user.entity.rel.tree</field>
<field name="model">encoach.user.entity.rel</field>
<field name="arch" type="xml">
<list string="User-Entity Memberships" editable="bottom">
<field name="user_id"/>
<field name="entity_id"/>
<field name="role_id"/>
</list>
</field>
</record>
<record id="view_encoach_user_entity_rel_form" model="ir.ui.view">
<field name="name">encoach.user.entity.rel.form</field>
<field name="model">encoach.user.entity.rel</field>
<field name="arch" type="xml">
<form string="User-Entity Membership">
<sheet>
<group>
<field name="user_id"/>
<field name="entity_id"/>
<field name="role_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_encoach_user_entity_rel" model="ir.actions.act_window">
<field name="name">User-Entity Memberships</field>
<field name="res_model">encoach.user.entity.rel</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No memberships yet.
</p>
<p>
User-entity memberships link users to entities with optional roles.
</p>
</field>
</record>
<menuitem id="menu_encoach_user_entity_rel"
name="Memberships"
parent="encoach_core.menu_encoach_users"
action="action_encoach_user_entity_rel"
sequence="40"/>
</odoo>