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.
263 lines
8.3 KiB
263 lines
8.3 KiB
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
use App\Common\PayType;
|
|
use App\Models\AdminSetting;
|
|
use App\Models\Agent;
|
|
use App\Models\AgentProduct;
|
|
use App\Models\AgentSetting;
|
|
use App\Models\Order;
|
|
use App\Models\Product;
|
|
use App\Models\UserMoneyLog;
|
|
use EasyWeChat\Factory;
|
|
use EasyWeChat\Kernel\Exceptions\Exception;
|
|
use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException;
|
|
use Illuminate\Support\Facades\DB;
|
|
use App\Common\OrderStatus;
|
|
|
|
class WxpayController
|
|
{
|
|
//微信支付 支付结果通知网址
|
|
public function notify()
|
|
{
|
|
$agent_id = request()->route('agent_id');
|
|
// $agent = Agent::find($agent_id);
|
|
|
|
$setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey']);
|
|
if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) {
|
|
return '获取系统配置失败';
|
|
}
|
|
|
|
$config = config('wechat.payment.default');
|
|
$config = array_merge($config, [
|
|
'app_id' => $setting['payee_appid'],
|
|
'mch_id' => $setting['payee_mchid'],
|
|
'key' => $setting['payee_mchkey'],
|
|
]);
|
|
$app = Factory::payment($config);
|
|
try {
|
|
$response = $app->handlePaidNotify(function ($message, $fail) use ($agent_id) {
|
|
//TODO 仅测试用
|
|
DB::table('pay_debugs')->insert(['agent_id' => $agent_id, 'type' => 1, 'content' => json_encode($message)]);
|
|
|
|
$this->log($message);
|
|
// 请求成功
|
|
if ($message['return_code'] === 'SUCCESS') {
|
|
//主要是为了区分定金支付和尾款支付,订单号带有-status后缀,分割后前面才是真正的订单号
|
|
$order_no = explode('-', $message['out_trade_no'])[0];
|
|
$order = Order::query()
|
|
->where(['order_no' => $order_no])
|
|
->first();
|
|
|
|
//已经处理过的订单直接返回true
|
|
if ($order && in_array($order->status, [OrderStatus::PAID, OrderStatus::PAID_RETAINAGE, OrderStatus::SUCCESS])) {
|
|
return true;
|
|
}
|
|
|
|
//判断该微信支付订单号有没有处理过
|
|
$exist_log = UserMoneyLog::where([
|
|
'user_id' => $order->user_id,
|
|
'order_id' => $order->id,
|
|
'type' => 1,
|
|
'transaction_id' => $message['transaction_id'],
|
|
])->first();
|
|
if ($exist_log) {
|
|
return true;
|
|
}
|
|
|
|
// 支付成功
|
|
if ($message['result_code'] === 'SUCCESS') {
|
|
DB::beginTransaction();
|
|
try {
|
|
//增加销量,库存在拍下时已经减了
|
|
$agent_product = AgentProduct::find($order->agent_product_id);
|
|
$agent_product->increment('sale', $order->num);
|
|
|
|
Product::query()
|
|
->where('id', $order->product_id)
|
|
->increment('sale', $order->num);
|
|
|
|
$status = $order->status;
|
|
$pay_type = $order->pay_type;
|
|
$money = $message['total_fee'] / 100;
|
|
//定金支付和首付款支付
|
|
if (in_array($pay_type, [PayType::DEPOSIT_PAY, PayType::EARNEST_PAY, PayType::DOWN_PAYMENT])) {
|
|
if ($status == OrderStatus::UNPAID) {
|
|
$order->status = OrderStatus::PAY_EARNEST;
|
|
} else if ($status == OrderStatus::PAY_EARNEST) {
|
|
$order->status = OrderStatus::PAID_RETAINAGE;
|
|
$order->verify_code = uniqid(); //生成核销码
|
|
}
|
|
} else if ($pay_type == PayType::ONLINE) {
|
|
$order->status = OrderStatus::PAID;
|
|
$order->verify_code = uniqid(); //生成核销码
|
|
}
|
|
|
|
$order->paid_at = now();
|
|
$order->paid_money = DB::raw('`paid_money` + ' . $money);
|
|
//如果是已付定金,重新设置超时时间,否则清除超时时间
|
|
if ($order->status == OrderStatus::PAY_EARNEST) {
|
|
if ($pay_type == PayType::DEPOSIT_PAY || $pay_type == PayType::EARNEST_PAY) { //订金超时
|
|
$time = $order->prepay_timeout * 60;
|
|
}
|
|
if (empty($time)) { //默认订单超时
|
|
$time = (AgentSetting::val($agent_id, 'order_timeout') ?? 60) * 60;
|
|
}
|
|
$order->timeout = date('Y-m-d H:i:s', time() + $time);
|
|
} else {
|
|
$order->timeout = null;
|
|
}
|
|
$order->save();
|
|
|
|
//资金流水
|
|
UserMoneyLog::query()->create([
|
|
'user_id' => $order->user_id,
|
|
'agent_id' => $order->agent_id,
|
|
'money' => $money,
|
|
'order_id' => $order->id,
|
|
'type' => 1,
|
|
'desc' => DB::raw("LEFT('购买产品:{$order->title}', 250)"),
|
|
'transaction_id' => $message['transaction_id'], //微信支付订单号
|
|
'created_at' => now(), //模型没有updated_at,无法自动写入时间
|
|
'out_trade_no' => $message['out_trade_no'] ?? '',
|
|
]);
|
|
|
|
DB::commit();
|
|
return true;
|
|
} catch (Exception $e) {
|
|
DB::rollBack();
|
|
$fail('Unknown error');
|
|
}
|
|
} // 支付失败
|
|
else if ($message['result_code'] === 'FAIL') {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// 希望微信重试
|
|
$fail('Unknown error 2');
|
|
});
|
|
} catch (InvalidSignException | Exception $e) {
|
|
$this->log($e->getMessage() . $e->getFile() . $e->getLine());
|
|
return 'error';
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
//退款通知
|
|
public function refund()
|
|
{
|
|
$agent_id = request()->route('agent_id');
|
|
// $agent = Agent::find($agent_id);
|
|
|
|
$setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey']);
|
|
if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) {
|
|
return '获取系统配置失败';
|
|
}
|
|
|
|
$config = config('wechat.payment.default');
|
|
$config = array_merge($config, [
|
|
'app_id' => $setting['payee_appid'],
|
|
'mch_id' => $setting['payee_mchid'],
|
|
'key' => $setting['payee_mchkey'],
|
|
]);
|
|
$app = Factory::payment($config);
|
|
try {
|
|
$response = $app->handleRefundedNotify(function ($message, $reqInfo, $fail) use ($agent_id) {
|
|
//TODO 仅测试用
|
|
DB::table('pay_debugs')->insert(['agent_id' => $agent_id, 'type' => 2, 'content' => json_encode($message)]);
|
|
|
|
// 记录一下本地调试
|
|
$this->log(['message' => $message, 'reqInfo' => $reqInfo], 'refund');
|
|
// 请求成功
|
|
if ($message['return_code'] === 'SUCCESS') {
|
|
//主要是为了区分定金支付和尾款支付,订单号带有-status后缀,分割后前面才是真正的订单号
|
|
$order_no = explode('-', $reqInfo['out_trade_no'])[0];
|
|
$order = Order::query()
|
|
->where(['order_no' => $order_no])
|
|
->first();
|
|
|
|
//如果已经处理过则不再处理
|
|
if ($order->status == OrderStatus::REFUNDED) {
|
|
return true;
|
|
}
|
|
|
|
//如果已经存在相关的退款记录,也不再处理
|
|
$exist_log = UserMoneyLog::where([
|
|
'user_id' => $order->user_id,
|
|
'order_id' => $order->id,
|
|
'type' => 2,
|
|
'transaction_id' => $reqInfo['transaction_id'],
|
|
])->first();
|
|
if ($exist_log) {
|
|
return true;
|
|
}
|
|
|
|
$log = UserMoneyLog::query()
|
|
->where([
|
|
'user_id' => $order->user_id,
|
|
'order_id' => $order->id,
|
|
'type' => 1,
|
|
'transaction_id' => $reqInfo['transaction_id'],
|
|
])->first();
|
|
|
|
if (!$log) {
|
|
$fail('找不到交易信息');
|
|
}
|
|
|
|
// 退款成功
|
|
if ($reqInfo['refund_status'] === 'SUCCESS') {
|
|
DB::beginTransaction();
|
|
try {
|
|
//更新订单状态为退款成功
|
|
$order->status = OrderStatus::REFUNDED;
|
|
$order->save();
|
|
//记录日志
|
|
UserMoneyLog::create([
|
|
'user_id' => $order->user_id,
|
|
'agent_id' => $order->agent_id,
|
|
'money' => -$reqInfo['settlement_refund_fee'] / 100,
|
|
'order_id' => $order->id,
|
|
'type' => 2,
|
|
'desc' => DB::raw("LEFT('退款:{$order->title}', 250)"),
|
|
'transaction_id' => $reqInfo['transaction_id'],
|
|
'created_at' => now(), //模型没有updated_at,无法自动写入时间
|
|
]);
|
|
|
|
// 退库存
|
|
Product::query()
|
|
->where('id', $order->product_id)
|
|
->increment('stock', $order->num);
|
|
|
|
DB::commit();
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
$fail('Unknown error');
|
|
}
|
|
}
|
|
}
|
|
|
|
$fail('Unknown error 2');
|
|
});
|
|
} catch (Exception $e) {
|
|
return 'error';
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
//保存消息,用于调试
|
|
private function log($write_data, $type = 'notify')
|
|
{
|
|
$dir = storage_path('wxpay');
|
|
if (!is_dir($dir)) {
|
|
mkdir($dir);
|
|
}
|
|
$filename = $dir . '/' . $type . '_' . date('Y-m-d-H') . '.log';
|
|
$data = '[' . date('Y-m-d H:i:s') . ']' . PHP_EOL;
|
|
$data .= '[message]: ' . (is_array($write_data) ? json_encode($write_data) : $write_data) . PHP_EOL . PHP_EOL;
|
|
file_put_contents($filename, $data, FILE_APPEND);
|
|
}
|
|
}
|