Browse Source

供应商入驻费用支付

master
李可松 4 years ago
parent
commit
d55e1d3112
  1. 2
      app/AdminAgent/Controllers/IndustryOrderController.php
  2. 108
      app/AdminSettled/Controllers/SupplierController.php
  3. 2
      app/AdminSettled/routes.php
  4. 4
      app/Http/Controllers/Api/TestController.php
  5. 194
      app/Http/Controllers/Api/WxpayController.php
  6. 133
      app/Http/Controllers/IndustryProductWxpay.php
  7. 13
      app/Models/SettledOrder.php
  8. 5
      app/Models/Supplier.php
  9. 1
      config/admin-settled.php
  10. 9
      routes/api.php

2
app/AdminAgent/Controllers/IndustryOrderController.php

@ -204,7 +204,7 @@ JS
'app_id' => $config['payee_appid'], 'app_id' => $config['payee_appid'],
'mch_id' => $config['payee_mchid'], 'mch_id' => $config['payee_mchid'],
'key' => $config['payee_mchkey'], 'key' => $config['payee_mchkey'],
'notify_url' => route('industry_product_wxpay_notify'),
'notify_url' => route('wxpay_industry_product_notify'),
]; ];
$app = Factory::payment($config); $app = Factory::payment($config);

108
app/AdminSettled/Controllers/SupplierController.php

@ -5,10 +5,12 @@ namespace App\AdminSettled\Controllers;
use App\Admin\Repositories\Supplier; use App\Admin\Repositories\Supplier;
use App\Common\UserStatus; use App\Common\UserStatus;
use App\Models\AdminSetting; use App\Models\AdminSetting;
use App\Models\SettledOrder;
use Dcat\Admin\Admin; use Dcat\Admin\Admin;
use Dcat\Admin\Form; use Dcat\Admin\Form;
use Dcat\Admin\Http\Controllers\AdminController; use Dcat\Admin\Http\Controllers\AdminController;
use Dcat\Admin\Widgets\Alert; use Dcat\Admin\Widgets\Alert;
use EasyWeChat\Factory;
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
@ -57,6 +59,7 @@ class SupplierController extends AdminController
$form->disableCreatingCheck(); $form->disableCreatingCheck();
$form->disableEditingCheck(); $form->disableEditingCheck();
$form->disableDeleteButton(); $form->disableDeleteButton();
$form->text('username')->required(); $form->text('username')->required();
$form->password('password')->minLength(6)->required(); $form->password('password')->minLength(6)->required();
$form->text('name')->required(); $form->text('name')->required();
@ -81,7 +84,9 @@ class SupplierController extends AdminController
->script('$(function(){ ->script('$(function(){
$(".field_agreement").parent().css("margin-right", 0).after(\'《<a target="_blank" href="'.$agreement_template.'" download="入驻协议">入驻协议</a>》\'); $(".field_agreement").parent().css("margin-right", 0).after(\'《<a target="_blank" href="'.$agreement_template.'" download="入驻协议">入驻协议</a>》\');
});'); });');
Admin::js('@qrcode');
})->saving(function (Form $form) { })->saving(function (Form $form) {
//禁止编辑
if ($form->isEditing()) { if ($form->isEditing()) {
return $form->response()->error('服务器出错了~~'); return $form->response()->error('服务器出错了~~');
} }
@ -112,9 +117,110 @@ class SupplierController extends AdminController
$form->status = UserStatus::UNAUDITED; $form->status = UserStatus::UNAUDITED;
$form->rate = 5; $form->rate = 5;
})->saved(function (Form $form) { })->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 = <<<JS
Dcat.swal.info(
'<div style="margin-top:1rem;"><div id="qrcode"></div><p style="text-align:center;">入驻费:¥{$cost}元</p></div>',
'<b style="color:red">请微信扫码支付,请勿关闭页面</b>',
{
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) { })->deleting(function (Form $form) {
return $form->response()->error('服务器出错了~~'); 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;
}
} }

2
app/AdminSettled/routes.php

@ -17,4 +17,6 @@ Route::group([
$router->resource('supplier', 'SupplierController'); $router->resource('supplier', 'SupplierController');
$router->resource('agent', 'AgentController'); $router->resource('agent', 'AgentController');
$router->resource('guide', 'GuideController'); $router->resource('guide', 'GuideController');
$router->get('is_pay', 'SupplierController@isPay'); //是否支付回调
}); });

