| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- <?php
- namespace addons\HiGo\common\logic;
- use addons\HiGo\common\enums\HiGoEnum;
- use addons\HiGo\common\models\HigoHibeiLog;
- use addons\HiGo\common\models\HigoMall;
- use addons\HiGo\common\models\HigoWallet;
- use addons\HiGo\common\models\HigoWalletFreezeLog;
- use addons\HiGo\common\models\HigoWalletFrozenLog;
- use addons\HiGo\common\models\HigoWalletLog;
- use common\enums\RabbitMqEnum;
- use common\enums\RedisKeyEnum;
- use common\enums\StatusEnum;
- use common\helpers\LockHelper;
- use common\helpers\TaskHelper;
- use common\models\common\CapitalLog;
- use common\traits\ErrorTrait;
- use Exception;
- use Yii;
- /**
- * Class HiZhiLogic
- * 嗨值/嗨呗钱包逻辑类
- * @Author: mz
- * @DateTime: 2022/11/08 16:39
- * @Copyright: copyright (c) 2022 广东七件事集团
- */
- class WalletLogic
- {
- use ErrorTrait;
- /**
- * 获取资金类型
- * @return array
- */
- public static function getWalletType()
- {
- return [
- HiGoEnum::WALLET_TYPE_HI_VALUE,
- HiGoEnum::WALLET_TYPE_HI_BEI,
- ];
- }
- /**
- * 获取资金类型描述
- * @param $type
- * @return mixed|string
- */
- public static function getWalletTypeMsg($mall_id, $type)
- {
- $arr = HiGoEnum::getHigoWalletText($mall_id);
- return $arr[$type] ?? '';
- }
- /**
- * 直接操作用户钱包
- * @param $task_id
- * @param $data
- *
- * @return bool
- */
- public static function handle($data, $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'];
- $mall_id = $data['mall_id'];
- $is_send = $data['is_send'] ?? 1; //是否属于发放
- $is_freeze = $data['is_freeze'] ?? false; //是否操作冻结资金
- $from_normal_to_freeze = $data['from_normal_to_freeze'] ?? false; //从正常账户 移动到冻结账户
- $unfreeze = $data['unfreeze'] ?? false; //是否操作解冻资金
- $freeze_log_id = $data['freeze_log_id'] ?? 0; //操作解冻资金的记录ID
- $capital_types = self::getWalletType();
- if (!in_array($wallet_type, $capital_types)) {
- self::$static_error = '操作类型有误';
- return false;
- }
- if(bccomp($data['change_num'],0,10) == 0){
- self::$static_error = '操作金额为0';
- return false;
- }
- //lock
- $lock_key = RedisKeyEnum::suffix(HiGoEnum::LOCK_HIGO_USER_WALLET, $user_id);
- $identification = uniqid();
- if (LockHelper::lock($lock_key, $identification, 100, 100)) {
- $t = \Yii::$app->db->beginTransaction();
- try {
- $edit_field = empty($is_freeze) ? $wallet_type : 'freeze_' . $wallet_type;
- //$edit_field = $wallet_type;
- //修改用户钱包表
- $user_wallet_model = HigoWallet::findOne(['mall_id' => $mall_id, 'user_id' => $user_id]);
- if (empty($user_wallet_model)) {
- $user_wallet_model = HigoWallet::setData([
- 'user_id' => $user_id,
- 'mall_id' => $mall_id,
- 'status' => StatusEnum::ENABLED
- ]);
- }
- $current_num = $user_wallet_model->$edit_field;
- $after_num = bcadd($current_num, $data['change_num'], 10);
- if (bccomp($after_num, 0, 10) < 0) {
- throw new Exception('用户' . self::getWalletTypeMsg($mall_id, $edit_field) . '不足');
- }
- //操作解冻,且资金是非冻结
- if (strpos($edit_field, 'freeze') === false && $data['change_num'] > 0 && $unfreeze) {
- $freeze_field = 'freeze_' . $edit_field;
- if(bccomp($user_wallet_model->$freeze_field, $data['change_num'], 10) < 0){
- throw new Exception('用户冻结' . self::getWalletTypeMsg($mall_id, $edit_field) . '不足');
- }
- $user_wallet_model->$freeze_field = bcsub($user_wallet_model->$freeze_field,$data['change_num'],10);
- //TODO $freeze_log_id
- if($freeze_log_id){
- HigoWalletFreezeLog::updateAll(['status' => CapitalLog::STATUS_SEND],['id' => $freeze_log_id]);
- }
- }
- $user_wallet_model->$edit_field = $after_num;
- if($from_normal_to_freeze && $is_freeze && $data['change_num'] > 0){
- //操作冻结账户,1、正常账户,减少对应金额,2、往冻结账户添加金额
- $freeze_edit_num = bcmul($data['change_num'],-1,10);
- $user_wallet_model->$wallet_type = bcadd($user_wallet_model->$wallet_type, $freeze_edit_num, 10);
- }
- if (!$user_wallet_model->save()) throw new Exception($user_wallet_model->getErrorMessage());
- $setData = [
- 'mall_id' => $mall_id,
- 'user_id' => $user_id,
- 'change_type' => $data['change_num'] > 0 ? CapitalLog::CHANGE_TYPE_ADD : CapitalLog::CHANGE_TYPE_SUB,
- 'change_num' => abs($data['change_num']),
- 'after_num' => $after_num,
- 'desc' => $data['desc'] ?? '',
- 'source_table' => $data['source_table'] ?? '',
- 'source_table_id' => $data['source_table_id'] ?? 0,
- 'from_type' => $data['from_type'] ?? '',
- 'wallet_type' => $data['wallet_type'],
- 'addon_name' => $data['addon_name'] ?? HiGoEnum::ADDONS_NAME
- ];
- if($is_freeze){
- $log_res = HigoWalletFreezeLog::setData($setData);
- }else{
- $log_res = HigoWalletLog::setData($setData);
- }
- if (!$log_res) {
- throw new Exception(CapitalLog::getStaticError());
- }
- $log_res_id = $log_res->id;
- //处理商城嗨呗表
- $higo_mall_model = HigoMall::findOne(['mall_id' => $mall_id]);
- if (empty($higo_mall_model)) {
- $higo_mall_model = HigoMall::setData([
- 'mall_id' => $mall_id,
- 'status' => StatusEnum::ENABLED
- ]);
- }
- if($wallet_type == HiGoEnum::WALLET_TYPE_HI_BEI){
- //操作嗨呗
- if($is_send){
- $higo_mall_model->$wallet_type = bcadd($higo_mall_model->$wallet_type, $data['change_num'], 10);
- //添加嗨呗记录
- HigoHibeiLog::setData(['mall_id' => $mall_id,'change_type' => CapitalLog::CHANGE_TYPE_ADD,'change_num'=>$data['change_num'],'from_type' => $data['from_type'],'desc' => $data['desc'],'setting' => $data['setting'] ?? 0]);
- }
- $higo_mall_model->available_hi_bei = bcadd($higo_mall_model->available_hi_bei, $data['change_num'], 10);
- }else{
- $higo_mall_model->$wallet_type = bcadd($higo_mall_model->$wallet_type, $data['change_num'], 10);
- }
- if (!$higo_mall_model->save()) throw new Exception($higo_mall_model->getErrorMessage());
- $t->commit();
- //unlock
- LockHelper::uLock($lock_key, $identification);
- $task_id && self::setHandleResult($task_id, $log_res_id);
- return true;
- } catch (Exception $e) {
- Yii::error(__CLASS__ . ' handle exception : ' . $e->getMessage() . ',task_id:' . $task_id);
- $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 = HiGoEnum::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 = HiGoEnum::USER_WALLET_RESUALT_KEY_PREFIX . $task_id;
- $redis = \Yii::$app->redis;
- return $redis->executeCommand('SET', [$result_key, $result, 'EX', 86400]);
- }
- /**
- * 异步队列操作用户钱包
- * @param array $data
- * @param bool $wait_result 是否阻塞,等待结果
- * @throws
- * @return bool
- */
- public static function handleInQueue($data, $wait_result = true)
- {
- if (!in_array($data['wallet_type'], self::getWalletType())) {
- throw new Exception('操作类型不合法');
- }
- // $res = self::handle($data,123);
- // $result = self::getHandleResult(123);
- // return $result;
- $task_id = TaskHelper::pushTaskQueue(
- RabbitMqEnum::EXCHANGE_TASK_USER_WALLET,
- RabbitMqEnum::USER_WALLET_QUEUE,
- $data,
- __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;
- }
- /**
- * 处理 未处理记录
- * @return void
- * @throws
- */
- public static function unfrozen($frozen_log)
- {
- if($frozen_log['status'] != CapitalLog::STATUS_WAIT_SEND) return ;
- $res = self::handleInQueue($frozen_log);
- if($res){
- HigoWalletFrozenLog::updateAll(['status' => CapitalLog::STATUS_SEND],['id' => $frozen_log['id']]);
- }
- return true;
- }
- /**
- * 删除未处理记录
- * @param $frozen_log
- * @return void
- */
- public static function delfrozen($frozen_log)
- {
- if($frozen_log['status'] != CapitalLog::STATUS_WAIT_SEND) return ;
- HigoWalletFrozenLog::updateAll(['status' => CapitalLog::STATUS_FAIL],['id' => $frozen_log['id']]);
- return true;
- }
- }
|