|
|
@@ -20,7 +20,8 @@ use common\components\util;
|
|
|
* 规则(仅此一套,无旧三件套):
|
|
|
* 1. 净 balance:正=有余额,负=待结;历史挂账已并入 balance(ensure 幂等)。
|
|
|
* 2. 来款:balance += 金额,记一条充值流水(amount=来款)。
|
|
|
- * 3. 销单:仅用「本次资金池」按订单 id FIFO 减少 remainDebtPrice,不再扣 balance。
|
|
|
+ * 3. 销单:仅用「本次资金池」减少 remainDebtPrice,不再扣 balance。
|
|
|
+ * 默认按订单 id FIFO;售后返充可传 preferOrderId,先结当前售后原单(可部分结),剩余再 FIFO。
|
|
|
* 4. 用账面正余额销账:无来款,FIFO 后 balance -= 实销额,可记「结账」流水。
|
|
|
*
|
|
|
* 入口:merchantRechargeWithAutoClear / onlinePayFifoClear / confirmClearBillWithIncoming /
|
|
|
@@ -189,7 +190,7 @@ class GhsRechargeSettleService
|
|
|
* @param string|float $amount 本次入账金额
|
|
|
* @param object|null $shop 供货商门店;空则取 ghs.shopId
|
|
|
* @param object|null $staff 操作人(结账单记录用)
|
|
|
- * @param array $options balanceBeforeRecharge|payWay
|
|
|
+ * @param array $options balanceBeforeRecharge|payWay|preferOrderId(售后原单优先消欠)
|
|
|
* @return array 与 fifoSettleWithPool 相同结构
|
|
|
*/
|
|
|
public static function afterCreditFifoClear($custom, $ghs, $amount, $shop = null, $staff = null, $options = [])
|
|
|
@@ -231,11 +232,15 @@ class GhsRechargeSettleService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * FIFO 分配计划:按订单 id 升序,资金池用尽即停止。
|
|
|
+ * 销挂账分配计划:可选优先本单,剩余按订单 id 升序 FIFO。
|
|
|
+ * 售后返充:preferOrderId=当前售后原单,先冲本单 remain(可部分结),再消其它挂账单。
|
|
|
*
|
|
|
+ * @param int $customId 客户 id
|
|
|
+ * @param string|float $poolAmount 本次可用金额
|
|
|
+ * @param int $preferOrderId 优先消欠的销售单 id,0=不优先
|
|
|
* @return array<int, array{orderId:int, clearAmount:string, orderSn:string}>
|
|
|
*/
|
|
|
- public static function planFifoByPool($customId, $poolAmount)
|
|
|
+ public static function planFifoByPool($customId, $poolAmount, $preferOrderId = 0)
|
|
|
{
|
|
|
$pool = self::money($poolAmount);
|
|
|
if (bccomp($pool, '0', 2) <= 0) {
|
|
|
@@ -249,12 +254,39 @@ class GhsRechargeSettleService
|
|
|
|
|
|
$plan = [];
|
|
|
$used = '0.00';
|
|
|
+ $preferOrderId = intval($preferOrderId);
|
|
|
+
|
|
|
+ // 1)有售后原单且仍挂账:先结本单(金额不够则部分结)
|
|
|
+ if ($preferOrderId > 0) {
|
|
|
+ foreach ($orderList as $order) {
|
|
|
+ if (intval($order->id ?? 0) !== $preferOrderId) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $remain = self::money($order->remainDebtPrice ?? 0);
|
|
|
+ if (bccomp($remain, '0', 2) <= 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ $clearAmount = bccomp($remain, $pool, 2) <= 0 ? $remain : $pool;
|
|
|
+ $plan[] = [
|
|
|
+ 'orderId' => $preferOrderId,
|
|
|
+ 'clearAmount' => $clearAmount,
|
|
|
+ 'orderSn' => $order->orderSn ?? '',
|
|
|
+ ];
|
|
|
+ $used = bcadd($used, $clearAmount, 2);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ // 2)剩余金额按 id 升序 FIFO(跳过已优先消过的本单)
|
|
|
foreach ($orderList as $order) {
|
|
|
$left = bcsub($pool, $used, 2);
|
|
|
if (bccomp($left, '0', 2) <= 0) {
|
|
|
break;
|
|
|
}
|
|
|
+ $oid = intval($order->id ?? 0);
|
|
|
+ if ($preferOrderId > 0 && $oid === $preferOrderId) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
$remain = self::money($order->remainDebtPrice ?? 0);
|
|
|
if (bccomp($remain, '0', 2) <= 0) {
|
|
|
@@ -263,7 +295,7 @@ class GhsRechargeSettleService
|
|
|
|
|
|
$clearAmount = bccomp($remain, $left, 2) <= 0 ? $remain : $left;
|
|
|
$plan[] = [
|
|
|
- 'orderId' => (int)($order->id ?? 0),
|
|
|
+ 'orderId' => $oid,
|
|
|
'clearAmount' => $clearAmount,
|
|
|
'orderSn' => $order->orderSn ?? '',
|
|
|
];
|
|
|
@@ -282,8 +314,9 @@ class GhsRechargeSettleService
|
|
|
$ghs = $pair['ghs'];
|
|
|
$customId = $custom->id ?? 0;
|
|
|
$pool = self::money($poolAmount);
|
|
|
+ $preferOrderId = intval($options['preferOrderId'] ?? 0);
|
|
|
|
|
|
- $plan = self::planFifoByPool($customId, $pool);
|
|
|
+ $plan = self::planFifoByPool($customId, $pool, $preferOrderId);
|
|
|
if (empty($plan)) {
|
|
|
self::refreshDebtFlags($custom, $ghs);
|
|
|
return self::emptyAllocateResult($custom, $ghs);
|