dlh_test_server/app/api/controller/Billions.php
2024-12-06 23:19:19 +08:00

444 lines
19 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\api\controller;
use app\api\validate\BillionsWithdrawValidate;
use app\common\basics\Api;
use app\api\logic\BillionsLogic;
use app\common\server\JsonServer;
use app\common\server\WeChatServer;
use EasyWeChat\Factory;
use app\common\model\WithdrawApply;
use think\facade\Db;
use app\common\logic\Billions as BillionsModel;
class Billions extends Api
{
public $like_not_need_login = ['lists'];
public static function getApp($client)
{
$config = WeChatServer::getPayConfigBySource($client)['config'];
$app = Factory::payment($config);
return $app;
}
public function lists()
{
$page = $this->request->get('page_no', $this->page_no);
$size = $this->request->get('page_size', $this->page_size);
$state = $this->request->get('state', 0);
$user_id = $this->request->get('user_id', $this->user_id);
if($user_id == 0 ){
$user_id = $this->user_id;
}
$list = BillionsLogic::lists($page, $size, $state, $user_id);
foreach($list['list'] as $key=>$value){
$ranking = BillionsLogic::getRanking($value['billions_id']);
$list['list'][$key]['ranking'] = $ranking;
BillionsLogic::checkBillions($value['billions_id'],$ranking,$user_id);
}
return JsonServer::success('获取成功', $list);
}
// 脚本1分钟运行一次
/**
* @notes 提现
*/
public function withdrawal()
{
$id = $this->request->post('billions_id');
if (BillionsLogic::withdrawRecord($id, $this->user_id)) {
return JsonServer::success('操作成功');
}
return JsonServer::error('操作失败');
}
/**
* @notes 获取提现配置
*/
public function config()
{
$data = BillionsLogic::getSubsidyWithdraw($this->user_id);
return JsonServer::success('', $data);
}
/**
* @notes 提交提现
*/
public function balanceapply()
{
$post = $this->request->post();
$post['user_id'] = $this->user_id;
(new BillionsWithdrawValidate())->goCheck('apply', $post);
$id = BillionsLogic::balanceapply($this->user_id, $post);
// (new BalanceWithdrawValidate())->goCheck('apply', $post);
// $id = WithdrawLogic::balanceapply($this->user_id, $post);
// return JsonServer::success('申请成功', ['id' => $id]);
}
/**
* @notes 百亿充值到本地余额
*/
public function rechargeBalance()
{
$post = $this->request->post();
return JsonServer::error("功能维护中");
$result = BillionsLogic::applyBillionsBalance($this->user_id, $post);
return JsonServer::success("请求成功",$result);
}
public function postBillions(){
$post = $this->request->post();
$result = BillionsLogic::asynchronousBillions($this->user_id, $post);
if ($result['code'] == -1) {
return JsonServer::error($result['msg']);
}
if ($result['code'] == 1) {
return JsonServer::success($result['msg']);
}
}
public function billionWithdrawal(){
$user_id = $this->user_id;
$price = $this->request->post("money");
$type = 1;
$user_msg = Db::name("user")->where("id",$user_id)->where("del",0)->find();
if($user_msg == null){
return JsonServer::error('无效账户');
}
$subsidy_withdrawal = Db::name("subsidy_withdrawal")->where("user_id",$user_id)->find();
if($price > $subsidy_withdrawal['total_amount']){
return JsonServer::error('提现金额不能大于佣金余额');
}
// 微信零钱最小提现金额 1元
if($price < 1) {
return JsonServer::error('扣除手续费后提现金额不能小于1元');
}
if($price > 500) {
return JsonServer::error('提现金额不能大于500');
}
// 每天最多可向同一用户付款7次
$count = Db::name('withdraw_apply')
->whereTime('update_time', 'd') // 今天
->where('user_id', $user_id)
->where('type', 2) // 微信零钱
->where('status', '>=', 2) // 提现中、提现成功、提现失败
->count();
if($count >= 7) {
return JsonServer::error('同一个用户一天最多可付款7次');
}
// 一个商户默认同一日付款总额限额10万元
$sum = Db::name('withdraw_apply')
->whereTime('update_time', 'd') // 今天
->where('type', 2) // 微信零钱
->where('status', 'in', [2, 3]) // 提现中、提现成功
->sum('left_money');
$sum = $sum + $price;
if($sum > 20000) {
return JsonServer::error('一个用户默认同一日付款总额限额2万元');
}
// 用户授权信息(同一个用户可能有多条,取client最小的一条)
$userAuth = Db::name('user_auth')->where('user_id', $user_id)->order('client', 'asc')->find();
if(!$userAuth) {
// 无授权记录
return JsonServer::error('查询不到该用户的openid');
}
//提现手续费
$poundage = 0;
$poundage_config = 0;
// if ($type != WithdrawEnum::TYPE_BALANCE) {
$p_msg = Db::name("config")->where("type","withdraw")->where("name","poundage")->find();
$poundage_config = $p_msg['value'];
// $poundage_config = ConfigServer::get('withdraw', 'poundage', 0);
$poundage = $price * $poundage_config / 100;
// }
$data = [
'sn' => createSn('withdraw_apply', 'sn'),
'batch_no' => createSn('withdraw_apply', 'batch_no','SJZZ'),
'user_id' => $user_id,
'type' => $type,
'account' => $post['account'] ?? '',
'real_name' => $user_msg['real_name'] ?? '',
'money' => $price,
'withdraw_source'=>2, //反补提现
'left_money' => $price - $poundage,
'money_qr_code' => $post['money_qr_code'] ?? '',
'remark' => $post['remark'] ?? '',
'bank' => $post['bank'] ?? '',
'subbank' => $post['subbank'] ?? '',
'poundage' => $poundage,
'status' => 1, // 待提现
'create_time' => time(),
];
$withdraw_id = WithdrawApply::insertGetId($data);
//获取配置信息
$config = WeChatServer::getPayConfigBySource($userAuth['client'])['config'];
$withdraw_msg = Db::name("withdraw_apply")->where("id",$withdraw_id)->find();
//请求URL
$url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
//移除表情
$user_msg['nickname'] = self::removeEmojiChar($user_msg['nickname']);
//请求方式
$http_method = 'POST';
//请求参数
// $user_msg['nickname'] = mb_convert_encoding($user_msg['nickname'], "UTF-8", "auto");
$data = [
'appid' => $config['app_id'],//申请商户号的appid或商户号绑定的appid(企业号corpid即为此appid)
'out_batch_no' => $withdraw_msg['batch_no'],//商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
'batch_name' => '提现至微信零钱',//该笔批量转账的名称
'batch_remark' => '提现至微信零钱,昵称:'.$user_msg['nickname'],//转账说明,UTF8编码,最多允许32个字符
'total_amount' => (int)($withdraw_msg['left_money'] * 100),//转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致,否则无法发起转账操作
'total_num' => 1,//一个转账批次单最多发起三千笔转账。转账总笔数必须与批次内所有明细之和保持一致,否则无法发起转账操作
'transfer_detail_list' => [
[//发起批量转账的明细列表,最多三千笔
'out_detail_no' => $withdraw_msg['sn'],//商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成
'transfer_amount' => (int)($withdraw_msg['left_money'] * 100),//转账金额单位为分
'transfer_remark' => '提现至微信零钱',//单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符
'openid' => $userAuth['openid'],//openid是微信用户在公众号appid下的唯一用户标识(appid不同,则获取到的openid就不同),可用于永久标记一个用户
]]
];
if ($withdraw_msg['left_money'] >= 2000) {
if (empty($withdraw_msg['real_name'])) {
throw new \Exception('转账金额 >= 2000元,收款用户真实姓名必填');
}
$data['transfer_detail_list'][0]['user_name'] = self::getEncrypt($withdraw_msg['real_name'],$config);
}
$token = self::token($url,$http_method,$data,$config);//获取token
// var_dump($token);
$result = self::https_request($url,json_encode($data),$token);//发送请求
// var_dump($result);
$result_arr = json_decode($result,true);
// var_dump($result_arr);
// $result_arr['d'] = 1;
if(!isset($result_arr['create_time'])) {//批次受理失败
// $result_arr['d'] = 0;
Db::name('withdraw_apply')
->where('id', $withdraw_msg['id'])
->update([
'status' => 4, // 提现中
'update_time' => time(),
'pay_desc' => $result
]);
return JsonServer::error('提现失败,请稍后再试');
// throw new \Exception($result_arr['message']);
}
//批次受理成功,更新提现申请单为提现中状态
Db::name('withdraw_apply')
->where('id', $withdraw_msg['id'])
->update([
'status' => 3, // 提现中
'update_time' => time(),
'pay_desc' => $result
]);
Db::name('subsidy_withdrawal')
->where('user_id', $user_id)
->dec("total_amount",$price)
->update();
$da['subsidy_withdrawal_id'] = $subsidy_withdrawal['id'];
$da['user_id'] = $user_id;
$da['type'] = 2;
$da['way'] = 1;
$da['commission_money'] = $poundage;
$da['commission'] = $poundage_config;
$da['take_money'] = $withdraw_msg['left_money'];
$da['money'] = $price;
$da['sn'] = $withdraw_msg['sn'];
$da['create_time'] = date("Y-m-d H:i:s");
Db::name("subsidy_withdrawal_record")->save($da);
return JsonServer::success('零钱提现中');
}
public function advance($billions_id,$money){
if($money < 1){
return JsonServer::error('提现金额不能小于1元');
}
$result = Db::name("user_billions")
->where("state",0)
->where("billions_id",$billions_id)
->find();
if($result == null){
return JsonServer::error('已结束的返补无法提现');
}
if($money > $result['subsidy_price']-$result['available_amount']){
return JsonServer::error('提现金额不能大于返补金额');
}
$data['available_amount'] = $result['available_amount'] + $money;
$data['withdrawal_amount'] = $result['withdrawal_amount'] - $money;
if($data['withdrawal_amount']<0){
return JsonServer::error('提现金额不能大于可提现金额');
}
$r = Db::name("user_billions")
->where("billions_id",$billions_id)
->update($data);
if($r){
$first_user_all_account = Db::name("subsidy_withdrawal")->where("user_id",$result['user_id'])->find();
if($first_user_all_account != null){
// 判断账户是否可用
if($first_user_all_account['state'] == 0 || $first_user_all_account['state'] == 2){
return -2;
}
// 更新主表
$first_update_subsidy_withdrawal = Db::name("subsidy_withdrawal")->where("user_id",$result['user_id'])->inc("total_amount",$money)->update();
if(!$first_update_subsidy_withdrawal){
return -4;
}
$dat['subsidy_withdrawal_id'] = $first_user_all_account['id'];
$dat['user_id'] = $result['user_id'];
$dat['billions_id'] = $result['billions_id'];
$dat['way'] = 4;
$dat['type'] = 1;
$dat['money'] = $money;
$dat['take_money'] = $money;
$dat['create_time'] = date("Y-m-d H:i:s");
// 插入提现记录
$first_save_record = Db::name("subsidy_withdrawal_record")->save($dat);
if(!$first_save_record){
return JsonServer::error('返补余额增加失败');
}
}else{
$d['user_id'] = $result['user_id'];
$d['total_amount'] = $money;
$first_update_subsidy_withdrawal = Db::name("subsidy_withdrawal")->insertGetId($d);
if(!$first_update_subsidy_withdrawal){
return JsonServer::error('新增返补余额失败');
}
$dat['subsidy_withdrawal_id'] = $first_update_subsidy_withdrawal;
$dat['user_id'] = $result['user_id'];
$dat['billions_id'] = $result['billions_id'];
$dat['way'] = 4;
$dat['type'] = 1;
$dat['money'] = $money ;
$dat['take_money'] = $money;
$dat['create_time'] = date("Y-m-d H:i:s");
// 插入提现记录
$first_save_record = Db::name("subsidy_withdrawal_record")->save($dat);
if(!$first_save_record){
return JsonServer::error('返补余额增加失败');
}
}
$billions = new BillionsModel();
$type = "billions_use";
$order['id'] = 0;
// 6为提前消费金额
$order['type'] = 6;
$order['order_sn'] = "billions".time().$result['user_id'];
$order['order_amount'] = $money;
$billions_result = $billions->billions($order,$result['user_id'],$type);
if($billions_result){
return JsonServer::success('提现成功');
}else{
return JsonServer::error('参与返补失败');
}
}else{
return JsonServer::error('提现失败');
}
}
public static function removeEmojiChar($str){
$mbLen = mb_strlen($str);
$strArr = [];
for ($i = 0; $i < $mbLen; $i++) {
$mbSubstr = mb_substr($str, $i, 1, 'utf-8');
if (strlen($mbSubstr) >= 4) {
continue;
}
$strArr[] = $mbSubstr;
}
return implode('', $strArr);
}
public static function token($url,$http_method,$data,$config)
{
$timestamp = time();//请求时间戳
$url_parts = parse_url($url);//获取请求的绝对URL
$nonce = $timestamp.rand('10000','99999');//请求随机串
$body = empty($data) ? '' : json_encode((object)$data);//请求报文主体
$stream_opts = [
"ssl" => [
"verify_peer"=>false,
"verify_peer_name"=>false,
]
];
$apiclient_cert_arr = openssl_x509_parse(file_get_contents($config['cert_path'],false, stream_context_create($stream_opts)));
$serial_no = $apiclient_cert_arr['serialNumberHex'];//证书序列号
$mch_private_key = file_get_contents($config['key_path'],false, stream_context_create($stream_opts));//密钥
$merchant_id = $config['mch_id'];//商户id
$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
$message = $http_method."\n".
$canonical_url."\n".
$timestamp."\n".
$nonce."\n".
$body."\n";
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign);//签名
$schema = 'WECHATPAY2-SHA256-RSA2048';
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$merchant_id, $nonce, $timestamp, $serial_no, $sign);//微信返回token
return $schema.' '.$token;
}
public static function https_request($url,$data,$token)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, (string)$url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//添加请求头
$headers = [
'Authorization:'.$token,
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
];
if(!empty($headers)){
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
/**
* @notes 百亿充值记录
*/
public function rechargeRecord()
{
$get = $this->request->get();
$get['page_no'] = $get['page_no'] ?? $this->page_no;
$get['page_size'] = $get['page_size'] ?? $this->page_size;
$get['user_id'] = $this->user_id;
// $get['type'] = $get['type'] ?? 'balance'; 参数暂时不用
$result = BillionsLogic::rechargeRecord($get);
return JsonServer::success('', $result);
}
/**
* @notes 百亿提现记录
*/
public function withdrawalRecord()
{
$get = $this->request->get();
$get['page_no'] = $get['page_no'] ?? $this->page_no;
$get['page_size'] = $get['page_size'] ?? $this->page_size;
$get['user_id'] = $this->user_id;
// $get['type'] = $get['type'] ?? 'weixin'; 参数暂时不用
$result = BillionsLogic::withdrawalRecord($get);
return JsonServer::success('', $result);
}
}