From ad8da1264dfdc316f15077dc0e653d061d9a1fa7 Mon Sep 17 00:00:00 2001 From: renshen <1005457301@qq.com> Date: Tue, 20 Oct 2026 13:44:00 +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=E6=8C=89=E9=87=87=E8=B4=AD=E5=8D=95=E5=8F=B7=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E6=9D=A1=E7=A0=81=E6=A0=B8=E5=AF=B9=E6=95=B0=E9=87=8F?= =?UTF-8?q?=E9=87=91=E9=A2=9D=20(#405)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 厂家账单改为按采购单号+日期+条码匹配,逐项比较双方数量、单价和金额,页面与钉钉通知明确展示厂家多算或少算。 --- .../Business/SupplierReconciliation.php | 14 +- .../Services/SupplierDingTalkNotifier.php | 23 +- .../Services/SupplierStatementMatcher.php | 233 ++++++++++++++++-- .../View/SupplierReconciliationPageData.php | 2 +- .../finance-data.blade.php | 50 +++- .../supplier-data.blade.php | 2 +- .../supplier-reconciliation/index.blade.php | 3 +- .../SupplierReconciliationDingTalkTest.php | 24 +- .../Business/SupplierReconciliationTest.php | 108 ++++++-- 9 files changed, 384 insertions(+), 75 deletions(-) diff --git a/app/Http/Controllers/Business/SupplierReconciliation.php b/app/Http/Controllers/Business/SupplierReconciliation.php index fa53c93d..b5c41f38 100644 --- a/app/Http/Controllers/Business/SupplierReconciliation.php +++ b/app/Http/Controllers/Business/SupplierReconciliation.php @@ -131,9 +131,10 @@ class SupplierReconciliation extends Controller 'month' => ['nullable', 'string', 'regex:/^\d{4}-\d{2}$/'], 'reconciler' => ['nullable', 'string', 'max:191'], 'scope' => ['required', 'in:all,row,selected'], + 'purchase_no' => ['nullable', 'string', 'max:191'], + 'date' => ['nullable', 'string', 'max:32'], 'barcode' => ['nullable', 'string', 'max:191'], 'difference_type' => ['nullable', 'string', 'max:32'], - 'unit_price' => ['nullable', 'numeric'], 'selected_rows' => ['nullable', 'array', 'max:600'], 'selected_rows.*' => ['string', 'max:2048'], ]); @@ -145,14 +146,16 @@ class SupplierReconciliation extends Controller )); if ($request->input('scope') === 'row') { + $purchaseNo = trim((string) $request->input('purchase_no')); + $date = trim((string) $request->input('date')); $barcode = trim((string) $request->input('barcode')); $type = trim((string) $request->input('difference_type')); - $unitPrice = (float) $request->input('unit_price'); $differences = array_values(array_filter( $differences, - static fn (array $row): bool => (string) ($row['barcode'] ?? '') === $barcode + static fn (array $row): bool => (string) ($row['purchaseNo'] ?? '') === $purchaseNo + && (string) ($row['date'] ?? '') === $date + && (string) ($row['barcode'] ?? '') === $barcode && (string) ($row['type'] ?? '') === $type - && abs((float) ($row['unitPrice'] ?? 0) - $unitPrice) < 0.005, )); } elseif ($request->input('scope') === 'selected') { $selected = []; @@ -214,9 +217,10 @@ class SupplierReconciliation extends Controller private function differenceRowKey(array $row): string { return implode("\0", [ + trim((string) ($row['purchaseNo'] ?? $row['purchase_no'] ?? '')), + trim((string) ($row['date'] ?? '')), trim((string) ($row['barcode'] ?? '')), trim((string) ($row['type'] ?? '')), - number_format((float) ($row['unitPrice'] ?? 0), 4, '.', ''), ]); } diff --git a/modules/EcommerceFinance/Services/SupplierDingTalkNotifier.php b/modules/EcommerceFinance/Services/SupplierDingTalkNotifier.php index 92355058..2cdad982 100644 --- a/modules/EcommerceFinance/Services/SupplierDingTalkNotifier.php +++ b/modules/EcommerceFinance/Services/SupplierDingTalkNotifier.php @@ -165,7 +165,7 @@ class SupplierDingTalkNotifier '- 对账月份:' . ($month !== '' ? $month : '全部月份'), '- 对账人:' . ($reconciler !== '' ? $reconciler : '全部'), '- 差异共 **' . $summary['count'] . '** 条(厂家多 ' . $summary['extra'] - . ' / 金额数量不一致 ' . $summary['mismatch'] . ' / 厂家少 ' . $summary['missing'] . ')', + . ' / 数量金额不一致 ' . $summary['mismatch'] . ' / 厂家少 ' . $summary['missing'] . ')', '- 差异金额:**¥' . number_format($summary['difference_amount'], 2) . '**', ]; @@ -179,22 +179,29 @@ class SupplierDingTalkNotifier $theirsQty = (float) ($row['theirsQty'] ?? 0); $mineAmount = (float) ($row['mineAmount'] ?? 0); $theirsAmount = (float) ($row['theirsAmount'] ?? 0); + $mineUnitPrice = (float) ($row['mineUnitPrice'] ?? $row['unitPrice'] ?? 0); + $theirsUnitPrice = (float) ($row['theirsUnitPrice'] ?? $row['unitPrice'] ?? 0); + $purchaseNo = trim((string) ($row['purchaseNo'] ?? '')); + $date = trim((string) ($row['date'] ?? '')); $barcode = trim((string) ($row['barcode'] ?? '')); $supplierBarcode = trim((string) ($row['supplierBarcode'] ?? '')); $lines[] = sprintf( - '%d. **%s** `%s`%s 单价 ¥%s|我方 %s / ¥%s|厂家 %s / ¥%s|%s', + '%d. **%s**|采购单号:%s|日期:%s|条码:%s%s', $rowOffset + $index + 1, (string) ($row['type'] ?? '差异'), + $purchaseNo !== '' ? $purchaseNo : '—', + $date !== '' ? $date : '—', $barcode, $supplierBarcode !== '' ? '(厂家条码 ' . $supplierBarcode . ')' : '', - number_format((float) ($row['unitPrice'] ?? 0), 2), - $this->number($mineQty), - number_format($mineAmount, 2), - $this->number($theirsQty), - number_format($theirsAmount, 2), - (string) ($row['note'] ?? ''), ); + $lines[] = ' 我方:数量 ' . $this->number($mineQty) + . '|单价 ¥' . number_format($mineUnitPrice, 2) + . '|金额 ¥' . number_format($mineAmount, 2); + $lines[] = ' 厂家:数量 ' . $this->number($theirsQty) + . '|单价 ¥' . number_format($theirsUnitPrice, 2) + . '|金额 ¥' . number_format($theirsAmount, 2); + $lines[] = ' 处理:' . (string) ($row['note'] ?? ''); } $lines[] = ''; diff --git a/modules/EcommerceFinance/Services/SupplierStatementMatcher.php b/modules/EcommerceFinance/Services/SupplierStatementMatcher.php index 2943be61..8bdb4652 100644 --- a/modules/EcommerceFinance/Services/SupplierStatementMatcher.php +++ b/modules/EcommerceFinance/Services/SupplierStatementMatcher.php @@ -4,9 +4,9 @@ namespace Modules\EcommerceFinance\Services; /** * 厂家对账单 vs 我方结算数据: - * - 行键 = 条码(去掉厂家编号/版本后缀,如 CJ019312N1097V01 → CJ019312)+ 单价 - * (同一把钥匙的多行先合并:数量、金额相加); - * - 四类结果:一致 / 厂家多(不结算、退回)/ 金额不一致(按金额低的一方结算)/ 厂家少(按厂家数据结算,即不付款)。 + * - 行键 = 采购单号 + 日期 + 条码(条码去掉厂家编号/版本后缀); + * - 同一行键的多行先合并数量与金额,再比较双方数量和金额; + * - 厂家未填采购单号时,仅在同日期+条码能唯一对应我方一条数据时兜底匹配。 */ class SupplierStatementMatcher { @@ -14,7 +14,7 @@ class SupplierStatementMatcher public const TYPE_SUPPLIER_EXTRA = '厂家多'; - public const TYPE_MISMATCH = '金额不一致'; + public const TYPE_MISMATCH = '数量/金额不一致'; public const TYPE_SUPPLIER_MISSING = '厂家少'; @@ -22,74 +22,129 @@ class SupplierStatementMatcher private const SUPPLIER_SUFFIX = '/[A-Z]{1,3}\d{3,6}V\d{1,3}$/i'; /** - * @param list> $mine 我方结算数据(货款对账:skuCode/unitPrice/qty/amount) - * @param list> $theirs 厂家对账单(barcode/unitPrice/qty/amount) + * @param list> $mine 我方数据(purchaseNo/date/skuCode/unitPrice/qty/amount) + * @param list> $theirs 厂家数据(purchaseNo/createdAt/barcode/unitPrice/qty/amount) * @return array{rows:list>,summary:array} */ public function compare(array $mine, array $theirs): array { - $mineGrouped = $this->group($mine, 'skuCode'); - $theirsGrouped = $this->group($theirs, 'barcode'); + $mineGrouped = $this->group($mine, 'skuCode', 'purchaseNo', 'date'); + $theirsGrouped = $this->group($theirs, 'barcode', 'purchaseNo', 'createdAt'); + + // 已有采购单号时严格按三元组匹配;缺失采购单号时,仅在日期+条码唯一时兜底。 + $fallbackIndex = []; + foreach ($mineGrouped as $key => $row) { + $fallbackIndex[$row['date'] . "\0" . $row['barcodeKey']][] = $key; + } + $theirsGrouped = $this->resolveMissingPurchaseNumbers($theirsGrouped, $fallbackIndex); $rows = []; - $summary = ['match' => 0, 'supplierExtra' => 0, 'mismatch' => 0, 'supplierMissing' => 0, - 'mineAmount' => 0.0, 'settleAmount' => 0.0]; + $summary = [ + 'match' => 0, + 'supplierExtra' => 0, + 'mismatch' => 0, + 'supplierMissing' => 0, + 'mineAmount' => 0.0, + 'theirsAmount' => 0.0, + 'supplierOverQty' => 0.0, + 'supplierOverAmount' => 0.0, + 'settleAmount' => 0.0, + ]; foreach (array_unique(array_merge(array_keys($mineGrouped), array_keys($theirsGrouped))) as $key) { $mineRow = $mineGrouped[$key] ?? null; $theirsRow = $theirsGrouped[$key] ?? null; - $barcode = (string) ($mineRow['barcode'] ?? $theirsRow['barcode']); - $supplierBarcode = (string) ($theirsRow['barcode'] ?? ''); - $unitPrice = (float) ($mineRow['unitPrice'] ?? $theirsRow['unitPrice']); + $purchaseNo = (string) ($mineRow['purchaseNo'] ?? $theirsRow['purchaseNo'] ?? ''); + $date = (string) ($mineRow['date'] ?? $theirsRow['date'] ?? ''); + $barcode = (string) ($mineRow['barcode'] ?? $theirsRow['barcode'] ?? ''); + $supplierBarcode = (string) ($theirsRow['supplierBarcode'] ?? ''); + $mineUnitPrice = (float) ($mineRow['unitPrice'] ?? 0); + $theirsUnitPrice = (float) ($theirsRow['unitPrice'] ?? 0); + $unitPrice = $mineUnitPrice > 0 ? $mineUnitPrice : $theirsUnitPrice; $mineQty = (float) ($mineRow['qty'] ?? 0); $mineAmount = (float) ($mineRow['amount'] ?? 0); $theirsQty = (float) ($theirsRow['qty'] ?? 0); $theirsAmount = (float) ($theirsRow['amount'] ?? 0); + $qtyDifference = $theirsQty - $mineQty; + $amountDifference = $theirsAmount - $mineAmount; + $quantityDifference = $this->describeDifference($qtyDifference, $amountDifference); + $fallbackNote = ''; + if (($theirsRow['matchedByFallback'] ?? false) === true) { + $fallbackNote = '厂家未填采购单号,已按日期+条码唯一匹配;'; + } elseif (($theirsRow['fallbackAmbiguous'] ?? false) === true) { + $fallbackNote = '厂家未填采购单号,且同日期+条码有多条我方数据,无法唯一匹配;'; + } if ($mineRow === null) { $type = self::TYPE_SUPPLIER_EXTRA; $settle = 0.0; - $note = '我方没有这条数据:不结算,退回厂家修改账单'; + $note = $fallbackNote . '厂家整条多报:' . $quantityDifference . ';我方没有该采购单号+日期+条码,不结算'; $summary['supplierExtra']++; } elseif ($theirsRow === null) { $type = self::TYPE_SUPPLIER_MISSING; $settle = 0.0; - $note = '厂家少报了这条数据:按厂家数据结算(不付款)'; + $note = '厂家漏报:我方数量 ' . $this->number($mineQty) + . ',单价 ¥' . number_format($mineUnitPrice, 2) + . ',金额 ¥' . number_format($mineAmount, 2) + . ';按厂家数据结算(不付款)'; $summary['supplierMissing']++; } elseif (abs($mineAmount - $theirsAmount) < 0.005 && abs($mineQty - $theirsQty) < 0.005) { $type = self::TYPE_MATCH; $settle = $mineAmount; - $note = '正常结算'; + $note = $fallbackNote . '采购单号、日期、条码、数量和金额一致,正常结算'; $summary['match']++; } else { $type = self::TYPE_MISMATCH; $settle = min($mineAmount, $theirsAmount); - $note = '金额/数量不一致:按金额低的一方结算'; + $note = $fallbackNote . $quantityDifference . ';按金额低的一方结算,请厂家修改'; $summary['mismatch']++; } $summary['mineAmount'] += $mineAmount; + $summary['theirsAmount'] += $theirsAmount; + $summary['supplierOverQty'] += max($qtyDifference, 0); + $summary['supplierOverAmount'] += max($amountDifference, 0); $summary['settleAmount'] += $settle; $rows[] = [ + 'purchaseNo' => $purchaseNo, + 'date' => $date, 'barcode' => $barcode, - 'supplierBarcode' => $supplierBarcode === $barcode ? '' : $supplierBarcode, + 'supplierBarcode' => $supplierBarcode !== '' && $supplierBarcode !== $barcode ? $supplierBarcode : '', 'unitPrice' => $unitPrice, + 'mineUnitPrice' => $mineUnitPrice, + 'theirsUnitPrice' => $theirsUnitPrice, 'mineQty' => $mineQty, 'mineAmount' => $mineAmount, 'theirsQty' => $theirsQty, 'theirsAmount' => $theirsAmount, + 'qtyDifference' => round($qtyDifference, 4), + 'amountDifference' => round($amountDifference, 2), + 'supplierOverQty' => round(max($qtyDifference, 0), 4), + 'supplierOverAmount' => round(max($amountDifference, 0), 2), 'type' => $type, 'settleAmount' => $settle, 'note' => $note, ]; } - usort($rows, static fn (array $a, array $b): int => [$a['type'] === self::TYPE_MATCH ? 1 : 0, $a['barcode']] - <=> [$b['type'] === self::TYPE_MATCH ? 1 : 0, $b['barcode']]); + usort($rows, static fn (array $a, array $b): int => [ + $a['type'] === self::TYPE_MATCH ? 1 : 0, + $a['date'], + $a['purchaseNo'], + $a['barcode'], + ] <=> [ + $b['type'] === self::TYPE_MATCH ? 1 : 0, + $b['date'], + $b['purchaseNo'], + $b['barcode'], + ]); $summary['mineAmount'] = round($summary['mineAmount'], 2); + $summary['theirsAmount'] = round($summary['theirsAmount'], 2); + $summary['supplierOverQty'] = round($summary['supplierOverQty'], 4); + $summary['supplierOverAmount'] = round($summary['supplierOverAmount'], 2); $summary['settleAmount'] = round($summary['settleAmount'], 2); $summary['differenceAmount'] = round($summary['mineAmount'] - $summary['settleAmount'], 2); @@ -97,12 +152,12 @@ class SupplierStatementMatcher } /** - * 按「条码 + 单价」归组,数量与金额相加。 + * 按「采购单号 + 日期 + 条码」归组,数量与金额相加。 * * @param list> $rows - * @return array + * @return array> */ - private function group(array $rows, string $barcodeField): array + private function group(array $rows, string $barcodeField, string $purchaseField, string $dateField): array { $grouped = []; foreach ($rows as $row) { @@ -111,22 +166,148 @@ class SupplierStatementMatcher continue; } + $barcodeKey = $this->normalizeBarcode($barcode); + $purchaseNo = $this->normalizePurchaseNo($row[$purchaseField] ?? ''); + $date = $this->normalizeDate($row[$dateField] ?? ''); $unitPrice = (float) ($row['unitPrice'] ?? 0); - $key = $this->normalizeBarcode($barcode) . '|' . number_format($unitPrice, 4, '.', ''); + $key = $this->matchKey($purchaseNo, $date, $barcodeKey); - $grouped[$key] ??= ['barcode' => $barcode, 'unitPrice' => $unitPrice, 'qty' => 0.0, 'amount' => 0.0]; + $grouped[$key] ??= [ + 'purchaseNo' => $purchaseNo, + 'date' => $date, + 'barcode' => $barcodeKey, + 'barcodeKey' => $barcodeKey, + 'supplierBarcode' => $barcodeField === 'barcode' ? $barcode : '', + 'unitPrice' => $unitPrice, + 'unitPrices' => [], + 'qty' => 0.0, + 'amount' => 0.0, + 'matchedByFallback' => false, + 'fallbackAmbiguous' => false, + ]; + if ($unitPrice > 0) { + $grouped[$key]['unitPrices'][number_format($unitPrice, 4, '.', '')] = true; + } $grouped[$key]['qty'] += (float) ($row['qty'] ?? 0); $grouped[$key]['amount'] += (float) ($row['amount'] ?? 0); } + foreach ($grouped as &$group) { + $group = $this->finalizeGroup($group); + } + unset($group); + return $grouped; } + /** + * @param array> $groups + * @param array> $fallbackIndex + * @return array> + */ + private function resolveMissingPurchaseNumbers(array $groups, array $fallbackIndex): array + { + $resolved = []; + foreach ($groups as $key => $group) { + $targetKey = $key; + if ($group['purchaseNo'] === '') { + $candidates = $fallbackIndex[$group['date'] . "\0" . $group['barcodeKey']] ?? []; + if (count($candidates) === 1) { + $targetKey = $candidates[0]; + $group['matchedByFallback'] = true; + } elseif (count($candidates) > 1) { + $group['fallbackAmbiguous'] = true; + } + } + + if (isset($resolved[$targetKey])) { + $resolved[$targetKey] = $this->mergeGroup($resolved[$targetKey], $group); + } else { + $resolved[$targetKey] = $group; + } + } + + return $resolved; + } + + /** @param array $left @param array $right */ + private function mergeGroup(array $left, array $right): array + { + $left['qty'] += (float) $right['qty']; + $left['amount'] += (float) $right['amount']; + $left['unitPrices'] += (array) $right['unitPrices']; + $left['matchedByFallback'] = (bool) $left['matchedByFallback'] || (bool) $right['matchedByFallback']; + $left['fallbackAmbiguous'] = (bool) $left['fallbackAmbiguous'] || (bool) $right['fallbackAmbiguous']; + if ($left['supplierBarcode'] === '' && $right['supplierBarcode'] !== '') { + $left['supplierBarcode'] = $right['supplierBarcode']; + } + + return $this->finalizeGroup($left); + } + + /** @param array $group @return array */ + private function finalizeGroup(array $group): array + { + $prices = array_keys((array) ($group['unitPrices'] ?? [])); + if (count($prices) === 1) { + $group['unitPrice'] = (float) $prices[0]; + } elseif ((float) $group['qty'] != 0.0) { + $group['unitPrice'] = round((float) $group['amount'] / (float) $group['qty'], 4); + } + + return $group; + } + + private function matchKey(string $purchaseNo, string $date, string $barcode): string + { + return $purchaseNo . "\0" . $date . "\0" . $barcode; + } + + private function normalizePurchaseNo(mixed $value): string + { + $purchaseNo = ltrim(trim((string) $value), "'"); + + return preg_match('/^(\d+)\.0+$/', $purchaseNo, $matches) === 1 ? $matches[1] : $purchaseNo; + } + + private function normalizeDate(mixed $value): string + { + $raw = trim((string) $value); + if (preg_match('/^(\d{4})[-\/.](\d{1,2})[-\/.](\d{1,2})/', $raw, $matches) === 1) { + $year = (int) $matches[1]; + $month = (int) $matches[2]; + $day = (int) $matches[3]; + if (checkdate($month, $day, $year)) { + return sprintf('%04d-%02d-%02d', $year, $month, $day); + } + } + + return $raw; + } + + private function describeDifference(float $qtyDifference, float $amountDifference): string + { + $parts = []; + if (abs($qtyDifference) >= 0.005) { + $parts[] = '厂家数量' . ($qtyDifference > 0 ? '多 ' : '少 ') . $this->number(abs($qtyDifference)); + } + if (abs($amountDifference) >= 0.005) { + $parts[] = '厂家金额' . ($amountDifference > 0 ? '多 ¥' : '少 ¥') . number_format(abs($amountDifference), 2); + } + + return $parts === [] ? '数量、金额一致' : implode(',', $parts); + } + + private function number(float $value): string + { + return rtrim(rtrim(number_format($value, 2, '.', ''), '0'), '.'); + } + /** 去掉条码末尾的「厂家编号 + 版本」后缀,双方口径统一后再匹配。 */ private function normalizeBarcode(string $barcode): string { $normalized = preg_replace(self::SUPPLIER_SUFFIX, '', $barcode); - return $normalized === null || $normalized === '' ? $barcode : $normalized; + return strtoupper($normalized === null || $normalized === '' ? $barcode : $normalized); } } diff --git a/modules/EcommerceFinance/View/SupplierReconciliationPageData.php b/modules/EcommerceFinance/View/SupplierReconciliationPageData.php index 1c28d216..bf55d097 100644 --- a/modules/EcommerceFinance/View/SupplierReconciliationPageData.php +++ b/modules/EcommerceFinance/View/SupplierReconciliationPageData.php @@ -12,7 +12,7 @@ use Modules\EcommerceFinance\Services\SupplierStatementStore; /** * 「供应商对账」页面数据: - * - 财务端数据:按供应商汇总 + 行级差异(条码 + 单价 匹配,四类结果带结算口径) + * - 财务端数据:按供应商汇总 + 行级差异(采购单号 + 日期 + 条码匹配,四类结果带结算口径) * - 厂家端数据:厂家上传的对账单(实时)与只读的退货明细 */ class SupplierReconciliationPageData diff --git a/resources/views/business/pages/supplier-reconciliation/finance-data.blade.php b/resources/views/business/pages/supplier-reconciliation/finance-data.blade.php index 0a24a693..cfbf4cfc 100644 --- a/resources/views/business/pages/supplier-reconciliation/finance-data.blade.php +++ b/resources/views/business/pages/supplier-reconciliation/finance-data.blade.php @@ -98,9 +98,10 @@ @endcanany

- 比对口径:按「条码 + 单价」逐行核对(同一把钥匙的多行先合并数量与金额)。一致 → 正常结算; - 厂家多(我方没有)→ 不结算、退回厂家修改账单;金额/数量不一致 → 取金额低的一方结算; - 厂家少(我方有)→ 按厂家数据结算(不付款)。厂家上传的对账单在「厂家端数据」实时可查。
+ 比对口径:按「采购单号 + 日期 + 条码」核对,同一采购单号、日期和条码的多行先合并数量与金额。 + 数量、金额一致 → 正常结算;厂家多(我方没有)→ 不结算、退回修改; + 数量或金额不一致 → 明确列出双方数量、单价、金额及厂家多算部分,取金额低的一方结算; + 厂家少(我方有)→ 按厂家数据结算(不付款)。厂家未填采购单号时,仅在同日期+条码能唯一匹配我方一条数据时兜底。
厂家登录:在「厂家登录账号管理」新增供应商并勾选可登录,供应商名称必须与对账数据中的厂家名称完全一致; 厂家登录后只能查看自己的对账单上传记录、全部退货明细及导出数据。

@@ -242,9 +243,11 @@
双方一致{{ $detail['summary']['match'] }}
厂家多(退回修改){{ $detail['summary']['supplierExtra'] }}
-
金额不一致(按低结算){{ $detail['summary']['mismatch'] }}
+
数量/金额不一致(按低结算){{ $detail['summary']['mismatch'] }}
厂家少(按厂家结算){{ $detail['summary']['supplierMissing'] }}
我方金额合计{{ number_format($detail['summary']['mineAmount'], 2) }}
+
厂家金额合计{{ number_format($detail['summary']['theirsAmount'], 2) }}
+
厂家多算金额{{ number_format($detail['summary']['supplierOverAmount'], 2) }}
按口径结算合计{{ number_format($detail['summary']['settleAmount'], 2) }}
差异金额{{ number_format($detail['summary']['differenceAmount'], 2) }}
@@ -256,12 +259,17 @@ 比对结果 + 采购单号 + 日期 条码 - 单价 我方数量 - 厂家数量 + 我方单价 我方金额 + 厂家数量 + 厂家单价 厂家金额 + 数量差异(厂家-我方) + 金额差异(厂家-我方) 结算口径 结算金额 推送 @@ -272,7 +280,7 @@ @php $tagClass = match ($row['type']) { '厂家多' => 'is-extra', - '金额不一致' => 'is-mismatch', + '数量/金额不一致' => 'is-mismatch', '厂家少' => 'is-missing', default => 'is-match', }; @@ -284,24 +292,41 @@ form="push-selected-form" type="checkbox" name="selected_rows[]" - value="{{ json_encode(['barcode' => $row['barcode'], 'type' => $row['type'], 'unitPrice' => $row['unitPrice']], JSON_UNESCAPED_UNICODE) }}" + value="{{ json_encode(['purchaseNo' => $row['purchaseNo'], 'date' => $row['date'], 'barcode' => $row['barcode'], 'type' => $row['type']], JSON_UNESCAPED_UNICODE) }}" aria-label="选择差异 {{ $row['barcode'] }}"> @else — @endif {{ $row['type'] }} + {{ $row['purchaseNo'] !== '' ? $row['purchaseNo'] : '—' }} + {{ $row['date'] !== '' ? $row['date'] : '—' }} {{ $row['barcode'] }} @if (! empty($row['supplierBarcode'])) (厂家:{{ $row['supplierBarcode'] }}) @endif - {{ number_format($row['unitPrice'], 2) }} {{ $row['mineQty'] !== 0.0 ? number_format($row['mineQty'], 2) : '—' }} - {{ $row['theirsQty'] !== 0.0 ? number_format($row['theirsQty'], 2) : '—' }} + {{ $row['mineUnitPrice'] !== 0.0 ? number_format($row['mineUnitPrice'], 2) : '—' }} {{ $row['mineAmount'] !== 0.0 ? number_format($row['mineAmount'], 2) : '—' }} + {{ $row['theirsQty'] !== 0.0 ? number_format($row['theirsQty'], 2) : '—' }} + {{ $row['theirsUnitPrice'] !== 0.0 ? number_format($row['theirsUnitPrice'], 2) : '—' }} {{ $row['theirsAmount'] !== 0.0 ? number_format($row['theirsAmount'], 2) : '—' }} + + @if (abs($row['qtyDifference']) < 0.005) + 一致 + @else + 厂家{{ $row['qtyDifference'] > 0 ? '多' : '少' }} {{ number_format(abs($row['qtyDifference']), 2) }} + @endif + + + @if (abs($row['amountDifference']) < 0.005) + 一致 + @else + 厂家{{ $row['amountDifference'] > 0 ? '多' : '少' }} ¥{{ number_format(abs($row['amountDifference']), 2) }} + @endif + {{ $row['note'] }} {{ number_format($row['settleAmount'], 2) }} @@ -314,9 +339,10 @@ + + -