# Module: Follow-up & Follow-up Cards (followup)

## Purpose
Pregnancy follow-up management for an OB/GYN clinic. Three sub-features:
1. **Follow-up sheet** (`followup.php`): one active pregnancy follow-up record per patient (LMP, EDD, IVF date, G/P), with dated child rows for visits (wt/BP/GA/US), diagnoses, examinations, investigations, plus in-screen prescriptions (`followupdrugs`, runtime-created table). Closed pregnancies are archived (`status = 1`) and browsable.
2. **Follow-up cards** (`followupcard.php`): printable per-encounter card (diagnosis + drug list) tied to the latest reception visit; confirming/printing a card pushes a prescription into the pharmacy module (`recepittmp` + `receiptdrugs`).
3. **Instructions** (`instruction.php`): a library of printable patient instruction texts, plus (oddly co-located) hospital transfer/referral letter generation.

## Controllers & Views (file paths)
Controllers:
- `/home/amrtechogate/public_html/obgy/core/controllers/followup.php` (657 lines)
- `/home/amrtechogate/public_html/obgy/core/controllers/followupcard.php` (408 lines)
- `/home/amrtechogate/public_html/obgy/core/controllers/instruction.php` (672 lines)

Views (Smarty):
- `/home/amrtechogate/public_html/obgy/core/views/obgy/followup/` : `add.html`, `archive.html`, `pregdetail.html`, `newrow.html`, `newrowUS.html`, `newrowdrugedit.html`, `showPrescriptions.html`
- `/home/amrtechogate/public_html/obgy/core/views/obgy/followupcard/` : `show.html`, `add.html`, `showdata.html`, `drawRow.html`, `print.html`
- `/home/amrtechogate/public_html/obgy/core/views/obgy/instruction/` : `add.html`, `show.html`, `edit.html`, `print.html`, `transfer.html`, `printtransfer.html`, `editmodel.html`, `editmodelinst.html`
- Prescription print reuses `/home/amrtechogate/public_html/obgy/core/views/obgy/gyna/print.html`

ORM: RedBeanPHP (`R::`), fluid mode (tables/columns can be created at runtime).

## Tables
Schema source: `/home/amrtechogate/public_html/obgy/_db/obgy_12-7-2024.sql`. No declared FKs anywhere; all FKs below are inferred from controller code. **None of the 8 assigned tables has any seeded INSERT rows in the dump** (all transactional/user-maintained; `instruction` is empty in this dump).

### followup (dump line 6986)
Master pregnancy follow-up record. One open record (`status=0`) per patient; auto-created on first screen entry.
| Column | Type | Notes |
|---|---|---|
| id | int(11) PK AI | |
| patientid | int(11) | FK -> patients.id |
| history | text | free text |
| lmp | date | last menstrual period; defaults to today on auto-create |
| eed | date | EDD, computed = LMP + 9 months + 7 days (strtotime) |
| ivf | date | computed = LMP + 9 months - 7 days |
| g | varchar(100) | gravida (free text) |
| p | varchar(100) | para (free text) |
| status | int(11) default 0 | comment: "1 end, 0 not yet" (archive flag) |

### followupcard (dump line 7005) — CHARSET latin1
Printable encounter card.
| Column | Type | Notes |
|---|---|---|
| id | int(11) PK AI | |
| enterdate | date NULL | copied from latest `visits.visitdate` |
| exitdate | date NULL | set to today at creation |
| date | date NULL | card date |
| patientid | int(11) | FK -> patients.id |
| doctorid | int(11) | FK -> awusers.user_id (from `$_SESSION['user_id']`) |
| diagnosis | text | free text |
| status | int(11) | 0 = draft, 1 = confirmed/printed |
| deleted | int(11) default 0 | soft delete |
| deptid | int(11) NULL | FK -> detections.id (copied from `visits.detectionid`) |

### followupcarddrugs (dump line 7025) — CHARSET latin1
Drug lines of a card.
| Column | Type | Notes |
|---|---|---|
| id | int(11) PK AI | |
| cardid | int(11) | FK -> followupcard.id |
| drugid | int(11) | FK -> drugs.id |
| drugtype | varchar(250) | free text from distinct drugs.drugtype |
| drugdos | varchar(250) | dose, free text |
| recepittmpid | int(11) default 0 | FK -> recepittmp.id (pharmacy receipt created at confirm) |

### followupdiagnosis (dump line 7041)
| Column | Type | Notes |
|---|---|---|
| id | int(11) PK AI | |
| followid | int(11) | FK -> followup.id |
| date | date | |
| diagnosis | text | free text |
| del | int(11) default 0 | soft delete |

