Files
ladill-care/resources/views/care/bills/show.blade.php
T
isaacclad 7a0a7fcb88
Deploy Ladill Care / deploy (push) Successful in 1m0s
Add Paystack, Flutterwave, and Hubtel for encounter billing.
Clinics on Pro/Enterprise can connect their own gateway in Integrations and collect card or MoMo on bills with 0% Ladill fee, while cash payments and balance totals stay correct for pending checkouts.
2026-07-16 10:24:28 +00:00

137 lines
9.5 KiB
PHP

@php $money = fn ($minor) => config('care.billing.currency').' '.number_format($minor / 100, 2); @endphp
<x-app-layout :title="$bill->invoice_number">
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div>
<p class="text-xs uppercase text-slate-500">{{ $statuses[$bill->status] ?? $bill->status }}</p>
<h1 class="text-2xl font-semibold text-slate-900">{{ $bill->invoice_number }}</h1>
<p class="mt-1 text-sm text-slate-500">{{ $bill->patient->fullName() }} · {{ $bill->branch?->name }}</p>
</div>
<div class="flex gap-2">
<a href="{{ route('care.bills.print', $bill) }}" target="_blank" class="rounded-lg border border-slate-200 px-4 py-2 text-sm">Print</a>
@if ($canManage && ! in_array($bill->status, [\App\Models\Bill::STATUS_PAID, \App\Models\Bill::STATUS_VOID]))
<x-confirm-dialog
:name="'void-bill-'.$bill->id"
title="Void this bill?"
message="The invoice will be voided and can no longer be paid."
:action="route('care.bills.void', $bill)"
confirm-label="Void bill"
>
<x-slot:trigger>
<x-btn type="button" variant="danger">Void</x-btn>
</x-slot:trigger>
</x-confirm-dialog>
@endif
</div>
</div>
<div class="mt-6 grid gap-6 lg:grid-cols-3">
<section class="rounded-2xl border border-slate-200 bg-white p-6 lg:col-span-2">
<h2 class="text-sm font-semibold uppercase text-slate-500">Line items</h2>
<table class="mt-4 min-w-full text-sm">
<thead class="text-left text-xs uppercase text-slate-500"><tr><th class="py-2">Description</th><th>Qty</th><th>Unit</th><th>Total</th></tr></thead>
<tbody class="divide-y divide-slate-50">
@foreach ($bill->lineItems as $item)
<tr>
<td class="py-2">{{ $item->description }} <span class="text-slate-400">({{ $lineTypes[$item->type] ?? $item->type }})</span></td>
<td>{{ $item->quantity }}</td>
<td>{{ $money($item->unit_price_minor) }}</td>
<td>{{ $money($item->total_minor) }}</td>
</tr>
@endforeach
</tbody>
</table>
<dl class="mt-4 space-y-1 border-t border-slate-100 pt-4 text-sm">
<div class="flex justify-between"><dt class="text-slate-500">Subtotal</dt><dd>{{ $money($bill->subtotal_minor) }}</dd></div>
@if ($bill->discount_minor)<div class="flex justify-between"><dt class="text-slate-500">Discount</dt><dd>-{{ $money($bill->discount_minor) }}</dd></div>@endif
@if ($bill->tax_minor)<div class="flex justify-between"><dt class="text-slate-500">Tax</dt><dd>{{ $money($bill->tax_minor) }}</dd></div>@endif
<div class="flex justify-between font-semibold"><dt>Total</dt><dd>{{ $money($bill->total_minor) }}</dd></div>
<div class="flex justify-between text-amber-700"><dt>Balance</dt><dd>{{ $money($bill->balance_minor) }}</dd></div>
</dl>
</section>
<div class="space-y-6">
@if ($canManage && ! in_array($bill->status, [\App\Models\Bill::STATUS_PAID, \App\Models\Bill::STATUS_VOID]))
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase text-slate-500">Add line item</h2>
<form method="POST" action="{{ route('care.bills.line-items.store', $bill) }}" class="mt-4 space-y-3">
@csrf
<select name="type" class="w-full rounded-lg border-slate-300 text-sm">@foreach ($lineTypes as $k => $v)<option value="{{ $k }}">{{ $v }}</option>@endforeach</select>
<input type="text" name="description" required placeholder="Description" class="w-full rounded-lg border-slate-300 text-sm">
<div class="grid grid-cols-2 gap-2">
<input type="number" name="quantity" value="1" min="1" class="rounded-lg border-slate-300 text-sm">
<input type="number" name="unit_price_minor" placeholder="Price (minor)" min="0" class="rounded-lg border-slate-300 text-sm">
</div>
<button type="submit" class="btn-primary w-full">Add</button>
</form>
</section>
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase text-slate-500">Discount & tax</h2>
<form method="POST" action="{{ route('care.bills.adjustments', $bill) }}" class="mt-4 space-y-3">
@csrf
<input type="number" name="discount_minor" value="{{ $bill->discount_minor }}" min="0" placeholder="Discount (minor)" class="w-full rounded-lg border-slate-300 text-sm">
<input type="number" name="tax_minor" value="{{ $bill->tax_minor }}" min="0" placeholder="Tax (minor)" class="w-full rounded-lg border-slate-300 text-sm">
<button type="submit" class="btn-primary w-full">Update</button>
</form>
</section>
@endif
@if ($canPay && $bill->balance_minor > 0 && $bill->status !== \App\Models\Bill::STATUS_VOID)
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase text-slate-500">Record payment</h2>
<form method="POST" action="{{ route('care.bills.payments.store', $bill) }}" class="mt-4 space-y-3">
@csrf
<input type="number" name="amount_minor" value="{{ $bill->balance_minor }}" min="1" required class="w-full rounded-lg border-slate-300 text-sm">
<select name="method" class="w-full rounded-lg border-slate-300 text-sm">@foreach ($manualPaymentMethods as $k => $v)<option value="{{ $k }}">{{ $v }}</option>@endforeach</select>
<input type="text" name="reference" placeholder="Reference" class="w-full rounded-lg border-slate-300 text-sm">
<button type="submit" class="btn-primary w-full">Record payment</button>
</form>
</section>
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase text-slate-500">Collect online</h2>
<p class="mt-1 text-xs text-slate-500">
Card or mobile money via your connected gateway
@if ($gatewayConfigured && $gatewayProvider)
({{ $gatewayLabels[$gatewayProvider] ?? ucfirst($gatewayProvider) }})
@endif
0% Ladill fee.
</p>
@if ($gatewayConfigured)
<form method="POST" action="{{ route('care.bills.payments.gateway', $bill) }}" class="mt-4 space-y-3">
@csrf
<input type="number" name="amount_minor" value="{{ $bill->balance_minor }}" min="1" max="{{ $bill->balance_minor }}" required class="w-full rounded-lg border-slate-300 text-sm" aria-label="Amount (minor units)">
<button type="submit" class="btn-primary w-full">Open checkout</button>
</form>
@else
<p class="mt-3 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800">
Connect Paystack, Flutterwave, or Hubtel in
<a href="{{ route('care.integrations') }}" class="font-medium underline">Integrations</a>
to collect online payments.
</p>
@endif
</section>
@endif
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase text-slate-500">Payments</h2>
@forelse ($bill->payments as $payment)
@php
$methodLabel = $payment->method === \App\Models\Payment::METHOD_GATEWAY
? ($gatewayLabels[$payment->gateway_provider] ?? 'Online')
: ($paymentMethods[$payment->method] ?? $payment->method);
$statusSuffix = $payment->status === \App\Models\Payment::STATUS_PAID
? ''
: ' · '.ucfirst($payment->status);
$when = $payment->isPaid()
? ($payment->paid_at?->format('d M Y') ?? $payment->created_at->format('d M Y'))
: $payment->created_at->format('d M Y');
@endphp
<p class="mt-2 text-sm">{{ $money($payment->amount_minor) }} · {{ $methodLabel }}{{ $statusSuffix }} · {{ $when }}@if($payment->reference)<span class="text-slate-400"> · {{ $payment->reference }}</span>@endif</p>
@empty
<p class="mt-2 text-sm text-slate-400">No payments recorded.</p>
@endforelse
</section>
</div>
</div>
</x-app-layout>