From 368c6c5a6cdb38b006fc33332b4cabc415ddeea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=8F=E6=9C=A8?= <594326199@qq.com> Date: Sat, 17 Oct 2026 09:16:15 +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=8D=95=E4=BB=B7/=E9=87=91=E9=A2=9D=E7=95=99?= =?UTF-8?q?=E7=A9=BA=E8=87=AA=E5=8A=A8=E8=A1=A5=E9=BD=90=EF=BC=8C=E6=9C=AA?= =?UTF-8?q?=E5=AE=9A=E4=BB=B7=E8=A1=8C=E5=8E=82=E5=AE=B6=E4=B9=9F=E8=83=BD?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实测雪翔家居 9 月对账单:表头已改对(10 列与模板一致),但第 11 行是未定价行(数量 52、单价为空、金额 0),按「单价必填」会被拒绝。现在单价留空按「金额÷数量」补齐、金额留空按「数量×单价」补齐、两者都空按 0(数量仍必填),厂家直接导出即可上传。 --- .../Services/SupplierStatementTemplate.php | 26 +++++++++++++++++-- .../supplier-data.blade.php | 3 ++- .../Business/SupplierReconciliationTest.php | 18 +++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/modules/EcommerceFinance/Services/SupplierStatementTemplate.php b/modules/EcommerceFinance/Services/SupplierStatementTemplate.php index 2923e6c6..946d4338 100644 --- a/modules/EcommerceFinance/Services/SupplierStatementTemplate.php +++ b/modules/EcommerceFinance/Services/SupplierStatementTemplate.php @@ -28,8 +28,8 @@ class SupplierStatementTemplate private const MAX_ROWS = 200000; - /** 允许留空的列。 */ - private const OPTIONAL_COLUMNS = ['expressName', 'expressNo', 'purchaseNo']; + /** 允许留空的列:快递信息可缺;单价/金额留空时按「金额÷数量」或「数量×单价」补齐,都空按 0。 */ + private const OPTIONAL_COLUMNS = ['expressName', 'expressNo', 'purchaseNo', 'unitPrice', 'amount']; /** 必须是数字的列。 */ private const NUMERIC_COLUMNS = ['qty', 'unitPrice', 'amount']; @@ -96,6 +96,8 @@ class SupplierStatementTemplate } } + $values = $this->completeAmounts($values); + if ($expectedSupplier !== null && $values['supplier'] !== $expectedSupplier) { throw ValidationException::withMessages([ 'import' => "第 {$rowNumber} 行:供应商必须填写「{$expectedSupplier}」,不能提交其他厂家的数据。", @@ -194,4 +196,24 @@ class SupplierStatementTemplate return mb_strtolower($label); } + + /** 单价/金额留空时互相补算;两者都空按 0(未定价行厂家直接导出时会出现)。 */ + private function completeAmounts(array $values): array + { + $qty = (float) ($values['qty'] ?? 0); + $unitPrice = $values['unitPrice'] === null ? null : (float) $values['unitPrice']; + $amount = $values['amount'] === null ? null : (float) $values['amount']; + + if ($unitPrice === null && $amount !== null && $qty != 0.0) { + $values['unitPrice'] = (string) round($amount / $qty, 4); + } elseif ($unitPrice === null) { + $values['unitPrice'] = '0'; + } + + if ($amount === null) { + $values['amount'] = (string) round($qty * (float) $values['unitPrice'], 2); + } + + return $values; + } } 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 52a5c2a9..b3c92384 100644 --- a/resources/views/business/pages/supplier-reconciliation/supplier-data.blade.php +++ b/resources/views/business/pages/supplier-reconciliation/supplier-data.blade.php @@ -41,7 +41,8 @@ 下载对账单模板

- 厂家只能按模板上传(表头列名与顺序必须与模板完全一致):快递名称、快递单号、单据编号(采购单号)可以留空,其余列必填; + 厂家只能按模板上传(表头列名与顺序必须与模板完全一致):快递名称、快递单号、单据编号(采购单号)可以留空; + 单价或金额留空时按数量自动补齐(都留空按 0,未定价行可直接导出上传);其余列必填; 不符合模板或数值格式的整份失败并提示具体行号。厂家上传成功后,下面的数据与「财务端数据」的比对结果立即更新。

@if ($selectedSupplier !== '') diff --git a/tests/Feature/Business/SupplierReconciliationTest.php b/tests/Feature/Business/SupplierReconciliationTest.php index 3ecbc46c..29ff7370 100644 --- a/tests/Feature/Business/SupplierReconciliationTest.php +++ b/tests/Feature/Business/SupplierReconciliationTest.php @@ -240,6 +240,24 @@ class SupplierReconciliationTest extends FeatureTestCase } } + public function test_template_completes_missing_unit_price_or_amount(): void + { + $file = UploadedFile::fake()->createWithContent( + 'statement.csv', + "\xEF\xBB\xBF" . self::HEADER . "\n" + . ',,编号-1,2026-09-30,晨丰,ZSJ-1,规格甲,24,,2916' . "\n" // 单价空 → 2916/24 + . ',,编号-2,2026-09-30,晨丰,ZSJ-2,规格甲,3,10,' . "\n", // 金额空 → 3×10 + ); + + $records = app(SupplierStatementTemplate::class)->parse($file, '晨丰'); + + $this->assertCount(2, $records); + $this->assertSame('121.5', $records[0]['unitPrice']); + $this->assertSame('2916', $records[0]['amount']); + $this->assertSame('10', $records[1]['unitPrice']); + $this->assertSame('30', $records[1]['amount']); + } + private function statementRow(string $barcode, string $unitPrice, string $qty, string $amount): array { return [ -- 2.47.2