48 lines
3.1 KiB
PHP
48 lines
3.1 KiB
PHP
<?php
|
|
namespace App\Services\Payments;
|
|
|
|
use App\Models\License;
|
|
use App\Models\LicenseProduct;
|
|
use App\Services\Licensing\LicenseIssuer;
|
|
use RuntimeException;
|
|
|
|
final class PurchaseProvisioner
|
|
{
|
|
public function __construct(private LicenseIssuer $issuer) {}
|
|
|
|
public function provision(string $provider, array $event): void
|
|
{
|
|
$normalized = match ($provider) {
|
|
'paddle' => $this->fromPaddle($event),
|
|
'lemon-squeezy' => $this->fromLemonSqueezy($event),
|
|
default => throw new RuntimeException('Unsupported payment provider.'),
|
|
};
|
|
if ($normalized['action'] === 'ignore') return;
|
|
if ($normalized['action'] === 'revoke') {
|
|
License::where('payment_provider',$provider)->where('external_order_id',$normalized['orderID'])->whereNull('revoked_at')->update(['revoked_at'=>now(),'revoke_reason'=>'Payment refunded or reversed']);
|
|
return;
|
|
}
|
|
$product = LicenseProduct::where('payment_provider',$provider)->where(function($q) use($normalized){ $q->where('external_price_id',$normalized['priceID'])->orWhere('external_product_id',$normalized['productID']); })->where('active',true)->first();
|
|
if (!$product) throw new RuntimeException('No active licence product maps to this payment item.');
|
|
$this->issuer->issue($product,$normalized['name'],$normalized['email'],$provider,$normalized['orderID'],$normalized['customerID'], true);
|
|
}
|
|
|
|
private function fromPaddle(array $e): array
|
|
{
|
|
$type=(string)($e['event_type']??''); $d=$e['data']??[];
|
|
if (in_array($type,['transaction.refunded','transaction.canceled'],true)) return ['action'=>'revoke','orderID'=>(string)($d['id']??''),'priceID'=>'','productID'=>'','name'=>null,'email'=>null,'customerID'=>null];
|
|
if ($type!=='transaction.completed') return ['action'=>'ignore'];
|
|
$item=$d['items'][0]??[]; $price=$item['price']??[]; $product=$price['product_id']??($item['product_id']??null);
|
|
return ['action'=>'issue','orderID'=>(string)($d['id']??''),'priceID'=>(string)($price['id']??($item['price_id']??'')),'productID'=>(string)($product??''),'name'=>$d['custom_data']['customer_name']??null,'email'=>$d['custom_data']['customer_email']??null,'customerID'=>isset($d['customer_id'])?(string)$d['customer_id']:null];
|
|
}
|
|
|
|
private function fromLemonSqueezy(array $e): array
|
|
{
|
|
$type=(string)($e['meta']['event_name']??''); $a=$e['data']['attributes']??[];
|
|
$order=(string)($e['data']['id']??($a['order_id']??''));
|
|
if (in_array($type,['order_refunded','subscription_expired'],true)) return ['action'=>'revoke','orderID'=>$order,'priceID'=>'','productID'=>'','name'=>null,'email'=>null,'customerID'=>null];
|
|
if (!in_array($type,['order_created','subscription_created'],true)) return ['action'=>'ignore'];
|
|
return ['action'=>'issue','orderID'=>$order,'priceID'=>(string)($a['variant_id']??''),'productID'=>(string)($a['product_id']??''),'name'=>$a['user_name']??null,'email'=>$a['user_email']??null,'customerID'=>isset($a['customer_id'])?(string)$a['customer_id']:null];
|
|
}
|
|
}
|