From c7bb212fb93d172aa4a4d2a38b1bc56d3dd94950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=8F=E6=9C=A8?= <594326199@qq.com> Date: Tue, 20 Oct 2026 10:34:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BE=9B=E5=BA=94=E5=95=86=E5=AF=B9=E8=B4=A6?= =?UTF-8?q?=EF=BC=9A=E5=86=85=E9=83=A8=E5=8F=AF=E6=90=9C=E7=B4=A2=E5=8E=82?= =?UTF-8?q?=E5=AE=B6=E5=B9=B6=E9=9A=94=E7=A6=BB=E5=8E=82=E5=AE=B6=E5=90=8D?= =?UTF-8?q?=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/SupplierReconciliationPageData.php | 8 ++- .../supplier-data.blade.php | 23 +++++-- .../Business/SupplierReconciliationTest.php | 62 +++++++++++++++++++ 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/modules/EcommerceFinance/View/SupplierReconciliationPageData.php b/modules/EcommerceFinance/View/SupplierReconciliationPageData.php index b1396544..066fd6b0 100644 --- a/modules/EcommerceFinance/View/SupplierReconciliationPageData.php +++ b/modules/EcommerceFinance/View/SupplierReconciliationPageData.php @@ -170,8 +170,10 @@ class SupplierReconciliationPageData $supplierNames = array_keys($suppliers); sort($supplierNames); - $selected = trim((string) request()->query('supplier', '')); - if ($selected === '' || ! in_array($selected, $supplierNames, true)) { + $supplierQuery = trim((string) request()->query('supplier', '')); + $selected = in_array($supplierQuery, $supplierNames, true) ? $supplierQuery : ''; + $supplierNotFound = $supplierQuery !== '' && $selected === ''; + if ($supplierQuery === '') { $selected = $supplierNames[0] ?? ''; } @@ -184,6 +186,8 @@ class SupplierReconciliationPageData return [ 'view' => 'business.pages.supplier-reconciliation.supplier-data', 'supplierNames' => $supplierNames, + 'supplierQuery' => $supplierQuery, + 'supplierNotFound' => $supplierNotFound, 'selectedSupplier' => $selected, 'uploads' => $selected !== '' ? $this->statements->uploads($selected, $companyId) : [], 'statementRows' => array_slice($statementRows, ($page - 1) * self::PER_PAGE, self::PER_PAGE), diff --git a/resources/views/business/pages/supplier-reconciliation/supplier-data.blade.php b/resources/views/business/pages/supplier-reconciliation/supplier-data.blade.php index 690cd2c3..a0593552 100644 --- a/resources/views/business/pages/supplier-reconciliation/supplier-data.blade.php +++ b/resources/views/business/pages/supplier-reconciliation/supplier-data.blade.php @@ -63,16 +63,29 @@

厂家对账单 · 上传与实时数据

-
- + 下载对账单模板
+ @if ($supplierNotFound) + + @endif

厂家只能按模板上传(表头列名与顺序必须与模板完全一致):快递名称、快递单号、单据编号(采购单号)可以留空; 单价或金额留空时按数量自动补齐(都留空按 0,未定价行可直接导出上传);其余列必填; diff --git a/tests/Feature/Business/SupplierReconciliationTest.php b/tests/Feature/Business/SupplierReconciliationTest.php index 1b34d507..aecb1b36 100644 --- a/tests/Feature/Business/SupplierReconciliationTest.php +++ b/tests/Feature/Business/SupplierReconciliationTest.php @@ -155,10 +155,48 @@ class SupplierReconciliationTest extends FeatureTestCase } } + public function test_supplier_page_uses_a_searchable_exact_supplier_picker(): void + { + $this->seedStatement('晨丰', [ + $this->statementRow('ZSJ-1', '128.00', '2', '256.00'), + ]); + $this->seedStatement('鸣飞家具', [ + array_merge($this->statementRow('SJ-1', '96.00', '1', '96.00'), ['supplier' => '鸣飞家具']), + ]); + + $pageUrl = route('business.pages.show', [ + 'company_id' => $this->company->id, + 'section' => 'supplier-reconciliation', + 'page' => 'supplier-data', + ]); + + $this->loginAs()->get($pageUrl) + ->assertOk() + ->assertSee('name="supplier"', false) + ->assertSee('list="supplier-name-options"', false) + ->assertSeeText('查询厂家') + ->assertSee('value="晨丰"', false) + ->assertSee('value="鸣飞家具"', false); + + $this->loginAs()->get($pageUrl . '?supplier=' . urlencode('鸣飞家具')) + ->assertOk() + ->assertSeeText('鸣飞家具 · 上传记录') + ->assertDontSeeText('晨丰 · 上传记录'); + + $this->loginAs()->get($pageUrl . '?supplier=' . urlencode('不存在的厂家')) + ->assertOk() + ->assertSeeText('未找到名为「不存在的厂家」的厂家') + ->assertDontSeeText('晨丰 · 上传记录') + ->assertDontSeeText('鸣飞家具 · 上传记录'); + } + public function test_vendor_portal_shows_only_all_returns_for_the_logged_in_supplier(): void { $store = app(SupplierPayableOverrideStore::class); $companyId = (int) $this->company->id; + $this->seedStatement('鸣飞家具', [ + array_merge($this->statementRow('OTHER-SUPPLIER', '100.00', '1', '100.00'), ['supplier' => '鸣飞家具']), + ]); for ($i = 1; $i <= 20; $i++) { $store->save('final:supplier:return-reconciliation', sprintf('portal:%02d', $i), [ 'summary_month' => '2026-09', @@ -198,6 +236,8 @@ class SupplierReconciliationTest extends FeatureTestCase ->assertSeeText('PORTAL-01') ->assertDontSeeText('PORTAL-20') ->assertDontSeeText('OTHER-SUPPLIER-RETURN') + ->assertDontSeeText('鸣飞家具') + ->assertDontSee('supplier-name-options', false) ->assertDontSeeText('预估单价'); $this->loginAs($vendor)->get($portalUrl . '?return_page=2') @@ -283,6 +323,28 @@ class SupplierReconciliationTest extends FeatureTestCase $this->assertCount(0, app(SupplierStatementStore::class)->rows('鸣飞家具', (int) $this->company->id)); } + public function test_vendor_portal_rejects_a_statement_for_another_supplier(): void + { + $this->withExceptionHandling(); + $vendor = $this->createVendorPortalUser('晨丰'); + $file = UploadedFile::fake()->createWithContent( + 'statement.csv', + "\xEF\xBB\xBF" . self::HEADER . "\n" + . ",,PORTAL-WRONG-SUPPLIER,2026-09-30,鸣飞家具,ZSJ-1,规格甲,2,128.00,256.00\n", + ); + + $this->loginAs($vendor) + ->post(route('portal.supplier-reconciliation.statement.upload', ['company_id' => $this->company->id]), [ + 'import' => $file, + ]) + ->assertSessionHasErrors([ + 'import' => '第 2 行:供应商必须填写「晨丰」,不能提交其他厂家的数据。', + ]); + + $this->assertCount(0, app(SupplierStatementStore::class)->rows('晨丰', (int) $this->company->id)); + $this->assertCount(0, app(SupplierStatementStore::class)->rows('鸣飞家具', (int) $this->company->id)); + } + public function test_return_bookkeeping_note_is_identical_on_finance_and_supplier_views(): void { $companyId = (int) $this->company->id; -- 2.47.2