Commit Graph
50 Commits
Author SHA1 Message Date
hamedandClaude Fable 5 385b81fae0 fix(patient): consistent debt/paid status, invoice totals, global service search
- patient_debt_rials now = session remaining (final - discount - paid), so the
  card status and invoice status stay consistent with is_paid even after a
  session is edited post-invoicing (no more '0 remaining but تکمیل پرداخت').
- InvoiceSummaryModal: remaining subtracts discount; the فاکتور status reflects
  actual settlement (تسویه شده / بدهکار), and the payments table shows a
  «مجموع پرداختی‌ها» total row.
- Add GET /api/v1/service-items (all owner services) and make the service
  picker searchable across all services without first choosing a section.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:53:28 +03:30
hamedandClaude Fable 5 142d653c68 fix(patient): derive is_paid from remaining, recompute on edit, audit add-payment
- is_paid now = remaining_rials == 0 (was payment_method != pending), so adding
  a service/package after settlement correctly flips the session back to debtor.
- updateSessionServices recomputes the cached settlement (payment_method/paid_at)
  after totals change.
- addSessionPayment now records a 'create' audit entry (actor, amount, time).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:34:41 +03:30
hamedandClaude Fable 5 7da7d968b9 feat(patient): session edit + payment PATCH/DELETE + audit-log endpoints
updateSession now accepts services/consumables/visit_price/insurance and calls
updateSessionServices; discount paths pass the actor for audit. Add
PATCH/DELETE /session/{uuid}/payments/{paymentUuid} and GET
/session/{uuid}/audit-log (owner-scoped). Inject the payment + audit repos.
Verified end-to-end (edit visit price, payment edit-exceeds guard, delete +
recompute, audit trail). Docs updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:14:49 +03:30
hamedandClaude Fable 5 cd1c9529cb feat(patient): session edit + payment edit/delete service logic with audit
Add updateSessionServices (replace services/consumables/visit-price/insurance,
recompute totals), updatePayment and deletePayment (wallet payments blocked;
recompute cached payment_method/paid_at via recomputeSettlement), and thread
audit logging (logSessionChange) through service edits and the discount path.
Add remove()/findByUuid to payment repo, remove() to service/consumable repos,
and method/amount/paid_at setters to SessionPayment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:11:07 +03:30
hamedandClaude Fable 5 d8c8ba0df7 feat(patient): add SessionAuditLog entity for financial/service change trail
New SessionAuditLog (mirrors AppointmentEvent): session FK, field, operation
(create/update/delete), old_value/new_value, actor id+name, note, created_at.
Repository saves and lists a session's history (newest first, array hydration).
Migration creates the table.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:06:25 +03:30
hamedandClaude Fable 5 666833fc69 feat(patient): soft-archive sessions with active/all/archived filter
Add archived + archived_at columns to PatientSession (setArchived stamps the
time). findByRecord/countByRecord accept an archived filter (default all to
keep existing callers, incl. the discount visit-count, unchanged); the
sessions GET reads ?filter=active|all|archived, defaulting to active so
archived visits are hidden. updateSession accepts { archived }. Records are
kept, only hidden. Verified end-to-end; docs updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 14:44:23 +03:30
hamedandClaude Fable 5 b3b1dad832 feat(discount): apply a discount rule to a session with audit
Extend PatientService::applyDiscount to carry the source rule id/label and
add applyDiscountRule, which computes the rial amount via the engine
(DiscountEngine::computeForRule now public) and records the rule for audit.
updateSession accepts discount_rule_uuid (owner-scoped, takes precedence over
the manual discount; ''/null clears). Verified end-to-end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 11:55:16 +03:30
hamedandClaude Fable 5 f0e1f43d51 feat(discount): add DiscountRule entity and session discount-rule audit columns
New Discount domain: DiscountRule (generic per-tenant rule with 6 types,
priority, combinable, validity window, and per-type target fields) plus its
repository. PatientSession gains applied_discount_rule_id/label audit columns
and setDiscount() now records the source rule. Migration creates the table
and columns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 11:47:33 +03:30
hamedandClaude Fable 5 8c39d720b5 fix(patient): populate auto-created session from the confirmed appointment
When an appointment is confirmed, the auto-created PatientSession was saved
empty: session_at null, visit_price_rials 0, no service line items, totals 0.
Now it copies the visit datetime from the appointment slot, the visit price
(falling back to the tenant free-visit price), a SessionService line per
appointment service (price snapshot from the service), and computes
services_total_rials / final_price_rials. Verified end-to-end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 11:38:13 +03:30
hamed a0ddb4c0d1 feat: add visit price requirement feature
- Introduced a new boolean flag `require_visit_price` in the `EntityInsurancePricing` to enforce visit price for appointments.
- Updated the appointment creation endpoints to validate `visit_price_rials` based on the new flag.
- Added `visit_price_rials` field to the `Appointment` entity to store the visit price.
- Enhanced the `PatientService` to validate visit price during session creation.
- Updated API documentation to reflect changes in appointment and insurance pricing.
- Implemented a new service `VisitPriceRequirementResolver` to determine if a visit price is required for a doctor based on their pricing settings.
- Added migrations to update the database schema for the new fields.
2026-07-16 19:44:30 +03:30
hamedandClaude Opus 4.8 07222826c3 feat: port tauri create-service page as 3-step new-session wizard
Backend:
- Add session_at and inventory_package_id to patient_sessions, new
  session_consumables table (migration Version20260716102537)
