CluPilotCloud/tests/Feature/Admin/GrantPlanTest.php

110 lines
4.0 KiB
PHP

<?php
use App\Livewire\Admin\Customers;
use App\Livewire\Admin\GrantPlan;
use App\Models\Customer;
use App\Models\Subscription;
use App\Models\SubscriptionAddon;
use App\Provisioning\Jobs\AdvanceRunJob;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
/**
* The console's side of granting: a modal (R20) on the customer's own row,
* gated by its own capability rather than merely hidden (mutation target #3).
*
* 'fsn' is seeded by the datacenters migration itself (baseline data, like
* the mailbox seeding) — no factory needed for it here.
*/
it('refuses to open for an operator without the capability, not merely hides the button', function () {
$customer = Customer::factory()->create();
// Support has customers.manage (can suspend, impersonate) but never had
// customers.grant_plan — giving away service is a bigger deal than a
// reversible suspend, and the seed migration deliberately keeps this one
// to Owner. A capability check that only hid the button would still let
// this request through.
Livewire::actingAs(operator('Support'), 'operator')
->test(GrantPlan::class, ['uuid' => $customer->uuid])
->assertForbidden();
});
it('hides the grant button from an operator without the capability', function () {
Customer::factory()->create();
Livewire::actingAs(operator('Support'), 'operator')
->test(Customers::class)
->assertDontSee(__('admin.grant_action'));
});
it('shows the grant button to the Owner', function () {
Customer::factory()->create();
Livewire::actingAs(operator('Owner'), 'operator')
->test(Customers::class)
->assertSee(__('admin.grant_action'));
});
it('grants a free package to a customer with no contract yet', function () {
Queue::fake();
$customer = Customer::factory()->create();
$owner = operator('Owner');
Livewire::actingAs($owner, 'operator')
->test(GrantPlan::class, ['uuid' => $customer->uuid])
->set('plan', 'team')
->set('term', 'monthly')
->set('datacenter', 'fsn')
->set('priceEuros', '0')
->set('note', 'Testkunde')
->call('grant')
->assertHasNoErrors();
$subscription = Subscription::query()->where('customer_id', $customer->id)->sole();
expect($subscription->price_cents)->toBe(0)
->and($subscription->isGranted())->toBeTrue()
->and($subscription->granted_by)->toBe($owner->id);
Queue::assertPushed(AdvanceRunJob::class);
});
it('grants a discounted module onto an existing contract', function () {
$customer = Customer::factory()->create();
Subscription::factory()->create(['customer_id' => $customer->id, 'status' => 'active']);
$owner = operator('Owner');
Livewire::actingAs($owner, 'operator')
->test(GrantPlan::class, ['uuid' => $customer->uuid])
->assertSet('kind', 'addon') // a contract already exists — default to the module form
->set('addonKey', 'priority_support')
->set('quantity', 1)
->set('priceEuros', '5,00')
->call('grant')
->assertHasNoErrors();
$addon = SubscriptionAddon::query()->where('addon_key', 'priority_support')->sole();
expect($addon->price_cents)->toBe(500)
->and($addon->isGranted())->toBeTrue()
->and($addon->granted_by)->toBe($owner->id);
});
it('shows who granted what, when, and until when', function () {
$customer = Customer::factory()->create();
$owner = operator('Owner');
$until = now()->addMonths(3);
Subscription::factory()->create([
'customer_id' => $customer->id, 'status' => 'active',
'price_cents' => 0, 'granted_by' => $owner->id, 'granted_at' => now(),
'grant_note' => 'Sponsoring', 'granted_until' => $until, 'catalogue_price_cents' => 17900,
]);
Livewire::actingAs($owner, 'operator')
->test(GrantPlan::class, ['uuid' => $customer->uuid])
->assertSee($owner->name)
->assertSee('Sponsoring')
->assertSee($until->local()->isoFormat('D. MMM YYYY'));
});