Преглед на файлове

Merge branch 'redesign‌-260706' into dev

shish преди 1 ден
родител
ревизия
3e731a89e4

+ 22 - 0
app-ghs/controllers/GhsController.php

@@ -76,6 +76,28 @@ class GhsController extends BaseController
         util::complete('修改成功');
     }
 
+    /**
+     * 【用途】供货商列表「待结笔数刷新」:按采购挂账单重算并回写 debtNum。
+     * GET id=供货商id
+     */
+    public function actionRefreshDebtNum()
+    {
+        $get = Yii::$app->request->get();
+        $id = intval($get['id'] ?? 0);
+        $ghs = GhsClass::getById($id, true);
+        if (empty($ghs)) {
+            util::fail('没有找到供货商');
+        }
+        if ($ghs->ownMainId != $this->mainId) {
+            util::fail('不是你的供货商');
+        }
+        $debtNum = GhsClass::refreshDebtNum($id);
+        if ($debtNum < 0) {
+            util::fail('刷新失败');
+        }
+        util::success(['debtNum' => $debtNum]);
+    }
+
     //添加供货商 ssh 20210611
     public function actionAdd()
     {

+ 20 - 6
biz-ghs/cg/services/CgRefundService.php

@@ -72,7 +72,7 @@ class CgRefundService extends BaseService
         $bookSn = $order->bookSn ?? 0;
         $isNextDay = $sameDay === CgPurchaseNextDayClass::SAME_DAY_NO;
 
-        // 当天:减实付、累加 tkPrice;隔天:实付不动,nextDayTkPrice 在 applyAmountAndFund 写入
+        // 当天:减实付、累加 tkPrice,并同步减本单 remainDebtPrice;隔天:实付不动,FIFO 在加余额后做
         if (!$isNextDay) {
             $currentTkPrice = bcadd($order->tkPrice, $refundPrice, 2);
             $order->tkPrice = $currentTkPrice;
@@ -83,10 +83,23 @@ class CgRefundService extends BaseService
             $order->actPrice = $currentActPrice;
             $order->realPrice = $currentRealPrice;
             $order->refund = 2;
-            // 待结采购单售后退尽:actPrice 已为 0 须同步改为已结清,否则会留下 debt=待结 的幽灵单
-            if (intval($order->debt ?? 0) === PurchaseOrderClass::DEBT_YES
-                && bccomp($currentActPrice, '0', 2) <= 0) {
-                $order->debt = PurchaseOrderClass::DEBT_NO;
+            // 待结单:当天售后同步减剩余待结(与 actPrice 对齐)
+            if (intval($order->debt ?? 0) === PurchaseOrderClass::DEBT_YES) {
+                $remain = bcadd((string)($order->remainDebtPrice ?? '0'), '0', 2);
+                if (bccomp($remain, '0', 2) <= 0) {
+                    $remain = bcadd((string)$actPrice, '0', 2);
+                }
+                $newRemain = bcsub($remain, $refundPrice, 2);
+                if (bccomp($newRemain, '0', 2) < 0) {
+                    $newRemain = '0.00';
+                }
+                $order->remainDebtPrice = $newRemain;
+                if (bccomp($newRemain, '0', 2) <= 0 || bccomp($currentActPrice, '0', 2) <= 0) {
+                    $order->debt = PurchaseOrderClass::DEBT_NO;
+                    $order->remainDebtPrice = '0.00';
+                    // 供 applyPurchaseRefundOnAccounts 识别:本单刚因当天售后结清,需减 debtNum
+                    $order->_purchaseDebtClearedByRefund = true;
+                }
             }
             $order->save();
         }
@@ -300,7 +313,8 @@ class CgRefundService extends BaseService
         if ($isNextDay) {
             CgPurchaseNextDayClass::applyAmountAndFund($refund, $order, $ghs, $sjId, $shopId);
         } else {
-            PurchaseOrderClass::applyPurchaseRefundOnAccounts($ghs, $refundPrice, $refund, $order, $sjId, $shopId);
+            // 当天已减本单 remain,加余额时不再 FIFO,避免同一笔退款重复消欠
+            PurchaseOrderClass::applyPurchaseRefundOnAccounts($ghs, $refundPrice, $refund, $order, $sjId, $shopId, false);
             $refund->hasReturn = CgPurchaseNextDayClass::FLAG_YES;
             $refund->save(false, ['hasReturn']);
         }

+ 10 - 4
biz-ghs/clear/classes/ClearClass.php

@@ -76,7 +76,7 @@ class ClearClass extends BaseClass
         if (empty($arr)) {
             util::fail('请选择采购单');
         }
-        $purchaseList = PurchaseOrderClass::getAllByCondition(['id' => ['in', $arr]], null, ['id', 'orderSn', 'actPrice', 'realPrice', 'debt', 'ghsId'], null, true);
+        $purchaseList = PurchaseOrderClass::getAllByCondition(['id' => ['in', $arr]], null, ['id', 'orderSn', 'actPrice', 'realPrice', 'debt', 'ghsId', 'debtPrice', 'remainDebtPrice'], null, true);
         if (empty($purchaseList)) {
             util::fail('请选择采购单');
         }
@@ -89,7 +89,12 @@ class ClearClass extends BaseClass
             if ($purchase->ghsId != $currentGhsId) {
                 util::fail('请选择同个供货商的订单');
             }
-            $totalPrice = bcadd($totalPrice, $purchase->actPrice, 2);
+            // 结账口径:剩余待结;历史单未回填时回落 actPrice
+            $remain = bcadd((string)($purchase->remainDebtPrice ?? '0'), '0', 2);
+            if (bccomp($remain, '0', 2) <= 0) {
+                $remain = bcadd((string)($purchase->actPrice ?? '0'), '0', 2);
+            }
+            $totalPrice = bcadd($totalPrice, $remain, 2);
         }
         $ghs = GhsClass::getById($currentGhsId, true);
         if (empty($ghs)) {
@@ -198,12 +203,13 @@ class ClearClass extends BaseClass
         $main->mayGathering = $currentGathering;
         $main->save();
 
-        //采购单状态变更
+        //采购单状态变更:结清剩余待结
         foreach ($list as $purchase) {
             $purchase->debt = PurchaseOrderClass::DEBT_NO;
+            $purchase->remainDebtPrice = '0.00';
             $purchase->payWay = $payWay;
             $purchase->clearId = $clearId;
-            $purchase->save();
+            $purchase->save(false, ['debt', 'remainDebtPrice', 'payWay', 'clearId']);
         }
 
         $custom = PurchaseOrderClass::applyPurchaseClearOnSupplierCustom($ghs, $order->actPrice, count($arr), $main);

+ 35 - 0
biz-ghs/ghs/classes/GhsClass.php

@@ -4,6 +4,8 @@ namespace bizGhs\ghs\classes;
 
 use bizGhs\base\classes\BaseClass;
 use bizGhs\custom\classes\AccountMoneyClass;
+use bizGhs\custom\classes\CustomClass;
+use bizGhs\order\classes\PurchaseOrderClass;
 use bizGhs\shop\classes\ShopClass;
 use common\components\imgUtil;
 use Yii;
@@ -207,4 +209,37 @@ class GhsClass extends BaseClass
         return ['file' => '/priceTable/' . $mainId . '/' . $file, 'shortFile' => $file];
     }
 
+    /**
+     * 【用途】按采购挂账单实数回写供货商待结笔数(xhGhs.debtNum)。
+     * 【为什么】列表展示直接读缓存字段,增量维护可能漂移,需手动按 debt=待结 的采购单重算纠正。
+     * 【副作用】同步更新关联客户 customId 的 debtNum(若有);不改 balance。
+     * @param int $ghsId 供货商 id
+     * @return int 回写后的待结笔数;供货商不存在时返回 -1
+     */
+    public static function refreshDebtNum($ghsId)
+    {
+        $ghsId = intval($ghsId);
+        $ghs = self::getById($ghsId, true);
+        if (empty($ghs)) {
+            return -1;
+        }
+        // 口径与结账/打印一致:debt=待结 的采购单笔数
+        $debtNum = (int)PurchaseOrderClass::getCount([
+            'ghsId' => $ghsId,
+            'debt' => PurchaseOrderClass::DEBT_YES,
+        ]);
+        $ghs->debtNum = $debtNum;
+        $ghs->save(false, ['debtNum']);
+
+        $customId = intval($ghs->customId ?? 0);
+        if ($customId > 0) {
+            $custom = CustomClass::getById($customId, true);
+            if (!empty($custom)) {
+                $custom->debtNum = $debtNum;
+                $custom->save(false, ['debtNum']);
+            }
+        }
+        return $debtNum;
+    }
+
 }