### followupexam (dump line 7056)
Identical shape to followupdiagnosis with `exam` text column. FK `followid` -> followup.id; `del` soft delete.

### followupinvest (dump line 7071)
Identical shape with `invest` text column (free-text investigation requests/results — NOT linked to the investigations catalog). FK `followid` -> followup.id; `del` soft delete.

### followupvisit (dump line 7086)
Antenatal visit row.
| Column | Type | Notes |
|---|---|---|
| id | int(11) PK AI | |
| followid | int(11) | FK -> followup.id |
| date | date | |
| wt | varchar(50) | weight, free text |
| bp | varchar(50) | blood pressure, free text |
| ga | varchar(100) | gestational age (also recomputed in code: round(days(LMP..date)/7) weeks) |
| us | varchar(100) | ultrasound summary |
| notes | text | |
| del | int(11) default 0 | soft delete |

### instruction (dump line 8188)
Patient instruction template library.
| Column | Type | Notes |
|---|---|---|
| id | int(11) PK AI | |
| patientid | int(11) | nominally FK -> patients.id, but **hardcoded to 1** in addit() and updateit() — effectively a global library |
| name | varchar(255) | title |
| content | text | HTML-formatted instruction body |
| tempdelete | char(1) default '0' | soft delete |

No seeded values in the dump (0 INSERT statements).

### Ghost table: followupdrugs (NOT in dump)
Heavily used by `followup.php` (getprescription, showprescription, printpre, addprescription) but **absent from the SQL dump** — created at runtime by RedBeanPHP fluid mode. Columns inferred from code: `id`, `patientid` (FK->patients), `followid` (FK->followup), `drugid` (FK->drugs), `date`, `forhusband` (0=wife/1=husband), `deleted`, plus drug type/dose fields. Must be captured from a live production dump before migration.

## Relationships (explicit list)
- followup.patientid -> patients.id
- followupvisit.followid -> followup.id
- followupdiagnosis.followid -> followup.id
- followupexam.followid -> followup.id
- followupinvest.followid -> followup.id
- followupcard.patientid -> patients.id
- followupcard.doctorid -> awusers.user_id
- followupcard.deptid -> detections.id (value copied from visits.detectionid)
- followupcarddrugs.cardid -> followupcard.id
- followupcarddrugs.drugid -> drugs.id
- followupcarddrugs.recepittmpid -> recepittmp.id (pharmacy)
- instruction.patientid -> patients.id (dead column, always 1)
- followupdrugs.{patientid,followid,drugid} -> patients.id / followup.id / drugs.id (runtime table, inferred)
- Cross-module reads in instruction.php transfer letters: mainantenental, mainantenentalus, phobstetric, phpastmedical(+phpastmedicaldisease), phpastsurgical(+phpastsurgicaloperation), phpastgynecological(+phpastgynecologicaloperation), hospitalnames, operationinstructions, bloodtypes, wifetypes
- Print flows read: programesetting, wifetypes, husbandtypes, patients

