入驻费:¥{$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([ + 'order_no' => $order_no, + 'user_type' => 1, + 'username' => $supplier->username, + 'money' => $setting['settled_supplier_cost'], + 'status' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ]); + + return $app->order->unify([ + 'product_id' => $supplier->id, + 'attach' => $supplier->username, + 'body' => mb_strcut($supplier->company_name . ' 供应商入驻', 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/AdminSupplier/Controllers/ProductController.php b/app/AdminSupplier/Controllers/ProductController.php index 2f6aabc..c8cdb9f 100644 --- a/app/AdminSupplier/Controllers/ProductController.php +++ b/app/AdminSupplier/Controllers/ProductController.php @@ -2,12 +2,16 @@ namespace App\AdminSupplier\Controllers; +use App\Admin\Repositories\Order; use App\AdminSupplier\Repositories\Product; +use App\Common\OrderStatus; use App\Common\ProductStatus; use App\Models\AgentProduct; use App\Models\AgentProductItem; +use App\Models\AgentProductSpec; use App\Models\Category; use App\Models\DiyForm; +use App\Models\ProductSpec; use Dcat\Admin\Admin; use Dcat\Admin\Form; use Dcat\Admin\Form\NestedForm; @@ -252,8 +256,16 @@ class ProductController extends AdminController if (!Admin::user()->publish_type || !in_array($form->type, Admin::user()->publish_type)) { return $form->response()->error('对不起,你没有此类产品的发布、编辑权限'); } - } else if ($form->isEditing()) { //type不允许编辑 - $form->type = $form->model()->type; + } else if ($form->isEditing()) { + $form->type = $form->model()->type; //type不允许编辑 + + //如果存在未核销的订单不允许编辑 + $exists = \App\Models\Order::where('product_id', $form->model()->id) + ->whereIn('status', [OrderStatus::PAID, OrderStatus::PAID_RETAINAGE, OrderStatus::OFFLINE_PAID, OrderStatus::REFUSED_REFUND]) + ->exists(); + if ($exists) { + return $form->response()->error('该产品还有未核销的订单,不允许编辑'); + } } //不允许编辑的字段,忽略字段不起作用? @@ -328,7 +340,33 @@ class ProductController extends AdminController ]); } - //TODO 还需要规格同步到代理商 + $delete_specs = array_filter($form->spec, fn($v) => $v['_remove_'] !== null); //删除的规格 + + //同步删除代理商规格 + AgentProductSpec::whereIn('product_spec_id', array_keys($delete_specs))->delete(); + + //最新销售价同步到代理商规格 + $product_id = $form->getKey(); + + $agent_product_ids = AgentProduct::where('product_id', $product_id)->pluck('id')->toArray(); //获取当前供应商产品的所有供应商产品ID + $product_specs = ProductSpec::where('product_id', $product_id)->get(); + $product_spec_old_ids = $form->model()->spec->pluck('id')->toArray(); //旧的规格ID(不包括新增的) + + if ($agent_product_ids && $product_spec_old_ids) { + //将代理商规格价格小于供应商销售价的,设置代理商规格的价格设置为供应商的售价 + foreach ($product_specs->whereIn('id', $product_spec_old_ids) as $v) { + AgentProductSpec::whereIn('agent_product_id', $agent_product_ids) + ->where([['product_spec_id', '=', $v->id], ['price', '<', $v->price]]) + ->update(['price' => $v->price]); + } + } + + /*if ($product_spec_old_ids) { + $product_spec_new_ids = $product_specs->whereNotIn('id', $product_spec_old_ids)->get()->toArray(); //新增的规格 + if ($product_spec_new_ids) { + //暂时不处理新增的规格 + } + }*/ } })->deleting(function (Form $form) { //不允许删除非自己的数据 diff --git a/app/Http/Controllers/Api/AgentProductController.php b/app/Http/Controllers/Api/AgentProductController.php index b819266..d2697e1 100644 --- a/app/Http/Controllers/Api/AgentProductController.php +++ b/app/Http/Controllers/Api/AgentProductController.php @@ -47,7 +47,7 @@ round( )) * 1000),0) AS `distance_m` SQL)); - $fields = ['id', 'sale', 'updated_at', 'price', 'distance_m']; //排序字段 TODO 还有距离排序 + $fields = ['id', 'sale', 'updated_at', 'price', 'distance_m']; //排序字段 $field = $fields[$type] ?? $fields[0]; $by = $by == 0 ? 'desc' : 'asc'; diff --git a/app/Http/Controllers/Api/OrderController.php b/app/Http/Controllers/Api/OrderController.php index 42c1f05..c7293b6 100644 --- a/app/Http/Controllers/Api/OrderController.php +++ b/app/Http/Controllers/Api/OrderController.php @@ -183,12 +183,11 @@ class OrderController extends Controller return $v; }, $spec); - //订单总价 - $order_price = 0; - $costPrice = 0; + $order_price = 0; //订单总价 + $costPrice = 0; //供应商成本总价 foreach ($spec as $v) { - $order_price += $v['price'] * $formData['num']; - $costPrice = bcadd($costPrice,bcmul($v->productSpec->cost_price,$formData['num'],6),6); + $order_price = bcadd($order_price, bcmul($v['price'], $formData['num'], 6), 6); + $costPrice = bcadd($costPrice, bcmul($v['cost_price'], $formData['num'], 6), 6); } $order_price = round($order_price, 2); 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..4d2202f 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)]); @@ -150,7 +160,7 @@ class WxpayController // 希望微信重试 $fail('Unknown error 2'); }); - } catch (InvalidSignException | Exception $e) { + } catch (InvalidSignException | Exception | \Exception $e) { $this->log($e->getMessage() . $e->getFile() . $e->getLine()); return 'error'; } @@ -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)]); @@ -254,7 +252,7 @@ class WxpayController $fail('Unknown error 2'); }); - } catch (Exception $e) { + } catch (Exception | \Exception $e) { $this->log($e->getMessage() . $e->getFile() . $e->getLine()); return 'error'; } @@ -274,4 +272,155 @@ 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 | \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->transaction_id = $message['transaction_id']; + $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 | \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'); //商家入驻微信支付回调 }); # 跳转到外部小程序支付