Lean control center at mini.ladill.com: payment QR CRUD, Paystack checkout with 5% fee settlement via Billing API, payments feed, and payouts. QR codes use a fixed black-and-white preset only. Co-authored-by: Cursor <cursoragent@cursor.com>
75 lines
2.3 KiB
PHP
75 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Qr;
|
|
|
|
use App\Models\QrCode;
|
|
use App\Models\QrTransaction;
|
|
use App\Models\QrWallet;
|
|
use App\Models\User;
|
|
use App\Services\Billing\BillingClient;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* QR Plus billing — consumes the platform UserWallet via the Billing API.
|
|
*/
|
|
class QrWalletBillingService
|
|
{
|
|
public function __construct(
|
|
private BillingClient $billing,
|
|
) {}
|
|
|
|
public function balanceCedis(User $user): float
|
|
{
|
|
return $this->billing->balanceMinor($user->public_id) / 100;
|
|
}
|
|
|
|
public function canCreate(User $user): bool
|
|
{
|
|
$priceMinor = (int) round(QrWallet::pricePerQr() * 100);
|
|
|
|
return $this->billing->canAfford($user->public_id, $priceMinor);
|
|
}
|
|
|
|
public function debitForQrCreation(QrWallet $wallet, QrCode $qrCode): QrTransaction
|
|
{
|
|
$price = QrWallet::pricePerQr();
|
|
$priceMinor = (int) round($price * 100);
|
|
$user = $wallet->user;
|
|
$reference = 'QR-DEBIT-'.strtoupper(Str::random(12));
|
|
|
|
return DB::transaction(function () use ($wallet, $user, $qrCode, $price, $priceMinor, $reference) {
|
|
$ok = $this->billing->debit(
|
|
$user->public_id,
|
|
$priceMinor,
|
|
'qr',
|
|
'qr_create',
|
|
$reference,
|
|
$qrCode->id,
|
|
sprintf('Created QR code: %s', $qrCode->label),
|
|
);
|
|
|
|
if (! $ok) {
|
|
throw new RuntimeException('Insufficient wallet balance.');
|
|
}
|
|
|
|
$wallet->increment('qr_codes_total');
|
|
$balanceAfter = $this->billing->balanceMinor($user->public_id) / 100;
|
|
|
|
return QrTransaction::create([
|
|
'user_id' => $wallet->user_id,
|
|
'qr_wallet_id' => $wallet->id,
|
|
'qr_code_id' => $qrCode->id,
|
|
'type' => QrTransaction::TYPE_DEBIT,
|
|
'amount_ghs' => round($price, 4),
|
|
'balance_after_ghs' => $balanceAfter,
|
|
'reference' => $reference,
|
|
'status' => 'completed',
|
|
'description' => sprintf('Created QR code: %s', $qrCode->label),
|
|
'metadata' => ['qr_code_id' => $qrCode->id],
|
|
]);
|
|
});
|
|
}
|
|
}
|