- New SessionConsumable entity/repository mirroring SessionService;
  price snapshot, quantity >= 1, tenant-scoped silent skip
- PatientService::createSession accepts session_at, consumables[] and
  inventory_package_uuid; consumables are fully patient-paid (no
  insurance coverage) and added to final_price_rials
- Functional tests: success, foreign-tenant/unknown skip, empty and
  zero-quantity edges (tests/Patient/SessionConsumableTest.php)
- docs/api/patient.md updated for the new Create Session fields

Frontend (admin):
- NewSessionPage rewritten as the tauri /files/create-service 3-step
  wizard (ایجاد سرویس ← پرداخت ← جزییات) using SessionStepper
- New CreateStep: acceptance date/time (Jalali), section/service/staff,
  consumables with counters, package select, conditional insurance
  block (insured service or insured patient profile), price summary
- PaymentStep/DetailsStep extracted from SessionPaymentPage and shared
  between both pages (behavior unchanged, tests still green)
- UserTick and FilesServiceAddCard icons ported verbatim from tauri
- Vitest coverage for the wizard incl. empty-data states

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:20:32 +03:30
hamedandClaude Opus 4.8 27d088c6dd feat: port tauri create-service payment flow to admin session settlement
Port the tauri /files/create-service page (payment mode) to the admin SPA
and back it with real multi-part session settlement:

Backend:
- New SessionPayment entity (session_payments table): partial payments
  per session with method (wallet/pos/cash/card), amount, paid_at, actor
- PatientSession: settlement discount (percent/fixed), discount_rials,
  paid_at, payments relation; remaining debt derived from
  final - discount - paid total
- POST /api/v1/session/{uuid}/payments: register a partial payment;
  wallet method debits the patient wallet; zero remaining marks paid
- PATCH /api/v1/session/{uuid}: accepts discount_type/discount_value
  (null removes) and paid_at, backward compatible
- New error codes: ERR_SESSION_PAYMENT_INVALID/_EXCEEDS,
  ERR_SESSION_DISCOUNT_INVALID
- Migration + 14 functional tests (partial/full/wallet/exceed/discount)

Frontend (admin):
- SessionPaymentPage: two-step stepper (پرداخت ← جزییات) ported from
  tauri AddService payment mode — service cost, settlement discount
  input, Jalali payment date, wallet balance, 4-method payment accordion,
  paid-list box, details summary
