Initial Ladill Hosting app with Gitea deploy pipeline.
Deploy Ladill Hosting / deploy (push) Failing after 17s
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>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
<?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()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user