seed(RolesAndPermissionsSeeder::class); config()->set('billing.enforce_booking', false); config()->set('app.theme', 'portal'); $user = User::factory()->create(['is_active' => true, 'portal' => $portal]); $user->forceFill(['registration_type' => 'apiuser'])->save(); Sanctum::actingAs($user, ['press-releases:read', 'press-releases:write', 'companies:read']); return $user; } /** * @param array $overrides */ function postApiCompany(array $overrides = []): int { $response = test()->postJson('/service/users/me/companies', [ 'company' => array_merge(['name' => 'Muster GmbH', 'email' => 'info@muster.de'], $overrides), ])->assertCreated(); return (int) basename((string) $response->headers->get('Location')); } function assignmentGroup(string $email, CompanyAddressClass $class, ?CompanyAddressClass $manual = null): void { CompanyEmailGroup::query()->create([ 'email' => $email, 'classification' => $class, 'manual_classification' => $manual, 'companies_count' => 30, 'distinct_names' => 30, 'published_companies_count' => 0, 'threshold' => 3, 'classified_at' => now(), ]); } test('the same company under the same email is reused instead of created', function () { /** @var TestCase $this */ $user = assignmentApiUser(); $existing = Company::factory()->create(['email' => 'info@muster.de', 'name' => 'Muster GmbH', 'portal' => 'businessportal24']); $id = postApiCompany(['email' => 'Info@Muster.de']); expect($id)->toBe($existing->id) ->and(Company::withoutGlobalScopes()->where('email', 'like', '%muster.de')->count())->toBe(1) ->and($existing->users()->whereKey($user->id)->wherePivot('role', 'member')->exists())->toBeTrue() ->and(ActivityEvent::query()->where('subject_id', $existing->id)->where('description', 'like', 'API-Firma%')->exists())->toBeTrue(); }); test('a name that differs only by legal form or a typo still matches', function () { /** @var TestCase $this */ assignmentApiUser(); $existing = Company::factory()->create(['email' => 'info@muster.de', 'name' => 'Muster Unternehmensberatung', 'portal' => 'businessportal24']); expect(postApiCompany(['name' => 'Muster Unternehmensberatung GmbH & Co. KG']))->toBe($existing->id) ->and(postApiCompany(['name' => 'Muster Unternehmensbertung']))->toBe($existing->id); }); test('a different name under the same address gets its own company as before', function () { /** @var TestCase $this */ assignmentApiUser(); Company::factory()->create(['email' => 'presse@agentur.de', 'name' => 'Kunde Eins GmbH', 'portal' => 'businessportal24']); $id = postApiCompany(['name' => 'Ganz Anderer Kunde AG', 'email' => 'presse@agentur.de']); expect(Company::withoutGlobalScopes()->find($id)->name)->toBe('Ganz Anderer Kunde AG') ->and(Company::withoutGlobalScopes()->where('email', 'presse@agentur.de')->count())->toBe(2); }); test('under a never-published address nothing is ever assigned', function () { /** @var TestCase $this */ assignmentApiUser(); assignmentGroup('yahoo@yahoo.com', CompanyAddressClass::NeverPublished); $existing = Company::factory()->create(['email' => 'yahoo@yahoo.com', 'name' => 'Muster GmbH', 'portal' => 'businessportal24']); expect(postApiCompany(['email' => 'yahoo@yahoo.com']))->not->toBe($existing->id); }); test('a manual decision can turn a never-published address back into a normal one', function () { /** @var TestCase $this */ assignmentApiUser(); assignmentGroup('presse@pr4you.de', CompanyAddressClass::NeverPublished, manual: CompanyAddressClass::CollectionAddress); $existing = Company::factory()->create(['email' => 'presse@pr4you.de', 'name' => 'Muster GmbH', 'portal' => 'businessportal24']); expect(postApiCompany(['email' => 'presse@pr4you.de']))->toBe($existing->id); }); test('a company on the other portal becomes both and the release lands on the requested portal', function () { /** @var TestCase $this */ $user = assignmentApiUser(Portal::Presseecho); $existing = Company::factory()->create(['email' => 'info@muster.de', 'name' => 'Muster GmbH', 'portal' => 'businessportal24']); $category = Category::factory()->create(['portal' => Portal::Both]); Queue::fake(); $id = postApiCompany(); expect($id)->toBe($existing->id) ->and($existing->fresh()->portal)->toBe(Portal::Both); $this->postJson('/service/pressreleases', [ 'press_release' => [ 'company_id' => $id, 'category_id' => $category->legacy_id ?? $category->id, 'language' => 'de', 'title' => 'Zuordnungs-Test', 'text' => 'Inhalt der Test-Pressemitteilung mit genug Text.', ], ])->assertCreated(); // `both` ist kein Ziel-Portal für eine Meldung — ohne Parameter und // Domain-Kontext entscheidet das Portal des API-Nutzers. $release = PressRelease::withoutGlobalScopes()->where('title', 'Zuordnungs-Test')->firstOrFail(); expect($release->portal)->toBe(Portal::Presseecho) ->and($release->company_id)->toBe($existing->id) ->and($release->user_id)->toBe($user->id); }); test('a slug taken on the other portal prevents widening and falls back to a new company', function () { /** @var TestCase $this */ assignmentApiUser(Portal::Presseecho); $existing = Company::factory()->create(['email' => 'info@muster.de', 'name' => 'Muster GmbH', 'portal' => 'businessportal24', 'slug' => 'muster-gmbh']); Company::factory()->create(['email' => 'anders@fremd.de', 'name' => 'Muster GmbH', 'portal' => 'presseecho', 'slug' => 'muster-gmbh']); $id = postApiCompany(); expect($id)->not->toBe($existing->id) ->and($existing->fresh()->portal)->toBe(Portal::Businessportal24); }); test('a merged-away company is not matched, its survivor is', function () { /** @var TestCase $this */ assignmentApiUser(Portal::Presseecho); $survivor = Company::factory()->create(['email' => 'info@muster.de', 'name' => 'Muster GmbH', 'portal' => 'both']); $gone = Company::factory()->create(['email' => 'info@muster.de', 'name' => 'Muster GmbH', 'portal' => 'presseecho']); $gone->delete(); expect(postApiCompany())->toBe($survivor->id); }); test('without an email a company is created as before', function () { /** @var TestCase $this */ assignmentApiUser(); $existing = Company::factory()->create(['email' => null, 'name' => 'Muster GmbH', 'portal' => 'businessportal24']); expect(postApiCompany(['email' => null]))->not->toBe($existing->id); });