+ 154 - 8
biz-ghs/order/classes/PurchaseOrderClass.php

@@ -63,6 +63,137 @@ class PurchaseOrderClass extends BaseClass
     const DEBT_YES = 1;
     const DEBT_NO = 2;
 
+    /**
+     * 挂账成立时写入原欠/剩余待结(两边相等,单位元)
+     * @param object $order 采购单
+     * @param string|float|null $amount 应付;空则用 actPrice
+     */
+    public static function initDebtPrices($order, $amount = null)
+    {
+        $pay = $amount !== null
+            ? bcadd((string)$amount, '0', 2)
+            : bcadd((string)($order->actPrice ?? '0'), '0', 2);
+        $order->debtPrice = $pay;
+        $order->remainDebtPrice = $pay;
+    }
+
+    /**
+     * 入库/改价后校准:尚未部分消欠时两边同步为当前 actPrice
+     */
+    public static function syncDebtPricesIfFullPending($order)
+    {
+        if (intval($order->debt ?? 0) !== self::DEBT_YES) {
+            return;
+        }
+        $debtPrice = bcadd((string)($order->debtPrice ?? '0'), '0', 2);
+        $remain = bcadd((string)($order->remainDebtPrice ?? '0'), '0', 2);
+        // 已有部分消欠(remain < debtPrice)时不覆盖原欠
+        if (bccomp($debtPrice, '0', 2) > 0 && bccomp($debtPrice, $remain, 2) !== 0) {
+            return;
+        }
+        $pay = bcadd((string)($order->actPrice ?? '0'), '0', 2);
+        $order->debtPrice = $pay;
+        $order->remainDebtPrice = $pay;
+    }
+
+    /**
+     * 减少本单剩余待结;减到 ≤0 则标已结清。不改 debtPrice。
+     * @return bool 是否本单因此从待结变为已结清
+     */
+    public static function reduceRemainDebtPrice($order, $amount)
+    {
+        $cut = bcadd((string)$amount, '0', 2);
+        if (bccomp($cut, '0', 2) <= 0) {
+            return false;
+        }
+        if (intval($order->debt ?? 0) !== self::DEBT_YES) {
+            return false;
+        }
+        $remain = bcadd((string)($order->remainDebtPrice ?? '0'), '0', 2);
+        // 历史单未回填 remain 时回落 actPrice
+        if (bccomp($remain, '0', 2) <= 0) {
+            $remain = bcadd((string)($order->actPrice ?? '0'), '0', 2);
+        }
+        $newRemain = bcsub($remain, $cut, 2);
+        if (bccomp($newRemain, '0', 2) < 0) {
+            $newRemain = '0.00';
+        }
+        $order->remainDebtPrice = $newRemain;
+        $cleared = false;
+        if (bccomp($newRemain, '0', 2) <= 0) {
+            $order->debt = self::DEBT_NO;
+            $cleared = true;
+        }
+        $order->save(false, ['remainDebtPrice', 'debt']);
+        return $cleared;
+    }
+
+    /**
+     * 售后加余额后 FIFO 消采购挂账:只减 remainDebtPrice,不再加余额。
+     * @param int $ghsId 买方供货商
+     * @param string|float $amount 本次入账金额
+     * @return string 实际消欠合计
+     */
+    public static function fifoClearRemainAfterCredit($ghsId, $amount)
+    {
+        $pool = bcadd((string)$amount, '0', 2);
+        if (bccomp($pool, '0', 2) <= 0 || intval($ghsId) <= 0) {
+            return '0.00';
+        }
+        $orderList = self::getAllByCondition(
+            ['ghsId' => intval($ghsId), 'debt' => self::DEBT_YES],
+            'id asc',
+            '*',
+            null,
+            true
+        );
+        if (empty($orderList)) {
+            return '0.00';
+        }
+        $used = '0.00';
+        $clearedCount = 0;
+        foreach ($orderList as $order) {
+            $left = bcsub($pool, $used, 2);
+            if (bccomp($left, '0', 2) <= 0) {
+                break;
+            }
+            $remain = bcadd((string)($order->remainDebtPrice ?? '0'), '0', 2);
+            if (bccomp($remain, '0', 2) <= 0) {
+                $remain = bcadd((string)($order->actPrice ?? '0'), '0', 2);
+            }
+            if (bccomp($remain, '0', 2) <= 0) {
+                continue;
+            }
+            $cut = bccomp($remain, $left, 2) <= 0 ? $remain : $left;
+            if (self::reduceRemainDebtPrice($order, $cut)) {
+                $clearedCount++;
+            }
+            $used = bcadd($used, $cut, 2);
+        }
+        if ($clearedCount > 0) {
+            $ghs = GhsClass::getLockById(intval($ghsId));
+            if (!empty($ghs)) {
+                $ghs->debtNum = max(0, intval($ghs->debtNum ?? 0) - $clearedCount);
+                $ghs->debt = bccomp((string)($ghs->balance ?? '0'), '0', 2) < 0
+                    ? GhsClass::DEBT_YES
+                    : (intval($ghs->debtNum) > 0 ? GhsClass::DEBT_YES : GhsClass::DEBT_NO);
+                $ghs->save(false, ['debtNum', 'debt']);
+                $customId = intval($ghs->customId ?? 0);
+                if ($customId > 0) {
+                    $custom = CustomClass::getLockById($customId);
+                    if (!empty($custom)) {
+                        $custom->debtNum = max(0, intval($custom->debtNum ?? 0) - $clearedCount);
+                        $custom->isDebt = bccomp((string)($custom->balance ?? '0'), '0', 2) < 0
+                            ? CustomClass::IS_DEBT_YES
+                            : (intval($custom->debtNum) > 0 ? CustomClass::IS_DEBT_YES : CustomClass::IS_DEBT_NO);
+                        $custom->save(false, ['debtNum', 'isDebt']);
+                    }
+                }
+            }
+        }
+        return $used;
+    }
+
     //寄付与到付
     const YF_PAY_WAY_JF = 1;
     const YF_PAY_WAY_DF = 2;
