'ID', 'mall_id' => 'Mall ID', 'user_id' => 'User ID', 'digital' => 'Digital', 'frozen_digital' => 'Frozen Digital', 'status' => 'Status', 'created_at' => 'Created At', 'updated_at' => 'Updated At', ]; } private static function getKey($user_id) { return 'lock_user_digital_' . $user_id; } /** * 保存数据 * @param array $params * @return bool|UserExtra */ public static function setData(array $params) { try { if (!empty($params['user_id'])) { $model = self::findOne(['user_id' => $params['user_id']]); if (empty($model)) { $model = new self(); $model->loadDefaultValues(); } if (!$model->load($params, '') || !$model->save()) throw new Exception($model->getErrorMessage()); return $model; } } catch (Exception $e) { self::$static_error = $e->getMessage(); return false; } } /** * 操作用户账户 * @param $mall_id * @param $user_id * @param $change_num * @param bool $is_frozen * @param array $params * @return bool */ public static function handleUserDigital($mall_id, $user_id, $change_num, $is_frozen = false, $params = []) { if (bccomp($change_num, 0, 10) == 0) { self::$static_error = '操作金额为0'; return false; } //获取设置是否启用 $is_enable = MallSetting::conf($mall_id,'digital.is_enable'); if(!$is_enable) { self::$static_error = '数字币未启用'; return false; } $origin_change_num = $change_num; $lock_key = self::getKey($user_id); $identification = uniqid(); if (LockHelper::lock($lock_key, $identification, 100, 100)) { $t = \Yii::$app->db->beginTransaction(); try { $edit_field = $is_frozen ? 'frozen_digital' : 'digital'; $user_wallet_model = self::findOne(['mall_id' => $mall_id, 'user_id' => $user_id, 'status' => StatusEnum::ENABLED]); if (empty($user_wallet_model)) { $user_wallet_model = self::setData([ 'user_id' => $user_id, 'mall_id' => $mall_id, 'status' => StatusEnum::ENABLED ]); if (!$user_wallet_model) throw new Exception(self::getStaticError()); } //扣除对应的贡献值 $open_deduct_redpack = MallSetting::conf($mall_id,'digital.deduct_redpack'); $is_installed_devote = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_DEVOTE); $from_type = $params['from_type'] ?? ''; $is_addons = MallAddons::isInstall($mall_id, $from_type); $force_deduct_redpack = $params['force_deduct_redpack'] ?? false; if(($open_deduct_redpack || $force_deduct_redpack) && $is_installed_devote && $change_num > 0 && $is_addons){ $deduct_redpack_ratio = MallSetting::conf($mall_id,'digital.deduct_redpack_ratio'); $deduct_num = bcmul($deduct_redpack_ratio,$change_num,2); //发放数字币 需要扣除贡献值 $params['addons_name'] = $from_type; $real_deduct_num = DevoteFrozenLog::deduct_frozen($mall_id,$user_id,$deduct_num,$params); if(!$real_deduct_num) throw new Exception('扣除贡献值失败'); if($real_deduct_num != $deduct_num){ //实际该发放的数字币 $change_num = bcdiv($real_deduct_num,$deduct_redpack_ratio,2); } $desc = $params['desc'] ?? ''; if($origin_change_num != $change_num && $desc){ //用户(103939),获得订单(9224)分销商奖励,奖励类型:间推奖励,金额:279.80 $params['desc'] = str_replace(':'.$origin_change_num,':'.$change_num,$desc); } }else{ $is_installed_devote = empty($is_installed_devote) ? 'false' : 'true'; $is_addons = empty($is_addons) ? 'false' : 'true'; Yii::error(__CLASS__ . ' handleUserDigital notice : ' . $open_deduct_redpack.$is_installed_devote.$is_addons); } $current_num = $user_wallet_model->$edit_field; $after_num = bcadd($current_num, $change_num, 2); if (bccomp($after_num, 0, 10) < 0) { $msg = $is_frozen ? '冻结数字币' : '数字币'; throw new Exception('用户' . $msg . '不足'); } $user_wallet_model->$edit_field = $after_num; if (!$user_wallet_model->save()) throw new Exception($user_wallet_model->getErrorMessage()); $log = [ 'mall_id' => $mall_id, 'user_id' => $user_id, 'change_type' => $change_num > 0 ? CapitalLog::CHANGE_TYPE_ADD : CapitalLog::CHANGE_TYPE_SUB, 'change_num' => abs($change_num), 'current_num' => $current_num, 'desc' => $params['desc'] ?? '', 'source_table' => $params['source_table'] ?? '', 'source_table_id' => $params['source_table_id'] ?? 0, 'from_type' => $params['from_type'] ?? '', 'capital_type' => $params['capital_type'] ?? '', 'order_no' => $params['order_no'] ?? '', 'contributor_name' => $params['contributor_name'] ?? '', 'contributor_money' => $params['contributor_money'] ?? 0, 'contributor_id' => $params['contributor_id'] ?? 0, 'send_status' => $is_frozen ? DigitalLog::SEND_STATUS_FROZEN : DigitalLog::SEND_STATUS_NORMAL ]; if (DigitalLog::setData($log) === false) throw new Exception(DigitalLog::getStaticError()); $t->commit(); LockHelper::uLock($lock_key, $identification); return abs($change_num); } catch (Exception $e) { Yii::error(__CLASS__ . ' handleUserDigital exception : ' . $e->getMessage() . ',user_id:' . $user_id); self::$static_error = $e->getMessage(); $t->rollBack(); LockHelper::uLock($lock_key, $identification); return false; } } else { //抢不到锁 Yii::error(__CLASS__ . ' handleUserDigital error : 抢不到锁,user_id:' . $user_id); self::$static_error = '操作太频繁'; return false; } } /** * 操作冻结数字币 * @param $log_id * @param bool $is_send true-释放,false-取消 * @return */ public static function unfrozen($log_id, $is_send = true) { $t = \Yii::$app->db->beginTransaction(); try { $log = DigitalLog::findOne(['id' => $log_id, 'status' => StatusEnum::ENABLED,'send_status' =>DigitalLog::SEND_STATUS_FROZEN ]); if (empty($log)) { throw new Exception('操作记录不存在'); } $lock_key = self::getKey($log->user_id); $identification = uniqid(); if (LockHelper::lock($lock_key, $identification, 100, 100)) { $user_wallet_model = self::findOne(['mall_id' => $log->mall_id, 'user_id' => $log->user_id, 'status' => StatusEnum::ENABLED]); $current_num = $user_wallet_model->frozen_digital; $after_num = bcsub($current_num, $log->change_num, 2); if (bccomp($after_num, 0, 10) < 0) { throw new Exception('用户冻结数字币不足'); } $user_wallet_model->frozen_digital = $after_num; if ($is_send) { $log->send_status = DigitalLog::SEND_STATUS_NORMAL; $user_wallet_model->digital = bcadd($user_wallet_model->digital,$log->change_num,2); }else{ $log->send_status = DigitalLog::SEND_STATUS_INVALID; } if (!$user_wallet_model->save()) throw new Exception($user_wallet_model->getErrorMessage()); if (!$log->save()) throw new Exception($log->getErrorMessage()); } $t->commit(); LockHelper::uLock($lock_key, $identification); } catch (Exception $e) { $t->rollBack(); Yii::error(__CLASS__ . ' unfrozen exception : ' . $e->getMessage()); self::$static_error = $e->getMessage(); return false; } } }