Commit Graph
3 Commits
Author SHA1 Message Date
hamedandClaude Opus 5 826b940c00 Add the resource↔service link that decides who offers what, and for how much
Until now a resource was picked by type and skill alone, so two devices of the
same type were indistinguishable even when only one of them performed the
service — and there was nowhere to say that this doctor takes 30 minutes for a
filler while that one takes 45.

ResourceServiceOffering is that link: resource ↔ service item, with an optional
duration, an optional price and an active flag. Because a "service option" here
is itself a ServiceItem inside an ItemGroup, one table covers both levels the
spec asks for — a row against the parent item is "resource + service", a row
against a member item is "resource + option". A third table would have meant
two sources of truth for one concept and a rewrite of every path that already
speaks ServiceItem.

It is an aggregate child of ClinicResource, like ResourceSkill: no tenant
columns of its own, since the resource already carries the pair and a copy is
just something that can drift. The constructor refuses a resource and a service
from different environments — TenantFilter does not cover that case, as both
uuids arrive from the request body and the filter does not apply to aggregate
children.

null means inherit, not zero: an explicit zero is a duration that does not
exist, while null means this resource has nothing to say and the resolver
should look one level up. Zero and negative values are rejected outright.

Tests cover the pair being stored, the duplicate pair hitting the unique
constraint, the cross-environment guard, null-means-inherit, one service across
two devices with different numbers, and deactivating without losing them.

Suite 1264 green, phpstan at its 14-error baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 21:01:18 +03:30
hamedandClaude Opus 5 8280aa7578 Remove the policy, package, course, cancellation and event subsystems
The product owner scoped the booking model down to resources, services and
service options; everything else goes. Deleted, with their tables, tests, panel
pages and API routes:

  src/Policy      27 files   policy engine, simulation, templates
  src/Package     13 files   packages and the credit ledger
  src/Course      14 files   treatment protocols and courses
  src/Cancellation + src/Waitlist  19 files  penalties, no-shows, waitlist
  src/Report + src/Shared/Event    events outbox and the two reports

The surviving code had hooks into all of them, so this is not only deletion:

- AppointmentPlanBuilder loses the timing and resource policy passes, and the
  requirement-from-policy builder that had no other caller (449 → 379 lines)
- PricingEngine loses policy discounts and package coverage; PriceQuote loses
  its package fields and quote() its patient argument, which existed only to
  find a usable package
- BookingService no longer consumes credit, unlinks course sessions or emits
  events; HoldService and ResourceBlockController stop emitting too
- ServiceSelectionValidator keeps groups and relations, drops the policy layer
- the appointment loses its course_session link

Cancelling an appointment still works and still records who and why — it moves
through PATCH /api/v1/appointment/{uuid}/status. What it no longer does is
compute a penalty, so the panel dialog is a plain confirm now. That is the
visible cost of this change and it is intended, not an oversight.

The drop migration uses DROP TABLE IF EXISTS with foreign-key checks off: a
half-applied earlier run left some tables already gone, and a migration that
only works from a pristine schema is a trap on any environment that was
interrupted. messenger_messages is deliberately left alone — it is Symfony's,
not ours.

Suite green at 1258 tests, slot-mode-frozen green, phpstan back to its 14-error
baseline after removing two now-unused members it caught, tsc clean, and
app:seed-scenarios still builds all three environments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 20:51:41 +03:30
hamedandClaude Opus 5 4711ba0af7 docs: prompt and checklist for the resource-first booking model
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 20:13:55 +03:30