- SessionStepper + stepper/payment icons ported verbatim from tauri SVGs
- «تکمیل پرداخت» on SessionServiceCard now navigates to the payment page
  (replaces the small settle modal on PatientDetailPage)
- Routes for patients/ and my-patients/ variants; vitest coverage
- docs/api/patient.md updated

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 13:32:06 +03:30
hamedandClaude Opus 4.8 15c92903e1 feat: replace patient messages tab with pinnable notes
Port the tauri AddNoteModal notes feature into the admin patient case-file,
replacing the mislabeled «پیام‌ها» (SMS log) tab with «یادداشت‌ها».

Backend (src/Patient):
- PatientNote entity + repository (record-scoped, pinned-first ordering)
- CRUD endpoints on PatientController: GET /notes, POST /note,
  PATCH /note/{uuid} (edit body + toggle pin), DELETE /note/{uuid}
- author display name captured server-side from the current user
- migration for patient_notes; docs/api/patient.md updated

Frontend (assets/admin):
- NotesTab: compose box, newest/oldest sort, pinned-first list with
  accent rail + pin/edit/delete, edit modal, confirm-delete, empty state
- tab key/label/icon messages -> notes; onAddNote deep-links the notes tab

Tests: PatientNoteTest (create/list-order/edit/pin/delete/validation/ownership),
PatientDetailPage notes cases (render/empty/pin/create).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 12:51:33 +03:30
hamedandClaude Opus 4.8 ef97b2b249 feat: unify wallet with real payment methods, full transaction transparency, pay-session-from-wallet
Address wallet feedback: use the clinic's real payment infrastructure,
redesign the tab to match the admin panel, and make every wallet movement
fully auditable.

Backend:
- WalletTransaction: add createdBy (acting user) + createdByName, payment_method,
  reference, status; toArray exposes them (migration Version20260716083939).
- WalletService (Settlement): balance/charge/withdraw + settleSessionFromWallet,
  records actor/method/reason; insufficient balance throws ERR_WALLET_INSUFFICIENT.
- PatientController: charge/withdraw delegate to WalletService and accept
  payment_method/reference; PATCH /session/{uuid} with payment_method=wallet
  debits the patient's final share from the wallet (reference=session:{uuid}).
- docs/api/patient.md updated.

Frontend:
- Wallet modal redesigned to panel style (no gradient); payment method now uses
  the clinic's real bank accounts + POS devices (usePaymentMethods) plus cash.
- Wallet tab: panel balance card + DataTable ledger with columns مبلغ/نوع/روش/
  دلیل/ثبت‌کننده/تاریخ/ساعت/وضعیت + همه/واریزی/برداشت filters.
- Session card «تکمیل پرداخت» opens a payment-method chooser incl. کیف پول.

Tests: backend transparency + session-from-wallet (success/insufficient/cash);
frontend modal (real methods, toman→rials) + wallet tab + settle chooser.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 12:22:37 +03:30
hamedandClaude Opus 4.8 f028d6841a feat: port wallet charge/withdraw modal from tauri to patient admin page
Add manual wallet withdrawal (debit) endpoint mirroring the offline app's
balance guard, and rebuild the patient کیف پول tab around a single
charge/withdraw toggle modal (quick amounts, تومان→ریال conversion,
transaction filters).

Backend:
- POST /api/v1/patient/{uuid}/wallet/withdraw — creates a debit
  WalletTransaction; 422 ERR_WALLET_INSUFFICIENT when amount exceeds balance.
- ErrorCodes: ERR_WALLET_INSUFFICIENT ('موجودی کیف پول کافی نیست').
- docs/api/patient.md updated.

Frontend:
- usePatientWallet hook (balance + charge/withdraw mutations).
- WalletTransactionModal (toggle, quick amounts, UI-only payment fields).
- WalletTab: charge button, همه/واریزی/برداشت filters.

