71 lines
2.3 KiB
PHP
71 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace App\Actions;
|
|
|
|
use App\Models\Operator;
|
|
use App\Models\Order;
|
|
use App\Models\Subscription;
|
|
use App\Models\SubscriptionAddon;
|
|
use App\Services\Billing\AddonCatalogue;
|
|
use Illuminate\Support\Carbon;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* Gives a customer a module without a payment — "ein Plugin schenken".
|
|
*
|
|
* Books through the same BookAddon a paid order uses, on a synthetic Order
|
|
* (no Stripe id, price set to what the customer actually pays) so the module
|
|
* ends up frozen on `subscription_addons` exactly like a real booking would.
|
|
*/
|
|
class GrantAddon
|
|
{
|
|
public function __construct(private BookAddon $bookAddon) {}
|
|
|
|
public function __invoke(
|
|
Subscription $subscription,
|
|
Operator $grantedBy,
|
|
string $addonKey,
|
|
int $priceCents,
|
|
int $quantity = 1,
|
|
?string $note = null,
|
|
?Carbon $until = null,
|
|
): SubscriptionAddon {
|
|
$cataloguePrice = app(AddonCatalogue::class)->priceCents($addonKey);
|
|
|
|
if ($cataloguePrice === null) {
|
|
throw new RuntimeException("Unknown add-on: {$addonKey}");
|
|
}
|
|
|
|
if ($priceCents < 0 || $priceCents > $cataloguePrice) {
|
|
throw new RuntimeException('A grant cannot charge more than the catalogue price.');
|
|
}
|
|
|
|
// Vestigial for a module — nothing is provisioned at a datacenter for
|
|
// it — but the column is not nullable, and the contract's own order
|
|
// already carries the right one.
|
|
$datacenter = $subscription->order?->datacenter ?? 'fsn';
|
|
|
|
$order = Order::create([
|
|
'customer_id' => $subscription->customer_id,
|
|
'plan' => $subscription->plan,
|
|
'type' => 'addon',
|
|
'addon_key' => $addonKey,
|
|
'amount_cents' => $priceCents,
|
|
'currency' => Subscription::catalogueCurrency(),
|
|
'datacenter' => $datacenter,
|
|
'stripe_event_id' => null,
|
|
'stripe_subscription_id' => null,
|
|
'status' => 'paid',
|
|
]);
|
|
|
|
return ($this->bookAddon)($subscription, $addonKey, $quantity, $order, [
|
|
'price_cents' => $priceCents,
|
|
'granted_by' => $grantedBy->id,
|
|
'granted_at' => now(),
|
|
'grant_note' => $note,
|
|
'granted_until' => $until,
|
|
'catalogue_price_cents' => $cataloguePrice,
|
|
]);
|
|
}
|
|
}
|