glhcp/server/app/common/logic/OrderRefundLogic.php

385 lines
13 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载https://gitee.com/likeshop_gitee
// | github下载https://github.com/likeshop-github
// | 访问官网https://www.likeshop.cn
// | 访问社区https://home.likeshop.cn
// | 访问手册http://doc.likeshop.cn
// | 微信公众号likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权购买去版权授权后方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\enum\OrderEnum;
use app\common\enum\OrderGoodsEnum;
use app\common\enum\OrderLogEnum;
use app\common\enum\PayEnum;
use app\common\model\order\Order;
use app\common\model\AccountLog;
use app\common\model\order\Order as CommonOrder;
use app\common\model\order\OrderGoods;
use app\common\model\order\OrderLog;
use app\common\model\Pay;
use app\common\model\user\User;
use app\common\server\AliPayServer;
use app\common\server\WeChatPayServer;
use app\common\server\WeChatServer;
use think\Exception;
use think\facade\Db;
use think\facade\Event;
/**
* 订单退款逻辑
* Class OrderRefundLogic
* @package app\common\logic
*/
class OrderRefundLogic
{
/**
* Notes: 取消订单
* @param $order_id
* @param int $handle_type
* @param int $handle_id
* @author 段誉(2021/1/28 15:23)
* @return Order
*/
public static function cancelOrder($order_id, $handle_type = OrderLogEnum::TYPE_SYSTEM, $handle_id = 0)
{
//更新订单状态
// $order = order::get($order_id);
$order = Order::where('id',$order_id)->find();
$order->order_status = OrderEnum::ORDER_STATUS_DOWN;
$order->update_time = time();
$order->cancel_time = time();
$order->save();
// 取消订单后的操作
switch ($handle_type) {
case OrderLogEnum::TYPE_USER:
$channel = OrderLogEnum::USER_CANCEL_ORDER;
break;
case OrderLogEnum::TYPE_SHOP:
$channel = OrderLogEnum::SHOP_CANCEL_ORDER;
break;
case OrderLogEnum::TYPE_SYSTEM:
$channel = OrderLogEnum::SYSTEM_CANCEL_ORDER;
break;
}
event('AfterCancelOrder', [
'type' => $handle_type,
'channel' => $channel,
'order_id' => $order->id,
'handle_id' => $handle_id,
]);
}
/**
* @notes 处理订单退款(事务在取消订单逻辑处)
* @param $order
* @param $order_amount
* @param $refund_amount
* @return bool
* @throws Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @author 段誉
* @date 2021/12/20 15:13
*/
public static function refund($order, $order_amount, $refund_amount)
{
//退款记录
$refund_id = self::addRefundLog($order, $order_amount, $refund_amount);
if ($refund_amount <= 0) {
return false;
}
switch ($order['pay_way']) {
//余额退款
case PayEnum::BALANCE_PAY:
self::balancePayRefund($order, $refund_amount);
break;
//微信退款
case PayEnum::WECHAT_PAY:
self::wechatPayRefund($order, $refund_id);
break;
//支付宝退款
case PayEnum::ALI_PAY:
self::aliPayRefund($order, $refund_id);
break;
}
return true;
}
/**
* Notes: 微信支付退款
* @param $order (订单信息)
* @param $refund_id (退款记录id) 
* @author 段誉(2021/1/27 16:04)
* @throws Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public static function wechatPayRefund($order, $refund_id)
{
$config = WeChatServer::getPayConfigBySource($order['order_source'])['config'];
if (empty($config)) {
throw new Exception('请联系管理员设置微信相关配置!');
}
if (!isset($config['cert_path']) || !isset($config['key_path'])) {
throw new Exception('请联系管理员设置微信证书!');
}
if (!file_exists($config['cert_path']) || !file_exists($config['key_path'])) {
throw new Exception('微信证书不存在,请联系管理员!');
}
$refund_log = Db::name('order_refund')->where(['id' => $refund_id])->find();
$total_fee = Db::name('order_trade')->where(['transaction_id' => $order['transaction_id']])->value('order_amount');
$data = [
'transaction_id' => $order['transaction_id'],
'refund_sn' => $refund_log['refund_sn'],
// 'total_fee' => $refund_log['order_amount'] * 100,//订单金额,单位为分
'total_fee' => $total_fee * 100,//订单金额,单位为分
'refund_fee' => $refund_log['refund_amount'] * 100,//退款金额
];
$result = WeChatPayServer::refund($config, $data);
if (isset($result['return_code']) && $result['return_code'] == 'FAIL') {
throw new Exception($result['return_msg']);
}
if (isset($result['err_code_des'])) {
throw new Exception($result['err_code_des']);
}
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
$update_data = [
'wechat_refund_id' => $result['refund_id'] ?? 0,
'refund_msg' => json_encode($result, JSON_UNESCAPED_UNICODE),
];
//更新退款日志记录
Db::name('order_refund')->where(['id' => $refund_id])->update($update_data);
} else {
throw new Exception('微信支付退款失败');
}
}
/**
* Notes: 支付宝退款
* @param $order
* @param $refund_id
* @author 段誉(2021/3/23 15:48)
* @throws Exception
* @throws \think\exception\PDOException
*/
public static function aliPayRefund($order, $refund_id)
{
$trade_id = $order['trade_id'];
$trade = Db::name('order_trade')->where(['id' => $trade_id])->find();
$result = (new AliPayServer())->refund($trade['t_sn'], $order['order_amount']);
$result = (array)$result;
if ($result['code'] == '10000' && $result['msg'] == 'Success' && $result['fundChange'] == 'Y') {
//更新退款日志记录
$update_data = ['refund_msg' => json_encode($result['httpBody'], JSON_UNESCAPED_UNICODE)];
Db::name('order_refund')->where(['id' => $refund_id])->update($update_data);
} else {
$result = (new AliPayServer())->refund($order['order_sn'], $order['order_amount']);
$result = (array)$result;
if ($result['code'] == '10000' && $result['msg'] == 'Success' && $result['fundChange'] == 'Y') {
//更新退款日志记录
$update_data = ['refund_msg' => json_encode($result['httpBody'], JSON_UNESCAPED_UNICODE)];
Db::name('order_refund')->where(['id' => $refund_id])->update($update_data);
}else{
throw new Exception('支付宝退款失败');
}
}
}
/**
* Notes: 增加退款记录
* @param $order
* @param $order_amount
* @param $refund_amount
* @param string $result_msg
* @author 段誉(2021/1/28 15:23)
* @return int|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function addRefundLog($order, $order_amount, $refund_amount, $result_msg = '退款成功')
{
$data = [
'order_id' => $order['id'],
'user_id' => $order['user_id'],
'refund_sn' => createSn('order_refund', 'refund_sn'),
'order_amount' => $order_amount,
'refund_amount' => $refund_amount,
'transaction_id' => $order['transaction_id'],
'create_time' => time(),
'refund_status' => 1,
'refund_at' => time(),
'refund_msg' => json_encode($result_msg, JSON_UNESCAPED_UNICODE),
];
return Db::name('order_refund')->insertGetId($data);
}
/**
* Notes: 取消订单,退款后更新订单和订单商品信息
* @param $order
* @author 段誉(2021/1/28 14:21)
* @throws Exception
* @throws \think\exception\PDOException
*/
public static function cancelOrderRefundUpdate($order)
{
//订单商品=>标记退款成功状态
Db::name('order_goods')
->where(['order_id' => $order['id']])
->update(['refund_status' => OrderGoodsEnum::REFUND_STATUS_SUCCESS]);
//更新订单支付状态为已退款
Db::name('order')->where(['id' => $order['id']])->update([
'pay_status' => PayEnum::REFUNDED,
'refund_status' => 2,//订单退款状态; 0-未退款1-部分退款2-全部退款
'refund_amount' => $order['order_amount'],
'is_cancel' => OrderEnum::ORDER_CANCEL,
]);
}
/**
* Notes:售后退款更新订单或订单商品状态
* @param $order
* @param $order_goods_id
* @author 段誉(2021/1/28 15:22)
*/
public static function afterSaleRefundUpdate($order, $order_goods_id, $admin_id = 0)
{
$order_goods = OrderGoods::find(['id' => $order_goods_id]);
$order_goods->refund_status = OrderGoodsEnum::REFUND_STATUS_SUCCESS;//退款成功
$order_goods->save();
//更新订单状态
$order = Order::find(['id' => $order['id']]);
$order->pay_status = PayEnum::REFUNDED;
$order->refund_amount += $order_goods['total_pay_price'];//退款金额 + 以前的退款金额
$order->refund_status = 1;//退款状态0-未退款1-部分退款2-全部退款
//如果订单商品已全部退款
if (self::checkOrderGoods($order['id'])) {
$order->order_status = CommonOrder::STATUS_CLOSE;
$order->refund_status = 2;
OrderLogLogic::record(
OrderLogEnum::TYPE_SHOP,
OrderLogEnum::SYSTEM_CANCEL_ORDER,
$order['id'],
$admin_id,
OrderLogEnum::SYSTEM_CANCEL_ORDER
);
}
$order->save();
}
//订单内商品是否已全部
public static function checkOrderGoods($order_id)
{
$order_goods = OrderGoods::where('order_id', $order_id)->select();
if (empty($order_goods)) {
return false;
}
foreach ($order_goods as $item) {
if ($item['refund_status'] != OrderGoodsEnum::REFUND_STATUS_SUCCESS) {
return false;
}
}
return true;
}
/**
* Notes: 余额退款
* @param $order
* @param $refund_amount
* @author 段誉(2021/1/28 15:24)
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function balancePayRefund($order, $refund_amount)
{
$user = User::find($order['user_id']);
$user->user_money = ['inc', $refund_amount];
$user->save();
AccountLogLogic::AccountRecord(
$order['user_id'],
$refund_amount,
1,
AccountLog::cancel_order_refund,
'',
$order['id'],
$order['order_sn']
);
return true;
}
/**
* Notes: 退款失败增加错误记录
* @param $order
* @param $err_msg
* @author 段誉(2021/1/28 15:24)
* @return int|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function addErrorRefund($order, $err_msg)
{
$refund_data = [
'order_id' => $order['id'],
'user_id' => $order['user_id'],
'refund_sn' => createSn('order_refund', 'refund_sn'),
'order_amount' => $order['order_amount'],//订单应付金额
'refund_amount' => $order['order_amount'],//订单退款金额
'transaction_id' => $order['transaction_id'],
'create_time' => time(),
'refund_status' => 2,
'refund_msg' => json_encode($err_msg, JSON_UNESCAPED_UNICODE),
];
return Db::name('order_refund')->insertGetId($refund_data);
}
}