Просмотр исходного кода

Merge branch 'after-sale' into dev

shish 1 день назад
Родитель
Сommit
b074ec45cc

+ 5 - 3
app-ghs/controllers/ConsoleController.php

@@ -238,7 +238,8 @@ class ConsoleController extends BaseController
             ["name" => "报损", "img" => "ghs/home/kcyjs.png", "url" => "/admin/breakage/list"],
             ["name" => "报损", "img" => "ghs/home/kcyjs.png", "url" => "/admin/breakage/list"],
             ["name" => "拆散", "img" => "ghs/home/kcyjs.png", "url" => "/admin/part/list"],
             ["name" => "拆散", "img" => "ghs/home/kcyjs.png", "url" => "/admin/part/list"],
             ["name" => "收款流水", "img" => "ghs/home/kcyjs.png", "url" => "/admin/order/scanPay"],
             ["name" => "收款流水", "img" => "ghs/home/kcyjs.png", "url" => "/admin/order/scanPay"],
-            ["name" => "冲销单", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/custom/selectCustom?style=1&forward=1"],
+            // 无原单退款:选客户→选花材→生成 sameDay=0 退款单(不关联销售单)
+            ["name" => "退款", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/custom/selectCustom?style=1&refund=1"],
             ["name" => "公告", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/ghsNotice/list"],
             ["name" => "公告", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/ghsNotice/list"],
         ];
         ];
         $menuV3 = [
         $menuV3 = [
@@ -261,7 +262,8 @@ class ConsoleController extends BaseController
             ["name" => "报损", "img" => "ghs/home/kcyjs.png", "url" => "/admin/breakage/list"],
             ["name" => "报损", "img" => "ghs/home/kcyjs.png", "url" => "/admin/breakage/list"],
             ["name" => "拆散", "img" => "ghs/home/kcyjs.png", "url" => "/admin/part/list"],
             ["name" => "拆散", "img" => "ghs/home/kcyjs.png", "url" => "/admin/part/list"],
             ["name" => "收款流水", "img" => "ghs/home/kcyjs.png", "url" => "/admin/order/scanPay"],
             ["name" => "收款流水", "img" => "ghs/home/kcyjs.png", "url" => "/admin/order/scanPay"],
-            ["name" => "冲销单", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/custom/selectCustom?style=1&forward=1"],
+            // 无原单退款:选客户→选花材→生成 sameDay=0 退款单(不关联销售单)
+            ["name" => "退款", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/custom/selectCustom?style=1&refund=1"],
             ["name" => "公告", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/ghsNotice/list"],
             ["name" => "公告", "img" => "ghs/home/icon_caigou.png", "url" => "/admin/ghsNotice/list"],
         ];
         ];
         $menuIconMap = [
         $menuIconMap = [
@@ -288,7 +290,7 @@ class ConsoleController extends BaseController
             '公告' => 'purchase_record',
             '公告' => 'purchase_record',
             '商城' => 'mall_code',
             '商城' => 'mall_code',
             '花材(简)' => 'item',
             '花材(简)' => 'item',
-            '冲销单' => 'purchase_record',
+            '退款' => 'purchase_record',
         ];
         ];
         if ($version == 2) {
         if ($version == 2) {
             $menu = $menuV2;
             $menu = $menuV2;

+ 93 - 0
app-ghs/controllers/RefundController.php

@@ -764,6 +764,99 @@ class RefundController extends BaseController
         }
         }
     }
     }
 
 
+    /**
+     * 无原单退款(工作台「退款」)
+     * POST: customId, price, product(json), fundType, refundType, remark
+     * 立即写售后单 sameDay=0 并通过;无关联销售单/采购单。
+     */
+    public function actionCreateFreeRefund()
+    {
+        $post = Yii::$app->request->post();
+        $shopAdmin = $this->shopAdmin;
+        if (isset($shopAdmin['super']) == false || $shopAdmin['super'] != 1) {
+            util::fail('超管才能操作退款');
+        }
+
+        // 与 create-order 生产环境售后权限保持一致
+        if (getenv('YII_ENV') == 'production') {
+            if ($this->mainId == 23390) {
+                if (!in_array($this->adminId, [23960, 77951, 4])) {
+                    util::fail('你不能售后哈。。');
+                }
+                $remark = $post['remark'] ?? '';
+                if (empty($remark)) {
+                    util::fail('请填写备注007');
+                }
+            }
+            if ($this->mainId == 7704) {
+                if (in_array($this->shopAdminId, [133727, 133545]) == false) {
+                    util::fail('无法操作。。');
+                }
+            }
+            if ($this->mainId == 42680) {
+                if (!in_array($this->adminId, [40144])) {
+                    util::fail('你不能售后哦。。');
+                }
+            }
+        }
+
+        $customId = intval($post['customId'] ?? 0);
+        $cacheKey = 'ghs_free_refund_' . $this->mainId . '_' . $customId;
+        $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
+        if (!empty($has)) {
+            util::fail('请5秒之后再提交');
+        }
+        Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 5, 'has']);
+
+        try {
+            $respond = util::runWithDbConcurrencyRetry(function () use ($post) {
+                $connection = Yii::$app->db;
+                $transaction = $connection->beginTransaction();
+                try {
+                    $refundType = intval($post['refundType'] ?? RefundOrderClass::REFUND_TYPE_MONEY_GOOD);
+                    if ($refundType == RefundOrderClass::REFUND_TYPE_MONEY_GOOD) {
+                        $productJson = $post['product'] ?? '';
+                        if (empty($productJson)) {
+                            util::fail('请选择花材');
+                        }
+                        $productList = is_array($productJson) ? $productJson : json_decode($productJson, true);
+                        if (!is_array($productList) || empty($productList)) {
+                            util::fail('请选择花材哦');
+                        }
+                        $post['product'] = $productList;
+                    } else {
+                        $post['product'] = [];
+                    }
+                    $post['price'] = $post['price'] ?? 0;
+                    if ($post['price'] <= 0) {
+                        util::fail('退款金额不能小于0');
+                    }
+                    $post['shopId'] = $this->shopId;
+                    $post['sjId'] = $this->sjId;
+                    $post['shopAdminId'] = $this->shopAdminId;
+                    $post['mainId'] = $this->mainId;
+                    $shopAdmin = $this->shopAdmin;
+                    $post['shopAdminName'] = $shopAdmin['name'] ?? '';
+                    $result = RefundOrderService::createFreeRefund($post);
+                    $transaction->commit();
+                    return $result;
+                } catch (\Exception $exception) {
+                    if ($transaction->isActive) {
+                        $transaction->rollBack();
+                    }
+                    throw $exception;
+                }
+            });
+            util::success($respond);
+        } catch (\Exception $exception) {
+            Yii::info('无原单退款出错:' . $exception->getMessage());
+            if (util::isDbConcurrencyException($exception)) {
+                util::fail('系统繁忙中,请稍后再试');
+            }
+            util::fail($exception->getMessage() ?: '操作失败');
+        }
+    }
+
     //修改售后原因 ssh 20250623
     //修改售后原因 ssh 20250623
     public function actionChangeRefundOption()
     public function actionChangeRefundOption()
     {
     {

+ 15 - 6
biz-ghs/custom/classes/CustomClass.php

@@ -715,7 +715,11 @@ class CustomClass extends BaseClass
         self::savePairBalanceAfterDeduct($custom, $ghs, $newBalance);
         self::savePairBalanceAfterDeduct($custom, $ghs, $newBalance);
 
 
         $refundSn = $refund->orderSn ?? '';
         $refundSn = $refund->orderSn ?? '';
-        $saleOrderSn = $order->orderSn ?? '';
+        $saleOrderSn = !empty($order) ? ($order->orderSn ?? '') : '';
+        // 无原单退款流水只挂售后单号,避免「原单:」空串误导
+        $event = $saleOrderSn !== ''
+            ? "隔天冲销返充余额,售后单:{$refundSn},原单:{$saleOrderSn}"
+            : "无原单退款返充余额,售后单:{$refundSn}";
         $capitalTypeCustom = dict::getDict('capitalType', 'ghsHelpCustomRechargeReturn', 'id');
         $capitalTypeCustom = dict::getDict('capitalType', 'ghsHelpCustomRechargeReturn', 'id');
         CustomBalanceChangeClass::add([
         CustomBalanceChangeClass::add([
             'relateId' => $refund->id ?? 0,
             'relateId' => $refund->id ?? 0,
@@ -727,10 +731,10 @@ class CustomClass extends BaseClass
             'balance' => $newBalance,
             'balance' => $newBalance,
             'io' => 1,
             'io' => 1,
             'payWay' => dict::getDict('payWay', 'balancePay'),
             'payWay' => dict::getDict('payWay', 'balancePay'),
-            'event' => "隔天冲销返充余额,售后单:{$refundSn},原单:{$saleOrderSn}",
+            'event' => $event,
             'sjId' => $refund->sjId ?? 0,
             'sjId' => $refund->sjId ?? 0,
             'shopId' => $refund->shopId ?? 0,
             'shopId' => $refund->shopId ?? 0,
-            'mainId' => $order->mainId ?? 0,
+            'mainId' => !empty($order) ? ($order->mainId ?? 0) : ($refund->mainId ?? 0),
             'payTime' => date('Y-m-d H:i:s'),
             'payTime' => date('Y-m-d H:i:s'),
             'staffId' => $refund->shopAdminId ?? 0,
             'staffId' => $refund->shopAdminId ?? 0,
             'staffName' => $refund->shopAdminName ?? '',
             'staffName' => $refund->shopAdminName ?? '',
@@ -797,8 +801,13 @@ class CustomClass extends BaseClass
         if (empty($ghs)) {
         if (empty($ghs)) {
             return;
             return;
         }
         }
-        // hd 端明细展示采购单号 xhCg.orderSn
-        $orderSn = self::resolveXhCgOrderSnForHdEvent($order);
+        // hd 端明细展示采购单号;无原单时用售后单号
+        $orderSn = !empty($order)
+            ? self::resolveXhCgOrderSnForHdEvent($order)
+            : ($refund->orderSn ?? '');
+        $event = !empty($order)
+            ? "订单售后退款,单号:{$orderSn}"
+            : "无原单退款返充余额,售后单:{$orderSn}";
         $customShopId = $custom->shopId ?? 0;
         $customShopId = $custom->shopId ?? 0;
         $customShop = ShopClass::getById($customShopId, true);
         $customShop = ShopClass::getById($customShopId, true);
         $gbData = [
         $gbData = [
@@ -813,7 +822,7 @@ class CustomClass extends BaseClass
             'onlinePay' => 1,
             'onlinePay' => 1,
             'payWay' => dict::getDict('payWay', 'balancePay'),
             'payWay' => dict::getDict('payWay', 'balancePay'),
             'fromType' => dict::getDict('fromType', 'shop'),
             'fromType' => dict::getDict('fromType', 'shop'),
-            'event' => "订单售后退款,单号:{$orderSn}",
+            'event' => $event,
             'sjId' => $customShop->sjId ?? ($custom->sjId ?? 0),
             'sjId' => $customShop->sjId ?? ($custom->sjId ?? 0),
             'mainId' => $customShop->mainId ?? 0,
             'mainId' => $customShop->mainId ?? 0,
             'shopId' => $customShopId,
             'shopId' => $customShopId,

+ 134 - 10
biz-ghs/order/services/NextDayRefundService.php

@@ -10,6 +10,10 @@ use bizGhs\custom\classes\CustomClass;
 use bizGhs\custom\services\GhsRechargeSettleService;
 use bizGhs\custom\services\GhsRechargeSettleService;
 use bizGhs\order\classes\OrderClass;
 use bizGhs\order\classes\OrderClass;
 use bizGhs\order\classes\RefundOrderClass;
 use bizGhs\order\classes\RefundOrderClass;
+use bizGhs\order\classes\RefundOrderItemClass;
+use bizGhs\product\classes\ProductClass;
+use bizGhs\shop\classes\MainClass;
+use bizGhs\stock\classes\StockRecordClass;
 use bizHd\cg\classes\CgRefundClass;
 use bizHd\cg\classes\CgRefundClass;
 use bizHd\purchase\classes\PurchaseClass;
 use bizHd\purchase\classes\PurchaseClass;
 use common\components\dict;
 use common\components\dict;
@@ -75,27 +79,28 @@ class NextDayRefundService
 
 
     /**
     /**
      * 解析隔天资金方式:挂账/余额强制返余额;在线可选原路/返余额/仅记账。
      * 解析隔天资金方式:挂账/余额强制返余额;在线可选原路/返余额/仅记账。
+     * $hasRelateOrder=false 表示无原单退款(工作台「退款」),不可原路退。
      */
      */
     public static function resolveFundType($fundType, $order, $hasRelateOrder = true)
     public static function resolveFundType($fundType, $order, $hasRelateOrder = true)
     {
     {
         $fundType = intval($fundType);
         $fundType = intval($fundType);
-        $payWay = intval($order->payWay ?? 0);
-        $onlinePay = intval($order->onlinePay ?? dict::getDict('onlinePay', 'not'));
-        $debtPay = dict::getDict('payWay', 'debtPay');
-        $balancePay = dict::getDict('payWay', 'balancePay');
-        $wxPay = dict::getDict('payWay', 'wxPay');
-        $aliPay = dict::getDict('payWay', 'alipay');
-        $isOnline = $onlinePay == dict::getDict('onlinePay', 'yes') && in_array($payWay, [$wxPay, $aliPay], true);
-
-        if (!$hasRelateOrder) {
+        // 无原单:只能返余额或仅记账
+        if (!$hasRelateOrder || empty($order)) {
             if ($fundType === self::FUND_ORIGINAL) {
             if ($fundType === self::FUND_ORIGINAL) {
-                util::fail('自由冲销不能原路退回');
+                util::fail('无原单退款不能原路退回');
             }
             }
             if (!in_array($fundType, [self::FUND_BALANCE, self::FUND_NONE], true)) {
             if (!in_array($fundType, [self::FUND_BALANCE, self::FUND_NONE], true)) {
                 return self::FUND_BALANCE;
                 return self::FUND_BALANCE;
             }
             }
             return $fundType;
             return $fundType;
         }
         }
+        $payWay = intval($order->payWay ?? 0);
+        $onlinePay = intval($order->onlinePay ?? dict::getDict('onlinePay', 'not'));
+        $debtPay = dict::getDict('payWay', 'debtPay');
+        $balancePay = dict::getDict('payWay', 'balancePay');
+        $wxPay = dict::getDict('payWay', 'wxPay');
+        $aliPay = dict::getDict('payWay', 'alipay');
+        $isOnline = $onlinePay == dict::getDict('onlinePay', 'yes') && in_array($payWay, [$wxPay, $aliPay], true);
         if ($payWay === $debtPay || $payWay === $balancePay) {
         if ($payWay === $debtPay || $payWay === $balancePay) {
             return self::FUND_BALANCE;
             return self::FUND_BALANCE;
         }
         }
@@ -175,6 +180,125 @@ class NextDayRefundService
         }
         }
     }
     }
 
 
+    /**
+     * 无原单退款通过:加库存(退货退款)、累计门店支出、扣客户消费、按 fundType 返余额/仅记账。
+     * 不写订单 nextDayTkPrice(无关联销售单)。
+     */
+    public static function passFreeRefund($refund)
+    {
+        if (empty($refund)) {
+            util::fail('退款单不存在');
+        }
+        if (intval($refund->status) === RefundOrderClass::STATUS_COMPLETE) {
+            util::fail('已通过');
+        }
+        if (intval($refund->status) === RefundOrderClass::STATUS_REJECT) {
+            util::fail('已驳回');
+        }
+        if (intval($refund->status) === RefundOrderClass::STATUS_CANCEL) {
+            util::fail('已取消');
+        }
+
+        $refund->status = RefundOrderClass::STATUS_COMPLETE;
+        $refund->passTime = date('Y-m-d H:i:s');
+        $refund->save();
+
+        $refundSn = $refund->orderSn ?? '';
+        $refundPrice = bcadd((string)($refund->refundPrice ?? '0'), '0', 2);
+        $refundType = intval($refund->refundType ?? RefundOrderClass::REFUND_TYPE_MONEY_GOOD);
+        $shopId = intval($refund->shopId ?? 0);
+        $mainId = intval($refund->mainId ?? 0);
+        $sjId = intval($refund->sjId ?? 0);
+        $customName = $refund->customName ?? '';
+
+        // 退货退款:按明细回库(无原单行,不校验可退数量)
+        if ($refundType === RefundOrderClass::REFUND_TYPE_MONEY_GOOD) {
+            $refundItemList = RefundOrderItemClass::getAllByCondition(['orderSn' => $refundSn], null, '*', null, true);
+            if (empty($refundItemList)) {
+                util::fail('没有找到退款花材');
+            }
+            foreach ($refundItemList as $val) {
+                $val->status = 1;
+                $val->save();
+                $productId = intval($val->productId ?? 0);
+                $ptItemId = intval($val->itemId ?? 0);
+                $num = bcadd((string)($val->xhNum ?? '0'), '0', 2);
+                if (bccomp($num, '0', 2) <= 0 || $productId <= 0) {
+                    continue;
+                }
+                if (intval($val->xhUnitType ?? 0) === 1) {
+                    $smallNum = $num;
+                    $bigNum = 0;
+                } else {
+                    $smallNum = 0;
+                    $bigNum = $num;
+                }
+                $stockInfo = ProductClass::addStock($productId, $bigNum, $smallNum);
+                ProductClass::tryRecoverLimitBuyWhenStockRollbackFromZero($productId, $stockInfo['oldStock'] ?? 0);
+                $oldStock = $stockInfo['oldStock'] ?? 0;
+                $newStock = $stockInfo['newStock'] ?? 0;
+                $recordData = [
+                    'relateName' => $customName,
+                    'itemNum' => $val->itemNum ?? 0,
+                    'sjId' => $sjId,
+                    'shopId' => $shopId,
+                    'mainId' => $mainId,
+                    'orderSn' => $refundSn,
+                    'itemId' => $ptItemId,
+                    'oldStock' => $oldStock,
+                    'productId' => $productId,
+                    'newStock' => $newStock,
+                    'io' => 1,
+                ];
+                StockRecordClass::ghsRefundAddRecord($recordData);
+                $val->itemStock = $oldStock;
+                $val->newStock = $newStock;
+                $val->save();
+            }
+        }
+
+        $main = MainClass::getLockById($mainId);
+        if (empty($main)) {
+            util::fail('没有main信息');
+        }
+        $main->totalExpend = bcadd((string)($main->totalExpend ?? '0'), $refundPrice, 2);
+        $main->totalRefund = bcadd((string)($main->totalRefund ?? '0'), $refundPrice, 2);
+        $main->save();
+
+        return self::applyFreeFund($refund);
+    }
+
+    /**
+     * 无原单退款资金:扣减客户累计消费;返余额走成对账户,仅记账不动余额。
+     * @return string 处理后的客户余额
+     */
+    public static function applyFreeFund($refund)
+    {
+        $refundPrice = bcadd((string)($refund->refundPrice ?? '0'), '0', 2);
+        $customId = intval($refund->customId ?? 0);
+        $custom = CustomClass::getLockById($customId);
+        if (empty($custom)) {
+            util::fail('没有找到客户');
+        }
+        $buyAmount = bcsub((string)($custom->buyAmount ?? '0'), $refundPrice, 2);
+        if (bccomp($buyAmount, '0', 2) < 0) {
+            $buyAmount = '0.00';
+        }
+        $custom->buyAmount = $buyAmount;
+        $custom->save(false, ['buyAmount']);
+
+        $fundType = intval($refund->fundType ?? self::FUND_UNUSED);
+        $balance = bcadd((string)($custom->balance ?? '0'), '0', 2);
+        if ($fundType === self::FUND_BALANCE) {
+            $pair = GhsRechargeSettleService::lockAccountPair($custom);
+            // 无原单:order 传 null,流水挂售后单号
+            CustomClass::nextDayRefundReturnBalance($pair['custom'], $pair['ghs'], $refund, null);
+            $custom = CustomClass::getById($customId, true);
+            $balance = bcadd((string)($custom->balance ?? '0'), '0', 2);
+        }
+        return $balance;
+    }
+
     /**
     /**
      * 按时段汇总成功隔天售后金额(收入/销量统计扣减用)
      * 按时段汇总成功隔天售后金额(收入/销量统计扣减用)
      */
      */

+ 139 - 0
biz-ghs/order/services/RefundOrderService.php

@@ -257,4 +257,143 @@ class RefundOrderService extends BaseService
         $refund = RefundOrderClass::add($data, true);
         $refund = RefundOrderClass::add($data, true);
         return $refund;
         return $refund;
     }
     }
+
+    /**
+     * 无原单退款(工作台「退款」):写 xhRefund.sameDay=0,relateOrderSn 为空;
+     * 选花材后立即通过——退货加库存、返余额/仅记账,不写采购侧镜像单。
+     * @param array $post customId/price/product/fundType/refundType/...
+     * @return array 结果页/海报所需字段
+     */
+    public static function createFreeRefund($post)
+    {
+        $customId = intval($post['customId'] ?? 0);
+        if ($customId <= 0) {
+            util::fail('请选择客户');
+        }
+        $custom = CustomClass::getLockById($customId);
+        if (empty($custom)) {
+            util::fail('没有找到客户');
+        }
+        $mainId = intval($post['mainId'] ?? 0);
+        if ($mainId > 0 && intval($custom->mainId ?? 0) !== $mainId) {
+            util::fail('客户不属于当前门店');
+        }
+
+        $refundPrice = bcadd((string)($post['price'] ?? '0'), '0', 2);
+        if (bccomp($refundPrice, '0', 2) <= 0) {
+            util::fail('请填写退款金额');
+        }
+
+        $refundType = intval($post['refundType'] ?? RefundOrderClass::REFUND_TYPE_MONEY_GOOD);
+        $fundType = NextDayRefundService::resolveFundType($post['fundType'] ?? 0, null, false);
+
+        $sjId = intval($post['sjId'] ?? 0);
+        $shopId = intval($post['shopId'] ?? 0);
+        $orderSn = orderSn::getGhsRefundSn();
+
+        $data = [
+            'status' => RefundOrderClass::STATUS_UN_COMPLETE,
+            'orderSn' => $orderSn,
+            'relateOrderSn' => '',
+            'sjId' => $sjId,
+            'shopId' => $shopId,
+            'mainId' => $mainId,
+            'shopAdminId' => $post['shopAdminId'] ?? 0,
+            'shopAdminName' => $post['shopAdminName'] ?? '',
+            'cause' => $post['cause'] ?? 0,
+            'refundSendCost' => 0,
+            'refundPackCost' => 0,
+            'customId' => $customId,
+            'customName' => $custom->name ?? '',
+            'customNamePy' => $custom->namePy ?? '',
+            'customMobile' => $custom->mobile ?? '',
+            'orderTime' => date('Y-m-d H:i:s'),
+            'imgList' => $post['imgList'] ?? '',
+            'remark' => $post['remark'] ?? '',
+            'refundPrice' => $refundPrice,
+            'refundType' => $refundType,
+            'sameDay' => RefundOrderClass::SAME_DAY_NO,
+            'fundType' => $fundType,
+        ];
+
+        $postProduct = $post['product'] ?? [];
+        if ($refundType === RefundOrderClass::REFUND_TYPE_MONEY_GOOD) {
+            if (empty($postProduct) || !is_array($postProduct)) {
+                util::fail('请选择花材');
+            }
+        }
+
+        $refund = RefundOrderClass::add($data, true);
+
+        // 无原单明细:按商品主档写售后行,orderItemId=0
+        if ($refundType === RefundOrderClass::REFUND_TYPE_MONEY_GOOD) {
+            foreach ($postProduct as $currentProduct) {
+                $productId = intval($currentProduct['productId'] ?? 0);
+                if ($productId <= 0) {
+                    util::fail('花材参数错误');
+                }
+                $product = ProductClass::getById($productId, true);
+                if (empty($product) || intval($product->mainId ?? 0) !== $mainId) {
+                    util::fail('没有找到退款花材');
+                }
+                $num = bcadd((string)($currentProduct['num'] ?? '0'), '0', 2);
+                if (bccomp($num, '0', 2) <= 0) {
+                    util::fail(($product->name ?? '花材') . '数量必须大于0');
+                }
+                $unitType = intval($currentProduct['unitType'] ?? 0);
+                $xhUnitPrice = bcadd((string)($currentProduct['unitPrice'] ?? '0'), '0', 2);
+                $xhUnitName = $currentProduct['unitName'] ?? '';
+                if ($xhUnitName === '') {
+                    $xhUnitName = $unitType === 1
+                        ? ($product->smallUnit ?? '支')
+                        : ($product->bigUnit ?? '扎');
+                }
+                $ratio = bcadd((string)($product->ratio ?? '1'), '0', 2);
+                if (bccomp($ratio, '0', 2) <= 0) {
+                    $ratio = '1';
+                }
+                $itemNum = $num;
+                if ($unitType == dict::getDict('unitType', 'small')) {
+                    $itemNum = bcdiv($num, $ratio, 2);
+                }
+                $xhPrice = bcmul($num, $xhUnitPrice, 2);
+                $thisItemData = [
+                    'sjId' => $sjId,
+                    'shopId' => $shopId,
+                    'orderSn' => $orderSn,
+                    'productId' => $productId,
+                    'name' => $product->name ?? '',
+                    'itemId' => $product->itemId ?? 0,
+                    'itemCost' => $product->avCost ?? ($product->cost ?? 0),
+                    'itemNum' => $itemNum,
+                    'xhNum' => $num,
+                    'xhUnitName' => $xhUnitName,
+                    'xhUnitType' => $unitType,
+                    'xhUnitPrice' => $xhUnitPrice,
+                    'xhPrice' => $xhPrice,
+                    'mainId' => $mainId,
+                    'orderItemId' => 0,
+                    'cause' => $post['cause'] ?? 0,
+                ];
+                RefundOrderItemClass::addData($thisItemData, null);
+            }
+        }
+
+        NextDayRefundService::passFreeRefund($refund);
+        $refund = RefundOrderClass::getById($refund->id, true);
+        $custom = CustomClass::getById($customId, true);
+
+        return [
+            'id' => intval($refund->id ?? 0),
+            'orderSn' => $refund->orderSn ?? '',
+            'sameDay' => RefundOrderClass::SAME_DAY_NO,
+            'fundType' => intval($refund->fundType ?? $fundType),
+            'refundPrice' => $refund->refundPrice ?? $refundPrice,
+            'customId' => $customId,
+            'customName' => $custom->name ?? ($refund->customName ?? ''),
+            'customBalance' => bcadd((string)($custom->balance ?? '0'), '0', 2),
+            'orderId' => 0,
+            'nextDayTkPrice' => '0.00',
+        ];
+    }
 }
 }

+ 7 - 1
biz-ghs/stat/classes/StatKdClass.php

@@ -447,7 +447,7 @@ class StatKdClass extends BaseClass
         }
         }
     }
     }
 
 