Tests: backend withdraw success/insufficient/non-positive/ownership;
frontend modal + wallet tab interactions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:56:39 +03:30
hamedandClaude Opus 4.8 1a783971c9 feat: port نوبت‌ها (appointments) tab from tauri to patient detail page
Replace the placeholder row list on the patient detail «نوبت‌ها» tab with the
card-grid design ported pixel-for-pixel from clinic-pro-tauri TurnsSection:

- New AppointmentTurnCard mirrors tauri TurnsCard (success icon, title, date/time
  chips, personnel, status). Status uses the live AppointmentStatusDropdown
  instead of the tauri mock.
- New AppointmentsTab in PatientDetailPage: sort/filter toolbar (client-side) +
  reserve/new buttons linking to existing /admin/appointments pages + card grid.
- Add CalendarD/ClockP/UserD/StatusGlobe icons (verbatim from tauri).
- Backend: expose version on GET /patient/{uuid}/appointments so the status
  dropdown can optimistic-lock. No new endpoint.
- Tests: PatientAppointmentsTest (shape/version/order/empty/ownership) +
  AppointmentTurnCard + tab data/empty cases. docs/api/patient.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:30:12 +03:30
hamedandClaude Opus 4.8 3e8126c520 fix: return patient national code from profile in patients list
National code is stored on the profiles table, not users, so the patients
search returned null user_national_code for patients that actually have one
— which blocked selecting an existing patient on the appointment create
form. Backfill user_national_code from the profile (batch query) in the
list endpoint. On the create page, show a picked patient's stored national
code read-only and only prompt for input when the record genuinely lacks
one. Add backend tests and update docs/api/patient.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:57:03 +03:30
hamed de6fe1bd56 feat(appointment): update patient identification to use national code from profile and enhance appointment creation logic 2026-07-15 18:46:56 +03:30
hamedandClaude Opus 4.8 5548d79d4c feat(appointment): identify admin-booked patient by national code
Admin-side booking (POST /api/v1/my/appointment and
/api/v1/admin/appointment) resolved the patient User by mobile only, so
one person booked under two mobiles produced two User rows — and two
case-files, since PatientRecord is keyed on user_id. National code is the
real unique identity (User.national_code is already unique); a person may
have several mobiles.

Booking now requires + validates patient_national_code and resolves the
patient national-code-first (then mobile) via a shared PatientResolver, so
the case-file stays unique per national code even across mobiles. Reusing a
mobile already bound to a different national code returns 422
ERR_PROFILE_MOBILE_TAKEN. The admin create form and NewAppointmentDrawer
gain a national-code field and send it; both had a dead patient-picker URL
(/api/v1/patient) fixed to the real /api/v1/patients, whose payload already
carries user_national_code for autofill.

Docs (appointment.md, admin.md) and tests updated; new
AppointmentNationalCodeTest covers success, single-file reuse, missing,
invalid, and identity-conflict cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 18:11:40 +03:30
hamedandClaude Opus 4.8 fd91840ba2 feat(patients): inline tag popover + advanced filters on the records list
Port the remaining pieces of tauri /files list into /admin/patients:

- inline tag assignment: the برچسب‌ها cell (table + card) opens a popover to
  assign/remove tenant tags without leaving the list. Uses existing endpoints
  (GET /api/v1/tenant-tags + PATCH /api/v1/patient/{uuid} { tags:[uuid] }).
  New component assets/admin/components/PatientTagsCell.tsx.
- advanced filter modal (PatientsFilterModal): admission date range, insurance,
  service status (pending/completed), has-debt, gender, tags — wired to the
  list query with an active-filter badge on the button.

Backend: GET /api/v1/patients gains tags/gender/insurance_id/admitted_from/
admitted_to/service_status/has_debt filters via a shared applyFilters() on
PatientRecordRepository (findByEntity + countByEntity stay consistent). Debt
and service status derive from unpaid sessions (payment_method='pending'),
documented in docs/api/patient.md.