## Business Workflows (traced from code)
1. **Open follow-up sheet** (`followup.php::index`): requires `?patientid`. Finds open `followup` (status=0) or auto-creates one (lmp=today, eed=lmp+9mo+7d, ivf=lmp+9mo-7d) plus an initial empty `followupvisit`. Renders 4 date-desc lists (diagnosis/exam/invest/visits); GA per visit computed as weeks since LMP; flags visits dated before LMP (`dateFlag`).
2. **Row management via AJAX**: `newdiag/newexam/newinv/newvisit` insert empty dated rows and return an HTML fragment (`newrow.html`). `update` is a generic cell editor: POST `id, tableName, colName, value, dated` -> `R::load($tablename)->$colname = $value`. Editing `lmp` recomputes and echoes eed+ivf. `del` sets `del=1` on any POSTed table.
3. **In-sheet prescriptions**: today's `followupdrugs` rows per patient+followid+forhusband shown alongside drug catalog dropdowns (distinct drugcat/drugtype/drugdos from `drugs`). `showprescription` lists historic prescription dates split wife/husband; `printpre` prints one date via `gyna/print.html` using patient name + wifetypes/husbandtypes title; `addprescription` soft-deletes a drug line.
4. **Archive**: `archive` lists `followup` rows with status=1 for the patient; `pregdetail?pregno=` re-renders a full read view of a past pregnancy.
5. **Follow-up card creation** (`followupcard.php::addit` without cardid): loads or creates draft card (status=0): enterdate = latest `visits.visitdate`, exitdate/date = today, doctorid = session user, deptid = `visits.detectionid`. Drug rows added client-side (`drawRow`).
6. **Card confirm + pharmacy push** (`printit`): if status==0: sets status=1, creates `recepittmp` (doctor_id, patient_id, rect_date, drugstablename='followupcarddrugs', status=0), then per drug row inserts `followupcarddrugs` (with recepittmpid) and `receiptdrugs` (drugs_id, amount=1, receipt_id) so pharmacy can price/dispense. Optionally prints `followupcard/print.html` with department title from `detections`. `yesOnly` mode reprints an existing card without pharmacy push.
7. **Card list** (`index`): confirmed (status=1, deleted=0) cards per patient with doctor name from `awusers` and concatenated drug names. Generic `update` endpoint also used for soft delete (note: line 270 uses `=` instead of `==` in the if condition — always true).
8. **Instruction library** (`instruction.php`): index/add/show/edit/updateit CRUD on `instruction` (patientid forced to 1); `del` soft-deletes via string-concatenated raw SQL (injection risk). `getprint` accepts a JSON array of instruction ids and prints them with patient name/title; `getinstdetail` prints a single one (auth checks commented out).
9. **Hospital transfer letter** (`instruction.php::showtransfer/printtransfer`): aggregates current pregnancy from `mainantenental` (NOT from `followup`!), computes G/P from `phobstetric` + patients counters (pno/ab/ectopic/vmodel), last placenta from `mainantenentalus`, past medical/surgical/gyna history from `ph*` tables, blood type, hospital from `hospitalnames`, operation instructions from `operationinstructions`; prints `printtransfer.html`. Side CRUD for `hospitalnames` and `operationinstructions` lives here too.

## ERP Migration Notes
Proposed Laravel models:
- **Pregnancy** (merge `followup` with `mainantenental` — same concept duplicated across modules (استنتاج/inference, field overlap: patientid, lmp, eed, g, p, status/done)): patient_id FK, lmp, edd (computed, Naegele rule LMP+280d instead of legacy strtotime "+9 months +7 days"), ivf_date, gravida/para int, status enum(active, closed).
- **AntenatalVisit** (from `followupvisit`): pregnancy_id FK, visit_date, weight decimal, bp_systolic/bp_diastolic, ga computed accessor, ultrasound_notes, notes. Add CHECK/validation visit_date >= lmp (legacy only flags it in UI).
- **ClinicalNote** — merge `followupdiagnosis` + `followupexam` + `followupinvest` into one table with `type` enum(diagnosis, examination, investigation); their schemas are 100% identical (followid, date, text, del). Optionally link investigations to the investigations catalog instead of free text.
- **Encounter/VisitCard** (from `followupcard`): visit_id FK (proper link instead of "latest visit" copy), patient_id, doctor_id (users), department_id (detections->departments), diagnosis, status enum(draft, confirmed), SoftDeletes.
- **Prescription + PrescriptionItem** — unify `followupcarddrugs`, runtime `followupdrugs`, and the other per-module drug tables into one prescription source of truth (prescribable polymorphic or encounter_id), items FK to drugs. Replace direct `recepittmp`/`receiptdrugs` inserts with a domain event (PrescriptionConfirmed) consumed by the pharmacy module.
- **InstructionTemplate** (from `instruction`): drop dead `patientid` column; keep name/content; SoftDeletes. Add **Referral** model + ReferralLetterService for the transfer-letter flow (currently print-only, no persistence) with hospital_id FK (`hospitalnames` -> Hospital lookup) and selected operation instructions.

Critical remediation during migration:
- **Capture live schema first**: `followupdrugs` (and possibly other RedBean fluid tables) is missing from the reference dump.
- Kill the generic `update/del` endpoints (client-supplied tableName/colName = mass-assignment over the whole DB) -> per-resource endpoints with FormRequest validation + Policies.
- Fix SQL injection in `instruction::del` (string-concatenated UPDATE) and re-enable the commented-out auth checks (`getinstdetail`, `addopinst`, `editopinst`, `update`).
- Fix latin1 charset on `followupcard`/`followupcarddrugs` (Arabic diagnosis text corruption risk) -> utf8mb4 with data verification.
- Normalize soft-delete flags (`del`, `deleted`, `tempdelete`, `status`) to Laravel `deleted_at` + explicit status enums.
- Convert free-text vitals (wt, bp, ga varchar) to typed numeric columns; migrate with parsing + manual review of non-numeric values.
- Note assignment-instead-of-comparison bug at followupcard.php:270 (`if($tablename = 'followupcard' && ...)`) — do not replicate behavior, it always echoes 1.
