Deploy Ladill Meet / deploy (push) Failing after 7s
Phases 0–18: core meetings, webinar, breakouts, team chat, live streaming, town hall, billing, and Ladill Mail calendar wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
77 lines
1.9 KiB
PHP
77 lines
1.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Billing;
|
|
|
|
use App\Models\CrmPurchase;
|
|
use Illuminate\Support\Str;
|
|
|
|
class OneTimePurchaseService
|
|
{
|
|
public function __construct(private readonly BillingClient $billing)
|
|
{
|
|
}
|
|
|
|
/** @return array<string, mixed>|null */
|
|
public function product(string $productKey): ?array
|
|
{
|
|
$product = config('crm_products.'.$productKey);
|
|
|
|
return is_array($product) ? $product : null;
|
|
}
|
|
|
|
public function hasPurchased(string $ownerRef, string $productKey): bool
|
|
{
|
|
return CrmPurchase::has($ownerRef, $productKey);
|
|
}
|
|
|
|
public function priceMinor(string $productKey): int
|
|
{
|
|
return (int) ($this->product($productKey)['price_minor'] ?? 0);
|
|
}
|
|
|
|
public function purchase(string $ownerRef, string $productKey): bool
|
|
{
|
|
if ($this->hasPurchased($ownerRef, $productKey)) {
|
|
return true;
|
|
}
|
|
|
|
$product = $this->product($productKey);
|
|
if (! $product) {
|
|
return false;
|
|
}
|
|
|
|
$costMinor = (int) ($product['price_minor'] ?? 0);
|
|
|
|
if ($costMinor > 0) {
|
|
try {
|
|
if (! $this->billing->canAfford($ownerRef, $costMinor)) {
|
|
return false;
|
|
}
|
|
|
|
$charged = $this->billing->debit(
|
|
$ownerRef,
|
|
$costMinor,
|
|
'purchase',
|
|
'crm-purchase-'.$productKey.'-'.$ownerRef,
|
|
'CRM: '.($product['name'] ?? $productKey),
|
|
);
|
|
|
|
if (! $charged) {
|
|
return false;
|
|
}
|
|
} catch (\Throwable) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
CrmPurchase::create([
|
|
'owner_ref' => $ownerRef,
|
|
'product_key' => $productKey,
|
|
'cost_minor' => $costMinor,
|
|
'purchased_at' => now(),
|
|
]);
|
|
|
|
return true;
|
|
}
|
|
}
|