| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- <?php
- namespace bizGhs\order\classes;
- use biz\ghs\classes\GhsClass;
- use biz\shop\classes\ShopClass;
- use bizGhs\custom\classes\CustomClass;
- use bizGhs\shop\classes\MainClass;
- use bizGhs\shop\classes\ShopMoneyChangeClass;
- use common\components\dict;
- use common\components\noticeUtil;
- use common\components\orderSn;
- use common\components\util;
- use bizGhs\base\classes\BaseClass;
- use bizGhs\clear\classes\OrderCgClearClass;
- use bizGhs\custom\services\GhsRechargeSettleService;
- use bizHd\purchase\classes\PurchaseClass;
- use bizHd\purchase\classes\PurchaseClearClass;
- class OrderClearClass extends BaseClass
- {
- public static $baseFile = '\bizGhs\order\models\OrderClear';
- /**
- * 使用账户正余额 FIFO 结挂账(GhsRechargeSettleService::consumePositiveBalanceFifo)
- */
- public static function useBalanceClear($custom, $ghs, $shop, $staff)
- {
- return GhsRechargeSettleService::consumePositiveBalanceFifo($custom, $ghs, $shop, $staff);
- }
- /** 作废该客户所有待付结账单(status=待付),新建销账前调用 */
- public static function expireAwaitPayClears($customId)
- {
- $list = self::getAllByCondition(['customId' => $customId, 'status' => PurchaseClearClass::STATUS_AWAIT_PAY], null, '*', null, true);
- if (empty($list)) {
- return;
- }
- foreach ($list as $item) {
- $item->status = PurchaseClearClass::STATUS_EXPIRE;
- $item->save();
- OrderCgClearClass::markExpireByClearId($item->id);
- }
- }
- /** 汇总结账单下各 OrderCgClear.amount(实销合计,支持部分销单) */
- public static function sumClearAmountByClearId($clearId)
- {
- $clearId = intval($clearId);
- if ($clearId <= 0) {
- return '0.00';
- }
- $list = OrderCgClearClass::getAllByCondition(['clearId' => $clearId], null, '*', null, true);
- $total = '0.00';
- if (!empty($list)) {
- foreach ($list as $row) {
- $total = bcadd($total, $row->amount ?? 0, 2);
- }
- }
- return $total;
- }
- /**
- * 按每单指定 clearAmount 建结账单(充值 FIFO 销账、末单可部分销 remainDebtPrice)
- *
- * @param array $post 同 clear()
- * @param array $orderRows [['orderId'=>,'clearAmount'=>,'orderSn'=>], ...]
- */
- public static function clearWithAmountMap($post, $orderRows, $sjId, $shopId)
- {
- if (empty($orderRows)) {
- util::fail('请选择订单');
- }
- $ids = [];
- $amountMap = [];
- foreach ($orderRows as $row) {
- $orderId = intval($row['orderId'] ?? 0);
- if ($orderId <= 0) {
- continue;
- }
- $ids[] = $orderId;
- $amountMap[$orderId] = bcadd((string)($row['clearAmount'] ?? 0), '0', 2);
- }
- if (empty($ids)) {
- util::fail('请选择订单');
- }
- $idText = json_encode(array_map(function ($id) {
- return ['id' => $id];
- }, $ids));
- $post['modifyPrice'] = $post['modifyPrice'] ?? array_sum(array_map('floatval', $amountMap));
- $clear = self::clear($post, $idText, $sjId, $shopId, $amountMap);
- return $clear;
- }
- //订单结算 ssh 2021.3.14
- public static function clear($post, $idText, $sjId, $shopId, $orderAmountMap = [])
- {
- $customId = $post['customId'] ?? 0;
- $data = json_decode($idText, true);
- $ids = array_column($data, 'id');
- if (empty($ids)) {
- util::fail('请选择交易记录');
- }
- $list = OrderClass::getByIds($ids);
- if (empty($list)) {
- util::fail('请选择订单');
- }
- $modifyPrice = bcadd((string)($post['modifyPrice'] ?? '0'), '0', 2);
- $amount = '0.00';
- if (!empty($orderAmountMap)) {
- // 充值 FIFO 销账:prePrice=Σ每单销账额(对照 hd Settle,勿用订单全款算优惠)
- foreach ($orderAmountMap as $mayClear) {
- $amount = bcadd($amount, (string)$mayClear, 2);
- }
- }
- foreach ($list as $key => $val) {
- if ($val['sjId'] != $sjId) {
- util::fail('只能结算自己的订单哦');
- }
- if ($val['debt'] == 0) {
- util::fail('有订单已经结算过了');
- }
- if ($val['customId'] != $customId) {
- util::fail('每次只能结算一个客户的订单');
- }
- if (empty($orderAmountMap)) {
- $amount = bcadd($amount, $val['remainDebtPrice'], 2);
- }
- }
- $custom = CustomClass::getLockById($customId);
- if (empty($custom)) {
- util::fail('没有找到客户');
- }
- // 建结账单前:历史挂账并入净 balance(关键词 ensure_before_recharge_clear)
- \bizGhs\custom\classes\AccountMoneyClass::ensureCustomMoneyReady($custom, true);
- $ghsId = $custom->ghsId;
- $ghs = GhsClass::getLockById($ghsId);
- if (empty($ghs)) {
- util::fail('没有找到供货商');
- }
- \bizGhs\custom\classes\AccountMoneyClass::ensureGhsMoneyReady($ghs, true);
- $ghsShopId = $ghs['shopId'] ?? 0;
- $ghsShop = ShopClass::getById($ghsShopId, true);
- $ghsShopName = $ghsShop->shopName ?? '';
- $ghsShopName = $ghsShopName == '首店' ? '总店' : $ghsShopName;
- $orderSn = orderSn::getPurchaseClearSn();
- //默认24小时过期
- $deadline = date("Y-m-d H:i:s", time() + 24 * 60 * 60);
- //天天鲜花12小时之后
- if ($ghsShopId == 763 || $ghsShopId == 795 || $ghsShopId == 1405) {
- $deadline = date("Y-m-d H:i:s", time() + 10 * 60 * 60);
- }
- //开发环境10个小时过期
- if (getenv('YII_ENV') != 'production') {
- $deadline = date("Y-m-d H:i:s", time() + 10 * 60 * 60);
- }
- //惠雅鲜花 结账单过期时间设置为30天
- if ($ghsShopId == 520 || $ghsShopId == 1489 || $ghsShopId == 2164 || $ghsShopId == 2167) {
- $deadline = date("Y-m-d H:i:s", time() + 30 * 24 * 60 * 60);
- }
- //昱成花卉 结账单过期时间设置为30天
- if ($ghsShopId == 8596) {
- $deadline = date("Y-m-d H:i:s", time() + 30 * 24 * 60 * 60);
- }
- //花大苪 结账单过期时间设置为30天
- if ($ghsShopId == 8249) {
- $deadline = date("Y-m-d H:i:s", time() + 30 * 24 * 60 * 60);
- }
- //丰行鲜花 结账单过期时间设置为30天
- if ($ghsShopId == 7855) {
- $deadline = date("Y-m-d H:i:s", time() + 30 * 24 * 60 * 60);
- }
- $payWay = isset($post['payWay']) && is_numeric($post['payWay']) ? $post['payWay'] : dict::getDict('payWay', 'unPay');
- $remark = $post['remark'] ?? '';
- $onlinePay = isset($post['onlinePay']) && is_numeric($post['onlinePay'])
- ? intval($post['onlinePay'])
- : intval(dict::getDict('onlinePay', 'not'));
- $clearData = [
- 'prePrice' => $amount,
- 'actPrice' => $modifyPrice,
- 'realPrice' => $modifyPrice,
- 'ghsId' => $ghsId,
- 'ghsName' => $ghs['name'] ?? '',
- 'ghsMobile' => $ghs['mobile'] ?? '',
- 'ghsAvatar' => $ghs['avatar'] ?? '',
- 'ghsAddress' => $ghs['address'] ?? '',
- 'ghsShopAdminId' => $post['ghsShopAdminId'],
- 'ghsShopId' => $post['ghsShopId'] ?? 0,
- 'ghsShopAdminName' => $post['ghsShopAdminName'],
- 'sjId' => $sjId,
- 'shopId' => $shopId,
- 'orderSn' => $orderSn,
- 'status' => 1,
- 'clearStyle' => dict::getDict('clearStyle', 'gys2Hd'),
- 'customId' => $customId,
- 'customName' => $custom['name'] ?? '',
- 'customShopId' => $custom['shopId'] ?? 0,
- 'customAvatar' => $custom['avatar'] ?? '',
- 'customMobile' => $custom['mobile'] ?? '',
- 'customAddress' => $custom['address'] ?? '',
- 'deadline' => $deadline,
- 'payWay' => $payWay,
- 'onlinePay' => $onlinePay,
- 'num' => count($ids),
- 'ghsShopName' => $ghsShopName,
- 'hasNoticeCustom' => 0,
- 'remark' => $remark,
- // 生成并保存 salt 字段,用于结账单的验签和防篡改分享链接
- 'salt' => $post['salt'] ?? \common\components\stringUtil::charsShuffleLowerCase(10),
- ];
- if (!empty($orderAmountMap)) {
- // 自动充值销账:结账单金额=本次来款池,不产生虚假「优惠」
- $modifyPrice = $amount;
- }
- if (bccomp($modifyPrice, $amount, 2) < 0) {
- $clearData['discountAmount'] = bcsub($amount, $modifyPrice, 2);
- $clearData['discountType'] = dict::getDict('discountType', 'discount');
- }
- if (bccomp($modifyPrice, $amount, 2) > 0) {
- //noticeUtil::push("结账金额大于总欠款金额 {$modifyPrice} {$amount}", '15280215347');
- util::fail('结账金额大于总欠款金额');
- }
- $return = PurchaseClearClass::add($clearData, true);
- $pairs = OrderCgClearClass::buildPairsFromOrders($list);
- // 充值销账:每单销账金额可小于 remainDebtPrice(部分销)
- if (!empty($orderAmountMap)) {
- foreach ($pairs as $k => $pair) {
- $oid = intval($pair['orderId'] ?? 0);
- if ($oid > 0 && isset($orderAmountMap[$oid])) {
- $pairs[$k]['amount'] = $orderAmountMap[$oid];
- }
- }
- }
- OrderCgClearClass::bindRelations($return, $pairs);
- $complete = $post['complete'] ?? 0;
- if ($complete == 1) {
- self::confirmClear($return, $payWay);
- }
- return $return;
- }
- /**
- * 净余额模型销账:只减订单 remainDebtPrice,不调 clearDebtAmountReduce、不二次扣 balance。
- * 充值/来款链路请只调本方法(GhsRechargeSettleService)。
- */
- public static function applyNetBalanceClear($clear, $payWay = 0, $options = [])
- {
- return self::confirmClear($clear, $payWay, array_merge([
- 'paymentSettleOnly' => true,
- ], $options));
- }
- /**
- * 确认结账(手工结账单等仍可能走完整链路;来款自动销账请用 applyNetBalanceClear)
- *
- * $options['paymentSettleOnly'] 只减订单待结
- * $options['skipCashMoney'] 现金已在 rechargeBalance 记过
- */
- public static function confirmClear($clear, $payWay, $options = [])
- {
- if ($clear->status == 2) {
- util::fail('已结过账了');
- }
- if ($clear->status == 3) {
- util::fail('已取消了');
- }
- $current = time();
- if ($current >= strtotime($clear->deadline)) {
- util::fail('已过期,请手动取消');
- }
- $clear->payWay = $payWay;
- $clear->payTime = date("Y-m-d H:i:s");
- $clear->status = 2;
- // 结清时同步 onlinePay;显式传入 not(1) 时不得被微信/支付宝兜底覆盖
- if (array_key_exists('onlinePay', $options) && is_numeric($options['onlinePay'])) {
- $clear->onlinePay = intval($options['onlinePay']);
- } elseif (in_array(intval($payWay), [
- intval(dict::getDict('payWay', 'wxPay')),
- intval(dict::getDict('payWay', 'alipay')),
- ], true)) {
- $clear->onlinePay = intval(dict::getDict('onlinePay', 'yes'));
- }
- $clear->save();
- $clearId = $clear->id ?? 0;
- $customId = $clear->customId ?? 0;
- $orderSn = $clear->orderSn ?? '';
- $customName = $clear->customName ?? '';
- $custom = CustomClass::getLockById($customId);
- if (empty($custom)) {
- util::fail('没有找到客户');
- }
- $ghsId = $custom->ghsId;
- $ghs = GhsClass::getLockById($ghsId);
- if (empty($ghs)) {
- util::fail('没有找到供货商');
- }
- // true=净余额模型下的销单;false=旧链路(仍调 clearDebtAmountReduce,complete=1 当场结清等)
- $paymentSettleOnly = !empty($options['paymentSettleOnly']);
- $orderSettleRows = OrderCgClearClass::getAllByCondition(['clearId' => $clearId], null, '*', null, true);
- if (empty($orderSettleRows)) {
- util::fail('数据错误');
- }
- $clearTime = date("Y-m-d H:i:s");
- $totalSettled = '0.00';
- // 手工结账单可能 actPrice < 明细合计(抹零);合并后销单以 actPrice 为本次付款上限
- $settleBudget = bcadd((string)($clear->actPrice ?? '0'), '0', 2);
- if ($paymentSettleOnly && bccomp($settleBudget, '0', 2) <= 0) {
- $settleBudget = bcadd((string)($clear->prePrice ?? '0'), '0', 2);
- }
- foreach ($orderSettleRows as $os) {
- $orderId = intval($os->orderId ?? 0);
- $cgId = intval($os->cgId ?? 0);
- $mayClear = bcadd((string)($os->amount ?? 0), '0', 2);
- if ($orderId <= 0 || bccomp($mayClear, '0', 2) <= 0) {
- continue;
- }
- if ($paymentSettleOnly && bccomp($settleBudget, '0', 2) > 0) {
- $budgetLeft = bcsub($settleBudget, $totalSettled, 2);
- if (bccomp($budgetLeft, '0', 2) <= 0) {
- break;
- }
- if (bccomp($mayClear, $budgetLeft, 2) > 0) {
- $mayClear = $budgetLeft;
- }
- }
- $order = OrderClass::getById($orderId, true);
- if (empty($order) || ($order->debt ?? 0) == 0) {
- continue;
- }
- // 按 OrderCgClear.amount 部分或足额减少待结,不是一律置 remainDebtPrice=0
- $newRemain = bcsub((string)($order->remainDebtPrice ?? 0), $mayClear, 2);
- $orderUpdate = [
- 'remainDebtPrice' => bccomp($newRemain, '0', 2) > 0 ? $newRemain : '0.00',
- 'clearTime' => $clearTime,
- ];
- if (bccomp($newRemain, '0', 2) <= 0) {
- $orderUpdate['debt'] = 0;
- $orderUpdate['clearId'] = $clearId;
- }
- OrderClass::updateById($orderId, $orderUpdate);
- // 批发单销账后立即按 xhGhsOrder 结果写回 xhCg,与充值 FIFO 同一事务内完成
- self::syncHdPurchaseAfterOrderClear($orderId, $cgId, $clearId, $clearTime);
- $totalSettled = bcadd($totalSettled, $mayClear, 2);
- $os->amount = $mayClear;
- $os->status = 1;
- $os->save();
- }
- if (!$paymentSettleOnly) {
- // 未合并或旧当场结清:仍减少 debtAmount 字段(合并后新业务勿走此分支)
- $amount = $clear->prePrice ?? 0;
- CustomClass::clearDebtAmountReduce($custom, $ghs, $amount, $clear);
- \bizHd\ghs\classes\GhsClass::clearDebtAmountReduce($ghs, $custom, $amount, $clear);
- } else {
- // 挂账已在 balance,只根据净余额刷新欠款标记;扣款在 clearConsumeBalance
- $amount = $totalSettled;
- $custom->isDebt = bccomp($custom->balance ?? '0', '0', 2) < 0 ? CustomClass::IS_DEBT_YES : CustomClass::IS_DEBT_NO;
- $custom->save(false, ['isDebt']);
- $ghs->debt = bccomp($custom->balance ?? '0', '0', 2) < 0 ? 2 : 1;
- $ghs->save(false, ['debt']);
- }
- //现金余额增加(充值销账链路里现金已在 rechargeBalance 记过,需 skipCashMoney)
- $skipCashMoney = !empty($options['skipCashMoney']);
- if (!$skipCashMoney && $payWay == dict::getDict('payWay', 'cash')) {
- $mainId = $ghs->mainId ?? 0;
- $main = MainClass::getLockById($mainId);
- if (empty($main)) {
- util::fail('没有商家信息');
- }
- $moneyBalance = bcadd($main->money, $amount, 2);
- $main->money = $moneyBalance;
- $main->save();
- $moneyEvent = $customName . "现金结账" . floatval($amount) . "元,单号 {$orderSn})";
- $moneyRemark = '';
- $capitalType = dict::getDict('capitalType', 'ghsXsClear', 'id');
- $change = [
- 'relateId' => $clearId,
- 'amount' => $amount,
- 'balance' => $moneyBalance,
- 'io' => 1,
- 'mainId' => $mainId,
- 'capitalType' => $capitalType,
- 'ptStyle' => dict::getDict('ptStyle', 'ghs'),
- 'event' => $moneyEvent,
- 'remark' => $moneyRemark,
- ];
- ShopMoneyChangeClass::addData($change);
- }
- OrderCgClearClass::markDoneByClearId($clearId);
- }
- /**
- * 批发订单销账后同步花店采购单待结(充值 FIFO、结账单确认等)。
- * 以销账后的 xhGhsOrder 为准写回 xhCg,避免两边各自加减导致 remainDebtPrice 不一致。
- *
- * @param int $orderId 批发销售单 id(xhGhsOrder.id)
- * @param int $cgId 结账单明细上的采购单 id,缺失时按 saleId 回查 xhCg
- * @param int $clearId 结账单 id
- * @param string $clearTime 销账时间
- */
- protected static function syncHdPurchaseAfterOrderClear($orderId, $cgId, $clearId, $clearTime)
- {
- $orderId = intval($orderId);
- $cgId = intval($cgId);
- $clearId = intval($clearId);
- if ($orderId <= 0) {
- return;
- }
- $order = OrderClass::getById($orderId, true);
- if (empty($order)) {
- noticeUtil::push("批发销账后同步采购单失败:未找到销售单 orderId:{$orderId} clearId:{$clearId}", '15280215347');
- return;
- }
- $purchase = null;
- if ($cgId > 0) {
- $purchase = PurchaseClass::getById($cgId, true);
- }
- if (empty($purchase)) {
- $orderSn = $order->orderSn ?? '';
- noticeUtil::push(
- "批发销账后同步采购单失败:未找到采购单 orderId:{$orderId} orderSn:{$orderSn} cgId:{$cgId} clearId:{$clearId}",
- '15280215347'
- );
- return;
- }
- $orderRemain = bcadd((string)($order->remainDebtPrice ?? '0'), '0', 2);
- $orderDebtFlag = intval($order->debt ?? 0);
- $orderDebtPrice = bcadd((string)($order->debtPrice ?? $order->orderPrice ?? '0'), '0', 2);
- $saveFields = ['remainDebtPrice', 'clearTime', 'debt'];
- $purchase->remainDebtPrice = bccomp($orderRemain, '0', 2) > 0 ? $orderRemain : '0.00';
- $purchase->clearTime = $clearTime;
- if ($orderDebtFlag === OrderClass::DEBT_YES) {
- $purchase->debt = PurchaseClass::DEBT_YES;
- } else {
- $purchase->debt = PurchaseClass::DEBT_NO;
- $orderClearId = intval($order->clearId ?? 0);
- if ($orderClearId > 0) {
- $purchase->clearId = $orderClearId;
- } elseif ($clearId > 0) {
- $purchase->clearId = $clearId;
- }
- $saveFields[] = 'clearId';
- }
- if (bccomp((string)($purchase->debtPrice ?? '0'), '0', 2) <= 0 && bccomp($orderDebtPrice, '0', 2) > 0) {
- $purchase->debtPrice = $orderDebtPrice;
- $saveFields[] = 'debtPrice';
- }
- $purchase->save(false, array_values(array_unique($saveFields)));
- }
- }
|