fix(pay): 支付回调与订单号一致,避免已付款仍显示待付款

- prepay 不再每次重生成 order_sn,回调可按商户单号找到订单

- notify 失败时返回 false 便于微信重试;回调加锁

- 纳入 shopro 支付相关文件;config.example 使用占位密钥

Co-authored-by: Cursor <cursoragent@cursor.com>
这个提交包含在:
可乐加冰
2026-09-23 20:24:44 +08:00
父节点 a2c24aff15
当前提交 54e2d6eec9
共有 4 个文件被更改,包括 1702 次插入 和 1 次删除

查看文件

@@ -0,0 +1,451 @@
<?php
namespace addons\shopro\controller;
use addons\epay\library\Service;
use fast\Random;
use think\addons\Controller;
use addons\shopro\exception\Exception;
use addons\shopro\model\Order;
use addons\shopro\model\User;
use addons\shopro\model\TradeOrder;
use think\Db;
use think\Log;
class Pay extends Base
{
protected $noNeedLogin = ['prepay', 'notifyx', 'notifyr', 'alipay'];
protected $noNeedRight = ['*'];
/**
* 支付宝网页支付
*/
public function alipay()
{
$order_sn = $this->request->get('order_sn');
list($order, $prepay_type) = $this->getOrderInstance($order_sn);
$order = $order->where('order_sn', $order_sn)->find();
try {
if (!$order) {
throw new \Exception("订单不存在");
}
if ($order->status > 0) {
throw new \Exception("订单已支付");
}
if ($order->status < 0) {
throw new \Exception("订单已失效");
}
$notify_url = $this->request->root(true) . '/addons/shopro/pay/notifyx/payment/alipay/platform/H5';
$pay = new \addons\shopro\library\PayService('alipay', 'url', $notify_url);
$order_data = [
'order_id' => $order->id,
'out_trade_no' => $order->order_sn,
'total_fee' => $order->total_fee,
'subject' => '商城订单支付',
];
$result = $pay->create($order_data);
$result = $result->getContent();
echo $result;
} catch (\Exception $e) {
echo $e->getMessage();
}
// $this->assign('result', $result);
// return $this->view->fetch();
}
/**
* 拉起支付
*/
public function prepay()
{
checkEnv('yansongda');
$order_sn = $this->request->post('order_sn');
$orderId = $this->request->post('order_id');
$payment = $this->request->post('payment');
$openid = $this->request->post('openid', '');
$user = $this->auth->getUser();
$platform = request()->header('platform');
// 重新获取订单号
if (strpos($order_sn, 'TO') !== 0) {
$order_sn = Db::name('shopro_order')
->where(['id' => $orderId])
->value('order_sn');
}
list($order, $prepay_type) = $this->getOrderInstance($order_sn);
$order = $order->nopay()->where('order_sn', $order_sn)->find();
if (!$order) {
$this->error("订单不存在");
}
if (!$payment || !in_array($payment, ['wechat', 'alipay', 'wallet', 'group'])) {
$this->error("支付类型不能为空");
}
if ($payment == 'wallet' && $prepay_type == 'order') {
// 余额支付
$this->walletPay($order, $payment, $platform);
}
$order_data = [
'order_id' => $order->id,
'out_trade_no' => $order->order_sn,
'total_fee' => $order->total_fee,
];
if (strpos($order_sn, 'TO') !== 0) {
// 保持 order_sn 不变,避免支付回调时找不到订单
if ($payment == 'group') {
$payment = 'wechat';
// 重新计算价格
$order_data['total_fee'] = bcsub($order_data['total_fee'], $user->money, 2);
// 更新组合付款余额
Db::name('shopro_order')->update([
'id' => $order->id,
'pay_type' => 'group',
'pay_money' => $user->money
]);
} else {
Db::name('shopro_order')->update([
'id' => $order->id,
'pay_type' => $payment,
'pay_money' => 0
]);
}
}
// 微信公众号,小程序支付,必须有 openid
if ($payment == 'wechat') {
if (in_array($platform, ['wxOfficialAccount', 'wxMiniProgram'])) {
if (isset($openid) && $openid) {
// 如果传的有 openid
$order_data['openid'] = $openid;
} else {
// 没有 openid 默认拿下单人的 openid
$oauth = \addons\shopro\model\UserOauth::where([
'user_id' => $order->user_id,
'provider' => 'Wechat',
'platform' => $platform
])->find();
$order_data['openid'] = $oauth ? $oauth->openid : '';
}
if (empty($order_data['openid'])) {
// 缺少 openid
return $this->success('缺少 openid', 'no_openid');
}
}
$order_data['body'] = '商城订单支付';
} else {
$order_data['subject'] = '商城订单支付';
}
$notify_url = $this->request->root(true) . '/addons/shopro/pay/notifyx/payment/' . $payment . '/platform/' . $platform;
$pay = new \addons\shopro\library\PayService($payment, $platform, $notify_url);
try {
$result = $pay->create($order_data);
} catch (\Yansongda\Pay\Exceptions\Exception $e) {
$this->error("支付配置错误:" . $e->getMessage());
}
if ($platform == 'App') {
// $result = json_decode($result->getContent(), true);
$result = $result->getContent();
}
if ($platform == 'H5' && $payment == 'wechat') {
$result = $result->getContent();
}
return $this->success('获取预付款成功', [
'pay_data' => $result,
'pay_action' => $pay->method,
]);
}
// 余额支付
public function walletPay($order, $type, $method)
{
$order = Db::transaction(function () use ($order, $type, $method) {
// 重新加锁读,防止连点问题
$order = Order::nopay()->where('order_sn', $order->order_sn)->lock(true)->find();
if (!$order) {
$this->error("订单已支付");
}
$total_fee = $order->total_fee;
// 扣除余额
$user = User::info();
if (is_null($user)) {
// 没有登录,请登录
$this->error(__('Please login first'), null, 401);
}
User::money(-$total_fee, $user->id, 'wallet_pay', $order->id, '', [
'order_id' => $order->id,
'order_sn' => $order->order_sn,
]);
// 支付后流程
$notify = [
'order_sn' => $order['order_sn'],
'transaction_id' => '',
'notify_time' => date('Y-m-d H:i:s'),
'buyer_email' => $user->id,
'pay_fee' => $order->total_fee,
'pay_type' => 'wallet' // 支付方式
];
$notify['payment_json'] = json_encode($notify);
$order->paymentProcess($order, $notify);
return $order;
});
$this->success('支付成功', $order);
}
/**
* 支付成功回调
*/
public function notifyx()
{
Log::write('notifyx-comein:');
$payment = $this->request->param('payment');
$platform = $this->request->param('platform');
$pay = new \addons\shopro\library\PayService($payment, $platform);
$result = $pay->notify(function ($data, $pay) use ($payment, $platform) {
Log::write('notifyx-result:' . json_encode($data));
// { // 微信回调参数
// "appid":"wx39cd0799d4567dd0",
// "bank_type":"OTHERS",
// "cash_fee":"1",
// "fee_type":"CNY",
// "is_subscribe":"N",
// "mch_id":"1481069012",
// "nonce_str":"dPpcZ6AzCDU8daNC",
// "openid":"oD9ko4x7QMDQPZEuN8V5jtZjie3g",
// "out_trade_no":"202010240834057843002700",
// "result_code":"SUCCESS",
// "return_code":"SUCCESS",
// "sign":"3103B6D06F13D2B3959C5B3F7F1FD61C",
// "time_end":"20200407102424",
// "total_fee":"1",
// "trade_type":"JSAPI",
// "transaction_id":"4200000479202004070804485027"
// }
// { // 支付宝支付成功回调参数
// "gmt_create":"2020-04-10 19:15:00",
// "charset":"utf-8",
// "seller_email":"xptech@qq.com",
// "subject":"\u5546\u57ce\u8ba2\u5355\u652f\u4ed8",
// "sign":"AOiYZ1a2mEMOuIbHFCi6V6A0LJ97UMiHsCWgNdSU9dlzKFl15Ts8b0mL\/tN+Hhskl+94S3OUiNTBD3dD0Kv923SqaTWxNdj533PCdo2GDKsZIZgKbavnOvaccSKUdmQRE9KtmePPq9V9lFzEQvdUkKq1M8KAWO5K9LTy2iT2y5CUynpiu\/04GVzsTL9PqY+LDwqj6K+w7MgceWm1BWaFWg27AXIRw7wvsFckr3k9GGajgE2fufhoCYGYtGFbhGOp6ExtqS5RXBuPODOyRhBLpD8mwpOX38Oy0X+R4YQIrOi02dhqwPpvw79YjnvgXY3qZEQ66EdUsrT7EBdcPHK0Gw==",
// "buyer_id":"2088902485164146",
// "invoice_amount":"0.01",
// "notify_id":"2020041000222191501064141414240102",
// "fund_bill_list":"[{\"amount\":\"0.01\",\"fundChannel\":\"PCREDIT\"}]",
// "notify_type":"trade_status_sync",
// "trade_status":"TRADE_SUCCESS",
// "receipt_amount":"0.01",
// "buyer_pay_amount":"0.01",
// "app_id":"2021001114666742",
// "sign_type":"RSA2",
// "seller_id":"2088721922277739",
// "gmt_payment":"2020-04-10 19:15:00",
// "notify_time":"2020-04-10 19:15:01",
// "version":"1.0",
// "out_trade_no":"202007144778322770017000",
// "total_amount":"0.01",
// "trade_no":"2020041022001464141443020240",
// "auth_app_id":"2021001114666742",
// "buyer_logon_id":"157***@163.com",
// "point_amount":"0.00"
// }
// { // 支付宝退款成功(交易关闭)回调参数
// "gmt_create": "2020-08-15 14:48:32",
// "charset": "utf-8",
// "seller_email": "xptech@qq.com",
// "gmt_payment": "2020-08-15 14:48:32",
// "notify_time": "2020-08-15 16:11:45",
// "subject": "商城订单支付",
// "gmt_refund": "2020-08-15 16:11:45.140",
// "sign": "b6ArkgzLIRteRL9FMGC6i\/jf6VwFYQbaGDGRx002W+pdmN5q9+O4edZ3ALF74fYaijSl9ksNr0dKdvanu3uYxBTcd\/GIS4N1CWzmCOv6pzgx5rO\/YvGoHLM3Yop0GKKuMxmnNsZ6jhYKEY7SYD3Y0L6PU9ZMdHV7yIiVj+zZmbKzUgK9MPDCEXs+nzpNAiSM8GTqYRSUvKobAK68hswG2k1QIcqr5z+ZmVYa\/nHHkoC9qXt5zwyGi4P+2eOsr6V2PjA3x8qqe7TN5aI1DeoZD5KqHPYYaYF17J2q6YPlgl3WUl1RhE7H86bivB1fIuYEv\/3+JR74WN\/o7krGw1RPHg==",
// "out_biz_no": "R202004114414846255015300",
// "buyer_id": "2088902485164146",
// "version": "1.0",
// "notify_id": "2020081500222161145064141453349793",
// "notify_type": "trade_status_sync",
// "out_trade_no": "202002460317545607015300",
// "total_amount": "0.01",
// "trade_status": "TRADE_CLOSED",
// "refund_fee": "0.01",
// "trade_no": "2020081522001464141438570535",
// "auth_app_id": "2021001114666742",
// "buyer_logon_id": "157***@163.com",
// "gmt_close": "2020-08-15 16:11:45",
// "app_id": "2021001114666742",
// "sign_type": "RSA2",
// "seller_id": "2088721922277739"
// }
try {
$out_trade_no = $data['out_trade_no'];
$out_refund_no = $data['out_biz_no'] ?? '';
list($order, $prepay_type) = $this->getOrderInstance($out_trade_no);
// 判断是否是支付宝退款(支付宝退款成功会通知该接口)
if ($payment == 'alipay' // 支付宝支付
&& $data['notify_type'] == 'trade_status_sync' // 同步交易状态
&& $data['trade_status'] == 'TRADE_CLOSED' // 交易关闭
&& $out_refund_no // 退款单号
) {
// 退款回调
if ($prepay_type == 'order') {
// 退款回调
$this->refundFinish($out_trade_no, $out_refund_no);
} else {
// 其他订单如果支持退款,逻辑这里补充
}
return $pay->success()->send();
}
// 判断支付宝微信是否是支付成功状态,如果不是,直接返回响应
if ($payment == 'alipay' && $data['trade_status'] != 'TRADE_SUCCESS') {
// 不是交易成功的通知,直接返回成功
return $pay->success()->send();
}
if ($payment == 'wechat' && ($data['result_code'] != 'SUCCESS' || $data['return_code'] != 'SUCCESS')) {
// 微信交易未成功,返回 false,让微信再次通知
return false;
}
// 支付成功流程
$pay_fee = $payment == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
// 你可以在此编写订单逻辑
$order = $order->nopay()->where('order_sn', $out_trade_no)->lock(true)->find();
if (!$order) {
// 已支付则直接返回成功,否则记录日志并通知微信重试
$paidOrder = Order::where('order_sn', $out_trade_no)->where('status', '>', 0)->find();
if ($paidOrder) {
return $pay->success()->send();
}
Log::write('notifyx-order-not-found:' . $out_trade_no);
return false;
}
Db::transaction(function () use ($order, $data, $payment, $platform, $pay_fee, $prepay_type) {
$notify = [
'order_sn' => $data['out_trade_no'],
'transaction_id' => $payment == 'alipay' ? $data['trade_no'] : $data['transaction_id'],
'notify_time' => date('Y-m-d H:i:s', strtotime($data['time_end'])),
'buyer_email' => $payment == 'alipay' ? $data['buyer_logon_id'] : $data['openid'],
'payment_json' => json_encode($data->all()),
'pay_fee' => $pay_fee,
'pay_type' => $order->pay_type == 'group' ? 'group' : $payment // 支付方式
];
$order->paymentProcess($order, $notify);
});
return $pay->success()->send();
} catch (\Exception $e) {
Log::write('notifyx-error:' . $e->getMessage());
return false;
}
});
return $result;
}
/**
* 退款成功回调
*/
public function notifyr()
{
Log::write('notifyreturn-comein:');
$payment = $this->request->param('payment');
$platform = $this->request->param('platform');
$pay = new \addons\shopro\library\PayService($payment, $platform);
$result = $pay->notifyRefund(function ($data, $pay) use ($payment, $platform) {
Log::write('notifyr-result:' . json_encode($data));
try {
$out_refund_no = $data['out_refund_no'];
$out_trade_no = $data['out_trade_no'];
// 退款
$this->refundFinish($out_trade_no, $out_refund_no);
return $pay->success()->send();
} catch (\Exception $e) {
Log::write('notifyreturn-error:' . json_encode($e->getMessage()));
}
});
return $result;
}
private function refundFinish($out_trade_no, $out_refund_no)
{
$order = Order::where('order_sn', $out_trade_no)->find();
$refundLog = \app\admin\model\shopro\order\RefundLog::where('refund_sn', $out_refund_no)->find();
if (!$order || !$refundLog || $refundLog->status != 0) {
// 订单不存在,或者订单已退款
return true;
}
$item = \app\admin\model\shopro\order\OrderItem::where('id', $refundLog->order_item_id)->find();
Db::transaction(function () use ($order, $item, $refundLog) {
\app\admin\model\shopro\order\Order::refundFinish($order, $item, $refundLog);
});
return true;
}
/**
* 根据订单号获取订单实例
*
* @param [type] $order_sn
* @return void
*/
private function getOrderInstance($order_sn)
{
$prepay_type = 'order';
if (strpos($order_sn, 'TO') === 0) {
// 充值订单
$prepay_type = 'recharge';
$order = new TradeOrder();
} else {
// 订单
$order = new Order();
}
return [$order, $prepay_type];
}
}

