Files
ladill-woo-manager/app/Services/Woo/BillingClient.php
T
isaaccladandCursor cebf0d2e61
Deploy Ladill Woo Manager / deploy (push) Successful in 51s
Add Woo Manager Pro with multi-store switching and free-tier limits.
Free: 1 store and 20 products. Pro/Business mirrors Invoice pricing (GHS 49/149)
with wallet renewals, Paystack prepay, session-based store switcher, and scoped UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 01:14:08 +00:00

101 lines
3.6 KiB
PHP

<?php
namespace App\Services\Woo;
use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class BillingClient
{
public function configured(): bool
{
return (string) config('billing.api_url', '') !== '' && (string) config('billing.api_key', '') !== '';
}
/**
* @return array{ok: bool, insufficient: bool, balance_minor: ?int, error: ?string}
*/
public function charge(User $user, int $amountMinor, string $reference, string $description): array
{
if (! $this->configured()) {
return ['ok' => false, 'insufficient' => false, 'balance_minor' => null, 'error' => 'Billing is not configured.'];
}
try {
$res = Http::withToken((string) config('billing.api_key'))
->acceptJson()->timeout(20)
->post(rtrim((string) config('billing.api_url'), '/').'/debit', [
'user' => $user->public_id,
'amount_minor' => $amountMinor,
'service' => (string) config('billing.service', 'woo'),
'source' => 'subscription',
'reference' => $reference,
'description' => $description,
]);
} catch (\Throwable $e) {
Log::warning('Woo BillingClient: charge failed', ['user' => $user->public_id, 'error' => $e->getMessage()]);
return ['ok' => false, 'insufficient' => false, 'balance_minor' => null, 'error' => 'Could not reach the billing service.'];
}
if ($res->status() === 402) {
return ['ok' => false, 'insufficient' => true, 'balance_minor' => (int) $res->json('balance_minor', 0), 'error' => 'Insufficient wallet balance.'];
}
if ($res->failed()) {
return ['ok' => false, 'insufficient' => false, 'balance_minor' => null, 'error' => 'Billing error ('.$res->status().').'];
}
return ['ok' => true, 'insufficient' => false, 'balance_minor' => null, 'error' => null];
}
/**
* @param array<string, mixed> $metadata
* @return array{checkout_url: string, reference: string}
*/
public function initiatePlanCheckout(
User $user,
string $plan,
int $months,
int $amountMinor,
string $returnUrl,
array $metadata = [],
): array {
$res = Http::withToken((string) config('billing.api_key'))
->acceptJson()->timeout(15)
->post(rtrim((string) config('billing.api_url'), '/').'/plan-checkout', [
'user' => $user->public_id,
'app' => (string) config('billing.service', 'woo'),
'plan' => $plan,
'months' => $months,
'amount_minor' => $amountMinor,
'return_url' => $returnUrl,
'metadata' => $metadata,
]);
$res->throw();
return [
'checkout_url' => (string) $res->json('checkout_url'),
'reference' => (string) $res->json('reference'),
];
}
/** @return array<string, mixed> */
public function verifyPlanCheckout(string $reference): array
{
$res = Http::withToken((string) config('billing.api_key'))
->acceptJson()->timeout(15)
->post(rtrim((string) config('billing.api_url'), '/').'/plan-checkout/verify', [
'reference' => $reference,
]);
if ($res->status() === 422) {
return ['paid' => false, 'error' => $res->json('error')];
}
$res->throw();
return $res->json();
}
}