|
|
@@ -932,7 +932,7 @@ class OrderService extends BaseService
|
|
|
//当天同个人同地址的订单汇总
|
|
|
$prefixDate = substr($order->payTime, 0, 10);
|
|
|
OrderClass::updateSameTimeIds($order, $prefixDate);
|
|
|
- OrderClass::updateMergeOrder($order,0);
|
|
|
+ OrderClass::updateMergeOrder($order, 0);
|
|
|
}
|
|
|
|
|
|
//发起退款
|
|
|
@@ -1022,9 +1022,10 @@ class OrderService extends BaseService
|
|
|
* 创建冲销单(金额为负的独立订单)
|
|
|
* 设计说明:不复用极其庞杂的常规开单主链路(createNewOrder->OrderClass::addOrder),
|
|
|
* 避免误伤现网所有商户的正常开单流程;只在数据落地时保持与正常订单相同的表结构,方便统一查询/统计。
|
|
|
- * @param $post array 前端提交参数:customId,product(JSON数组),remark,needPrint,payWay,forwardStock,returnBalance,relateOrderId(可选)
|
|
|
+ * @param $post array 前端提交参数:customId,product(JSON数组),remark,needPrint,payWay,forwardStock,returnBalance,
|
|
|
+ * originalRefund(可选,原路退回网关,仅线上支付+关联原单时生效),relateOrderId(可选),refundOrderId(可选)
|
|
|
* @param $custom array 客户信息(CustomClass::getCustom 返回)
|
|
|
- * @return array ['order'=>冲销单模型, 'customBalance'=>返充后的余额(未返充时为null)]
|
|
|
+ * @return array ['order'=>冲销单模型, 'customBalance'=>返充后的余额(未返充时为null), 'thirdRefundNo'=>原路退回的网关流水号(未走原路退回时为空)]
|
|
|
*/
|
|
|
public static function createForwardOrder($post, $custom)
|
|
|
{
|
|
|
@@ -1099,11 +1100,14 @@ class OrderService extends BaseService
|
|
|
|
|
|
$forwardStock = isset($post['forwardStock']) && in_array((int)$post['forwardStock'], [0, 1], true) ? (int)$post['forwardStock'] : 1;
|
|
|
$returnBalance = isset($post['returnBalance']) && (int)$post['returnBalance'] == 1 ? 1 : 0;
|
|
|
+ //原路退回(仅线上支付关联原单场景可用):是否调支付网关把这笔钱退回给付款人,与"返充到余额"二选一。ssh 冲销单功能
|
|
|
+ $originalRefund = isset($post['originalRefund']) && (int)$post['originalRefund'] == 1 ? 1 : 0;
|
|
|
$payWay = isset($post['payWay']) ? (int)$post['payWay'] : dict::getDict('payWay', 'wxPay');
|
|
|
|
|
|
//关联原单场景:累计冲销上限校验,并且强制按原单支付方式,不信任前端传的 payWay
|
|
|
$relateOrderId = $post['relateOrderId'] ?? 0;
|
|
|
$relateOrder = null;
|
|
|
+ $relateCg = null;
|
|
|
if (!empty($relateOrderId)) {
|
|
|
$relateOrder = OrderClass::getLockById($relateOrderId);
|
|
|
if (empty($relateOrder)) {
|
|
|
@@ -1112,6 +1116,16 @@ class OrderService extends BaseService
|
|
|
if ($relateOrder->mainId != $mainId || $relateOrder->customId != $customId) {
|
|
|
util::fail('原订单信息不匹配');
|
|
|
}
|
|
|
+
|
|
|
+ //服务端复核"转冲销单"资格:非当天下单 或者 欠款已结清,二者满足其一才允许,不能只靠前端拦截,
|
|
|
+ //避免绕过前端直接调接口对"今天下的、欠款还没结清"的订单发起冲销单。ssh 冲销单功能
|
|
|
+ $relatePayTime = $relateOrder->payTime ?? '';
|
|
|
+ $notToday = empty($relatePayTime) || date('Y-m-d', strtotime($relatePayTime)) != date('Y-m-d');
|
|
|
+ $debtCleared = bccomp($relateOrder->debtPrice ?? 0, '0', 2) > 0 && bccomp($relateOrder->remainDebtPrice ?? 0, '0', 2) == 0;
|
|
|
+ if (!$notToday && !$debtCleared) {
|
|
|
+ util::fail('该订单不满足转冲销单条件(需为非当天订单,或欠款已结清),请走常规售后流程');
|
|
|
+ }
|
|
|
+
|
|
|
$actPrice = $relateOrder->actPrice ?? 0;
|
|
|
$hasForwardPrice = $relateOrder->forwardPrice ?? 0;
|
|
|
if (bccomp($hasForwardPrice, $actPrice, 2) >= 0) {
|
|
|
@@ -1123,6 +1137,41 @@ class OrderService extends BaseService
|
|
|
}
|
|
|
//退款方式锁定为原单实际支付方式
|
|
|
$payWay = $relateOrder->payWay ?? $payWay;
|
|
|
+
|
|
|
+ //花店侧原采购单:下面"原路退回"网关退款、以及后面同步hasForward/forwardPrice都要用到,这里统一加锁取一次
|
|
|
+ $relateCgId = $relateOrder->purchaseId ?? 0;
|
|
|
+ if (!empty($relateCgId)) {
|
|
|
+ $relateCg = PurchaseClass::getLockById($relateCgId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //资金处理方式按原单支付渠道强制/校验,不完全信任前端传值:仅在"售后转冲销单"(带relateOrderId)场景生效,
|
|
|
+ //因为只有这种场景 payWay 才是真实原订单的支付渠道;没有关联原单的自由开冲销单,payWay 只是用户自己选的
|
|
|
+ //一个记账渠道说明,并不对应任何真实交易,不需要也不能做这里的强制/原路退回逻辑。
|
|
|
+ //挂账、余额支付:欠款本质是负余额,返充余额=冲减欠款,二者在账本层面是同一个动作,强制走"返充余额",不允许原路退回网关
|
|
|
+ //微信/支付宝:允许"原路退回"(真实网关退款)与"返充余额"二选一
|
|
|
+ if (!empty($relateOrderId)) {
|
|
|
+ $wxPay = dict::getDict('payWay', 'wxPay');
|
|
|
+ $aliPay = dict::getDict('payWay', 'alipay');
|
|
|
+ $debtPay = dict::getDict('payWay', 'debtPay');
|
|
|
+ $balancePay = dict::getDict('payWay', 'balancePay');
|
|
|
+ if (in_array($payWay, [$debtPay, $balancePay], true)) {
|
|
|
+ $returnBalance = 1;
|
|
|
+ $originalRefund = 0;
|
|
|
+ } elseif (in_array($payWay, [$wxPay, $aliPay], true)) {
|
|
|
+ if ($originalRefund == 1) {
|
|
|
+ if (empty($relateCg)) {
|
|
|
+ util::fail('没有关联原订单的真实交易信息,无法原路退回');
|
|
|
+ }
|
|
|
+ //原路退回和返充余额二选一,不能同时生效
|
|
|
+ $returnBalance = 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $originalRefund = 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //自由开冲销单:不存在"原路退回网关"这个概念,永远不生效,防止前端异常传参
|
|
|
+ $originalRefund = 0;
|
|
|
}
|
|
|
|
|
|
//落库统一取负:金额字段为负,数量字段保持正数(代表冲销的数量)
|
|
|
@@ -1151,7 +1200,7 @@ class OrderService extends BaseService
|
|
|
|
|
|
$orderData = [
|
|
|
'mainId' => $mainId,
|
|
|
- 'sendNum' => '0' . date('j') . StatOrderCountClass::addOrder(ShopClass::getLockById($shopId), MainClass::getLockById($mainId)),
|
|
|
+ 'sendNum' => '',
|
|
|
'orderSn' => $orderSn,
|
|
|
'customId' => $customId,
|
|
|
'customName' => $custom['name'] ?? '',
|
|
|
@@ -1182,7 +1231,7 @@ class OrderService extends BaseService
|
|
|
'status' => OrderClass::ORDER_STATUS_COMPLETE,
|
|
|
'payStatus' => OrderClass::PAY_STATUS_HAS_PAY,
|
|
|
'sendType' => OrderClass::SEND_TYPE_SHOP_GET,
|
|
|
- 'sendStatus' => 2,
|
|
|
+ 'sendStatus' => -4,
|
|
|
'sendTimeWant' => date('Y-m-d'),
|
|
|
'payTime' => $now,
|
|
|
'deadline' => $deadline,
|
|
|
@@ -1316,9 +1365,16 @@ class OrderService extends BaseService
|
|
|
$ghs->expendAmount = bcadd($ghs->expendAmount ?? '0.00', $actPrice, 2);
|
|
|
$ghs->save(false, ['expendAmount']);
|
|
|
|
|
|
- //余额处理:returnBalance==1 加回客户余额;==0 不改 balance,只把 payWay 记在订单上作为返款渠道记录
|
|
|
+ //资金处理:originalRefund==1 调支付网关原路退回给付款人;returnBalance==1 加回客户余额;
|
|
|
+ //两者都为0时不改动任何资金字段,只把 payWay 记在订单上作为返款渠道记录。ssh 冲销单功能
|
|
|
$customBalance = null;
|
|
|
- if ($returnBalance == 1) {
|
|
|
+ $thirdRefundNo = '';
|
|
|
+ if ($originalRefund == 1) {
|
|
|
+ //原路退回:用原单对应的采购单(xhCg)真实支付信息调网关退款,用冲销单自己的orderSn做退款流水号,天然保证唯一/幂等
|
|
|
+ $thirdRefundNo = PurchaseClass::forwardOriginalOnlineRefund($relateCg, $orderSn, $totalAmount, '冲销单' . $orderSn . '原路退回');
|
|
|
+ $order->remark = trim(($order->remark ?? '') . " [原路退回成功,网关退款单号:{$thirdRefundNo}]");
|
|
|
+ $order->save(false, ['remark']);
|
|
|
+ } elseif ($returnBalance == 1) {
|
|
|
$customBalance = CustomClass::forwardReturnBalance($lockCustom, $order, $totalAmount);
|
|
|
}
|
|
|
|
|
|
@@ -1342,23 +1398,20 @@ class OrderService extends BaseService
|
|
|
|
|
|
//同步花店侧原采购单(xhCg)的 hasForward/forwardPrice 与采购单项(xhCgItem)的 forwardNum,
|
|
|
//供 hdApp 的 purDetails.vue/refundList.vue 展示冲销记录,与 GHS 侧原单缓存字段保持一致
|
|
|
- $relateCgId = $relateOrder->purchaseId ?? 0;
|
|
|
- if (!empty($relateCgId)) {
|
|
|
- $relateCg = PurchaseClass::getById($relateCgId, true);
|
|
|
- if (!empty($relateCg)) {
|
|
|
- $relateCg->hasForward = 1;
|
|
|
- $relateCg->forwardPrice = bcadd($relateCg->forwardPrice ?? 0, $totalAmount, 2);
|
|
|
- $relateCg->save(false, ['hasForward', 'forwardPrice']);
|
|
|
-
|
|
|
- $relateCgItems = PurchaseItemClass::getAllByCondition(['orderSn' => $relateCg->orderSn], null, '*', 'productId', true);
|
|
|
- foreach ($negItems as $it) {
|
|
|
- $productId = $it['productId'] ?? 0;
|
|
|
- $relateCgItem = $relateCgItems[$productId] ?? null;
|
|
|
- if (!empty($relateCgItem)) {
|
|
|
- $relateCgItem->forward = 1;
|
|
|
- $relateCgItem->forwardNum = bcadd($relateCgItem->forwardNum ?? 0, $it['num'] ?? 0, 2);
|
|
|
- $relateCgItem->save(false, ['forward', 'forwardNum']);
|
|
|
- }
|
|
|
+ //($relateCg 已在前面校验资金处理方式时统一加锁取过,这里直接复用,避免重复查询/重复加锁)
|
|
|
+ if (!empty($relateCg)) {
|
|
|
+ $relateCg->hasForward = 1;
|
|
|
+ $relateCg->forwardPrice = bcadd($relateCg->forwardPrice ?? 0, $totalAmount, 2);
|
|
|
+ $relateCg->save(false, ['hasForward', 'forwardPrice']);
|
|
|
+
|
|
|
+ $relateCgItems = PurchaseItemClass::getAllByCondition(['orderSn' => $relateCg->orderSn], null, '*', 'productId', true);
|
|
|
+ foreach ($negItems as $it) {
|
|
|
+ $productId = $it['productId'] ?? 0;
|
|
|
+ $relateCgItem = $relateCgItems[$productId] ?? null;
|
|
|
+ if (!empty($relateCgItem)) {
|
|
|
+ $relateCgItem->forward = 1;
|
|
|
+ $relateCgItem->forwardNum = bcadd($relateCgItem->forwardNum ?? 0, $it['num'] ?? 0, 2);
|
|
|
+ $relateCgItem->save(false, ['forward', 'forwardNum']);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -1396,7 +1449,7 @@ class OrderService extends BaseService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return ['order' => $order, 'customBalance' => $customBalance];
|
|
|
+ return ['order' => $order, 'customBalance' => $customBalance, 'thirdRefundNo' => $thirdRefundNo];
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
+}
|