shish 2 mesiacov pred
rodič
commit
a9cb319227

+ 12 - 1
app-ghs/controllers/OrderController.php

@@ -2479,7 +2479,18 @@ class OrderController extends BaseController
                 util::fail('请选时间');
             }
         }
-        $list = OrderClass::getAllByCondition($where, 'addTime DESC', ['id', 'orderSn', 'actPrice', 'addTime', 'remainDebtPrice', 'payTime']);
+        $list = OrderClass::getAllByCondition($where, 'addTime DESC', ['id', 'orderSn', 'actPrice', 'addTime', 'remainDebtPrice', 'debtPrice', 'payTime']);
+        if (!empty($list)) {
+            foreach ($list as $key => $value) {
+                $debtPrice = $value['debtPrice'] ?? 0;
+                $remainDebtPrice = $value['remainDebtPrice'] ?? 0;
+                $hasPayDebt = '0.00';
+                if (bccomp((string)$debtPrice, (string)$remainDebtPrice, 2) > 0) {
+                    $hasPayDebt = bcsub((string)$debtPrice, (string)$remainDebtPrice, 2);
+                }
+                $list[$key]['hasPayDebt'] = floatval($hasPayDebt);
+            }
+        }
         $result = ['customInfo' => $info, 'list' => $list];
         util::success($result);
     }

+ 10 - 4
biz-ghs/custom/classes/CustomClass.php

@@ -196,12 +196,13 @@ class CustomClass extends BaseClass
     }
 
     /**
-     * 使用账户余额结账:扣减净 balance(合并后来款销单必调)
-     * 调用方:CustomPaymentAllocateService 在 confirmClear(paymentSettleOnly) 之后,
-     *         按实销金额扣回「已用于销挂账」部分,避免 balance 与订单欠款不一致
+     * 用账面正余额支付挂账:扣减净 balance 并记「结账」流水。
+     * 来款充值后的自动销单不要调本方法(对照 hd:来款已入账,销单只改订单)。
+     * 调用方:CustomPaymentAllocateService::allocateFromExistingBalance
      */
