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>
A representation editing its own record could raise its own commission or
self-activate (privilege escalation). Restrict both fields to ROLE_ADMIN and
range-check commission (0–100). Owner can still edit name/city/bank.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- container_xml_path -> containerXmlPath (phpstan-symfony v2 rename); the old
key made phpstan abort with an invalid-configuration error, so analysis
silently never ran
- add the missing tests/doctrine_object_manager.php loader
- drop a stale ignoreErrors pattern
phpstan now runs and surfaces 42 pre-existing level-5 errors (tracked separately).
AppointmentExpiryService ran one findPendingByAppointment query per expiring
booking. Add PaymentRepository::findPendingByAppointments (one IN query keyed
by appointment id) and use it. Test covers expiry + payment cancellation for
several appointments at once.
Auto-discovers each mapped entity that has a sibling <Entity>Repository class
and asserts getRepository() returns it (not Doctrine's default). Catches the
prod-only opcache.preload bug class that broke /oauth/userinfo.
getOverride leaked any doctor's override to any authenticated user; add the
owner-or-admin check (matching the update/delete endpoints) + regression test.
getSchedule returned any doctor's schedule to any authenticated user — the
mutation endpoints (update/delete) already checked owner-or-admin but this GET
did not. Add the same check + regression test (fails without the fix).
- Add SendSmsMessage class for encapsulating SMS message data.
- Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS.
- Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates.
- Develop SendSmsHandler for handling SMS sending messages.
- Create SmsService to manage SMS dispatching and logging.
- Add UserProfileController for managing user profiles with CRUD operations.
- Implement UserProfile entity and repository for user profile data management.
- Update symfony.lock and bootstrap.php for project dependencies and environment setup.