diff --git a/app/Http/Controllers/Business/CourierAgreementSignatures.php b/app/Http/Controllers/Business/CourierAgreementSignatures.php index 6b994ce1..d4abc707 100644 --- a/app/Http/Controllers/Business/CourierAgreementSignatures.php +++ b/app/Http/Controllers/Business/CourierAgreementSignatures.php @@ -121,16 +121,11 @@ class CourierAgreementSignatures extends Controller ? '请填写原公司法人的 E 签宝实名认证姓名。' : '请填写变更前主体签署人的 E 签宝实名认证姓名。']); } - if ($formerCompanyDeregistered) { - $data['secondary_esign_account'] = null; - $data['secondary_operator_name'] = null; - } else { - if (blank($data['secondary_esign_account'] ?? null)) { - throw ValidationException::withMessages(['secondary_esign_account' => '普通主体变更需要填写变更后主体的 E 签宝账号。']); - } - if (blank($data['secondary_operator_name'] ?? null)) { - throw ValidationException::withMessages(['secondary_operator_name' => '请填写变更后主体签署人的 E 签宝实名认证姓名。']); - } + if (blank($data['secondary_esign_account'] ?? null)) { + throw ValidationException::withMessages(['secondary_esign_account' => '请填写变更后主体的 E 签宝账号。']); + } + if (blank($data['secondary_operator_name'] ?? null)) { + throw ValidationException::withMessages(['secondary_operator_name' => '请填写变更后主体签署人的 E 签宝实名认证姓名。']); } } if ($type === 'cooperation-contract') { diff --git a/app/Support/CourierAgreementSignatureService.php b/app/Support/CourierAgreementSignatureService.php index 0f30160f..d6bb27e8 100644 --- a/app/Support/CourierAgreementSignatureService.php +++ b/app/Support/CourierAgreementSignatureService.php @@ -342,22 +342,25 @@ final class CourierAgreementSignatureService $payload['entity_change_old_company_deregistered'] ?? false, FILTER_VALIDATE_BOOLEAN, ); - if ($formerCompanyDeregistered || ($payload['counterparty_signer_type'] ?? 'organization') === 'person') { - return [[ + if (blank($payload['secondary_esign_account'] ?? null) || blank($payload['secondary_operator_name'] ?? null)) { + throw new RuntimeException('请填写变更后主体的 E 签宝账号和实名认证姓名。'); + } + $formerSigner = $formerCompanyDeregistered || ($payload['counterparty_signer_type'] ?? 'organization') === 'person' + ? [ 'signer_type' => 0, 'organization_name' => null, 'operator_name' => $signature->operator_name, 'operator_account' => $signature->operator_account, - ]]; - } + ] + : array_merge($primary, ['organization_name' => $payload['former_company_name'] ?? $signature->organization_name]); return [ - array_merge($primary, ['organization_name' => $payload['former_company_name'] ?? $signature->organization_name]), + $formerSigner, [ 'signer_type' => 1, 'organization_name' => $payload['changed_company_name'] ?? $signature->organization_name, - 'operator_name' => $payload['secondary_operator_name'] ?? $signature->operator_name, - 'operator_account' => $payload['secondary_esign_account'] ?? $signature->operator_account, + 'operator_name' => $payload['secondary_operator_name'], + 'operator_account' => $payload['secondary_esign_account'], ], ]; } diff --git a/resources/views/business/pages/courier-payables/agreement-signing.blade.php b/resources/views/business/pages/courier-payables/agreement-signing.blade.php index e2336d00..97b0a171 100644 --- a/resources/views/business/pages/courier-payables/agreement-signing.blade.php +++ b/resources/views/business/pages/courier-payables/agreement-signing.blade.php @@ -1597,7 +1597,7 @@
特此证明!
变更前公司法人签字盖公章:
-变更后公司法人签字盖公章:
原公司法人个人签字:待填写
+变更后公司法人签字盖公章:待填写(签署人:待填写)
日期:{{ now()->format('Y年n月j日') }}
第 1 页 / 共 1 页
@@ -2811,7 +2811,7 @@ refreshSignerAccountLabels(templateType); var secondary = root.querySelector('[data-secondary-signer-fields]'); if (secondary) { - var needsSecondary = (entityChange && !formerCompanyDeregistered) || templateType === 'cooperation-contract' || templateType === 'authorization'; + var needsSecondary = entityChange || templateType === 'cooperation-contract' || templateType === 'authorization'; secondary.hidden = !needsSecondary; secondary.querySelectorAll('input').forEach(function (control) { control.disabled = !needsSecondary; @@ -2834,7 +2834,7 @@ } } if (secondaryOperatorField) { - var needsSecondaryOperator = (entityChange && !formerCompanyDeregistered) || cooperationContract || (authorization && !trusteeIsPerson); + var needsSecondaryOperator = entityChange || cooperationContract || (authorization && !trusteeIsPerson); secondaryOperatorField.hidden = !needsSecondaryOperator; secondaryOperatorInput.disabled = !needsSecondaryOperator; secondaryOperatorInput.required = needsSecondaryOperator; @@ -2842,7 +2842,7 @@ } setText('[data-template-name]', documentOption.dataset.name); setText('[data-template-code]', documentOption.dataset.code); - setText('[data-template-description]', formerCompanyDeregistered ? '旧公司作为历史主体保留,仅向原法人发送个人签署请求。' : otherSignerIsPerson ? '使用合作人的个人实名认证姓名和账号签署。' : documentOption.dataset.description); + setText('[data-template-description]', formerCompanyDeregistered ? '原法人以个人身份签字,变更后公司仍须法人签字并盖章;双方分别接收签署请求。' : otherSignerIsPerson ? '使用合作人的个人实名认证姓名和账号签署。' : documentOption.dataset.description); setText('[data-variable-template-name]', documentOption.dataset.name); setText('[data-preview-template-code]', documentOption.dataset.code); setPreviewValue('company', companyName); @@ -2875,6 +2875,7 @@ setPreviewValue('changedCompanyName', fieldValue('[name="changed_company_name"]', '待填写')); setPreviewValue('changedCompanyStartDate', formatDateField('[name="changed_company_start_date"]', '待填写')); setPreviewValue('formerLegalRepresentative', fieldValue('[name="operator_name"]', '待填写')); + setPreviewValue('changedLegalRepresentative', fieldValue('[name="secondary_operator_name"]', '待填写')); root.querySelectorAll('[data-entity-organization-signatures]').forEach(function (element) { element.hidden = formerCompanyDeregistered; }); diff --git a/resources/views/business/pdf/courier-agreement.blade.php b/resources/views/business/pdf/courier-agreement.blade.php index 58b6c6d5..2e454688 100644 --- a/resources/views/business/pdf/courier-agreement.blade.php +++ b/resources/views/business/pdf/courier-agreement.blade.php @@ -77,11 +77,15 @@ @endif变更后,原公司的各项事宜由变更后的公司继续执行。原公司的结算未付款项,由变更之后的公司提供的收款账户收款。原公司的业务和款项若出现法律上的纠纷,由变更后的公司承担责任。
特此证明!
- @if (filter_var($payload['entity_change_old_company_deregistered'] ?? false, FILTER_VALIDATE_BOOLEAN)) -原公司法人个人签字:{!! $mixedText($payload['former_legal_representative'] ?? '') !!}
日期:{!! $mixedText($signatureDate) !!}
变更前公司法人签字盖公章:{!! $mixedText($payload['former_company_name']) !!}(签署人:{!! $mixedText($payload['former_legal_representative'] ?? '') !!})
变更后公司法人签字盖公章:{!! $mixedText($payload['changed_company_name']) !!}(签署人:{!! $mixedText($payload['secondary_operator_name'] ?? '') !!})
日期:{!! $mixedText($signatureDate) !!}
原公司法人个人签字:{!! $mixedText($payload['former_legal_representative'] ?? '') !!}
+ @else +变更前公司法人签字盖公章:{!! $mixedText($payload['former_company_name']) !!}(签署人:{!! $mixedText($payload['former_legal_representative'] ?? '') !!})
+ @endif +变更后公司法人签字盖公章:{!! $mixedText($payload['changed_company_name']) !!}(签署人:{!! $mixedText($payload['secondary_operator_name'] ?? '') !!})
+日期:{!! $mixedText($signatureDate) !!}
+与 {!! $mixedText($payload['company_full_name'] ?? $signature->company_full_name) !!} 合作的 {!! $mixedText($sharedCourierText) !!},均归属于 {!! $mixedText($payload['contract_partner_name'] ?? '') !!},共用一份合同及同一份打款资料,合同签署及结算主体均为 {!! $mixedText($payload['contract_partner_name'] ?? '') !!}。
特此证明!
diff --git a/tests/Feature/Business/AgreementSigningPageTest.php b/tests/Feature/Business/AgreementSigningPageTest.php index dd5b9705..10bb44b0 100644 --- a/tests/Feature/Business/AgreementSigningPageTest.php +++ b/tests/Feature/Business/AgreementSigningPageTest.php @@ -345,7 +345,9 @@ class AgreementSigningPageTest extends FeatureTestCase ->assertSeeText('变更前公司名称') ->assertSeeText('变更后公司名称') ->assertSeeText('变更前公司已注销,使用原法人个人签署') + ->assertSeeText('原法人以个人身份签字,变更后公司仍须法人签字并盖章。') ->assertSeeText('变更后主体 E 签宝实名认证姓名') + ->assertSee('data-preview-bind="changedLegalRepresentative"', false) ->assertSeeText('原公司法人个人签字') ->assertSeeText('受托方签署类型') ->assertSeeText('个人签署') diff --git a/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php b/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php index 60519812..49474608 100644 --- a/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php +++ b/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php @@ -224,7 +224,7 @@ class CourierAgreementSignatureWorkflowTest extends FeatureTestCase }); } - public function test_entity_change_can_use_the_former_legal_representative_as_a_person_after_deregistration(): void + public function test_deregistered_entity_change_sends_the_former_person_and_current_enterprise(): void { $this->fakeEsign(); @@ -238,34 +238,91 @@ class CourierAgreementSignatureWorkflowTest extends FeatureTestCase 'signing_deadline' => now()->addDays(7)->toDateString(), 'esign_account' => '13800138000', 'operator_name' => '原法人', + 'secondary_esign_account' => '13900139000', + 'secondary_operator_name' => '新法人', + 'archive_mode' => 'auto', + 'entity_change_old_company_deregistered' => '1', + 'former_company_name' => '已注销原公司有限公司', + 'entity_change_date' => '2026-10-01', + 'changed_company_name' => '新公司有限公司', + 'changed_company_start_date' => '2026-10-10', + ]; + + $this->loginAs()->post(route('business.courier-agreement-signatures.store'), $payload)->assertRedirect(); + + $signature = CourierAgreementSignature::query()->firstOrFail(); + $this->assertTrue($signature->payload['entity_change_old_company_deregistered']); + $this->assertSame('原法人', $signature->payload['former_legal_representative']); + $this->assertSame('13900139000', $signature->payload['secondary_esign_account']); + $this->assertSame('新法人', $signature->payload['secondary_operator_name']); + $html = view('business.pdf.courier-agreement', [ + 'signature' => $signature, + 'type' => $signature->document_type, + 'title' => $signature->documentLabel(), + 'payload' => $signature->payload, + 'signatureDate' => '2026年10月10日', + 'fontPath' => str_replace('\\', '/', resource_path('fonts/DroidSansFallback.ttf')), + ])->render(); + $this->assertStringContainsString('原公司法人个人签字:原法人', strip_tags($html)); + $this->assertStringContainsString('变更后公司法人签字盖公章:新公司有限公司(签署人:新法人)', strip_tags($html)); + $this->assertStringNotContainsString('变更前公司法人签字盖公章', $html); + + Http::assertSent(function (ClientRequest $request): bool { + if ($request->url() !== 'https://smlopenapi.esign.test/v3/sign-flow/create-by-file') { + return false; + } + + $signers = $request->data()['signers'] ?? []; + + return count($signers) === 2 + && data_get($signers, '0.signerType') === 0 + && data_get($signers, '0.psnSignerInfo.psnAccount') === '13800138000' + && data_get($signers, '0.psnSignerInfo.psnInfo.psnName') === '原法人' + && data_get($signers, '0.orgSignerInfo') === null + && data_get($signers, '1.signerType') === 1 + && data_get($signers, '1.orgSignerInfo.orgName') === '新公司有限公司' + && data_get($signers, '1.orgSignerInfo.transactorInfo.psnAccount') === '13900139000' + && data_get($signers, '1.orgSignerInfo.transactorInfo.psnInfo.psnName') === '新法人'; + }); + } + + public function test_deregistered_entity_change_rejects_missing_current_signer_before_creating_a_task(): void + { + Http::fake(); + $payload = [ + 'idempotency_key' => 'entity-change-missing-current-signer', + 'courier_name' => '新北中通', + 'document_type' => 'entity-change', + 'signing_subject' => $this->company->name, + 'company_full_name' => $this->company->name, + 'signature_date' => '2026-10-10', + 'signing_deadline' => now()->addDays(7)->toDateString(), + 'esign_account' => '13800138000', + 'operator_name' => '原法人', 'archive_mode' => 'auto', 'entity_change_old_company_deregistered' => '1', 'former_company_name' => '已注销原公司有限公司', 'entity_change_date' => '2026-10-01', 'changed_company_name' => '新公司有限公司', 'changed_company_start_date' => '2026-10-10', + 'secondary_esign_account' => '13900139000', + 'secondary_operator_name' => '新法人', ]; - $this->loginAs()->post(route('business.courier-agreement-signatures.store'), $payload)->assertRedirect(); - - $signature = CourierAgreementSignature::query()->firstOrFail(); - $this->assertTrue($signature->payload['entity_change_old_company_deregistered']); - $this->assertSame('原法人', $signature->payload['former_legal_representative']); - $this->assertNull($signature->payload['secondary_esign_account'] ?? null); - - Http::assertSent(function (ClientRequest $request): bool { - if ($request->url() !== 'https://smlopenapi.esign.test/v3/sign-flow/create-by-file') { - return false; - } - - $signers = $request->data()['signers'] ?? []; - - return count($signers) === 1 - && data_get($signers, '0.signerType') === 0 - && data_get($signers, '0.psnSignerInfo.psnAccount') === '13800138000' - && data_get($signers, '0.psnSignerInfo.psnInfo.psnName') === '原法人' - && data_get($signers, '0.orgSignerInfo') === null; - }); + $this->withExceptionHandling()->loginAs(); + foreach (['secondary_esign_account', 'secondary_operator_name'] as $field) { + $missing = $payload; + unset($missing[$field]); + $this->postJson(route('business.courier-agreement-signatures.store'), $missing) + ->assertStatus(422) + ->assertJsonValidationErrors($field); + } + $payload['secondary_esign_account'] = 'not-an-account'; + $this->postJson(route('business.courier-agreement-signatures.store'), $payload) + ->assertStatus(422) + ->assertJsonValidationErrors('secondary_esign_account'); + $this->assertDatabaseCount('business_courier_agreement_signatures', 0); + Http::assertNothingSent(); } public function test_cooperation_contract_maps_party_variables_and_creates_two_signers(): void