diff --git a/app/Console/Commands/SyncStoreReceiptOrderMatches.php b/app/Console/Commands/SyncStoreReceiptOrderMatches.php index 004f775f..e5164a41 100644 --- a/app/Console/Commands/SyncStoreReceiptOrderMatches.php +++ b/app/Console/Commands/SyncStoreReceiptOrderMatches.php @@ -162,6 +162,17 @@ class SyncStoreReceiptOrderMatches extends Command /** 优惠/冲减账单所在的订单没有收款行时,补行用这个标注。 */ private const REMARK_PROMO_ONLY = '无收款账单'; + /** + * 1688 采销专用账户(按账单店铺名识别): + * 这个账户收的是采销/供货结算款,不是店铺销售单收款,订单侧本来就没有对应的销售单, + * 所以未匹配原因单独成档,避免和真实丢单混在「订单表无此单」里。 + */ + private const CAIXIAO_STORE_KEYWORD = '采销专用'; + + private const REMARK_EMPTY_NO_CAIXIAO = '账单无单号(采销收款)'; + + private const REMARK_NO_ORDER_CAIXIAO = '1688采销收款(非销售单)'; + public function handle(): int { // 全量重建时账单与订单侧映射都在内存里:拼多多 / 淘系支付宝这类大平台需要 1G 以上, @@ -691,6 +702,8 @@ class SyncStoreReceiptOrderMatches extends Command $status = $basis === 'product' ? $productStatus : $paidStatus; $remark = $basis === 'product' ? $productRemark : $paidRemark; + // 1688 采销专用账户的未匹配原因单独成档(采销收款不是店铺销售单)。 + $remark = self::caixiaoRemark((string) $group['store_name'], $remark); $basisAmount = $basis === 'product' ? $productAmount : $paidAmount; if ($status === self::STATUS_MATCHED && (int) $group['payment_count'] > 1 && $remark === '') { @@ -1081,7 +1094,9 @@ class SyncStoreReceiptOrderMatches extends Command 'paid_amount' => null, 'difference' => null, 'match_status' => self::STATUS_UNMATCHED, - 'remark' => $core === '' ? self::REMARK_EMPTY_NO : self::REMARK_PROMO_ONLY, + 'remark' => $core === '' + ? self::caixiaoRemark((string) $group['store_name'], self::REMARK_EMPTY_NO) + : self::REMARK_PROMO_ONLY, 'imported_at' => $now, ]; } @@ -1197,6 +1212,30 @@ class SyncStoreReceiptOrderMatches extends Command return strtoupper($value); } + /** + * 是否 1688 采销专用账户(按账单店铺名判断)。 + */ + private static function isCaixiaoStore(string $storeName): bool + { + return str_contains(trim($storeName), self::CAIXIAO_STORE_KEYWORD); + } + + /** + * 1688 采销专用账户的未匹配原因单独成档;其余店铺的标注原样返回。 + */ + private static function caixiaoRemark(string $storeName, string $remark): string + { + if (! self::isCaixiaoStore($storeName)) { + return $remark; + } + + return match ($remark) { + self::REMARK_EMPTY_NO => self::REMARK_EMPTY_NO_CAIXIAO, + self::REMARK_NO_ORDER => self::REMARK_NO_ORDER_CAIXIAO, + default => $remark, + }; + } + /** * 账单行上的业务备注:科目映射表的「业务备注关键词」用它匹配。 * diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index 0d10616a..8d3a7592 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -137,7 +137,15 @@ class Pages extends Controller { $basis = self::differenceBasis(); - return ['账单无单号', '单号格式异常', '订单表无此单', $basis['no_amount_remark'], '无收款账单']; + return [ + '账单无单号', + '账单无单号(采销收款)', + '单号格式异常', + '订单表无此单', + '1688采销收款(非销售单)', + $basis['no_amount_remark'], + '无收款账单', + ]; } /** diff --git a/config/business_navigation.php b/config/business_navigation.php index 3bf05e0e..c1bdf4d0 100644 --- a/config/business_navigation.php +++ b/config/business_navigation.php @@ -806,7 +806,7 @@ $navigation = [ 'directory' => [ 'icon' => 'receipt_long', 'status' => '共享镜像', - 'description' => '覆盖店铺收款账户账单各平台页签(总账备注=订单收入),按「店铺 + 订单号」匹配订单侧商品金额与订单实付金额;一行 = 一个店铺的一个订单,商品金额只挂一次。「商品金额」只取主单(拆单子单不参与,整单没有主单时退化为取全部行),并排除虚拟条码(X0000x:信誉订单 / 虚拟订单)明细行;「订单实付金额」取订单级实付(拆单取主单)再减去虚拟条码行实付。「优惠金额」「冲减金额」另取总账备注=优惠收入 / 冲减收入的账单金额,不计入收入金额;「退款金额」另取总账备注=退款的账单金额,只单独列示,不计入收入金额、也不参与差额;「种菜金额」是订单号在种菜明细表或聚水潭订单标签明细(是否种菜订单=是)任意一边出现过时,该订单的收入金额(两个条件是或的关系),只是收入金额里的一部分,不参与差额;差额=(收入金额+优惠金额+冲减金额)−订单实付金额,匹配状态与差额异常备注同样按订单实付金额判定,未匹配到订单实付金额的行按订单实付金额=0 计入差额,只反映真正对不上的部分。挂不到订单行的优惠/冲减会补成一行(收入/商品留空)。「差额异常备注」只说明差额为什么产生,按顺序自动判定:订单实付未匹配(未匹配到订单实付金额,具体原因看「未匹配原因」列);订单实付取数为0(种菜)(订单实付=0 且是种菜单)、订单实付取数为0(订单实付=0 但不是种菜单)、订单实付未减冲减(订单实付=收入+优惠 → 差额=冲减金额)、订单实付未减优惠(订单实付=收入+冲减 → 差额=优惠金额)、订单实付未减优惠和冲减(订单实付=收入 → 差额=优惠+冲减)、订单实付含已退款部分(仅抖音负差额:聚水潭退款单/取消子单金额≈差额,或退款合计+账单退款净额≈实付−收入,或整单全退(退款合计≈实付)对上才标注)、订单实付未减联合营销费(仅得物负差额:联合营销费未让利尾数对上才标注)、订单实付取供货价(仅京喜正差额:差额=该单直营服务费(供货模式净收)时标注);都不满足则留空。「未匹配原因」单独一列,取值:账单无单号 / 单号格式异常 / 订单表无此单 / 订单无实付金额 / 无收款账单。', + 'description' => '覆盖店铺收款账户账单各平台页签(总账备注=订单收入),按「店铺 + 订单号」匹配订单侧商品金额与订单实付金额;一行 = 一个店铺的一个订单,商品金额只挂一次。「商品金额」只取主单(拆单子单不参与,整单没有主单时退化为取全部行),并排除虚拟条码(X0000x:信誉订单 / 虚拟订单)明细行;「订单实付金额」取订单级实付(拆单取主单)再减去虚拟条码行实付。「优惠金额」「冲减金额」另取总账备注=优惠收入 / 冲减收入的账单金额,不计入收入金额;「退款金额」另取总账备注=退款的账单金额,只单独列示,不计入收入金额、也不参与差额;「种菜金额」是订单号在种菜明细表或聚水潭订单标签明细(是否种菜订单=是)任意一边出现过时,该订单的收入金额(两个条件是或的关系),只是收入金额里的一部分,不参与差额;差额=(收入金额+优惠金额+冲减金额)−订单实付金额,匹配状态与差额异常备注同样按订单实付金额判定,未匹配到订单实付金额的行按订单实付金额=0 计入差额,只反映真正对不上的部分。挂不到订单行的优惠/冲减会补成一行(收入/商品留空)。「差额异常备注」只说明差额为什么产生,按顺序自动判定:订单实付未匹配(未匹配到订单实付金额,具体原因看「未匹配原因」列);订单实付取数为0(种菜)(订单实付=0 且是种菜单)、订单实付取数为0(订单实付=0 但不是种菜单)、订单实付未减冲减(订单实付=收入+优惠 → 差额=冲减金额)、订单实付未减优惠(订单实付=收入+冲减 → 差额=优惠金额)、订单实付未减优惠和冲减(订单实付=收入 → 差额=优惠+冲减)、订单实付含已退款部分(仅抖音负差额:聚水潭退款单/取消子单金额≈差额,或退款合计+账单退款净额≈实付−收入,或整单全退(退款合计≈实付)对上才标注)、订单实付未减联合营销费(仅得物负差额:联合营销费未让利尾数对上才标注)、订单实付取供货价(仅京喜正差额:差额=该单直营服务费(供货模式净收)时标注);都不满足则留空。「未匹配原因」单独一列,取值:账单无单号 / 账单无单号(采销收款)/ 单号格式异常 / 订单表无此单 / 1688采销收款(非销售单)/ 订单无实付金额 / 无收款账单(「采销收款」两档专指「支付宝-1688采销专用」账户:该账户收的是采销/供货结算款,不是店铺销售单收款,不按丢单处理)。', 'empty' => '店铺收款匹配订单明细尚未同步,请先执行 store-receipt:order-match:sync。', 'fields' => [ ['name' => 'platform', 'label' => '平台'],