@@ -130,21 +261,27 @@ class PurchaseOrderClass extends BaseClass
     }
 
     /**
-     * 采购售后退款:买方 xhGhs 净 balance 增加 + 流水;供货方 custom 同步
+     * 采购售后退款:买方 xhGhs 净 balance 增加 + 流水;供货方 custom 同步。
+     * @param bool $doFifo 是否用本次金额 FIFO 消其它挂账;当天已减本单 remain 时传 false,隔天传 true
      */
-    public static function applyPurchaseRefundOnAccounts($ghs, $amount, $refund, $order, $sjId, $shopId)
+    public static function applyPurchaseRefundOnAccounts($ghs, $amount, $refund, $order, $sjId, $shopId, $doFifo = true)
     {
         AccountMoneyClass::ensureGhsMoneyReady($ghs, true);
         $ghsNewBalance = bcadd($ghs->balance ?? '0.00', $amount, 2);
         $ghs->balance = $ghsNewBalance;
 
-        // 待结采购单售后:净 balance 增加;若该单待结金额已退尽则 debtNum 减 1
-        $wasDebtOrder = intval($order->debt ?? 0) === self::DEBT_YES;
-        $clearOrderDebt = $wasDebtOrder && bccomp($order->actPrice ?? '0', '0', 2) <= 0;
+        // 本单刚因当天售后结清时减 debtNum(隔天 FIFO 内部自行处理)
+        $clearOrderDebt = !empty($order->_purchaseDebtClearedByRefund);
+        if (!$clearOrderDebt && intval($order->debt ?? 0) === self::DEBT_YES
+            && bccomp((string)($order->actPrice ?? '1'), '0', 2) <= 0
+            && bccomp((string)($order->remainDebtPrice ?? '1'), '0', 2) <= 0) {
+            $order->debt = self::DEBT_NO;
+            $order->remainDebtPrice = '0.00';
+            $order->save(false, ['debt', 'remainDebtPrice']);
+            $clearOrderDebt = true;
+        }
         if ($clearOrderDebt) {
             $ghs->debtNum = max(0, intval($ghs->debtNum ?? 0) - 1);
-            $order->debt = self::DEBT_NO;
-            $order->save(false, ['debt']);
         }
         $ghs->debt = bccomp($ghsNewBalance, '0', 2) < 0 ? GhsClass::DEBT_YES : GhsClass::DEBT_NO;
         $ghs->save(false, ['balance', 'debtNum', 'debt']);
@@ -186,6 +323,11 @@ class PurchaseOrderClass extends BaseClass
             }
         }
 
