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.
340 lines
13 KiB
340 lines
13 KiB
<?php
|
|
|
|
namespace App\JsonRpc;
|
|
|
|
use App\Commons\Log;
|
|
use App\Constants\v3\ErrorCode;
|
|
use App\Constants\v3\LogLabel;
|
|
use App\Constants\v3\OrderState;
|
|
use App\Exception\ErrorCodeException;
|
|
use App\Model\v3\Order;
|
|
use App\Model\v3\OrderGoods;
|
|
use App\Model\v3\OrderMain;
|
|
use App\Service\v3\Interfaces\FinancialRecordServiceInterface;
|
|
use App\Service\v3\Interfaces\OrderOnlineServiceInterface;
|
|
use App\Service\v3\Interfaces\SeparateAccountsServiceInterface;
|
|
use EasyWeChat\Factory;
|
|
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
|
|
use Hyperf\DbConnection\Db;
|
|
use Hyperf\Guzzle\CoroutineHandler;
|
|
use Hyperf\RpcServer\Annotation\RpcService;
|
|
use Hyperf\Di\Annotation\Inject;
|
|
use App\JsonRpc\OrdersServiceInterface;
|
|
|
|
/**
|
|
* @RpcService(name="OrdersService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="")
|
|
*/
|
|
class OrdersService implements OrdersServiceInterface
|
|
{
|
|
|
|
/**
|
|
* @Inject
|
|
* @var Log
|
|
*/
|
|
protected $log;
|
|
|
|
/**
|
|
* @Inject
|
|
* @var OrderOnlineServiceInterface
|
|
*/
|
|
protected $orderOnlineService;
|
|
|
|
/**
|
|
* @Inject
|
|
* @var SeparateAccountsServiceInterface
|
|
*/
|
|
protected $separateAccountsService;
|
|
|
|
/**
|
|
* @Inject
|
|
* @var FinancialRecordServiceInterface
|
|
*/
|
|
protected $financialRecordService;
|
|
|
|
/**
|
|
* 订单完成
|
|
* @param $global_order_id
|
|
* @param $user_id
|
|
* @return array
|
|
*/
|
|
public function onlineComplete($global_order_id, $user_id)
|
|
{
|
|
Db::beginTransaction();
|
|
try {
|
|
|
|
$this->orderOnlineService->doComplete($global_order_id, $user_id);
|
|
$this->separateAccountsService->orderOnlineCompleted($global_order_id, $user_id);
|
|
|
|
Db::commit();
|
|
return [
|
|
"status" => 200,
|
|
"code" => 0,
|
|
"result" => [],
|
|
"message" => '处理成功'
|
|
];
|
|
} catch (\Exception $e) {
|
|
|
|
Db::rollBack();
|
|
$this->log->event(LogLabel::ORDER_COMPLETE_LOG, ['jsonrpc_order_service_exception_onlineComplete' => $e->getMessage(), 'params' => json_encode([$global_order_id, $user_id])]);
|
|
return [
|
|
"status" => 200,
|
|
"code" => $e->getCode() ?? ErrorCode::ORDER_COMPLETE_FAIL,
|
|
"result" => [],
|
|
"message" => $e->getMessage()
|
|
];
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 线上订单退款,整个订单退,这个是专门用于处理用户的申请退款的同意退款操作
|
|
* @param $global_order_id
|
|
* @param $user_id
|
|
* @return array
|
|
*/
|
|
public function onlineRefund($global_order_id, $user_id)
|
|
{
|
|
try {
|
|
$result = $this->orderOnlineService->doRefund($global_order_id, $user_id);
|
|
|
|
return [
|
|
"status" => 200,
|
|
"code" => 0,
|
|
"result" => [],
|
|
"message" => '处理成功'
|
|
];
|
|
} catch (\Exception $e) {
|
|
return [
|
|
"status" => 200,
|
|
"code" => $e->getCode(),
|
|
"result" => [],
|
|
"message" => $e->getMessage()
|
|
];
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 线上订单单笔退款,主要用于后台强行操作退单退款
|
|
* 支持单商品、单店、整单
|
|
* 按比例计算红包进行退款
|
|
* 比如:两个子订单和子订单商品,分别是2元,98元,使用了10元优惠券
|
|
* 退2元商品时,退款金额为
|
|
* 红包 :(2/(98+2))*10 = 0.2
|
|
* 退款:2-0.2=1.8元
|
|
* @param $user_id *用户ID
|
|
* @param $global_order_id *全局总订单ID
|
|
* @param $order_child_id *主订单ID,
|
|
* @param $order_goods_id *订单商品ID
|
|
* @param $note
|
|
* @return array
|
|
*/
|
|
public function onlineSingleRefund($user_id, $note, $global_order_id, $order_child_id='', $order_goods_id='')
|
|
{
|
|
|
|
Db::beginTransaction();
|
|
try {
|
|
|
|
$params = [
|
|
'user_id' => $user_id,
|
|
'note' => $note,
|
|
'global_order_id' => $global_order_id,
|
|
'order_child_id' => $order_child_id,
|
|
'order_goods_id' => $order_goods_id,
|
|
];
|
|
|
|
if (!$user_id || !$global_order_id || !$note) {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => '参数不对',
|
|
'params' => json_encode($params)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
// 主订单
|
|
$orderMain = OrderMain::query()
|
|
->where(['global_order_id' => $global_order_id, 'user_id' => $user_id])
|
|
->whereIn('state', array_merge(OrderState::CAN_REFUND_DIRECT, [OrderState::REFUNDED]))
|
|
->first();
|
|
|
|
if (is_null($orderMain)) {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => '订单不存在',
|
|
'params' => json_encode($params)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
// 子订单
|
|
$orderChild = null;
|
|
if ($order_child_id) {
|
|
$orderChild = Order::query()->with('store')->where(['order_main_id' => $orderMain->global_order_id, 'id' => $order_child_id])->first();
|
|
}
|
|
|
|
// 订单商品
|
|
$orderGoods = null;
|
|
if ($order_goods_id) {
|
|
if (!$order_child_id || is_null($orderChild)) {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => '子订单参数异常[单品]',
|
|
'params' => json_encode($params)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
$orderGoods = OrderGoods::query()
|
|
->where(['order_id' => $orderChild->id, 'id' => $order_goods_id, 'status' => 1])
|
|
->first();
|
|
|
|
if (is_null($orderGoods)) {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => '订单商品参数异常[单品]',
|
|
'params' => json_encode($params)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
}
|
|
$totalAmount = $orderMain->total_money; // 订单可退款金额,总订单金额不含配送费和服务费
|
|
$preRefundAmount = 0; // 预退款金额
|
|
$refundAmount = 0; // 实际退款金额
|
|
$refundType = 'main'; // 退款类型, Main整单 Sub子单 Goods单品
|
|
if ($orderGoods) { // 1. 如果订单商品存在则说明要退单品
|
|
$preRefundAmount = bcmul($orderGoods->price, $orderGoods->number, 2);
|
|
$refundType = 'goods';
|
|
} elseif ($orderChild) { // 2. 否则如果存在子订单说明退子订单
|
|
$preRefundAmount = $orderChild->money;
|
|
$refundType = 'sub';
|
|
} else { // 3. 再则如果存在主订单说明退主订单
|
|
$preRefundAmount = $orderMain->total_money;
|
|
$refundType = 'main';
|
|
}
|
|
|
|
// 占订单金额的比例
|
|
$rate = bcdiv($preRefundAmount, $totalAmount, 6);
|
|
// 计算优惠券所占金额
|
|
$couponMoney = bcmul($orderMain->coupon_money, $rate, 6);
|
|
// 计算本次退款实际退款金额
|
|
$refundAmount = bcsub($preRefundAmount, $couponMoney, 2);
|
|
|
|
if ($refundAmount <= 0) {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => '没有可退款金额[实际退款金额]',
|
|
'params' => json_encode($params)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
// 开始退款
|
|
$config = config('wxpay');
|
|
$app = Factory::payment($config);
|
|
$app['guzzle_handler'] = CoroutineHandler::class;
|
|
$result = $app->refund->byOutTradeNumber(
|
|
$orderMain->global_order_id,
|
|
$orderMain->global_order_id.$order_child_id.$order_goods_id,
|
|
bcmul($orderMain->money, 100, 0),
|
|
bcmul($refundAmount, 100, 0),
|
|
[
|
|
'refund_desc' => '订单协商退款[' . $refundType . ']',
|
|
'notify_url' => config('wechat.notify_url.refund_single'),
|
|
]
|
|
);
|
|
|
|
if ($result['return_code'] == 'FAIL') {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => $result['return_msg'] . '[微信退款失败]',
|
|
'params' => json_encode($result)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
if ($result['result_code'] == 'FAIL') {
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => $result['err_code_des'] . '[微信退款失败]' . $result['err_code'],
|
|
'params' => json_encode($result)
|
|
]);
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
// 退款申请成功,查询退款状态,此处暂时无法传递和记录单品退的信息,所以直接查询退款状态处理,不做回调
|
|
$refundResult = $app->refund->queryByRefundId($result['refund_id']);
|
|
$this->log->event(LogLabel::ORDER_REFUND_LOG, [
|
|
'jsonrpc_order_service_exception_onlineSingleRefund' => '[微信退款查询]',
|
|
'params' => json_encode($refundResult)
|
|
]);
|
|
|
|
// 退款成功
|
|
if (
|
|
!($refundResult['return_code'] == 'SUCCESS'
|
|
&& isset($refundResult['result_code'])
|
|
&& $refundResult['result_code'] == 'SUCCESS')
|
|
) {
|
|
throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
|
|
}
|
|
|
|
$currentTime = time();
|
|
// 处理订单状态
|
|
$orderMain->state = OrderState::REFUNDED_DIRECT;
|
|
$orderMain->total_refund_note = $note;
|
|
$orderMain->refund_time = $currentTime;
|
|
$orderMain->save();
|
|
|
|
if ($refundType == 'sub') {
|
|
$orderChild->status = 3;
|
|
$orderChild->refund_note = $note;
|
|
$orderChild->refund_time = $currentTime;
|
|
$orderChild->save();
|
|
} elseif ($refundType == 'goods') {
|
|
$orderGoods->status = 3;
|
|
$orderGoods->refund_note = $note;
|
|
$orderGoods->refund_time = $currentTime;
|
|
$orderGoods->save();
|
|
}
|
|
|
|
// 处理用户和商户流水
|
|
$orderChildren = [];
|
|
if ($refundType == 'main') { # 整单退的话还得处理所有子订单的商户
|
|
|
|
$orderChildren = Order::query()->with('store:user_id')->where(['order_main_id' => $orderMain->global_order_id])->get();
|
|
foreach ($orderChildren as $key => &$order) {
|
|
// 占订单金额的比例
|
|
$rate = bcdiv($order->money, $totalAmount, 6);
|
|
// 计算优惠券所占金额
|
|
$couponMoney = bcmul($orderMain->coupon_money, $rate, 6);
|
|
// 计算本次退款实际退款金额
|
|
$refundStoreAmount = bcsub($order->money, $couponMoney, 2);
|
|
$this->financialRecordService->storeRefundDirect($order->store->user_id, $order->id, $refundStoreAmount);
|
|
}
|
|
|
|
} elseif ($refundType == 'sub'||$refundType == 'goods') { # 退子订单或者退单品的话,商户只有一个
|
|
$orderChildren = Order::query()->with('store:user_id')->where(['id' => $order_child_id])->get();
|
|
$this->financialRecordService->storeRefundDirect($orderChild->store->user_id, $orderChild->id, $refundAmount);
|
|
}
|
|
|
|
$this->financialRecordService->userRefundDirect($orderMain->user_id, $orderMain->global_order_id, $refundAmount);
|
|
|
|
Db::commit();
|
|
|
|
// 记录badge
|
|
$orderChildIds = array_values(array_column($orderChildren, 'store_id'));
|
|
$this->badgeService->doByOrder($orderMain->user_id, $orderChildIds, $orderMain->global_order_id, OrderState::REFUNDED);
|
|
|
|
return [
|
|
"status" => 200,
|
|
"code" => 0,
|
|
"result" => [],
|
|
"message" => '处理成功'
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
Db::rollBack();
|
|
return [
|
|
"status" => 200,
|
|
"code" => $e->getCode(),
|
|
"result" => [],
|
|
"message" => '[退款失败]'.$e->getMessage()
|
|
];
|
|
}
|
|
|
|
}
|
|
}
|