feat: Enhance insurance billing system to support supplementary insurance
- Updated CoverageRule and related entities to include franchise_percent instead of franchise_rials. - Modified Appointment entity to carry supplementary insurance ID alongside base insurance. - Implemented SessionBillingService to ensure finalized invoices for insured patient sessions. - Created InvoiceFinalized event to trigger claims creation upon invoice finalization. - Added BackfillMissingClaimsCommand to generate claims for finalized invoices without existing claims. - Developed tests to validate the new functionality for supplementary insurance handling in appointments and claims.
This commit is contained in:
@@ -5,9 +5,7 @@ namespace App\Patient\Controller;
|
||||
use App\Auth\Entity\User;
|
||||
use App\Auth\Repository\UserRepository;
|
||||
use App\Billing\Repository\InvoiceRepository;
|
||||
use App\Billing\Service\ClaimService;
|
||||
use App\Billing\Service\InvoiceService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use App\Billing\Service\SessionBillingService;
|
||||
use App\Patient\Entity\PatientRecord;
|
||||
use App\Patient\Repository\PatientRecordRepository;
|
||||
use App\Patient\Repository\PatientSessionRepository;
|
||||
@@ -40,8 +38,7 @@ class PatientController extends BaseController
|
||||
private readonly PatientRecordScopeResolver $scopeResolver,
|
||||
private readonly \App\UserProfile\Repository\UserProfileRepository $profileRepo,
|
||||
private readonly \App\Insurance\Repository\InsuranceRepository $insuranceRepo,
|
||||
private readonly InvoiceService $invoiceService,
|
||||
private readonly ClaimService $claimService,
|
||||
private readonly SessionBillingService $sessionBilling,
|
||||
private readonly InvoiceRepository $invoiceRepo,
|
||||
private readonly \App\Appointment\Repository\AppointmentRepository $appointmentRepo,
|
||||
private readonly \App\Tag\Repository\TenantTagRepository $tenantTagRepo,
|
||||
@@ -60,7 +57,6 @@ class PatientController extends BaseController
|
||||
private readonly \App\Patient\Repository\SessionAuditLogRepository $sessionAuditRepo,
|
||||
private readonly SecretaryAccessChecker $secretaryAccess,
|
||||
private readonly \App\Clinic\Security\ClinicDoctorAccessChecker $clinicDoctorAccess,
|
||||
private readonly LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
// ── Financials (مالی: پرداخت / تراکنش / کیفپول) ────────────────────────────
|
||||
@@ -1058,34 +1054,11 @@ class PatientController extends BaseController
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
$session = $this->patientService->createSession($record, $data, $entityType, $entityId);
|
||||
|
||||
$this->autoCreateClaim($session, $entityType, $entityId);
|
||||
$this->sessionBilling->ensureFinalizedInvoice($session, $entityType, $entityId);
|
||||
|
||||
return $this->success($this->sessionWithBilling($session), 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* اتصال خودکار مطالبهی بیمه: اگر session بیمهی پایه یا مکمل داشته باشد،
|
||||
* صورتحساب ساخته و نهایی میشود و مطالبه (در وضعیت pending) ایجاد میگردد.
|
||||
* ارسال مطالبه دستی از صفحهی مطالبات انجام میشود.
|
||||
* خطا در این مرحله نباید ثبت session را خراب کند.
|
||||
*/
|
||||
private function autoCreateClaim(\App\Patient\Entity\PatientSession $session, string $entityType, int $entityId): void
|
||||
{
|
||||
if ($session->getInsuranceBaseId() === null && $session->getInsuranceSupplementaryId() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$invoice = $this->invoiceService->createFromSession($session, $entityType, $entityId);
|
||||
$this->invoiceService->finalize($invoice);
|
||||
$this->claimService->createFromInvoice($invoice);
|
||||
} catch (\App\Shared\Exception\AppException $e) {
|
||||
// سهم بیمهای صفر بود یا صورتحساب از قبل وجود داشت — قابل چشمپوشی.
|
||||
$this->logger->info('auto claim skipped', ['session' => $session->getUuid(), 'reason' => $e->getMessage()]);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error('auto claim failed', ['session' => $session->getUuid(), 'error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/api/v1/session/{uuid}', methods: ['PATCH'])]
|
||||
public function updateSession(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
|
||||
@@ -1112,6 +1085,10 @@ class PatientController extends BaseController
|
||||
|| array_key_exists('visit_price_rials', $data) || array_key_exists('insurance_base_id', $data)
|
||||
|| array_key_exists('base_insurance_discount_percent', $data)) {
|
||||
$this->patientService->updateSessionServices($session, $data, $entityType, $entityId, $user);
|
||||
|
||||
// بیمه ممکن است همین حالا به مراجعه اضافه شده باشد؛ بدون این، مراجعهای که
|
||||
// بیمهاش بعداً ثبت میشود هرگز صورتحساب و مطالبه نمیگیرد.
|
||||
$this->sessionBilling->ensureFinalizedInvoice($session, $entityType, $entityId);
|
||||
}
|
||||
|
||||
// تخفیف بر اساس قانون (discount_rule_uuid): مقدار از خود قانون، با ثبت منبع.
|
||||
|
||||
Reference in New Issue
Block a user