diff --git a/app/Command/MineCommand.php b/app/Command/MineCommand.php index a908059..366480b 100644 --- a/app/Command/MineCommand.php +++ b/app/Command/MineCommand.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Command; use App\Helper\Efps\Api; +use App\Helper\Efps\Signer; use App\Helper\StringHelper; use App\Request\BindCardRequest; use App\Request\PaymentQueryRequest; @@ -43,6 +44,24 @@ class MineCommand extends HyperfCommand public function handle(): void { + /** + * @var PaymentService $paymentService + */ + $paymentService = $this->container->make(PaymentService::class); + + $params = $this->pay(); + $data = $paymentService->payment($params); + var_dump($data); + return; + $data = '{"amount":100,"procedureFee":0,"payerInfo":{"bankCode":"ICBC","cardType":"D","payerName":"饶丽秀","cardNo":"621226*********9613"},"payTime":"20230608205458","outTradeNo":"2023060820542300001","transactionNo":"32202306080424492842514","cashAmount":100,"customerCode":"562276004021027","payState":"00","payerAmount":100,"channelOrder":"2023060809159764121176190110008","nonceStr":"78bbeb2da77943b5845f861110048ad6"}'; + $str = 'a:1:{i:0;s:344:"ZLtxw/cBTFE+PDyxcfS+/amMMaReCPGAPS88UOEYZG4vv3ekwYDzeHOXo9yIBaaRCo98FeER+3AdFH/KNUXkcLPZPLqezFlolxfBCPoVIUk6R0d6TLMgCXYYDDUVq8OQ2na/qQYxib2eDVJtJjyxrr2HKqaCS9ZrXUIFtYeV+/o3CmtY/P4mn3sEwjaiVYOXhsmgQ8v/gW3L+Z/ba7jmDdGXTc/Fc8Uyfzh4sTzafyiqWnCRSD5dY838BzjIZKiqwBH2wKywpnEdAiqXKqjDxHac9dx4xFenxGNPxQN1wi7eKn/DHrSwV6ATuQcuEh0c5EGnGOfeEMcOJ2oroNpdgA==";}'; + $data = '{"amount":5000,"procedureFee":23,"payerInfo":{"bankCode":"ICBC","cardType":"D","payerName":"\u9c8d\u4e91\u8f89","cardNo":"621226*********3143"},"payTime":"20230610180818","outTradeNo":"2023061018080300001","transactionNo":"32202306102881341174762","cashAmount":5000,"customerCode":"562276004021027","payState":"00","payerAmount":5000,"channelOrder":"2023061016326911986931600110901","nonceStr":"bda108e1ed1947f488be4b3b23bb6562"}'; + $data = '{"amount":5000,"procedureFee":23,"payerInfo":{"bankCode":"ICBC","cardType":"D","payerName":"\u9c8d\u4e91\u8f89","cardNo":"621226*********3143"},"payTime":"20230610180818","outTradeNo":"2023061018080300001","transactionNo":"32202306102881341174762","cashAmount":5000,"customerCode":"562276004021027","payState":"00","payerAmount":5000,"channelOrder":"2023061016326911986931600110901","nonceStr":"bda108e1ed1947f488be4b3b23bb6562"}'; + $data = '{"amount":5000,"procedureFee":23,"payerInfo":{"bankCode":"ICBC","cardType":"D","payerName":"鲍云辉","cardNo":"621226*********3143"},"payTime":"20230610180818","outTradeNo":"2023061018080300001","transactionNo":"32202306102881341174762","cashAmount":5000,"customerCode":"562276004021027","payState":"00","payerAmount":5000,"channelOrder":"2023061016326911986931600110901","nonceStr":"bda108e1ed1947f488be4b3b23bb6562"}'; + $str = 'a:1:{i:0;s:344:"KKfrhc/4YNJFuphVMe8yo4sT+gQakxNtOfMqSqSeeMAHMp6684jm76p2yRog9pv7UE5WLJ8EEWajEMfLKYSBYIG9c2L3CPp+aJ+ot39SrAbq3BzCTiQvxC7Om6I7pOewU5m+ZVrlL/kLapi6lShx1vzZnGDzjJ0s+QFdY7sfm7NmqEgyZn1Q0L6IguT4/TmM0GNsB4XhO0IozXEa1EYzI//bS2eRtCLGh2TCND+4+mhdaBPsjD3F0g9C7hDU0cLPqOBd1Rzl22F0W8R0u5DzOp2ic4pdjVoWr7HV9ZS3nsnKANktLFQNSaQ3oH/dXyeY9kTfadKymPvDXavgCCmc/Q==";}'; + var_dump(unserialize($str)); + var_dump(Signer::verify($data, unserialize($str)[0])); + return; // $ret = Api::withdrawalToCard([]); // var_dump($ret); // return; @@ -227,4 +246,21 @@ class MineCommand extends HyperfCommand $params = $request->getData(); var_dump($params); } + + public function pay() + { + $params = [ + 'app_id' => '202304270000004', + 'timestamp' => time(), + 'nonce_str' => StringHelper::getRandomString(32), + 'data' => json_encode([ + 'outOrderNo' => time().rand(1000, 9999), + 'outMemberId' => 'T001', + 'notifyUrl' => 'https://www.baidu.com', + ]), + ]; + $sign = \App\Helper\Platform\Signer::sign($params, 'lSHKbuFngCXHN8Ue1s8QHAAzPvOL3u9O'); + $params['sign'] = $sign; + return $params; + } } diff --git a/app/Controller/Payment/NotifyController.php b/app/Controller/Payment/NotifyController.php index 6fb00b6..3c915e4 100644 --- a/app/Controller/Payment/NotifyController.php +++ b/app/Controller/Payment/NotifyController.php @@ -40,10 +40,10 @@ class NotifyController extends AbstractController ]; } $params = json_decode($data, true); - $outOrderNo = $params['outTradeNo'] ?: ''; - $order = Order::where('out_order_no', $outOrderNo)->first(); + $outTradeNo = $params['outTradeNo'] ?: ''; + $order = Order::where('order_no', $outTradeNo)->first(); if (!$order) { - Log::info('paymentNotifyToOut: ' . '订单号不存在[' . $outOrderNo . ']'); + Log::info('paymentNotifyToOut: ' . '订单号不存在[' . $outTradeNo . ']'); return [ 'returnCode' => '0000', 'returnMsg' => '处理成功' @@ -51,7 +51,7 @@ class NotifyController extends AbstractController } $app = App::where('app_id', $order->app_id)->first(); if (!$app) { - Log::info('paymentNotifyToOut: ' . 'APP不存在[' . $outOrderNo . '][' . $order->app_id . ']'); + Log::info('paymentNotifyToOut: ' . 'APP不存在[' . $outTradeNo . '][' . $order->app_id . ']'); return [ 'returnCode' => '0000', 'returnMsg' => '处理成功' @@ -70,12 +70,12 @@ class NotifyController extends AbstractController $this->paymentService->handlePayResult($result, $order); $result = $this->notify($order->notify_url, $app, [ - 'outTradeNo' => $params['outTradeNo'] ?: '', - 'transactionNo' => $params['transactionNo'] ?: '', + 'outOrderNo' => $order->out_order_no ?: '', + 'orderNo' => $params['outTradeNo'] ?: '', 'payState' => $params['payState'], 'amount' => $params['amount'] ?: 0, ]); - Log::info('paymentNotifyToOut result: ' . '订单[' . $outOrderNo . '][' . $$result . ']'); + Log::info('paymentNotifyToOut result: ' . '订单[' . $outTradeNo . '][' . $$result . ']'); return [ 'returnCode' => '0000', diff --git a/app/Controller/Recharge/RechargeController.php b/app/Controller/Recharge/RechargeController.php index ac8a7cc..22c64dc 100644 --- a/app/Controller/Recharge/RechargeController.php +++ b/app/Controller/Recharge/RechargeController.php @@ -26,22 +26,26 @@ class RechargeController extends AbstractController } public function getMemberInfo(RequestInterface $request) { - [$app, $prePayLog] = $this->checkToken($request->input('token', '')); + [$app, $prePayLog] = $this->checkToken($request->input('stoken', '')); $user = User::where('out_member_id', $prePayLog->out_member_id)->first(); $bankCard = null; + $userInfo = null; if ($user) { $bankCard = BankCard::where('member_id', $user->member_id)->where('status', BankCard::STATUS_ACTIVE)->first(); + $userInfo = [ + 'name' => $user->real_name ?? '', + 'cardNo' => $user->card_no ?? '', + 'mobile' => $user->mobile ?? '', + 'bankCardNo' => $bankCard->bank_card_no ?? '', + ]; } return $this->success([ - 'name' => $user->real_name ?? '', - 'card_no' => $user->card_no ?? '', - 'mobile' => $user->mobile ?? '', - 'bank_card_no' => $bankCard->bank_card_no ?? '', + 'user' => $userInfo ]); } public function recharge(RequestInterface $request) { - [$app, $prePayLog] = $this->checkToken($request->input('token', '')); + [$app, $prePayLog] = $this->checkToken($request->input('stoken', '')); $name = $request->input('name'); if (empty($name)) { throw new BusinessException('请输入姓名'); @@ -72,13 +76,17 @@ class RechargeController extends AbstractController $user = User::where('member_id', $memberId)->first(); $bankCard = null; if ($user) { + if (empty($user->out_member_id)) { + $user->out_member_id = $prePayLog->out_member_id; + $user->save(); + } $bankCard = BankCard::where('member_id', $user->member_id)->where('bank_card_no', $bankCardNo)->where('status', BankCard::STATUS_ACTIVE)->first(); } if ($bankCard) { - $outTradeNo = $prePayLog->out_order_no; + $outOrderNo = $prePayLog->out_order_no; $nextStep = 'confirm-pay'; - $bizData = $this->paymentService->protocolPayPreRequest($this->buildPrepayParams($prePayLog->out_member_id, $outTradeNo, $bankCard->protocol, intval($amount * 100), $app)); + $bizData = $this->paymentService->protocolPayPreRequest($this->buildPrepayParams($prePayLog->out_member_id, $outOrderNo, $bankCard->protocol, intval($amount * 100), $app)); } else { $mchOrderNo = StringHelper::generateBankCardOrderNo(); $nextStep = 'confirm-bind'; @@ -94,7 +102,7 @@ class RechargeController extends AbstractController } public function confirmBindCard(RequestInterface $request) { - [$app, $prePayLog] = $this->checkToken($request->input('token', '')); + [$app, $prePayLog] = $this->checkToken($request->input('stoken', '')); $outMemberId = $request->input('outMemberId'); $smsNo = $request->input('smsNo'); $smsCode = $request->input('smsCode'); @@ -106,7 +114,7 @@ class RechargeController extends AbstractController } public function confirmPay(RequestInterface $request) { - [$app, $prePayLog] = $this->checkToken($request->input('token', '')); + [$app, $prePayLog] = $this->checkToken($request->input('stoken', '')); $outMemberId = $request->input('outMemberId'); $token = $request->input('token'); $protocol = $request->input('protocol'); @@ -139,7 +147,7 @@ class RechargeController extends AbstractController return $params; } - private function buildPrepayParams($outMemberId, $outTradeNo, $protocol, $amount, $app) + private function buildPrepayParams($outMemberId, $outOrderNo, $protocol, $amount, $app) { $params = [ 'app_id' => $app->app_id, @@ -147,7 +155,7 @@ class RechargeController extends AbstractController 'nonce_str' => StringHelper::getRandomString(32), 'data' => json_encode([ 'outMemberId' => $outMemberId, - 'outTradeNo' => $outTradeNo, + 'outOrderNo' => $outOrderNo, 'protocol' => $protocol, 'payAmount' => $amount, ]), @@ -195,16 +203,53 @@ class RechargeController extends AbstractController { $page = $request->input('page', 1); $pageSize = $request->input('pageSize', 20); + $status = $request->input('status', 0); + $timeRange = $request->input('timeRange', null); $token = $request->input('token'); + $mobile = $request->input('mobile', ''); + $cardNo = $request->input('cardNo', ''); + $orderNo = $request->input('orderNo', ''); + $outOrderNo = $request->input('outOrderNo', ''); + $bankCardNo = $request->input('bankCardNo', ''); - $value = Redis::get('token:' . $token); - $users = $this->getUsers(); - if (empty($value) || !isset($users[$value])) { + $appId = Redis::get('token:' . $token); + if (empty($appId)) { throw new UnauthorizedException(); } $offset = ($page - 1) * $pageSize; - $orders = Order::query()->orderBy('id', 'desc')->offset($offset)->limit($pageSize)->get(); + $query = Order::query()->where('app_id', $appId); + if ($status) { + $query->where('status', $status); + } + if ($mobile) { + $memberIds = User::where('app_id', $appId)->where('mobile', $mobile)->get(['member_id'])->pluck('member_id')->toArray(); + $query->whereIn('member_id', $memberIds); + } + if ($cardNo) { + $memberIds = User::where('app_id', $appId)->where('card_no', $cardNo)->get(['member_id'])->pluck('member_id')->toArray(); + $query->whereIn('member_id', $memberIds); + } + if ($bankCardNo) { + $protocols = BankCard::where('app_id', $appId)->where('bank_card_no', $bankCardNo)->get(['protocol'])->pluck('protocol')->toArray(); + $query->whereIn('protocol', $protocols); + } + if ($orderNo) { + $query->where('order_no', $orderNo); + } + if ($outOrderNo) { + $query->where('out_order_no', $outOrderNo); + } + if ($timeRange) { + $timeRange[0] .= ' 00:00:00'; + $timeRange[1] .= ' 23:59:59'; + $query->whereBetween('created_at', $timeRange); + } + + $countQuery = clone $query; + $sumQuery = clone $query; + + $orders = $query->orderBy('id', 'desc')->offset($offset)->limit($pageSize)->get(); $protocols = $orders->pluck('protocol'); $bankCards = BankCard::whereIn('protocol', $protocols)->get(); $bankCards = $bankCards->keyBy('protocol'); @@ -225,10 +270,12 @@ class RechargeController extends AbstractController ]; } - $total = Order::query()->count(); + $total = $countQuery->count(); + $amount = $sumQuery->sum('amount'); return $this->success([ 'records' => $records, 'total' => $total, + 'amount' => $amount / 100, ]); } @@ -241,28 +288,31 @@ class RechargeController extends AbstractController throw new BusinessException('账号或密码错误'); } - $users = $this->getUsers(); + $user = $this->getUser($username); + if (!$user) { + throw new BusinessException('账号或密码错误'); + } - if (isset($users[$username]) && $users[$username] === $password) { - $token = md5(microtime() . $username . $password); - Redis::set('token:' . $token, $username); - Redis::expire('token:' . $token, 60*60); - return $this->success(['token' => $token]); + if ($user['password'] !== $password) { + throw new BusinessException('账号或密码错误'); } - throw new BusinessException('账号或密码错误'); + + $token = md5(microtime() . $username . $password); + Redis::set('token:' . $token, $user['app_id']); + Redis::expire('token:' . $token, 60*60); + return $this->success(['token' => $token]); } - private function getUsers() { - return [ - 'owx0tlx' => 'lSoLW28NxtMlxUazC8p', - 'ioexlp2' => 'wwU8Ir3Xp0rxXssA9NV' + private function getUser($username) { + $users = [ + 'owx0tlx' => ['password' => 'lSoLW28NxtMlxUazC8p', 'app_id' => '202304270000004'], + 'ioexlp2' => ['password' => 'wwU8Ir3Xp0rxXssA9NV', 'app_id' => '202305270000001'], + 'lix73nxIN' => ['password' => 'a01@lWl3dfNmT', 'app_id' => '202306140000001'], ]; + return $users[$username] ?? null; } private function checkToken($token) { - $app = App::query()->orderBy('id', 'asc')->first(); - return $app; - if (empty($token)) { throw new BusinessException('token异常'); } @@ -273,10 +323,6 @@ class RechargeController extends AbstractController if ($log->created_at->timestamp < time() - 5*60) { throw new BusinessException('支付超时,请重新请求'); } - $order = Order::where('app_id', $log->app_id)->where('out_order_no', $log->out_order_no)->first(); - if ($order) { - throw new BusinessException('订单重复,请重新请求'); - } $app = App::where('app_id', $log->app_id)->first(); if (empty($app)) { throw new BusinessException('应用异常'); diff --git a/app/Service/PaymentService.php b/app/Service/PaymentService.php index efaea46..dd4b37e 100644 --- a/app/Service/PaymentService.php +++ b/app/Service/PaymentService.php @@ -35,10 +35,10 @@ class PaymentService extends AbstractService public function createOrder(App $app, array $params, $user) { $order = new Order(); $order->app_id = $app->app_id; - $order->order_no = StringHelper::generateOrderNo(); + $order->order_no = $params['outTradeNo']; $order->member_id = $user->member_id; $order->out_member_id = $params['outMemberId'] ?? ''; - $order->out_order_no = $params['outTradeNo'] ?? ''; + $order->out_order_no = $params['outOrderNo'] ?? ''; $order->amount = $params['payAmount'] ?? 0; $order->notify_url = $params['notifyUrl'] ?? ''; $order->order_info = json_encode($params['orderInfo'] ?? [], JSON_UNESCAPED_UNICODE); @@ -82,6 +82,17 @@ class PaymentService extends AbstractService $req = new ProtocolPayPreRequest($params); $app = $req->getApp(); $data = $req->getData(); + + if ($data['payAmount'] > 3000) { + throw new BusinessException('超出限额'); + } + + $order = Order::where('app_id', $app->app_id)->where('out_order_no', $data['outOrderNo'])->first(); + if ($order) { + throw new BusinessException('订单重复'); + } + + $data['outTradeNo'] = StringHelper::generateOrderNo(); $result = Api::protocolPayPre($data); $user = User::where('app_id', $app->app_id)->where('out_member_id', $data['outMemberId'])->first(); diff --git a/config/routes.php b/config/routes.php index afd0d8b..94119e5 100644 --- a/config/routes.php +++ b/config/routes.php @@ -21,6 +21,7 @@ Router::addGroup('/payment',function () { Router::post('/protocol-pay-confirm', [PayController::class, 'protocolPayConfirm']); Router::post('/refund-query', [PayController::class, 'refundQuery']); Router::post('/payment-query', [PayController::class, 'paymentQuery']); + Router::post('/pay', [PayController::class, 'payment']); }, ['middleware' => [\App\Middleware\RequestLogMiddleware::class]]); Router::addGroup('/recharge',function () { @@ -29,6 +30,7 @@ Router::addGroup('/recharge',function () { Router::post('/confirm-pay', [RechargeController::class, 'confirmPay']); Router::post('/orders', [RechargeController::class, 'orders']); Router::post('/login', [RechargeController::class, 'login']); + Router::post('/get-member-info', [RechargeController::class, 'getMemberInfo']); }); Router::addGroup('/notify',function () { diff --git a/payment.sql b/payment.sql index c868828..e01c4df 100644 --- a/payment.sql +++ b/payment.sql @@ -127,4 +127,6 @@ CREATE TABLE `pre_pay_logs` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='预支付表'; alter table users add column `out_member_id` varchar(32) not null default '' after member_id; -alter table orders add column `out_member_id` varchar(32) not null default '' after member_id; \ No newline at end of file +alter table orders add column `out_member_id` varchar(32) not null default '' after member_id; +alter table orders add column `member_id` varchar(32) not null default '' after app_id; +alter table orders add column `order_no` varchar(32) not null default '' after app_id; \ No newline at end of file diff --git a/public/index.html b/public/is9lks3d2a9ks12llsi.html similarity index 100% rename from public/index.html rename to public/is9lks3d2a9ks12llsi.html diff --git a/public/orders.html b/public/orders.html index 79eca1d..a4a0e27 100644 --- a/public/orders.html +++ b/public/orders.html @@ -11,6 +11,49 @@ 充值记录 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 查询 + + +
充值金额:{{ amount }}
+
+
+
+ :total="total" + style="margin-top: 10px"> @@ -88,8 +132,19 @@ el: '#app', data() { return { + search: { + name: '', + mobile: '', + cardNo: '', + bankCardNo: '', + orderNo: '', + outOrderNo: '', + timeRange: null, + status: undefined + }, records: [], total: 0, + amount: 0, pageSize: 20, loginVisible: false, loginer: { @@ -107,11 +162,10 @@ }, methods: { searchList(page) { - let data = { - token: window.sessionStorage.getItem('token'), - page: page, - pageSize: this.pageSize - } + let data = {...this.search} + data.token = window.sessionStorage.getItem('token'); + data.page = page; + data.pageSize = this.pageSize; axios.post('/recharge/orders', data) .then( (response) => { console.log(response); @@ -124,6 +178,7 @@ } this.records = result.data.records; this.total = result.data.total; + this.amount = result.data.amount; }) .catch((error) => { this.$message.error('请求错误'); @@ -131,6 +186,9 @@ }); console.log('submit!'); }, + query() { + this.searchList(1) + }, handleCurrentChange(val) { this.searchList(val) }, diff --git a/public/payment.html b/public/payment.html index b4e1906..338e0c3 100644 --- a/public/payment.html +++ b/public/payment.html @@ -27,7 +27,7 @@ - + @@ -74,21 +74,24 @@ el: '#app', data() { return { - token: undefined, + stoken: undefined, bindConfirmVisible: false, bindConfirmForm: { + stoken: '', smsCode: '', smsNo: '', memberId: '' }, payConfirmVisible: false, payConfirmForm: { + stoken: '', smsCode: '', memberId: '', token: '', protocol: '' }, form: { + stoken: '', name: '', mobile: '', cardNo: '', @@ -99,10 +102,14 @@ } }, created() { - this.token = this.getQueryParam('token'); - if (!this.token) { + this.stoken = this.getQueryParam('token'); + if (!this.stoken) { return this.$message.error('参数异常'); } + this.form.stoken = this.stoken; + this.bindConfirmForm.stoken = this.stoken; + this.payConfirmForm.stoken = this.stoken; + this.getMemberInfo() }, methods: { recharge() { @@ -171,16 +178,39 @@ }); console.log('submit!'); }, - getQueryParam($name) { + getQueryParam(name) { var query = window.location.search.substring(1); + console.log(query) var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); + console.log(pair[0], name) if(pair[0] == name) { return pair[1]; } } return undefined; + }, + getMemberInfo() { + axios.post('/recharge/get-member-info', {stoken: this.stoken}) + .then( (response) => { + console.log(response); + let result = response.data + if (result.code != 1000) { + return this.$message.error(response.data.message); + } + if (result.user != null) { + this.form.name = result.user.name; + this.form.cardNo = result.user.cardNo; + this.form.mobile = result.user.mobile; + this.form.bankCardNo = result.user.bankCardNo; + } + }) + .catch((error) => { + this.$message.error('请求错误'); + console.log(error); + }); + console.log('submit!'); } } })