From d55e1d31127dfb03d94ed60bdaf47e81279d1b1f Mon Sep 17 00:00:00 2001 From: liapples Date: Tue, 19 Oct 2021 11:49:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BE=9B=E5=BA=94=E5=95=86=E5=85=A5=E9=A9=BB?= =?UTF-8?q?=E8=B4=B9=E7=94=A8=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/IndustryOrderController.php | 2 +- .../Controllers/SupplierController.php | 108 +++++++++- app/AdminSettled/routes.php | 2 + app/Http/Controllers/Api/TestController.php | 4 +- app/Http/Controllers/Api/WxpayController.php | 194 +++++++++++++++--- app/Http/Controllers/IndustryProductWxpay.php | 133 ------------ app/Models/SettledOrder.php | 13 ++ app/Models/Supplier.php | 5 + config/admin-settled.php | 1 + routes/api.php | 9 +- 10 files changed, 306 insertions(+), 165 deletions(-) delete mode 100644 app/Http/Controllers/IndustryProductWxpay.php create mode 100644 app/Models/SettledOrder.php diff --git a/app/AdminAgent/Controllers/IndustryOrderController.php b/app/AdminAgent/Controllers/IndustryOrderController.php index 96e4ff1..f4e5a39 100644 --- a/app/AdminAgent/Controllers/IndustryOrderController.php +++ b/app/AdminAgent/Controllers/IndustryOrderController.php @@ -204,7 +204,7 @@ JS 'app_id' => $config['payee_appid'], 'mch_id' => $config['payee_mchid'], 'key' => $config['payee_mchkey'], - 'notify_url' => route('industry_product_wxpay_notify'), + 'notify_url' => route('wxpay_industry_product_notify'), ]; $app = Factory::payment($config); diff --git a/app/AdminSettled/Controllers/SupplierController.php b/app/AdminSettled/Controllers/SupplierController.php index a9b95c8..3ad1f58 100644 --- a/app/AdminSettled/Controllers/SupplierController.php +++ b/app/AdminSettled/Controllers/SupplierController.php @@ -5,10 +5,12 @@ namespace App\AdminSettled\Controllers; use App\Admin\Repositories\Supplier; use App\Common\UserStatus; use App\Models\AdminSetting; +use App\Models\SettledOrder; use Dcat\Admin\Admin; use Dcat\Admin\Form; use Dcat\Admin\Http\Controllers\AdminController; use Dcat\Admin\Widgets\Alert; +use EasyWeChat\Factory; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Storage; @@ -57,6 +59,7 @@ class SupplierController extends AdminController $form->disableCreatingCheck(); $form->disableEditingCheck(); $form->disableDeleteButton(); + $form->text('username')->required(); $form->password('password')->minLength(6)->required(); $form->text('name')->required(); @@ -81,7 +84,9 @@ class SupplierController extends AdminController ->script('$(function(){ $(".field_agreement").parent().css("margin-right", 0).after(\'《入驻协议》\'); });'); + Admin::js('@qrcode'); })->saving(function (Form $form) { + //禁止编辑 if ($form->isEditing()) { return $form->response()->error('服务器出错了~~'); } @@ -112,9 +117,110 @@ class SupplierController extends AdminController $form->status = UserStatus::UNAUDITED; $form->rate = 5; })->saved(function (Form $form) { - return $form->response()->success('操作成功,请等待管理员审核')->refresh(); + $pay = (new SupplierController)->payConfig($form->repository()->model()); + + if (empty($pay['code_url'])) { + if (isset($pay['result_code'], $pay['err_code_des']) && $pay['result_code'] != 'SUCCESS') { + $msg = $pay['err_code_des']; + } else { + $msg = $pay['return_msg'] ?? '获取支付信息失败'; + } + $js = "Dcat.swal.info('支付:$msg', null);"; + } else { + $ajax_url = admin_url('is_pay'); + $cost = AdminSetting::val('settled_supplier_cost'); + $js = <<

入驻费:¥{$cost}元

', + '请微信扫码支付,请勿关闭页面', + { + type: null, + imageWidth: 240, + imageHeight: 240, + animation: false, + // confirmButtonText: '我已完成支付,刷新', + showConfirmButton: false, + allowOutsideClick: false, + allowEscapeKey: false, + onOpen: function () { + $('#qrcode').qrcode({text:'{$pay["code_url"]}', width:240, height:240}); + if (window.timer) { + clearInterval(window.timer); + } + window.timer = setInterval(function () { + $.ajax({ + url: '$ajax_url', + data: { + username: '{$form->repository()->model()->username}' + }, + success: function (res) { + if (res == 1) { + clearInterval(window.timer); + Dcat.swal.success('支付成功,请联系平台审核!', null, { + onClose: function () { + window.location.reload(); + } + }).then(() => { + window.location.reload(); + }); + } + } + }); + }, 1000); + } + }); + JS; + } + return $form->response()->success('操作成功,请等待管理员审核')->script($js); })->deleting(function (Form $form) { return $form->response()->error('服务器出错了~~'); }); } + + //付款 + private function payConfig($supplier) + { + $setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey', 'settled_supplier_cost']); + $config = [ + 'app_id' => $setting['payee_appid'], + 'mch_id' => $setting['payee_mchid'], + 'key' => $setting['payee_mchkey'], + 'notify_url' => route('wxpay_settled_notify'), + ]; + $app = Factory::payment($config); + + //生成订单号 + list($micro, $sec) = explode(' ', microtime()); + $micro = str_pad(floor($micro * 1000000), 6, 0, STR_PAD_LEFT); + $order_no = date('ymdHis', $sec) . $micro . mt_rand(1000, 9999); + + //保存订单记录 + SettledOrder::insertOrIgnore([ + 'out_trade_no' => $order_no, + 'user_type' => 1, + 'username' => $supplier->username, + 'money' => $setting['settled_supplier_cost'], + 'status' => 0, + ]); + + return $app->order->unify([ + 'product_id' => $supplier->id, + 'attach' => $supplier->username, + 'body' => mb_strcut($supplier->username . ' 供应商入驻', 0, 127), + 'out_trade_no' => $order_no, + 'total_fee' => round($setting['settled_supplier_cost'] * 100), //支付金额单位为分 + 'trade_type' => 'NATIVE', // 请对应换成你的支付方式对应的值类型 + ]); + } + + //ajax回调,判断是否已支付 + public function isPay(): int + { + $username = request()->input('username'); + $order = SettledOrder::where(['username' => $username, 'user_type' => 1])->first(); + if (!$order) { + return 0; + } + return (int)$order->status; + } } diff --git a/app/AdminSettled/routes.php b/app/AdminSettled/routes.php index 1fbcb86..36d028a 100644 --- a/app/AdminSettled/routes.php +++ b/app/AdminSettled/routes.php @@ -17,4 +17,6 @@ Route::group([ $router->resource('supplier', 'SupplierController'); $router->resource('agent', 'AgentController'); $router->resource('guide', 'GuideController'); + + $router->get('is_pay', 'SupplierController@isPay'); //是否支付回调 }); diff --git a/app/Http/Controllers/Api/TestController.php b/app/Http/Controllers/Api/TestController.php index 5d2ba12..4e23dcf 100644 --- a/app/Http/Controllers/Api/TestController.php +++ b/app/Http/Controllers/Api/TestController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Api; -use App\Models\MiniProgramTemplate; +use App\Models\Supplier; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; @@ -15,7 +15,7 @@ class TestController { public function index() { - dd(MiniProgramTemplate::find(26)->toArray()); + dd(Supplier::with('settledOrder')->find(2)->toArray()); } /** diff --git a/app/Http/Controllers/Api/WxpayController.php b/app/Http/Controllers/Api/WxpayController.php index 02087b5..d56b90c 100644 --- a/app/Http/Controllers/Api/WxpayController.php +++ b/app/Http/Controllers/Api/WxpayController.php @@ -8,37 +8,47 @@ use App\Models\AdminSetting; use App\Models\Agent; use App\Models\AgentProduct; use App\Models\AgentSetting; +use App\Models\IndustryOrder; +use App\Models\IndustryPayLog; +use App\Models\IndustryProduct; use App\Models\Order; use App\Models\Product; +use App\Models\SettledOrder; 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; +use Illuminate\Support\Facades\Log; class WxpayController { - //微信支付 支付结果通知网址 - public function notify() + private $app = null; + public function __construct() { - $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, [ + $config = [ 'app_id' => $setting['payee_appid'], 'mch_id' => $setting['payee_mchid'], 'key' => $setting['payee_mchkey'], - ]); - $app = Factory::payment($config); + ]; + + $this->app = Factory::payment($config); + } + + //微信支付 支付结果通知网址 + public function notify() + { + $agent_id = request()->route('agent_id'); +// $agent = Agent::find($agent_id); + try { - $response = $app->handlePaidNotify(function ($message, $fail) use ($agent_id) { + $response = $this->app->handlePaidNotify(function ($message, $fail) use ($agent_id) { //仅测试用,回调记录 DB::table('pay_debugs')->insert(['agent_id' => $agent_id, 'type' => 1, 'content' => json_encode($message)]); @@ -164,20 +174,8 @@ class WxpayController $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) { + $response = $this->app->handleRefundedNotify(function ($message, $reqInfo, $fail) use ($agent_id) { //仅测试用,回调记录 DB::table('pay_debugs')->insert(['agent_id' => $agent_id, 'type' => 2, 'content' => json_encode($message)]); @@ -274,4 +272,154 @@ class WxpayController $data .= '[message]: ' . (is_array($write_data) ? json_encode($write_data) : $write_data) . PHP_EOL . PHP_EOL; file_put_contents($filename, $data, FILE_APPEND); } + + /** + * 行业产品支付回调 + */ + public function IndustryProductNotify() + { + try { + $response = $this->app->handlePaidNotify(function ($message, $fail) { + //仅测试用,回调记录 + DB::table('pay_debugs')->insert(['agent_id' => -1, 'type' => 1, 'content' => json_encode($message)]); + + // 请求成功 + if ($message['return_code'] === 'SUCCESS') { + //主要是为了区分定金支付和尾款支付,订单号带有-status后缀,分割后前面才是真正的订单号 + $order_no = explode('-', $message['out_trade_no'])[0]; + $order = IndustryOrder::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 = IndustryPayLog::where([ + 'agent_id' => $order->agent_id, + 'supplier_id' => $order->supplier_id, + 'industry_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 { + //增加销量,库存在拍下时已经减了 + IndustryProduct::query() + ->where('id', $order->industry_product_id) + ->increment('sale', $order->num); + + $old_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 ($old_status == OrderStatus::UNPAID) { + $order->status = OrderStatus::PAY_EARNEST; + } else if ($old_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); + $order->timeout = null; + $order->save(); + + //资金流水 + IndustryPayLog::create([ + 'agent_id' => $order->agent_id, + 'supplier_id' => $order->supplier_id, + 'money' => $money, + 'industry_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) { + LOG::debug('行业产品支付:', [$e->getFile(), $e->getLine(), $e->getMessage()]); + return 'error'; + } + + return $response; + } + + /** + * 商家入驻支付回调 + */ + public function SettledNotify() + { + try { + $response = $this->app->handlePaidNotify(function ($message, $fail) { + //仅测试用,回调记录 + DB::table('pay_debugs')->insert(['agent_id' => -2, 'type' => 1, 'content' => json_encode($message)]); + + // 请求成功 + if ($message['return_code'] === 'SUCCESS') { + $order_no = $message['out_trade_no']; + $order = SettledOrder::query()->where(['order_no' => $order_no])->first(); + + //已经处理过的订单直接返回true + if ($order && $order->status == 1) { + return true; + } + + // 支付成功 + if ($message['result_code'] === 'SUCCESS') { + try { + $order->paid_money = $message['total_fee'] / 100; + $order->paid_at = now(); + $order->status = 1; + $order->save(); + + return true; + } catch (Exception $e) { + $fail('Unknown error'); + } + } // 支付失败 + else if ($message['result_code'] === 'FAIL') { + return true; + } + } + + // 希望微信重试 + $fail('Unknown error 2'); + }); + } catch (Exception $e) { + LOG::debug('商家入驻支付回调:', [$e->getFile(), $e->getLine(), $e->getMessage()]); + return 'error'; + } + + return $response; + } } diff --git a/app/Http/Controllers/IndustryProductWxpay.php b/app/Http/Controllers/IndustryProductWxpay.php deleted file mode 100644 index 7c723c7..0000000 --- a/app/Http/Controllers/IndustryProductWxpay.php +++ /dev/null @@ -1,133 +0,0 @@ - $setting['payee_appid'], - 'mch_id' => $setting['payee_mchid'], - 'key' => $setting['payee_mchkey'], - ]; - - $app = Factory::payment($config); - try { - $response = $app->handlePaidNotify(function ($message, $fail) { - //仅测试用,回调记录 - DB::table('pay_debugs')->insert(['agent_id' => 0, 'type' => 1, 'content' => json_encode($message)]); - - // 请求成功 - if ($message['return_code'] === 'SUCCESS') { - //主要是为了区分定金支付和尾款支付,订单号带有-status后缀,分割后前面才是真正的订单号 - $order_no = explode('-', $message['out_trade_no'])[0]; - $order = IndustryOrder::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 = IndustryPayLog::where([ - 'agent_id' => $order->agent_id, - 'supplier_id' => $order->supplier_id, - 'industry_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 { - //增加销量,库存在拍下时已经减了 - IndustryProduct::query() - ->where('id', $order->industry_product_id) - ->increment('sale', $order->num); - - $old_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 ($old_status == OrderStatus::UNPAID) { - $order->status = OrderStatus::PAY_EARNEST; - } else if ($old_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); - $order->timeout = null; - $order->save(); - - //资金流水 - IndustryPayLog::create([ - 'agent_id' => $order->agent_id, - 'supplier_id' => $order->supplier_id, - 'money' => $money, - 'industry_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) { - LOG::debug('行业产品支付', [$e->getFile(), $e->getLine(), $e->getMessage()]); - return 'error'; - } - - return $response; - } -} diff --git a/app/Models/SettledOrder.php b/app/Models/SettledOrder.php new file mode 100644 index 0000000..652eb30 --- /dev/null +++ b/app/Models/SettledOrder.php @@ -0,0 +1,13 @@ +belongsTo('App\Models\ChinaArea', 'area_id','code'); } + + public function settledOrder() + { + return $this->hasOne(SettledOrder::class, 'username', 'username')->where('user_type', 1); + } } diff --git a/config/admin-settled.php b/config/admin-settled.php index ffa66c8..3378c10 100644 --- a/config/admin-settled.php +++ b/config/admin-settled.php @@ -153,6 +153,7 @@ return [ 'agent/create', 'guide', 'guide/create', + 'is_pay', ], ], diff --git a/routes/api.php b/routes/api.php index bfaad21..1350621 100644 --- a/routes/api.php +++ b/routes/api.php @@ -21,15 +21,14 @@ use Illuminate\Support\Facades\Route; # 登录 Route::post('login', 'App\Http\Controllers\Api\LoginController@login'); -# 行业产品微信支付回调 -Route::any('industry_product/wxpay/notify', 'App\Http\Controllers\IndustryProductWxpay@notify')->name('industry_product_wxpay_notify'); - # 微信相关 Route::namespace('App\Http\Controllers\Api')->group(function () { # 微信支付 Route::prefix('wxpay')->group(function () { - Route::post('notify/{agent_id}', 'WxpayController@notify')->name('wxpay_notify'); //异步通知,aid为代理商ID - Route::post('refund/{agent_id}', 'WxpayController@refund')->name('wxpay_refund'); //退款通知,aid为代理商ID + Route::post('notify/{agent_id}', 'WxpayController@notify')->name('wxpay_notify'); //小程序端支付异步通知 + Route::post('refund/{agent_id}', 'WxpayController@refund')->name('wxpay_refund'); //小程序端支付退款通知 + Route::post('industry_product_notify', 'WxpayController@IndustryProductNotify')->name('wxpay_industry_product_notify'); //行业产品微信支付回调 + Route::post('settled_notify', 'WxpayController@SettledNotify')->name('wxpay_settled_notify'); //商家入驻微信支付回调 }); # 跳转到外部小程序支付