Tests: tests/Patient/PatientListFilterTest.php (5) + PatientsListPage tag-popover
and filter-apply tests. Pre-existing LoginPage.test failures are unrelated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:40:54 +03:30
hamedandClaude Fable 5 165ececab4 feat(appointments): close the three remaining design gaps
1. شارژ کیف پول is now functional end-to-end. New owner-gated
   POST /api/v1/patient/{uuid}/wallet/charge creates a manual credit
   WalletTransaction (computed balance_after); the patient detail's wallet tab
   gains a top-up modal (PriceInput + description) and supports ?tab= deep
   links. The deposit sections of the create drawer, the edit page and the
   replace modal link to it via WalletChargeLink (record resolved by mobile).
2. جایگزینی نوبت now matches appointments-replace.pdf: patient search-or-new,
   بخش/سرویس/پرسنل selects prefilled from the appointment, deposit toggle +
   amount + charge link, read-only original date/time, status pick and notes —
   all through the general PATCH.
3. The confirmed-appointments table is paginated (20/page, client-side so the
   schedule view and doctor-tab derivation keep the whole day), resetting on
   date/doctor/filter changes. The page-local STATUS_META also adopts the
   design labels plus following_up/salon for the schedule cards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 00:26:47 +03:30
hamedandClaude Opus 4.8 665a210ef8 feat(patients): phase D — call-center tab (patient call log)
Add a record-scoped PatientCall entity (subject, summary, outcome
success/missed, called_at, personnel) with its repository and three
owner-gated endpoints on PatientController:

  GET    /patient/{uuid}/calls   — call log, newest first, optional ?outcome
  POST   /patient/{uuid}/call    — log a call (subject required)
  DELETE /patient/call/{uuid}    — delete an entry

Wire the previously-placeholder "کال سنتر" tab as a CallCenterTab: a register
form (date/time/subject/summary + success/missed toggle, personnel taken from
the logged-in user) beside a filterable call history (all / success / missed).
With this every patient-detail tab is now backed by a real endpoint, so the
generic Placeholder is no longer reachable. PatientCallTest covers create/list/
delete, the outcome filter, the invalid-outcome fallback, and ownership scoping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 16:01:16 +03:30
hamedandClaude Opus 4.8 61981a45d0 feat(patients): phase C — patient financial tabs (payments, wallet, transactions)
The generic wallet/payment endpoints are bound to #[CurrentUser] (the
requester's own money), so they cannot serve a record owner viewing a patient's
finances. Add three record-owner-gated read endpoints on PatientController that
reuse the existing repositories:

  GET /patient/{uuid}/payments             — paginated gateway payments (?status)
  GET /patient/{uuid}/wallet               — balance + 10 recent transactions
  GET /patient/{uuid}/wallet/transactions  — full paginated ledger

