169 lines
6.3 KiB
PHP
169 lines
6.3 KiB
PHP
<?php
|
|
|
|
use App\Livewire\Admin\CustomerDetail;
|
|
use App\Models\Customer;
|
|
use App\Models\Instance;
|
|
use App\Models\Invoice;
|
|
use App\Models\InvoiceSeries;
|
|
use App\Models\Order;
|
|
use App\Models\Subscription;
|
|
use App\Support\CompanyProfile;
|
|
use Livewire\Livewire;
|
|
|
|
/**
|
|
* The customer page shows the customer.
|
|
*
|
|
* The first version was a compose box with three lists under it, and the
|
|
* complaint was exactly right: it showed nothing ABOUT the customer. An operator
|
|
* on the phone needs the address, the package, whether the last invoice was paid
|
|
* and what was already said — and none of that was on the page.
|
|
*/
|
|
beforeEach(function () {
|
|
CompanyProfile::put([
|
|
'name' => 'CluPilot GmbH', 'address' => 'Musterstraße 1',
|
|
'postcode' => '1010', 'city' => 'Wien', 'vat_id' => 'ATU12345678',
|
|
]);
|
|
|
|
$this->customer = Customer::factory()->create([
|
|
'name' => 'Beispiel GmbH',
|
|
'contact_name' => 'Bea Berger',
|
|
'phone' => '+43 1 2345678',
|
|
'billing_address' => "Musterstraße 2\n1020 Wien",
|
|
'vat_id' => 'ATU99999999',
|
|
'customer_type' => Customer::TYPE_BUSINESS,
|
|
]);
|
|
});
|
|
|
|
it('opens on the details', function () {
|
|
Livewire::actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSet('tab', 'overview')
|
|
// The things somebody on the phone needs first.
|
|
->assertSee('Bea Berger')
|
|
->assertSee('+43 1 2345678')
|
|
->assertSee('ATU99999999')
|
|
->assertSee('1020 Wien')
|
|
->assertSee(__('customer_detail.type_business'));
|
|
});
|
|
|
|
it('remembers the tab across a reload, because it is in the URL', function () {
|
|
Livewire::withQueryParams(['tab' => 'billing'])
|
|
->actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSet('tab', 'billing')
|
|
->assertSee(__('customer_detail.invoices'));
|
|
});
|
|
|
|
it('falls back to the first tab when the URL names one that does not exist', function () {
|
|
Livewire::withQueryParams(['tab' => 'wat'])
|
|
->actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSet('tab', 'overview');
|
|
});
|
|
|
|
it('says a customer nobody asked is treated as a consumer', function () {
|
|
// Not cosmetic: it decides whether a withdrawal right exists at all, and the
|
|
// page must not let "nobody asked" read as "business".
|
|
$unknown = Customer::factory()->create(['customer_type' => null]);
|
|
|
|
Livewire::actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $unknown->uuid])
|
|
->assertSee(__('customer_detail.type_unknown'));
|
|
});
|
|
|
|
it('shows the contract the customer is owed, with its own frozen figures', function () {
|
|
// The contract's own price, not today's catalogue: a price rise does not
|
|
// reach back into what somebody already bought.
|
|
Subscription::factory()->plan('team')->create([
|
|
'customer_id' => $this->customer->id,
|
|
'status' => 'active',
|
|
]);
|
|
|
|
Livewire::withQueryParams(['tab' => 'package'])
|
|
->actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSee(__('billing.plan.team'))
|
|
->assertSee('500 GB') // team's quota
|
|
->assertSee(__('customer_detail.price'));
|
|
});
|
|
|
|
it('shows the machine, and says so plainly when there is none', function () {
|
|
Livewire::withQueryParams(['tab' => 'package'])
|
|
->actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSee(__('customer_detail.no_contract'));
|
|
|
|
Subscription::factory()->plan('start')->create(['customer_id' => $this->customer->id, 'status' => 'active']);
|
|
Instance::factory()->create([
|
|
'customer_id' => $this->customer->id,
|
|
'subdomain' => 'kanzlei-berger',
|
|
'status' => 'active',
|
|
]);
|
|
|
|
Livewire::withQueryParams(['tab' => 'package'])
|
|
->actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSee('kanzlei-berger');
|
|
});
|
|
|
|
it('shows what was invoiced and what was bought, which are two questions', function () {
|
|
// An order is a purchase; an invoice is a document about one. A customer
|
|
// asking "was das schon verrechnet?" is asking about the second.
|
|
InvoiceSeries::query()->firstOrCreate(
|
|
['kind' => 'invoice'],
|
|
['name' => 'Rechnungen', 'prefix' => 'RE', 'active' => true],
|
|
);
|
|
|
|
Order::factory()->create([
|
|
'customer_id' => $this->customer->id,
|
|
'plan' => 'start',
|
|
'amount_cents' => 4900,
|
|
'status' => 'paid',
|
|
]);
|
|
|
|
Invoice::create([
|
|
'invoice_series_id' => InvoiceSeries::query()->first()->id,
|
|
'customer_id' => $this->customer->id,
|
|
'number' => 'RE-2026-0007',
|
|
'number_year' => 2026,
|
|
'number_sequence' => 7,
|
|
'issued_on' => now()->toDateString(),
|
|
'due_on' => now()->addDays(14)->toDateString(),
|
|
'snapshot' => ['meta' => ['number' => 'RE-2026-0007']],
|
|
'net_cents' => 4900,
|
|
'tax_cents' => 980,
|
|
'gross_cents' => 5880,
|
|
'currency' => 'EUR',
|
|
]);
|
|
|
|
Livewire::withQueryParams(['tab' => 'billing'])
|
|
->actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid])
|
|
->assertSee('RE-2026-0007')
|
|
->assertSee('58,80')
|
|
->assertSee(__('customer_detail.orders'));
|
|
});
|
|
|
|
it('offers writing last, because it is what you do after reading', function () {
|
|
$tabs = CustomerDetail::TABS;
|
|
|
|
expect($tabs[0])->toBe('overview')
|
|
->and(end($tabs))->toBe('compose');
|
|
|
|
// Every tab has a label, or the bar reads "customer_detail.tab.x".
|
|
foreach ($tabs as $tab) {
|
|
expect(__('customer_detail.tab.'.$tab))->not->toBe('customer_detail.tab.'.$tab);
|
|
}
|
|
});
|
|
|
|
it('does not print a lang key at anybody', function () {
|
|
// The badge read "customers.status.active" once. A key with no file behind
|
|
// it renders as itself and Laravel says nothing about it.
|
|
$page = Livewire::actingAs(operator('Owner'), 'operator')
|
|
->test(CustomerDetail::class, ['uuid' => $this->customer->uuid]);
|
|
|
|
$page->assertDontSee('customers.status.')
|
|
->assertDontSee('customer_detail.tab.')
|
|
->assertSee(__('admin.status.active'));
|
|
});
|