You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
payment/app/Controller/Recharge/RechargeController.php

402 lines
15 KiB
PHTML

1 year ago
<?php
declare(strict_types=1);
namespace App\Controller\Recharge;
use App\Exception\BusinessException;
use App\Exception\UnauthorizedException;
use App\Helper\Redis;
use App\Helper\StringHelper;
use App\Model\App;
use App\Model\BankCard;
use App\Model\Order;
1 year ago
use App\Model\PrePayLog;
1 year ago
use App\Model\User;
use App\Service\PaymentService;
use Hyperf\HttpServer\Contract\RequestInterface;
class RechargeController extends AbstractController
{
private PaymentService $paymentService;
public function __construct(PaymentService $paymentService)
{
$this->paymentService = $paymentService;
}
1 year ago
public function getMemberInfo(RequestInterface $request) {
1 year ago
[$app, $prePayLog] = $this->checkToken($request->input('stoken', ''));
1 year ago
$outMemberId = $prePayLog->out_member_id;
$user = User::where('app_id', $app->app_id)->where('out_member_id', $outMemberId)->first();
1 year ago
$bankCard = null;
1 year ago
$userInfo = null;
1 year ago
if ($user) {
1 year ago
$bankCard = BankCard::where('app_id', $app->app_id)->where('out_member_id', $outMemberId)->where('status', BankCard::STATUS_ACTIVE)->first();
1 year ago
$userInfo = [
'name' => $user->real_name ?? '',
'cardNo' => $user->card_no ?? '',
'mobile' => $user->mobile ?? '',
'bankCardNo' => $bankCard->bank_card_no ?? '',
];
1 year ago
}
return $this->success([
1 year ago
'user' => $userInfo,
'amount' => intval($prePayLog->amount / 100),
1 year ago
]);
}
1 year ago
public function recharge(RequestInterface $request) {
1 year ago
[$app, $prePayLog] = $this->checkToken($request->input('stoken', ''));
1 year ago
$name = $request->input('name');
if (empty($name)) {
throw new BusinessException('请输入姓名');
}
$amount = $request->input('amount');
1 year ago
if ($prePayLog->amount == 0) {
$amount = $request->input('amount');
if (empty($amount)) {
throw new BusinessException('请输入金额');
}
if (!is_numeric($amount)) {
throw new BusinessException('请输入金额');
}
if ($amount <= 0) {
throw new BusinessException('金额需大于0');
}
1 year ago
}
1 year ago
1 year ago
$cardNo = $request->input('cardNo');
if (empty($cardNo)) {
throw new BusinessException('请输入身份证号');
}
$mobile = $request->input('mobile');
if (empty($mobile)) {
throw new BusinessException('请输入手机号');
}
$bankCardNo = $request->input('bankCardNo');
if (empty($bankCardNo)) {
throw new BusinessException('请输入银行卡号');
}
1 year ago
$outMemberId = $prePayLog->out_member_id;
$user = User::where('app_id', $app->app_id)->where('out_member_id', $outMemberId)->first();
1 year ago
$bankCard = null;
if ($user) {
1 year ago
$bankCard = BankCard::where('app_id', $app->app_id)
->where('out_member_id', $outMemberId)
->where('bank_card_no', $bankCardNo)
->where('status', BankCard::STATUS_ACTIVE)->first();
$mobile = $user->mobile;
$cardNo = $user->cardNo;
$name = $user->real_name;
1 year ago
}
if ($bankCard) {
1 year ago
$outOrderNo = $prePayLog->out_order_no;
1 year ago
$nextStep = 'confirm-pay';
1 year ago
$amount = $prePayLog->amount > 0 ? $prePayLog->amount : intval($amount * 100);
1 year ago
$bizData = $this->paymentService->protocolPayPreRequest($this->buildPrepayParams($outMemberId, $outOrderNo, $bankCard->protocol, $amount, $prePayLog->notify_url, $app));
1 year ago
} else {
$mchOrderNo = StringHelper::generateBankCardOrderNo();
$nextStep = 'confirm-bind';
1 year ago
$bizData = $this->paymentService->bindCard($this->buildBindCardParams(
1 year ago
$mchOrderNo, $outMemberId, $name, $cardNo, $mobile, $bankCardNo, $app
1 year ago
));
1 year ago
}
return $this->success([
'nextStep' => $nextStep,
1 year ago
'outMemberId' => $outMemberId,
1 year ago
'bizData' => $bizData
]);
}
public function confirmBindCard(RequestInterface $request) {
1 year ago
[$app, $prePayLog] = $this->checkToken($request->input('stoken', ''));
1 year ago
$smsNo = $request->input('smsNo');
$smsCode = $request->input('smsCode');
1 year ago
$bizData = $this->paymentService->bindCardConfirm($this->buildComfirmBindCardParams($prePayLog->out_member_id, $smsNo, $smsCode, $app));
1 year ago
return $this->success([
1 year ago
'outMemberId' => $prePayLog->out_member_id,
1 year ago
'bizData' => $bizData
]);
}
1 year ago
public function confirmBindCardAndPay(RequestInterface $request) {
[$app, $prePayLog] = $this->checkToken($request->input('stoken', ''));
$amount = $request->input('amount');
if ($prePayLog->amount == 0) {
$amount = $request->input('amount');
if (empty($amount)) {
throw new BusinessException('请输入金额');
}
if (!is_numeric($amount)) {
throw new BusinessException('请输入金额');
}
if ($amount <= 0) {
throw new BusinessException('金额需大于0');
}
}
$outMemberId = $prePayLog->out_member_id;
$outOrderNo = $prePayLog->out_order_no;
$notifyUrl = $prePayLog->notify_url;
$amount = $prePayLog->amount > 0 ? $prePayLog->amount : intval($amount * 100);
$smsNo = $request->input('smsNo');
$smsCode = $request->input('smsCode');
$this->paymentService->protocolPayPreRequest($this->buildConfirmBindAndPay($outMemberId, $outOrderNo, $smsNo, $smsCode, $amount, $notifyUrl, $app));
return $this->success([
'outMemberId' => $prePayLog->out_member_id,
'bizData' => ['outOrderNo' => $prePayLog->out_order_no]
]);
}
1 year ago
public function confirmPay(RequestInterface $request) {
1 year ago
[$app, $prePayLog] = $this->checkToken($request->input('stoken', ''));
1 year ago
$token = $request->input('token');
$protocol = $request->input('protocol');
$smsCode = $request->input('smsCode');
1 year ago
$this->paymentService->protocolPayConfirm($this->buildConfirmPayParams($token, $protocol, $smsCode, $app));
1 year ago
return $this->success([
1 year ago
'outMemberId' => $prePayLog->out_member_id,
1 year ago
'bizData' => ['outOrderNo' => $prePayLog->out_order_no]
1 year ago
]);
}
1 year ago
private function buildBindCardParams($mchOrderNo, $outMemberId, $name, $cardNo, $mobile, $bankCardNo, $app)
1 year ago
{
$params = [
'app_id' => $app->app_id,
'timestamp' => time(),
'nonce_str' => StringHelper::getRandomString(32),
'data' => json_encode([
'mchtOrderNo' => $mchOrderNo,
1 year ago
'outMemberId' => $outMemberId,
1 year ago
'userName' => $name,
'phoneNum' => $mobile,
'bankCardNo' => $bankCardNo,
'bankCardType' => 'debit',
'certificatesNo' => $cardNo,
]),
];
$sign = \App\Helper\Platform\Signer::sign($params, $app->app_key);
$params['sign'] = $sign;
return $params;
}
1 year ago
private function buildPrepayParams($outMemberId, $outOrderNo, $protocol, $amount, $notifyUrl, $app)
1 year ago
{
$params = [
'app_id' => $app->app_id,
'timestamp' => time(),
'nonce_str' => StringHelper::getRandomString(32),
'data' => json_encode([
1 year ago
'outMemberId' => $outMemberId,
1 year ago
'outOrderNo' => $outOrderNo,
1 year ago
'protocol' => $protocol,
'payAmount' => $amount,
1 year ago
'notifyUrl' => $notifyUrl,
1 year ago
]),
];
$sign = \App\Helper\Platform\Signer::sign($params, $app->app_key);
$params['sign'] = $sign;
return $params;
}
1 year ago
private function buildConfirmBindAndPay($outMemberId, $outOrderNo, $smsNo, $smsCode, $amount, $notifyUrl, $app)
{
$params = [
'app_id' => $app->app_id,
'timestamp' => time(),
'nonce_str' => StringHelper::getRandomString(32),
'data' => json_encode([
'outMemberId' => $outMemberId,
'outOrderNo' => $outOrderNo,
'payAmount' => $amount,
'notifyUrl' => $notifyUrl,
'smsNo' => $smsNo,
'smsCode' => $smsCode,
]),
];
$sign = \App\Helper\Platform\Signer::sign($params, $app->app_key);
$params['sign'] = $sign;
return $params;
}
1 year ago
private function buildConfirmPayParams($token, $protocol, $smsCode, $app)
{
$params = [
'app_id' => $app->app_id,
'timestamp' => time(),
'nonce_str' => StringHelper::getRandomString(32),
'data' => json_encode([
'token' => $token,
'protocol' => $protocol,
'smsCode' => $smsCode,
]),
];
$sign = \App\Helper\Platform\Signer::sign($params, $app->app_key);
$params['sign'] = $sign;
return $params;
}
1 year ago
private function buildComfirmBindCardParams($outMemberId, $smsNo, $smsCode, $app)
1 year ago
{
$params = [
'app_id' => $app->app_id,
'timestamp' => time(),
'nonce_str' => StringHelper::getRandomString(32),
'data' => json_encode([
1 year ago
'outMemberId' => $outMemberId,
1 year ago
'smsNo' => $smsNo,
'smsCode' => $smsCode,
]),
];
$sign = \App\Helper\Platform\Signer::sign($params, $app->app_key);
$params['sign'] = $sign;
return $params;
}
public function orders(RequestInterface $request)
{
$page = $request->input('page', 1);
$pageSize = $request->input('pageSize', 20);
1 year ago
$status = $request->input('status', 0);
$timeRange = $request->input('timeRange', null);
1 year ago
$token = $request->input('token');
1 year ago
$mobile = $request->input('mobile', '');
$cardNo = $request->input('cardNo', '');
$orderNo = $request->input('orderNo', '');
$outOrderNo = $request->input('outOrderNo', '');
$bankCardNo = $request->input('bankCardNo', '');
1 year ago
1 year ago
$appId = Redis::get('token:' . $token);
if (empty($appId)) {
1 year ago
throw new UnauthorizedException();
}
1 year ago
if ($appId == 'all') {
$appIds = App::all()->pluck('app_id')->toArray();
} else {
$appIds = explode(',', $appId);
}
1 year ago
$offset = ($page - 1) * $pageSize;
1 year ago
$query = Order::query()->whereIn('app_id', $appIds);
1 year ago
if ($status) {
$query->where('status', $status);
}
if ($mobile) {
1 year ago
$memberIds = User::whereIn('app_id', $appIds)->where('mobile', $mobile)->get(['member_id'])->pluck('member_id')->toArray();
1 year ago
$query->whereIn('member_id', $memberIds);
}
if ($cardNo) {
1 year ago
$memberIds = User::whereIn('app_id', $appIds)->where('card_no', $cardNo)->get(['member_id'])->pluck('member_id')->toArray();
1 year ago
$query->whereIn('member_id', $memberIds);
}
if ($bankCardNo) {
1 year ago
$protocols = BankCard::whereIn('app_id', $appIds)->where('bank_card_no', $bankCardNo)->get(['protocol'])->pluck('protocol')->toArray();
1 year ago
$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();
1 year ago
$protocols = $orders->pluck('protocol');
1 year ago
$bankCards = BankCard::whereIn('app_id', $appIds)->whereIn('protocol', $protocols)->get();
1 year ago
$bankCards = $bankCards->keyBy('protocol');
$records = [];
foreach ($orders as $order) {
1 year ago
$bankCard = $order->protocol ? ($bankCards[$order->protocol] ?? null) : null;
1 year ago
$records[] = [
'out_order_no' => $order->out_order_no,
'payed_at' => $order->payed_at,
'status' => $order->status,
'amount' => number_format($order->amount / 100, 2, '.', ''),
'real_name' => $bankCard ? $bankCard->real_name : '',
'bank_card_no' => $bankCard ? $bankCard->bank_card_no : '',
'mobile' => $bankCard ? $bankCard->mobile : '',
'card_no' => $bankCard ? $bankCard->card_no : '',
'status_text' => $order->getStatusText(),
];
}
1 year ago
$total = $countQuery->count();
$amount = $sumQuery->sum('amount');
1 year ago
return $this->success([
'records' => $records,
'total' => $total,
1 year ago
'amount' => $amount / 100,
1 year ago
]);
}
public function login(RequestInterface $request)
{
$username = $request->input('username');
$password = $request->input('password');
if (empty($username) || empty($password)) {
throw new BusinessException('账号或密码错误');
}
1 year ago
$user = $this->getUser($username);
if (!$user) {
throw new BusinessException('账号或密码错误');
}
1 year ago
1 year ago
if ($user['password'] !== $password) {
throw new BusinessException('账号或密码错误');
1 year ago
}
1 year ago
$token = md5(microtime() . $username . $password);
Redis::set('token:' . $token, $user['app_id']);
Redis::expire('token:' . $token, 60*60);
return $this->success(['token' => $token]);
1 year ago
}
1 year ago
private function getUser($username) {
$users = [
1 year ago
'owx0tlx' => ['password' => 'lSoLW28NxtMlxUazC8p', 'app_id' => 'all'],
1 year ago
'ioexlp2' => ['password' => 'wwU8Ir3Xp0rxXssA9NV', 'app_id' => '202305270000001'],
'lix73nxIN' => ['password' => 'a01@lWl3dfNmT', 'app_id' => '202306140000001'],
1 year ago
'xtIxt2x3L' => ['password' => 'sd3@xxgNtxxJipOmT', 'app_id' => '202306200000001'],
1 year ago
'ni2Nx2M9T' => ['password' => 'x5sN!xlNoiQxpVbs', 'app_id' => '202306260000001'],
'Nx28OpjmL' => ['password' => 'xny3MU26MRxwqStM', 'app_id' => '202306260000002'],
1 year ago
];
1 year ago
return $users[$username] ?? null;
1 year ago
}
1 year ago
private function checkToken($token) {
if (empty($token)) {
throw new BusinessException('token异常');
}
$log = PrePayLog::where('token', $token)->first();
if (empty($log)) {
throw new BusinessException('预支付记录不存在');
}
1 year ago
if ($log->created_at->timestamp < time() - 5*60) {
throw new BusinessException('支付超时,请重新请求');
}
1 year ago
$app = App::where('app_id', $log->app_id)->first();
if (empty($app)) {
throw new BusinessException('应用异常');
}
return [$app, $log];
}
1 year ago
}