Deploy Ladill Hosting / deploy (push) Failing after 17s
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>
100 lines
2.9 KiB
PHP
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()]);
|
|
}
|
|
}
|
|
}
|