查看文件

@@ -0,0 +1,273 @@
<?php
namespace addons\shopro\library;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Log;
use addons\shopro\exception\Exception;
class PayService
{
protected $config;
protected $platform;
protected $payment;
protected $notify_url;
public $method;
public function __construct($payment, $platform = '', $notify_url = '', $type = 'pay')
{
$this->platform = $platform;
$this->payment = $payment;
$this->notify_url = $notify_url;
$this->type = $type;
$this->setPaymentConfig();
}
private function setPaymentConfig()
{
if ($this->platform === 'App' && $this->payment != 'alipay') {
$paymentConfig = json_decode(\addons\shopro\model\Config::get(['name' => 'wechat_app'])->value, true);
} else {
$paymentConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->payment])->value, true);
}
// 如果是支付,并且不是 复制地址的支付宝支付
if ($this->type == 'pay' && $this->platform != 'url' && !in_array($this->platform, $paymentConfig['platform'])) {
new Exception('暂不支持该方式付款');
}
$this->config = $paymentConfig;
$this->config['notify_url'] = $this->notify_url;
if ($this->payment === 'wechat') {
// 根据不同平台设置相应的 appid
$this->setWechatAppId();
}
// 设置支付证书路径
$this->setCert();
}
private function setWechatAppId()
{
switch ($this->platform) {
case 'wxOfficialAccount':
$platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->platform])->value, true);
if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
$this->config['sub_app_id'] = $platformConfig['app_id'];
} else {
$this->config['app_id'] = $platformConfig['app_id'];
}
break;
case 'wxMiniProgram':
$platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->platform])->value, true);
if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
$this->config['sub_miniapp_id'] = $platformConfig['app_id'];
// $this->config['sub_app_id'] = $platformConfig['app_id'];
} else {
$this->config['miniapp_id'] = $platformConfig['app_id'];
$this->config['app_id'] = $platformConfig['app_id']; // 小程序微信企业付款
}
break;
case 'H5':
$platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->platform])->value, true);
if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
$this->config['sub_app_id'] = $platformConfig['app_id'];
} else {
$this->config['app_id'] = $platformConfig['app_id'];
}
break;
case 'App':
$platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => 'App'])->value, true);
if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
$this->config['sub_appid'] = $platformConfig['app_id'];
$this->config['sub_app_id'] = $platformConfig['app_id'];
} else {
$this->config['appid'] = $platformConfig['app_id']; // 微信 App 支付使用这个
$this->config['app_id'] = $platformConfig['app_id']; // 微信 App 支付退款使用的是这个
}
break;
}
}
// 处理证书路径
private function setCert()
{
// 处理证书路径
if ($this->payment == 'wechat') {
// 微信支付证书
$this->config['cert_client'] = ROOT_PATH . 'public' . $this->config['cert_client'];
$this->config['cert_key'] = ROOT_PATH . 'public' . $this->config['cert_key'];
} else {
// 支付宝证书路径
$end = substr($this->config['ali_public_key'], -4);
if ($end == '.crt') {
$this->config['ali_public_key'] = ROOT_PATH . 'public' . $this->config['ali_public_key'];
}
$this->config['app_cert_public_key'] = ROOT_PATH . 'public' . $this->config['app_cert_public_key'];
$this->config['alipay_root_cert'] = ROOT_PATH . 'public' . $this->config['alipay_root_cert'];
}
}
private function setPaymentMethod()
{
$method = [
'wechat' => [
'wxOfficialAccount' => 'mp', //公众号支付 Collection
'wxMiniProgram' => 'miniapp', //小程序支付
'H5' => 'wap', //手机网站支付 Response
'App' => 'app' //APP 支付 JsonResponse
],
'alipay' => [
'wxOfficialAccount' => 'wap', //手机网站支付 Response
'wxMiniProgram' => 'wap', //小程序支付
'H5' => 'wap', //手机网站支付 Response
'url' => 'wap', //手机网站支付 Response
'App' => 'app' //APP 支付 JsonResponse
],
];
$this->method = $method[$this->payment][$this->platform];
}
public function create($order)
{
// $order = [
// 'out_trade_no' => time(),
// 'total_fee' => '1', // **单位:分**
// 'body' => 'test body - 测试',
// 'openid' => 'onkVf1FjWS5SBIixxxxxxx', //微信需要带openid过来
// ];
// 设置支付方式
$this->setPaymentMethod();
$method = $this->method;
switch ($this->payment) {
case 'wechat':
if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
$order['sub_openid'] = $order['openid'];
unset($order['openid']);
}
$order['total_fee'] = $order['total_fee'] * 100;
$pay = Pay::wechat($this->config)->$method($order);
break;
case 'alipay':
if (in_array($this->platform, ['wxOfficialAccount', 'wxMiniProgram', 'H5'])) {
// 返回支付宝支付链接
$pay = request()->domain() . '/addons/shopro/pay/alipay?order_sn=' . $order['out_trade_no'];
} else {
if ($this->method == 'wap') {
// 支付宝 wap 支付,增加 return_url
// 获取 h5 域名
$platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => 'shopro'])->value, true);
// 如果域名存在,增加 return_url
if ($platformConfig && isset($platformConfig['domain'])) {
$start = substr($platformConfig['domain'], -1) == '/' ? "" : "/";
$orderType = strpos($order['out_trade_no'], 'TO') === 0 ? 'recharge' : 'goods';
$this->config['return_url'] = $platformConfig['domain'] . $start . "pages/order/payment/result?orderId=" . $order['order_id'] . "&type=alipay&payState=success&orderType=" . $orderType;
}
}
$pay = Pay::alipay($this->config)->$method($order);
}
break;
}
return $pay;
}
// 企业付款
public function transfer($payload)
{
$code = 0;
$response = [];
switch ($this->payment) {
case 'wechat':
$payload['amount'] = $payload['amount'] * 100;
$response = Pay::wechat($this->config)->transfer($payload);
if ($response['return_code'] === 'SUCCESS' && $response['result_code'] === 'SUCCESS') {
$code = 1;
}
break;
case 'alipay':
$response = Pay::alipay($this->config)->transfer($payload);
if ($response['code'] === '10000' && $response['status'] === 'SUCCESS') {
$code = 1;
}
break;
}
return [$code, $response];
}
public function notify($callback)
{
$pay = $this->getPay();
try {
$data = $pay->verify(); // 是的,验签就这么简单!
$result = $callback($data, $pay);
// Log::debug('Wechat notify', $data->all());
} catch (\Exception $e) {
\think\Log::error('notify-error:' . $e->getMessage());
return false;
}
return $result;
}
public function refund($order_data)
{
$pay = $this->getPay();
$order_data['type'] = $this->platform == 'wxMiniProgram' ? 'miniapp' : '';
$result = $pay->refund($order_data);
return $result;
}
public function notifyRefund($callback)
{
$pay = $this->getPay();
try {
$data = $pay->verify(null, true); // 是的,验签就这么简单!
$result = $callback($data, $pay);
// Log::debug('Wechat notify', $data->all());
} catch (\Exception $e) {
// $e->getMessage();
}
return $result;
}
private function getPay()
{
switch ($this->payment) {
case 'wechat':
$pay = Pay::wechat($this->config);
break;
case 'alipay':
$pay = Pay::alipay($this->config);
break;
default:
new Exception('支付方式不支持');
}
return $pay;
}
}

