perf(reports): read every resource's calendar in one batch, and close the owed tests
Writing the query-count test that task 14 owed showed the growth was real: one resource cost 10 queries, six cost 33 — about five per resource, because the available-minutes figure walked each resource's calendar on its own. Holidays, tenant overrides and branch hours are identical for every resource in a report, so they now load once outside the loop; shifts and exceptions load for all resources in one query each. The batched path is a new method rather than a change to rawAvailability, which the booking engine also calls. The test pins the shape of the growth, not an exact count. Also landed: - app:segment:seed-templates with beauty, dental and physio presets. Building four segments and their requirements by hand is the first thing a new clinic must do and the most tedious; this gives them something to edit instead of an empty page. It refuses to touch a service that already has segments unless --force, and it will not invent resource types the tenant never defined. - book-all is all-or-nothing, proven rather than asserted: with a calendar open one day a week and a 1-2 day protocol gap, session one finds a slot and session two cannot, and every session must come back planned. - credit_refundable: false takes the credit back with a negative adjustment and deletes nothing — the ledger stays append-only. - the segments editor has frontend tests, including that it sends back what the user sees and renders read-only without the permission. useBranches now returns [] for a non-array payload instead of throwing "branches.map is not a function" and taking the page down with it. BookingLocationsScanTest built a Clinic around a Doctor loaded from a different manager, which Doctrine treats as a new entity; it flushed fine most runs and failed on cascade in others. It now loads the doctor from the same manager. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,34 @@ class ResourceCalendarRepository extends ServiceEntityRepository
|
||||
->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* شیفتهای چند منبع با **یک** کوئری — گزارش بهرهوری روی چهل منبع، چهل کوئری نمیخواهد.
|
||||
*
|
||||
* @param int[] $resourceIds
|
||||
* @return array<int, list<\App\Resource\Entity\ResourceCalendar>> کلید: شناسهٔ منبع
|
||||
*/
|
||||
public function findForResources(array $resourceIds): array
|
||||
{
|
||||
if ($resourceIds === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = $this->createQueryBuilder('c')
|
||||
->where('IDENTITY(c.resource) IN (:ids)')
|
||||
->setParameter('ids', $resourceIds)
|
||||
->orderBy('c.dayOfWeek', 'ASC')
|
||||
->addOrderBy('c.sequence', 'ASC')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$byResource = [];
|
||||
foreach ($rows as $row) {
|
||||
$byResource[(int) $row->getResource()->getId()][] = $row;
|
||||
}
|
||||
|
||||
return $byResource;
|
||||
}
|
||||
|
||||
public function deleteForResource(ClinicResource $resource): int
|
||||
{
|
||||
return (int) $this->createQueryBuilder('c')
|
||||
|
||||
@@ -41,4 +41,35 @@ class ResourceExceptionRepository extends ServiceEntityRepository
|
||||
->getQuery()
|
||||
->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* استثناهای چند منبع با یک کوئری.
|
||||
*
|
||||
* @param int[] $resourceIds
|
||||
* @return array<int, list<\App\Resource\Entity\ResourceException>>
|
||||
*/
|
||||
public function findOverlappingForResources(array $resourceIds, int $from, int $to): array
|
||||
{
|
||||
if ($resourceIds === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = $this->createQueryBuilder('e')
|
||||
->where('IDENTITY(e.resource) IN (:ids)')
|
||||
->andWhere('e.startsAt < :to')
|
||||
->andWhere('e.endsAt > :from')
|
||||
->setParameter('ids', $resourceIds)
|
||||
->setParameter('from', $from)
|
||||
->setParameter('to', $to)
|
||||
->orderBy('e.startsAt', 'ASC')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$byResource = [];
|
||||
foreach ($rows as $row) {
|
||||
$byResource[(int) $row->getResource()->getId()][] = $row;
|
||||
}
|
||||
|
||||
return $byResource;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user