packGb())->toBe(20) ->and($catalogue->packDiskGb())->toBe(22) ->and($catalogue->priceCents(AddonCatalogue::STORAGE))->toBe(1500) ->and($catalogue->maxQuantity(AddonCatalogue::STORAGE))->toBe(3); }); it('bleibt teurer je Gigabyte als der Aufstieg', function () { // Gerechnet wird mit dem, was Katalog und Konfiguration WIRKLICH sagen — // mit festen Zahlen prüfte dieser Test nur, ob PHP dividieren kann. So // schlägt er an, wenn ein Preis später einmal so gesetzt wird, dass // Stapeln sich wieder lohnt. $catalogue = app(AddonCatalogue::class); $plans = app(PlanCatalogue::class)->sellable(); $blockPerGb = $catalogue->priceCents(AddonCatalogue::STORAGE) / $catalogue->packGb(); foreach ([['start', 'team'], ['team', 'business']] as [$von, $nach]) { $mehrGb = $plans[$nach]['quota_gb'] - $plans[$von]['quota_gb']; $mehrCent = $plans[$nach]['price_cents'] - $plans[$von]['price_cents']; expect($blockPerGb)->toBeGreaterThan($mehrCent / $mehrGb); } }); it('bietet Enterprise keinen Zusatzspeicher an', function () { // Enterprise wird seit der neuen Leiter angefragt statt gekauft; der // Vertrag hier ist einer aus der Zeit davor, und die laufen weiter. $order = Order::factory()->create(['plan' => 'enterprise', 'datacenter' => 'fsn', 'status' => 'paid']); $subscription = asGrandfathered('enterprise', fn () => app(OpenSubscription::class)($order)); expect(fn () => app(BookAddon::class)($subscription, AddonCatalogue::STORAGE, 1)) ->toThrow(RuntimeException::class); }); /** * Nachtrag: derselbe Ausschluss, wenn der Betreiber ein Modul verschenkt. * * GrantAddon bucht durch BookAddon (siehe dessen Kopfkommentar), also reicht * die Prüfung an einer Stelle — dieser Test belegt nur, dass der Weg * tatsächlich derselbe ist und nicht heimlich daran vorbeiführt. */ it('lässt auch den Betreiber keinen Zusatzspeicher an Enterprise verschenken', function () { $order = Order::factory()->create(['plan' => 'enterprise', 'datacenter' => 'fsn', 'status' => 'paid']); $subscription = asGrandfathered('enterprise', fn () => app(OpenSubscription::class)($order)); $operator = Operator::factory()->create(); expect(fn () => app(GrantAddon::class)($subscription, $operator, AddonCatalogue::STORAGE, 0, 1)) ->toThrow(RuntimeException::class); }); /** * Nachtrag: dieselbe Sperre, bevor Geld fließt, nicht erst danach. * * `storageLimitNote` ist das, was den Knopf im Portal verschwinden lässt (statt * ihn anzubieten und dann an der Zahlung zu scheitern) — derselbe Grund, aus * dem die kaufmännische Grenze dort schon geprüft wurde. Ohne diese Prüfung * würde ein Enterprise-Kunde einen zahlbaren Auftrag in den Warenkorb legen * können, den BookAddon nach der Zahlung nur noch ablehnen könnte, während der * Auftrag selbst „paid" stehen bliebe. */ it('bietet Enterprise auch im Warenkorb keinen Zusatzspeicher an', function () { $customer = Customer::factory()->create(); $user = User::factory()->create(['email' => $customer->email]); $order = asGrandfathered('enterprise', fn () => Order::factory()->withSubscription()->for($customer)->create(['plan' => 'enterprise'])); Instance::factory()->for($customer)->create([ 'order_id' => $order->id, 'plan' => 'enterprise', 'status' => 'active', ]); withStripeSecret(); Livewire\Livewire::actingAs($user) ->test(Billing::class) ->call('purchase', 'storage'); expect(Order::query()->where('customer_id', $customer->id)->where('type', 'storage')->count())->toBe(0); });