Wire the previously-placeholder "پرداخت‌ها" and "کیف پول" tabs on the patient
detail page: payments via the shared TabList, wallet via a new WalletTab (balance
card + credit/debit ledger). PatientFinancialsTest covers the happy path, the
credit−debit balance, and ownership scoping (404 for a different owner).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:53:04 +03:30
hamedandClaude Opus 4.8 5fb4c52246 feat(patients): phase B4 — messages (پیام‌ها)
Add a patient message/communication log: a new PatientMessage entity
(record-scoped, CASCADE) + repository, and owner-scoped endpoints
(GET messages, POST message, DELETE message) with a validated channel
(sms/note/call/email). Wire the "پیام‌ها" tab in PatientDetailPage
(send box + list + delete). PHPUnit covers create/list/delete + ownership
+ validation; Vitest covers the tab. API docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:35:10 +03:30
hamedandClaude Opus 4.8 293eb8a0d2 feat(patients): phase B3 — medical records (پرونده پزشکی)
Add patient medical-exam entries: a new PatientMedicalRecord entity
(record-scoped, CASCADE) + repository, and owner-scoped CRUD endpoints
(GET list, POST create, PATCH, DELETE) under /api/v1/patient. Wire the
"پرونده پزشکی" tab in PatientDetailPage (list + add/edit modal with title,
date and notes + delete). PHPUnit covers CRUD + ownership + validation;
Vitest covers the tab. API docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:27:34 +03:30
hamedandClaude Opus 4.8 537bb8c7b3 feat(patients): phase B2 — attachments (ضمیمه)
Add patient file attachments: a new PatientAttachment entity (record-scoped,
CASCADE) + repository, and endpoints GET /patient/{uuid}/attachments,
POST /patient/{uuid}/attachment (raw-body upload) and DELETE
/patient/attachment/{uuid} (owner-scoped). Factor the shared raw-body upload
logic into FileUploadService. Wire the "ضمیمه" tab in PatientDetailPage
(upload + list + delete). PHPUnit covers list/delete/ownership; Vitest covers
the tab. API docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:20:00 +03:30
hamedandClaude Opus 4.8 15c6f5dce7 feat(patients): phase A — records list + create/edit form (Figma)
Rebuild the patient records (پرونده‌ها) area, phase A of the Figma redesign:

- BE: add a clinic-scoped `record_number` and a TenantTag `tags` M2M to
  PatientRecord (migration + EAGER-hydrated collection). POST /patient and
  PATCH /patient/{uuid} now accept `record_number` and tenant-scoped `tags`
  (foreign tag → 422); demographic fields (gender, date_of_birth,
  referral_source, description) continue to live on UserProfile via PATCH.
- FE: new PatientsListPage (table + card views, search, pagination, tags
  column, "تشکیل پرونده") at /admin/patients, and PatientRecordFormPage
  (create/edit) that POSTs the record then PATCHes the demographics. Point
  the sidebar "پرونده" entry to the new list.

Phases B–E (tabbed patient file, service stepper, invoice, payments/wallet,
call-center) follow. Backend covered by PHPUnit, FE by Vitest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:54:38 +03:30
hamedandClaude Opus 4.8 580bc983b3 feat(patient): complete "اطلاعات پرونده" demographic form
Backend:
- Add profile columns field_of_study, province_id, city_id, postal_code,
  referral_source (UserProfile + migration).
- Extend PATCH /api/v1/patient/{uuid} to persist all demographic fields
  and return them in the patient profile payload.
- Support editable mobile (login identifier): validation, uniqueness,
  User.setMobileNumber, new ERR_PROFILE_002.
- Update docs/api/patient.md.

Frontend:
- New reusable Input, Field, and PatientRecordInfoForm (RHF + Zod).
- usePatient/useUpdatePatient hooks and patientForm mapping helpers.
- Extend the existing "info" tab in MyPatientsPage to the full field set
  via the shared form (province/city/insurance options, Jalali date).

Tests: Patient entity + PATCH integration (PHPUnit); form, hooks, and
mapping helpers (Vitest).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 11:51:18 +03:30
hamed a4a17bf8c7 feat: add patient appointment interface and endpoints
- Introduced `PatientAppointment` interface to define appointment structure.
- Implemented `findByUserAndDoctorIds` method in `AppointmentRepository` to retrieve appointments for a user filtered by doctor IDs.
- Added `acceptedDoctorIdsByClinic` method in `ClinicDoctorInvitationRepository` to get accepted doctor IDs for a clinic.
- Created new endpoint in `PatientController` to fetch appointments for a patient, ensuring only relevant doctors' appointments are displayed.
2026-07-13 10:15:44 +03:30
hamed f15c57d73c feat(patient): enhance session management with billing details and service tracking 2026-07-12 22:09:13 +03:30
hamedandClaude Opus 4.8 fdce888e0e feat(patient): edit patient basic info (doctor/clinic/secretary)
Add PATCH /api/v1/patient/{uuid} to update User.realName + UserProfile
demographic/insurance fields (mobile stays immutable, national_code
uniqueness enforced). Expose name/family separately in profile payload.
Add edit modal in my-patients. Update patient.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 22:00:33 +03:30
hamedandClaude Opus 4.8 66ab597efd fix(audit): low-tier — session patient-gate + 201 statuses (L1, L11) + triage
L1: PATCH /session now enforces the patient_records subscription gate like its
sibling endpoints (ownership was already checked; the feature gate was missing).
L11: POST /pre-registration and POST /representation/iban return 201 on create.

