Add Paystack, Flutterwave, and Hubtel for encounter billing.
Deploy Ladill Care / deploy (push) Successful in 1m0s
Deploy Ladill Care / deploy (push) Successful in 1m0s
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.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Confirming payment</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; background: #f8fafc; color: #0f172a; display: grid; place-items: center; min-height: 100vh; margin: 0; }
|
||||
p { font-size: 0.95rem; color: #475569; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Confirming payment…</p>
|
||||
<script>
|
||||
(function () {
|
||||
var url = @json($redirect);
|
||||
try {
|
||||
if (window.top && window.top !== window.self) {
|
||||
window.top.location.replace(url);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
window.location.replace(url);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -81,17 +81,52 @@
|
||||
<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 ($paymentMethods as $k => $v)<option value="{{ $k }}">{{ $v }}</option>@endforeach</select>
|
||||
<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)
|
||||
<p class="mt-2 text-sm">{{ $money($payment->amount_minor) }} · {{ $paymentMethods[$payment->method] ?? $payment->method }} · {{ $payment->paid_at->format('d M Y') }}</p>
|
||||
@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
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<x-app-layout title="Integrations">
|
||||
<x-settings.page title="Messaging integrations">
|
||||
<x-settings.page title="Integrations">
|
||||
<p class="text-sm text-slate-600">
|
||||
Configure <a href="https://sms.ladill.com" target="_blank" rel="noopener" class="text-teal-700 underline">SMS</a>
|
||||
Configure messaging and payment gateways for encounter billing.
|
||||
Use <a href="https://sms.ladill.com" target="_blank" rel="noopener" class="text-teal-700 underline">SMS</a>
|
||||
and <a href="https://bird.ladill.com" target="_blank" rel="noopener" class="text-teal-700 underline">email</a>
|
||||
credentials for outbound messaging.
|
||||
for outbound messages; connect Paystack, Flutterwave, or Hubtel so bill payments land in your account (0% Ladill fee).
|
||||
</p>
|
||||
|
||||
@if (! $canManage)
|
||||
@@ -124,6 +125,88 @@
|
||||
@endif
|
||||
@endif
|
||||
</x-settings.card>
|
||||
|
||||
<x-settings.card title="Payment gateway" description="Encounter bill payments via your own Paystack, Flutterwave, or Hubtel account — 0% Ladill platform fee. Pro & Enterprise only.">
|
||||
@if ($canUsePaymentGateway ?? false)
|
||||
@if ($gateway?->isConfigured())
|
||||
<div class="mb-4 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-800">
|
||||
Connected · {{ $gatewayLabels[$gateway->provider] ?? ucfirst($gateway->provider) }}
|
||||
@if (! $gateway->is_active)
|
||||
· <span class="font-medium text-amber-800">disabled</span>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class="mb-4 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800">
|
||||
Online checkout stays disabled until a gateway is connected.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($canManage)
|
||||
<form method="POST" action="{{ route('care.integrations.gateway.save') }}" class="space-y-4">
|
||||
@csrf
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700">Provider</label>
|
||||
<select name="gateway_provider" required class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
||||
<option value="">Select a provider</option>
|
||||
@foreach ($gatewayLabels as $value => $label)
|
||||
<option value="{{ $value }}" @selected(old('gateway_provider', $gateway?->provider) === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700">Public key / Merchant account</label>
|
||||
<input type="text" name="gateway_public_key" value="{{ old('gateway_public_key') }}"
|
||||
placeholder="{{ $gateway?->public_key ? '•••• saved — leave blank to keep' : 'pk_live_… or Hubtel account #' }}"
|
||||
class="mt-1 w-full rounded-lg border-slate-300 font-mono text-sm" autocomplete="off">
|
||||
<p class="mt-1 text-xs text-slate-500">Hubtel: merchant account number. Paystack/Flutterwave: public key.</p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700">Secret / API key</label>
|
||||
<input type="password" name="gateway_secret_key" value=""
|
||||
placeholder="{{ $gateway?->secret_key ? '•••• saved — leave blank to keep' : 'sk_live_…' }}"
|
||||
class="mt-1 w-full rounded-lg border-slate-300 font-mono text-sm" autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700">Webhook secret / Hubtel client auth (optional)</label>
|
||||
<input type="password" name="gateway_webhook_secret" value=""
|
||||
placeholder="{{ $gateway?->webhook_secret ? '•••• saved — leave blank to keep' : 'Optional · Hubtel: clientId:clientSecret' }}"
|
||||
class="mt-1 w-full rounded-lg border-slate-300 font-mono text-sm" autocomplete="new-password">
|
||||
</div>
|
||||
<label class="inline-flex items-center gap-2 text-sm text-slate-700">
|
||||
<input type="hidden" name="gateway_is_active" value="0">
|
||||
<input type="checkbox" name="gateway_is_active" value="1" @checked(old('gateway_is_active', $gateway?->is_active ?? true)) class="rounded border-slate-300 text-teal-600 focus:ring-teal-500">
|
||||
Gateway enabled for encounter billing
|
||||
</label>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button type="submit" class="btn-primary">Save gateway</button>
|
||||
</div>
|
||||
</form>
|
||||
@if ($gateway)
|
||||
<div class="mt-3">
|
||||
<x-confirm-dialog
|
||||
name="disconnect-gateway"
|
||||
title="Disconnect payment gateway?"
|
||||
message="Online checkout for bills will stop until credentials are connected again."
|
||||
:action="route('care.integrations.gateway.disconnect')"
|
||||
confirm-label="Disconnect"
|
||||
>
|
||||
<x-slot:trigger>
|
||||
<button type="button" class="text-sm text-rose-700 hover:underline">Disconnect</button>
|
||||
</x-slot:trigger>
|
||||
</x-confirm-dialog>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
@else
|
||||
<div class="rounded-lg border border-teal-100 bg-teal-50 px-4 py-3 text-sm text-teal-900">
|
||||
<p class="font-medium">Your own payment gateway is a Pro feature</p>
|
||||
<p class="mt-1 text-teal-800/80">Upgrade to Care Pro or Enterprise to connect Paystack, Flutterwave, or Hubtel for encounter bill payments with 0% Ladill fee.</p>
|
||||
<a href="{{ route('care.pro.index') }}" class="mt-3 inline-flex text-sm font-semibold text-teal-700 hover:text-teal-900">View plans →</a>
|
||||
</div>
|
||||
@endif
|
||||
</x-settings.card>
|
||||
</div>
|
||||
|
||||
<p class="mt-6 text-sm text-slate-500">
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
<li>Full clinical workflows</li>
|
||||
<li>Laboratory & pharmacy</li>
|
||||
<li>Encounter billing</li>
|
||||
<li>Your own Paystack / Flutterwave / Hubtel</li>
|
||||
<li>Ladill Queue integration</li>
|
||||
<li>Unlimited branches (billed per branch)</li>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user