4
app/Http/Controllers/Api/TestController.php

@ -2,7 +2,7 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Models\MiniProgramTemplate;
use App\Models\Supplier;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -15,7 +15,7 @@ class TestController
{ {
public function index() public function index()
{ {
dd(MiniProgramTemplate::find(26)->toArray());
dd(Supplier::with('settledOrder')->find(2)->toArray());
} }
/** /**

194
app/Http/Controllers/Api/WxpayController.php

@ -8,37 +8,47 @@ use App\Models\AdminSetting;
use App\Models\Agent; use App\Models\Agent;
use App\Models\AgentProduct; use App\Models\AgentProduct;
use App\Models\AgentSetting; use App\Models\AgentSetting;
use App\Models\IndustryOrder;
use App\Models\IndustryPayLog;
use App\Models\IndustryProduct;
use App\Models\Order; use App\Models\Order;
use App\Models\Product; use App\Models\Product;
use App\Models\SettledOrder;
use App\Models\UserMoneyLog; use App\Models\UserMoneyLog;
use EasyWeChat\Factory; use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\Exception; use EasyWeChat\Kernel\Exceptions\Exception;
use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException; use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Common\OrderStatus; use App\Common\OrderStatus;
use Illuminate\Support\Facades\Log;
class WxpayController 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']); $setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey']);
if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) { if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) {
return '获取系统配置失败'; return '获取系统配置失败';
} }
$config = config('wechat.payment.default');
$config = array_merge($config, [
$config = [
'app_id' => $setting['payee_appid'], 'app_id' => $setting['payee_appid'],
'mch_id' => $setting['payee_mchid'], 'mch_id' => $setting['payee_mchid'],
'key' => $setting['payee_mchkey'], '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 { 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)]); 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_id = request()->route('agent_id');
// $agent = Agent::find($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 { 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)]); 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; $data .= '[message]: ' . (is_array($write_data) ? json_encode($write_data) : $write_data) . PHP_EOL . PHP_EOL;
file_put_contents($filename, $data, FILE_APPEND); 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;
}
} }

133
app/Http/Controllers/IndustryProductWxpay.php

@ -1,133 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Common\OrderStatus;
use App\Common\PayType;
use App\Models\AdminSetting;
use App\Models\IndustryOrder;
use App\Models\IndustryPayLog;
use App\Models\IndustryProduct;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\Exception;
use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* 行业产品微信支付回调
* Class IndustryProductWxpay
* @package App\Http\Controllers
*/
class IndustryProductWxpay
{
public function notify()
{
$setting = AdminSetting::val(['payee_appid', 'payee_mchid', 'payee_mchkey']);
if (!isset($setting['payee_appid'], $setting['payee_mchid'], $setting['payee_mchkey'])) {
return '获取系统配置失败';
}
$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) {
//仅测试用,回调记录
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;
}
}

13
app/Models/SettledOrder.php

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SettledOrder extends Model
{
use HasFactory;
// protected $guarded = ['id'];
}

5
app/Models/Supplier.php

@ -84,4 +84,9 @@ class Supplier extends BaseModel
{ {
return $this->belongsTo('App\Models\ChinaArea', 'area_id','code'); return $this->belongsTo('App\Models\ChinaArea', 'area_id','code');
} }
public function settledOrder()
{
return $this->hasOne(SettledOrder::class, 'username', 'username')->where('user_type', 1);
}
} }

1
config/admin-settled.php

@ -153,6 +153,7 @@ return [
'agent/create', 'agent/create',
'guide', 'guide',
'guide/create', 'guide/create',
'is_pay',
], ],
], ],

9
routes/api.php

@ -21,15 +21,14 @@ use Illuminate\Support\Facades\Route;
# 登录 # 登录
Route::post('login', 'App\Http\Controllers\Api\LoginController@login'); 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::namespace('App\Http\Controllers\Api')->group(function () {
# 微信支付 # 微信支付
Route::prefix('wxpay')->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'); //商家入驻微信支付回调
}); });
# 跳转到外部小程序支付 # 跳转到外部小程序支付

Loading…
Cancel
Save