|
|
@@ -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);
|