Files
RSync-Studio/rsync-studio-licensing/app/Services/Payments/PurchaseProvisioner.php
T
2026-09-09 08:23:43 +01:00

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