create([ 'is_active' => true, 'name' => 'Original Name', 'language' => 'de', ]); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->assertSee('Rechnungsadresse') ->set('name', 'Neuer Anzeigename') ->set('firstName', 'Max') ->set('lastName', 'Mustermann') ->set('language', 'en') ->set('address', 'Musterfirma GmbH, Musterstrasse 1, 10115 Berlin') ->set('countryCode', 'AT') ->set('billingCompany', 'Musterfirma GmbH') ->set('billingFirstName', 'Max') ->set('billingLastName', 'Mustermann') ->set('billingAddress1', 'Musterstrasse 1') ->set('billingPostalCode', '10115') ->set('billingCity', 'Berlin') ->set('billingCountryCode', 'DE') ->set('taxIdNumber', 'DE123456789') ->set('showStats', true) ->call('saveProfile') ->assertHasNoErrors(); $customer->refresh(); expect($customer->name)->toBe('Neuer Anzeigename'); expect($customer->language)->toBe('en'); expect($customer->profile?->first_name)->toBe('Max'); expect($customer->profile?->last_name)->toBe('Mustermann'); expect($customer->profile?->address)->toBe('Musterfirma GmbH, Musterstrasse 1, 10115 Berlin'); expect($customer->profile?->country_code)->toBe('AT'); expect($customer->profile?->tax_id_number)->toBe('DE123456789'); expect($customer->profile?->show_stats)->toBeTrue(); expect($customer->billingAddress?->company)->toBe('Musterfirma GmbH'); expect($customer->billingAddress?->first_name)->toBe('Max'); expect($customer->billingAddress?->last_name)->toBe('Mustermann'); expect($customer->billingAddress?->name)->toBe('Max Mustermann'); expect($customer->billingAddress?->address1)->toBe('Musterstrasse 1'); expect($customer->billingAddress?->postal_code)->toBe('10115'); expect($customer->billingAddress?->city)->toBe('Berlin'); expect($customer->billingAddress?->country_code)->toBe('DE'); expect($customer->billingAddress?->vat_id)->toBe('DE123456789'); }); test('an incomplete billing address reports each missing field exactly once', function () { /** @var TestCase $this */ $customer = User::factory()->create(['is_active' => true]); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->set('billingCompany', 'Nur Firma GmbH') ->call('saveProfile') ->assertHasErrors(['billingLastName', 'billingAddress1', 'billingPostalCode', 'billingCity']); }); test('a malformed vat id blocks saving with a field error', function () { /** @var TestCase $this */ $customer = User::factory()->create(['is_active' => true]); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->set('taxIdNumber', '123-nicht-gueltig') ->call('saveProfile') ->assertHasErrors(['taxIdNumber']); }); test('the profile data can be copied into the billing address', function () { /** @var TestCase $this */ $customer = User::factory()->create(['is_active' => true]); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->set('salutationKey', 'mr') ->set('firstName', 'Kopier') ->set('lastName', 'Kunde') ->set('countryCode', 'AT') ->call('copyProfileToBilling') ->assertSet('billingSalutationKey', 'mr') ->assertSet('billingFirstName', 'Kopier') ->assertSet('billingLastName', 'Kunde') ->assertSet('billingCountryCode', 'AT'); }); test('customer profile keeps company management out of the profile page', function () { /** @var TestCase $this */ $customer = User::factory()->create(['is_active' => true]); $company = Company::factory()->presseecho()->create([ 'owner_user_id' => $customer->id, 'name' => 'Nicht im Profil geladene Firma', ]); $customer->companies()->attach($company->id, ['role' => 'owner']); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->assertSee('Rechnungsadresse') ->assertSee('Persönliche Daten') ->assertSee('Firmen verwalten') ->assertDontSee('Zugeordnete Firmen') ->assertDontSee('Nicht im Profil geladene Firma'); }); test('customer can save profile settings without a billing address', function () { /** @var TestCase $this */ $customer = User::factory()->create([ 'is_active' => true, 'name' => 'Ohne Rechnung', ]); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->set('name', 'Nur Profil') ->set('firstName', 'Nur') ->set('lastName', 'Profil') ->call('saveProfile') ->assertHasNoErrors(); expect($customer->refresh()->name)->toBe('Nur Profil'); expect($customer->billingAddress)->toBeNull(); }); test('customer security page renders password and email forms', function () { /** @var TestCase $this */ $customer = User::factory()->create([ 'is_active' => true, 'password' => bcrypt('current-password'), ]); $this->actingAs($customer); LivewireVolt::test('customer.security') ->assertSee('Konto-Sicherheit') ->assertSee('Letzter Login') ->assertSee('Aktive Sessions') ->assertSee('Passwort ändern') ->assertSee('E-Mail-Adresse ändern') ->assertSee('Zwei-Faktor-Authentifizierung'); }); test('customer can change own password through security page', function () { /** @var TestCase $this */ $customer = User::factory()->create([ 'is_active' => true, 'password' => bcrypt('current-password'), ]); $this->actingAs($customer); LivewireVolt::test('customer.security') ->set('current_password', 'current-password') ->set('password', 'new-strong-password') ->set('password_confirmation', 'new-strong-password') ->call('updatePassword') ->assertHasNoErrors(); $customer->refresh(); expect(Hash::check('new-strong-password', $customer->password))->toBeTrue(); }); test('press release policy denies access to other users releases', function () { /** @var TestCase $this */ $owner = User::factory()->create(['is_active' => true]); $intruder = User::factory()->create(['is_active' => true]); $pr = PressRelease::factory()->create([ 'user_id' => $owner->id, 'status' => 'draft', ]); expect($intruder->can('view', $pr))->toBeFalse(); expect($intruder->can('update', $pr))->toBeFalse(); expect($owner->can('view', $pr))->toBeTrue(); expect($owner->can('update', $pr))->toBeTrue(); }); test('me press release routes only resolve own press releases even for admins', function () { /** @var TestCase $this */ $this->seed(RolesAndPermissionsSeeder::class); $admin = User::factory()->create(['is_active' => true]); $admin->assignRole('admin'); $otherUser = User::factory()->create(['is_active' => true]); $otherPressRelease = PressRelease::factory()->create([ 'user_id' => $otherUser->id, 'status' => 'draft', ]); $this->actingAs($admin); $this->get(route('me.press-releases.show', $otherPressRelease->id)) ->assertNotFound(); $this->get(route('me.press-releases.edit', $otherPressRelease->id)) ->assertNotFound(); }); test('customer press releases derive portal from selected company', function () { /** @var TestCase $this */ $customer = User::factory()->create(['is_active' => true]); $company = Company::factory()->presseecho()->create(); $customer->companies()->attach($company->id, ['role' => 'owner']); $contact = Contact::factory()->for($company)->create(['portal' => $company->portal->value]); $this->actingAs($customer); LivewireVolt::test('customer.press-releases.create') ->set('companyId', $company->id) ->set('portal', Portal::Businessportal24->value) ->set('categoryId', Category::factory()->create()->id) ->set('contactId', $contact->id) ->set('title', 'Neue Meldung fuer Presseecho') ->set('text', str_repeat('Dies ist ein ausreichend langer Testtext. ', 3)) ->call('save', 'draft') ->assertHasNoErrors(); $pressRelease = PressRelease::query()->where('user_id', $customer->id)->firstOrFail(); expect($pressRelease->portal)->toBe(Portal::Presseecho); }); test('customer press release detail shows assigned contacts and status history', function () { /** @var TestCase $this */ $customer = User::factory()->create([ 'is_active' => true, 'name' => 'Kunden Nutzer', ]); $company = Company::factory()->presseecho()->create([ 'name' => 'Alpha GmbH', ]); $customer->companies()->attach($company->id, ['role' => 'owner']); $pressRelease = PressRelease::factory()->forPortal(Portal::Presseecho)->create([ 'user_id' => $customer->id, 'company_id' => $company->id, 'title' => 'Alpha Detailmeldung', 'status' => PressReleaseStatus::Review->value, 'hits' => 1234, ]); $contact = Contact::factory()->create([ 'company_id' => $company->id, 'portal' => Portal::Presseecho->value, 'first_name' => 'Paula', 'last_name' => 'Presse', 'responsibility' => 'PR Managerin', 'email' => 'paula@example.test', ]); $pressRelease->contacts()->attach($contact->id); PressReleaseStatusLog::query()->create([ 'press_release_id' => $pressRelease->id, 'changed_by_user_id' => $customer->id, 'from_status' => PressReleaseStatus::Draft->value, 'to_status' => PressReleaseStatus::Review->value, 'reason' => 'Zur Prüfung eingereicht', 'source' => 'customer', 'created_at' => now(), ]); $this->actingAs($customer); LivewireVolt::test('customer.press-releases.show', ['id' => $pressRelease->id]) ->assertSee('Alpha Detailmeldung') ->assertSee('Zugeordnete Pressekontakte') ->assertSee('Paula Presse') ->assertSee('paula@example.test') ->assertSee('Status & Verlauf') ->assertSee('In Pruefung') ->assertSee('1.234') ->assertSee('Zur Prüfung eingereicht') ->assertSee('durch Kunden Nutzer'); }); test('legacy invoice policy denies access to invoices of other users', function () { /** @var TestCase $this */ $owner = User::factory()->create(['is_active' => true]); $intruder = User::factory()->create(['is_active' => true]); $invoice = LegacyInvoice::query()->create([ 'legacy_portal' => 'presseecho', 'legacy_id' => 9001, 'user_id' => $owner->id, 'legacy_user_id' => 9001, 'number' => 'RE-OWN-9001', 'amount_cents' => 9900, 'total_cents' => 9900, 'status' => 'paid', 'invoice_date' => now()->subMonth(), 'imported_at' => now(), ]); expect($owner->can('view', $invoice))->toBeTrue(); expect($intruder->can('view', $invoice))->toBeFalse(); expect($intruder->can('downloadPdf', $invoice))->toBeFalse(); });