+        // 隔天等:入账后 FIFO 消挂账;当天已减本单 remain 则不再 FIFO,避免重复消欠
+        if ($doFifo) {
+            self::fifoClearRemainAfterCredit(intval($ghs->id ?? 0), $amount);
+        }
+
         return $ghs;
     }
 
@@ -928,6 +1070,8 @@ class PurchaseOrderClass extends BaseClass
         ShopCapitalClass::addCapital($capitalData);
         $status = self::PURCHASE_ORDER_STATUS_COMPLETE;
         $cg->debt = self::DEBT_YES;
+        // 挂账成立:写入原欠/剩余待结
+        self::initDebtPrices($cg, $currentPrice);
         $cg->status = $status;
         $update = ['status' => $status];
         if (isset($data['entryTime']) && !empty($data['entryTime'])) {
@@ -1351,7 +1495,9 @@ class PurchaseOrderClass extends BaseClass
                 $ghsMain->save();
 
                 $order->debt = self::DEBT_YES;
-                $order->save(false, ['debt']);
+                // 稍后入库→入库完成:校准/写入挂账原欠与剩余待结
+                self::initDebtPrices($order, $currentPrice);
+                $order->save(false, ['debt', 'debtPrice', 'remainDebtPrice']);
 
                 //当天和当月支出统计
                 StatOutClass::updateOrInsert($main, $shop, $currentPrice);

+ 1 - 0
biz-ghs/order/models/PurchaseOrder.php

@@ -4,6 +4,7 @@ use bizGhs\base\models\Base;
 /**
  * 采购订单 xhGhsCgOrder
  * nextDayTkPrice:隔天售后累计退款,不改 actPrice;可退上限=actPrice-nextDayTkPrice
+ * debtPrice:挂账原欠;remainDebtPrice:剩余待结(结账/FIFO 消欠只减本字段)
  */
 class PurchaseOrder extends Base
 {

+ 21 - 0
biz-ghs/order/services/PurchaseOrderService.php

@@ -22,6 +22,27 @@ class PurchaseOrderService extends BaseService
         Yii::$app->request->setQueryParams(array_merge($get, ['page' => $page, 'pageSize' => $pageSize]));
         $result = PurchaseOrderClass::getList('*', $where, 'addTime DESC');
         $result['debtNum'] = $result['totalNum'] ?? 0;
+        $list = $result['list'] ?? [];
+        if (!empty($list)) {
+            foreach ($list as $key => $value) {
+                $debtPrice = bcadd((string)($value['debtPrice'] ?? '0'), '0', 2);
+                $remainDebtPrice = bcadd((string)($value['remainDebtPrice'] ?? '0'), '0', 2);
+                // 历史单未回填 remain 时用 actPrice
+                if (bccomp($remainDebtPrice, '0', 2) <= 0) {
+                    $remainDebtPrice = bcadd((string)($value['actPrice'] ?? '0'), '0', 2);
+                    $result['list'][$key]['remainDebtPrice'] = $remainDebtPrice;
+                }
+                if (bccomp($debtPrice, '0', 2) <= 0) {
+                    $debtPrice = $remainDebtPrice;
+                    $result['list'][$key]['debtPrice'] = $debtPrice;
+                }
+                $hasPayDebt = '0.00';
+                if (bccomp($debtPrice, $remainDebtPrice, 2) > 0) {
+                    $hasPayDebt = bcsub($debtPrice, $remainDebtPrice, 2);
+                }
+                $result['list'][$key]['hasPayDebt'] = floatval($hasPayDebt);
+            }
+        }
         return $result;
     }
 

+ 12 - 3
biz-hd/homePageConfig/classes/HomePageDisplayClass.php

@@ -94,8 +94,17 @@ class HomePageDisplayClass
             }
             $icon = $item['icon'] ?? '';
             $iconUrl = $icon;