-    /** 与批发开单入账分支一致,映射渠道 key */
+    /** 与批发开单入账分支一致,映射渠道 key;无原单退款按 fundType 归余额/其它 */
     protected static function resolveNextDayIncomeChannel($row)
     protected static function resolveNextDayIncomeChannel($row)
     {
     {
         $debtPrice = bcadd((string)($row['debtPrice'] ?? '0'), '0', 2);
         $debtPrice = bcadd((string)($row['debtPrice'] ?? '0'), '0', 2);
@@ -456,6 +456,12 @@ class StatKdClass extends BaseClass
         $payWay = intval($row['orderPayWay'] ?? ($row['payWay'] ?? 0));
         $payWay = intval($row['orderPayWay'] ?? ($row['payWay'] ?? 0));
         $onlinePay = intval($row['onlinePay'] ?? dict::getDict('onlinePay', 'not'));
         $onlinePay = intval($row['onlinePay'] ?? dict::getDict('onlinePay', 'not'));
 
 
+        // 无关联销售单:返余额记 balancePay,仅记账进 other
+        if ($orderId <= 0) {
+            $fundType = intval($row['fundType'] ?? 0);
+            return $fundType === 2 ? 'balancePay' : 'other';
+        }
+
         if ($orderId > 0 && bccomp($debtPrice, '0', 2) > 0) {
         if ($orderId > 0 && bccomp($debtPrice, '0', 2) > 0) {
             return bccomp($remainDebt, '0', 2) > 0 ? 'debt' : 'debtClear';
             return bccomp($remainDebt, '0', 2) > 0 ? 'debt' : 'debtClear';
         }
         }