|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; } }