Class: UserLoyalty
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- UserLoyalty
- Defined in:
- app/models/user_loyalty.rb
Overview
Schema Information
Table name: user_loyalties
id :bigint not null, primary key
ab_testing_group :string(191)
progress_total_reservations :integer default(0)
progress_total_spending_cents :integer default(0), not null
progress_total_spending_currency :string(191) default("THB"), not null
start_date_level :datetime
state :string(191)
total_reservations :integer default(0)
total_spending_cents :bigint default(0), not null
total_spending_currency :string(191) default("THB"), not null
created_at :datetime not null
updated_at :datetime not null
last_loyalty_level_id :bigint
loyalty_level_id :bigint
session_id :string(191)
top_loyalty_level_id :bigint
user_id :bigint
Indexes
index_user_loyalties_on_last_loyalty_level_id (last_loyalty_level_id)
index_user_loyalties_on_loyalty_level_id (loyalty_level_id)
index_user_loyalties_on_top_loyalty_level_id (top_loyalty_level_id)
index_user_loyalties_on_updated_at (updated_at)
index_user_loyalties_on_user_id (user_id)
Constant Summary collapse
- LOYALTY_SCORE =
{ hunger: 1, silver: 2, gold: 3, platinum: 4, }.freeze
- TIER_IMAGES =
{ hunger: 'red-tier.png', silver: 'silver-tier.png', gold: 'gold-tier.png', platinum: 'platinum-tier.png', }.freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#already_downgraded_today? ⇒ Boolean
no need to downgrade again if user already downgraded when their points expired because when user points expired, points will be 0 and user level will be downgraded.
-
#benefit_value(key, cast: :to_f) ⇒ Numeric
Returns the value of a specific benefit for the user's loyalty level.
-
#dine_in_point_key_by_country(country) ⇒ String
Returns the dine-in point key name based on the given country.
- #expired_date_level ⇒ Object
- #init_loyalty_level ⇒ Object
- #next_tier ⇒ Object
- #no_booking_in_current_level? ⇒ Boolean
- #number_booking_to_next_tier ⇒ Object
- #qualified_to_downgrade_now? ⇒ Boolean
- #qualified_to_upgrade?(next_tier = nil) ⇒ Boolean
- #renew_session_id ⇒ Object
- #total_data_reservations ⇒ Object
- #total_data_spending ⇒ Object
- #total_spend_to_next_tier ⇒ Object
- #trigger_reservation_summary_sync_on_loyalty_change ⇒ Object
Methods inherited from ApplicationRecord
Class Method Details
.update_data_user(user_ids, from_month) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'app/models/user_loyalty.rb', line 179 def self.update_data_user(user_ids, from_month) return if user_ids.blank? User.includes(:reservations).where(id: user_ids).find_each do |user| total_reservation = user.reservations.reached_goal_scope.where('created_at >= ?', from_month.beginning_of_month) user_loyalty = user.user_loyalty user_loyalty.total_spending = 0 user_loyalty.total_reservations = 0 user_loyalty.progress_total_spending = total_reservation.sum(&:charge_price) user_loyalty.progress_total_reservations = total_reservation.count user_loyalty.state = :hunger user_loyalty.save current_level = :hunger (LoyaltyLevel::AVAILABLE_LEVELS.keys.reverse! - [:hunger]).each do |attr| qualification = LoyaltyProgram::Qualification.new(user_loyalty) next unless qualification.qualified_to_upgrade?(attr) user_loyalty.last_loyalty_level = user_loyalty.loyalty_level user_loyalty.top_loyalty_level = LoyaltyLevel.send(attr) user_loyalty.loyalty_level = LoyaltyLevel.send(attr) user_loyalty.state = attr # update data and reset progress data user_loyalty.start_date_level = Time.now_in_tz(user_loyalty.user.time_zone) user_loyalty.total_spending = user_loyalty.total_data_spending user_loyalty.total_reservations = user_loyalty.total_data_reservations.to_i user_loyalty.progress_total_spending = 0 user_loyalty.progress_total_reservations = 0 user_loyalty.save! current_level = attr break end if current_level == :hunger user_loyalty.last_loyalty_level = LoyaltyLevel.hunger user_loyalty.top_loyalty_level = LoyaltyLevel.hunger user_loyalty.loyalty_level = LoyaltyLevel.hunger user_loyalty.save end end end |
Instance Method Details
#already_downgraded_today? ⇒ Boolean
no need to downgrade again if user already downgraded when their points expired because when user points expired, points will be 0 and user level will be downgraded
121 122 123 124 125 126 127 128 129 |
# File 'app/models/user_loyalty.rb', line 121 def already_downgraded_today? last_reward = user.rewards.order(created_at: :desc).first return false unless last_reward same_day = last_reward.created_at.to_date == updated_at.to_date is_points_expiry_downgrade = last_reward.description.include?('Inactive account points expiry') same_day && is_points_expiry_downgrade end |
#benefit_value(key, cast: :to_f) ⇒ Numeric
Returns the value of a specific benefit for the user's loyalty level.
267 268 269 270 |
# File 'app/models/user_loyalty.rb', line 267 def benefit_value(key, cast: :to_f) value = loyalty_level&.benefits&.public_send(key) value.respond_to?(cast) ? value.public_send(cast) : 0.public_send(cast) end |
#dine_in_point_key_by_country(country) ⇒ String
251 252 253 254 255 256 |
# File 'app/models/user_loyalty.rb', line 251 def dine_in_point_key_by_country(country) return 'dine_in_point_sg' if country&.alpha3 == ApiV5::Constants::COUNTRY_CODE_SG return 'dine_in_point_my' if country&.alpha3 == ApiV5::Constants::COUNTRY_CODE_MY 'dine_in_point_th' end |
#expired_date_level ⇒ Object
143 144 145 146 147 |
# File 'app/models/user_loyalty.rb', line 143 def expired_date_level # same logic with points expiry date # to avoid duplicate logic, we use the same method Reward.points_expiry_date(user) end |
#init_loyalty_level ⇒ Object
92 93 94 95 96 97 98 99 100 |
# File 'app/models/user_loyalty.rb', line 92 def init_loyalty_level time_zone = user&.time_zone || Time::THAILAND_ZONE self.loyalty_level = LoyaltyLevel.hunger self.last_loyalty_level = LoyaltyLevel.hunger self.top_loyalty_level = LoyaltyLevel.hunger self.start_date_level = Time.now_in_tz(time_zone).beginning_of_day self.ab_testing_group = user&.id.to_i % 2 == 0 ? 'B' : 'A' end |
#next_tier ⇒ Object
169 170 171 172 173 174 175 |
# File 'app/models/user_loyalty.rb', line 169 def next_tier current_tier = state.to_sym current_rank = UserLoyalty::LOYALTY_SCORE[current_tier] next_rank = current_rank + 1 UserLoyalty::LOYALTY_SCORE.invert[next_rank] || UserLoyalty::LOYALTY_SCORE.invert[UserLoyalty::LOYALTY_SCORE.invert.keys.max] end |
#no_booking_in_current_level? ⇒ Boolean
131 132 133 |
# File 'app/models/user_loyalty.rb', line 131 def no_booking_in_current_level? user.reservations.reached_goal_scope.where(created_at: start_date_level..expired_date_level).blank? end |
#number_booking_to_next_tier ⇒ Object
153 154 155 156 157 158 159 |
# File 'app/models/user_loyalty.rb', line 153 def number_booking_to_next_tier return 0 if state?(:platinum) next_qualification = LoyaltyProgram::Template::TIER_QUALIFICATIONS[next_tier] next_total_reservations = next_qualification[:total_reservations] next_total_reservations - total_data_reservations end |
#qualified_to_downgrade_now? ⇒ Boolean
107 108 109 110 111 112 113 114 115 116 117 |
# File 'app/models/user_loyalty.rb', line 107 def qualified_to_downgrade_now? # return false because there is no lower level after hunger return false if state?(:hunger) return false if already_downgraded_today? today = Time.now_in_tz(user.time_zone) return false unless expired_date_level && expired_date_level.to_date == today.to_date no_booking_in_current_level? end |
#qualified_to_upgrade?(next_tier = nil) ⇒ Boolean
102 103 104 105 |
# File 'app/models/user_loyalty.rb', line 102 def qualified_to_upgrade?(next_tier = nil) qualification = LoyaltyProgram::Qualification.new(self, next_tier) qualification.qualified_to_upgrade? end |
#renew_session_id ⇒ Object
149 150 151 |
# File 'app/models/user_loyalty.rb', line 149 def renew_session_id self.session_id = SecureRandom.hex(10) end |
#total_data_reservations ⇒ Object
135 136 137 |
# File 'app/models/user_loyalty.rb', line 135 def total_data_reservations total_reservations.to_i + progress_total_reservations.to_i end |
#total_data_spending ⇒ Object
139 140 141 |
# File 'app/models/user_loyalty.rb', line 139 def total_data_spending total_spending&.amount.to_i + progress_total_spending&.amount.to_i end |
#total_spend_to_next_tier ⇒ Object
161 162 163 164 165 166 167 |
# File 'app/models/user_loyalty.rb', line 161 def total_spend_to_next_tier return 0 if state?(:platinum) next_qualification = LoyaltyProgram::Template::TIER_QUALIFICATIONS[next_tier] next_total_spending = next_qualification[:total_spending] next_total_spending - total_data_spending end |
#trigger_reservation_summary_sync_on_loyalty_change ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'app/models/user_loyalty.rb', line 225 def trigger_reservation_summary_sync_on_loyalty_change # Only trigger if loyalty_level_id has changed (indicating a level change) return unless saved_change_to_loyalty_level_id? return unless defined?(PartnerService::LoyaltyChangeDetectorService) begin # Trigger batch sync for reservation summaries PartnerService::LoyaltyChangeDetectorService.new(self).execute rescue StandardError => e Rails.logger.error "[UserLoyalty] Error triggering reservation summary sync for user #{user_id}: #{e.}" Rails.logger.error e.backtrace.first(3).join("\n") end end |