-            // 上传图标转完整 URL;预设图标前端用本地映射,原样返回
-            if (intval($item['iconType'] ?? 1) === 2 && $icon !== '' && strpos($icon, 'http') !== 0) {
+            $iconType = intval($item['iconType'] ?? 1);
+            // 默认图标库 preset:N → OSS 静态图完整 URL(与前端默认图库一致)
+            if (preg_match('/^preset:(\d+)$/', $icon, $m)) {
+                $n = intval($m[1]);
+                if ($n >= 1 && $n <= 12) {
+                    $path = 'hhb/images/navGrid-default/navGrid-default' . $n . '.png';
+                    $formatted = business::formatUploadImg($path);
+                    $iconUrl = $formatted['url'] ?? $path;
+                }
+            } elseif ($iconType === 2 && $icon !== '' && strpos($icon, 'http') !== 0) {
+                // 商家上传图标转完整 URL
                 $formatted = business::formatUploadImg($icon);
                 $iconUrl = $formatted['url'] ?? $icon;
             }
@@ -104,7 +113,7 @@ class HomePageDisplayClass
                 'name' => $item['name'],
                 'icon' => $icon,
                 'iconUrl' => $iconUrl,
-                'iconType' => intval($item['iconType'] ?? 1),
+                'iconType' => $iconType,
                 'type' => intval($item['type'] ?? 3),
                 'value' => strval($item['value'] ?? ''),
             ];

+ 13 - 0
sql/20260706_redesign.sql

@@ -441,3 +441,16 @@ ALTER TABLE xhPsMethod
 
 ALTER TABLE `xhShop`
     MODIFY COLUMN `hasRenew` tinyint(4) NOT NULL DEFAULT 0 COMMENT '已续费 0没有 1有' AFTER `beforeDeadline`;
+
+
+-- 初始化批发店花材分类设置 oyyz 2026-8-25 10:37:59
+INSERT INTO `xhCategorySetting`
+(`mainId`, `shopId`, `itemCateName`, `isItemCateTop`, `isItemCateShow`, `createTime`, `updateTime`)
+SELECT t.mainId, t.id AS shopId, '鲜花花材', 1, 1,  NOW(), NOW()
+FROM xhShop t
+WHERE t.ptStyle = 1
+  AND t.mainId IN (SELECT mainId FROM xhShop WHERE ptStyle = 2)
+  AND NOT EXISTS (
+    SELECT 1 FROM xhCategorySetting cs
+    WHERE cs.mainId = t.mainId AND cs.shopId = t.id
+);