Remaining low-tier findings triaged and accepted without change (documented in
docs/audit-backlog.md): L8 is a false positive (FK auto-indexed), L6/L7/L9 are
marginal indexes, L4/L5 are small bounded N+1, L2/L3/L10/L12 are minor — none
with security/integrity impact.

Regression: tests/Audit/LowTierFixesTest (both fail without the fix).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 21:21:03 +03:30
hamed 8b96753df6 perf(db): add missing indexes (appointment expiry, session dates, user status)
- appointments(status, expires_at): the per-minute expiry scheduler filtered on
  these with no covering index
- patient_sessions(created_at): dashboard revenue range scans
- users(status): admin user-list filter

PatientRecord(entity_type,entity_id) already covered by its unique constraint;
UserActiveContext.user_id is the PK — neither needed a new index.
2026-06-28 17:13:44 +03:30
hamed 8b419d0272 feat(profile): enhance national_code uniqueness error message with masked mobile number 2026-06-24 12:16:16 +03:30
hamed 650e36bce2 feat(profile): enforce uniqueness of national_code across user profiles and update related error handling 2026-06-24 11:52:13 +03:30
hamed 91fb55258a feat(claims): enhance claims filtering with insurance, date range, and patient search 2026-06-24 06:19:25 +03:30
hamed c189daa860 feat(claims): enrich claims with insurance details and item specifics 2026-06-24 04:48:11 +03:30
hamed 27840da78d feat: integrate insurance coverage management for clinic services
- Updated NewSessionPage to calculate patient share based on insurance coverage rules.
- Refactored billing calculations to utilize new patientShareOf function for service items.
- Enhanced API documentation to reflect changes in service coverage structure.
- Implemented ServiceInsuranceModal for managing insurance coverage per service.
- Added UI components for displaying and editing insurance coverage details.
- Removed obsolete toggle switch styles and adjusted CSS for new components.
- Ensured backend endpoints support both service_item_id and service_item_uuid for flexibility.
2026-06-24 04:23:50 +03:30
hamed f7eb1ebd91 feat(claims): implement automatic claim creation for insurance sessions 2026-06-24 02:08:12 +03:30
hamedandClaude Opus 4.8 0e6111f1be feat(patients): service quantity in visit session
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 22:13:51 +03:30
hamedandClaude Opus 4.8 2206f02396 feat: enrich patient record with full profile
GET /api/v1/patient/{uuid} now returns a `profile` object from UserProfile
(demographics, contact, insurance names resolved). Admin record detail shows
a "patient info" section. Empty fields render as "ثبت نشده".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:21:33 +03:30
hamedandClaude Opus 4.8 af881231d0 fix: store appointment address from schedule and auto-add patient to clinic
Appointments now persist address_id resolved from the weekly-schedule
session (location_id) across all booking paths (online, secretary, admin).
On confirm, the patient is added to the clinic owning that address, or to
the doctor's single clinic as fallback. Weekly-schedule create/update now
requires location_id on every active session. PatientSession exposes
doctor_uuid/doctor_name so clinic records show which doctor each visit is for.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 16:10:36 +03:30
hamedandClaude Opus 4.8 51d7e24e04 feat: create patient record without prior signup
Extend POST /api/v1/patient to resolve user by uuid or mobile, and
create a new ROLE_USER (name + optional national code, no password)
when no user exists. Admin modal shows a new-patient form on lookup miss.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:20:56 +03:30
hamedandClaude Opus 4.8 89191eee57 feat: insurance & medical billing system (6 phases)
Multi-tenant insurance contracts, service coverage, versioned tariffs,
invoice calculation, and insurance claims with debt reporting.