-    public static function clearConsumeBalance($amount, $custom, $ghs, $shop, $staff, $clear)
+    public static function clearConsumeBalance($amount, $custom, $ghs, $shop, $staff, $clear, $options = [])
     {
+        $skipBalanceChangeRecord = !empty($options['skipBalanceChangeRecord']);
         // 先合并历史挂账到 balance,再扣减(只记余额变动)
         AccountMoneyClass::ensureCustomMoneyReady($custom, true);
         AccountMoneyClass::ensureGhsMoneyReady($ghs, true);
@@ -234,6 +235,11 @@ class CustomClass extends BaseClass
         $custom->balance = $newCustomBalance;
         $custom->save();
 
+        // 充值销账:只记一条充值流水(附 clearAmount),不另记「结账 -X」行(对照 hd settleAmount)
+        if ($skipBalanceChangeRecord) {
+            return;
+        }
+
         $capitalType = dict::getDict('capitalType', 'ghsHelpCustomUseBalanceClear', 'id');
         $fromType = dict::getDict('fromType', 'shop');
         $cbData = [

+ 53 - 32
biz-ghs/custom/services/CustomPaymentAllocateService.php

@@ -15,17 +15,24 @@ use bizHd\purchase\classes\PurchaseClearClass;
 use common\components\util;
 
 /**
- * 批发客户来款分配销挂账(对齐零售 RechargeClass::complete + SettleClass::clearSettle
+ * 批发来款与销挂账(对齐 hd RechargeClass::complete,非照搬 ghs 旧三件套
  *
- * 【背景】挂账已并入净 balance 后,不能再走「clearDebtAmountReduce + 整单 remainDebtPrice=0」旧销账,
- *        也不能「充值后 balance 必须 >0 才 useBalanceClear」。
- * 【原则】
- *   1. 写账前:ensureCustomMoneyReady + ensureGhsMoneyReady(见 AccountMoneyClass)
- *   2. 来款先入账:balance += 本次金额(rechargeBalance / thirdPay)
- *   3. 仅用「本次来款」作资金池 FIFO 销 debt=1 订单(末单可部分销,见 buildNeedClearMap)
- *   4. confirmClear(['paymentSettleOnly'=>true]) 只改订单欠款
- *   5. clearConsumeBalance(实销合计) 扣减净余额,避免余额与订单状态不一致
- *   6. 回写充值单/流水 clearId、clearSn、clearAmount;列表 becomeBalance = amount - clearAmount
+ * ── 账户模型(合并后)──
+ *   净 balance:正=有余额,负=待结。订单 remainDebtPrice 仍逐单记录待结。
+ *   合并式:balance 已含历史挂账,勿再 clearDebtAmountReduce。
+ *
+ * ── hd 零售(对照)──
+ *   balance / balancePay 与订单欠款分开记;充值 balance += 来款;
+ *   销单只改订单 remainDebtPrice,不再减 balance;
+ *   流水一条:amount=来款,settleAmount=用于销单,balance=充值+销单后的最终值。
+ *
+ * ── ghs 应对齐的行为 ──
+ *   A. 来款充值销账(rechargeClear / 线上 thirdPay+allocate):
+ *      来款已 rechargeBalance 入账 → FIFO 销单(仅改订单)→ 不再 clearConsumeBalance(否则 +1 又 -1)。
+ *   B. 用已有正余额销账(allocateFromExistingBalance):
+ *      无新来款 → 销单后须 clearConsumeBalance 扣减 balance → 可记一条「结账」流水。
+ *   C. 待付结账单确认(linkedClearAfterRecharge):
+ *      来款入账 + 按结账单销单 → 同 A,不二次扣 balance。
  *
  * 搜索关键词:ensure_before_recharge_clear、custom_ghs_recharge、custom_recharge_ghs_clear_action
  */
@@ -55,14 +62,15 @@ class CustomPaymentAllocateService
 
         self::syncDebtFlags($custom, $ghs);
 
-        // 3. 仅用「本次充值额」作资金池 FIFO 销单,再扣余额(见 applyPoolToDebtOrders
+        // 3. 仅用「本次充值额」FIFO 销单(只改订单,不二次扣 balance,对照 hd
         $allocate = self::applyPoolToDebtOrders($custom, $ghs, $shop, $staff, $amount, [
             'remark' => $params['remark'] ?? '充值销账',
+            'funding' => 'recharge',
         ]);
 
         // 4. 回写充值单、余额流水上的 clearId/clearAmount(供 becomeBalance 展示)
         if (!empty($customRecharge) && !empty($allocate['clear'])) {
-            self::patchRechargeAudit($customRecharge, $respond['ghsRecharge'] ?? null, $allocate);
+            self::patchRechargeAudit($customRecharge, $respond['ghsRecharge'] ?? null, $allocate, $custom, $ghs);
         }
 
         return $respond;
@@ -85,10 +93,11 @@ class CustomPaymentAllocateService
         // thirdPay 已入账,此处只按「本次支付金额」销挂账,勿在 NoticeController 再调 useBalanceClear
         $allocate = self::applyPoolToDebtOrders($custom, $ghs, $shop, null, $amount, [
             'remark' => '线上充值销账',
+            'funding' => 'recharge',
         ]);
 
         if (!empty($customRecharge) && !empty($allocate['clear'])) {
-            self::patchRechargeAudit($customRecharge, $ghsRecharge, $allocate);
+            self::patchRechargeAudit($customRecharge, $ghsRecharge, $allocate, $custom, $ghs);
         }
 
         return $allocate;
@@ -96,8 +105,7 @@ class CustomPaymentAllocateService
 
     /**
      * 【用途】待付结账单 — 供货商确认「客户已转账」(OrderClearController::actionConfirmClear)。
-     * 【流程】rechargeBalance(结账单 actPrice) → confirmClear(paymentSettleOnly) → clearConsumeBalance(实销)
-     * 【替代】旧逻辑「充值 + confirmClear(clearDebt) + clearConsumeBalance(整单 actPrice)」会在合并后双计挂账。
+     * 【流程】rechargeBalance(来款) → confirmClear(paymentSettleOnly)(不 clearConsumeBalance,对照 hd)
      */
     public static function linkedClearAfterRecharge($custom, $ghs, $shop, $staff, $clear, $payWay, $customRecharge = null)
     {
@@ -136,13 +144,7 @@ class CustomPaymentAllocateService
         if (bccomp($realClearAmount, $payCap, 2) > 0) {
             $realClearAmount = $payCap;
         }
-        // 从净余额扣掉实销金额(不超过结账单 actPrice,兼容手工抹零结账单)
-        if (bccomp($realClearAmount, '0', 2) > 0) {
-            $custom = CustomClass::getLockById($custom->id ?? 0);
-            $ghs = BizGhsClass::getLockById($ghs->id ?? 0);
-            CustomClass::clearConsumeBalance($realClearAmount, $custom, $ghs, $shop, $staff, $clear);
-            self::syncDebtFlags($custom, $ghs);
-        }
+        self::syncDebtFlags($custom, $ghs);
         $allocate = [
             'clear' => $clear,
             'realClearAmount' => $realClearAmount,
@@ -152,7 +154,7 @@ class CustomPaymentAllocateService
         ];
 
         if (!empty($customRecharge)) {
-            self::patchRechargeAudit($customRecharge, $ghsRecharge ?? null, $allocate);
+            self::patchRechargeAudit($customRecharge, $ghsRecharge ?? null, $allocate, $custom, $ghs);
         } else {
             self::patchRechargeAuditByClear($custom, $ghs, $clear, $realClearAmount);
         }
@@ -182,10 +184,12 @@ class CustomPaymentAllocateService
 
         $allocate = self::applyPoolToDebtOrders($custom, $ghs, $shop, $staff, $pool, [
             'remark' => '余额结账',
+            'funding' => 'existing_balance',
         ]);
 
         $realClearAmount = $allocate['realClearAmount'] ?? '0.00';
         if (bccomp($realClearAmount, '0', 2) > 0 && !empty($allocate['clear'])) {
+            // 用已有正余额销账:无充值流水,仍记一条「结账」变动
             CustomClass::clearConsumeBalance($realClearAmount, $custom, $ghs, $shop, $staff, $allocate['clear']);
             self::syncDebtFlags($custom, $ghs);
         }
@@ -290,8 +294,9 @@ class CustomPaymentAllocateService
     }
 
     /**
-     * 【用途】用指定来款池金额销挂账:建结账单 → paymentSettleOnly 确认 → clearConsumeBalance。
-     * 【参数】$poolAmount 本次来款(充值额或正余额),不是账户历史累计余额。
+     * 用资金池 FIFO 销挂账。
+     * funding=recharge:来款已入账,只改订单,不 clearConsumeBalance(对照 hd)。
+     * funding=existing_balance:用账面正余额,销单后 clearConsumeBalance 扣减。
      */
     protected static function applyPoolToDebtOrders($custom, $ghs, $shop, $staff, $poolAmount, $options = [])
     {
@@ -344,12 +349,15 @@ class CustomPaymentAllocateService
             util::fail('销账金额超过本次来款' . floatval($poolAmount) . '元,请检查订单待结或联系技术员');
         }
 
-        // 入账后须把「用于销单」的部分从 balance 扣回,净余额才与订单状态一致
-        if (bccomp($realClearAmount, '0', 2) > 0) {
+        $funding = $options['funding'] ?? 'recharge';
+        // 仅「用已有正余额」销账时才扣 balance;来款充值销账的来款已在 rechargeBalance 记入 balance
+        if ($funding === 'existing_balance' && bccomp($realClearAmount, '0', 2) > 0) {
             $custom = CustomClass::getLockById($custom->id ?? 0);
             $ghs = BizGhsClass::getLockById($ghs->id ?? 0);
             CustomClass::clearConsumeBalance($realClearAmount, $custom, $ghs, $shop, $staff, $clear);
             self::syncDebtFlags($custom, $ghs);
+        } else {
+            self::syncDebtFlags($custom, $ghs);
         }
 
         return [
@@ -377,27 +385,36 @@ class CustomPaymentAllocateService
     }
 
     /** 回写 xhCustomRecharge、xhCustomBalanceChange 的 clearId/clearSn/clearAmount(需先执行 add_clear_audit_fields.sql) */
-    protected static function patchRechargeAudit($customRecharge, $ghsRecharge, $allocate)
+    protected static function patchRechargeAudit($customRecharge, $ghsRecharge, $allocate, $custom = null, $ghs = null)
     {
         $clearId = $allocate['clearId'] ?? 0;
         $clearSn = $allocate['clearSn'] ?? '';
         $clearAmount = $allocate['clearAmount'] ?? '0.00';
+        $finalCustomBalance = is_object($custom) ? ($custom->balance ?? null) : null;
+        $finalGhsBalance = is_object($ghs) ? ($ghs->balance ?? null) : null;
 
         if (!empty($customRecharge)) {
             if (self::modelHasAttr($customRecharge, 'clearId')) {
                 $customRecharge->clearId = $clearId;
                 $customRecharge->clearSn = $clearSn;
                 $customRecharge->clearAmount = $clearAmount;
-                $customRecharge->save(false, ['clearId', 'clearSn', 'clearAmount']);
+                if ($finalCustomBalance !== null) {
+                    $customRecharge->balance = $finalCustomBalance;
+                }
+                $customRecharge->save(false);
             }
         }
 
         $relateId = $customRecharge->id ?? 0;
-        self::patchBalanceChangeRow(CustomBalanceChangeClass::class, $relateId, $clearId, $clearSn, $clearAmount);
+        self::patchBalanceChangeRow(CustomBalanceChangeClass::class, $relateId, $clearId, $clearSn, $clearAmount, [], $finalCustomBalance);
 
         if (!empty($ghsRecharge)) {
             $gRelateId = $ghsRecharge->id ?? 0;
-            self::patchBalanceChangeRow(GhsBalanceChangeClass::class, $gRelateId, $clearId, $clearSn, $clearAmount);
+            self::patchBalanceChangeRow(GhsBalanceChangeClass::class, $gRelateId, $clearId, $clearSn, $clearAmount, [], $finalGhsBalance);
+            if ($finalGhsBalance !== null) {
+                $ghsRecharge->balance = $finalGhsBalance;
+                $ghsRecharge->save(false, ['balance']);
+            }
         }
     }
 
@@ -417,7 +434,7 @@ class CustomPaymentAllocateService
         ]);
     }
 
-    protected static function patchBalanceChangeRow($class, $relateId, $clearId, $clearSn, $clearAmount, $extraWhere = [])
+    protected static function patchBalanceChangeRow($class, $relateId, $clearId, $clearSn, $clearAmount, $extraWhere = [], $finalBalance = null)
     {
         $where = array_merge(['io' => 1], $extraWhere);
         if ($relateId > 0) {
@@ -433,6 +450,10 @@ class CustomPaymentAllocateService
         if (self::modelHasAttr($row, 'giveAmount')) {
             $row->giveAmount = '0.00';
         }
+        // 流水余额列展示充值+销账后的净余额(与 hd 单条充值流水一致)
+        if ($finalBalance !== null && self::modelHasAttr($row, 'balance')) {
+            $row->balance = $finalBalance;
+        }
         $row->save(false);
     }