Deploy Ladill QR Plus / deploy (push) Successful in 2m2s
Create was making three sequential public HTTPS billing calls (~400ms each) while holding a DB transaction open for image generation. Use loopback DNS forcing, cache balances briefly, return balance from debit, regenerate images only when style changes, and keep remote work outside the DB transaction.
75 lines
2.1 KiB
PHP
75 lines
2.1 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\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));
|
|
|
|
$result = $this->billing->debit(
|
|
$user->public_id,
|
|
$priceMinor,
|
|
'qr',
|
|
'qr_create',
|
|
$reference,
|
|
$qrCode->id,
|
|
sprintf('Created QR code: %s', $qrCode->label),
|
|
);
|
|
|
|
if ($result === null) {
|
|
throw new RuntimeException('Insufficient wallet balance.');
|
|
}
|
|
|
|
$wallet->increment('qr_codes_total');
|
|
|
|
$balanceAfter = isset($result['balance_after_minor'])
|
|
? ((int) $result['balance_after_minor']) / 100
|
|
: $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],
|
|
]);
|
|
}
|
|
}
|