companies:retire-agency-type: Firmen-Typ „Agentur" abschaffen
A4 des Umbaus Agentur-Attribution → User-Profil: Agentur-Firmen mit PMs oder Pressekontakten werden zu type=company umtypisiert (sie sind faktisch Newsrooms), leere Agentur-Firmen soft-gelöscht. Geschützt vor Löschung (nur Umtypisierung): Mitgliedschaften Dritter in company_user oder Verknüpfungen in user_payment_option_company. --dry-run + JSON-Report; im Deploy-Runbook nach legacy:migrate-agency-names eingereiht. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
85fddbfdf8
commit
59ac67a4c8
3 changed files with 252 additions and 4 deletions
126
tests/Feature/RetireAgencyCompanyTypeTest.php
Normal file
126
tests/Feature/RetireAgencyCompanyTypeTest.php
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\CompanyType;
|
||||
use App\Enums\Portal;
|
||||
use App\Models\Company;
|
||||
use App\Models\Contact;
|
||||
use App\Models\PressRelease;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPaymentOption;
|
||||
use App\Scopes\PortalScope;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
beforeEach(function (): void {
|
||||
/** @var TestCase $this */
|
||||
Storage::fake('local');
|
||||
});
|
||||
|
||||
function agencyCompany(array $attributes = []): Company
|
||||
{
|
||||
return Company::factory()->create(array_merge([
|
||||
'portal' => Portal::Presseecho,
|
||||
'type' => CompanyType::Agency,
|
||||
'owner_user_id' => User::factory()->create()->id,
|
||||
], $attributes));
|
||||
}
|
||||
|
||||
test('an agency with press releases is retyped to company', function () {
|
||||
/** @var TestCase $this */
|
||||
$agency = agencyCompany();
|
||||
PressRelease::factory()->forPortal(Portal::Presseecho)->create(['company_id' => $agency->id]);
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
$fresh = $agency->fresh();
|
||||
expect($fresh->type)->toBe(CompanyType::Company)
|
||||
->and($fresh->trashed())->toBeFalse();
|
||||
});
|
||||
|
||||
test('an agency with press contacts is retyped to company', function () {
|
||||
/** @var TestCase $this */
|
||||
$agency = agencyCompany();
|
||||
Contact::factory()->create(['company_id' => $agency->id, 'portal' => Portal::Presseecho->value]);
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
expect($agency->fresh()->type)->toBe(CompanyType::Company);
|
||||
});
|
||||
|
||||
test('an agency without press releases and contacts is soft-deleted', function () {
|
||||
/** @var TestCase $this */
|
||||
$agency = agencyCompany();
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
// Ohne PortalScope, aber MIT SoftDeletes-Scope: gelöscht = nicht auffindbar.
|
||||
expect(Company::withoutGlobalScope(PortalScope::class)->find($agency->id))->toBeNull()
|
||||
->and(Company::withoutGlobalScopes()->find($agency->id)->trashed())->toBeTrue();
|
||||
});
|
||||
|
||||
test('an empty agency with third-party members is only retyped, never deleted', function () {
|
||||
/** @var TestCase $this */
|
||||
$agency = agencyCompany();
|
||||
$agency->users()->attach(User::factory()->create()->id, ['role' => 'member']);
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
$fresh = $agency->fresh();
|
||||
expect($fresh)->not->toBeNull()
|
||||
->and($fresh->type)->toBe(CompanyType::Company);
|
||||
|
||||
$reportFile = collect(Storage::disk('local')->allFiles('migration'))->first();
|
||||
$report = json_decode(Storage::disk('local')->get($reportFile), true);
|
||||
expect($report['protected'])->toHaveCount(1)
|
||||
->and($report['protected'][0]['company_id'])->toBe($agency->id);
|
||||
});
|
||||
|
||||
test('an empty agency with a payment option link is only retyped, never deleted', function () {
|
||||
/** @var TestCase $this */
|
||||
$agency = agencyCompany();
|
||||
UserPaymentOption::factory()->create()->companies()->attach($agency->id, ['is_active' => true]);
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
$fresh = $agency->fresh();
|
||||
expect($fresh)->not->toBeNull()
|
||||
->and($fresh->type)->toBe(CompanyType::Company);
|
||||
});
|
||||
|
||||
test('a membership of the owner does not protect an empty agency from deletion', function () {
|
||||
/** @var TestCase $this */
|
||||
$owner = User::factory()->create();
|
||||
$agency = agencyCompany(['owner_user_id' => $owner->id]);
|
||||
$agency->users()->attach($owner->id, ['role' => 'owner']);
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
expect(Company::withoutGlobalScopes()->withTrashed()->find($agency->id)->trashed())->toBeTrue();
|
||||
});
|
||||
|
||||
test('regular companies stay untouched', function () {
|
||||
/** @var TestCase $this */
|
||||
$company = Company::factory()->create([
|
||||
'portal' => Portal::Presseecho,
|
||||
'type' => CompanyType::Company,
|
||||
]);
|
||||
|
||||
$this->artisan('companies:retire-agency-type')->assertSuccessful();
|
||||
|
||||
$fresh = $company->fresh();
|
||||
expect($fresh->type)->toBe(CompanyType::Company)
|
||||
->and($fresh->trashed())->toBeFalse();
|
||||
});
|
||||
|
||||
test('dry-run changes nothing but writes a report', function () {
|
||||
/** @var TestCase $this */
|
||||
$newsroomAgency = agencyCompany();
|
||||
PressRelease::factory()->forPortal(Portal::Presseecho)->create(['company_id' => $newsroomAgency->id]);
|
||||
$emptyAgency = agencyCompany();
|
||||
|
||||
$this->artisan('companies:retire-agency-type', ['--dry-run' => true])->assertSuccessful();
|
||||
|
||||
expect($newsroomAgency->fresh()->type)->toBe(CompanyType::Agency)
|
||||
->and($emptyAgency->fresh()->trashed())->toBeFalse()
|
||||
->and(Storage::disk('local')->allFiles('migration'))->toHaveCount(1);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue