| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787 |
- <?php
- namespace services\common;
- use common\components\Service;
- use common\enums\UserWalletEnum;
- use common\events\census\ShareEvent;
- use common\events\user\UserWalletEvent;
- use common\helpers\TaskHelper;
- use common\helpers\LockHelper;
- use common\logic\wechat\WechatMessageLogic;
- use common\models\common\CapitalErrorLog;
- use common\models\common\CapitalLogRelation;
- use common\models\common\FrozenCommissionLog;
- use common\models\user\UserWallet;
- use common\models\common\CapitalLog;
- use services\common\RabbitMqService;
- use common\enums\RedisKeyEnum;
- use common\enums\RabbitMqEnum;
- use common\enums\StatusEnum;
- use common\models\user\UserFreezeCommission;
- use common\models\user\UserInfo;
- use common\traits\ErrorTrait;
- use common\models\user\UserWithdrawLog;
- use Exception;
- use Yii;
- use yii\helpers\Json;
- /**
- *
- * 用户资金服务类
- * Date: 2021/10/08
- * Time: 14:56
- */
- class UserWalletService extends Service
- {
- use ErrorTrait;
- //钱包操作类型
- const WALLET_TYPE_SCORE = 'score';
- const WALLET_TYPE_FROZEN_SCORE = 'frozen_score';
- const WALLET_TYPE_BALANCE = 'balance';
- const WALLET_TYPE_FROZEN_BALANCE = 'frozen_balance';
- const WALLET_TYPE_COMMISSION = 'commission';
- const WALLET_TYPE_FROZEN_COMMISSION = 'frozen_commission';
- /**
- * 获取资金类型
- * @return array
- */
- public static function getWalletType()
- {
- return [
- self::WALLET_TYPE_SCORE,
- self::WALLET_TYPE_BALANCE,
- self::WALLET_TYPE_COMMISSION
- ];
- }
- /**
- * 获取资金类型描述
- * @param $type
- * @return mixed|string
- */
- public static function getWalletTypeMsg($type)
- {
- $arr = [
- self::WALLET_TYPE_SCORE => '积分',
- self::WALLET_TYPE_FROZEN_SCORE => '冻结积分',
- self::WALLET_TYPE_BALANCE => '余额',
- self::WALLET_TYPE_FROZEN_BALANCE => '冻结余额',
- self::WALLET_TYPE_COMMISSION => '佣金',
- self::WALLET_TYPE_FROZEN_COMMISSION => '冻结佣金',
- ];
- return $arr[$type] ?? '';
- }
- /**
- * 异步队列操作用户钱包
- * @param int $mall_id
- * @param int $user_id
- * @param string $wallet_type 操作类型:score,balance,commission
- * @param float $money 操作金额,负数:减少/正数:增加
- * @param bool $is_frozen 是否操作冻结资金
- * @param string $desc 操作描述
- * @param string $source 来源
- * @param int $source_id 来源业务ID
- * @param bool $wait_result 是否阻塞,等待结果
- * @throws
- * @return bool
- */
- public static function handleByQueue($mall_id, $user_id, $wallet_type, $money, $is_frozen = false, $desc = '', $source = '', $source_id = 0, $wait_result = true)
- {
- if (!in_array($wallet_type, [self::WALLET_TYPE_SCORE, self::WALLET_TYPE_BALANCE, self::WALLET_TYPE_COMMISSION])) {
- throw new Exception('操作类型不合法');
- }
- $task_id = TaskHelper::pushTaskQueue(
- RabbitMqEnum::EXCHANGE_TASK_USER_WALLET,
- RabbitMqEnum::USER_WALLET_QUEUE,
- ['mall_id' => $mall_id, 'user_id' => $user_id, 'wallet_type' => $wallet_type, 'money' => $money, 'is_frozen' => $is_frozen, 'desc' => $desc, 'source' => $source, 'source_id' => $source_id],
- __CLASS__,
- 'handle'
- );
- if (!$task_id) {
- throw new Exception('操作失败');
- }
- $result = true;
- //block for result
- if ($wait_result) {
- $hasWait = 0; //已经等待的时间:毫秒
- $max_wait_time = 3 * 1000; //最长等待 3s
- while (true) {
- $result = self::getHandleResult($task_id);
- if ($result) {
- break;
- }
- usleep(30 * 1000);//等待30ms
- $hasWait += 30;
- if ($hasWait > $max_wait_time) {
- //等待超时
- $result = false;
- break;
- }
- }
- }
- //注意:返回false 表示正在等待处理
- return $result;
- }
- /**
- * 异步队列-批量操作用户钱包
- * @param $data
- * [
- * ['mall_id' => $mall_id,'user_id'=>1,'is_frozen'=>true,'not_add_total'=>true,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type'],
- * ['mall_id' => $mall_id,'user_id'=>2,'is_frozen'=>false,'not_add_total'=>false,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type'],
- * ]
- * @return bool
- * @throws Exception
- */
- public static function batchHandleByQueue($data)
- {
- $capital_types = self::getWalletType();
- $function = 'batchHandle';
- //判断data 数据格式
- foreach ($data as $val) {
- if (empty($val['user_id'])) {
- throw new Exception('参数不合法 ,user_id 不能为空');
- }
- if (empty($val['mall_id'])) {
- throw new Exception('参数不合法 ,mall_id 不能为空');
- }
- if (!in_array($val['wallet_type'], $capital_types)) {
- throw new Exception('操作类型不合法');
- }
- $change_type[] = $val['money'] > 0 ? 'add' : 'sub';
- }
- //操作类型不一致
- $change_type = array_unique($change_type);
- if(count($change_type) > 1) $function = 'batchHandleByTransaction';
- $task_id = TaskHelper::pushTaskQueue(
- RabbitMqEnum::EXCHANGE_TASK_USER_WALLET,
- RabbitMqEnum::USER_WALLET_QUEUE,
- $data,
- __CLASS__,
- $function
- );
- if (!$task_id) {
- throw new Exception('操作失败');
- }
- return true;
- }
- /**
- * 批量操作用户钱包
- * @param int $task_id mq消费message_id
- * @param array $data
- * [
- * ['mall_id' => $mall_id,'user_id'=>1,'is_frozen'=>true,'not_add_total'=>true,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type','order_no'=>$order_no,'contributor_name'=>$contributor_name,'contributor_id'=>$contributor_id,'contributor_money'=>$contributor_money],
- * ['mall_id' => $mall_id,'user_id'=>2,'is_frozen'=>false,'not_add_total'=>false,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type','order_no'=>$order_no,'contributor_name'=>$contributor_name,'contributor_id'=>$contributor_id,'contributor_money'=>$contributor_money],
- *
- * ]
- * @throws
- * @return bool
- *
- */
- public static function batchHandle($data)
- {
- $task_id = 0;
- if(!empty($data['message_id'])){
- $task_id = $data['message_id'];
- unset($data['message_id']);
- }
- $user_handles = [];
- $capital_log_list = [];// 提交数据记录类型
- foreach ($data as $val) {
- $wallet_type = empty($val['is_frozen']) ? $val['wallet_type'] : 'frozen_'.$val['wallet_type'];
- $capital_log_type = empty($val['is_frozen']) ? $val['wallet_type'] : $val['wallet_type'] . '_frozen';
- if (!in_array($capital_log_type, $capital_log_list)) {
- $capital_log_list[] = $capital_log_type;
- }
- $user_handles[$val['user_id']][$wallet_type][] = $val;
- }
- $error = [];
- $time = time();
- $user_wallet_list = [];
- $mall_id = $data[0]['mall_id'];
- foreach ($user_handles as $user_id => $handle) {
- $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_USER_WALLET , $user_id);
- $identification = uniqid();
- if (!LockHelper::lock($lock_key, $identification, 100, 100)) {
- Yii::error(__CLASS__ . ' batchHandle error : 抢不到锁,task_id:' . $task_id);
- continue;
- }
- $user_wallet_model = UserWallet::findOne(['user_id' => $user_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]);
- if (empty($user_wallet_model)) {
- $error[] = ['user_id' => $user_id, 'type' => '', 'params' => json_encode($handle), 'error_msg' => '用户钱包不存在'];
- continue;
- }
- foreach ($handle as $wallet_type => $logs) {
- $is_frozen = false;
- if (strpos($wallet_type, 'frozen') !== false) {
- $is_frozen = true;
- }
- //求和
- $money = array_sum(array_column($logs, 'money'));
- if (!is_numeric($money) || empty($money)) {
- continue;
- }
- $current_num = $user_wallet_model->$wallet_type;
- /*if ($current_num + $money < 0) {
- $error[] = ['user_id' => $user_id, 'type' => $wallet_type, 'params' => json_encode($logs), 'error_msg' => '用户' . self::getWalletTypeMsg($wallet_type) . '不足'];
- continue;
- }*/
- foreach ($logs as $key => $log) {
- //操作非冻结资金
- $wallet_type = $log['wallet_type'];
- $frozen_field = 'frozen_'.$wallet_type;
- $total_field = 'total_' . $wallet_type;
- $total_use_field = 'total_use_' . $wallet_type;
- if ($log['is_frozen']) {
- $user_wallet_model->$frozen_field += $log['money'];//冻结
- }else{
- $user_wallet_model->$wallet_type += $log['money'];//非冻结
- }
- if ($log['is_frozen']==false&&empty($log['not_add_total'])) {
- $log['money'] > 0 && $user_wallet_model->$total_field += $log['money'];//总数
- }
- if ($log['capital_type'] != UserWalletEnum::WITHDRAWAL_DECR) {
- $log['is_frozen'] == false && $log['money'] < 0 && $user_wallet_model->$total_use_field += abs($log['money']);//已使用
- }
- }
- $trans = Yii::$app->db->beginTransaction();
- if (!$user_wallet_model->save()) {
- $error[] = ['user_id' => $user_id, 'wallet_type' => $wallet_type, 'logs' => $logs, 'error_msg' => $user_wallet_model->getErrorMessage()];
- $trans->rollBack();
- continue;
- }
- $values_arr = [];
- foreach ($logs as $key => $log) {
- if($log['is_frozen']) $is_frozen = true;
- $info = [
- $log['mall_id'],
- $log['user_id'],
- $log['money'] >= 0 ? CapitalLog::CHANGE_TYPE_ADD : CapitalLog::CHANGE_TYPE_SUB,
- abs($log['money']),
- $current_num,
- $log['desc'],
- $log['source_table'],
- $log['source_table_id'],
- $log['from_type'],
- $log['capital_type'],
- $time,
- $time,
- $log['order_no']??'',
- $log['contributor_name']??'',
- $log['contributor_money']??0,
- $log['contributor_id']??0,
- ];
- $is_frozen && $info[] = CapitalLog::STATUS_WAIT_SEND;
- if(isset($log['service_charge'])){
- $info[] = $log['service_charge'];
- }
- $values_arr[] = $info;
- $current_num = $current_num + $log['money'];
- }
- $fields = ['mall_id', 'user_id', 'change_type', 'change_num', 'current_num', 'desc', 'source_table', 'source_table_id','from_type', 'capital_type','created_at', 'updated_at','order_no','contributor_name','contributor_money','contributor_id'];
- if ($is_frozen) {
- //操作冻结资金
- CapitalLog::$capitalType = str_replace('frozen_', '', $wallet_type) . '_frozen';
- $fields[] = 'status';
- } else {
- CapitalLog::$capitalType = $wallet_type;
- }
- if(isset($log['service_charge'])){
- $fields[] = 'service_charge';
- }
- Yii::$app->db->createCommand()->batchInsert(
- CapitalLog::tableName(),
- $fields,
- $values_arr
- )->execute();
- if(UserFreezeCommission::setLogData($user_id, $logs) === false) {
- $error[] = ['user_id' => $user_id, 'wallet_type' => $wallet_type, 'logs' => $logs, 'error_msg' => 'from qimall_user_freeze_commission err: '.UserFreezeCommission::getStaticError()];
- }
- // 重新编写用户金额管理
- $user_wallet_list[] = ['user_id' => $user_id, 'wallet_type' => $wallet_type, 'logs' => $logs];
- $trans->commit();
- }
- LockHelper::uLock($lock_key, $identification);
- }
- // 操作积分-余额-佣金 日志
- foreach ($capital_log_list as $item){
- $log_value = ['time' => $time, 'capitalType' => $item];
- \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, $log_value, CapitalLogRelation::class, 'addLog');
- }
- $event = new UserWalletEvent($mall_id);
- \Yii::$app->services->events->dispatch($event, ['mall_id' => $mall_id, 'user_wallet_list' => $user_wallet_list], $event->listeners);
- if ($error) {
- //记录错误信息
- foreach ($error as $err) {
- $log = new CapitalErrorLog();
- $log->attributes = $err;
- $log->save();
- }
- }
- return true;
- }
- /**
- * 批量操作用户钱包 强一致性【在一个事务内完成 所有操作】
- * @param int $task_id mq消费message_id
- * @param array $data
- * [
- * ['mall_id' => $mall_id,'user_id'=>1,'is_frozen'=>true,'not_add_total'=>true,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type','order_no'=>$order_no,'contributor_name'=>$contributor_name,'contributor_id'=>$contributor_id,'contributor_money'=>$contributor_money],
- * ['mall_id' => $mall_id,'user_id'=>2,'is_frozen'=>false,'not_add_total'=>false,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type','order_no'=>$order_no,'contributor_name'=>$contributor_name,'contributor_id'=>$contributor_id,'contributor_money'=>$contributor_money],
- *
- * ]
- * @throws
- * @return bool
- *
- */
- public static function batchHandleByTransaction($data)
- {
- $trans = Yii::$app->db->beginTransaction();
- try{
- $task_id = 0;
- if(!empty($data['message_id'])){
- $task_id = $data['message_id'];
- unset($data['message_id']);
- }
- Yii::error(__CLASS__ . ' batchHandleByTransaction task_id : ,task_id:' . $task_id);
- $user_handles = [];
- $capital_log_list = [];// 提交数据记录类型
- foreach ($data as $val) {
- $wallet_type = empty($val['is_frozen']) ? $val['wallet_type'] : 'frozen_'.$val['wallet_type'];
- $capital_log_type = empty($val['is_frozen']) ? $val['wallet_type'] : $val['wallet_type'] . '_frozen';
- if (!in_array($capital_log_type, $capital_log_list)) {
- $capital_log_list[] = $capital_log_type;
- }
- $user_handles[$val['user_id']][$wallet_type][] = $val;
- }
- // 因为所有传来列表mall_id相同 所以拿取第一个数组的mall_id赋值
- $mall_id = $data[0]['mall_id'];
- $user_wallet_list = [];
- $time = time();
- foreach ($user_handles as $user_id => $handle) {
- $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_USER_WALLET , $user_id);
- $identification = uniqid();
- if (!LockHelper::lock($lock_key, $identification, 100, 100)) {
- throw new Exception(__CLASS__ . ' batchHandle error : 抢不到锁,task_id:' . $task_id);
- }
- $user_wallet_model = UserWallet::findOne(['user_id' => $user_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]);
- if (empty($user_wallet_model)) {
- LockHelper::uLock($lock_key, $identification);
- throw new Exception("{$user_id}用户钱包不存在");
- }
- foreach ($handle as $wallet_type => $logs) {
- $is_frozen = false;
- if (strpos($wallet_type, 'frozen') !== false) {
- $is_frozen = true;
- }
- //求和
- $money = array_sum(array_column($logs, 'money'));
- if (!is_numeric($money) || empty($money)) {
- continue;
- }
- $current_num = $user_wallet_model->$wallet_type;
- /*因为新需求可以导入负数所以注释此段代码
- if ($current_num + $money < 0) {
- LockHelper::uLock($lock_key, $identification);
- throw new Exception("{$user_id}用户".self::getWalletTypeMsg($wallet_type)."不足");
- //$error[] = ['user_id' => $user_id, 'type' => $wallet_type, 'params' => json_encode($logs), 'error_msg' => '用户' . self::getWalletTypeMsg($wallet_type) . '不足'];
- }*/
- foreach ($logs as $key => $log) {
- //操作非冻结资金
- $wallet_type = $log['wallet_type'];
- $frozen_field = 'frozen_'.$wallet_type;
- $total_field = 'total_' . $wallet_type;
- $total_use_field = 'total_use_' . $wallet_type;
- if ($log['is_frozen']) {
- $user_wallet_model->$frozen_field += $log['money'];//冻结
- }else{
- $user_wallet_model->$wallet_type += $log['money'];//非冻结
- }
- if ($log['is_frozen']==false&&empty($log['not_add_total'])) {
- $log['money'] > 0 && $user_wallet_model->$total_field += $log['money'];//总数
- }
- if ($log['capital_type'] != UserWalletEnum::WITHDRAWAL_DECR) {
- $log['is_frozen'] == false && $log['money'] < 0 && $user_wallet_model->$total_use_field += abs($log['money']);//已使用
- }
- }
- if (!$user_wallet_model->save()) {
- LockHelper::uLock($lock_key, $identification);
- throw new Exception("{$user_id}用户".self::getWalletTypeMsg($wallet_type)." error".$user_wallet_model->getErrorMessage());
- }
- $values_arr = [];
- foreach ($logs as $key => $log) {
- if($log['is_frozen']) $is_frozen = true;
- $info = [
- $log['mall_id'],
- $log['user_id'],
- $log['money'] >= 0 ? CapitalLog::CHANGE_TYPE_ADD : CapitalLog::CHANGE_TYPE_SUB,
- abs($log['money']),
- $current_num,
- $log['desc'],
- $log['source_table'],
- $log['source_table_id'],
- $log['from_type'],
- $log['capital_type'],
- $time,
- $time,
- $log['order_no']??'',
- $log['contributor_name']??'',
- $log['contributor_money']??0,
- $log['contributor_id']??0,
- ];
- $is_frozen && $info[] = CapitalLog::STATUS_WAIT_SEND;
- if(isset($log['service_charge'])){
- $info[] = $log['service_charge'];
- }
- $values_arr[] = $info;
- $current_num = $current_num + $log['money'];
- }
- $fields = ['mall_id', 'user_id', 'change_type', 'change_num', 'current_num', 'desc', 'source_table', 'source_table_id','from_type', 'capital_type','created_at', 'updated_at','order_no','contributor_name','contributor_money','contributor_id'];
- if ($is_frozen) {
- //操作冻结资金
- CapitalLog::$capitalType = str_replace('frozen_', '', $wallet_type) . '_frozen';
- $fields[] = 'status';
- } else {
- CapitalLog::$capitalType = $wallet_type;
- }
- if(isset($log['service_charge'])){
- $fields[] = 'service_charge';
- }
- Yii::$app->db->createCommand()->batchInsert(
- CapitalLog::tableName(),
- $fields,
- $values_arr
- )->execute();
- if(UserFreezeCommission::setLogData($user_id, $logs) === false) {
- \Yii::error(__METHOD__.' from qimall_user_freeze_commission err: '.UserFreezeCommission::getStaticError());
- }
- $user_wallet_list[] = ['user_id' => $user_id, 'wallet_type' => $wallet_type, 'logs' => $logs];
- }
- LockHelper::uLock($lock_key, $identification);
- }
- $trans->commit();
- // 操作积分-余额-佣金 日志
- foreach ($capital_log_list as $item){
- $log_value = ['time' => $time, 'capitalType' => $item];
- \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, $log_value, CapitalLogRelation::class, 'addLog');
- }
- // 修改事务请求
- $event = new UserWalletEvent($mall_id);
- \Yii::$app->services->events->dispatch($event, ['mall_id'=>$mall_id, 'user_wallet_list' => $user_wallet_list], $event->listeners);
- }catch(Exception $e){
- $trans->rollBack();
- Yii::error(__CLASS__ . ' batchHandleByTransaction exception : ' . $e->getMessage() . ',task_id:' . $task_id);
- self::$static_error = $e->getMessage();
- return ;
- }
- return true;
- }
- /**
- * 直接操作用户钱包
- *
- * @param int $task_id
- * @param array $data
- * ['mall_id' => $mall_id,'user_id'=>1,'is_frozen'=>true,'not_add_total'=>true,'wallet_type'=>'balance','money'=>1,'desc'=> '操作描述','source_table' => $source,'source_table_id' => $source_id,'from_type'=>$from_type','capital_type'=>$capital_type','order_no'=>$order_no,'contributor_name'=>$contributor_name,'contributor_id'=>$contributor_id,'contributor_money'=>$contributor_money],
- * @param boolean $is_trans 是否启用事务
- * @return bool
- */
- public static function handle($task_id, $data, bool $is_trans = true)
- {
- $task_id = 0;
- if(!empty($data['message_id'])){
- $task_id = $data['message_id'];
- unset($data['message_id']);
- }
- $user_id = $data['user_id'];
- $wallet_type = $data['wallet_type'];
- $is_frozen = $data['is_frozen'] ?? false; //是否操作冻结资金
- $unfrozen = $data['unfrozen'] ?? false; //是否操作解冻资金
- $capital_types = self::getWalletType();
- if (!in_array($wallet_type, $capital_types)) {
- self::$static_error = '操作类型有误';
- return false;
- }
- //lock
- $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_USER_WALLET , $user_id);
- $identification = uniqid();
- if (LockHelper::lock($lock_key, $identification, 100, 100)) {
- $is_trans && $t = \Yii::$app->db->beginTransaction();
- try {
- $edit_field = empty($is_frozen) ? $wallet_type : 'frozen_' . $wallet_type;
- $edit_use_field = 'total_use_' . $wallet_type;
- //修改用户钱包表
- $user_wallet_model = UserWallet::findOne(['user_id' => $user_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]);
- if (empty($user_wallet_model)) throw new Exception('服务不存在或已删除');
- $current_num = $user_wallet_model->$edit_field;
- if ($data['money'] < 0 && bcadd($current_num, $data['money'],2) < 0) {
- throw new Exception('用户' . self::getWalletTypeMsg($edit_field) . '不足');
- }
- $frozen_field = 'frozen_' . $edit_field;
- if($unfrozen && abs($user_wallet_model->$frozen_field) < $data['money']){
- throw new Exception('用户' . self::getWalletTypeMsg($frozen_field) . '不足');
- }
- $user_wallet_model->$edit_field += $data['money'];
- if ($data['capital_type'] != UserWalletEnum::WITHDRAWAL_DECR) {
- empty($is_frozen) && $data['money'] < 0 && $user_wallet_model->$edit_use_field += abs($data['money']);
- }
- if (strpos($edit_field, 'frozen') === false && $data['money'] > 0) {
- $total_field = 'total_' . $edit_field;
- if (empty($data['no_change_field']) || !in_array($total_field, $data['no_change_field'])){
- $user_wallet_model->$total_field += $data['money'];
- }
- if($unfrozen){
- $frozen_field = 'frozen_' . $edit_field;
- $user_wallet_model->$frozen_field -= $data['money'];
- }
- }
- if (!$user_wallet_model->save()) throw new Exception($user_wallet_model->getErrorMessage());
- $setData = [
- 'mall_id' => $data['mall_id'],
- 'user_id' => $data['user_id'],
- 'change_type' => $data['money'] >= 0 ? CapitalLog::CHANGE_TYPE_ADD : CapitalLog::CHANGE_TYPE_SUB,
- 'change_num' => abs($data['money']),
- 'current_num' => $current_num,
- 'desc' => $data['desc'] ?? '',
- 'source_table' => $data['source_table'] ?? '',
- 'source_table_id' => $data['source_table_id'] ?? 0,
- 'from_type' => $data['from_type'] ?? '',
- 'capital_type' => $data['capital_type'] ?? '',
- 'order_no' => $data['order_no'] ?? '',
- 'contributor_name' => $data['contributor_name'] ?? '',
- 'contributor_id' => $data['contributor_id'] ?? 0,
- 'contributor_money' => $data['contributor_money'] ?? 0,
- ];
- if(isset($data['change_type'])) {
- $setData['change_type'] = $data['change_type'];
- }
- if ($is_frozen) {
- //操作冻结资金
- CapitalLog::$capitalType = $wallet_type . '_frozen';
- $setData['status'] = CapitalLog::STATUS_WAIT_SEND;
- } else {
- CapitalLog::$capitalType = $wallet_type;
- }
- $is_send_message = false;
- if ($is_frozen && $data['money'] < 0 && !$unfrozen) {
- //取消冻结资金 不添加记录 add by zmz
- }else{
- $is_send_message = true;
- $log_res = CapitalLog::setData($setData);
- if (!$log_res) {
- throw new Exception(CapitalLog::getStaticError());
- }
- if(isset($data['service_charge'])){
- $log_res->service_charge = $data['service_charge'];
- $log_res->save();
- }
- }
- if(UserFreezeCommission::setLogData($user_id, [$data]) === false) {
- \Yii::error(__METHOD__.' from qimall_user_freeze_commission err: '.UserFreezeCommission::getStaticError());
- }
- $is_trans && $t->commit();
- //佣金到账微信公众号消息通知
- if (CapitalLog::$capitalType == 'commission' && $data['money'] >= 0) {
- $obj = new WechatMessageLogic();
- $obj->OrderCommissionSettle(['mall_id' => $data['mall_id'], 'user_id' => $data['user_id'], 'money' => abs($data['money'])]);
- }
- //unlock
- LockHelper::uLock($lock_key, $identification);
- $task_id && self::setHandleResult($task_id, true);
- if($is_send_message||!$is_frozen){
- $send_message_data = [
- 'user_id'=>$user_id,
- 'money'=>$data['money'],
- 'wallet_type'=>$wallet_type,
- 'mall_id' => $data['mall_id'],
- 'change_type'=>$setData['change_type'],
- ];
- \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, $send_message_data, WechatMessageLogic::class, 'receiptSendMessage');
- }
- return true;
- } catch (Exception $e) {
- Yii::error(__CLASS__ . ' handle exception : ' . $e->getMessage() . ',task_id:' . $task_id);
- $is_trans && $t->rollBack();
- LockHelper::uLock($lock_key, $identification);
- self::$static_error = $e->getMessage();
- return false;
- }
- } else {
- //抢不到锁
- Yii::error(__CLASS__ . ' handle error : 抢不到锁,task_id:' . $task_id);
- self::$static_error = '操作太频繁';
- return false;
- }
- }
- /**
- * 获取处理结果
- * @param $task_id
- * @return array|bool|null|string
- * @throws \yii\db\Exception
- */
- public static function getHandleResult($task_id)
- {
- $result_key = RabbitMqEnum::USER_WALLET_RESUALT_KEY_PREFIX . $task_id;
- $redis = \Yii::$app->redis;
- return $redis->executeCommand('GET', [$result_key]);
- }
- /**
- * 获取处理结果
- * @param $task_id
- * @param $result
- * @return array|bool|null|string
- * @throws \yii\db\Exception
- */
- public static function setHandleResult($task_id, $result)
- {
- $result_key = RabbitMqEnum::USER_WALLET_RESUALT_KEY_PREFIX . $task_id;
- $redis = \Yii::$app->redis;
- return $redis->executeCommand('SET', [$result_key, $result, 'EX', 86400]);
- }
- /**
- * 解冻资金:将冻结金额 转换成 正常金额
- * @param $log_id
- * @param $wallet_type
- * @param bool $is_send 是否发放
- * @return bool
- */
- public static function unfrozen($log_id, $wallet_type, $is_send = true)
- {
- try {
- $capital_types = self::getWalletType();
- if (!in_array($wallet_type, $capital_types)) {
- throw new Exception('操作类型有误');
- }
- CapitalLog::$capitalType = $wallet_type . '_frozen';
- $log = CapitalLog::findOne(['id' => $log_id, 'status' => CapitalLog::STATUS_WAIT_SEND]);
- if (empty($log)) {
- throw new Exception('操作记录不存在');
- }
- if ($is_send) {
- $log_arr = $log->toArray();
- $log_arr['wallet_type'] = $wallet_type;
- $log_arr['is_frozen'] = false;
- if ($log['change_type'] == 'sub') {
- $log_arr['money'] = bcmul($log_arr['change_num'], -1, 2);
- } else {
- $log_arr['money'] = $log_arr['change_num'];
- }
- $log_arr['unfrozen'] = true;
- $res = self::handle(0, $log_arr);
- if (!$res) {
- throw new Exception(self::$static_error);
- }
- $status = CapitalLog::STATUS_SEND;
- } else {
- $log_arr = $log->toArray();
- $log_arr['wallet_type'] = $wallet_type;
- $log_arr['is_frozen'] = true; //操作冻结
- $log_arr['money'] = $log_arr['change_num'] * -1;
- $log_arr['unfrozen'] = false; //非解冻
- $res = self::handle(0, $log_arr);
- $status = CapitalLog::STATUS_FAIL;
- }
- //修改记录状态
- CapitalLog::$capitalType = $wallet_type . '_frozen';
- if(!CapitalLog::updateAll(['status' =>$status ],['id' => $log_id])){
- throw new Exception($log->getErrorMessage());
- }
- return true;
- } catch (Exception $e) {
- Yii::error(__CLASS__ . ' unfrozen exception : ' . $e->getMessage());
- self::$static_error = $e->getMessage();
- return false;
- }
- }
- //获取用户上一次填写的提现信息
- public function getPrevInfo($mall_id, $user_id, $params)
- {
- try {
- $where = [
- ['mall_id' => $mall_id],
- ['user_id' => $user_id],
- ['from' => $params['from']],
- ['type' => $params['type']],
- ];
- if (!empty($params['source'])) $where[] = ['source' => $params['source']];
- // print_r($where);exit;
- $info = UserWithdrawLog::getOne($where, true, [], 'id desc');
- if (empty($info)) return [];
- $info['extra'] = json_decode($info['extra'], true);
- if (empty($info['extra']['bank_account_type'])) $info['extra']['bank_account_type'] = 1;
- return $info['extra'];
- } catch (\Exception $e) {
- throw new Exception($e->getMessage());
- }
- }
- }
|