Commit Graph
22 Commits
Author SHA1 Message Date
hamedandClaude Fable 5 f2ea2ff262 feat(admin): session edit form, payment edit/delete UI, and audit history modal
- SessionServiceCard menu gains «ویرایش» and «تاریخچه تغییرات» items.
- SessionAuditModal shows the session's change history (field, op badge,
  old->new, actor, time) from /session/{uuid}/audit-log.
- PaymentStep payment rows get edit (modal) + delete (confirm) controls for
  non-wallet payments, calling the new PATCH/DELETE payment endpoints.
- CreateStep accepts an editSession prop (prefill + PATCH); EditSessionPage
  reuses it at /patients/:recordUuid/session/:sessionUuid/edit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:23:02 +03:30
hamedandClaude Fable 5 0d943d8fc5 feat(admin): session action menu (view invoice + archive) and archive filter
SessionServiceCard's '...' icon becomes a real dropdown with «مشاهده فاکتور»
and «آرشیو»/«خروج از آرشیو» (click-outside close), plus an «آرشیو» badge on
archived cards. PatientDetailPage adds a فعال‌ها/همه/آرشیو segmented filter on
the services tab (default active), threads the filter into the sessions query,
and wires the archive action to PATCH /session/{uuid} { archived }.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 14:48:08 +03:30
hamedandClaude Opus 4.8 76bfa5d36f fix: issue invoice on demand so view-invoice buttons actually work
The admin SPA never called POST /billing/invoices, so every session had
invoice_uuid = null and the view-invoice buttons on the patient services
tab (and MyPatients visit modal) were permanently disabled. Add a shared
useIssueInvoice hook (idempotent create + finalize when draft) and wire
it into:
- DetailsStep: the wizard's final step now really issues the invoice
- SessionServiceCard / PatientDetailPage: clicking view-invoice on a
  session without an invoice issues it first, then opens the summary
- MyPatientsPage visit modal: same, replacing the dead disabled button

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 15:39:02 +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
hamed 65083854cb feat: set default date and time in CallCenterTab, update input styles 2026-07-16 12:38:22 +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 069189863c feat: port پرداخت‌ها (payments) tab from tauri to patient detail page
Replace the flat gateway-payment list on the patient detail «پرداخت‌ها» tab with
the session-grouped accordion design ported from clinic-pro-tauri PaymentsSection:

- New SessionPaymentAccordion mirrors the tauri accordion: header (service, date,
  final price, پرداخت شده/تسویه نشده badge) + a settlement line (date, amount,
  method, personnel=doctor) or the «هیچ پرداختی ثبت نشده است.» empty message.
- New PaymentsTab reuses the already-fetched sessions query (real model = one
  payment_method per session) — no extra request, no backend change, no new API.
- Add FilesServicePaymentsCheck icon (verbatim from tauri).
- Remove the now-unused paymentsQ (gateway list), PAYMENT_STATUS map and the dead
  TabList helper (both its callers replaced by the ported card/accordion tabs).
- Tests: SessionPaymentAccordion (paid/unpaid/collapsed/toggle) + updated the page
  payments-tab test to assert session accordions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 11:40:51 +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 46ee24d101 feat: add supplementary insurance select to patient record info form
The «اطلاعات پرونده» form only exposed basic insurance («نوع بیمه»). Add a
«بیمه تکمیلی» select next to it, wired to the supplementary insurances from
insurance-pricing. Backend PATCH /api/v1/patient/{uuid} already accepts
supplementary_insurance_id (UserProfile entity + controller) — frontend-only:
schema field, form select, profileToFormValues/formValuesToPayload mapping,
PatientProfileUpdate type, and the supplementary option passed from both the
case-file info tab (PatientDetailPage) and MyPatientsPage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:59:23 +03:30
hamedandClaude Opus 4.8 9638f363af feat: wire editable «اطلاعات پرونده» form into patient case-file info tab
Port tauri /files-services FileInfoSection into PatientDetailPage's info
tab. The tab previously rendered a stripped read-only InfoRow list; it now
renders the inline editable PatientRecordInfoForm (18 fields + ثبت اطلاعات),
matching the tauri source. Reuses the existing form component, patientForm
helpers, and the already-present patient/provinces/cities/insurance-pricing
endpoints (no new API). PATCH /api/v1/patient/{uuid} on submit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 10:52:31 +03:30
hamedandClaude Opus 4.8 f0b7a51b8f fix: make patient detail page full-width to match tauri FilesServices
Removed the maxWidth:1060 centered wrapper on PatientDetailPage that
boxed the page; tauri's FilesServices renders full-width in a plain Box.
Added a regression test asserting the root wrapper has no max-width cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 11:16:40 +03:30
hamedandClaude Opus 4.8 be4d63744d feat(patients): port tauri /files-services detail pixel-for-pixel
Rebuild the patient case-file (/admin/patients/:uuid) to match tauri
files-services:
- breadcrumb (پرونده > name) + 140px patient banner (name + completion chip,
  file number, tag dots, phone/date rows, next appointment, یادداشت button)
  ported from BreadcrumbHeader + FileServicesHeader.
- services tab: replaced the plain list with the ServiceCard «مراجعه» grid —
  each card = a session (visit + performed services): success icon, services
  subtitle, doctor/date/notes rows, cost + remaining debt, تکمیل پرداخت
  (settles the session) / مشاهده فاکتور.
- مشاهده فاکتور opens InvoiceSummaryModal (خلاصه فاکتور tables) fed by the real
  invoice (GET /billing/invoices/{uuid}).
- tab bar now uses the tauri custom SVG icons.
- 20+ SVGs ported verbatim into components/icons/FilesServiceIcons.tsx; new
  components SessionServiceCard, PatientCaseBanner, InvoiceSummaryModal.

Frontend only — the sessions endpoint already returns invoice_uuid /
patient_debt_rials / is_paid. Tests updated (9 green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 10:36:47 +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 3036c0bf45 feat(patients): phase B5 — wire service creation into the detail page
Reuse the existing NewSessionPage (service section/item + insurance coverage +
payment flow → POST /patient/{recordUuid}/session) from the new patient detail:
add a patients-scoped route /admin/patients/:recordUuid/session/new and a
"سرویس جدید" action on the services tab. The multi-step visual restyle and the
standalone invoice-issuance screen remain a follow-up (the underlying
session/billing endpoints already exist).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:40:52 +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 7ac875a7a6 feat(patients): phase B1 — tabbed patient detail page
Add a standalone PatientDetailPage at /admin/patients/:uuid: a header + the
9-tab case-file bar (services, info, appointments, payments, wallet, messages,
call-center, attachments, medical-record). The info, services (sessions) and
appointments tabs are wired to existing endpoints; the remaining tabs render a
placeholder until their backends land (phases B2–B5). The list "مشاهده" action
now opens this detail page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:08:53 +03:30