'申请', self::STATUS_AGREE => '同意', self::STATUS_ALREADY_TRANS => '已打款', self::STATUS_ALREADY_REJECT => '驳回', self::STATUS_FAIL => '失败', self::STATUS_WAIT => '打款中' ]; //打款类型 public static $type_msg = [ 'auto' => '自动打款', 'wechat' => '微信', 'alipay' => '支付宝', 'bank' => '银行转账', 'balance' => '打款到余额' ]; public static $from_msg = [ self::FROM_BALANCE => '余额', self::FROM_INCOME => '佣金', self::FROM_SCORE => '积分', self::FROM_SCORE_GAME => '积分增长赢', self::FROM_HUIDIAN => '惠点' ]; /** * @var float|int|mixed|null */ /** * {@inheritdoc} */ public static function tableName() { return '{{%user_withdraw_log}}'; } /** * {@inheritdoc} */ public function rules() { return [ [['mall_id', 'user_id', 'num', 'actual_num', 'extra', 'content', 'from', 'type'], 'required'], [['id', 'mall_id', 'user_id', 'from', 'status', 'created_at', 'updated_at'], 'integer'], [['num', 'actual_num', 'poundage_num', 'direct_withdraws_reward_num', 'indirect_withdraws_reward_num', 'poundage_ratio', 'exchange_score_num', 'exchange_score_ratio', 'give_score_num', 'direct_withdraws_reward_ratio', 'indirect_withdraws_reward_ratio', 'exchange_balance_num', 'exchange_balance_ratio'], 'number'], [['extra', 'content', 'transfer'], 'string'], [['order_no','source'], 'string', 'max' => 255], [['type','sign'], 'string', 'max' => 45], [['from'], 'in', 'range' => [1, 2, 3, 4, 9, 10]], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'id' => 'ID', 'mall_id' => 'Mall ID', 'user_id' => 'User ID', 'order_no' => 'Order No', 'num' => 'Num', 'actual_num' => 'Actual Num', 'poundage_num' => 'Poundage Num', 'poundage_ratio' => 'Poundage Ratio', 'exchange_score_num' => 'Exchange Score Num', 'exchange_score_ratio' => 'Exchange Score Ratio', 'give_score_num' => 'Give Score Num', 'from' => 'From', 'type' => 'Type', 'extra' => 'Extra', 'content' => 'Content', 'status' => 'Status', 'transfer' => 'Transfer', 'created_at' => 'Created At', 'updated_at' => 'Updated At', 'source' => 'source', ]; } public static function fieldsList($field = null, $isChanjet = false) { $fields = [ 'user_id' => '会员ID', // 'user_info' => '基本信息', 'username' => '会员编号', 'nickname' => '会员昵称', 'user_mobile' => '手机号码', 'from' => '提现类型', // 'type' => '账户信息', 'alipay_name' => '支付宝姓名', 'mobile' => '支付宝账号', 'bank_account_type' => '账户类型', 'name' => '持卡/开户人', 'bank_name' => '开户行', 'bank_account' => '银行卡号', 'withdraw_type' => '提现方式', 'idcard' => '身份证', // 'withdrawal_information' => '提现信息', 'num' => '提现金额', 'actual_num' => '实际到账金额', 'poundage_num' => '手续费', 'exchange_score_num' => '转积分扣除', 'status' => '状态', 'updated_at' => '时间', 'remark' => '备注', ]; if ($isChanjet) { $fields['chanjet_updated_at'] = '最后推送时间'; $fields['chanjet_request_status'] = '推送状态'; } if ($field === null) return $fields; $temp = []; foreach ($field as $val) { if (isset($fields[$val])) $temp[$val] = $fields[$val]; } return $temp; } /** * User: wniu * Date: 2021/10/25 * Time: 6:02 下午 * * * @param $params * @param array $extra 额外自定义参数 * @return false|int[] * @throws Exception */ public function saveRecord($params, $extra = []) { if ($params['price'] <= 0) { return [ 'state' => false, 'msg' => '提现金额必须大于0!' ]; } $exists = self::find()->where([ 'mall_id' => $params['mall_id'], 'status' => 0, 'user_id' => $params['user_id'], 'from' => $params['from'] ])->asArray()->one(); if ($exists) { return [ 'state' => false, 'msg' => '尚有未审核的提现申请!' ]; } $user_balance = UserWallet::getOne([['user_id' => $params['user_id'], 'status' => 1]], true, [], false, 'balance,commission,score'); $actual_num = $params['price']; //提现到账金额 /** * 增加缓存机制防止重新提交表单 */ // $cacheKey = 'cash-submit-' . $params['user_id']; // $cacheValue = md5($params['price'] . $params['type']); // if(!$this->formLimitSubmis($cacheKey, $cacheValue)){ // return $this->returnApiResultData(ApiCode::CODE_FAIL, '操作太快啦,请稍候'); // } $deduct_equal_points = 0; $payment = []; if ($params['from'] == self::FROM_BALANCE) { if ($user_balance['balance'] < $params['price']) { return [ 'state' => false, 'msg' => '提现金额超出可提现金额!' ]; } $payment = \Yii::$app->services->setting->mall->get($params['mall_id'], 'withdraw_balance'); if (!empty($payment['balance_min_money']) && $params['price'] < $payment['balance_min_money']) { return [ 'state' => false, 'msg' => '最少提现金额是' . $payment['balance_min_money'] . '!' ]; } if (!$payment || $payment['balance_cash_status'] == 0) { return [ 'state' => false, 'msg' => '暂未开启提现功能!' ]; } if (!empty($payment['balance_cash_multiple']) && ($multiple = $payment['balance_cash_multiple'])) { if (bcmod($params['price'], $multiple, 2) != 0) { return [ 'state' => false, 'msg' => sprintf('请输入%s的倍数!', $multiple), ]; } } // 限制 if ($this->witdrawLimit($params, $payment) === false) { return [ 'state' => false, 'msg' => $this->getError(), ]; } $dayMaxMoney = isset($payment['balance_day_max_money']) && $payment['balance_day_max_money'] > 0 ? $payment['balance_day_max_money'] : 100000; $minMoney = isset($payment['balance_min_money']) && $payment['balance_min_money'] > 0 ? $payment['balance_min_money'] : 0; $poundage_ratio = isset($payment['balance_cash_service_fee']) && $payment['balance_cash_service_fee'] > 0 ? $payment['balance_cash_service_fee'] : 0; $exchange_score_ratio = isset($payment['balance_trans_score_rate']) && $payment['balance_trans_score_rate'] > 0 ? $payment['balance_trans_score_rate'] : 0; $wallet_type = UserWalletService::WALLET_TYPE_BALANCE; }elseif($params['from'] == self::FROM_SCORE){ $payment = \Yii::$app->services->setting->mall->get($params['mall_id'], 'score'); if (!empty($payment['score_cash_min_money'])) { //&& $params['price'] < $payment['score_cash_min_money'] $score_cash_radio = $payment['score_cash_radio']; $score_cash_min_money = bcmul($payment['score_cash_min_money'],$score_cash_radio,2); if ($params['price'] < $score_cash_min_money) { return [ 'state' => false, 'msg' => '最少提现数量是' . $score_cash_min_money . '!' ]; } } if (!$payment || $payment['score_cash_status'] == 0) { return [ 'state' => false, 'msg' => '暂未开启提现功能!' ]; } $actual_num = ScoreLogic::checkUserCash($params['mall_id'],$params['user_id'],$params['price']); if(!$actual_num){ return [ 'state' => false, 'msg' => ScoreLogic::getStaticError() ]; } $dayMaxMoney = isset($payment['score_cash_day_max_money']) && $payment['score_cash_day_max_money'] > 0 ? $payment['score_cash_day_max_money'] : 100000; $minMoney = isset($payment['score_cash_min_money']) && $payment['score_cash_min_money'] > 0 ? $payment['score_cash_min_money'] : 0; $poundage_ratio = isset($payment['score_cash_service_fee']) && $payment['score_cash_service_fee'] > 0 ? $payment['score_cash_service_fee'] : 0; $wallet_type = UserWalletService::WALLET_TYPE_SCORE; } else { $freeze_commission = UserFreezeCommission::handlePromotionCenter($params['mall_id'], $params['user_id']); if(!empty($freeze_commission['is_freeze_commission'])){ $user_balance['commission'] -= $freeze_commission['freeze_amount']; $user_balance['commission'] < 0 && $user_balance['commission'] = 0; } if ($user_balance['commission'] < $params['price']) { return [ 'state' => false, 'msg' => '提现金额超出可提现金额!' ]; } $payment = \Yii::$app->services->setting->mall->get($params['mall_id'], 'withdraw_income'); // 如果是提现到余额则根据配置 "提现到余额总权重控制" 决定是否对余额提现进行每项的限制 $needCheckLevels = $this->getIsNeedCheckSettingMap($params['from'], $params['type'], $payment); $deduct_equal_points = ($payment['deduct_equal_points'] ?? $deduct_equal_points) && $needCheckLevels[WithdrawEnum::DEDUCT_EQUAL_POINTS]; $score_name = \Yii::$app->services->setting->mall->get($params['mall_id'], 'score.score_name'); //扣除冻结红包 $deduct_equal_frozen_redpack = ($payment['deduct_equal_frozen_redpack'] ?? 0) && $needCheckLevels[WithdrawEnum::DEDUCT_FROZEN_REDPACKET]; $install_redpack = MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_REDPACK); if($deduct_equal_frozen_redpack && $install_redpack){ //查询用户红包 $redpack = RedpackWallet::find()->select("frozen_redpack")->where(['user_id' => $params['user_id'], 'status' => StatusEnum::ENABLED])->asArray()->one(); if($redpack['frozen_redpack'] < $params['price']){ $config = Yii::$app->services->setting->addons->get($params['mall_id'], AddonsEnum::ADDONS_NAME_REDPACK, 'basic'); $redpack_name = $config['redpack_name'] ?? '红包';// 自定义红包名称 return [ 'state' => false, 'msg' => '提现金额超出可扣除冻结' . $redpack_name . '!' ]; } } $withdrawsLimitLogType = WithdrawsLimitLog::getType($params['mall_id'], $params['type'], $payment); $payment["withdraws_limit_enable"] = $needCheckLevels[WithdrawEnum::LIMIT_STRATEGY] && !empty($payment["withdraws_limit_enable"]); $withdraws_limit_enable = $payment["withdraws_limit_enable"]; if(!empty($payment["withdraws_limit_enable"])){ $withdraws_limit_money = $withdrawsLimitLogType == WithdrawsLimitLog::COMMON_LIMIT ? (isset($payment["withdraws_limit_money"]) ? $payment["withdraws_limit_money"] : 0) : ($payment["independent_balance_withdraw_max_amount"] ?? 0); $withdrawsLimitLog = WithdrawsLimitLog::getOne([['user_id' => $params['user_id'], 'status' => StatusEnum::ENABLED,'from'=>1, 'type' => $withdrawsLimitLogType]], true, [], false, 'amount'); if(!empty($withdrawsLimitLog)){ $withdraws_limit_money = $withdrawsLimitLog['amount']; } if($params['price'] > $withdraws_limit_money){ return [ 'state' => false, 'msg' => '提现金额超出可提现额度,复购任意产品可恢复额度', ]; } } if (($user_balance['score'] < $params['price']) && $deduct_equal_points == 1) { return [ 'state' => false, 'msg' => '提现金额超出可扣除' . $score_name . '!' ]; } // 如果提现到余额根据配置决定要不要限制(如果提现到余额总权重控制 关闭或者开启但是未选择最小提现额度则不需要限制) if ($needCheckLevels[WithdrawEnum::MIN_WITHDRAW_AMOUNT] && !empty($payment['min_money']) && $params['price'] < $payment['min_money']) { return [ 'state' => false, 'msg' => '最少提现金额是' . $payment['min_money'] . '!' ]; } if (!$payment || $payment['is_income_cash'] == 0) { return [ 'state' => false, 'msg' => '暂未开启提现功能!' ]; } if ($needCheckLevels[WithdrawEnum::WITHDRAW_MULTIPLE] && !empty($payment['income_cash_multiple']) && ($multiple = $payment['income_cash_multiple'])) { if (bcmod($params['price'], $multiple, 2) != 0) { return [ 'state' => false, 'msg' => sprintf('请输入%s的倍数!', $multiple), ]; } } // 限制 if ($needCheckLevels[WithdrawEnum::WITHDRAW_RESTRICTION] && $this->witdrawLimit($params, $payment) === false) { return [ 'state' => false, 'msg' => $this->getError(), ]; } $dayMaxMoney = $needCheckLevels[WithdrawEnum::DAILY_MAX_WITHDRAW] ? (isset($payment['day_max_money']) && $payment['day_max_money'] > 0 ? $payment['day_max_money'] : -1) : -1; $minMoney = isset($payment['min_money']) && $payment['min_money'] > 0 ? $payment['min_money'] : 0.1; //$poundage_ratio = isset($payment['cash_service_fee']) && $payment['cash_service_fee'] > 0 ? $payment['cash_service_fee'] : 0; if ($params['type'] == 'balance') { $poundage_ratio = isset($payment['cash_income_service_fee']) && $payment['cash_income_service_fee'] > 0 ? $payment['cash_income_service_fee'] : 0; } else { $poundage_ratio = isset($payment['cash_service_fee']) && $payment['cash_service_fee'] > 0 ? $payment['cash_service_fee'] : 0; } $exchange_score_ratio = $needCheckLevels[WithdrawEnum::CONVERT_TO_POINTS_RATIO] && isset($payment['balance_trans_score_rate']) && $payment['balance_trans_score_rate'] > 0 ? $payment['balance_trans_score_rate'] : 0; $wallet_type = UserWalletService::WALLET_TYPE_COMMISSION; // 提现转余额比例 $trans_balance_rate = !empty($payment['trans_balance_rate']) ? $payment['trans_balance_rate'] : 0; } $direct_withdraws_reward_rate = isset($payment['direct_withdraws_reward']) && $payment['direct_withdraws_reward'] > 0 ? $payment['direct_withdraws_reward'] : 0; $indirect_withdraws_reward_rate = isset($payment['indirect_withdraws_reward']) && $payment['indirect_withdraws_reward'] > 0 ? $payment['indirect_withdraws_reward'] : 0; $direct_withdraws_reward = intval(bcmul($params['price'] * $direct_withdraws_reward_rate / 100, 100)) / 100; $indirect_withdraws_reward = intval(bcmul($params['price'] * $indirect_withdraws_reward_rate / 100, 100)) / 100; $check_password_result = self::checkPassword($params['user_id'], $params['transaction_password'], $payment); if(is_array($check_password_result)){ return $check_password_result; } // $balance_config = \Yii::$app->services->setting->mall->get($params['mall_id'], 'pay.balance'); // if ($balance_config) { // $balance_config = Json::decode((string)$balance_config); // if ($balance_config['pay_password_status'] == 1) { // $transactionPassword = $params['transaction_password']; // $password = User::getOne([['id' => $params['user_id']]], true, '', '', 'transaction_password'); // if (!$params['transaction_password']) { // return [ // 'state' => false, // 'msg' => '请输入支付密码!' // ]; // } // if (empty($password['transaction_password'])) { // return [ // 'state' => false, // 'msg' => '您未设置支付密码!' // ]; // } // if (empty($transactionPassword)) { // return [ // 'state' => false, // 'msg' => '请输入交易密码!' // ]; // } // if (!\Yii::$app->getSecurity()->validatePassword(trim($transactionPassword), $password['transaction_password'])) { // return [ // 'state' => false, // 'msg' => '支付密码错误!' // ]; // } // } // } // if ($minMoney > $params['price']) { // return [ // 'state' => false, // 'msg' => '最低提现金额为' . $minMoney // ]; // } if ($dayMaxMoney > -1) { // 根据配置 "提现到余额总权重限制" 决定要不要忽略今日的余额提现 // 空表示对余额不限制,那么今日已提现的则不能累计 if (!$this->inBalanceWithdrawTotalWeightLimitSelectedByType($params['from'], WithdrawEnum::DAILY_MAX_WITHDRAW, $payment)) { $filterBalanceWhere = ['<>', 'type', 'balance']; } $today_cash_price = self::find()->where(['user_id' => $params['user_id'], 'mall_id' => $params['mall_id'], 'from' => $params['from']])->andWhere(['>', 'created_at', strtotime(date('Y-m-d', time()))])->andWhere(['<', 'status', 3])->andWhere($filterBalanceWhere ?? [])->sum('num'); if ($today_cash_price >= $dayMaxMoney) { return [ 'state' => false, 'msg' => '今日可提现额度已用完!' ]; } if (floatval($params['price']) + floatval($today_cash_price) > floatval($dayMaxMoney)) { return [ 'state' => false, 'msg' => '提现金额大于今日剩余可提现额度!' ]; } } if (!$params['type']) { return [ 'state' => false, 'msg' => '请选择提现方式!' ]; } if ($params['type'] == 'wechat') { if (!isset($params['wechat_qrcode'])) { return [ 'state' => false, 'msg' => '请上传微信收款码!' ]; } } if ($params['type'] == 'alipay') { if (!$params['mobile']) { return [ 'state' => false, 'msg' => '请填写支付宝账号!' ]; } if (!$params['name']) { return [ 'state' => false, 'msg' => '请填写支付宝姓名!' ]; } } if ($params['type'] == 'paid' || $params['type'] == 'joinpay') { //代付银行卡 if (!$params['name']) { return [ 'state' => false, 'msg' => '请填写持卡人!' ]; } if (!$params['bank_account']) { return [ 'state' => false, 'msg' => '请填写银行卡号!' ]; } } if ($params['type'] == 'alipay_tax') { if (!$params['mobile']) { return [ 'state' => false, 'msg' => '请填写支付宝账号(手机号)' ]; } if (!$params['name']) { return [ 'state' => false, 'msg' => '请填写支付宝姓名' ]; } if (!$params['id_card']) { return [ 'state' => false, 'msg' => '请填写身份证信息' ]; } $service = new \addons\AvoidTax\common\service\UserService(['mall_id' => $this->mall_id]); // $res = $service->checkSign($this->user_id); // 判断当前身份ID是否已经签约 已签约则不签约 if (!$service->idIsSignAndAddAuthOfUid( $params['id_card'], $params['name'], $this->user_id, $params['mobile'] )) { // 判断用户是否签约 $res = $service->checkSign($this->user_id); if ($res === false) { if ($service->getConfigService()->isXLApiType()) { $res = $service->goToSing($this->user_id, $params['mobile'], $params['id_card'], $params['name'], $extra['redirect_url'] ?? ''); if (!$res) { return [ 'state' => false, 'msg' => $service->error ]; } // 跳转url签约 return [ 'state' => true, 'data' => $res ]; } if ($service->getConfigService()->isLYApiType()) { $res = $service->silentSign( $this->user_id, $params['name'], $params['mobile'], $params['id_card'] ); if ($res === false) { return [ 'state' => false, 'msg' => $service->getError(), ]; } } } } } if ($params['type'] == 'digital') {//数字化用工 if (!$params['mobile']) { return [ 'state' => false, 'msg' => '请填写支付宝绑定的手机号!' ]; } if($params['bank_account_type'] == 2){ $params['bank_account'] = $params['mobile']; } if($params['bank_account_type'] == 3){ $findOpenId = UserInfo::find()->where(['user_id'=>$this->user_id, 'status'=>StatusEnum::ENABLED])->one(); if(empty($findOpenId->openid)){ return [ 'state' => false, 'msg' => '该账号未绑定微信,无法使用微信提现方式!' ]; } } // 是否签约 $sign = DigitalEmploymentOrder::inquireSign($this->mall_id, $this->user_id); // 1-签约中 2-签约成功 3-签约失败 if (empty($sign)) { return [ 'state' => false, 'msg' => '该用户未进行签约!' ]; } if($sign->result->signState == 1){ return [ 'state' => false, 'msg' => '该用户的签约正在审核中!' ]; } if($sign->result->signState == 3){ return [ 'state' => false, 'msg' => '用户签约失败,请重新签约!' ]; } } // 微信零钱打款 if ($params['type'] == 'auto') { $payment_conf = Yii::$app->services->setting->mall->get($params['mall_id'], 'pay.wechat'); $payment_conf = json_decode($payment_conf, true); if(!is_numeric($payment_conf['wechat_auto_pay_limit'])) $payment_conf['wechat_auto_pay_limit'] = 200; if($params['from'] == self::FROM_SCORE){//积分提现,需除以积分提现比例 $payment = Yii::$app->services->setting->mall->get($params['mall_id'], 'score'); $params['price'] = bcdiv($params['price'],$payment['score_cash_radio'],2); } if($params['price'] > $payment_conf['wechat_auto_pay_limit']){ return [ 'state' => false, 'msg' => '微信自动打款提现最高提现金额不能超过'.$payment_conf['wechat_auto_pay_limit'].'元' ]; } } $cash = new self(); $cash->mall_id = $params['mall_id']; $cash->user_id = $params['user_id']; $cash->num = $actual_num; $cash->source = $params['source']??''; $cash->actual_num = $actual_num; $cash->content = Json::encode(['user_content' => $params['content']]); $cash->from = $params['from']; $cash->type = $params['type']; $cash->extra = Json::encode([ 'name' => !empty($params['name']) ? $params['name'] : '', 'mobile' => !empty($params['mobile']) ? $params['mobile'] : '', 'bank_name' => $params['bank_name'], 'bank_account' => (string)$params['bank_account'], 'bank_account_type' => $params['bank_account_type'], 'wechat_qrcode' => $params['wechat_qrcode'], 'id_card' => $params['id_card']?? '', 'receive_bank_chanel_no' => $params['receive_bank_chanel_no'] ?? '', 'x-app-platform' => $params['x-app-platform'] ?? '', 'bank_address' => !empty($params['bank_address']) ? $params['bank_address'] : '', 'idcard' => !empty($params['idcard']) ? $params['idcard'] : '', // 'settlementInfoId' => !empty($params['settlementInfoId']) ? $params['settlementInfoId'] : '', //点薪灵工结算单id ], JSON_UNESCAPED_UNICODE); $cash->sign = $params['sign'] ?? ''; if ($poundage_ratio < 0 || $poundage_ratio > 100) { return [ 'state' => false, 'msg' => '手续费设置不正确!' ]; } //手续费 $poundage = 0; if ($poundage_ratio > 0 && $poundage_ratio < 100) { //手续费:取小数点2位,截断 $poundage = bcmul($poundage_ratio / 100, $actual_num, 2); $cash->actual_num = bcsub($actual_num, $poundage, 2); //只影响余额提现 if ($params['from'] == self::FROM_BALANCE && $payment['received_full']) { //提现金额需要全额到账,重新计算提现金额(手续费额外从余额扣减) $new_num = bcadd($actual_num, $poundage, 2); if ($user_balance['balance'] < $new_num) { return [ 'state' => false, 'msg' => '余额不足以扣除手续费!' ]; } $params['price'] = $cash->num = $new_num; $cash->actual_num = $actual_num; } $cash->poundage_num = $poundage; $cash->poundage_ratio = $poundage_ratio; } // //点薪灵工发起结算订单 // if ($params['type'] == 'linggong') { // $res = (new ApiRequestService())->addSettlement($cash); // if ($res['status'] == false) return $res; // } $score_money = 0; //扣除转积分的费用 if ($exchange_score_ratio > 0 && $exchange_score_ratio < 100) { // 提现转积分扣除比例=balance_trans_score_rate,提现赠送积分比例=score_withdrawal_giving_ratio $giving_ratio = 1; //转增比例 $scoreAssets = Yii::$app->services->setting->mall->get($params['mall_id'], 'score'); if (!empty($scoreAssets)) { if (isset($scoreAssets['score_withdrawal_giving_ratio']) && $scoreAssets['score_withdrawal_giving_ratio'] > 0) $giving_ratio = $scoreAssets['score_withdrawal_giving_ratio']; } $score_money = bcmul($exchange_score_ratio / 100, $params['price'], 2); // 提现转积分扣除的手续费 = 转积分扣除的手续费比例 * 提现金额 $exchange_score_num = $score_money * $giving_ratio; // 可得积分 = 提现转积分扣除的手续费 * 提现赠送积分比例 $cash->actual_num = bcsub($cash->actual_num, $score_money, 2); $cash->exchange_score_num = $score_money; $cash->exchange_score_ratio = $exchange_score_ratio; $cash->give_score_num = $exchange_score_num; } if (intval(bcmul($cash->actual_num, 100)) < 1) { return [ 'state' => false, 'msg' => '提现金额扣除费用后金额不足!' ]; } $balance_money = 0; //扣除转余额的费用 if (isset($trans_balance_rate) && $params['type'] != 'balance' && $trans_balance_rate > 0 && $trans_balance_rate < 100) { // 提现转积分扣除比例=balance_trans_score_rate,提现赠送积分比例=score_withdrawal_giving_ratio $balance_money = bcmul($trans_balance_rate / 100, $cash->actual_num, 2); // 提现转余额扣除的手续费 = 转余额扣除的手续费比例 * 剩余可提现金额 $cash->actual_num = bcsub($cash->actual_num, $balance_money, 2); $cash->exchange_balance_num = $balance_money; $cash->exchange_balance_ratio = $trans_balance_rate; if (intval(bcmul($cash->actual_num, 100)) < 1) { return [ 'state' => false, 'msg' => '提现金额扣除费用后金额不足!' ]; } } //提现分佣金额 $cash->direct_withdraws_reward_num = $direct_withdraws_reward; $cash->indirect_withdraws_reward_num = $indirect_withdraws_reward; $cash->direct_withdraws_reward_ratio = $direct_withdraws_reward_rate; $cash->indirect_withdraws_reward_ratio = $indirect_withdraws_reward_rate; $t = \Yii::$app->db->beginTransaction(); try { $cash->order_no = $this->getCashOrder($params['mall_id']); //$desc = $cash->from == self::FROM_INCOME ? '佣金提现' : '余额提现'; $desc = self::$from_msg[$cash->from].'提现'; //$desc .= $cash->num; $desc .= $params['price']; if ($poundage > 0) { $desc .= ':手续费¥' . $poundage; } if ($score_money > 0) { $desc .= ' 转积分扣除¥' . $score_money; } if ($balance_money > 0) { $desc .= ' 转余额扣除¥' . $balance_money; } if (!$cash->save()) { throw new Exception($cash->getErrorMessage()); } $res_data = [ 'state' => true, 'data' => ['cash_id' => $cash->id], 'msg' => '' ]; //提现限额 $payment = \Yii::$app->services->setting->mall->get($cash->mall_id, 'withdraw_income'); if (isset($withdraws_limit_enable)) { $payment["withdraws_limit_enable"] = $withdraws_limit_enable; } if($cash->from == 1 && !empty($payment["withdraws_limit_enable"])){ $withdrawsLimitLogType = $withdrawsLimitLogType ?? 0; $withdraws_limit_money = $withdrawsLimitLogType == WithdrawsLimitLog::COMMON_LIMIT ? (isset($payment["withdraws_limit_money"]) ? $payment["withdraws_limit_money"] : 0) : ($payment["independent_balance_withdraw_max_amount"] ?? 0); $withdrawsLimitLog = WithdrawsLimitLog::findOne(['user_id' => $cash->user_id, 'status' => StatusEnum::ENABLED,'from'=>1, 'type' => $withdrawsLimitLogType]); $log_data = [ 'mall_id' => $cash->mall_id, 'user_id' => $cash->user_id, 'amount' => $withdraws_limit_money, 'from' => 1, 'type' => $withdrawsLimitLogType ]; if(empty($withdrawsLimitLog)){ $withdrawsLimitLog = WithdrawsLimitLog::setData($log_data); if(!$withdrawsLimitLog){ throw new \Exception(); } } $withdrawsLimitLog->amount = bcsub($withdrawsLimitLog->amount,$cash->num,2); if(!$withdrawsLimitLog->save()){ throw new \Exception(); } $log_data['amount'] = $cash->num; $log_data['withdraw_log_id'] = $cash->id; $withdrawsLimitChangeLog = WithdrawsLimitChangeLog::setData($log_data); if(!$withdrawsLimitChangeLog){ throw new \Exception(); } } //扣除冻结红包 if ($params['from'] == self::FROM_INCOME && $deduct_equal_frozen_redpack && $install_redpack) { $config = Yii::$app->services->setting->addons->get($params['mall_id'], AddonsEnum::ADDONS_NAME_REDPACK, 'basic'); $redpack_name = $config['redpack_name'] ?? '红包';// 自定义红包名称 $wallet = RedpackWallet::setData([ 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'is_frozen' => true, 'is_deduct' => true, 'money' => $params['price'] * -1, 'from_type' => RedpackEnum::FROM_CASH_DEDUCT, 'desc' => "佣金提现扣除等额冻结".$redpack_name, 'source_table' => self::tableName(), 'source_table_id' => $cash->id, ]); if(!$wallet) throw new \Exception(RedpackWallet::getStaticError()); } $t->commit(); $data = [ 'message_id' => 0, 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'wallet_type' => $wallet_type, 'is_frozen' => false, 'unfrozen' => false, 'money' => -abs($params['price']), 'desc' => $desc, 'source_table' => 'user_wallet', 'source_table_id' => $cash->id, 'from_type' => UserWalletEnum::WITHDRAWAL, // 'capital_type' => $params['from'] == self::FROM_BALANCE ? UserWalletEnum::WITHDRAWAL_DECR : UserWalletEnum::RECHARGE_COMMISSION, 'capital_type' => UserWalletEnum::WITHDRAWAL_DECR, ]; $wallet_service_status = UserWalletService::handle(0, $data); if ($params['from'] == self::FROM_INCOME && $deduct_equal_points == 1) { $score_data = [ 'message_id' => 0, 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'wallet_type' => 'score', 'is_frozen' => false, 'unfrozen' => false, 'money' => -abs($cash->num), 'desc' => $desc, 'source_table' => 'user_wallet', 'source_table_id' => $cash->id, 'from_type' => UserWalletEnum::WITHDRAWAL, 'capital_type' => UserWalletEnum::WITHDRAWAL_FOLLOW_DECR, ]; UserWalletService::handle(0, $score_data); } if (!$wallet_service_status) { $cash->status = 4; $cash->save(); return [ 'state' => false, 'msg' => '提现失败!' . UserWalletService::getStaticError() ]; } //佣金提现到余额免审核 if ($cash->type == 'balance' && $cash->from == self::FROM_INCOME && isset($payment['is_examine']) && $payment['is_examine']) { $this->remit($cash); // 如果是提现的余额,通知余额变动 $user_wallet_list = ['user_id' => $cash->user_id, 'wallet_type' => UserWalletService::WALLET_TYPE_BALANCE]; $event = new UserWalletEvent($cash->mall_id); Yii::$app->services->events->dispatch($event, ['mall_id'=>$cash->mall_id, 'user_wallet_list' => $user_wallet_list], $event->listeners); $event = new UserWithdrawSuccessfulEvent($cash->mall_id); $data['id'] = $cash->id; $data['mall_id'] = $cash->mall_id; Yii::$app->services->events->dispatch($event, $data, $event->listeners); } if ($cash->type == 'joinpay') { //获取汇聚代付配置 $huiju_config = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_JOIN_PAY, 'basic'); if (!empty($huiju_config['joinpay_channel_alternative'])) $huiju_config['joinpay_channel_alternative'] = json_decode($huiju_config['joinpay_channel_alternative'], true); if ($huiju_config['not_to_examine'] == 1 && !empty($huiju_config['joinpay_channel_alternative']) && in_array($cash->from, $huiju_config['joinpay_channel_alternative'])) { $this->remit($cash); } } //灵工点薪免审核打款 // if ($cash->type == 'linggong') { // $config = \Yii::$app->services->setting->addons->get($cash->mall_id, AddonsEnum::ADDONS_NAME_LINGGONG, 'basic'); // if (!empty($config) && $config['is_examine'] == 1) { // $this->remit($cash); // } // } $event = new UserWithdrawEvent($cash->mall_id); Yii::$app->services->events->dispatch($event, ['mall_id'=>$cash->mall_id, 'id' => $cash['id']], $event->listeners); } catch (Exception $e) { $t->rollBack(); \Yii::error($e->getMessage()); return [ 'state' => false, 'msg' => '提现失败!' . $e->getMessage() ]; } return $res_data; } public function getCashOrder($mall_id): string { $order_no = null; while (true) { $order_no = 'TX' . date('YmdHis') . rand(10000, 99999); $exist = self::find()->where(['mall_id' => $mall_id, 'order_no' => $order_no,])->asArray()->one(); if (!$exist) { break; } } return $order_no; } /** * User: wniu * Date: 2021/11/1 * Time: 4:28 下午 * * * @param $get * @return array */ public function searchLogList($get): array { $mall_id = $get['mall_id']; $params['alias'] = 'b'; $params['joinWith'] = ['user']; $params['where'][] = ['!=', 'b.status', -1]; if ($get['status'] && $get['status'] >= 0) { $params['where'][] = ['=', 'b.status', $get['status']]; } if ($get['status'] == 0) { $params['where'][] = ['=', 'b.status', $get['status']]; } if (!empty($get['keyword'])) { $params['where'] = [[ 'or', ['like', 'nickname', $get['keyword']], ['like', 'mobile', $get['keyword']] ]]; } if (!empty($get['user_id'])) { $params['where'][] = ['=', 'user_id', $get['user_id']]; } if (!empty($get['id'])) { $params['where'][] = ['=', 'b.id', $get['id']]; } if (!empty($get['withdraw_type'])) { $params['where'][] = ['=', 'b.type', $get['withdraw_type']]; } if (!empty($get['withdraw_from'])) { $params['where'][] = ['=', 'b.from', $get['withdraw_from']]; } if (!empty($get['start_date']) && !empty($get['end_date'])) { $get['start_date'] = str_replace('+', ' ', $get['start_date']); $get['end_date'] = str_replace('+', ' ', $get['end_date']); $params['where'][] = ['>=', 'b.created_at', strtotime($get['start_date'])]; $params['where'][] = ['<=', 'b.created_at', strtotime($get['end_date'])]; } $params['where'][] = ['=', 'b.mall_id', $mall_id]; $params['order'] = ['status' => SORT_ASC, 'updated_at' => SORT_DESC]; $params['limit'] = 10; $isChanjet = !empty($get['is_chanjet_addons']); // 畅捷通插件相关 if ($isChanjet) { $params['with'][] = 'addonsChanjetRequest'; } $list = self::listPage($params, false, false); $newList = []; $joinpay_msg = ''; if(MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_HUI_DIAN)){ $huidian_from_msg = \Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_HUI_DIAN, 'basic.custom_name'); } foreach ($list['list'] as $item) { $serviceCharge = $item->poundage_num; $fact_price = $item->actual_num; $score_money = $item->exchange_score_num; $extra = $item->extra ? json_decode($item->extra, true) : []; if (!empty($extra)) $extra['bank_account'] = (string)$extra['bank_account']; if ($item->type == 'paid' || $item->type == 'joinpay') { //汇聚代付 $pay_log = PaidSinglePayLog::getOne([['mall_id' => $item->mall_id, 'order_no' => $item->order_no]],false,[],'id desc'); if ($pay_log) { if ($pay_log->status == PaidSinglePayLog::STATUS_SUCCESS) { $joinpay_msg = '打款成功'; } else { $joinpay_msg = $pay_log->error_msg ?: '打款中'; } } } if (isset($item->addonsChanjetRequest)) { $addonsChanjetRequest = $item->addonsChanjetRequest ? ['updated_at' => $item->addonsChanjetRequest->updated_at, 'request_status' => $item->addonsChanjetRequest->request_status] : null; } $from_msg = self::$from_msg[$item->from]; if($item->from == self::FROM_SCORE_GAME && MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_SCORE_GAME)){ $wallet_text = ScoreGameEnum::getWalletText(); $from_msg = $from_msg.' - '.$wallet_text[$item->source]; } if ($item->from == self::FROM_HUIDIAN) { $from_msg = $huidian_from_msg ?? '惠点'; } $newItem = [ 'id' => $item->id, 'from' => $item->from, 'order_no' => $item->order_no, 'type' => $item->type, 'status' => $item->status, 'extra' => $extra, 'created_at' => $item->created_at, 'updated_at' => $item->updated_at, 'addonsChanjetRequest' => $addonsChanjetRequest ?? null, 'content' => $item->content ? Json::decode($item->content) : [], 'user' => [ 'avatar' => isset($item->user->avatar_url) ? $item->user->avatar_url : '', 'nickname' => isset($item->user->nickname) ? $item->user->nickname : '', 'id' => isset($item->user->id) ? $item->user->id : '', 'mobile' => isset($item->user->mobile) ? $item->user->mobile : '', ], 'cash' => [ 'price' => round($item->num, 2), 'service_fee_rate' => $serviceCharge, 'score_money' => $score_money, 'fact_price' => $fact_price, 'exchange_balance_num' => $item->exchange_balance_num ], 'joinpay_msg' => $joinpay_msg, 'from_msg' => $from_msg.'提现' ]; $newList[] = $newItem; } $export_list = self::fieldsList(null, $isChanjet); return [ 'code' => 0, 'data' => [ 'list' => $newList, 'export_list' => $export_list, 'pagination' => $list['pagination'], ] ]; } /** * @throws Exception */ public function updateLog(): bool { $where = [['id' => $this->id]]; $cash = self::getOne($where); if (!$cash) { throw new \Exception('提现记录不存在'); } if ($cash->status == 2) { throw new \Exception('提现已打款'); } if ($cash->status == 3) { throw new \Exception('提现已被驳回'); } if ($this->status <= $cash->status) { throw new \Exception('状态错误, 请刷新重试'); } $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_USER_CASH, $cash->user_id); $identification = uniqid(); if (!LockHelper::lock($lock_key, $identification, 100, 100)) { \Yii::error('cashForm 获取锁(' . $lock_key . ')失败阻塞,提现打款:cash,操作:save,金额:' . $cash->actual_num); return false; } $t = \Yii::$app->db->beginTransaction(); try { switch ($this->status) {// 1=提现申请通过,2=同意提现,3=拒绝提现 case 1: $this->validateCash($cash); break; case 2: $this->remit($cash); $flag = true; break; case 3: $this->reject($cash); break; default: throw new \Exception('错误的提现类型'); } $t->commit(); LockHelper::uLock($lock_key, $identification); if (isset($flag)) { // 如果是提现的余额,通知余额变动 或 余额提现到第三方 if ($cash->type === 'balance' || $cash->from == self::FROM_BALANCE) { $user_wallet_list = ['user_id' => $cash->user_id, 'wallet_type' => UserWalletService::WALLET_TYPE_BALANCE]; $event = new UserWalletEvent($cash->mall_id); Yii::$app->services->events->dispatch($event, ['mall_id'=>$cash->mall_id, 'user_wallet_list' => $user_wallet_list], $event->listeners); } $event = new UserWithdrawSuccessfulEvent($cash->mall_id); $data['id'] = $cash->id; $data['mall_id'] = $cash->mall_id; Yii::$app->services->events->dispatch($event, $data, $event->listeners); } // 执行成功后触发插件操作 GlobalInvoke::exec(GlobalInvoke::INVOKE_WITHDRAW_OPERATE, $cash->mall_id, $cash->toArray()); if($this->status==3){ //用户提现审核不通过事件 $event = new UserWithdrawRejectEvent($cash->mall_id); $data['id'] = $cash->id; $data['mall_id'] = $cash->mall_id; Yii::$app->services->events->dispatch($event, $data, $event->listeners); } } catch (\Exception $exception) { $t->rollBack(); LockHelper::uLock($lock_key, $identification); \Yii::error("finance cashForm error=" . $exception->getFile() . ";line:" . $exception->getLine() . ";message:" . $exception->getMessage()); throw new \Exception($exception->getMessage()); } return true; } /** * 申请 * @param $cash * @return bool * @throws Exception */ private function validateCash($cash): bool { if (!$cash->content) { $content = []; } else { $content = Json::decode($cash->content); } $cash->status = 1; $content['validate_content'] = $this->content ?: '审核通过'; $cash->content = Json::encode($content); if (!$cash->save()) { throw new \Exception('失败'); } return true; } /** * @Author: 广东七件事 ganxiaohao * @Date: 2020-05-30 * @Time: 11:22 * @Note:拒绝 * @param $cash * @return void * @throws \Exception */ private function reject($cash): void { if (!$this->content) { throw new \Exception('请填写备注'); } if (!$cash->content) { $content = []; } else { $content = Json::decode($cash->content); } $cash->status = 3; $content['reject_content'] = $this->content; $cash->content = Json::encode($content); if (!$cash->save()) { throw new \Exception('失败'); } $from = $cash->from; $cash_num = $cash->num; if ($from == self::FROM_INCOME) { $desc = "佣金申请提现被驳回,驳回原因:" . $this->content ?? ''; $wallet_type = UserWalletService::WALLET_TYPE_COMMISSION; }elseif ($from == self::FROM_SCORE) { $desc = "积分申请提现被驳回,驳回原因:" . $this->content ?? ''; $wallet_type = UserWalletService::WALLET_TYPE_SCORE; //原路返回积分数量查询 积分记录表 $score_log = ScoreLog::find()->where(['user_id' => $cash->user_id, 'from_type' => UserWalletEnum::WITHDRAWAL, 'source_table' => 'user_wallet', 'source_table_id' => $cash->id])->asArray()->one(); $cash_num = $score_log['change_num'] ?? 0; }elseif ($from == self::FROM_SCORE_GAME) { //插件提现 } elseif ($from == self::FROM_HUIDIAN) { //惠点插件提现驳回 $log = \addons\HuiDian\common\models\HuidianLog::getOne([ ['mall_id' => $cash->mall_id], ['user_id' => $cash->user_id], ['from_type' => \addons\HuiDian\common\enums\HuiDianEnum::FROEM_TYPE_WITHDRAWS_SUBMIT], ['source_table' => self::tableName()], ['source_table_id' => $cash->id] ]); if ($log) { $res = \addons\HuiDian\common\models\Huidian::setData([ 'mall_id' => $log['mall_id'], 'user_id' => $log['user_id'], 'amount' => $log['change_num'], 'desc' => "提现申请被驳回,驳回原因:" . $this->content ?? '', 'source_table' => self::tableName(), 'source_table_id' => $cash->id, 'from_type' => \addons\HuiDian\common\enums\HuiDianEnum::FROEM_TYPE_WITHDRAWS_REJECT, 'is_withdraw_reject' => true ]); if ($res === false) throw new \Exception(); } } else { $desc = "余额提现申请被驳回,驳回原因:" . $this->content ?? ''; $wallet_type = UserWalletService::WALLET_TYPE_BALANCE; } if($wallet_type){ $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $cash->user_id, 'wallet_type' => $wallet_type, 'is_frozen' => false, 'unfrozen' => false, 'money' => abs($cash_num), 'desc' => $desc, 'source_table' => AssetsType::CASH_OUT_REFUND, 'source_table_id' => $cash->id, 'from_type' => UserWalletEnum::WITHDRAWAL, 'capital_type' => UserWalletEnum::WITHDRAWAL_REFUND, 'no_change_field' => ['total_commission'] ]; UserWalletService::handle(0, $data); } if ($from == self::FROM_INCOME) { // 处理被扣除积分退回 CapitalLog::$capitalType = 'score'; $logs = CapitalLog::lists([ 'where' => [ ['mall_id' => $cash->mall_id], ['user_id' => $cash->user_id], ['from_type' => UserWalletEnum::WITHDRAWAL], ['capital_type' => UserWalletEnum::WITHDRAWAL_FOLLOW_DECR], ['source_table_id' => $cash->id], ], 'select' => 'user_id,from_type,change_num' ]); if ($logs) { $log = $logs[0]; $change_num = abs($log['change_num']); $score_name = \Yii::$app->services->setting->mall->get($cash->mall_id, 'score.score_name'); $desc = "佣金申请提现被驳回,{$change_num}{$score_name}原路退回"; $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $cash->user_id, 'wallet_type' => 'score', 'is_frozen' => false, 'unfrozen' => false, 'money' => $change_num, 'desc' => $desc, 'source_table' => AssetsType::CASH_OUT_REFUND, 'source_table_id' => $cash->id, 'from_type' => UserWalletEnum::WITHDRAWAL, 'capital_type' => UserWalletEnum::WITHDRAWAL_REFUND, ]; UserWalletService::handle(0, $data); } //返还冻结红包 $this->reject_redpack($cash); //处理被扣除提现额度 $withdrawsLimitChangeLog = WithdrawsLimitChangeLog::findOne(['withdraw_log_id' => $cash->id, 'status' => StatusEnum::ENABLED,'from'=>1]); if(!empty($withdrawsLimitChangeLog)){ $payment = \Yii::$app->services->setting->mall->get($cash->mall_id, 'withdraw_income'); $withdrawsLimitLog = WithdrawsLimitLog::findOne(['user_id' => $cash->user_id, 'status' => StatusEnum::ENABLED,'from'=>1, 'type' => $withdrawsLimitChangeLog->type]); if(!empty($withdrawsLimitLog)){ $withdraws_limit_money = $withdrawsLimitChangeLog->type == WithdrawsLimitLog::BALANCE_LIMIT ? ($payment["independent_balance_withdraw_max_amount"] ?? 0) : (isset($payment["withdraws_limit_money"]) ? $payment["withdraws_limit_money"] : 0); $withdrawsLimitLog->amount = bcadd($withdrawsLimitLog->amount,$cash->num,2); if($withdrawsLimitLog->amount > $withdraws_limit_money){ $withdrawsLimitLog->amount = $withdraws_limit_money; } if(!$withdrawsLimitLog->save()){ throw new \Exception(); } $withdrawsLimitChangeLog->status = StatusEnum::DISABLED; if(!$withdrawsLimitChangeLog->save()){ throw new \Exception(); } } } } } public function getUser(): \yii\db\ActiveQuery { return $this->hasOne(User::class, ['id' => 'user_id']); } /** * @throws Exception */ private function remit($cash): void { $res = false; if ($cash->type === 'auto') { //todo 待测试联调 /** * @var UserInfo $userInfo ; */ $userInfo = UserInfo::getOne([["user_id" => $cash->user_id, "platform" => [User::PLATFORM_WECHAT, User::PLATFORM_MP_WX], "status" => StatusEnum::ENABLED]]); if (empty($userInfo)) { throw new \Exception('该用户不存在微信相关信息!'); } // $wechatPaySetting = OptionLogic::get(Option::NAME_PAYMENT, \Yii::$app->mall->id, Option::GROUP_APP); // if (!$wechatPaySetting) { // throw new \Exception('系统未开启微信支付!'); // } // if (!$wechatPaySetting['wechat_status']) { // throw new \Exception('系统未开启微信支付!'); // } try { $payment = new PayService(); $paymentTransfer = new PaymentTransfer(); $paymentTransfer->orderNo = PaymentTransfer::generate_order_no("TR"); $paymentTransfer->user = $userInfo; $paymentTransfer->title = "收益提现"; $paymentTransfer->amount = $cash->actual_num; $paymentTransfer->withdrawal_source = 'UserWithdrawLog'; $paymentTransfer->withdrawal_source_id = $cash->id; $paymentTransfer->transferType = PayTypeEnum::WECHAT; // $paymentTransfer->transferType = PaymentTransfer::TRANSFER_TYPE_WECHAT; $paymentTransfer->cashInfo = $cash; $res = $payment->transfer($paymentTransfer); } catch (Exception $e) { throw new \Exception($e->getMessage()); } } else if ($cash->type === 'balance') { $userInfo = User::getOne([['id' => $cash->user_id, 'status' => StatusEnum::ENABLED]]); if (!$userInfo) { throw new \Exception('该用户不存在!'); } $desc = "用户收益提现到余额:" . $cash->actual_num . "元"; $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $cash->user_id, 'wallet_type' => UserWalletService::WALLET_TYPE_BALANCE, 'is_frozen' => false, 'unfrozen' => false, 'money' => abs($cash->actual_num), 'desc' => $desc, 'source_table' => AssetsType::CASH_OUT, 'source_table_id' => $cash->id, 'from_type' => UserWalletEnum::RECHARGE, 'capital_type' => UserWalletEnum::RECHARGE_COMMISSION, ]; $res = UserWalletService::handle(0, $data); //免审核,免打款 $withdraw_config = \Yii::$app->services->setting->mall->get($cash->mall_id, 'withdraw_income'); if (isset($withdraw_config['is_examine']) && $withdraw_config['is_examine']) { $cash->content = Json::encode(['validate_content' => '提现免审核,免打款']); } } elseif ($cash->type === 'paid' || $cash->type === 'joinpay') { //代付 $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_WITHDRAW_EXTENSION_PAY, $cash->mall_id, ['cash' => $cash]); if ($res) { // 提交成功 self::remit_wait($cash, "提交成功"); return; } else { // 提交失败 $msg = '代付打款失败'; throw new \Exception($msg); } } else if ($cash->type == 'alipay_offline' || $cash->type == 'wechat' || $cash->type == 'bank') { //线下转账 $res = true; } else if ($cash->type == 'digital') { $ids = [ $cash->id ]; $pay_res = GlobalInvoke::exec(GlobalInvoke::INVOKE_WITHDRAW_AVOIDTAX_PAY,$cash->mall_id,[ 'ids'=>$ids, 'mall_id'=>$cash->mall_id ]); if($pay_res){ // 提交成功 self::remit_wait($cash,"提交成功"); return; }else{ // 提交失败 $msg = '代付打款失败'; throw new \Exception($msg); } } else if ($cash->type === 'bank_tax') { // 银企直连 $data['mall_id'] = $cash->mall_id; $data['log_id'] = $cash->id; $service = new WithdrawalService($data); $banktaxToPay = $service->banktaxToPay(); if ($banktaxToPay === false) { $msg = '银企直连打款失败'; Yii::$app->custom->logs('提现到银企直连失败', ['err' => $service->error, 'cash' => $cash]); throw new \Exception($msg); } Yii::$app->custom->logs('提现到银企直连成功', ['res' => $banktaxToPay, 'cash' => $cash]); return; } else if ($cash->type === 'linggong') { //点薪灵工 $data['mall_id'] = $cash->mall_id; $data['log_id'] = $cash->id; $service = new WithdrawalService($data); $linggongToPay = $service->linggongToPay(); if ($linggongToPay === false) { $msg = '点薪灵工打款失败'; Yii::$app->custom->logs('提现到点薪灵工失败', ['err' => $service->error, 'cash' => $cash]); throw new \Exception($msg); } Yii::$app->custom->logs('提现到点薪灵工成功', ['res' => $linggongToPay, 'cash' => $cash]); return; } if ($res) { self::remit_success($cash); try { $obj = new WechatMessageLogic(); $obj->withdrawalSuccessSendMessage(['mall_id'=>$cash->mall_id,'user_id'=>$cash->user_id,'money'=>$cash->actual_num]); }catch (\Exception $e){ } }else{ $msg = '打款失败'; throw new \Exception($msg); } } /** * 明确打款成功 * * @param UserWithdrawLog $cash * @param string $msg * @return void */ public static function remit_success(UserWithdrawLog $cash, $msg = '打款成功') { // 保存提现信息 if ($cash->content) { $content = Json::decode($cash->content); } else { $content = []; } $cash->status = 2; $content['remit_at'] = date('Y-m-d H:i:s', time()); $content['remit_content'] = $msg; $cash->content = Json::encode($content); if (!$cash->save()) { throw new \Exception(); } $user_wallet_model = UserWallet::findOne(['user_id' => $cash->user_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]); if ($cash->from == 1) { //佣金 $user_wallet_model->commission_withdrawal += $cash->num; } else { //余额 $user_wallet_model->balance_withdrawal += $cash->num; } if (!$user_wallet_model->save()) { throw new \Exception(); } $user = []; //获取收益提现配置 $withdraw_income_config = \Yii::$app->services->setting->mall->get($cash->mall_id, 'withdraw_income'); if ($withdraw_income_config['level_withdrwas_reward_type'] == 1) { // 全局设置 if ($cash->direct_withdraws_reward_num > 0 || $cash->indirect_withdraws_reward_num > 0) { $user = User::getOne([['id' => $cash->user_id]]); } } else { // 独立设置 $user = User::getOne([['id' => $cash->user_id]]); } // print_r($withdraw_income_config);exit; if (!empty($withdraw_income_config['level_withdrwas_reward'])) $withdraw_income_config['level_withdrwas_reward'] = json_decode($withdraw_income_config['level_withdrwas_reward'], true); if (!empty($withdraw_income_config['indep_withdrwas_reward'])) $withdraw_income_config['indep_withdrwas_reward'] = json_decode($withdraw_income_config['indep_withdrwas_reward'], true); //发放提现直推奖 $can_reward = 1; $parent_id = $user->parent_id; if ($cash->from == 1) { $parent_user = User::find()->where(['mall_id' => $cash->mall_id, 'id' => $parent_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])->with(['userLevelTwo'])->asArray()->one(); if ($withdraw_income_config['level_withdrwas_reward_type'] == 1) { //查询上级等级 if (!empty($withdraw_income_config['level_withdrwas_reward'])) { if (!in_array($parent_user['level'], $withdraw_income_config['level_withdrwas_reward'])) $can_reward = 0; } } else if ($withdraw_income_config['level_withdrwas_reward_type'] == 2) { if (!empty($withdraw_income_config['indep_withdrwas_reward'][$parent_user['level']])) { $can_reward = 1; $cash->direct_withdraws_reward_num = intval(bcmul($cash->num * $withdraw_income_config['indep_withdrwas_reward'][$parent_user['level']]['direct_withdraws_reward'] / 100, 100)) / 100; } else { $can_reward = 0; } // print_r($withdraw_income_config['indep_withdrwas_reward']);exit; } } if ($cash->direct_withdraws_reward_num > 0) { if (!empty($parent_id) && $can_reward == 1) { $desc = "下级用户({$cash->user_id})提现({$cash->order_no}),发放直推奖励"; $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $parent_id, 'wallet_type' => $cash->from == 1 ? UserWalletService::WALLET_TYPE_COMMISSION : UserWalletService::WALLET_TYPE_BALANCE, 'is_frozen' => false, 'unfrozen' => false, 'money' => abs($cash->direct_withdraws_reward_num), 'desc' => $desc, 'source' => AssetsType::CASH_OUT, 'source_id' => $cash->id, 'from_type' => UserWalletEnum::REWARD, 'capital_type' => UserWalletEnum::DIRECT_REWARD ]; UserWalletService::handle(0, $data); } } //发放提现间推奖 $can_reward = 1; $second_parent_id = $user->second_parent_id; if ($cash->from == 1) { $second_parent_user = User::find()->where(['mall_id' => $cash->mall_id, 'id' => $second_parent_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]])->asArray()->one(); if ($withdraw_income_config['level_withdrwas_reward_type'] == 1) { //查询上级等级 if (!empty($withdraw_income_config['level_withdrwas_reward'])) { if (!in_array($second_parent_user['level'], $withdraw_income_config['level_withdrwas_reward'])) $can_reward = 0; } } else if ($withdraw_income_config['level_withdrwas_reward_type'] == 2) { if (!empty($withdraw_income_config['indep_withdrwas_reward'][$second_parent_user['level']])) { $can_reward = 1; $cash->indirect_withdraws_reward_num = intval(bcmul($cash->num * $withdraw_income_config['indep_withdrwas_reward'][$second_parent_user['level']]['indirect_withdraws_reward'] / 100, 100)) / 100; } else { $can_reward = 0; } } } if ($cash->indirect_withdraws_reward_num > 0) { if (!empty($second_parent_id) && $can_reward == 1) { $desc = "下下级用户({$cash->user_id})提现({$cash->order_no}),发放间推奖励"; $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $second_parent_id, 'wallet_type' => $cash->from == 1 ? UserWalletService::WALLET_TYPE_COMMISSION : UserWalletService::WALLET_TYPE_BALANCE, 'is_frozen' => false, 'unfrozen' => false, 'money' => abs($cash->indirect_withdraws_reward_num), 'desc' => $desc, 'source' => AssetsType::CASH_OUT, 'source_id' => $cash->id, 'from_type' => UserWalletEnum::REWARD, 'capital_type' => UserWalletEnum::INDIRECT_REWARD ]; UserWalletService::handle(0, $data); } } //提现余额&佣金转积分 if ($cash->give_score_num > 0) { $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $cash->user_id, 'wallet_type' => UserWalletService::WALLET_TYPE_SCORE, 'is_frozen' => false, 'unfrozen' => false, 'money' => abs($cash->give_score_num), 'desc' => '提现[' . $cash->order_no . '] 转积分', 'source' => AssetsType::RECHARGE, 'source_id' => $cash->id, 'from_type' => UserWalletEnum::TRANSFER, 'capital_type' => $cash->from == 1 ? UserWalletEnum::WITHDRAWAL_COMMISSION_TRANSFER : UserWalletEnum::WITHDRAWAL_BALANCE_TRANSFER ]; UserWalletService::handle(0, $data); } //提现佣金转余额 if ($cash->exchange_balance_num > 0) { $data = [ 'message_id' => 0, 'mall_id' => $cash->mall_id, 'user_id' => $cash->user_id, 'wallet_type' => UserWalletService::WALLET_TYPE_BALANCE, 'is_frozen' => false, 'unfrozen' => false, 'money' => abs($cash->exchange_balance_num), 'desc' => '提现[' . $cash->order_no . '] 转余额', 'source' => AssetsType::RECHARGE, 'source_id' => $cash->id, 'from_type' => UserWalletEnum::TRANSFER, 'capital_type' => UserWalletEnum::WITHDRAWAL_COMMISSION_TRANSFER_BALANCE ]; UserWalletService::handle(0, $data); } } /** * 打款失败,变成已同意状态,让客户自己去驳回 * * @param UserWithdrawLog $cash * @param string $msg * @return void */ public static function remit_fail(UserWithdrawLog $cash, $msg) { $content = empty($cash->content) ? [] : Json::decode($cash->content); $content['remit_content'] = $msg; $res = UserWithdrawLog::updateAll([ 'status' => 1, 'content' => Json::encode($content), 'updated_at' => time() ], ['id' => $cash->id]); } /** * 打款中 * * @param [type] $cash * @param [type] $msg * @return void */ public static function remit_wait(UserWithdrawLog $cash, $msg) { $content = empty($cash['content']) ? [] : Json::decode($cash['content']); $content['remit_content'] = $msg; $res = self::updateAll(['content' => Json::encode($content), 'status' => 5], ['id' => $cash['id']]); } public static function exportHandle(array $data) { $download_id = $data['download_id'] ?? 0; $download = Download::findOne(['id' => $download_id]); if ($download) { try { $params = json_decode($download->params, true); $isChanjetExport = !empty($params['is_chanjet_addons']); $filename = $download->name; $type = $download->type; $user_withdrawlog_model = UserWithdrawLog::find(); $user_withdrawlog_model->where(['mall_id' => $params['mall_id']]); if (!empty($params['keyword'])) { $user = User::find()->where([ 'OR', ['like', 'nickname', $params['keyword'] . '%', false], ['like', 'mobile', $params['keyword'] . '%', false], ])->all(); $where[] = ['in', 'user_id', array_column($user, 'id')]; $user_withdrawlog_model->andWhere(['in', 'user_id', array_column($user, 'id')]); } if (!empty($params['user_id'])) $user_withdrawlog_model->andWhere(['=', 'user_id', $params['user_id']]); if (!empty($params['withdraw_type'])) $user_withdrawlog_model->andWhere(['=', 'type', $params['withdraw_type']]); if (!empty($params['withdraw_from'])) $user_withdrawlog_model->andWhere(['=', 'from', $params['withdraw_from']]); if (!empty($params['start_date'])) $user_withdrawlog_model->andWhere(['>=', 'created_at', strtotime($params['start_date'])]); if (!empty($params['end_date'])) $user_withdrawlog_model->andWhere(['<=', 'created_at', strtotime($params['end_date'])]); if (isset($params['status'])) { $user_withdrawlog_model->andWhere(['=', 'status', $params['status']]); } else { $user_withdrawlog_model->andWhere(['>=', 'status', StatusEnum::DISABLED]); } $fields = $params['fields']; $fields_arr = self::fieldsList(null, $isChanjetExport); $have_select_field_arr = []; foreach ($fields as $value) { $have_select_field_arr[] = $fields_arr[$value]; } // 获取提现方式 $userWithdrawType = self::getUserWithdrawType($params['mall_id']); $csv = new CsvTool(); $csv->filename = $filename; $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($type); $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC; $csv->header = $have_select_field_arr; $user_withdrawlog_model->with(['user' => function ($query) { $query->select('id,nickname,username,avatar_url,mobile'); }]); if ($isChanjetExport) { $user_withdrawlog_model->with(['addonsChanjetRequest']); } $user_withdrawlog_model->orderBy('status asc,created_at desc'); foreach ($user_withdrawlog_model->batch() as $withdrawlog) { $csv->data = array_map(function ($withdrawlog) use ($fields, $userWithdrawType) { $row = []; $extra = json_decode($withdrawlog['extra'], true) ?: []; foreach ($fields as $field) { switch (true) { case (in_array($field, ['updated_at'])): $row[] = !empty($withdrawlog[$field]) ? date('Y-m-d H:i:s', $withdrawlog[$field]) : ''; break; case ($field == 'username'): $row[] = $withdrawlog['user']['username'] ?: ''; break; case ($field == 'nickname'): $row[] = $withdrawlog['user']['nickname'] ?: ''; break; case ($field == 'user_mobile'): $row[] = $withdrawlog['user']['mobile'] ?: ''; break; case ($field == 'from'): $row[] = $withdrawlog[$field] == 1 ? '佣金收益提现' : '余额提现'; break; case ($field=='alipay_name'): $row[] = $extra['name'] ?: ''; break; case ($field=='mobile'): $row[] = empty($extra['mobile']) ? '' : $extra['mobile']."\t"; break; case ($field=='bank_account_type'): $row[] = $extra['bank_account_type'] == 1 ? '对私账户' : ($extra['bank_account_type'] == 2 ? '对公账号' : ''); break; case ($field=='name'): $row[] = $extra['name'] ?: ''; break; case ($field=='bank_name'): $row[] = $extra['bank_name'] ?: ''; break; case ($field=='bank_account'): $row[] = empty($extra['bank_account']) ? '' : $extra['bank_account']."\t"; break; case ($field == 'withdraw_type'): // 提现方式 $row[] = $userWithdrawType[$withdrawlog['type']] ?? ''; break; case ($field=='idcard'): $row[] = empty($extra['idcard']) ? '' : $extra['idcard']."\t"; break; case ($field=='wechat_qrcode'): $row[] = $extra['wechat_qrcode'] ?: ''; break; case ($field=='status'): $str = ''; switch ($withdrawlog[$field]){ case 0: $str='待审核'; break; case 1: $str='待打款'; break; case 2: $str='已打款'; break; case 5: $str='打款中'; break; case 3: $str='已驳回'; break; } $row[] = $str; break; case ($field == 'remark'): $withdrawlog['content'] = json_decode($withdrawlog['content'], true); $str = ''; if (!empty($withdrawlog['content']['reject_content'])) $str .= '驳回备注:' . $withdrawlog['content']['reject_content']; if (!empty($withdrawlog['content']['validate_content']) && in_array($withdrawlog['status'], [1, 2])) $str .= ';审核备注:' . $withdrawlog['content']['validate_content']; if (!empty($withdrawlog['content']['remit_content']) && in_array($withdrawlog['status'], [1, 2])) $str .= ';打款备注:' . $withdrawlog['content']['remit_content']; if (!empty($withdrawlog['content']['joinpay_msg'])) $str .= ';汇聚备注:' . $withdrawlog['content']['joinpay_msg']; $row[] = $str; break; case ($field == 'chanjet_updated_at'): if (isset($withdrawlog['addonsChanjetRequest']['updated_at'])) { $row[] = date('Y-m-d H:i:s', $withdrawlog['addonsChanjetRequest']['updated_at']); }else { $row[] = ''; } break; case ($field == 'chanjet_request_status'): if (isset($withdrawlog['addonsChanjetRequest']['request_status'])) { $row[] = AddonsChanjetRequestEnum::getMap()[$withdrawlog['addonsChanjetRequest']['request_status']] ?? ''; }else { $row[] = ''; } break; default: $row[] = !empty($withdrawlog[$field]) ? $withdrawlog[$field] : ''; } } return $row; }, $withdrawlog); $csv->export(); } $csv->updateDown($download, $params['mall_id']); return true; } catch (\Exception $e) { $download->status = 3; $res = $download->save(); self::setStaticError($e->getMessage()); return $e->getMessage(); } } } /** * 获取用户提现方式 * @param int $mall_id * @return array|string[] */ public static function getUserWithdrawType(int $mall_id) { $cashTypeBalance = $cashTypeIncome = []; $paymentIncome = \Yii::$app->services->setting->mall->get($mall_id, 'withdraw_income'); if (!empty($paymentIncome['balance_cash_type'])) { $decoded = Json::decode($paymentIncome['balance_cash_type']); if (is_array($decoded)) { $cashTypeIncome = $decoded; } } $paymentBalance = \Yii::$app->services->setting->mall->get($mall_id, 'withdraw_balance'); if (!empty($paymentBalance['balance_cash_type'])) { $decoded = Json::decode($paymentBalance['balance_cash_type']); if (is_array($decoded)) { $cashTypeBalance = $decoded; } } $cash_type = array_merge($cashTypeIncome, $cashTypeBalance); $cash_type_name = []; if (!empty($cash_type)) { $default_withdraw_way = WithdrawWayEnum::getDefaultWithDrawWayMap(WithdrawWayEnum::WITHDRAW_TYPE_2); $extension_withdraw_way = GlobalInvoke::exec(GlobalInvoke::INVOKE_GET_WITHDRAW_EXTENSION_WAY, $mall_id, ['mall_id' => $mall_id]); $all_withdraw = array_merge($default_withdraw_way, $extension_withdraw_way); foreach ($cash_type as $item) { if (isset($all_withdraw[$item])) { $value = $all_withdraw[$item]; $name = is_array($value) ? ($value['name'] ?? '') : $value; $cash_type_name[$item] = $name; } } } return array_merge($cash_type_name, WithdrawWayEnum::getDefaultWithDrawWayMap(null)) ?? []; } /** * 提现限制 * * @param array $params * @return boolean */ protected function witdrawLimit(array $params, array $setting) { // 开启限制 if (isset($setting['limit_switch']) && $setting['limit_switch'] == 1) { // 周限制 if ($setting['limit_type'] == 1) { // ISO-8601 格式数字表示的星期中的第几天(PHP 5.1.0 新加 $d = date('N'); $limit = !empty($setting['week']) ? Json::decode($setting['week']) : []; sort($limit); $weekStr = [1 => '一', 2 => '二', 3 => '三', 4 => '四', 5 => '五', 6 => '六', 7 => '日']; $limitStr = array_map(function ($item) use ($weekStr) { return $weekStr[$item] ?? ''; }, $limit); $error = sprintf('当前可提现时间为每周%s', implode(',', array_filter($limitStr))); } // 月限制 if ($setting['limit_type'] == 2) { // 月份中的第几天,没有前导零 $d = date('j'); $limit = !empty($setting['month']) ? Json::decode($setting['month']) : []; sort($limit); $error = sprintf('当前可提现时间为每月的%s号', implode(',', $limit)); } // 提现限制时间 if (in_array($d, $limit) === false) { $this->error = $error; return false; } // 首次提现 if (!empty($setting['first_withdraw']) && $first_withdraw = $setting['first_withdraw']) { // 是否首次提现 if (static::isFirstWithdraw($params['from'], $params['user_id'])) { // 提现金额不足 if (!empty($params['price']) && $params['price'] < $first_withdraw) { $this->error = sprintf('首次提现最低金额为%s', sprintf('%.2f', $first_withdraw)); return false; } } } } return true; } /** * 提现拒绝,红包返回 * @param $cash */ protected function reject_redpack($cash) { $mall_id = $cash->mall_id; $install_redpack = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_REDPACK); if($install_redpack){ //本次提现是否扣除冻结红包 $exist = RedpackWalletLog::findOne(['mall_id' => $mall_id,'user_id' => $cash->user_id,'redpack_wallet_type' => 'frozen_redpack','from_type' => RedpackEnum::FROM_CASH_DEDUCT,'source_table_id' => $cash->id]); if($exist){ $config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REDPACK, 'basic'); $redpack_name = $config['redpack_name'] ?? '红包';// 自定义红包名称 $wallet = RedpackWallet::setData([ 'mall_id' => $mall_id, 'user_id' => $cash->user_id, 'is_frozen' => true, 'is_deduct' => true, 'money' => $exist['change_num'], 'from_type' => RedpackEnum::FROM_CASH_DEDUCT, 'desc' => "佣金提现审核失败,返还冻结".$redpack_name, 'source_table' => self::tableName(), 'source_table_id' => $cash->id, ]); if(!$wallet) throw new \Exception(RedpackWallet::getStaticError()); } } } public static function doRepurchaseCheck($payment, $user, $mall_id) { $is_withdraw_repurchase = isset(\Yii::$app->params['is_withdraw_repurchase']) ? \Yii::$app->params['is_withdraw_repurchase'] : false; if (!$is_withdraw_repurchase) return 0; if (!$payment['enable_repurchase_limit']) return 0; if ($payment['repurchase_reach_money'] <= 0) return 0; $level_arr = json_decode($payment['repurchase_user_level_limit'], true); if (!in_array($user['level'], $level_arr)) return 0; $log = UserWithdrawLog::find()->where([ 'and', ['mall_id' => $mall_id], ['user_id' => $user['id']], ['from' => 1], ['status' => [1, 2]] ])->orderBy('id desc')->limit(1)->one(); $repurchase_money = 0; if ($log) { if (date('m', $log['created_at']) == date('m')) { $repurchase_money = \common\models\order\Order::find()->where([ 'and', ['mall_id' => $mall_id], ['user_id' => $user['id']], ['pay_status' => StatusEnum::ENABLED], ['>=', 'pay_time', strtotime(date('Y-m-01', time()))], ['<=', 'pay_time', strtotime(date('Y-m-t', time()))] ])->sum('goods_price') ?? 0; } else { $start_time = $log['created_at']; $start_year = date('Y', $start_time); $current_year = date('Y', time()); $start_month = (int)date('m', $start_time); $current_month = (int)date('m', time()); $distance_year = $current_year - $start_year; //月份相差多少 $distance_month = 12 - $start_month + $current_month; //相差一年就加12 $distance = $distance_month + (($distance_year - 1) * 12); $payment['repurchase_reach_money'] = bcmul($distance, $payment['repurchase_reach_money'], 2); $repurchase_money = \common\models\order\Order::find()->where([ 'and', ['mall_id' => $mall_id], ['user_id' => $user['id']], ['pay_status' => StatusEnum::ENABLED], ['>', 'pay_time', strtotime(date('Y-m-t 23:59:59', $start_time))], ['<=', 'pay_time', time()] ])->sum('goods_price') ?? 0; } } else { $repurchase_money = \common\models\order\Order::find()->where([ 'and', ['mall_id' => $mall_id], ['user_id' => $user['id']], ['pay_status' => StatusEnum::ENABLED], ['>=', 'pay_time', strtotime(date('Y-m-01', time()))], ['<=', 'pay_time', strtotime(date('Y-m-t 23:59:59', time()))] ])->sum('goods_price') ?? 0; } return $repurchase_money - $payment['repurchase_reach_money']; } /** * 是否首次提现 * * @param integer $from * @return boolean */ public static function isFirstWithdraw(int $from, int $user_id) { $has = static::find() ->andWhere([ 'user_id' => $user_id, 'status' => static::STATUS_ALREADY_TRANS, 'from' => $from, ]) ->select(['id']) ->one(); return empty($has); } public static function checkPassword($user_id, $check_transaction_password, $setting = []) { if ($setting) { $enable_password = $setting['enable_password'] ?? 0; if ($enable_password == 1) { $userinfo = User::getOne([['id' => $user_id]], true, '', '', 'transaction_password'); if (!$check_transaction_password) { return [ 'state' => false, 'msg' => '请输入支付密码!' ]; } if (empty($userinfo['transaction_password'])) { return [ 'state' => false, 'msg' => '您未设置支付密码!' ]; } if (empty($check_transaction_password)) { return [ 'state' => false, 'msg' => '请输入交易密码!' ]; } if (!\Yii::$app->getSecurity()->validatePassword(trim($check_transaction_password), $userinfo['transaction_password'])) { return [ 'state' => false, 'msg' => '支付密码错误!' ]; } } } return true; } /** * 获取数据 * * @param integer $mall_id * @return array */ public static function getWithdrawLogStatistic(int $mall_id) { $audit_commision = static::find()->where(['mall_id' => $mall_id, 'status' => 0])->sum('num'); $pending_commision = static::find()->where(['mall_id' => $mall_id, 'status' => 1])->sum('num'); $paid_commision = static::find()->where(['mall_id' => $mall_id, 'status' => 2])->sum('num'); $rejected_commision = static::find()->where(['mall_id' => $mall_id, 'status' => 3])->sum('num'); $total_commision = static::find()->where(['mall_id' => $mall_id])->sum('num'); return [ $audit_commision ?? '0.00', $pending_commision ?? '0.00', $paid_commision ?? '0.00', $rejected_commision ?? '0.00', $total_commision ?? '0.00', ]; } /** * 畅捷通请求 * * @return \yii\db\ActiveQuery */ public function getAddonsChanjetRequest() { return $this ->hasOne(AddonsChanjetRequest::class, ['table_id' => 'id']) ->orderBy('updated_at desc') ->select('id, table_id, request_status, updated_at') ->where([ 'table' => self::tableName(), 'path' => [Request::PATHS['EXPENSE_VOUCHER_CREATE_EXPENSE_VOUCHER']] ]) ->andWhere(['>', 'request_status', 0]); } public static function withdrawCheck($params) { if (!$params['type']) { throw new Exception('请选择提现方式'); } switch ($params['type']) { case "yunfast_pay": if (empty($params['bank_account'])) { throw new Exception('请选择银行卡'); } if (empty($params['bank_account_type'])) { throw new Exception('请选择账户类型'); } if (empty($params['name'])) { throw new Exception('请输入持卡人姓名'); } break; case 'alitopay': case WithdrawWayEnum::ALIPAY_OFFLINE: if (empty($params['mobile'])) { throw new Exception('请输入支付宝账号'); } if (empty($params['name'])) { throw new Exception('请输入支付宝真实姓名'); } break; case 'wechat': if (!isset($params['wechat_qrcode'])) { throw new Exception('请上传微信收款码'); } break; case 'alipay': if (!isset($params['mobile'])) { throw new Exception('请填写支付宝账号'); } if (!$params['name']) { throw new Exception('请填写支付宝姓名'); } break; case 'paid': case 'joinpay': if (!$params['name']) { throw new \Exception('请填写持卡人'); } if (!$params['bank_account']) { throw new \Exception('请填写银行卡号'); } break; case 'alipay_tax': if (!$params['mobile']) { throw new \Exception('请填写支付宝账号(手机号)'); } if (!$params['name']) { throw new \Exception('请填写支付宝姓名'); } if (!$params['id_card']) { throw new \Exception('请填写身份证信息'); } $service = new \addons\AvoidTax\common\service\UserService(['mall_id' => $params['mall_id']]); // 判断当前身份ID是否已经签约 已签约则不签约 if (!$service->idIsSignAndAddAuthOfUid( $params['id_card'], $params['name'], $params['user_id'], $params['mobile'] )) { // 判断用户是否签约 $res = $service->checkSign($params['user_id']); if ($res === false) { if ($service->getConfigService()->isXLApiType()) { $res = $service->goToSing($params['user_id'], $params['mobile'], $params['id_card'], $params['name'], $extra['redirect_url'] ?? ''); if (!$res) { throw new \Exception($service->error); } // 跳转url签约 return [ 'state' => true, 'data' => $res ]; } if ($service->getConfigService()->isLYApiType()) { $res = $service->silentSign( $params['user_id'], $params['name'], $params['mobile'], $params['id_card'] ); if ($res === false) { throw new \Exception($service->error); } } } } break; case 'digital': if (!$params['mobile']) { throw new \Exception('请填写支付宝绑定的手机号!'); } if ($params['bank_account_type'] == 2) { $params['bank_account'] = $params['mobile']; } if ($params['bank_account_type'] == 3) { $findOpenId = UserInfo::find()->where(['user_id' => $params['user_id'], 'status' => StatusEnum::ENABLED])->one(); if (empty($findOpenId->openid)) { return [ 'state' => false, 'msg' => '该账号未绑定微信,无法使用微信提现方式!' ]; } } // 是否签约 $sign = DigitalEmploymentOrder::inquireSign($params['mall_id'], $params['user_id']); // 1-签约中 2-签约成功 3-签约失败 if (empty($sign)) { throw new \Exception('该用户未进行签约!'); } if ($sign->result->signState == 1) { throw new \Exception('该用户的签约正在审核中!'); } if ($sign->result->signState == 3) { throw new \Exception('用户签约失败,请重新签约!'); } break; case 'auto': $payment_conf = Yii::$app->services->setting->mall->get($params['mall_id'], 'pay.wechat'); $payment_conf = json_decode($payment_conf, true); if(!is_numeric($payment_conf['wechat_auto_pay_limit'])) $payment_conf['wechat_auto_pay_limit'] = 200; if($params['from'] == self::FROM_SCORE){//积分提现,需除以积分提现比例 $payment = Yii::$app->services->setting->mall->get($params['mall_id'], 'score'); $params['price'] = bcdiv($params['price'],$payment['score_cash_radio'],2); } if ($params['price'] > $payment_conf['wechat_auto_pay_limit']) { throw new \Exception('微信自动打款提现最高提现金额不能超过'.$payment_conf['wechat_auto_pay_limit'].'元'); } break; case 'bank': if (empty($params['bank_account']) || empty($params['name'] || empty($params['bank_name']))) { throw new \Exception('请选择你要提现的银行'); } break; case 'linggong': //点薪灵工 if (empty($params['name'])) { throw new \Exception('请输入真实姓名'); } if (empty($params['mobile'])) { throw new \Exception('请输入手机号'); } if (empty($params['bank_account'])) { throw new \Exception('请输入银行卡号'); } if (empty($params['idcard'])) { throw new \Exception('请输入身份证'); } break; } if (!empty($params['need_auth'])) { $need_auth = GlobalInvoke::exec( GlobalInvoke::REAL_AUTH, $params['mall_id'], ['user_id' => $params['user_id'], 'mall_id' => $params['mall_id'], 'type' => 'cash'] ); if ($need_auth === true) { // 需要先进行实名认证 throw new Exception('请先进行实名认证'); } } //商家认证 if (!empty($params['MerchantAuth'])) { if (MallAddons::isInstall($params['mall_id'], 'MerchantAuth')) { $configs = Yii::$app->services->setting->addons->get($params['mall_id'], 'MerchantAuth', 'basic'); if (!empty($configs['is_force'])) { //强制需要认证 $res = MerchantAuthLog::getOne([ ['mall_id' => $params['mall_id']], ['user_id' => $params['user_id']], ['status' => 1] ]); if (empty($res)) { throw new Exception('未查询到认证资料,请先进行商家认证'); } if (empty($res['progress'])) { if ($res['is_poss'] == 0) { throw new Exception('商家认证资料已提交,请等待审核'); } else { throw new Exception('请先进行商家认证'); } } elseif ($configs['is_force'] == 2 && $res['progress'] != 2) { if ($res['is_poss'] == 0) { throw new Exception('商家认证资料已提交,请等待审核'); } else { throw new Exception('请先进行商家认证'); } } } } } } //汇聚代付-免审核 public static function joinpay_remit($cash): void { $res = false; if ($cash->type === 'paid' || $cash->type === 'joinpay') { //代付 // print_r($cash);exit; $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_WITHDRAW_EXTENSION_PAY, $cash->mall_id, ['cash' => $cash]); // print_r($res);exit; if ($res) { // 提交成功 self::remit_wait($cash, "提交成功"); return; } else { // 提交失败 $msg = '代付打款失败'; throw new \Exception($msg); } } if ($res) { self::remit_success($cash); try { $obj = new WechatMessageLogic(); $obj->withdrawalSuccessSendMessage(['mall_id'=>$cash->mall_id,'user_id'=>$cash->user_id,'money'=>$cash->actual_num]); }catch (\Exception $e){ } }else{ $msg = '打款失败'; throw new \Exception($msg); } } /** * 根据提现到余额总权重控制配置决定要不要验证具体的项 * * @param int $from * @param string $type * @param array $setting * * @return array */ protected function getIsNeedCheckSettingMap(int $from, string $type, array $setting): array { $isNeedCheckMap = []; $isOpen = !empty($setting['balance_withdraw_total_weight_limit_switch']); if ($isOpen) { $balanceWithdrawTotalWeightLimitSelected = json_decode($setting['balance_withdraw_total_weight_limit_selected'] ?? '', true); !is_array($balanceWithdrawTotalWeightLimitSelected) && $balanceWithdrawTotalWeightLimitSelected = []; } else { $balanceWithdrawTotalWeightLimitSelected = array_column(WithdrawEnum::BALANCE_WITHDRAW_TOTAL_WEIGHT_LIMIT_OPTION, 'value'); } foreach (WithdrawEnum::BALANCE_WITHDRAW_TOTAL_WEIGHT_LIMIT_OPTION as $item) { if ($type !== 'balance' || $from !== self::FROM_INCOME || !$isOpen) { $isNeedCheckMap[$item['value']] = true; continue; } $isNeedCheckMap[$item['value']] = in_array($item['value'], $balanceWithdrawTotalWeightLimitSelected); } return $isNeedCheckMap; } /** * 返回是否在 "提现到余额总权重限制" 的配置中根据type * * @param int $from * @param string $type * @param array $setting * * @return bool */ public function inBalanceWithdrawTotalWeightLimitSelectedByType(int $from, string $type, array $setting) { if ($from !== self::FROM_INCOME) { return true; } if (empty($setting['balance_withdraw_total_weight_limit_switch'])) { return true; } $balanceWithdrawTotalWeightLimitSelected = json_decode($setting['balance_withdraw_total_weight_limit_selected'] ?? '', true); if (!$balanceWithdrawTotalWeightLimitSelected || !is_array($balanceWithdrawTotalWeightLimitSelected)) { return false; } return in_array($type, $balanceWithdrawTotalWeightLimitSelected); } }