CluPilotCloud/tests/Feature/Billing/OfficeNotSoldTest.php

92 lines
4.0 KiB
PHP

<?php
use App\Livewire\Billing;
use App\Models\Customer;
use App\Models\Instance;
use App\Models\Order;
use App\Models\User;
use App\Services\Billing\AddonCatalogue;
use Livewire\Livewire;
/**
* Office liefert nicht — siehe App\Support\OpenWork::all() — und die
* Preistafel verspricht `collabora_pro` deshalb seit der Umstellung nicht
* mehr (LandingPriceSheetTest). Offen blieb der zweite Weg, den der Umsetzer
* selbst gemeldet hat: ein eingeloggter Team- oder Business-Kunde konnte das
* Modul weiterhin über die Abrechnungsseite buchen, weil AddonCatalogue den
* Preis unverändert kannte (BookAddon braucht ihn für Bestandsfälle und ein
* Geschenk des Betreibers) und App\Livewire\Billing::purchase() nie danach
* gefragt hat.
*
* Der Riegel sitzt jetzt in AddonCatalogue::saleRefusal() — derselben Stelle,
* die auch LandingController::modulePrices() liest — und wird hier an BEIDEN
* Enden geprüft: der Kauf selbst (am Formular vorbei, nicht nur "der Knopf
* fehlt") und die Karte, die ihn anbieten würde.
*/
function officeShopper(string $plan = 'team'): array
{
$customer = Customer::factory()->create();
$user = User::factory()->create(['email' => $customer->email]);
$order = Order::factory()->withSubscription()->for($customer)->create(['plan' => $plan]);
$instance = Instance::factory()->for($customer)->create([
'order_id' => $order->id,
'plan' => $plan,
'status' => 'active',
]);
$order->subscription->update(['instance_id' => $instance->id]);
// purchase() refuses outright without a Stripe key for the active mode
// (Task 5) — the refusal this test is about must not be masked by that
// earlier one.
withStripeSecret();
return [$customer, $user];
}
it('weist eine Buchung von collabora_pro am Formular vorbei ab, solange Office nicht verkauft wird', function () {
// Absichtlich NICHT über einen fehlenden Knopf geprüft: das würde nur
// zeigen, dass die Anzeige geschlossen ist. Dieser Aufruf geht am
// Formular vorbei — genau der Weg, den ein zweites Browser-Fenster, eine
// alte Sitzung oder ein direkter Aufruf des Komponentennamens auch nähme.
[$customer, $user] = officeShopper('team');
Livewire::actingAs($user)->test(Billing::class)
->call('purchase', 'addon', 'collabora_pro')
->assertDispatched('notify', message: __('billing.addon_not_on_sale', [
'module' => __('billing.addon.collabora_pro.name'),
]));
// Kein Auftrag, also nichts, das später fälschlich zur Buchung würde.
expect(Order::query()->where('customer_id', $customer->id)->where('type', 'addon')->exists())->toBeFalse();
});
it('zeigt die Office-Karte im Portal nicht mehr an, solange sie ohnehin abgewiesen würde', function () {
[, $user] = officeShopper('team');
// Team trägt `collabora_pro` nicht in `unavailable_on` — ohne den neuen
// Riegel stünde die Karte hier also, mit einem Kauf-Knopf, der beim
// Anklicken nur die Meldung aus dem Test oben gezeigt hätte.
Livewire::actingAs($user)->test(Billing::class)
->assertDontSee(__('billing.addon.collabora_pro.name'));
});
it('lässt die anderen Module unberührt, sowohl in der Anzeige als auch bei der Buchung', function () {
// Der Riegel gilt nur `collabora_pro` — für alles andere muss
// saleRefusal() weiterhin null bleiben, sonst hätte diese Änderung den
// ganzen Shop zugesperrt statt eines einzelnen Moduls.
$catalogue = app(AddonCatalogue::class);
foreach (['extra_backups', 'priority_support', 'custom_domain', AddonCatalogue::STORAGE] as $key) {
expect($catalogue->saleRefusal($key))->toBeNull();
}
[, $user] = officeShopper('team');
Livewire::actingAs($user)->test(Billing::class)
->call('purchase', 'addon', 'priority_support')
->assertDispatched('notify', message: __('billing.purchased'));
expect(Order::query()->where('type', 'addon')->where('addon_key', 'priority_support')->exists())->toBeTrue();
});