Multi-tenant insurance contracts, service coverage, versioned tariffs, invoice calculation, and insurance claims with debt reporting. - TenantInsurance: per-tenant insurance contracts (coverage/franchise/ceiling, versioning, soft-deactivate) + active guard - ServiceItem.insuranceCovered + TenantServiceCoverage per-service overrides - Tariff: versioned yearly tariffs with fallback to ServiceItem price - Billing domain: Money/ShareBreakdown VOs, BillingCalculator (unit-tested), Invoice/InvoiceItem aggregate, InvoiceService.createFromSession - Claim/ClaimItem with state machine (pending->submitted->approved/rejected->paid), ClaimService, insurance-debt report - ClaimSubmitterInterface + ManualClaimSubmitter (future insurance API ready) - Admin UI: insurance-pricing page, claims page, service tariff modal, service insurance toggle; routes + sidebar entries - Architecture doc + billing/insurance/clinic-services API docs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
55 lines
1.6 KiB
PHP
55 lines
1.6 KiB
PHP
<?php
|
|
|
|
namespace App\ClinicService\Service;
|
|
|
|
use App\ClinicService\Entity\ServiceItem;
|
|
use App\ClinicService\Entity\Tariff;
|
|
use App\ClinicService\Repository\TariffRepository;
|
|
|
|
class TariffService
|
|
{
|
|
public function __construct(
|
|
private readonly TariffRepository $tariffRepo,
|
|
) {}
|
|
|
|
/**
|
|
* تعرفهی یک خدمت برای یک سال شمسی.
|
|
* اگر تعرفهی آن سال ثبت نشده باشد، به priceRials خود خدمت fallback میشود.
|
|
*/
|
|
public function resolvePrice(ServiceItem $service, ?int $year = null): int
|
|
{
|
|
$year ??= $this->currentJalaliYear();
|
|
|
|
$tariff = $service->getId() !== null
|
|
? $this->tariffRepo->findForServiceYear($service->getId(), $year)
|
|
: null;
|
|
|
|
return $tariff?->getPriceRials() ?? $service->getPriceRials();
|
|
}
|
|
|
|
public function upsert(int $serviceItemId, int $year, int $priceRials): Tariff
|
|
{
|
|
$tariff = $this->tariffRepo->findForServiceYear($serviceItemId, $year);
|
|
if ($tariff === null) {
|
|
$tariff = new Tariff($serviceItemId, $year, $priceRials);
|
|
} else {
|
|
$tariff->setPriceRials($priceRials)->setActive(true);
|
|
}
|
|
$this->tariffRepo->save($tariff);
|
|
return $tariff;
|
|
}
|
|
|
|
public function currentJalaliYear(): int
|
|
{
|
|
$fmt = new \IntlDateFormatter(
|
|
'en_US@calendar=persian',
|
|
\IntlDateFormatter::FULL,
|
|
\IntlDateFormatter::NONE,
|
|
'Asia/Tehran',
|
|
\IntlDateFormatter::TRADITIONAL,
|
|
'yyyy'
|
|
);
|
|
return (int) $fmt->format(time());
|
|
}
|
|
}
|