createAppointment only checked the caller held an allowed role, then booked
onto whatever doctor_uuid the request named — a doctor could book onto any
other doctor's calendar, a clinic onto doctors outside it, a secretary outside
their scope. Add canBookForDoctor(): doctor→own only, clinic→member doctors,
secretary→active scope + appointments.create permission, admin→any.
Regression: tests/Appointment/BookingScopeTest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The callback marked an order success on any verify-ok result without comparing
the gateway-settled amount to the amount charged. SEP returns AffectiveAmount;
an underpayment or a replayed RefNum from a cheaper order would confirm the
expensive order. Now reject (status=failed, no activation) when the gateway
reports an amount that mismatches the stored amount_rials. Gateways that don't
report a settled amount (Mellat binds it server-side) skip the check.
MockGateway now echoes mock_amount so the guard is exercisable in tests.
Regression: tests/Payment/PaymentCallbackAmountTest (underpayment rejected,
matching amount succeeds).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Persists the audit plan so a session restart no longer loses it (TodoWrite
is volatile). 10 done, 1 critical, 10 high, 21 medium, 12 low, 4 epics.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>