Files
ladill-hosting/app/Services/Payment/WalletPaymentService.php
T
isaaccladandCursor e251a4cf60
Deploy Ladill Hosting / deploy (push) Failing after 17s
Initial Ladill Hosting app with Gitea deploy pipeline.
Shared web hosting extracted from the platform monolith, with CI deploy
to /var/www/ladill-hosting matching Bird/Domains/Email.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 16:24:20 +00:00

100 lines
2.9 KiB
PHP

<?php
namespace App\Services\Payment;
use App\Models\User;
use App\Services\Billing\BillingClient;
use Illuminate\Support\Facades\Log;
/**
* Wallet payments for the Email product against the one platform UserWallet
* (Billing API, tagged 'email'). Mailboxes are wallet-funded; card top-ups
* happen on the account portal. Debits are idempotent by reference.
*/
class WalletPaymentService
{
public function __construct(private BillingClient $billing) {}
private function service(): string
{
return (string) config('billing.service', 'email');
}
public function isConfigured(): bool
{
return (string) config('billing.api_key') !== '';
}
public function balanceMinor(User $user): int
{
try {
return $this->billing->balanceMinor($user->public_id);
} catch (\Throwable $e) {
Log::warning('WalletPaymentService: balance failed', ['error' => $e->getMessage()]);
return 0;
}
}
public function canAfford(User $user, int $amountMinor): bool
{
if ($amountMinor <= 0) {
return true;
}
if (! $this->isConfigured()) {
return false;
}
try {
return $this->billing->canAfford($user->public_id, $amountMinor);
} catch (\Throwable $e) {
Log::warning('WalletPaymentService: canAfford failed', ['error' => $e->getMessage()]);
return false;
}
}
/**
* Debit the wallet. Returns true on success, false on insufficient balance.
* Idempotent by $reference.
*/
public function charge(User $user, int $amountMinor, string $reference, string $source, string $description): bool
{
if ($amountMinor <= 0) {
return true;
}
if (! $this->isConfigured()) {
return false;
}
try {
return $this->billing->debit(
publicId: $user->public_id,
amountMinor: $amountMinor,
service: $this->service(),
source: $source,
reference: $reference,
description: $description,
);
} catch (\Throwable $e) {
Log::error('WalletPaymentService: charge failed', ['reference' => $reference, 'error' => $e->getMessage()]);
return false;
}
}
/** Refund (e.g. if provisioning fails after charge). Idempotent. */
public function refund(User $user, int $amountMinor, string $reference, string $description): void
{
if ($amountMinor <= 0 || ! $this->isConfigured()) {
return;
}
try {
$this->billing->credit($user->public_id, $amountMinor, $this->service(), 'mailbox_refund', $reference.':refund', null, $description);
} catch (\Throwable $e) {
Log::error('WalletPaymentService: refund failed', ['reference' => $reference, 'error' => $e->getMessage()]);
}
}
}