319 lines
16 KiB
Markdown
319 lines
16 KiB
Markdown
# Prompt for Django Agent – Motamarat Project
|
||
|
||
## Objective
|
||
Develop a complete **Django + Django REST Framework** system that implements the Motamarat Project BRD for managing CME/CPD activities end‑to‑end: requests, multi‑level approvals, registry, scientific program, speakers, finances, announcements, attendance, and integrations (Mustamir, SCFHS, Motamarat). Deliver a production‑ready scaffold with role‑based access, workflow automation, ColorAdmin templates, and a fully documented API.
|
||
|
||
---
|
||
|
||
## 1) Project Constraints & Non‑Functional Requirements
|
||
- **Tech**: Python 3.12, Django 5.x, DRF 3.15+, Postgres, Redis + Celery (async tasks), drf-nested-routers, django-filter.
|
||
- **Security**: Multi-tenant aware roles/groups; object-level permissions on requests/activities; audit timestamps.
|
||
- **i18n**: `ar` and `en` fields for user-facing titles; RTL-ready templates (ColorAdmin).
|
||
- **Validation**: Enforce *proposed_date ≥ today + 6 weeks* at form, serializer, and model `clean()` levels.
|
||
- **Emails/Notifications**: Use Celery for async emails (department approval, additional approvals, speaker notices, attendee reminders, accreditation hours).
|
||
- **Integrations**: Provide **stubs** (`MustamirClient`, `SCFHSClient`, `MotamaratClient`, `CommsCampaignClient`) with `.send(payload)` and `.status(ref)`; serialize models into payloads.
|
||
- **Testing**: Unit tests for models/serializers; integration tests for workflow transitions; API tests for endpoints.
|
||
- **Docs**: README with setup (ENV vars), Makefile or management commands for bootstrap (fixtures, superuser).
|
||
|
||
---
|
||
|
||
## 2) Django App Structure
|
||
Create a Django project `motamarat` and the following apps:
|
||
- `core_cme` – abstract models, enums, lookups, shared utils (validators, choices, emails, workflow).
|
||
- `cme_requests` – **request intake** + **workflow** (Steps 1–9).
|
||
- `cpd_registry` – **approved activities** management (committee, speakers, program, finance, announcement, attendance).
|
||
- `cme_plans` – Centre/Department yearly planning submissions and workflow.
|
||
|
||
---
|
||
|
||
## 3) Implementation Sequence (generate code in this exact order)
|
||
1. `models.py`
|
||
2. `signals.py` (only where useful)
|
||
3. `utils.py` (validators, choices, workflow, integrations, finance, emails)
|
||
4. `forms.py`
|
||
5. `views.py` (CBVs)
|
||
6. `urls.py`
|
||
7. **Templates list** (ColorAdmin-based)
|
||
8. **DRF**: `serializers.py`, `api_views.py` (ViewSets), **routers & urls**
|
||
|
||
---
|
||
|
||
## 4) Data Model (models.py)
|
||
|
||
### 4.1 Shared (in `core_cme`)
|
||
- **Abstracts**: `TimeStampedModel`, `SoftDeleteModel` (boolean flag `is_deleted` + queryset manager).
|
||
- **Enumerations (TextChoices)**:
|
||
`EventType`, `DeliveryMethod`, `Language`, `Status` (Draft/Submitted/In Review/Approved/Rejected/Closed),
|
||
`SubStatus` (Department Approval, CME Review, Further Dept Approval, CME Under Process, Conf Date Confirmed, Event Confirmed, Requester Date Approval, Completed),
|
||
`MotamaratStatus` (Announced/Under Process/Canceled/NA), `AnnouncementStatus` (Announced/Under Process/Canceled),
|
||
`VenueType` (R/J/M/Outside), `Category` (CME/CPD/GrandRound), `YesNo` (Yes/No).
|
||
- **Lookups** (with fixtures and admin): `Country`, `City`, `Specialty`, `TargetAudience`, `Department`, `SubDepartment`.
|
||
|
||
### 4.2 CME Requests (app `cme_requests`)
|
||
- **CMEActivityRequest**
|
||
Fields:
|
||
```
|
||
request_number (unique, slug-ish)
|
||
requester (FK User)
|
||
title_ar, title_en
|
||
event_type (EventType)
|
||
is_repeated (bool), repeated_accreditation_no (nullable)
|
||
aims_outcomes (Text)
|
||
goals_objectives (JSON list – max N items, each ≤ 50 words)
|
||
learning_methods (Text)
|
||
evaluation_method (Text)
|
||
professional_fields (M2M to Specialty or Domain model)
|
||
target_audiences (M2M to TargetAudience)
|
||
learning_gap (Text)
|
||
needs_assessment_tools (JSON or M2M)
|
||
specialty (FK Specialty), subspecialty (CharField or FK)
|
||
language (Language), other_language (CharField, conditional)
|
||
proposed_date (Date), remarks (Text)
|
||
has_international_speakers (bool), international_speakers_count (1–20, conditional)
|
||
event_country (FK Country), event_city (FK City), venue_type (VenueType), venue_address, venue_capacity (int), target_participants (int)
|
||
delivery_method (DeliveryMethod)
|
||
est_expenses (Decimal), est_income (Decimal), est_budget (Decimal), budget_source (CharField)
|
||
collaboration: has_collaboration (bool), collaborator_org (Char), collaboration_type (Char),
|
||
content_developed_by_kfshrc (bool), content_developer (Char)
|
||
attachments (Generic relation or simple FK to RequestAttachment)
|
||
status (Status), sub_status (SubStatus), assigned_to (FK User, nullable)
|
||
```
|
||
Constraints: `proposed_date >= today + 42 days` on submit; clean transitions.
|
||
- **DepartmentApproval**: `request` FK, `approver` FK, `decision` (Approve/Reject), `comment`, `decided_at`.
|
||
- **CMEHeadReview**: `request` FK, `editor` FK, `changes_json` (tracked), `completed`, `completed_at`, M2M `added_approvals` (through `AdditionalApproval`).
|
||
- **AdditionalApproval**: `request` FK, `selected_staff` FK, `decision` (Approve/Reject/Pending), `comment`, `decided_at`.
|
||
- **CMECoordinatorProcess**: `request` FK, `coordinator` FK, `conference_date_reserved` (Date), `mustamir_payload` (JSON), `sent_to_mustamir_at` (DateTime), `notes`.
|
||
- **RequesterDateApproval**: `request` FK, `requester` FK, `decision` (Approve/Reject), `comment`, `decided_at`.
|
||
- **RequestAttachment**: `request` FK, `file`, `type` (General/ProgramPDF/SponsorLogo/etc).
|
||
|
||
### 4.3 CPD Registry (app `cpd_registry`)
|
||
- **CPDActivity**
|
||
```
|
||
category (Category), date_of_event (Date)
|
||
scfhs_request_no (Char), accreditation_no (Char, nullable)
|
||
status (Approved/Rejected/Cancelled)
|
||
hours (Decimal) # CME hours
|
||
motamarat_status (MotamaratStatus), announcement_status (AnnouncementStatus)
|
||
request_number (Char), requester_name (Char), request_date (Date)
|
||
committee_chairman (Char)
|
||
duration_days (PositiveSmallInteger, 1–5), assigned_to (FK User), site (VenueType or Site enum R/J/M)
|
||
comments (Text)
|
||
```
|
||
- **OrganizingCommitteeMember**: FK `activity`, `user` (optional), `name`, `hospital_id`, `job_title`, `department`.
|
||
- **Speaker**: FK `activity`, `is_hospital_staff` (bool), `user` (optional), else `name`, `job_title`, `department`, `specialty`, `institute`, contact info, `scfhs_license_no`, `license_expiry`, `speaker_type` (International/Local), `visa_needed`, `ticket_needed`, `hotel_needed`.
|
||
- **ScientificProgramItem**: FK `activity`, `start_time`, `end_time`, `topic`, `length_minutes` (5-step), FK `speaker`, `session_type`, `order`.
|
||
- **SpeakerDisclosure** / **SpeakerCVSummary**: FK `speaker`, file fields or structured text.
|
||
- **FinancialForecast** (parent) + line-item children for expenses/income:
|
||
- Expense tables: `ExpenseInternationalSpeaker`, `ExpenseLocalSpeaker`, `ExpenseOutsideClassroom`, `ExpenseInsideClassroom`, `ExpenseLogistics`, `ExpenseAdvertisement`, `ExpenseOther`
|
||
- Income tables: `IncomeRegistration`, `IncomeSponsorship`, `IncomeOther`
|
||
- Fields per line: `description`, `estimated`, `actual`, computed `over_under`.
|
||
- **NetRevenueDistribution** view/prop: totals + split matrix (e.g., 50% Dept, 50% Education; or 30% A&TA/20% Dept; make matrix configurable).
|
||
- **AnnouncementRequest**: campaign fields (overview, goals_objectives, contact_person, sponsor fields, fees early/late, `program_pdf`, `sponsor_logo`), and Motamarat payload + timestamps.
|
||
- **AttendanceBatch**: FK `activity`, reminder schedule flags/timestamps (D-1 and same-day 06:30), QR session metadata.
|
||
- **Attendance**: `name`, `email`, `phone`, `specialty`, `classification_no`, `checked_in_at` (QR), `certificate_sent_at`.
|
||
|
||
### 4.4 CME Plans (app `cme_plans`)
|
||
- **CMEPlanSubmission**: `request_number`, `requester`, `coe` FK, `status`, `sub_status`, `assigned_to`, `educational_plan_pdf`.
|
||
- **CMEPlannedEvent**: under submission – titles, event_type, objectives (list), format, subspecialty, target_audience (M2M), language, proposed_date, international speakers (count), remarks, location & venue, estimated participants, collaboration flags.
|
||
|
||
---
|
||
|
||
## 5) Signals (signals.py)
|
||
- `CMEActivityRequest.pre_save`: assign `request_number` like `CME-{YYYYMMDD}-{seq:04d}` if blank.
|
||
- `CMEActivityRequest.clean` or `pre_save`: enforce 6-week rule **only when** `status` moves to Submitted or beyond.
|
||
- `CMEActivityRequest.post_save` on state change: enqueue emails to next actor; expose `assigned_to` to requester during “CME Under Process”.
|
||
- On terminal `Completed`: auto-create `CPDActivity` from request + copy key fields.
|
||
- `CPDActivity.post_save`: when `accreditation_no` or `hours` set, email requester with accredited hours.
|
||
- `Speaker.post_save`: when logistic flags are finalized, send information email.
|
||
|
||
---
|
||
|
||
## 6) Utilities (utils.py)
|
||
- `choices.py` – enums and helper mappings.
|
||
- `validators.py` – 6-week lead time, value ranges, conditional required fields.
|
||
- `workflow.py` – finite-state transitions: `advance(request, action) -> (new_status, new_sub_status, assignee)`.
|
||
- `finance.py` – aggregation helpers for totals and net distribution; compute `over_under` and cache results.
|
||
- `integrations.py` – clients:
|
||
```python
|
||
class MustamirClient: # submit conference / event
|
||
def send(self, payload): ...
|
||
def status(self, ref): ...
|
||
|
||
class SCFHSClient: # accreditation
|
||
def send(self, payload): ...
|
||
def status(self, ref): ...
|
||
|
||
class MotamaratClient: # announcement
|
||
def send(self, payload): ...
|
||
def status(self, ref): ...
|
||
```
|
||
- `emails.py` – `send_department_approval_request(...)`, `send_additional_approval_request(...)`, `send_speaker_notice(...)`, `send_attendee_reminder(...)`, `send_accreditation_notice(...)`.
|
||
|
||
---
|
||
|
||
## 7) Forms (forms.py)
|
||
- `CMEActivityRequestForm` with conditional UI: repeated accreditation number, “Other language”, venue outside fields, international speaker count.
|
||
- `DepartmentApprovalForm`, `CMEHeadReviewForm` (inline add approvals), `AdditionalApprovalForm`.
|
||
- `CMECoordinatorConferenceForm` (reserve date & Mustamir payload), `RequesterDateApprovalForm`, `EventConfirmForm`.
|
||
- `CPDActivityAdminForm` (site, coordinator, status, hours).
|
||
- `SpeakerForm` (staff vs external), `ScientificProgramItemForm` (time consistency).
|
||
- Financial formsets per expense/income category (read-only totals card).
|
||
- `AnnouncementRequestForm`, `AttendanceUploadForm` (CSV), QR session form.
|
||
- `CMEPlanSubmissionForm` + inline formset for `CMEPlannedEvent`.
|
||
|
||
---
|
||
|
||
## 8) Views (views.py) – Class-Based Views
|
||
### App `cme_requests`
|
||
- CRUD: `CMEActivityRequestCreate/Update/Detail/List`.
|
||
- Actions:
|
||
- `SubmitRequestView` (enforces 6-week rule)
|
||
- `DepartmentApproveRejectView`
|
||
- `CMEHeadReviewView` (edits + add approvals)
|
||
- `AdditionalApprovalDecisionView`
|
||
- `AssignCMECoordinatorView`
|
||
- `ConferenceDateConfirmView`
|
||
- `RequesterDateApprovalView`
|
||
- `EventConfirmView` (send to Mustamir)
|
||
- `CompleteAndCreateActivityView`
|
||
|
||
### App `cpd_registry`
|
||
- `CPDActivityList/Detail/Update`
|
||
- Inlines/tabs: committee, speakers, program (sortable), finances (formsets), announcement, attendance (QR check-in).
|
||
- Actions: send speakers email, attendee reminders (D-1 & 06:30), send to Motamarat, generate certificates.
|
||
|
||
### App `cme_plans`
|
||
- Submission CRUD + `HeadReviewView`, `SpecialistDesignView`, `CompletePlanView`.
|
||
|
||
---
|
||
|
||
## 9) URLs (urls.py)
|
||
**cme_requests/**
|
||
```
|
||
requests/
|
||
requests/new/
|
||
requests/<pk>/
|
||
requests/<pk>/submit/
|
||
requests/<pk>/dept-approval/
|
||
requests/<pk>/head-review/
|
||
requests/<pk>/additional-approval/<id>/
|
||
requests/<pk>/assign-coordinator/
|
||
requests/<pk>/conference-date/
|
||
requests/<pk>/requester-date-approval/
|
||
requests/<pk>/event-confirm/
|
||
requests/<pk>/complete/
|
||
```
|
||
**cpd_registry/**
|
||
```
|
||
activities/
|
||
activities/<pk>/
|
||
activities/<pk>/speakers/
|
||
activities/<pk>/program/
|
||
activities/<pk>/finances/
|
||
activities/<pk>/announcement/
|
||
activities/<pk>/attendance/
|
||
activities/<pk>/actions/send-motamarat/
|
||
activities/<pk>/actions/remind-attendees/
|
||
activities/<pk>/actions/send-speakers/
|
||
```
|
||
**cme_plans/**
|
||
```
|
||
plans/
|
||
plans/new/
|
||
plans/<pk>/
|
||
plans/<pk>/head-review/
|
||
plans/<pk>/specialist-design/
|
||
plans/<pk>/complete/
|
||
```
|
||
|
||
---
|
||
|
||
## 10) Templates (ColorAdmin-based)
|
||
**cme_requests/**
|
||
- `request_form.html`, `request_detail.html`, `request_list.html`
|
||
- `partials/_fields_dynamic.html` (language other, venue outside, repeated event)
|
||
- `dept_approval_form.html`, `head_review_form.html`, `additional_approval_form.html`
|
||
- `conference_date_form.html`, `requester_date_approval_form.html`, `event_confirm_form.html`
|
||
- `request_timeline.html` (status/sub-status trace)
|
||
|
||
**cpd_registry/**
|
||
- `activity_list.html`, `activity_detail.html`, `activity_edit.html`
|
||
- `committee_formset.html`, `speaker_form.html`, `program_formset.html` (sortable)
|
||
- `finances/*.html` (tabs per category + totals card)
|
||
- `announcement_form.html`, `attendance_list.html`, `attendance_qr.html`, `certificates_send.html`
|
||
|
||
**cme_plans/**
|
||
- `plan_form.html`, `plan_detail.html`, `plan_list.html`, `plan_review_head.html`, `plan_design_specialist.html`
|
||
|
||
**emails/** shared templates for all notifications.
|
||
|
||
---
|
||
|
||
## 11) DRF Layer
|
||
|
||
### serializers.py
|
||
- `cme_requests`:
|
||
- `CMEActivityRequestSerializer` (+ writable nested for attachments)
|
||
- `DepartmentApprovalSerializer`, `CMEHeadReviewSerializer`, `AdditionalApprovalSerializer`
|
||
- `CoordinatorProcessSerializer`, `RequesterDateApprovalSerializer`, `RequestAttachmentSerializer`
|
||
- `cpd_registry`:
|
||
- `CPDActivitySerializer` (full nested)
|
||
- `OrganizingCommitteeMemberSerializer`, `SpeakerSerializer`, `ScientificProgramItemSerializer`
|
||
- `FinancialForecastSerializer` + line-item serializers
|
||
- `AnnouncementRequestSerializer`, `AttendanceSerializer`, `AttendanceBatchSerializer`
|
||
- `cme_plans`:
|
||
- `CMEPlanSubmissionSerializer`, `CMEPlannedEventSerializer`
|
||
- `Lookup` serializers for dropdowns.
|
||
|
||
### api_views.py (ViewSets + custom actions)
|
||
- `CMEActivityRequestViewSet`:
|
||
- CRUD + actions: `submit`, `dept_approve`, `dept_reject`, `head_review`, `additional_approve`, `additional_reject`, `assign_coordinator`, `conference_reserve_date`, `requester_approve_date`, `requester_reject_date`, `event_confirm`, `complete`.
|
||
- `CPDActivityViewSet`:
|
||
- CRUD; nested routes for committee/speakers/program/finances/announcement/attendance.
|
||
- Actions: `send_to_motamarat`, `send_speakers_email`, `recalc_finances`, `remind_attendees`, `send_certificates`.
|
||
- `CMEPlanSubmissionViewSet`: CRUD + `head_review`, `specialist_design_upload`, `complete`.
|
||
- `LookupsViewSet`: read-only.
|
||
|
||
### routers & urls
|
||
```
|
||
router.register('requests', CMEActivityRequestViewSet)
|
||
router.register('activities', CPDActivityViewSet)
|
||
router.register('plans', CMEPlanSubmissionViewSet)
|
||
router.register('lookups', LookupsViewSet, basename='lookups')
|
||
```
|
||
Use `drf-nested-routers` for activity sub-resources:
|
||
`/activities/{id}/committee/`, `/speakers/`, `/program/`, `/finances/`, `/announcement/`, `/attendance/`.
|
||
|
||
---
|
||
|
||
## 12) Business Rules & Automations
|
||
- Enforce 6-week lead time on submission.
|
||
- Conference date reservation required for `EventType.CONFERENCE` before event confirmation.
|
||
- Requester sees assigned coordinator during “CME Under Process”.
|
||
- Financial totals & over/under computed; distribution matrix configurable.
|
||
- Attendee reminders scheduled D-1 and same-day 06:30; QR check-in generates `checked_in_at`.
|
||
- Completion of request auto-creates CPDActivity; setting `accreditation_no` or `hours` triggers email.
|
||
- Speakers with logistics flags get automatic instruction emails.
|
||
|
||
---
|
||
|
||
## 13) Admin & Fixtures
|
||
- Register all models with search fields and list filters (status, sub_status, site, date_of_event).
|
||
- Provide initial fixtures for lookups (Country, City, Specialty, TargetAudience, Department).
|
||
- Management command: `load_cme_fixtures` and `create_demo_users` with standard roles.
|
||
|
||
---
|
||
|
||
## 14) Roles & Permissions
|
||
- Groups: **Requester**, **CME Coordinator**, **CME Specialist**, **CME Admin**, **CME Head**.
|
||
- Map view permissions and API actions to these groups; object-level checks to ensure only assigned actors can transition.
|
||
|
||
---
|
||
|
||
## 15) Output Expectations
|
||
- Generate the full Django project with: models, admin, migrations, serializers, viewsets, urls, templates (ColorAdmin integrated), Celery tasks, and stub integrations.
|
||
- Include comprehensive README and `.env.example` (DB URL, EMAIL settings, API keys for external systems).
|
||
- All tests pass: run `pytest` or Django test runner.
|
||
|
||
**Deliver this as a ready-to-run scaffold.**
|