Visitor management app with SSO, kiosk, badges, reports, and Gitea CI deploy to frontdesk.ladill.com. Co-authored-by: Cursor <cursoragent@cursor.com>
65 lines
2.0 KiB
PHP
65 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Billing;
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
/**
|
|
* Client for the platform Billing HTTP API — the one UserWallet lives on the
|
|
* platform; CRM only consumes it. Amounts are integer minor units; the user is
|
|
* identified by public_id. Authenticates with the per-consumer config('billing.api_key').
|
|
*/
|
|
class BillingClient
|
|
{
|
|
private function base(): string
|
|
{
|
|
return rtrim((string) config('billing.api_url'), '/');
|
|
}
|
|
|
|
private function token(): string
|
|
{
|
|
return (string) (config('billing.api_key') ?? '');
|
|
}
|
|
|
|
public function balanceMinor(string $publicId): int
|
|
{
|
|
$res = Http::withToken($this->token())->acceptJson()->timeout(8)
|
|
->get($this->base().'/balance', ['user' => $publicId]);
|
|
$res->throw();
|
|
|
|
return (int) ($res->json('balance_minor') ?? 0);
|
|
}
|
|
|
|
public function canAfford(string $publicId, int $amountMinor): bool
|
|
{
|
|
$res = Http::withToken($this->token())->acceptJson()->timeout(8)
|
|
->get($this->base().'/can-afford', ['user' => $publicId, 'amount_minor' => $amountMinor]);
|
|
$res->throw();
|
|
|
|
return (bool) ($res->json('affordable') ?? false);
|
|
}
|
|
|
|
/**
|
|
* Debit the wallet. Returns true on success, false on insufficient balance
|
|
* (HTTP 402). Idempotent by $reference.
|
|
*/
|
|
public function debit(string $publicId, int $amountMinor, string $source, string $reference, ?string $description = null): bool
|
|
{
|
|
$res = Http::withToken($this->token())->acceptJson()->timeout(10)->post($this->base().'/debit', array_filter([
|
|
'user' => $publicId,
|
|
'amount_minor' => $amountMinor,
|
|
'service' => (string) config('billing.service', 'crm'),
|
|
'source' => $source,
|
|
'reference' => $reference,
|
|
'description' => $description,
|
|
], static fn ($v) => $v !== null));
|
|
|
|
if ($res->status() === 402) {
|
|
return false;
|
|
}
|
|
$res->throw();
|
|
|
|
return true;
|
|
}
|
|
}
|