- TenantInsurance: per-tenant insurance contracts (coverage/franchise/ceiling,
  versioning, soft-deactivate) + active guard
- ServiceItem.insuranceCovered + TenantServiceCoverage per-service overrides
- Tariff: versioned yearly tariffs with fallback to ServiceItem price
- Billing domain: Money/ShareBreakdown VOs, BillingCalculator (unit-tested),
  Invoice/InvoiceItem aggregate, InvoiceService.createFromSession
- Claim/ClaimItem with state machine (pending->submitted->approved/rejected->paid),
  ClaimService, insurance-debt report
- ClaimSubmitterInterface + ManualClaimSubmitter (future insurance API ready)
- Admin UI: insurance-pricing page, claims page, service tariff modal,
  service insurance toggle; routes + sidebar entries
- Architecture doc + billing/insurance/clinic-services API docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:05:24 +03:30
hamed 5b1dfe9b40 feat: add national code to patient records and user entity, update related functionality 2026-06-22 19:44:17 +03:30
hamed ec36eefeb8 feat: add OpenAPI tags to various controllers for improved API documentation 2026-06-15 14:54:10 +03:30
hamed d13d8436ab feat(patient): add search user functionality by mobile number 2026-06-15 12:52:45 +03:30
hamed 4bf381ac94 feat(secretary): implement scope separation for secretaries in clinics and personal practices
- Added `owner_type` and `clinic_id` fields to `DoctorSecretary` entity to distinguish between clinic and personal practice relationships.
- Updated repository methods to be scope-aware, allowing for specific queries based on the context of the secretary's relationship (clinic or doctor).
- Modified `SecretaryController` to handle secretary creation with appropriate scope based on the current user's role.
- Enhanced `AuthController` to build contexts that reflect the scope of the secretary's access.
- Updated `DashboardController` and `PatientController` to respect the new scope logic when retrieving data.
- Created migration to update the database schema accordingly, dropping the old unique constraint and adding the new fields and constraints.
2026-06-15 11:19:37 +03:30
hamed 5cdcec23a9 feat: enhance staff management and payment gateway features
- Fix national code handling in staff creation and updates to support Persian digits.
- Update ClinicStaff entity to allow longer national codes (up to 15 characters).
- Implement support for clinic secretaries in SecretaryController, allowing creation without a doctor UUID.
- Add a new endpoint to retrieve doctors associated with a clinic for secretary management.
- Improve appointment management by ensuring doctors are selectable even when no appointments exist.
- Extend PatientController to allow secretaries to create patient records if they have the appropriate permissions.
- Introduce a PriceInput component for better price formatting in forms, supporting Persian digits.
- Add a MockGateway for testing payment processes without real transactions.
- Enhance SMS settings management with an approval flow for post-visit text messages, including new fields for pending text and status.
- Update migrations to reflect changes in database schema for national codes and SMS settings.
2026-06-15 11:03:56 +03:30
hamed b0244f28f5 feat: implement staff management and subscription system
- Added StaffController for managing clinic staff, including listing, creating, updating, and toggling staff status.
- Created ClinicStaff entity and repository for staff data handling.
- Developed SubscriptionController to manage subscription plans and periods, including trial subscriptions.
- Introduced SubscriptionPlan, SubscriptionPeriod, and ClinicSubscription entities for subscription management.
- Implemented SubscriptionService for handling subscription logic, including trial activation and subscription creation from payments.
- Added necessary repositories for subscription entities to facilitate data access and manipulation.
2026-06-14 22:10:28 +03:30