查看文件

@@ -0,0 +1,977 @@
<?php
namespace addons\shopro\library\traits\model\order;
use addons\shopro\exception\Exception;
use addons\shopro\model\Coupons;
use addons\shopro\model\RobOrderModel;
use addons\shopro\model\User;
use addons\shopro\model\GoodsComment;
use addons\shopro\model\Order;
use addons\shopro\model\OrderAction;
use addons\shopro\model\OrderItem;
use addons\shopro\model\Store;
use addons\shopro\model\UserAddress;
use addons\shopro\model\Verify;
use app\admin\model\shopro\order\RefundLog;
use function fast\e;
use think\Db;
trait OrderOper
{
use OrderOperSendGet, OrderOperCreate;
// 获取订单号
public static function getSn($user_id)
{
$rand = $user_id < 9999 ? mt_rand(100000, 99999999) : mt_rand(100, 99999);
$order_sn = date('Yhis') . $rand;
$id = str_pad($user_id, (24 - strlen($order_sn)), '0', STR_PAD_BOTH);
return $order_sn . $id;
}
// 计算订单
public static function pre($params, $calc_type = 'pre')
{
self::$calc_type = $calc_type;
$user = User::info();
// 检测必要系统环境
checkEnv(['bcmath', 'queue']);
// 获取请求参数 "order_type", "groupon_id", "buy_type"
extract(self::preParams($params));
// 检测并重新组装要购买的商品列表
list(
$new_goods_list, // 组合好的新的商品列表
$activity_type, // 订单参与的活动类型,后面还需计算一次
$activity_discounts, // 订单可能参与的所有活动
$need_address, // 是否需要收货地址
$user_address // 用户收货地址
) = self::preCheck($params);
// 计算订单商品价格,所需积分,运费
list(
$new_goods_list, // 新的商品列表
$goods_original_amount, // 商品原始总价
$goods_amount, // 商品现在总价
$dispatch_amount, // 订单运费(所有商品种最高的,后面还需根据活动再次计算)
$score_amount, // 订单所需支付积分
$deliveryFee,
$dispatchData,
) = self::preCalcAmount($params, $new_goods_list, $user_address, $dispatch_id);
// 记录原始运费
$origin_dispatch_amount = $dispatch_amount;
// 计算订单优惠折扣,优惠券,邮费
list(
$new_goods_list, // 重新赋值活动, 商品上增加了 activity_type
$activity_discount_infos, // 每个活动包含的优惠信息
$activity_discount_money, // 促销活动优惠总金额
$dispatch_discount_money, // 邮费总优惠金额
$free_shipping_goods_ids, // 包邮的商品的ids
$activity_type, // 全部参与的活动类型
$dispatch_amount, // 重新计算的运费
$user_coupons, // 使用的优惠券信息
$coupon_money // 优惠券优惠金额
) = self::preCalcDiscount(
$params,
$new_goods_list,
$activity_discounts,
$activity_type,
$goods_amount,
$dispatch_amount,
$user_address
);
// 计算订单总金额,需支付金额
list(
$new_goods_list,
$total_amount,
$discount_fee,
$total_fee,
$coupon_fee,
) = self::preCalcOrder(
$new_goods_list,
$goods_amount,
$origin_dispatch_amount,
$dispatch_amount,
$activity_discount_infos,
$activity_discount_money,
$dispatch_discount_money,
$free_shipping_goods_ids,
$coupon_money,
$deliveryFee
);
// 获取发票金额
$invoice_amount = self::preCalcInvoiceAmount($total_fee, $goods_amount);
// 获取快递列表(即将废弃)
$expressName = '';
$expressList = Db::name('shopro_dispatch')
->where(['type' => 'express'])
->field(['id', 'name', 'type_ids'])
->select();
if (!empty($expressList) && !empty($dispatchData)) {
foreach ($expressList as &$v) {
if ($v['id'] === $dispatchData['dispatch_id']) {
$v['active'] = 1;
$expressName = $v['name'];
} else {
$v['active'] = 0;
}
}
}
// 处理返回结果
return self::preReturnParams(
$goods_original_amount,
$goods_amount,
$origin_dispatch_amount,
$dispatch_amount,
$total_amount,
$total_fee,
$discount_fee,
$coupon_fee,
$activity_discount_money,
$dispatch_discount_money,
$activity_type,
$score_amount,
$new_goods_list,
$need_address,
$activity_discount_infos,
$user_coupons,
$user_address,
$invoice_amount,
$deliveryFee,
$expressList,
$expressName
);
}
// 获取可用优惠券列表
public static function coupons($params, $goods_amount = 0)
{
$user = User::info();
extract($params);
$order_type = $order_type ?? 'goods';
$groupon_id = $groupon_id ?? 0; // 拼团的 团 id
$buy_type = $buy_type ?? 'alone'; // 拼团的 购买方式: alone=单独购买,groupon=开团
// 商品总金额
if (!$goods_amount) {
// 下单的时候把计算好的 goods_amount 传进来了,接口直接获取可用列表的时候,需要计算
foreach ($goods_list as $k => $goods) {
$goods_amount += ($goods['goods_price'] * $goods['goods_num']);
}
}
$coupons = Coupons::getCouponsList(Coupons::COUPONS_CAN_USE);
$new_coupons = [];
// 过滤,如果有一个产品不适用,则优惠券不允许使用,不显示
foreach ($coupons as $key => $coupon) {
if ($coupon['goods_ids'] === '0') {
// 所有商品可用
$can_use = true;
} else {
$goods_ids = explode(',', $coupon['goods_ids']);
$can_use = true;
foreach ($goods_list as $k => $goods) {
if (!in_array($goods['goods_id'], $goods_ids)) {
$can_use = false;
break;
}
}
}
// 商品可用 并且 商品金额满足
if ($can_use && $coupon->enough <= $goods_amount) {
$new_coupons[] = $coupon;
}
}
$new_coupons = array_values($new_coupons);
return $new_coupons;
}
public static function createOrder($params)
{
$user = User::info();
// 入参
extract($params);
$remark = $remark ?? null;
$order_type = $order_type ?? 'goods';
$groupon_id = $groupon_id ?? 0; // 拼团的 团 id
$buy_type = $buy_type ?? 'alone'; // 拼团的 购买方式: alone=单独购买,groupon=开团
$invoice = $invoice ?? null; // 发票申请
// 订单计算数据
extract(self::pre($params, "create"));
$order = Db::transaction(function () use (
$user,
$order_type,
$groupon_id,
$buy_type,
$goods_original_amount,
$goods_amount,
$dispatch_amount,
$total_amount,
$score_amount,
$total_fee,
$discount_fee,
$coupon_fee,
$activity_discount_money,
$dispatch_discount_money,
$activity_discount_infos,
$new_goods_list,
$activity_type,
$user_coupons,
$user_address,
$remark,
$from,
$invoice,
$invoice_amount,
$deliveryFee,
$expressName
) {
// 订单创建前
$data = [
'user' => $user,
'order_type' => $order_type,
'groupon_id' => $groupon_id,
'buy_type' => $buy_type,
'goods_original_amount' => $goods_original_amount,
'goods_amount' => $goods_amount,
'dispatch_amount' => $dispatch_amount,
'total_amount' => $total_amount,
'score_amount' => $score_amount,
'total_fee' => $total_fee,
'discount_fee' => $discount_fee,
'coupon_fee' => $coupon_fee,
'activity_discount_money' => $activity_discount_money,
'dispatch_discount_money' => $dispatch_discount_money,
'activity_discount_infos' => $activity_discount_infos,
'new_goods_list' => $new_goods_list,
'activity_type' => $activity_type,
'user_coupons' => $user_coupons,
'user_address' => $user_address,
'remark' => $remark,
'from' => $from
];
// 如果是抢购需看是否有名额才能下单
$activityId = 0;
if ($activity_type === 'robbuy') {
$activityId = $new_goods_list[0]['detail']['activity']['id'];
$id = RobOrderModel::where([
'user_id' => $user->id,
'activity_id' => $activityId,
'goods_id' => $new_goods_list[0]['detail']['id'],
'is_rob' => 1
])->value('id');
if (empty($id)) {
return [
'create_result' => 401,
'msg' => '你未获得抢购资格暂无法购买'
];
}
}
// 如果是活动,这里面减掉 redis 库存
\think\Hook::listen('order_create_before', $data);
// 团信息, 如果是参与旧团拼团才会不为 null,(开新团放到支付成功)
$groupon = cache('grouponinfo-' . $user->id);
$groupon = $groupon ? json_decode($groupon, true) : null;
// 立即清除缓存
cache('grouponinfo-' . $user->id, NULL);
$orderData = [];
$orderData['order_sn'] = self::getSn($user->id);
$orderData['user_id'] = $user->id;
$orderData['type'] = $order_type;
$orderData['activity_type'] = $activity_type;
$orderData['goods_amount'] = $goods_amount;
$orderData['dispatch_amount'] = $dispatch_amount;
$orderData['store_delivery_fee'] = $deliveryFee;
$orderData['total_amount'] = $total_amount;
$orderData['pay_fee'] = $total_amount;
$orderData['score_amount'] = $score_amount;
$orderData['total_fee'] = $total_fee;
$orderData['discount_fee'] = $discount_fee;
$orderData['score_fee'] = $score_amount; // 记录score 支付数
$orderData['coupon_fee'] = $coupon_fee;
$orderData['activity_discount_money'] = $activity_discount_money;
$orderData['dispatch_discount_money'] = $dispatch_discount_money;
$orderData['goods_original_amount'] = $goods_original_amount;
$orderData['last_total_fee'] = 0;
$orderData['activity_id'] = $activityId;
$orderData['express_name'] = $expressName;
if ($user_address) {
$orderData['phone'] = $user_address->phone;
$orderData['consignee'] = $user_address->consignee;
$orderData['province_name'] = $user_address->province_name;
$orderData['city_name'] = $user_address->city_name;
$orderData['area_name'] = $user_address->area_name;
$orderData['address'] = $user_address->address;
$orderData['province_id'] = $user_address->province_id;
$orderData['city_id'] = $user_address->city_id;
$orderData['area_id'] = $user_address->area_id;
}
// 处理发票申请
if ($invoice_amount > 0) {
if (!empty($invoice) && $invoice['amount'] == $invoice_amount) {
$orderData['invoice_status'] = 1; // 已申请
} else {
$orderData['invoice_status'] = 0; // 未申请
}
} else {
$orderData['invoice_status'] = -1; // 不可开具发票
}
$orderData['status'] = 0;
$orderData['remark'] = $remark;
$orderData['coupons_id'] = $user_coupons ? $user_coupons->id : 0;
$orderData['platform'] = request()->header('platform');
$ext = $activity_discount_infos ? ['activity_discount_infos' => $activity_discount_infos] : []; // 促销活动信息
$orderData['ext'] = json_encode($ext);
$order = new Order();
$order->allowField(true)->save($orderData);
// 将优惠券使用掉
if ($user_coupons) {
$user_coupons->use_order_id = $order->id;
$user_coupons->usetime = time();
$user_coupons->save();
}
// 如果需要支付积分,扣除积分
if ($score_amount) {
// $user 为 Common\Auth 对象
User::score(-$score_amount, $user->id, 'score_pay', $order->id, '', [
'order_id' => $order->id,
'order_sn' => $order->order_sn,
]);
}
// 添加发票数据
if ($order->invoice_status == 1) {
\addons\shopro\model\OrderInvoice::create([
'order_id' => $order->id,
'user_id' => $order->user_id,
'amount' => $invoice['amount'],
'type' => $invoice['type'],
'header_name' => $invoice['header_name'],
'tax_no' => $invoice['tax_no'],
'mobile' => $invoice['mobile'],
]);
}
// 添加 订单 item
foreach ($new_goods_list as $key => $buyinfo) {
$detail = $buyinfo['detail'];
$current_sku_price = $detail['current_sku_price'];
$orderItem = new OrderItem();
$orderItem->user_id = $user->id;
$orderItem->order_id = $order->id;
$orderItem->goods_id = $buyinfo['goods_id'];
$orderItem->goods_type = $detail['type'];
$orderItem->goods_sku_price_id = $buyinfo['sku_price_id'];
$item_activity_type = (isset($current_sku_price['activity_type']) && $current_sku_price['activity_type']) ? $current_sku_price['activity_type'] : '';
$item_activity_type .= $buyinfo['activity_type'] ? ',' . $buyinfo['activity_type'] : '';
$item_activity_type = trim($item_activity_type, ',');
$orderItem->activity_id = $current_sku_price['activity_id'] ?? 0; // 商品当前的活动类型
$orderItem->activity_type = $item_activity_type ?: null; // 商品当前的活动类型
// 当前商品规格对应的 活动下对应商品规格的 id
$orderItem->item_goods_sku_price_id = isset($current_sku_price['item_goods_sku_price']) ?
$current_sku_price['item_goods_sku_price']['id'] : 0;
$orderItem->goods_sku_text = $current_sku_price['goods_sku_text'];
$orderItem->goods_title = $detail->title;
$orderItem->goods_image = empty($current_sku_price['image']) ? $detail->image : $current_sku_price['image'];
$orderItem->goods_original_price = $detail->original_price;
$orderItem->discount_fee = $buyinfo['discount_fee']; // 平均计算单件商品所享受的折扣
$orderItem->pay_price = $buyinfo['pay_price']; // 平均计算单件商品不算运费,算折扣时候的金额
$orderItem->goods_price = $detail->current_sku_price->price;
$orderItem->goods_num = $buyinfo['goods_num'] ?? 1;
$orderItem->goods_weight = $detail->current_sku_price->weight;
$orderItem->dispatch_status = 0;
$orderItem->dispatch_fee = $buyinfo['dispatch_amount'];
$orderItem->dispatch_type = $buyinfo['dispatch_type'];
$orderItem->dispatch_id = $buyinfo['dispatch_id'] ? $buyinfo['dispatch_id'] : 0;
$orderItem->store_id = $buyinfo['store_id'] ? $buyinfo['store_id'] : 0;
$orderItem->aftersale_status = 0;
$orderItem->comment_status = 0;
$orderItem->refund_status = 0;
$ext = [];
if (isset($buyinfo['dispatch_date'])) {
$ext['dispatch_date'] = $buyinfo['dispatch_date'];
}
if (isset($buyinfo['dispatch_phone'])) {
$ext['dispatch_phone'] = $buyinfo['dispatch_phone'];
}
$orderItem->ext = json_encode($ext);
$orderItem->save();
}
// 订单创建后
$data = [
'user' => $user,
'order' => $order,
'from' => $from,
'groupon' => $groupon,
'buy_type' => $buy_type,
'activity_type' => $activity_type,
'new_goods_list' => $new_goods_list
];
\think\Hook::listen('order_create_after', $data);
// 重新获取订单
$order = self::where('id', $order['id'])->find();
$order['create_result'] = 200;
saveUserMessage([
'user_id' => $user->id,
'content' => "您成功创建了订单:订单号:{$order->order_sn}",
'create_time' => time()
]);
return $order;
});
return $order;
}
// 订单列表
public static function getList($params)
{
$user = User::info();
extract($params);
$order = (new self())->where('user_id', $user->id)->with('item');
switch ($type) {
case 'all':
$order = $order;
break;
case 'nopay':
$order = $order->nopay();
break;
case 'nosend':
$order = $order->payed()->nosend();
break;
case 'noget':
$order = $order->payed()->noget();
break;
case 'nocomment':
$order = $order->payed()->nocomment();
break;
case 'aftersale':
$order = $order->payed()->aftersale(); // 个人中心售后单不在走这里,而是直接走的售后单列表
break;
}
$orders = $order->order('id', 'desc')->paginate(10);
// 处理未支付订单 item status_code
$orders = $orders->toArray();
if ($orders['data']) {
$data = $orders['data'];
foreach ($data as $key => $od) {
$data[$key] = self::setOrderItemStatusByOrder($od);
}
$orders['data'] = $data;
}
return $orders;
}
// 订单详情
public static function detail($params)
{
$user = User::info();
extract($params);
$order = (new self())->with('item')->where('user_id', $user->id);
if (isset($order_sn)) {
$order = $order->where('order_sn', $order_sn);
}
if (isset($id)) {
$order = $order->where('id', $id);
}
$order = $order->find();
if (!$order) {
new Exception('订单不存在');
}
// 处理未支付订单 item status_code
$order = self::setOrderItemStatusByOrder($order);
// 用户余额
$order['user_money'] = $user->money;
// 手机号码
$order['user_mobile'] = hideStr($user->mobile, 3, 6);
// 组合付款金额
$order['group_fee'] = bcsub($order['total_fee'], $user->money, 2);
return $order;
}
// 订单商品详情
public static function itemDetail($params)
{
$user = User::info();
extract($params);
$type = $type ?? 'default';
$order = (new self())->with(['item' => function ($query) use ($order_item_id) {
$query->where('id', $order_item_id);
}])->where('user_id', $user->id);
if (isset($order_sn)) {
$order = $order->where('order_sn', $order_sn);
}
if (isset($id)) {
$order = $order->where('id', $id);
}
$order = $order->find();
if (!$order || !$order->item) {
new Exception('订单不存在');
}
// 处理未支付订单 item status_code
$order = self::setOrderItemStatusByOrder($order);
$item = $order['item'][0];
unset($order['item']); // 移除订单表中的 item
$item['order'] = $order; // 订单信息
if ($type == 'dispatch') {
$store = null;
$verifies = [];
if (in_array($item['dispatch_type'], ['selfetch', 'store']) && $item['store_id']) {
// 自提,商家配送
if (
$item['dispatch_type'] == 'selfetch'
&& $item['dispatch_status'] == OrderItem::DISPATCH_STATUS_SENDED
&& $item['refund_status'] <= 0
) {
// 关联核销码
$verifies = Verify::where('order_id', $item['order_id'])
->where('order_item_id', $item['id'])->select();
}
$store = Store::where('id', $item['store_id'])->find();
}
$item['store'] = $store; // 门店信息
$item['verify'] = $verifies; // 核销券列表
// $item['autosend']
// 订单详情,自动发货内容 待补充
}
return $item;
}
// 取消订单
public static function operCancel($params)
{
$user = User::info();
extract($params);
$order = self::with('item')->where('user_id', $user->id)->where('id', $id)->nopay()->find();
if (!$order) {
new Exception('订单不存在或已取消');
}
// 订单取消
$order = (new self)->doCancel($order, $user);
return $order;
}
public function doCancel($order, $user, $type = 'user')
{
$order = Db::transaction(function () use ($order, $user, $type) {
$data = ['order' => $order];
\think\Hook::listen('order_cancel_before', $data);
$order->status = Order::STATUS_CANCEL; // 取消订单
$order->ext = json_encode($order->setExt($order, ['cancel_time' => time()])); // 取消时间
$order->save();
OrderAction::operAdd($order, null, $user, $type, ($type == 'user' ? '用户' : '管理员') . '取消订单');
// 订单取消,退回库存,退回优惠券积分,等
$data = ['order' => $order];
\think\Hook::listen('order_cancel_after', $data);
return $order;
});
return $order;
}
private static function getItem($order, $order_item_id)
{
if (!$order) {
new Exception('当前订单不存在');
}
$order_item = null;
foreach ($order->item as $item) {
if ($item->id == $order_item_id) {
$order_item = $item;
break;
}
}
if (!$order_item) {
new Exception('订单商品不需要操作');
}
return $order_item;
}
// 确认收货订单
public static function operConfirm($params)
{
$user = User::info();
extract($params);
$order = Db::transaction(function () use ($id, $order_item_id, $user) {
// 加锁查询订单,exist 里面的子查询不会加锁,但是该语句需要等待锁释放才能正常查询,所以下面的获取 item 已经是更改过状态之后的了
$order = self::noget()->where('user_id', $user->id)->where('id', $id)->lock(true)->find();
// 获取要操作的 订单 item
$item = self::getItem($order, $order_item_id);
if ($item->dispatch_status == OrderItem::DISPATCH_STATUS_NOSEND) {
new Exception('当前订单未发货');
}
if ($item->dispatch_status == OrderItem::DISPATCH_STATUS_GETED) {
new Exception('当前订单已收货');
}
(new self())->getedItem($order, $item, ['oper_type' => 'user']);
});
return $order;
}
// 删除订单
public static function operDelete($params)
{
$user = User::info();
extract($params);
$order = self::canDelete()->where('user_id', $user->id)->where('id', $id)->find();
if (!$order) {
new Exception('订单不存在或不可删除');
}
$order = Db::transaction(function () use ($order, $user) {
$order->delete(); // 删除订单
OrderAction::operAdd($order, null, $user, 'user', '用户删除订单');
return $order;
});
return $order;
}
// 评价
public static function operComment($params)
{
$user = User::info();
$order = Db::transaction(function () use ($user, $params) {
extract($params);
// 加锁读取订单,直到订单评价状态改变
$order = self::with('item')->payed()->where('user_id', $user->id)->where('id', $id)->lock(true)->find();
// 获取要操作的 订单 item
$item = self::getItem($order, $order_item_id);
if ($item->comment_status == 1) {
new Exception('当前商品已评价');
}
// 订单评价前
$data = ['order' => $order, 'item' => $item];
\think\Hook::listen('order_comment_before', $data); // 重新拿到更新过的订单
$images = (isset($images) && $images) ? $images : null;
// 获取用户评论配置
$config = \addons\shopro\model\Config::where('name', 'order')->value('value');
$config = json_decode($config, true);
GoodsComment::create([
'goods_id' => $item->goods_id,
'order_id' => $order->id,
'order_item_id' => $item->id,
'user_id' => $user->id,
'level' => $level,
'content' => $content,
'images' => $images ? implode(',', $images) : $images,
'status' => !empty($config['user_reply']) ? 'show' : 'hidden'
]);
$item->comment_status = OrderItem::COMMENT_STATUS_OK; // 评价成功
$item->save();
OrderAction::operAdd($order, $item, $user, 'user', '用户评价成功');
// 订单评价后
$data = ['order' => $order, 'item' => $item];
\think\Hook::listen('order_comment_after', $data);
return $order;
});
return $order;
}
// 个人中心订单数量
public static function statusNum()
{
$user = User::info();
$status_num['nopay'] = self::where('user_id', $user->id)->nopay()->count();
$status_num['nosend'] = self::where('user_id', $user->id)->payed()->nosend()->count();
$status_num['noget'] = self::where('user_id', $user->id)->payed()->noget()->count();
$status_num['nocomment'] = self::where('user_id', $user->id)->payed()->nocomment()->count();
// $status_num['aftersale'] = self::where('user_id', $user->id)->payed()->aftersale()->count();
$status_num['aftersale'] = \addons\shopro\model\OrderAftersale::where('user_id', $user->id)->count();
return $status_num;
}
public function paymentProcess($order, $notify)
{
$order->status = Order::STATUS_PAYED;
$order->paytime = time();
$order->transaction_id = $notify['transaction_id'];
$order->payment_json = $notify['payment_json'];
$order->pay_type = $notify['pay_type'];
$order->pay_fee = $notify['pay_fee'];
// 组合支付更新付款金额
if ($order->pay_type == 'group') {
$order->total_fee = bcsub($order->total_fee, $order->pay_money, 2);
}
$order->save();
saveUserMessage([
'user_id' => $order->user_id,
'content' => "付款成功,订单号:{$order->order_sn}",
'create_time' => time()
]);
$user = User::where('id', $order->user_id)->find();
OrderAction::operAdd($order, null, $user, 'user', '用户支付成功');
// 组合支付扣除用户余额
if ($order->pay_type == 'group') {
User::where(['id' => $user->id])->setDec('money', $order->pay_money);
}
// 预约抢购标记成已使用
if ($order->activity_type === 'robbuy') {
RobOrderModel::where([
'user_id' => $user->id,
'activity_id' => $order->activity_id,
'goods_id' => OrderItem::where(['order_id' => $order->id])->value('goods_id')
])->update(['is_use' => 1]);
}
// 支付成功后续使用异步队列处理
\think\Queue::push('\addons\shopro\job\OrderPayed@payed', ['order' => $order, 'user' => $user], 'shopro-high');
return $order;
}
// 开始退款
public static function startRefund($order, $item, $refund_money, $user = null, $remark = '')
{
// 订单退款前
$data = ['order' => $order, 'item' => $item];
\think\Hook::listen('order_refund_before', $data);
$item->refund_status = \app\admin\model\shopro\order\OrderItem::REFUND_STATUS_OK; // 同意退款
$item->refund_fee = bcadd($item->refund_fee, $refund_money, 2);;
$item->save();
\addons\shopro\model\OrderAction::operAdd($order, $item, $user, ($user ? 'admin' : 'system'), $remark . ',退款金额:' . $refund_money);
\app\admin\model\shopro\order\Order::refund($order, $item, $refund_money, $remark);
// 订单退款后
$data = ['order' => $order, 'item' => $item];
\think\Hook::listen('order_refund_after', $data);
}
// 退款
public static function refund($order, $item, $refund_money, $remark = '')
{
// 生成退款单
$refundLog = new RefundLog();
$refundLog->order_sn = $order->order_sn;
$refundLog->refund_sn = RefundLog::getSn($order->user_id);
$refundLog->order_item_id = $item->id;
$refundLog->pay_fee = $order->pay_fee;
$refundLog->refund_fee = $refund_money;
$refundLog->pay_type = $order->pay_type;
$refundLog->save();
if ($order->pay_type == 'wechat' || $order->pay_type == 'alipay') {
// 微信|支付宝退款
// 退款数据
$order_data = [
'out_trade_no' => $order->order_sn
];
if ($order->pay_type == 'wechat') {
$total_fee = $order->pay_fee * 100;
$refund_fee = $refund_money * 100;
$order_data = array_merge($order_data, [
'out_refund_no' => $refundLog->refund_sn,
'total_fee' => $total_fee,
'refund_fee' => $refund_fee,
'refund_desc' => $remark,
]);
} else {
$order_data = array_merge($order_data, [
'out_request_no' => $refundLog->refund_sn,
'refund_amount' => $refund_money,
]);
}
$notify_url = request()->domain() . '/addons/shopro/pay/notifyr/payment/' . $order->pay_type . '/platform/' . $order->platform;
$pay = new \addons\shopro\library\PayService($order->pay_type, $order->platform, $notify_url);
$result = $pay->refund($order_data);
\think\Log::write('refund-result' . json_encode($result));
if ($order->pay_type == 'wechat') {
// 微信通知回调 pay->notifyr
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
return true;
} else {
throw new \Exception($result['return_msg']);
}
} else {
// 支付宝通知回调 pay->notifyx
if ($result['code'] == "10000") {
return true;
} else {
throw new \Exception($result['msg']);
}
}
// { // 微信返回结果
// "return_code":"SUCCESS",
// "return_msg":"OK",
// "appid":"wx39cd0799d4567dd0",
// "mch_id":"1481069012",
// "nonce_str":"huW9eIAb5BDPn0Ma",
// "sign":"250316740B263FE53F5DFF50AF5A8FA1",
// "result_code":"SUCCESS",
// "transaction_id":"4200000497202004072822298902",
// "out_trade_no":"202010300857029180027000",
// "out_refund_no":"1586241595",
// "refund_id":"50300603862020040700031444448",
// "refund_channel":[],
// "refund_fee":"1",
// "coupon_refund_fee":"0",
// "total_fee":"1",
// "cash_fee":"1",
// "coupon_refund_count":"0",
// "cash_refund_fee":"1
// }
// { // 支付宝返回结果
// "code": "10000",
// "msg": "Success",
// "buyer_logon_id": "157***@163.com",
// "buyer_user_id": "2088902485164146",
// "fund_change": "Y",
// "gmt_refund_pay": "2020-08-15 16:11:45",
// "out_trade_no": "202002460317545607015300",
// "refund_fee": "0.01",
// "send_back_fee": "0.00",
// "trade_no": "2020081522001464141438570535"
// }
} else if ($order->pay_type == 'wallet') {
// 余额退款
if ($refund_money != 0) {
\addons\shopro\model\User::money($refund_money, $order->user_id, 'wallet_refund', $order->id, '', [
'order_id' => $order->id,
'order_sn' => $order->order_sn,
'item_id' => $item->id,
]);
}
self::refundFinish($order, $item, $refundLog);
return true;
} else if ($order->pay_type == 'score') {
// 积分退款,暂不支持积分退款
}
}
public static function refundFinish($order, $item, $refundLog)
{
// 退款完成
$refundLog->status = 1;
$refundLog->save();
// 退款完成
$item->refund_status = \app\admin\model\shopro\order\OrderItem::REFUND_STATUS_FINISH; // 退款完成
$item->save();
\addons\shopro\model\OrderAction::operAdd($order, $item, null, 'admin', '退款成功');
}
public function setExt($order, $field, $origin = [])
{
$newExt = array_merge($origin, $field);
$orderExt = $order['ext_arr'];
return array_merge($orderExt, $newExt);
}
}

查看文件

@@ -9,7 +9,7 @@
*/
return [
// Gitea Web 钩子「密钥」
'webhook_secret' => 'sdsl23lsdsd2323aaaq#@$kks',
'webhook_secret' => '请改为随机长字符串',
// 站点根目录(含 .git 的项目目录,非 public)
'deploy_path' => '/www/wwwroot/chufang.gynhc.com',