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()]); } } }