190 lines
7.9 KiB
PHP
190 lines
7.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Business;
|
|
|
|
use App\Models\Auth\Permission;
|
|
use App\Models\Business\CourierAgreementSignature;
|
|
use App\Models\Business\CourierSigningSubject;
|
|
use Tests\Feature\FeatureTestCase;
|
|
|
|
class CourierSigningSubjectTest extends FeatureTestCase
|
|
{
|
|
protected function grantWorkspaceAccess(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
}
|
|
|
|
public function testAdminCanCreateUpdateAndSwitchSigningSubjects(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
|
|
$first = $this->loginAs()->postJson(
|
|
route('business.courier-agreement-signatures.subjects.store'),
|
|
['name' => '甲公司', 'unified_social_credit_code' => '91320100MA1TEST001'],
|
|
);
|
|
|
|
$first->assertOk()
|
|
->assertJsonPath('subject.name', '甲公司')
|
|
->assertJsonPath('subject.is_default', true);
|
|
|
|
$firstSubject = CourierSigningSubject::query()->where('name', '甲公司')->firstOrFail();
|
|
|
|
$second = $this->postJson(
|
|
route('business.courier-agreement-signatures.subjects.store'),
|
|
['name' => '乙公司'],
|
|
);
|
|
|
|
$second->assertOk()->assertJsonPath('subject.is_default', false);
|
|
$secondSubject = CourierSigningSubject::query()->where('name', '乙公司')->firstOrFail();
|
|
|
|
$this->postJson(
|
|
route('business.courier-agreement-signatures.subjects.default', $secondSubject),
|
|
)->assertOk()->assertJsonPath('subject.is_default', true);
|
|
|
|
$this->assertFalse($firstSubject->fresh()->is_default);
|
|
$this->assertTrue($secondSubject->fresh()->is_default);
|
|
|
|
$this->postJson(
|
|
route('business.courier-agreement-signatures.subjects.update', $secondSubject),
|
|
['name' => '乙公司(新)', 'unified_social_credit_code' => '91320100MA1TEST002'],
|
|
)->assertOk()->assertJsonPath('subject.name', '乙公司(新)');
|
|
|
|
$this->assertDatabaseHas('business_courier_signing_subjects', [
|
|
'id' => $secondSubject->id,
|
|
'name' => '乙公司(新)',
|
|
'is_default' => 1,
|
|
]);
|
|
}
|
|
|
|
public function testDuplicateSubjectNameIsRejected(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
$this->loginAs()->postJson(
|
|
route('business.courier-agreement-signatures.subjects.store'),
|
|
['name' => '甲公司'],
|
|
)->assertOk();
|
|
|
|
$this->withExceptionHandling()->postJson(
|
|
route('business.courier-agreement-signatures.subjects.store'),
|
|
['name' => '甲公司'],
|
|
)->assertStatus(422)
|
|
->assertJsonValidationErrors(['name']);
|
|
}
|
|
|
|
public function testDeletingAnOrdinarySubjectPreservesTheDefaultAndHistoricalAgreement(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
$default = $this->subject('默认公司', true);
|
|
$subject = $this->subject('历史签署公司');
|
|
$task = CourierAgreementSignature::create([
|
|
'company_id' => $this->company->id,
|
|
'business_no' => 'AGR-SUBJECT-DELETE',
|
|
'idempotency_key' => 'subject-delete-snapshot',
|
|
'document_type' => 'account-proof',
|
|
'template_code' => 'TPL-ACCOUNT-CERT-V2',
|
|
'template_version' => '2',
|
|
'source_file_name' => '收款账户证明文件.doc',
|
|
'status' => CourierAgreementSignature::STATUS_ARCHIVED,
|
|
'courier_name' => '测试快递',
|
|
'company_full_name' => $subject->name,
|
|
'organization_name' => '测试快递有限公司',
|
|
'payload' => ['signing_subject' => $subject->name],
|
|
'environment' => 'sandbox',
|
|
'source_pdf_path' => 'subject-delete/source.pdf',
|
|
'source_pdf_sha256' => str_repeat('a', 64),
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
|
|
$this->loginAs()->deleteJson($this->deleteUrl($subject), ['delete_confirmed' => true])
|
|
->assertOk()->assertJsonCount(1, 'subjects')
|
|
->assertJsonPath('subjects.0.id', $default->id)
|
|
->assertJsonPath('subjects.0.is_default', true);
|
|
|
|
$this->assertSoftDeleted($subject);
|
|
$this->assertSame($this->user->id, $subject->fresh()->updated_by);
|
|
$this->assertSame($subject->name, $task->fresh()->company_full_name);
|
|
$this->assertSame($subject->name, $task->fresh()->payload['signing_subject']);
|
|
$this->assertFalse($task->fresh()->trashed());
|
|
$this->withExceptionHandling()->deleteJson($this->deleteUrl($subject), ['delete_confirmed' => true])->assertNotFound();
|
|
}
|
|
|
|
public function testDeletingTheDefaultSelectsOneRemainingSubjectInTheSameCompany(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
$default = $this->subject('默认公司', true);
|
|
$next = $this->subject('剩余公司一');
|
|
$other = $this->subject('剩余公司二');
|
|
$foreign = $this->subject('其他租户公司', true, $this->company->id + 100);
|
|
|
|
$this->loginAs()->deleteJson($this->deleteUrl($default), ['delete_confirmed' => true])
|
|
->assertOk()->assertJsonCount(2, 'subjects')
|
|
->assertJsonPath('subjects.0.id', $next->id)
|
|
->assertJsonPath('subjects.0.is_default', true);
|
|
|
|
$this->assertSoftDeleted($default);
|
|
$this->assertTrue($next->fresh()->is_default);
|
|
$this->assertFalse($other->fresh()->is_default);
|
|
$this->assertTrue($foreign->fresh()->is_default);
|
|
$this->assertSame(1, CourierSigningSubject::query()->where('is_default', true)->count());
|
|
}
|
|
|
|
public function testLastSubjectCanBeDeletedAndANewSubjectBecomesDefault(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
$subject = $this->subject('唯一公司', true);
|
|
|
|
$this->loginAs()->postJson($this->deleteUrl($subject), ['_method' => 'DELETE', 'delete_confirmed' => '1'])
|
|
->assertOk()->assertJsonCount(0, 'subjects')->assertJsonPath('subject', null);
|
|
|
|
$this->assertSoftDeleted($subject);
|
|
$this->postJson(route('business.courier-agreement-signatures.subjects.store'), ['name' => '唯一公司'])
|
|
->assertOk()->assertJsonPath('subject.is_default', true);
|
|
}
|
|
|
|
public function testSubjectDeletionRequiresConfirmation(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
$subject = $this->subject('保留公司', true);
|
|
|
|
$this->withExceptionHandling()->loginAs()->deleteJson($this->deleteUrl($subject))
|
|
->assertStatus(422)->assertJsonValidationErrors(['delete_confirmed']);
|
|
|
|
$this->assertFalse($subject->fresh()->trashed());
|
|
}
|
|
|
|
public function testSubjectDeletionEnforcesCompanyAndManagementPermission(): void
|
|
{
|
|
$this->grantWorkspaceAccess();
|
|
$subject = $this->subject('本租户公司', true);
|
|
$foreign = $this->subject('其他租户公司', true, $this->company->id + 100);
|
|
|
|
$this->withExceptionHandling()->loginAs()->deleteJson($this->deleteUrl($foreign), ['delete_confirmed' => true])
|
|
->assertNotFound();
|
|
$this->assertFalse($foreign->fresh()->trashed());
|
|
|
|
$this->user->roles()->detach();
|
|
$this->user->unsetRelation('roles');
|
|
$this->deleteJson($this->deleteUrl($subject), ['delete_confirmed' => true])->assertForbidden();
|
|
$this->assertFalse($subject->fresh()->trashed());
|
|
}
|
|
|
|
private function subject(string $name, bool $default = false, ?int $companyId = null): CourierSigningSubject
|
|
{
|
|
return CourierSigningSubject::create([
|
|
'company_id' => $companyId ?? $this->company->id,
|
|
'name' => $name,
|
|
'is_default' => $default,
|
|
'created_by' => $this->user->id,
|
|
'updated_by' => $this->user->id,
|
|
]);
|
|
}
|
|
|
|
private function deleteUrl(CourierSigningSubject $subject): string
|
|
{
|
|
return route('business.courier-agreement-signatures.subjects.destroy', $subject);
|
|
}
|
|
}
|