You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
839 lines
35 KiB
839 lines
35 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
|
// +----------------------------------------------------------------------
|
|
// | Author: CRMEB Team <admin@crmeb.com>
|
|
// +----------------------------------------------------------------------
|
|
declare (strict_types=1);
|
|
|
|
namespace app\services\erp;
|
|
|
|
use app\jobs\order\OrderSyncJob;
|
|
use app\services\order\StoreOrderCartInfoServices;
|
|
use app\services\order\StoreOrderCreateServices;
|
|
use app\services\order\StoreOrderDeliveryServices;
|
|
use app\services\order\StoreOrderRefundServices;
|
|
use app\services\order\StoreOrderServices;
|
|
use crmeb\exceptions\AdminException;
|
|
use crmeb\services\erp\Erp as erpServices;
|
|
use think\facade\Log;
|
|
|
|
/**
|
|
* Class OrderServices
|
|
* @package app\services\erp
|
|
*/
|
|
class OrderServices
|
|
{
|
|
protected $services;
|
|
|
|
/**
|
|
* OrderServices constructor.
|
|
* @param erpServices $services
|
|
*/
|
|
public function __construct(erpServices $services)
|
|
{
|
|
$this->services = $services;
|
|
}
|
|
|
|
/**
|
|
* 订单上传
|
|
* @param int $oid
|
|
* @return bool
|
|
* @throws \Exception
|
|
*/
|
|
public function upload(int $oid): bool
|
|
{
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
$order = $orderServices->get($oid, ['*'], ['store']);
|
|
|
|
if ($order['id'] < 1) {
|
|
throw new AdminException('订单信息不能为空!');
|
|
}
|
|
|
|
// 过滤已退款订单和虚拟商品
|
|
if ($order['refund_status'] == 2 || $order['product_type'] > 0) {
|
|
return true;
|
|
}
|
|
|
|
$biz = [
|
|
'shop_id' => $this->getShopId($order->store->erp_shop_id ?? 0), // 店铺编号
|
|
'so_id' => $this->getErpOrderId($order['order_id'], $order['erp_order_id']), // 线上订单号, 长度 <= 50
|
|
'shop_status' => 'WAIT_SELLER_SEND_GOODS', // 订单状态 待发货
|
|
'buyer_message' => $order['mark'], // 买家留言
|
|
'shop_buyer_id' => (string)$order['uid'], // 买家帐号
|
|
'receiver_name' => $order['real_name'], // 收件人
|
|
'receiver_mobile' => $order['user_phone'], // 联系手机
|
|
'pay_amount' => (float)$order['pay_price'], // 应付金额,保留两位小数,单位元)
|
|
'freight' => (float)$order['freight_price'], // 运费
|
|
'order_date' => date('Y-m-d H:i:s', $order['add_time']), // 订单日期
|
|
'shop_modified' => date('Y-m-d H:i:s', $order['add_time']), // 订单修改日期
|
|
'items' => $this->getItems($oid, (int)$order['uid'], $order['unique']),
|
|
'pay' => [
|
|
'outer_pay_id' => 'xxx', // 外部支付单号,最大50
|
|
'pay_date' => date('Y-m-d H:i:s', $order['pay_time']), // 支付日期
|
|
'payment' => $order['pay_type'], // 支付方式,最大20
|
|
'seller_account' => 'seller', // 卖家支付账号,最大 50
|
|
'buyer_account' => 'buyer', // 买家支付账号,最大 200
|
|
'amount' => (float)$order['pay_price'] // 支付总额
|
|
]
|
|
];
|
|
|
|
$biz = array_merge($biz, $this->getAddress($order['user_address']));
|
|
|
|
$num = 3;
|
|
for ($i = $num; $i >= 0; $i--) {
|
|
if ($i <= 0) {
|
|
Log::error(['msg' => 'ERP订单上传失败,调用均为异常', 'oid' => $oid]);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$result = $this->services->serviceDriver('order')->ordersUpload([$biz]);
|
|
if ($result['datas'][0]['issuccess'] && $order['erp_order_id'] != $biz['so_id']) {
|
|
$order->save(['erp_id' => $result['datas'][0]['o_id'], 'erp_order_id' => $biz['so_id']]);
|
|
}
|
|
break;
|
|
} catch (\Exception $e) {
|
|
usleep(1000 * 50);
|
|
Log::error('ERP订单上传失败,原因:' . $e->getMessage());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 收货地址
|
|
* @param string $userAddress
|
|
* @return array
|
|
*/
|
|
public function getAddress(string $userAddress): array
|
|
{
|
|
$receiver_state = $receiver_city = $receiver_district = $receiver_address = '';
|
|
if (!empty($userAddress)) {
|
|
$address = explode(' ', $userAddress);
|
|
$receiver_state = $address[0] ?? ''; // 收货省份
|
|
$receiver_city = $address[1] ?? ''; // 收货市
|
|
$receiver_district = $address[2] ?? ''; // 收货区
|
|
$receiver_address = $address[3] ?? ''; // 收货街道
|
|
$receiver_address .= $address[4] ?? ''; // 街道
|
|
}
|
|
|
|
return compact('receiver_state', 'receiver_city', 'receiver_district', 'receiver_address');
|
|
}
|
|
|
|
/**
|
|
* 获取erp指定订单商品详情
|
|
* @param int $oid
|
|
* @param int $uid
|
|
* @param string $unique
|
|
* @return array
|
|
*/
|
|
public function getItems(int $oid, int $uid, string $unique): array
|
|
{
|
|
/** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */
|
|
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
$cartInfo = $storeOrderCartInfoServices->getOrderCartInfo($oid);
|
|
|
|
if (empty($cartInfo)) {
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
|
|
//同步查询订单商品为查询到 查询缓存信息
|
|
$orderInfo = $orderServices->getCacheOrderInfo($uid, $unique);
|
|
$cartInfo = $orderInfo['cartInfo'] ?? [];
|
|
}
|
|
|
|
$items = [];
|
|
foreach ($cartInfo as $cart) {
|
|
$cart = $cart['cart_info'] ?? $cart;
|
|
$attrInfo = $cart['productInfo']['attrInfo'];
|
|
$items[] = [
|
|
'sku_id' => $attrInfo['code'],
|
|
'shop_sku_id' => $attrInfo['code'],
|
|
'base_price' => (float)bcdiv((string)$cart['truePrice'], (string)$cart['cart_num'], 2),
|
|
'amount' => (float)$cart['truePrice'],
|
|
'qty' => $cart['cart_num'],
|
|
'pic' => $cart['productInfo']['image'],
|
|
'name' => $cart['productInfo']['store_name'],
|
|
'properties_value' => $attrInfo['suk'],
|
|
'outer_oi_id' => $cart['product_attr_unique'],
|
|
];
|
|
}
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* 取消回调
|
|
* @param array $cancel
|
|
* @return bool
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
*/
|
|
public function cancelCallback(array $cancel): bool
|
|
{
|
|
try {
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
$orders = explode('_', $cancel['so_id']);
|
|
$cancel['order_id'] = $orders[0] ?? '';
|
|
$order = $orderServices->getOne(['order_id' => $cancel['order_id']], '*');
|
|
if (!$order) {
|
|
throw new AdminException('订单信息不能为空!');
|
|
}
|
|
|
|
$order = is_object($order) ? $order->toArray() : $order;
|
|
$ids = [$order['erp_order_id']];
|
|
|
|
// 获取子订单号
|
|
$orders = $orderServices->getColumn(['pid' => $order['id']], 'erp_order_id', 'id');
|
|
if ($orders) {
|
|
$ids = array_values(array_unique(array_filter(array_merge($ids, $orders))));
|
|
}
|
|
|
|
$result = $this->services->serviceDriver('order')->ordersSingleQuery(['so_ids' => $ids]);
|
|
// 取消申请退货
|
|
$this->checkRefundApply((int)$order['id']);
|
|
|
|
// 部分退货
|
|
if (count($result['orders']) > 1) {
|
|
$this->applyPartRefund($cancel, $order, $result['orders'], $orderServices);
|
|
} else {
|
|
$this->applyRefund($cancel, $order, $orderServices);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error(['msg' => '订单取消失败,原因:' . $e->getMessage(), 'data' => $cancel]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 订单申请退款
|
|
* @param array $cancel
|
|
* @param array $order
|
|
* @param StoreOrderServices $orderServices
|
|
* @return void
|
|
*/
|
|
protected function applyRefund(array $cancel, array $order, StoreOrderServices $orderServices)
|
|
{
|
|
try {
|
|
$data['refund_reason_wap_explain'] = $cancel['remark'];
|
|
$data['order_id'] = $cancel['order_id'];
|
|
|
|
/** @var StoreOrderRefundServices $storeOrderRefundServices */
|
|
$storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
|
|
|
|
if ($storeOrderRefundServices->count(['store_order_id' => $order['id'], 'refund_type' => [0, 1, 2, 4, 5], 'is_cancel' => 0, 'is_del' => 1])) {
|
|
throw new AdminException('请先处理售后申请!');
|
|
}
|
|
//0元退款
|
|
if ($order['pay_price'] == 0 && in_array($order['refund_status'], [0, 1])) {
|
|
$refund_price = 0;
|
|
} else {
|
|
if ($order['pay_price'] == $order['refund_price']) {
|
|
throw new AdminException('已退完支付金额!不能再退款了!');
|
|
}
|
|
$refund_price = bcsub((string)$order['pay_price'], $order['refund_price'], 2);
|
|
}
|
|
$data['refund_status'] = 2;
|
|
$data['refund_type'] = 6;
|
|
|
|
$refund_data['pay_price'] = $order['pay_price'];
|
|
$refund_data['refund_price'] = $refund_price;
|
|
if ($order['refund_price'] > 0) {
|
|
mt_srand();
|
|
$refund_data['refund_id'] = $order['order_id'] . rand(100, 999);
|
|
}
|
|
|
|
/** @var StoreOrderCreateServices $service */
|
|
$storeOrderCreateServices = app()->make(StoreOrderCreateServices::class);
|
|
|
|
//生成退款订单
|
|
$refundOrderData['uid'] = $order['uid'];
|
|
$refundOrderData['store_id'] = $order['store_id'];
|
|
$refundOrderData['store_order_id'] = $order['id'];
|
|
$refundOrderData['refund_num'] = $order['total_num'];
|
|
$refundOrderData['refund_type'] = $data['refund_type'];
|
|
$refundOrderData['refund_price'] = $order['pay_price'];
|
|
$refundOrderData['refunded_price'] = $refund_price;
|
|
$refundOrderData['refund_reason'] = $cancel['remark'];
|
|
$refundOrderData['order_id'] = $storeOrderCreateServices->getNewOrderId('');
|
|
$refundOrderData['refunded_time'] = time();
|
|
$refundOrderData['add_time'] = time();
|
|
|
|
/** @var StoreOrderCartInfoServices $orderInfoServices */
|
|
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
$cartInfos = $storeOrderCartInfoServices->getCartColunm(['oid' => $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'];
|
|
}
|
|
$refundOrderData['cart_info'] = json_encode(array_column($cartInfos, 'cart_info'));
|
|
$res = $storeOrderRefundServices->save($refundOrderData);
|
|
|
|
//修改订单退款状态
|
|
if ($storeOrderRefundServices->agreeRefund((int)$res->id, $refund_data)) {
|
|
//主动退款清楚原本退款单
|
|
$storeOrderRefundServices->delete(['store_order_id' => $order['id']]);
|
|
$orderServices->update($order['id'], $data);
|
|
} else {
|
|
$storeOrderRefundServices->storeProductOrderRefundYFasle((int)$order['id'], $refund_price);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('订单申请退款失败,原因:' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 部分退款申请
|
|
* @param array $cancel
|
|
* @param array $order
|
|
* @param array $orders
|
|
* @param StoreOrderServices $orderServices
|
|
* @return bool|void
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
*/
|
|
protected function applyPartRefund(array $cancel, array $order, array $orders, StoreOrderServices $orderServices)
|
|
{
|
|
try {
|
|
$cartWhere = ['oid' => $order['id']];
|
|
|
|
// 获取拆单信息
|
|
if ($order['pid'] < 0) {
|
|
$oIds = $orderServices->Value([['pid', '=', $order['id']], ['refund_status', '<', 2], ['status', '=', 0]], 'GROUP_CONCAT(id)');
|
|
if (!empty($oIds)) {
|
|
$oIds = array_filter(explode(',', $oIds));
|
|
}
|
|
$cartWhere = ['oid' => $oIds, 'split_status' => [0, 1]];
|
|
}
|
|
|
|
/** @var StoreOrderCartInfoServices $orderInfoServices */
|
|
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
|
|
$cartInfos = $storeOrderCartInfoServices->getCartColunm($cartWhere, 'id,oid,cart_id,cart_num,split_surplus_num,cart_info');
|
|
foreach ($cartInfos as &$cartInfo) {
|
|
$cartInfo['cart_info'] = is_string($cartInfo['cart_info']) ? json_decode($cartInfo['cart_info'], true) : $cartInfo['cart_info'];
|
|
}
|
|
|
|
// 过滤已退商品
|
|
$cancelled = $this->filter($orders, $order['id']);
|
|
if (empty($cancelled)) {
|
|
return true;
|
|
}
|
|
|
|
$cartOid = 0;
|
|
$cartIds = [];
|
|
foreach ($cartInfos as $cart) {
|
|
$num = $cancelled[$cart['cart_info']['productInfo']['attrInfo']['code']] ?? 0;
|
|
if ($num > 0) {
|
|
$allow = $num <= $cart['split_surplus_num'] ? $num : $num - $cart['split_surplus_num'];
|
|
$cartId = (string)$cart['cart_id'];
|
|
if (isset($cartIds[$cartId])) {
|
|
$cartIds[$cartId]['cart_num'] += $allow;
|
|
} else {
|
|
$cartIds[$cartId] = ['cart_id' => $cartId, 'cart_num' => $allow, 'oid' => $cart['oid']];
|
|
$cartOid = $cart['oid'];
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($order['pid'] < 0) {
|
|
$oid = $orderServices->Value([['pid', '=', $order['id']], ['refund_status', '<', 2], ['status', '=', 0]], 'id');
|
|
if ($oid < 1) {
|
|
return true;
|
|
}
|
|
$order = $orderServices->getOne(['id' => $oid], '*');
|
|
if (!$order) {
|
|
throw new AdminException('订单信息不能为空!');
|
|
}
|
|
}
|
|
|
|
/** @var StoreOrderRefundServices $storeOrderRefundServices */
|
|
$storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
|
|
|
|
$refundData = ['refund_reason' => $cancel['remark'], 'refund_explain' => 'ERP取消订单', 'refund_img' => json_encode([])];
|
|
$refundId = $storeOrderRefundServices->applyRefund($cartOid, $order['uid'], $order, array_values($cartIds), 1, 0.00, $refundData, 1, false);
|
|
if ($refundId) {
|
|
$refund = $storeOrderRefundServices->get($refundId);
|
|
// 立即退款
|
|
$this->receivedCallback(['outer_as_id' => $refund['order_id']], 1);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('订单部分退款申请失败,原因:' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 订单发货
|
|
* @param array $data
|
|
* @return bool
|
|
*/
|
|
public function deliverCallback(array $data): bool
|
|
{
|
|
try {
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
|
|
/** @var StoreOrderDeliveryServices $orderDeliveryServices */
|
|
$orderDeliveryServices = app()->make(StoreOrderDeliveryServices::class);
|
|
$order = $orderServices->getOne(['erp_id' => $data['o_id'], 'status' => 0], '*');
|
|
$deliver = [
|
|
"type" => 1, // 订单统一使用快递配送
|
|
"delivery_name" => $data['logistics_company'], // 快递公司名称
|
|
"delivery_id" => $data['l_id'], // 快递公司单号
|
|
"delivery_code" => $data['lc_id'], // 快递公司编码
|
|
"express_record_type" => "1", // 快递
|
|
'express_temp_id' => '',
|
|
'expressTemp' => [],
|
|
"to_name" => '',
|
|
"to_tel" => '',
|
|
"to_addr" => '',
|
|
"sh_delivery_name" => "",
|
|
"sh_delivery_id" => "",
|
|
"sh_delivery_uid" => "",
|
|
"fictitious_content" => "",
|
|
"export_open" => true,
|
|
'erp_id' => (int)$data['o_id'] // 内部订单编号
|
|
];
|
|
// 单个订单发货
|
|
if (!empty($order)) {
|
|
// 取消申请退货
|
|
$this->checkRefundApply($order['id']);
|
|
$other = ["to_name" => $order['real_name'], "to_tel" => $order['user_phone'], "to_addr" => $order['user_address']];
|
|
$orderDeliveryServices->delivery($order['id'], array_merge($deliver, $other));
|
|
return true;
|
|
}
|
|
|
|
// 根据订单ID查找为空则订单异常
|
|
$order = $orderServices->getOne(['erp_order_id' => $data['so_id']], '*');
|
|
if (!$order) {
|
|
throw new AdminException('订单信息获取异常,不能进行自动发货!');
|
|
}
|
|
|
|
// 拆单发货
|
|
/** @var StoreOrderCartInfoServices $cartInfoServices */
|
|
$cartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
$list = $cartInfoServices->getSplitCartList($order['id']);
|
|
|
|
if ($order['pid'] < 0 && empty($list)) {
|
|
$oIds = $orderServices->Value([['pid', '=', $order['id']], ['status', '=', 0], ['refund_status', '<', 2]], 'GROUP_CONCAT(id)');
|
|
if ($oIds) {
|
|
$oIds = array_filter(explode(',', $oIds));
|
|
// 获取拆单信息进行匹配是否拆单
|
|
$cartWhere = ['oid' => $oIds, 'split_status' => [0, 1]];
|
|
$list = $cartInfoServices->getCartColunm($cartWhere, 'id,oid,cart_id,cart_num,split_surplus_num,cart_info');
|
|
foreach ($list as &$cartInfo) {
|
|
$cartInfo['cart_info'] = is_string($cartInfo['cart_info']) ? json_decode($cartInfo['cart_info'], true) : $cartInfo['cart_info'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取发货数据
|
|
[$deliver['cart_ids'], $oid] = $this->generateCart($data['items'], $list);
|
|
if (empty($deliver['cart_ids'])) {
|
|
return true;
|
|
}
|
|
|
|
// 取消申请退货
|
|
$this->checkRefundApply($oid);
|
|
|
|
$other = ["to_name" => $order['real_name'], "to_tel" => $order['user_phone'], "to_addr" => $order['user_address']];
|
|
$orderDeliveryServices->splitDelivery($oid, array_merge($deliver, $other));
|
|
} catch (\Exception $e) {
|
|
Log::error('发货回调失败, 原因:' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 订单拆分后的数据
|
|
* @param array $items
|
|
* @param array $list
|
|
* @return array
|
|
* @throws Exception
|
|
*/
|
|
public function generateCart(array $items, array $list): array
|
|
{
|
|
$carts = [];
|
|
$oid = 0;
|
|
foreach ($items as $item) {
|
|
foreach ($list as $cart) {
|
|
if ($item['sku_id'] == $cart['cart_info']['productInfo']['attrInfo']['code']) {
|
|
$carts[] = ['cart_id' => $cart['cart_id'], 'cart_num' => (int)$item['qty']];
|
|
$oid = $cart['oid'];
|
|
}
|
|
}
|
|
}
|
|
|
|
return [$carts, $oid];
|
|
}
|
|
|
|
/**
|
|
* 售后单上传
|
|
* @param array $refundIds
|
|
* @return bool
|
|
*/
|
|
public function refundOrderUpload(array $refundIds, string $shopStatus = 'WAIT_SELLER_CONFIRM_GOODS')
|
|
{
|
|
try {
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
|
|
/** @var StoreOrderRefundServices $storeOrderRefundServices */
|
|
$storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
|
|
|
|
$list = [];
|
|
foreach ($refundIds as $refundId) {
|
|
$refund = $storeOrderRefundServices->getOne(['id' => $refundId], '*', ['order']);
|
|
if ($refund->order['pid'] > 0) {
|
|
$order = $orderServices->get($refund->order['pid']);
|
|
if (!$order) {
|
|
throw new AdminException('父级订单信息不能为空!');
|
|
}
|
|
$soId = $order->erp_order_id;
|
|
} else {
|
|
$soId = $refund->order->erp_order_id;
|
|
}
|
|
|
|
$refundData = [
|
|
'shop_id' => $this->getShopId($refund->order->store->erp_shop_id ?? 0), // 店铺编号
|
|
'outer_as_id' => $refund['order_id'], // 退货退款单号,平台唯一
|
|
'so_id' => $soId, // 平台订单号
|
|
'type' => '普通退货', // 售后类型
|
|
'shop_status' => $shopStatus, // WAIT_SELLER_CONFIRM_GOODS:等待卖家确认收货 CLOSED:退款关闭
|
|
'good_status' => 'BUYER_RETURNED_GOODS', // 买家已退货
|
|
'question_type' => null,
|
|
'remark' => $refund['refund_reason'], // 问题类型
|
|
'total_amount' => (float)$refund->order['pay_price'], // 原单据总金额
|
|
'refund' => (float)$refund['refund_price'], // 卖家应退金额
|
|
'payment' => 0.00 // 买家应补偿金额
|
|
];
|
|
|
|
$items = [];
|
|
foreach ($refund['cart_info'] as $cart) {
|
|
$items[] = [
|
|
'sku_id' => $cart['productInfo']['attrInfo']['code'], // 商家商品编码
|
|
'qty' => (int)$cart['cart_num'], // 退货数量
|
|
'amount' => bcadd(bcmul((string)($cart['truePrice'] ?? 0), (string)$cart['cart_num'], 4), (string)($cart['postage_price'] ?? 0), 2), // SKU退款金额
|
|
'type' => '退货',
|
|
'pic' => $cart['productInfo']['attrInfo']['image']
|
|
];
|
|
}
|
|
$refundData['items'] = $items;
|
|
$list[] = $refundData;
|
|
}
|
|
|
|
$result = $this->services->serviceDriver('order')->afterSaleUpload($list);
|
|
if ($result['datas'][0]['issuccess'] != true) {
|
|
Log::error('退货单:' . implode(',', $refundIds) . ' 发送失败,原因:' . $result['datas'][0]['msg']);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error(['msg' => '售后单上传失败,原因:' . $e->getMessage(), 'data' => ['refundIds' => $refundIds, 'shopStatus' => $shopStatus]]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取店铺编号
|
|
* @param int $erpShopId
|
|
* @return int
|
|
*/
|
|
public function getShopId(int $erpShopId): int
|
|
{
|
|
if ($erpShopId < 1) {
|
|
$erpShopId = sys_config('jst_default_shopid');
|
|
}
|
|
|
|
return (int)$erpShopId;
|
|
}
|
|
|
|
/**
|
|
* ERP订单取消
|
|
* @param string $orderId
|
|
* @param array $erpOrderId
|
|
* @return void
|
|
*/
|
|
public function cancelOrder(string $orderId, array $erpOrderId = [])
|
|
{
|
|
$erpOrderId[] = $orderId;
|
|
$result = $this->services->serviceDriver('order')->ordersSingleQuery(['so_ids' => array_filter($erpOrderId), 'status' => 'WaitConfirm']);
|
|
if (!$erpIds = array_column($result['orders'], 'o_id')) {
|
|
Log::error(['msg' => 'ERP订单取消失败,原因:未找到待发货订单', 'data' => [$orderId, $erpOrderId]]);
|
|
return false;
|
|
}
|
|
|
|
$cancelData = ['o_ids' => $erpIds, 'cancel_type' => '用户申请退货, 重新生成订单'];
|
|
$num = 3;
|
|
for ($i = $num; $i >= 0; $i--) {
|
|
if ($i <= 0) {
|
|
Log::error(['msg' => 'ERP订单取消失败,调用均为异常', 'data' => [$orderId, $erpOrderId]]);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$this->services->serviceDriver('order')->orderByOIdCancel($cancelData);
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
usleep(1000 * 50);
|
|
Log::error('ERP订单取消失败,原因:' . $e->getMessage());
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 售后收货回调
|
|
* @param array $refund
|
|
* @param int $type
|
|
* @param bool $isUpload
|
|
* @return void
|
|
*/
|
|
public function receivedCallback(array $refund, int $type = 1, bool $isUpload = false)
|
|
{
|
|
try {
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
|
|
/** @var StoreOrderRefundServices $orderRefundServices */
|
|
$orderRefundServices = app()->make(StoreOrderRefundServices::class);
|
|
|
|
$data = [
|
|
'refund_type' => 6, // 已退款
|
|
'refunded_time' => time()
|
|
];
|
|
|
|
if ($type == 1) {
|
|
$data['refund_status'] = 2;
|
|
$data['refund_type'] = 6;
|
|
} else if ($type == 2) {
|
|
$data['refund_status'] = 0;
|
|
$data['refund_type'] = 3;
|
|
}
|
|
|
|
$orderRefund = $orderRefundServices->getOne(['order_id' => $refund['outer_as_id']]);
|
|
if (!$orderRefund) {
|
|
throw new AdminException('Data does not exist!');
|
|
}
|
|
|
|
$id = (int)$orderRefund['id'];
|
|
|
|
if ($type == 2) {
|
|
$refundData = [
|
|
'refuse_reason' => 'ERP订单发货取消',
|
|
'refund_type' => 3,
|
|
'refunded_time' => time()
|
|
];
|
|
$orderRefundServices->refuseRefund($id, $refundData, $orderRefund);
|
|
} else {
|
|
if ($orderRefund['is_cancel'] == 1) {
|
|
throw new AdminException('用户已取消申请!');
|
|
}
|
|
|
|
$order = $orderServices->get((int)$orderRefund['store_order_id']);
|
|
if (!$order) {
|
|
throw new AdminException('Data does not exist!');
|
|
}
|
|
|
|
if (!in_array($orderRefund['refund_type'], [0, 1, 2, 5]) && !($orderRefund['refund_type'] == 4 && $orderRefund['apply_type'] == 3)) {
|
|
throw new AdminException('售后订单状态不支持该操作');
|
|
}
|
|
|
|
// 0元退款
|
|
if ($orderRefund['refund_price'] == 0) {
|
|
$refund_price = 0;
|
|
} else {
|
|
$refund_price = $orderRefund['refund_price'];
|
|
if ($orderRefund['refund_price'] == $orderRefund['refunded_price']) {
|
|
throw new AdminException('已退完支付金额!不能再退款了');
|
|
}
|
|
|
|
$data['refunded_price'] = bcadd($refund_price, $orderRefund['refunded_price'], 2);
|
|
$bj = bccomp((string)$orderRefund['refund_price'], $data['refunded_price'], 2);
|
|
if ($bj < 0) {
|
|
throw new AdminException('退款金额大于支付金额,请修改退款金额');
|
|
}
|
|
}
|
|
$refund_data['pay_price'] = $order['pay_price'];
|
|
$refund_data['refund_price'] = $refund_price;
|
|
if ($order['refund_price'] > 0) {
|
|
mt_srand();
|
|
$refund_data['refund_id'] = $order['order_id'] . rand(100, 999);
|
|
}
|
|
// 修改订单退款状态
|
|
unset($data['refund_price']);
|
|
if ($orderRefundServices->agreeRefund($id, $refund_data)) {
|
|
$orderRefundServices->update($id, $data);
|
|
} else {
|
|
$orderRefundServices->storeProductOrderRefundYFasle($id, $refund_price);
|
|
throw new AdminException('退货单退款失败');
|
|
}
|
|
// 重新上传订单
|
|
if ($type && $isUpload) {
|
|
$orders = explode('_', $refund['so_id']);
|
|
$order = $orderServices->getOne(['order_id' => $orders[0] ?? ''], 'id, pid, status, refund_status, erp_order_id');
|
|
if (!$order) {
|
|
throw new AdminException('订单不存在');
|
|
}
|
|
|
|
$erpOrderId = [];
|
|
$oid = (int)$order['id'];
|
|
$status = (int)$order['status'];
|
|
if ($order['pid'] < 0) {
|
|
$childOrder = $orderServices->getOne([['pid', '=', $order['id']], ['status', '=', 0], ['refund_status', '=', 0]], 'id, pid, status, refund_status, erp_order_id');
|
|
$refundChild = $orderServices->getColumn([['pid', '=', $order['id']], ['status', '=', 0], ['refund_status', '=', 2]], 'erp_order_id');
|
|
if (!empty($refundChild)) {
|
|
$erpOrderId = array_unique($refundChild);
|
|
}
|
|
if ($childOrder) {
|
|
$oid = (int)$childOrder['id'];
|
|
$erpOrderId[] = $childOrder['erp_order_id'];
|
|
$status = (int)$childOrder['status'];
|
|
}
|
|
}
|
|
|
|
if ($oid > 0) {
|
|
!in_array($status, [2, 4]) && OrderSyncJob::dispatchDo('reorderOrder', [$order['erp_order_id'], $erpOrderId, $oid]);
|
|
} else {
|
|
Log::error(['msg' => '售后收货回调没有需要取消的订单', 'data' => $refund]);
|
|
}
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error(['msg' => '售后收货回调失败,原因:' . $e->getMessage(), 'data' => ['refund' => $refund, 'type' => $type, 'isUpload' => $isUpload]]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 过滤ERP不可退订单
|
|
* @param array $orders
|
|
* @param int $oid
|
|
* @return array
|
|
*/
|
|
protected function filter(array $orders, int $oid): array
|
|
{
|
|
$cancelled = $waitConfirm = [];
|
|
foreach ($orders as $cartOrder) {
|
|
if (in_array($cartOrder['status'], ['WaitConfirm', 'Sent'])) {
|
|
foreach ($cartOrder['items'] as $item) {
|
|
if (!isset($waitConfirm[$item['sku_id']])) {
|
|
$waitConfirm[$item['sku_id']] = $item['qty'];
|
|
} else {
|
|
$waitConfirm[$item['sku_id']] += $item['qty'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */
|
|
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
$cartInfo = $storeOrderCartInfoServices->getOrderCartInfo($oid);
|
|
|
|
foreach ($cartInfo as $cart) {
|
|
$attrInfo = $cart['cart_info']['productInfo']['attrInfo'];
|
|
$cancelled[$attrInfo['code']] = $cart['cart_info']['cart_num'];
|
|
if (isset($waitConfirm[$attrInfo['code']])) {
|
|
$cancelled[$attrInfo['code']] -= $waitConfirm[$attrInfo['code']];
|
|
if ($cancelled[$attrInfo['code']] < 1) {
|
|
unset($cancelled[$attrInfo['code']]);
|
|
}
|
|
}
|
|
}
|
|
|
|
$refundData = $this->getOrderRefund($oid);
|
|
foreach ($refundData as $key => $item) {
|
|
$num = $cancelled[$key] ?? 0;
|
|
if ($num > 0) {
|
|
$cancelled[$key] -= $item;
|
|
if ($cancelled[$key] < 1) {
|
|
unset($cancelled[$key]);
|
|
}
|
|
}
|
|
}
|
|
return $cancelled;
|
|
}
|
|
|
|
/**
|
|
* 累计订单已退数量
|
|
* @param int $oid
|
|
* @return array
|
|
*/
|
|
public function getOrderRefund(int $oid): array
|
|
{
|
|
$attrData = [];
|
|
$refunds = $this->orderRefundList($oid);
|
|
foreach ($refunds as $refund) {
|
|
foreach ($refund['cart_info'] as $item) {
|
|
if (!isset($attrData[$item['productInfo']['attrInfo']['code']])) {
|
|
$attrData[$item['productInfo']['attrInfo']['code']] = $item['cart_num'];
|
|
} else {
|
|
$attrData[$item['productInfo']['attrInfo']['code']] += $item['cart_num'];
|
|
}
|
|
}
|
|
}
|
|
return $attrData;
|
|
}
|
|
|
|
/**
|
|
* 存在申请退货单则关闭
|
|
* @param int $oid
|
|
* @return bool
|
|
*/
|
|
public function checkRefundApply(int $oid): bool
|
|
{
|
|
$refunds = $this->orderRefundList($oid, 1);
|
|
|
|
if (!empty($refunds)) {
|
|
$refundIds = [];
|
|
foreach ($refunds as $refund) {
|
|
$refundIds[] = $refund['id'];
|
|
$this->receivedCallback(['outer_as_id' => $refund['order_id']], 2);
|
|
}
|
|
// 关闭 ERP 退货单
|
|
$this->refundOrderUpload($refundIds, 'CLOSED');
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 订单退货单相关信息
|
|
* @param int $id
|
|
* @param int $refundType
|
|
* @return array
|
|
*/
|
|
public function orderRefundList(int $id, int $refundType = 4): array
|
|
{
|
|
/** @var StoreOrderRefundServices $storeOrderRefundServices */
|
|
$storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
|
|
$refunds = $storeOrderRefundServices->getRefundList(['store_order_id' => $id, 'refundTypes' => $refundType], 'id, store_order_id, store_id, order_id, uid, cart_info');
|
|
|
|
/** @var StoreOrderServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderServices::class);
|
|
$ids = $orderServices->Value(['pid' => $id], 'GROUP_CONCAT(id)');
|
|
if ($ids) {
|
|
$ids = array_filter(explode(',', $ids));
|
|
$list = $storeOrderRefundServices->getRefundList(['store_order_id' => $ids, 'refundTypes' => $refundType], 'id, store_order_id, store_id, order_id, uid, cart_info');
|
|
$refunds = array_merge($refunds, $list);
|
|
}
|
|
return $refunds;
|
|
}
|
|
|
|
/**
|
|
* ERP订单号
|
|
* @return string $orderId
|
|
* @return string $erpOrderId
|
|
*/
|
|
public function getErpOrderId(string $orderId, string $erpOrderId = ''): string
|
|
{
|
|
if (!empty($erpOrderId)) {
|
|
$arr = explode('_', $erpOrderId);
|
|
if (count($arr) == 1) {
|
|
return $erpOrderId . '_1';
|
|
}
|
|
|
|
$num = end($arr);
|
|
return $arr[0] . '_' . ++$num;
|
|
}
|
|
return $orderId;
|
|
}
|
|
}
|
|
|