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:
hamed
2026-07-29 19:57:02 +03:30
parent 9b05c6d1ff
commit e6267080b2
25 changed files with 876 additions and 126 deletions
+47
View File
@@ -72,6 +72,53 @@ class ClaimService
return $claims;
}
/**
* مطالبات جاافتاده‌ی یک صورتحساب نهایی‌شده را می‌سازد و مطالبات موجود را دست نمی‌زند.
* برخلاف createFromInvoice که یک عملِ کاربر است و با خطا جواب می‌دهد، این متد
* روی رویدادِ نهایی‌شدن صدا زده می‌شود و «کاری برای انجام نبود» حالت عادی‌اش است.
*
* @return Claim[] مطالبات تازه‌ساخته‌شده
*/
public function syncFromInvoice(Invoice $invoice): array
{
if ($invoice->getStatus() !== Invoice::STATUS_FINALIZED || $invoice->getId() === null) {
return [];
}
$existingKinds = $this->claimRepo->kindsForInvoice($invoice->getId());
$claims = [];
foreach ([
Claim::KIND_BASE => $invoice->getBaseInsuranceId(),
Claim::KIND_SUPPLEMENTARY => $invoice->getSupplementaryInsuranceId(),
] as $kind => $insuranceId) {
if ($insuranceId === null || in_array($kind, $existingKinds, true)) {
continue;
}
$claim = $this->buildClaim($invoice, $insuranceId, $kind);
if ($claim !== null) {
$claims[] = $claim;
}
}
if ($claims === []) {
return [];
}
foreach ($claims as $claim) {
$this->claimRepo->save($claim, false);
}
$this->claimRepo->getEntityManager()->flush();
foreach ($claims as $claim) {
$this->logTransition($claim, null, $claim->getStatus(), 'ایجاد مطالبه', null);
}
$this->claimRepo->getEntityManager()->flush();
return $claims;
}
private function buildClaim(Invoice $invoice, int $insuranceId, string $kind): ?Claim
{
$claim = new Claim($invoice->getEntityType(), $invoice->getEntityId(), $insuranceId, $kind);