Refactor booking system: Remove unused policies, packages, and related entities
- Removed package consumption flags and related properties from PriceQuote. - Eliminated unused domain event publishing for policies and waitlist in Schedule. - Cleaned up BookingEngineSeeder by removing package and policy related logic. - Updated SeedScenariosCommand to reflect removal of policies from output. - Dropped policy, package, treatment course, cancellation, waitlist, and domain event tables in migration. - Removed domain event assertions from tests related to resource blocking.
This commit is contained in:
@@ -13,8 +13,6 @@ use App\Auth\Repository\UserRepository;
|
||||
use App\Doctor\Repository\DoctorRepository;
|
||||
use App\Pricing\Entity\PriceSnapshot;
|
||||
use App\Pricing\Service\PriceSnapshotService;
|
||||
use App\Package\Service\PackageConsumptionService;
|
||||
use App\Policy\Service\BookingPolicyGuard;
|
||||
use App\Pricing\Service\PricingEngine;
|
||||
use App\Appointment\Plan\Service\AppointmentPlanBuilder;
|
||||
use App\Auth\Entity\User;
|
||||
@@ -25,8 +23,6 @@ use App\Resource\Entity\ClinicResource;
|
||||
use App\Resource\Repository\ClinicResourceRepository;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Controller\BaseController;
|
||||
use App\Shared\Event\DomainEventPublisher;
|
||||
use App\Shared\Event\DomainEvents;
|
||||
use App\Shared\Exception\AppException;
|
||||
use App\Shared\Tenant\TenantOwnershipChecker;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -56,38 +52,11 @@ class BookingController extends BaseController
|
||||
private readonly PricingEngine $pricing,
|
||||
private readonly PriceSnapshotService $snapshots,
|
||||
private readonly BranchResolver $branches,
|
||||
private readonly BookingPolicyGuard $guard,
|
||||
private readonly PackageConsumptionService $packages,
|
||||
private readonly TenantOwnershipChecker $ownership,
|
||||
private readonly AppointmentSegmentRepository $segments,
|
||||
private readonly DomainEventPublisher $domainEvents,
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* پرچمهایی که فقط در همین درخواست وجود دارند و جایی ذخیره نمیشوند
|
||||
* (مثل رضایت والدین که اپراتور همان لحظه میگیرد).
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function requestFlags(array $data): array
|
||||
{
|
||||
$flags = [];
|
||||
|
||||
foreach (['has_parental_consent'] as $flag) {
|
||||
if (isset($data[$flag])) {
|
||||
$flags[$flag] = (bool) $data[$flag];
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($data['patient_gender'] ?? null)) {
|
||||
$flags['patient_gender'] = $data['patient_gender'];
|
||||
}
|
||||
|
||||
return $flags;
|
||||
}
|
||||
|
||||
#[Route('/api/v1/appointment-hold', name: 'appointment_hold_create', methods: ['POST'])]
|
||||
public function create(#[CurrentUser] User $user, Request $request): JsonResponse
|
||||
{
|
||||
@@ -128,9 +97,6 @@ class BookingController extends BaseController
|
||||
is_string($data['patient_gender'] ?? null) ? $data['patient_gender'] : null,
|
||||
);
|
||||
|
||||
// قوانین وابسته به بیمار پیش از گرفتن صندلی اجرا میشوند، نه هنگام ثبت نهایی.
|
||||
$this->guard->assertEligible($user, $service, $selected, $address, $this->requestFlags($data));
|
||||
$this->guard->assertSpacing($user, $service, $address, (int) $data['start']);
|
||||
|
||||
$assignment = $this->resolveAssignment($user, $data['assignment']);
|
||||
$this->assertAssignmentCoversPlan($plan, $assignment);
|
||||
@@ -255,19 +221,6 @@ class BookingController extends BaseController
|
||||
$this->booking->confirm($hold, $appointment);
|
||||
$released = $this->booking->cancel($appointment);
|
||||
|
||||
// `confirm` و `cancel` هرکدام رویداد خودشان را ثبت کردهاند؛ این سومی میگوید آن دو
|
||||
// یک جابهجایی بودهاند نه یک لغو و یک رزروِ بیربط. مصرفکنندهای که فقط
|
||||
// `AppointmentCancelled` را بشنود، برای بیماری که هنوز نوبت دارد پیام لغو میفرستد.
|
||||
$this->domainEvents->recordAndFlush(
|
||||
$appointment->getEntityType(),
|
||||
$appointment->getEntityId(),
|
||||
DomainEvents::APPOINTMENT_RESCHEDULED,
|
||||
[
|
||||
'appointment_uuid' => $appointment->getUuid(),
|
||||
'previous_start' => $previousStart,
|
||||
'new_start' => $hold->getStartsAt(),
|
||||
],
|
||||
);
|
||||
|
||||
return $this->success([
|
||||
'appointment_uuid' => $appointment->getUuid(),
|
||||
@@ -305,8 +258,6 @@ class BookingController extends BaseController
|
||||
$address,
|
||||
$hold->getStartsAt(),
|
||||
is_array($data['policy'] ?? null) ? $data['policy'] : [],
|
||||
// پروندهٔ بیمار در همین محیط — پکیج کلینیک الف در کلینیک ب معنا ندارد.
|
||||
$this->packages->patientRecordFor($appointment),
|
||||
);
|
||||
|
||||
return $this->snapshots->record($appointment, $quote);
|
||||
|
||||
@@ -6,12 +6,7 @@ use App\Appointment\Availability\Entity\ResourceOccupancy;
|
||||
use App\Appointment\Booking\Entity\AppointmentHold;
|
||||
use App\Appointment\Booking\Entity\AppointmentSegment;
|
||||
use App\Appointment\Entity\Appointment;
|
||||
use App\Package\Service\CreditLedgerService;
|
||||
use App\Course\Service\CourseSessionLinker;
|
||||
use App\Package\Service\PackageConsumptionService;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Event\DomainEventPublisher;
|
||||
use App\Shared\Event\DomainEvents;
|
||||
use App\Shared\Exception\AppException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
@@ -26,10 +21,6 @@ final class BookingService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly HoldService $holds,
|
||||
private readonly PackageConsumptionService $packages,
|
||||
private readonly CreditLedgerService $credits,
|
||||
private readonly CourseSessionLinker $courseSessions,
|
||||
private readonly DomainEventPublisher $events,
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
|
||||
@@ -61,21 +52,9 @@ final class BookingService
|
||||
$this->writeSegments($hold, $appointment);
|
||||
$hold->markConfirmed($now);
|
||||
|
||||
// رویداد در همان flushِ ثبت نوبت میرود؛ اگر این تراکنش برگردد، رویدادی هم
|
||||
// نمیماند که کسی به آن واکنش نشان دهد.
|
||||
$this->events->record(
|
||||
$appointment->getEntityType(),
|
||||
$appointment->getEntityId(),
|
||||
DomainEvents::APPOINTMENT_BOOKED,
|
||||
['appointment_uuid' => $appointment->getUuid(), 'hold_uuid' => $hold->getUuid()],
|
||||
$now,
|
||||
);
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
// مصرف اعتبار **اینجا**ست نه در پیشنمایش قیمت: تنها لحظهای که نوبت واقعاً
|
||||
// وجود دارد. کلید یکتای دفتر هم تضمین میکند اجرای دوباره جلسهٔ دوم نخورد.
|
||||
$this->packages->consumeFor($appointment);
|
||||
|
||||
return $appointment;
|
||||
}
|
||||
@@ -119,18 +98,9 @@ final class BookingService
|
||||
|
||||
$this->holds->release($occupancies);
|
||||
|
||||
// ردیف `consume` **حذف نمیشود**؛ بازگشت یک ردیف تازه است تا تاریخچه بماند.
|
||||
$this->credits->refund($appointment);
|
||||
|
||||
// جلسهٔ دوره به `planned` برمیگردد؛ بقیهٔ جلسات دستنخورده میمانند.
|
||||
$this->courseSessions->unlink($appointment);
|
||||
|
||||
$this->events->recordAndFlush(
|
||||
$appointment->getEntityType(),
|
||||
$appointment->getEntityId(),
|
||||
DomainEvents::APPOINTMENT_CANCELLED,
|
||||
['appointment_uuid' => $appointment->getUuid(), 'released_resources' => count($occupancies)],
|
||||
);
|
||||
$this->em->flush();
|
||||
|
||||
return count($occupancies);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ use App\Appointment\Plan\ValueObject\AppointmentPlan;
|
||||
use App\Auth\Entity\User;
|
||||
use App\Resource\Entity\ClinicResource;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Event\DomainEventPublisher;
|
||||
use App\Shared\Event\DomainEvents;
|
||||
use App\Shared\Exception\AppException;
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -36,7 +34,6 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
final class HoldService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DomainEventPublisher $events,
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
|
||||
@@ -98,15 +95,6 @@ final class HoldService
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// بعد از اینکه **همهٔ** منابع گرفته شدند، نه پیش از آن: رزروی که وسط کار
|
||||
// شکسته، رویدادی هم ندارد.
|
||||
$this->events->recordAndFlush(
|
||||
$entityType,
|
||||
$entityId,
|
||||
DomainEvents::HOLD_CREATED,
|
||||
['hold_uuid' => $hold->getUuid(), 'starts_at' => $startsAt, 'resources' => count($taken)],
|
||||
$now,
|
||||
);
|
||||
|
||||
return $hold;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user