diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index 829e8ac4..90ad36b8 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -372,6 +372,10 @@ class Pages extends Controller $jdSofiaGuobu = '(' . $jdSofiaPay . ' - COALESCE(income_amount, 0)) > 0.005'; $rules['差额=订单实付包含商家承担优惠和以旧换新国补'] = $jdSofiaGuard . ' AND ' . $jdSofiaGuobu; $rules['差额=订单实付包含商家承担优惠'] = $jdSofiaGuard . ' AND NOT (' . $jdSofiaGuobu . ')'; + // 拼多多全额退款:先于通用「未减优惠/冲减」判定,避免抵减项把退款单误标成其他原因。 + $pddFullRefundHit = "platform = '拼多多'" + . ' AND ABS(COALESCE(income_amount, 0) + COALESCE(refund_amount, 0)) <= 0.02'; + $rules['订单实付含已退款部分'] = $pddFullRefundHit; // C 方案:这三条是"通用等式档"——口径(卖家实收 / 应付已付)能对上账单的行让位给口径兜底 // (归零 + 口径标识),只有口径也对不上时才显示这三档,避免把口径差标成一堆"未减优惠/冲减"。 $notBasisMarked = self::receiptReasonNotBasisMarkedSql(); @@ -410,7 +414,18 @@ class Pages extends Controller . ' OR ' . $refundGapHit($refundEvidence['cancelled_sum']) . ' OR ' . $refundGapNetHit($refundEvidence['refund_sum']) . ' OR ' . $refundFullHit($refundEvidence['refund_sum']) - . ') ELSE 0 END = 1) OR ' . $taoRefundHit; + . ') ELSE 0 END = 1) OR ' . $taoRefundHit . ' OR ' . $pddFullRefundHit; + + // 拼多多部分退款:账单收入高于聚水潭买家实付,且扣除优惠/冲减后仍有正向小额差额, + // 与「多多支付立减」等平台支付类补贴一致;只标注原因,不改差额和收入。 + $pddPaymentDiscount = '(' . $effective . ' - COALESCE(discount_amount, 0) - COALESCE(offset_amount, 0))'; + $rules['差额=平台支付立减'] = "platform = '拼多多'" + . " AND match_status = '已匹配'" + . ' AND ' . $effective . ' > 0.005' + . ' AND COALESCE(refund_amount, 0) < -0.005' + . ' AND ' . $pddPaymentDiscount . ' > 0.005' + . ' AND ' . $pddPaymentDiscount . ' <= 20.005' + . ' AND ' . $notBasisMarked; // 1688 先采后付订单的订单实付包含平台红包补贴,但支付宝实际到账是扣除补贴后的现金; // 仅对已匹配、负差额、无优惠/冲减/退款且当前没有口径标识的行标注,不改差额金额。 @@ -601,6 +616,11 @@ class Pages extends Controller if (abs($product) < 0.005) { return ($row->planting_amount ?? null) !== null ? $label . '取数为0(种菜)' : $label . '取数为0'; } + // 拼多多全额退款优先于其它抵减等式:退款后实际净收款为 0,不应再落成优惠/冲减异常。 + if (($row->platform ?? '') === '拼多多' + && abs($income + (float) ($row->refund_amount ?? 0)) <= 0.02) { + return '订单实付含已退款部分'; + } // 得物负差额:差额与联合营销费未让利尾数吻合(营销费支出 + 差额恰为整数)→「订单实付未减联合营销费」。 // 放在通用「未减冲减/优惠」等式之前:得物这类行的差额常恰好等于冲减(营销费)金额,需优先给出具体项备注。 if (($row->platform ?? '') === '得物' && $difference < -0.005) { @@ -707,6 +727,17 @@ class Pages extends Controller } } + // 拼多多部分退款:差额扣除优惠/冲减后,剩余部分与平台支付立减一致。 + $pddPaymentDiscount = $difference - $discount - $offset; + if (($row->platform ?? '') === '拼多多' + && ! $basisMarked + && $difference > 0.005 + && (float) ($row->refund_amount ?? 0) < -0.005 + && $pddPaymentDiscount > 0.005 + && $pddPaymentDiscount <= 20.005) { + return '差额=平台支付立减'; + } + // 原因优先:上面的规则都没命中时,如果这行的口径(卖家实收 / 应付已付)能对上账单, // 就按口径兜底——差额按 0 展示、口径标识在「匹配原因」列,不再当异常。 $rawRemark = trim((string) ($row->remark ?? '')); @@ -1661,8 +1692,8 @@ class Pages extends Controller // 联动统计要跑几次全表聚合,短时间内重复请求(页面加载 + 下拉刷新)直接吃缓存 $cacheKey = 'performance-details-facets:' . md5(serialize([$month, $filters, $orderNo])); - // 数据按天同步,缓存 10 分钟:大幅降低大平台(拼多多等)的联动等待。 - return response()->json(cache()->remember($cacheKey, now()->addSeconds(600), function () use ($month, $filters, $orderNo) { + // 数据按天同步;联动统计会扫全月,缓存 1 小时,避免相同筛选反复等待。 + return response()->json(cache()->remember($cacheKey, now()->addHour(), function () use ($month, $filters, $orderNo) { return [ 'month' => substr($month, 0, 7), 'facets' => $this->receiptOrderMatchFacets($month, $filters, $orderNo), diff --git a/tests/Unit/EcommerceFinance/PerformanceDifferenceRemarkTest.php b/tests/Unit/EcommerceFinance/PerformanceDifferenceRemarkTest.php new file mode 100644 index 00000000..bf131158 --- /dev/null +++ b/tests/Unit/EcommerceFinance/PerformanceDifferenceRemarkTest.php @@ -0,0 +1,71 @@ + '拼多多', + 'match_status' => '已匹配', + 'income_amount' => 0, + 'discount_amount' => 0, + 'offset_amount' => 0, + 'refund_amount' => 0, + 'product_amount' => 0, + 'paid_amount' => 0, + 'difference' => 0, + 'planting_amount' => null, + 'remark' => null, + ], $attributes); + + return (new ReflectionMethod(Pages::class, 'receiptDifferenceRemark'))->invoke(null, $row); + } + + public function test_pinduoduo_full_refund_wins_before_other_difference_rules(): void + { + $this->assertSame('订单实付含已退款部分', $this->remark([ + 'income_amount' => 7.00, + 'discount_amount' => 17.00, + 'refund_amount' => -7.00, + 'product_amount' => 42.00, + 'paid_amount' => 6.99, + 'difference' => 17.01, + ])); + } + + public function test_pinduoduo_partial_refund_marks_platform_payment_discount(): void + { + $this->assertSame('差额=平台支付立减', $this->remark([ + 'income_amount' => 896.00, + 'refund_amount' => -552.36, + 'product_amount' => 936.00, + 'paid_amount' => 894.21, + 'difference' => 1.79, + ])); + + $this->assertSame('差额=平台支付立减', $this->remark([ + 'income_amount' => 16.43, + 'refund_amount' => -12.00, + 'product_amount' => 21.90, + 'paid_amount' => 16.42, + 'difference' => 0.01, + ])); + } + + public function test_large_unexplained_pinduoduo_difference_stays_pending(): void + { + $this->assertSame('差额待核实', $this->remark([ + 'income_amount' => 130.00, + 'refund_amount' => -50.00, + 'product_amount' => 150.00, + 'paid_amount' => 100.00, + 'difference' => 30.00, + ])); + } +}