# EnCoach Odoo 19 -- Developer Feedback **Date:** March 11, 2026 **Status:** ALL ITEMS RESOLVED (March 13, 2026) **Reference:** ODOO_MIGRATION_SRS_v2.md --- ## Overall Assessment The delivery covers approximately **85% of the SRS v2 requirements**. All 15 custom modules are present, the core AI/ML services are well-implemented, data models match the specification, and 67-72 API endpoints are wired up with proper JWT authentication and security groups. The code quality is solid -- clean structure, proper error handling, and good separation of concerns. The items below still need to be implemented to reach full SRS compliance. --- ## 1. Payment Integration (Critical -- Not Implemented) **SRS Reference:** Section 7 All three payment services are currently stubs that return `"not yet implemented"`. The SRS requires full integration with: ### 1.1 Stripe **Files:** `encoach_subscription/services/stripe_service.py` Required functionality: - Install and use the `stripe` Python SDK - `create_checkout_session()` -- Create a Stripe Checkout Session using `stripe.checkout.Session.create()` with: - `line_items` from the selected `encoach.package` - `success_url` and `cancel_url` from the request - `client_reference_id` = user ID - `customer_email` = user email - Apply discount if `discount_code` is provided (validate against `encoach.discount`) - Return `{ "sessionId": "cs_...", "url": "https://checkout.stripe.com/..." }` - **Webhook endpoint** (`POST /api/stripe/webhook`): - Verify signature using `stripe.Webhook.construct_event()` with `STRIPE_WEBHOOK_SECRET` - Handle `checkout.session.completed` event: - Find user by `client_reference_id` - Extend `subscription_expiration` by the package's `duration_days` - Create `encoach.subscription.payment` record - For corporate users, propagate subscription to entity members ### 1.2 PayPal **Files:** `encoach_subscription/services/paypal_service.py` Required functionality: - Use PayPal REST API (`httpx` or `requests`) - Obtain access token from `PAYPAL_ACCESS_TOKEN_URL` using `client_id` + `client_secret` - `create_order()` -- Create PayPal order via `POST /v2/checkout/orders`: - `intent: "CAPTURE"` - `purchase_units` with amount from package (minus discount) - Return `{ "orderId": "...", "approvalUrl": "https://paypal.com/..." }` - `capture_order()` -- Capture approved order via `POST /v2/checkout/orders/{id}/capture`: - On success, extend subscription and create payment record - Return `{ "ok": true }` ### 1.3 Paymob **Files:** `encoach_subscription/services/paymob_service.py` Required functionality: - Use Paymob API (`httpx` or `requests`) - `create_intention()` -- Create payment intention: - Authenticate with `PAYMOB_API_KEY` - Create order, then payment key - Return `{ "intentionId": "...", "clientSecret": "..." }` - `verify_transaction()` -- Verify webhook callback: - Validate HMAC using `PAYMOB_SECRET` - On success, extend subscription and create payment record - **Webhook endpoint** (`POST /api/paymob/webhook`): - Verify transaction authenticity - Update subscription on success ### 1.4 Subscription Extension Logic After any successful payment (all providers), the system must: 1. Calculate new expiration: `max(current_expiration, now()) + duration_days` 2. Update `user.subscription_expiration` 3. Create `encoach.subscription.payment` record with provider, amount, transaction ID 4. For corporate users: propagate the new expiration to all entity members --- ## 2. Missing API Endpoints **SRS Reference:** Section 4 The following endpoints are specified in the SRS but not present in the delivery: ### 2.1 Exam Variants (add to `encoach_api/controllers/generation.py` or `exams.py`) | Endpoint | Method | Description | |----------|--------|-------------| | `POST /api/exam/writing//attachment` | POST | Academic writing Task 1 with image upload (multipart form with `file` + `difficulty`). Must send image to GPT-4o vision API for prompt generation. | | `GET /api/exam/level/` | GET | Return a pre-built level exam (no AI generation) | | `GET /api/exam/level/utas` | GET | Return a UTAS-format level exam | | `POST /api/exam/level/import/` | POST | Import level exam from uploaded file | | `POST /api/exam/level/custom/` | POST | Generate custom level exam from JSON specification | | `POST /api/exam/reading/import` | POST | Import reading exam from Word/Excel file | | `POST /api/exam/listening/import` | POST | Import listening exam from file | ### 2.2 Entity/Role/Permission Management (new controller files needed) | Endpoint | Method | Description | |----------|--------|-------------| | `GET /api/entities` | GET | List entities (with pagination) | | `POST /api/entities` | POST | Create entity | | `PATCH /api/entities/` | PATCH | Update entity | | `DELETE /api/entities/` | DELETE | Delete entity | | `GET /api/roles` | GET | List roles (filter by entityID) | | `POST /api/roles` | POST | Create role | | `PATCH /api/roles/` | PATCH | Update role | | `DELETE /api/roles/` | DELETE | Delete role | | `GET /api/permissions` | GET | List permissions | ### 2.3 Other Missing Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `GET /api/discounts` | GET | List discount codes | | `POST /api/discounts` | POST | Create discount code | | `PATCH /api/discounts/` | PATCH | Update discount code | | `DELETE /api/discounts/` | DELETE | Delete discount code | | `GET /api/approval-workflows` | GET | List approval workflows | | `POST /api/approval-workflows` | POST | Create approval workflow | | `PATCH /api/approval-workflows/` | PATCH | Update approval workflow | | `DELETE /api/approval-workflows/` | DELETE | Delete approval workflow | --- ## 3. Evaluation Status Endpoint Path **SRS Reference:** Section 4.2 **Current:** `GET /api/evaluate/status?sessionId=...&exerciseId=...` (query params) **SRS specifies:** `GET /api/evaluate//` (path params) The frontend SRS document (`ODOO_MIGRATION_FRONTEND_SRS.md`) references the path-param version. Please either: - (A) Change the endpoint to use path params to match the SRS, OR - (B) Confirm that query params are intentional so we can update the frontend SRS --- ## 4. Record-Level Security Rules (`ir.rule`) **SRS Reference:** Section 5 The delivery has model-level ACL rules (`ir.model.access.csv`) for each module, which is good. However, record-level security rules (`ir.rule`) are also needed to ensure: - **Students** can only read/write their own records (sessions, stats, evaluations, training, tickets) - **Teachers** can see records for students in their groups/assignments - **Corporate** users can see records within their entity - **Admin/Developer** users have unrestricted access Example rules needed (add to each module's `security/` directory): ```xml Students see own stats [('user_id', '=', user.id)] ``` Models that need record rules: - `encoach.session` -- students see own sessions only - `encoach.stat` -- students see own stats only - `encoach.evaluation` -- students see own evaluations only - `encoach.training` -- students see own training only - `encoach.ticket` -- students see own tickets, admins see all - `encoach.assignment` -- students see assignments they're assigned to - `encoach.exam` -- filtered by access field (public/private/entity) --- ## 5. Whisper Scaling **SRS Reference:** Section 6.5 **Current:** Single lazy-loaded Whisper model instance in `whisper_service.py` **SRS specifies:** 4 model instances with `ThreadPoolExecutor(max_workers=4)` for parallel transcription Update `encoach_ai_media/services/whisper_service.py` to: 1. Load the configurable number of model instances (from `encoach.whisper_workers` system parameter, default 4) 2. Use `concurrent.futures.ThreadPoolExecutor` to process transcription requests in parallel 3. Round-robin or queue-based assignment of requests to model instances This is important for production performance when multiple students submit speaking exams simultaneously. --- ## 6. FAISS Index Type **SRS Reference:** Section 6.8 **Current:** `faiss.IndexFlatIP` (inner product) **SRS specifies:** `faiss.IndexFlatL2` (L2/Euclidean distance) The current implementation normalizes vectors and uses inner product, which effectively gives cosine similarity. This works correctly, but it's a deviation from the SRS. If the original `ielts-be` training data was built with L2 distance, the results may differ slightly. Please verify which index type the original system used and align accordingly. --- ## 7. Payment Webhook Endpoints **SRS Reference:** Section 7 In addition to the payment service implementations (Item 1 above), the following webhook controller routes need to be added to `encoach_api/controllers/subscriptions.py`: ```python @http.route('/api/stripe/webhook', type='http', auth='public', methods=['POST'], csrf=False, cors='*') def stripe_webhook(self, **kwargs): """Handle Stripe webhook events (checkout.session.completed, etc.).""" ... @http.route('/api/paymob/webhook', type='http', auth='public', methods=['POST'], csrf=False, cors='*') def paymob_webhook(self, **kwargs): """Handle Paymob transaction callbacks.""" ... ``` These must be `auth='public'` (no JWT) since they're called by external services. --- ## Summary of Action Items | # | Item | Priority | Status | |---|------|----------|--------| | 1 | Payment integration (Stripe/PayPal/Paymob) | **Critical** | RESOLVED | | 2 | Missing API endpoints (~20 endpoints) | **High** | RESOLVED | | 3 | Evaluation status endpoint path alignment | **Medium** | RESOLVED | | 4 | `ir.rule` record-level security rules | **High** | RESOLVED | | 5 | Whisper multi-instance scaling | **Medium** | RESOLVED | | 6 | FAISS index type verification | **Low** | RESOLVED | | 7 | Payment webhook endpoints | **Critical** | RESOLVED | --- ## Changes Already Applied The following small fixes have been applied directly to the codebase: 1. **`encoach_ai_media/__manifest__.py`** -- Added missing `external_dependencies`: `numpy`, `openai-whisper`, `librosa`, `soundfile`, `httpx` 2. **`encoach_training/__manifest__.py`** -- Added missing `external_dependencies`: `numpy`, `faiss-cpu`, `sentence-transformers` 3. **`requirements.txt`** -- Created at project root with all Python dependencies and versions from SRS Section 6.10