feat(haichao): 新增聚水潭ERP集成功能
- 新增聚水潭回调接口及事件处理机制 - 添加聚水潭商品、订单、售后同步任务 - 实现聚水潭订单推送及售后状态同步 - 新增手动同步聚水潭商品功能 - 在各路由组添加聚水潭中间件支持
This commit is contained in:
40
app/haichao/callback/JstCallbackEventManager.php
Normal file
40
app/haichao/callback/JstCallbackEventManager.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback;
|
||||
|
||||
use app\haichao\callback\event\JstEvent;
|
||||
use app\haichao\callback\event\JstOrderPostEvent;
|
||||
use app\haichao\callback\event\JstOrderCancelEvent;
|
||||
use app\haichao\callback\event\JstOrderRefundEvent;
|
||||
use app\haichao\callback\event\JstProductEvent;
|
||||
use app\haichao\callback\event\JstTradeEvent;
|
||||
use app\Request;
|
||||
use ReflectionClass;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
use think\response\Json;
|
||||
|
||||
abstract class JstCallbackEventManager
|
||||
{
|
||||
public static array $eventList = [
|
||||
'business_sku_syn' => JstProductEvent::class,
|
||||
'trade_after_sale' => JstTradeEvent::class,
|
||||
'orderCancel' => JstOrderCancelEvent::class,
|
||||
'orderPost' => JstOrderPostEvent::class,
|
||||
'orderRefund' => JstOrderRefundEvent::class,
|
||||
];
|
||||
|
||||
public static function callback(Request $request): Json
|
||||
{
|
||||
$actionCode = $request->getMore([['action_code', false]])['action_code'] ?? '';
|
||||
Log::info('JST callback ' . $actionCode);
|
||||
if ($actionCode && isset(self::$eventList[$actionCode])) {
|
||||
$reflectionClass = new ReflectionClass(self::$eventList[$actionCode]);
|
||||
/** @var JstEvent $eventObj */
|
||||
$eventObj = $reflectionClass->newInstance();
|
||||
$eventObj->event($request);
|
||||
return json(['code' => 0, 'msg' => 'ok']);
|
||||
}
|
||||
throw new ValidateException('unknown action_code');
|
||||
}
|
||||
}
|
||||
10
app/haichao/callback/event/JstEvent.php
Normal file
10
app/haichao/callback/event/JstEvent.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback\event;
|
||||
|
||||
use app\Request;
|
||||
|
||||
interface JstEvent
|
||||
{
|
||||
public function event(Request $request);
|
||||
}
|
||||
23
app/haichao/callback/event/JstOrderCancelEvent.php
Normal file
23
app/haichao/callback/event/JstOrderCancelEvent.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback\event;
|
||||
|
||||
use app\Request;
|
||||
use app\services\erp\OrderServices;
|
||||
|
||||
class JstOrderCancelEvent implements JstEvent
|
||||
{
|
||||
public function event(Request $request): array
|
||||
{
|
||||
$soId = $request->getMore([['so_id', false]])['so_id'];
|
||||
if ($soId) {
|
||||
/** @var OrderServices $orderServices */
|
||||
$orderServices = app()->make(OrderServices::class);
|
||||
$orderServices->cancelCallback($request->postMore([
|
||||
['so_id', 0],
|
||||
['remark', ''],
|
||||
]));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
296
app/haichao/callback/event/JstOrderPostEvent.php
Normal file
296
app/haichao/callback/event/JstOrderPostEvent.php
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback\event;
|
||||
|
||||
use app\Request;
|
||||
use app\services\order\StoreOrderCartInfoServices;
|
||||
use app\services\order\StoreOrderDeliveryServices;
|
||||
use app\services\order\StoreOrderRefundServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Log;
|
||||
|
||||
class JstOrderPostEvent implements JstEvent
|
||||
{
|
||||
public function event(Request $request)
|
||||
{
|
||||
$payload = [];
|
||||
$content = (string)$request->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oId = $request->getMore([['o_id', false]])['o_id'] ?: (string)($payload['o_id'] ?? $biz['o_id'] ?? ($payload['oId'] ?? $biz['oId'] ?? ''));
|
||||
$logisticsCompany = $request->getMore([['logistics_company', false]])['logistics_company'] ?: (string)($payload['logistics_company'] ?? $biz['logistics_company'] ?? ($payload['logisticsCompany'] ?? $biz['logisticsCompany'] ?? ''));
|
||||
$lId = $request->getMore([['l_id', false]])['l_id'] ?: (string)($payload['l_id'] ?? $biz['l_id'] ?? ($payload['lId'] ?? $biz['lId'] ?? ''));
|
||||
$lcId = $request->getMore([['lc_id', false]])['lc_id'] ?: (string)($payload['lc_id'] ?? $biz['lc_id'] ?? ($payload['lcId'] ?? $biz['lcId'] ?? ''));
|
||||
$soId = $request->getMore([['so_id', false]])['so_id'] ?: (string)($payload['so_id'] ?? $biz['so_id'] ?? ($payload['soId'] ?? $biz['soId'] ?? ''));
|
||||
$items = $request->getMore([['items', false]])['items'] ?: ($payload['items'] ?? $biz['items'] ?? ($payload['item_list'] ?? $biz['item_list'] ?? []));
|
||||
if (!is_array($items)) {
|
||||
$items = [];
|
||||
}
|
||||
|
||||
$skus = [];
|
||||
if (is_array($items)) {
|
||||
foreach ($items as $it) {
|
||||
$skus[] = ['sku' => $it['sku_id'] ?? '', 'qty' => (int)($it['qty'] ?? 0)];
|
||||
}
|
||||
}
|
||||
Log::info('jst.cb.orderPost.start ' . json_encode([
|
||||
'so_id' => $soId,
|
||||
'o_id' => $oId,
|
||||
'logistics_company' => $logisticsCompany,
|
||||
'l_id' => $lId,
|
||||
'lc_id' => $lcId,
|
||||
'item_count' => is_array($items) ? count($items) : 0,
|
||||
'sku_list' => $skus,
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
|
||||
/** @var StoreOrderServices $storeOrderServices */
|
||||
$storeOrderServices = app()->make(StoreOrderServices::class);
|
||||
/** @var StoreOrderDeliveryServices $orderDeliverServices */
|
||||
$orderDeliverServices = app()->make(StoreOrderDeliveryServices::class);
|
||||
/** @var StoreOrderRefundServices $storeOrderRefundServices */
|
||||
$storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
|
||||
/** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */
|
||||
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
||||
|
||||
if ($soId === '') {
|
||||
Log::info('jst.cb.orderPost.skip ' . json_encode(['reason' => 'missing so_id'], JSON_UNESCAPED_UNICODE));
|
||||
return 'missing so_id';
|
||||
}
|
||||
|
||||
$orderInfo = $storeOrderServices->getOne(['order_id' => $soId]);
|
||||
if (!$orderInfo) throw new ValidateException('order not found ' . $soId);
|
||||
$oid = $orderInfo['id'];
|
||||
$splitOrderList = $storeOrderServices->getSplitOrderList(['pid' => $oid]);
|
||||
$nol = [];
|
||||
foreach ($splitOrderList as $splitOrder) {
|
||||
if ($splitOrder['status'] === 0) $nol[] = $splitOrder;
|
||||
}
|
||||
$splitOrderList = $nol;
|
||||
Log::info('jst.cb.orderPost.split.count ' . json_encode(['so_id' => $soId, 'count' => count($splitOrderList)], JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$cardIds = $orderInfo['cart_id'];
|
||||
$num = 0;
|
||||
foreach ($cardIds as $cardId) {
|
||||
$cardInfo = $storeOrderCartInfoServices->getOne(['cart_id' => $cardId])->toArray();
|
||||
$num += $cardInfo['cart_num'];
|
||||
}
|
||||
$num2 = 0;
|
||||
foreach ($items as $item) {
|
||||
$num2 += $item['qty'];
|
||||
}
|
||||
if ($num !== $num2) {
|
||||
Log::warning('jst.cb.orderPost.qty_mismatch ' . json_encode(['so_id' => $soId, 'order_cart_num' => $num, 'ship_qty_sum' => $num2], JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
$existSo = false;
|
||||
if ($splitOrderList) {
|
||||
foreach ($splitOrderList as $splitOrder) {
|
||||
if ($splitOrder['order_id'] == $soId) {
|
||||
$existSo = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$existSo = true;
|
||||
}
|
||||
if (!$existSo) {
|
||||
Log::warning('jst.cb.orderPost.no_exist_so ' . json_encode(['so_id' => $soId], JSON_UNESCAPED_UNICODE));
|
||||
foreach ($splitOrderList as $item) {
|
||||
foreach ($item['cart_id'] as $cartId) {
|
||||
$cartInfo = $item['_info'][$cartId]['cart_info'];
|
||||
$productInfo = $cartInfo['productInfo'];
|
||||
$cartfa = [];
|
||||
foreach ($items as $sentProduct) {
|
||||
if ($productInfo['attrInfo']['suk'] == $sentProduct['sku_id'] ||
|
||||
$productInfo['attrInfo']['code'] == $sentProduct['sku_id'] ||
|
||||
($productInfo['attrInfo']['unique'] . 'ok') == $sentProduct['sku_id']) {
|
||||
$cartfa[] = [
|
||||
'cart_id' => $cartId,
|
||||
'cart_num' => $sentProduct['qty'],
|
||||
];
|
||||
}
|
||||
}
|
||||
try {
|
||||
$deliverArgs = [
|
||||
'type' => 1,
|
||||
'delivery_name' => $logisticsCompany,
|
||||
'delivery_id' => $lId,
|
||||
'delivery_code' => $lcId,
|
||||
'express_record_type' => "1",
|
||||
'express_temp_id' => md5(time()),
|
||||
'cart_ids' => $cartfa
|
||||
];
|
||||
$orderDeliverServices->splitDelivery($item['id'], $deliverArgs, 0, true);
|
||||
Log::info('jst.cb.orderPost.success ' . json_encode(['so_id' => $soId, 'oid' => (int)$item['id'], 'mode' => 'split'], JSON_UNESCAPED_UNICODE));
|
||||
return 'ok';
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error('jst.cb.orderPost.split.error ' . json_encode(['oid' => $item['id'], 'msg' => $exception->getMessage()], JSON_UNESCAPED_UNICODE));
|
||||
throw new ValidateException('split delivery error ' . $exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::warning('jst.cb.orderPost.no_match.split ' . json_encode(['so_id' => $soId], JSON_UNESCAPED_UNICODE));
|
||||
return 'no match';
|
||||
}
|
||||
try {
|
||||
if (count($splitOrderList) > 1 || count($orderInfo['cart_id']) > 1) {
|
||||
if (count($splitOrderList) > 0) {
|
||||
foreach ($splitOrderList as $item) {
|
||||
foreach ($item['cart_id'] as $cartId) {
|
||||
$cartInfo = $item['_info'][$cartId]['cart_info'];
|
||||
$productInfo = $cartInfo['productInfo'];
|
||||
foreach ($items as $postItem) {
|
||||
$postItemSku = $postItem['sku_id'];
|
||||
if ($productInfo['attrInfo']['suk'] == $postItemSku || $productInfo['attrInfo']['code'] == $postItemSku) {
|
||||
try {
|
||||
$deliverArgs = [
|
||||
'type' => 1,
|
||||
'delivery_name' => $logisticsCompany,
|
||||
'delivery_id' => $lId,
|
||||
'delivery_code' => $lcId,
|
||||
'express_record_type' => "1",
|
||||
'express_temp_id' => md5(time()),
|
||||
'cart_ids' => [
|
||||
[
|
||||
'cart_id' => $cartId,
|
||||
'cart_num' => $cartInfo['cart_num'],
|
||||
]
|
||||
]
|
||||
];
|
||||
$orderDeliverServices->splitDelivery($oid, $deliverArgs, 0, true);
|
||||
Log::info('jst.cb.orderPost.success ' . json_encode(['so_id' => $soId, 'oid' => (int)$oid, 'mode' => 'split.pid', 'cart_id' => (int)$cartId], JSON_UNESCAPED_UNICODE));
|
||||
return 'ok';
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error('jst.cb.orderPost.split.pid.error ' . json_encode(['pid' => $oid, 'cart_id' => $cartId, 'msg' => $exception->getMessage()], JSON_UNESCAPED_UNICODE));
|
||||
throw new ValidateException('split delivery error ' . $exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::warning('jst.cb.orderPost.no_match.pid ' . json_encode(['so_id' => $soId, 'pid' => (int)$oid], JSON_UNESCAPED_UNICODE));
|
||||
return 'no match';
|
||||
}
|
||||
if (count($orderInfo['cart_id']) > 1) {
|
||||
$cartfa = [];
|
||||
foreach ($items as $sentProduct) {
|
||||
foreach ($orderInfo['cart_id'] as $cartId) {
|
||||
$cartInfo = $storeOrderCartInfoServices->getOne(['cart_id' => $cartId]);
|
||||
$productInfo = $cartInfo['cart_info']['productInfo'] ?? [];
|
||||
if (!$productInfo) continue;
|
||||
if ($productInfo['attrInfo']['suk'] == $sentProduct['sku_id'] ||
|
||||
$productInfo['attrInfo']['code'] == $sentProduct['sku_id'] ||
|
||||
($productInfo['attrInfo']['unique'] . 'ok') == $sentProduct['sku_id']) {
|
||||
$cartfa[] = [
|
||||
'cart_id' => $cartId,
|
||||
'cart_num' => $cartInfo['cart_num'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::info('jst.cb.orderPost.multi.mapping ' . json_encode(['pid' => $oid, 'match' => $cartfa], JSON_UNESCAPED_UNICODE));
|
||||
try {
|
||||
$deliverArgs = [
|
||||
'type' => 1,
|
||||
'delivery_id' => $lId,
|
||||
'delivery_code' => $lcId,
|
||||
'express_record_type' => "1",
|
||||
'express_temp_id' => md5(time()),
|
||||
'cart_ids' => $cartfa
|
||||
];
|
||||
$orderDeliverServices->splitDelivery($oid, $deliverArgs, 0, true);
|
||||
Log::info('jst.cb.orderPost.success ' . json_encode(['so_id' => $soId, 'oid' => (int)$oid, 'mode' => 'multi'], JSON_UNESCAPED_UNICODE));
|
||||
return 'ok';
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error('jst.cb.orderPost.multi.error ' . json_encode(['pid' => $oid, 'msg' => $exception->getMessage()], JSON_UNESCAPED_UNICODE));
|
||||
throw new ValidateException('split delivery error ' . $exception->getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($num == $num2) {
|
||||
$deliverArgs = [
|
||||
'type' => 1,
|
||||
'delivery_name' => $logisticsCompany,
|
||||
'delivery_id' => $lId,
|
||||
'delivery_code' => $lcId,
|
||||
'express_record_type' => "1",
|
||||
'express_temp_id' => md5(time()),
|
||||
];
|
||||
$orderDeliverServices->delivery($oid, $deliverArgs);
|
||||
Log::info('jst.cb.orderPost.success ' . json_encode(['so_id' => $soId, 'oid' => (int)$oid, 'mode' => 'delivery'], JSON_UNESCAPED_UNICODE));
|
||||
return 'ok';
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
if ($e->getMessage() != '订单已发货请勿重复操作!') {
|
||||
Log::error('jst.cb.orderPost.error ' . json_encode(['oid' => $oid, 'msg' => $e->getMessage()], JSON_UNESCAPED_UNICODE));
|
||||
throw new ValidateException($e->getMessage());
|
||||
}
|
||||
Log::info('jst.cb.orderPost.repeat ' . json_encode(['so_id' => $soId, 'oid' => (int)$oid], JSON_UNESCAPED_UNICODE));
|
||||
return 'ok';
|
||||
}
|
||||
$cardIds = $orderInfo['cart_id'];
|
||||
if (count($cardIds) >= 1) {
|
||||
$cartfa = [];
|
||||
foreach ($cardIds as $cartId) {
|
||||
$cardInfo = $storeOrderCartInfoServices->getOne(['cart_id' => $cartId])->toArray();
|
||||
$productInfo = $cardInfo['cart_info']['productInfo'] ?? [];
|
||||
foreach ($items as $sentProduct) {
|
||||
if ($productInfo['attrInfo']['suk'] == $sentProduct['sku_id'] ||
|
||||
$productInfo['attrInfo']['code'] == $sentProduct['sku_id'] ||
|
||||
($productInfo['attrInfo']['unique'] . 'ok') == $sentProduct['sku_id']) {
|
||||
$cartfa[] = [
|
||||
'cart_id' => $cartId,
|
||||
'cart_num' => $sentProduct['qty'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
$deliverArgs = [
|
||||
'type' => 1,
|
||||
'delivery_name' => $logisticsCompany,
|
||||
'delivery_id' => $lId,
|
||||
'delivery_code' => $lcId,
|
||||
'express_record_type' => "1",
|
||||
'express_temp_id' => md5(time()),
|
||||
'cart_ids' => $cartfa
|
||||
];
|
||||
$orderDeliverServices->splitDelivery($oid, $deliverArgs);
|
||||
Log::info('jst.cb.orderPost.success ' . json_encode(['so_id' => $soId, 'oid' => (int)$oid, 'mode' => 'cartfa'], JSON_UNESCAPED_UNICODE));
|
||||
return 'ok';
|
||||
} catch (\Throwable $exception) {
|
||||
Log::error('jst.cb.orderPost.cartfa.error ' . json_encode(['pid' => $oid, 'msg' => $exception->getMessage()], JSON_UNESCAPED_UNICODE));
|
||||
throw new ValidateException('split delivery error ' . $exception->getMessage());
|
||||
}
|
||||
}
|
||||
Log::warning('jst.cb.orderPost.unknown ' . json_encode(['so_id' => $soId], JSON_UNESCAPED_UNICODE));
|
||||
throw new ValidateException('unknown delivery ' . $soId);
|
||||
}
|
||||
}
|
||||
27
app/haichao/callback/event/JstOrderRefundEvent.php
Normal file
27
app/haichao/callback/event/JstOrderRefundEvent.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback\event;
|
||||
|
||||
use app\Request;
|
||||
use app\services\order\StoreOrderServices;
|
||||
|
||||
class JstOrderRefundEvent implements JstEvent
|
||||
{
|
||||
public function event(Request $request): array
|
||||
{
|
||||
$actionName = $request->getMore(['action_name'])['action_name'];
|
||||
switch ($actionName) {
|
||||
case '确认收货':
|
||||
{
|
||||
/** @var StoreOrderServices $storeOrderServices */
|
||||
$storeOrderServices = app()->make(StoreOrderServices::class);
|
||||
$orderInfo = $storeOrderServices->getOne(['erp_id' => $request->getMore([['o_id', -1]])['o_id']]);
|
||||
if ($orderInfo) {
|
||||
$storeOrderServices->update(['id' => $orderInfo['id']], ['status' => 3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
48
app/haichao/callback/event/JstProductEvent.php
Normal file
48
app/haichao/callback/event/JstProductEvent.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback\event;
|
||||
|
||||
use app\Request;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use think\facade\Log;
|
||||
use Throwable;
|
||||
|
||||
class JstProductEvent implements JstEvent
|
||||
{
|
||||
public function event(Request $request): array
|
||||
{
|
||||
try {
|
||||
$param = $request->param();
|
||||
$body = json_decode((string)($param['biz'] ?? '{}'), true);
|
||||
$skuId = (string)($body['skuId'] ?? '');
|
||||
$stock = (int)($body['qty'] ?? 0);
|
||||
if (!$skuId) {
|
||||
$cont = $request->getContent();
|
||||
$output = [];
|
||||
parse_str($cont, $output);
|
||||
$body = json_decode((string)($output['biz'] ?? '{}'), true);
|
||||
$skuId = (string)($body['skuId'] ?? '');
|
||||
$stock = (int)($body['qty'] ?? 0);
|
||||
}
|
||||
if (!$skuId) return [];
|
||||
/** @var StoreProductAttrValueServices $spas */
|
||||
$spas = app()->make(StoreProductAttrValueServices::class);
|
||||
$model = $spas->getOne(['code' => $skuId]);
|
||||
if ($model) {
|
||||
$pdt = $model->toArray();
|
||||
$id = $pdt['id'] ?? 0;
|
||||
if ($id) {
|
||||
$spas->update($id, [
|
||||
'stock' => $stock,
|
||||
'sum_stock' => $stock
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Log::error('jst.cb.product_stock.error ' . json_encode([
|
||||
'msg' => $e->getMessage(),
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
298
app/haichao/callback/event/JstTradeEvent.php
Normal file
298
app/haichao/callback/event/JstTradeEvent.php
Normal file
@@ -0,0 +1,298 @@
|
||||
<?php
|
||||
|
||||
namespace app\haichao\callback\event;
|
||||
|
||||
use app\Request;
|
||||
use app\services\erp\OrderServices;
|
||||
use app\services\order\StoreOrderCartInfoServices;
|
||||
use app\services\order\StoreOrderRefundServices;
|
||||
use app\services\order\StoreOrderServices;
|
||||
use think\facade\Log;
|
||||
|
||||
class JstTradeEvent implements JstEvent
|
||||
{
|
||||
public function event(Request $request): array
|
||||
{
|
||||
$payload = [];
|
||||
$content = (string)$request->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 [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user