dlh_test_server/app/api/logic/WithdrawLogic.php
xucong 7d9c3f0a67 1.添加了商品状态为1
2.提现金额设置为整数
2024-09-25 15:53:22 +08:00

551 lines
21 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\logic;
use app\common\basics\Logic;
use app\common\logic\AccountLogLogic;
use app\common\model\{AccountLog, Withdraw, WithdrawApply,BalanceWithdrawApply};
use app\common\model\user\User;
use app\common\enum\WithdrawEnum;
use app\common\server\ConfigServer;
use app\common\server\JsonServer;
use app\common\server\WeChatServer;
use think\facade\Db;
use think\Exception;
use think\facade\Log;
/***
* Class WithdrawLogic 会员提现
* @package app\api\logic
*/
class WithdrawLogic extends Logic
{
/**
* @notes 基础配置
* @param $user_id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author suny
* @date 2021/7/13 6:26 下午
*/
public static function config($user_id, $hide = '')
{
$user = User::where('id', $user_id)->find();
$config = [
'able_withdraw' => $user['earnings'] ? $user['earnings'] : 0,
'balanceable_withdraw' => $user['user_money'] ? $user['user_money'] : 0,
'min_withdraw' => ConfigServer::get('withdraw', 'min_withdraw', 0),//最低提现金额;
'max_withdraw' => ConfigServer::get('withdraw', 'max_withdraw', 0),//最高提现金额;
'poundage_percent' => ConfigServer::get('withdraw', 'poundage', 0),//提现手续费;
'balancepoundage_percent' => ConfigServer::get('withdraw', 'balancepoundage', 0),//余额提现手续费;
];
$types = ConfigServer::get('withdraw', 'type', [2]); //提现方式,若未设置默认为提现方式为钱包
// 封装提现方式
$config['type'] = [];
if ($types) {
foreach ($types as $value) {
$config['type'][] = [
'name' => WithdrawEnum::getTypeDesc($value),
'value' => $value
];
}
}
// $a = $config['type'][0];
// $config['type'][0] = $config['type'][1];
// $config['type'][1] = $config['type'][2];
// if ($hide == 'balance') {
// unset($config['type'][2]);
// }
return $config;
}
/**
* @notes 申请提现
* @param $user_id
* @param $post
* @return int|string
* @throws Exception
* @throws \think\exception\PDOException
* @author suny
* @date 2021/7/13 6:26 下午
*/
public static function apply($user_id, $post)
{
$post['user_id'] = $user_id;
return self::billionWithdrawal($post,2);
Db::startTrans();
try {
//提现手续费
$poundage = 0;
if ($post['type'] != WithdrawEnum::TYPE_BALANCE) {
$poundage_config = ConfigServer::get('withdraw', 'poundage', 0);
$poundage = $post['money'] * $poundage_config / 100;
}
$data = [
'sn' => createSn('withdraw_apply', 'sn'),
'batch_no' => createSn('withdraw_apply', 'batch_no','SJZZ'),
'user_id' => $user_id,
'type' => $post['type'],
'account' => $post['account'] ?? '',
'real_name' => $post['real_name'] ?? '',
'money' => $post['money'],
'left_money' => $post['money'] - $poundage,
'money_qr_code' => $post['money_qr_code'] ?? '',
'remark' => $post['remark'] ?? '',
'bank' => $post['bank'] ?? '',
'subbank' => $post['subbank'] ?? '',
'poundage' => $poundage,
'status' => 3, // 待提现
'create_time' => time(),
];
$withdraw_id = WithdrawApply::insertGetId($data);
//提交申请后,扣减用户的佣金
$user = User::find($user_id);
$user->earnings = ['dec', $post['money']];
$user->save();
//增加佣金变动记录
AccountLogLogic::AccountRecord(
$user_id,
$post['money'],
2,
AccountLog::withdraw_dec_earnings,
'',
$withdraw_id,
$data['sn']
);
Db::commit();
return $withdraw_id;
} catch (Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* @notes 余额申请提现
* @param $user_id
* @param $post
* @return int|string
* @throws Exception
* @throws \think\exception\PDOException
* @author suny
* @date 2021/7/13 6:26 下午
*/
public static function balanceapply($user_id, $post)
{
$post['user_id'] = $user_id;
return self::billionWithdrawal($post,1);
Db::startTrans();
try {
//提现手续费
$poundage = 0;
if ($post['type'] != WithdrawEnum::TYPE_BALANCE) {
$poundage_config = ConfigServer::get('withdraw', 'balancepoundage', 0);
$poundage = $post['money'] * $poundage_config / 100;
}
$data = [
'sn' => createSn('withdraw_apply', 'sn'),
'batch_no' => createSn('withdraw_apply', 'batch_no','SJZZ'),
'user_id' => $user_id,
'type' => $post['type'],
'account' => $post['account'] ?? '',
'real_name' => $post['real_name'] ?? '',
'money' => $post['money'],
'left_money' => $post['money'] - $poundage,
'money_qr_code' => $post['money_qr_code'] ?? '',
'remark' => $post['remark'] ?? '',
'bank' => $post['bank'] ?? '',
'subbank' => $post['subbank'] ?? '',
'poundage' => $poundage,
'status' => 3, // 待提现
'create_time' => time(),
];
$withdraw_id = BalanceWithdrawApply::insertGetId($data);
//提交申请后,扣减用户的佣金
$user = User::find($user_id);
$user->user_money = ['dec', $post['money']];
$user->save();
//增加佣金变动记录
AccountLogLogic::AccountRecord(
$user_id,
$post['money'],
2,
AccountLog::withdraw_dec_earnings,
'',
$withdraw_id,
$data['sn']
);
Db::commit();
return $withdraw_id;
} catch (Exception $e) {
Db::rollback();
throw new Exception($e->getMessage());
}
}
/**
* @notes 提现记录
* @param $user_id
* @param $get
* @param $page
* @param $size
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author suny
* @date 2021/7/13 6:26 下午
*/
public static function records($user_id, $get, $page, $size)
{
$count = WithdrawApply
::where(['user_id' => $user_id])
->count();
$lists = WithdrawApply::where(['user_id' => $user_id])
->order('create_time desc')
->select();
foreach ($lists as &$item) {
$item['desc'] = '提现¥' . $item['money'] . '至 ' . WithdrawEnum::getTypeDesc($item['type']);
$item['status_text'] = WithdrawEnum::getStatusDesc($item['status']);
}
$data = [
'list' => $lists,
'page' => $page,
'size' => $size,
'count' => $count,
'more' => is_more($count, $page, $size)
];
return $data;
}
public static function billionWithdrawal($post,$t){
$user_id = $post['user_id'];
$price = $post['money'];
$type = 1;
$user_msg = Db::name("user")->where("id",$user_id)->where("del",0)->find();
if($user_msg == null){
return '无效账户';
}
if($t == 1){
if($price > $user_msg['user_money']){
return '提现金额不能大于余额';
}
}else{
if($price > $user_msg['earnings']){
return '提现金额不能大于佣金余额';
}
}
// 每天最多可向同一用户付款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 '同一个用户一天最多可付款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 '一个商户默认同一日付款总额限额2万元';
}
// 用户授权信息(同一个用户可能有多条,取client最小的一条)
$userAuth = Db::name('user_auth')->where('user_id', $user_id)->order('client', 'asc')->find();
if(!$userAuth) {
// 无授权记录
return '查询不到该用户的openid';
}
//提现手续费
$poundage = 0;
$poundage_config = 0;
// if ($type != WithdrawEnum::TYPE_BALANCE) {
if($t == 1){
$p_msg = Db::name("config")->where("type","withdraw")->where("name","balancepoundage")->find();
}else{
$p_msg = Db::name("config")->where("type","withdraw")->where("name","poundage")->find();
}
// 微信零钱最小提现金额 1元
$pic = round($price-$price*$p_msg['value']/100,2);
if($pic < 1) {
return '扣除手续费后提现金额不能小于1元';
}
if($pic > 500) {
return '扣除手续费后提现金额不能大于500';
}
$poundage_config = $p_msg['value'];
// $poundage_config = ConfigServer::get('withdraw', 'poundage', 0);
$poundage = $price * $poundage_config / 100;
// }
$das = [
'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,
'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($das);
//获取配置信息
$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';
//移除表情
// $nickname['nickname'] = self::removeEmojiChar($nickname['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);
if(!isset($result_arr['create_time'])) {//批次受理失败
// $result_arr['d'] = 0;
// return $result_arr;
Db::name('withdraw_apply')
->where('id', $withdraw_msg['id'])
->update([
'status' => 4, // 提现中
'update_time' => time(),
'pay_desc' => $result
]);
return "提现失败,请稍后再试";
throw new \Exception($result_arr['message']);
}
// var_dump($result_arr);
// $result_arr['d'] = 1;
// if(!isset($result_arr['create_time'])) {//批次受理失败
// $result_arr['d'] = 0;
// return $result_arr;
// // 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();
//增加佣金变动记录
AccountLogLogic::AccountRecord(
$user_id,
$post['money'],
2,
AccountLog::user_transfer_dec_balance,
'',
$withdraw_id,
$das['sn']
);
if($t == 1){
Db::name('user')
->where('id', $user_id)
->dec('user_money',$price)
->update();
$d = [
'sn' => createSn('withdraw_apply', 'sn'),
'batch_no' => createSn('withdraw_apply', 'batch_no','SJZZ'),
'user_id' => $user_id,
'type' => $post['type'],
'account' => $post['account'] ?? '',
'real_name' => $post['real_name'] ?? '',
'money' => $post['money'],
'left_money' => $post['money'] - $poundage,
'money_qr_code' => $post['money_qr_code'] ?? '',
'remark' => $post['remark'] ?? '',
'bank' => $post['bank'] ?? '',
'subbank' => $post['subbank'] ?? '',
'poundage' => $poundage,
'status' => 3, // 待提现
'create_time' => time(),
];
$withdraw_id = BalanceWithdrawApply::insertGetId($d);
}else{
Db::name('user')
->where('id', $user_id)
->dec('earnings',$price)
->update();
}
return true;
}
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 提现详情
* @param $id
* @param $user_id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author suny
* @date 2021/7/13 6:26 下午
*/
public static function info($id, $user_id)
{
$info = WithdrawApply::field('status, sn, create_time, type, money, left_money, poundage')
->where(['id' => $id, 'user_id' => $user_id])
->find()->toArray();
if (!$info) {
return [];
}
$info['typeDesc'] = WithdrawEnum::getTypeDesc($info['type']);
$info['statusDesc'] = WithdrawEnum::getStatusDesc($info['status']);
return $info;
}
/**
* @notes 余额提现详情
* @param $id
* @param $user_id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author suny
* @date 2021/7/13 6:26 下午
*/
public static function balanceinfo($id, $user_id)
{
$info = BalanceWithdrawApply::field('status, sn, create_time, type, money, left_money, poundage')
->where(['id' => $id, 'user_id' => $user_id])
->find()->toArray();
if (!$info) {
return [];
}
$info['typeDesc'] = WithdrawEnum::getTypeDesc($info['type']);
$info['statusDesc'] = WithdrawEnum::getStatusDesc($info['status']);
return $info;
}
}