currentVersion($plan); $cataloguePrice = $version->priceFor($term); if ($cataloguePrice === null) { throw new RuntimeException("Plan '{$plan}' is not sold on a {$term} term."); } // A "grant" that charges more than the plan actually costs is not a // grant — that path already exists, and it goes through Stripe. if ($priceCents < 0 || $priceCents > $cataloguePrice->amount_cents) { throw new RuntimeException('A grant cannot charge more than the catalogue price.'); } [$run, $subscription] = DB::transaction(function () use ( $customer, $grantedBy, $plan, $term, $datacenter, $priceCents, $bonus, $note, $until, $cataloguePrice, ) { $order = Order::create([ 'customer_id' => $customer->id, 'plan' => $plan, 'type' => 'new', 'amount_cents' => $priceCents, 'currency' => Subscription::catalogueCurrency(), 'datacenter' => $datacenter, // Never Stripe's: this purchase never went through Stripe at // all, which is the whole point, and is also what tells // IssueInvoice and the revenue figures this row apart from an // ordinary (possibly also zero-priced) checkout. 'stripe_event_id' => null, 'stripe_subscription_id' => null, 'status' => 'paid', ]); $run = ProvisioningRun::create([ 'subject_type' => Order::class, 'subject_id' => $order->id, 'pipeline' => 'customer', 'status' => ProvisioningRun::STATUS_PENDING, 'current_step' => 0, 'context' => ['branding' => $customer->brandingResolved()], ]); $overrides = array_filter([ 'price_cents' => $priceCents, 'quota_gb' => $bonus['quota_gb'] ?? null, 'seats' => $bonus['seats'] ?? null, 'traffic_gb' => $bonus['traffic_gb'] ?? null, ], fn ($value) => $value !== null); $overrides += [ 'granted_by' => $grantedBy->id, 'granted_at' => now(), 'grant_note' => $note, 'granted_until' => $until, 'catalogue_price_cents' => $cataloguePrice->amount_cents, ]; $subscription = ($this->openSubscription)($order, $term, $overrides); return [$run, $subscription]; }); // After the commit, never inside it — a worker can pick the run up // before the transaction lands (see StartCustomerProvisioning). AdvanceRunJob::dispatch($run->uuid); return $subscription; } }