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; } }