priceFor($service, $sources); $itemsTotal = 0; foreach ($items as $item) { $itemsTotal += $this->priceFor($item, $sources); } $subtotal = $base + $itemsTotal; [$discount, $discounts] = $this->discountFor($subtotal, $policy); // تخفیف بیشتر از مبلغ، مبلغ را **صفر** می‌کند نه منفی: بدهی منفی یعنی کلینیک // به بیمار پول بدهکار شود، که هیچ‌جای این جریان معنا ندارد. $discount = min($discount, $subtotal); $afterDiscount = $subtotal - $discount; // ── بیمه ────────────────────────────────────────────────────────────── $insuranceBase = $this->percentOf($afterDiscount, $policy['insurance_base_percent'] ?? 0.0); $insuranceBase = min($insuranceBase, $afterDiscount); $remaining = $afterDiscount - $insuranceBase; $supplementary = min($this->percentOf($remaining, $policy['insurance_supplementary_percent'] ?? 0.0), $remaining); $patientShare = $remaining - $supplementary; // ── مالیات ──────────────────────────────────────────────────────────── // روی سهم بیمار حساب می‌شود، نه روی کل: بیمار مالیاتِ سهمی که بیمه می‌دهد را // نمی‌پردازد. $tax = $this->percentOf($patientShare, $policy['tax_percent'] ?? 0.0); $final = $patientShare + $tax; // ── بیعانه ──────────────────────────────────────────────────────────── $deposit = isset($policy['deposit_rials']) ? (int) $policy['deposit_rials'] : $this->percentOf($final, $policy['deposit_percent'] ?? 0.0); $deposit = max(0, min($deposit, $final)); return new PriceQuote( baseRials: $base, itemsRials: $itemsTotal, discountRials: $discount, insuranceBaseRials: $insuranceBase, insuranceSupplementaryRials: $supplementary, taxRials: $tax, finalRials: $final, depositRials: $deposit, discounts: $discounts, sources: $sources, ); } /** * @param array $sources */ private function priceFor(ServiceItem $service, array &$sources): int { $sources[$service->getUuid()] = 'service_item'; return $service->getPriceRials(); } /** * @param array $policy * @return array{0: int, 1: list>} */ private function discountFor(int $subtotal, array $policy): array { $discounts = []; $total = 0; if (($policy['discount_percent'] ?? 0.0) > 0) { $amount = $this->percentOf($subtotal, (float) $policy['discount_percent']); $total += $amount; $discounts[] = [ 'label' => $policy['discount_label'] ?? 'تخفیف درصدی', 'percent' => $policy['discount_percent'], 'rials' => $amount, ]; } if (($policy['discount_rials'] ?? 0) > 0) { $amount = (int) $policy['discount_rials']; $total += $amount; $discounts[] = [ 'label' => $policy['discount_label'] ?? 'تخفیف مبلغی', 'rials' => $amount, ]; } // سقف جمع تخفیف‌ها per محیط: چند تخفیفِ جداگانه که هرکدام منطقی‌اند، با هم // می‌توانند مبلغ را بی‌معنا کنند. $cap = $policy['max_total_discount_percent'] ?? null; if ($cap !== null && $cap >= 0) { $maxAllowed = $this->percentOf($subtotal, (float) $cap); if ($total > $maxAllowed) { $discounts[] = [ 'label' => sprintf('سقف تخفیف %s٪ اعمال شد', $cap), 'rials' => $maxAllowed - $total, ]; $total = $maxAllowed; } } return [$total, $discounts]; } /** ریال واحد صحیح است؛ گرد کردن به پایین از اضافه‌گرفتن جلوگیری می‌کند. */ private function percentOf(int $amount, float $percent): int { if ($percent <= 0) { return 0; } return (int) floor($amount * $percent / 100); } }