getContent(); if ($content !== '') { $decoded = json_decode($content, true); if (is_array($decoded)) { $payload = $decoded; } else { $output = []; parse_str($content, $output); if (is_array($output)) { $payload = $output; } } } if (!$payload) { $payload = $request->param(); } $biz = []; if (isset($payload['biz']) && $payload['biz'] !== '') { if (is_array($payload['biz'])) { $biz = $payload['biz']; } else { $bizDecoded = json_decode((string)$payload['biz'], true); if (is_array($bizDecoded)) { $biz = $bizDecoded; } } } $actionName = (string)($payload['action_name'] ?? $biz['action_name'] ?? ($payload['action'] ?? $biz['action'] ?? '')); $shopStatus = strtoupper((string)($payload['shop_status'] ?? $biz['shop_status'] ?? ($payload['shopStatus'] ?? $biz['shopStatus'] ?? ''))); $outerAsId = (string)($payload['outer_as_id'] ?? $biz['outer_as_id'] ?? ($payload['outerAsId'] ?? $biz['outerAsId'] ?? '')); $soId = (string)($payload['so_id'] ?? $biz['so_id'] ?? ($payload['soId'] ?? $biz['soId'] ?? '')); $bizStatus = strtoupper((string)($biz['status'] ?? $payload['status'] ?? '')); $bizType = (string)($biz['type'] ?? ''); $bizRemark = (string)($biz['remark'] ?? ''); Log::info('jst.cb.trade_after_sale.start ' . json_encode([ 'action_name' => $actionName, 'shop_status' => $shopStatus, 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'biz_status' => $bizStatus, 'biz_type' => $bizType, 'content_len' => strlen($content), ], JSON_UNESCAPED_UNICODE)); if ($outerAsId === '') { Log::info('jst.cb.trade_after_sale.skip ' . json_encode([ 'reason' => 'missing outer_as_id', 'shop_status' => $shopStatus, 'action_name' => $actionName, ], JSON_UNESCAPED_UNICODE)); return []; } try { $applyType = 1; if ($bizType !== '') { if (mb_strpos($bizType, '仅退款') !== false) { $applyType = 1; } elseif (mb_strpos($bizType, '退货') !== false) { $applyType = 2; } } /** @var StoreOrderServices $storeOrderServices */ $storeOrderServices = app()->make(StoreOrderServices::class); $soIdsToTry = array_values(array_filter(array_unique([ $soId, (string)(explode('_', $soId)[0] ?? ''), ]))); $order = null; foreach ($soIdsToTry as $trySoId) { $order = $storeOrderServices->getOne(['erp_order_id' => $trySoId], 'id,uid,store_id,supplier_id,order_id,erp_order_id,total_num,pay_price,pay_postage,channel,pid'); if ($order) break; $order = $storeOrderServices->getOne(['order_id' => $trySoId], 'id,uid,store_id,supplier_id,order_id,erp_order_id,total_num,pay_price,pay_postage,channel,pid'); if ($order) break; } if (!$order) { Log::error('jst.cb.trade_after_sale.order_missing ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'biz_status' => $bizStatus, 'biz_type' => $bizType, ], JSON_UNESCAPED_UNICODE)); return []; } /** @var StoreOrderRefundServices $storeOrderRefundServices */ $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class); $orderRefund = $storeOrderRefundServices->getOne(['order_id' => $outerAsId]); if (!$orderRefund) { /** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */ $storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class); $items = $biz['items'] ?? []; $skuQtyMap = []; if (is_array($items)) { foreach ($items as $item) { if (!is_array($item)) continue; $sku = (string)($item['sku_id'] ?? $item['skuId'] ?? ''); $qty = (int)($item['qty'] ?? 0); if ($sku !== '' && $qty > 0) { $skuQtyMap[$sku] = ($skuQtyMap[$sku] ?? 0) + $qty; } } } $targetOrder = $order; $leftSkuQtyMap = $skuQtyMap; $cartInfos = $storeOrderCartInfoServices->getCartColunm(['oid' => (int)$order['id']], 'id,cart_id,cart_num,cart_info'); foreach ($cartInfos as &$cartInfo) { $cartInfo['cart_info'] = is_string($cartInfo['cart_info']) ? json_decode($cartInfo['cart_info'], true) : $cartInfo['cart_info']; } unset($cartInfo); if ($skuQtyMap && (int)($order['pid'] ?? 0) === -1) { $candidateOrders = [$order]; $subOrders = $storeOrderServices->getColumn(['pid' => (int)$order['id'], 'is_system_del' => 0], 'id,uid,store_id,supplier_id,order_id,erp_order_id,total_num,pay_price,pay_postage,channel,pid'); if ($subOrders && is_array($subOrders)) { $candidateOrders = array_merge($candidateOrders, $subOrders); } $bestScore = -1; $bestCartInfos = $cartInfos; $bestLeftSkuQtyMap = $skuQtyMap; foreach ($candidateOrders as $cand) { if (!is_array($cand) || !isset($cand['id'])) continue; $candCartInfos = $storeOrderCartInfoServices->getCartColunm(['oid' => (int)$cand['id']], 'id,cart_id,cart_num,cart_info'); foreach ($candCartInfos as &$candCartInfo) { $candCartInfo['cart_info'] = is_string($candCartInfo['cart_info']) ? json_decode($candCartInfo['cart_info'], true) : $candCartInfo['cart_info']; } unset($candCartInfo); $need = $skuQtyMap; $score = 0; foreach ($candCartInfos as $candCart) { $ci = $candCart['cart_info']; if (!is_array($ci)) continue; $sku = (string)($ci['productInfo']['attrInfo']['code'] ?? $ci['productInfo']['attrInfo']['sku'] ?? $ci['productInfo']['sku'] ?? ''); if ($sku === '' || !isset($need[$sku]) || (int)$need[$sku] <= 0) continue; $cartNum = (int)($candCart['cart_num'] ?? 0); $useNum = min($cartNum, (int)$need[$sku]); if ($useNum <= 0) continue; $score += $useNum; $need[$sku] -= $useNum; } if ($score > $bestScore) { $bestScore = $score; $targetOrder = $cand; $bestCartInfos = $candCartInfos; $bestLeftSkuQtyMap = $need; } } $cartInfos = $bestCartInfos; $leftSkuQtyMap = $bestLeftSkuQtyMap; Log::info('jst.cb.trade_after_sale.split_match ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'best_score' => $bestScore, 'target_store_order_id' => (int)($targetOrder['id'] ?? 0), 'target_order_id' => (string)($targetOrder['order_id'] ?? ''), 'target_erp_order_id' => (string)($targetOrder['erp_order_id'] ?? ''), ], JSON_UNESCAPED_UNICODE)); } $selectedCartInfo = []; if ($skuQtyMap) { foreach ($cartInfos as $cart) { $ci = $cart['cart_info']; if (!is_array($ci)) continue; $sku = (string)($ci['productInfo']['attrInfo']['code'] ?? $ci['productInfo']['attrInfo']['sku'] ?? $ci['productInfo']['sku'] ?? ''); if ($sku === '' || !isset($skuQtyMap[$sku])) continue; $cartNum = (int)($cart['cart_num'] ?? 0); $applyNum = min($cartNum, (int)$skuQtyMap[$sku]); if ($applyNum <= 0) continue; $ci['id'] = $ci['id'] ?? (int)($cart['id'] ?? 0); $ci['cart_id'] = $ci['cart_id'] ?? (int)($cart['cart_id'] ?? 0); $ci['cart_num'] = $applyNum; $selectedCartInfo[] = $ci; $skuQtyMap[$sku] -= $applyNum; } } if (!$selectedCartInfo) { $selectedCartInfo = array_values(array_filter(array_column($cartInfos, 'cart_info'), 'is_array')); } $refundNum = 0; $refundPrice = 0.00; foreach ($selectedCartInfo as $ci) { $refundNum += (int)($ci['cart_num'] ?? 0); if (isset($ci['truePrice'])) { $refundPrice = bcadd((string)$refundPrice, bcmul((string)$ci['truePrice'], (string)($ci['cart_num'] ?? 0), 4), 2); } } if ($refundPrice <= 0 && (int)($targetOrder['total_num'] ?? 0) > 0 && $refundNum > 0) { $refundPrice = (float)bcmul((string)$targetOrder['pay_price'], bcdiv((string)$refundNum, (string)$targetOrder['total_num'], 6), 2); } $refundData = [ 'uid' => (int)$targetOrder['uid'], 'store_id' => (int)$targetOrder['store_id'], 'supplier_id' => (int)($targetOrder['supplier_id'] ?? 0), 'store_order_id' => (int)$targetOrder['id'], 'refund_num' => $refundNum > 0 ? $refundNum : (int)($targetOrder['total_num'] ?? 0), 'apply_type' => $applyType, 'refund_type' => $applyType, 'refund_goods_type' => in_array($applyType, [2, 3]) ? $applyType : 1, 'apply_price' => $refundPrice, 'refund_price' => $refundPrice, 'refund_reason' => $bizRemark !== '' ? $bizRemark : '聚水潭发起售后', 'order_id' => $outerAsId, 'add_time' => time(), 'cart_info' => json_encode($selectedCartInfo, JSON_UNESCAPED_UNICODE), 'channel' => (int)($targetOrder['channel'] ?? 0), ]; $res = $storeOrderRefundServices->save($refundData); $orderRefund = $storeOrderRefundServices->get((int)$res->id); Log::info('jst.cb.trade_after_sale.refund_created ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'store_order_id' => (int)$targetOrder['id'], 'refund_id' => (int)$res->id, 'apply_type' => $applyType, 'refund_num' => $refundData['refund_num'], 'refund_price' => $refundData['refund_price'], ], JSON_UNESCAPED_UNICODE)); } if ($shopStatus === 'CLOSED' || $bizStatus === 'CLOSED') { $storeOrderRefundServices->update((int)$orderRefund['id'], [ 'refund_type' => 3, 'refuse_reason' => $bizRemark !== '' ? $bizRemark : '聚水潭关闭售后', 'refunded_time' => time(), ]); Log::info('jst.cb.trade_after_sale.refund_closed ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'refund_id' => (int)$orderRefund['id'], ], JSON_UNESCAPED_UNICODE)); return []; } if (in_array($bizStatus, ['REFUNDED', 'REFUND_SUCCESS', 'FINISHED', 'COMPLETED'], true)) { /** @var OrderServices $orderServices */ $orderServices = app()->make(OrderServices::class); $ok = (bool)$orderServices->receivedCallback(['outer_as_id' => $outerAsId, 'so_id' => $soId], 1, $soId !== ''); Log::info('jst.cb.trade_after_sale.refund_finalize ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'refund_id' => (int)$orderRefund['id'], 'success' => $ok ? 1 : 0, ], JSON_UNESCAPED_UNICODE)); } else { Log::info('jst.cb.trade_after_sale.synced ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'refund_id' => (int)$orderRefund['id'], 'apply_type' => (int)($orderRefund['apply_type'] ?? 0), 'refund_type' => (int)($orderRefund['refund_type'] ?? 0), ], JSON_UNESCAPED_UNICODE)); } } catch (\Throwable $e) { Log::error('jst.cb.trade_after_sale.error ' . json_encode([ 'outer_as_id' => $outerAsId, 'so_id' => $soId, 'action_name' => $actionName, 'shop_status' => $shopStatus, 'biz_status' => $bizStatus, 'biz_type' => $bizType, 'error' => [ 'class' => get_class($e), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), ], ], JSON_UNESCAPED_UNICODE)); } return []; } }