Class: PartnerService::Dashboards::CalculateService
- Inherits:
-
ApplicationService
- Object
- ApplicationService
- PartnerService::Dashboards::CalculateService
- Includes:
- ElasticAPM::SpanHelpers
- Defined in:
- app/services/partner_service/dashboards/calculate_service.rb
Overview
Service class for calculating dashboard metrics for partner restaurants.
Provides methods to calculate various metrics including revenue, bookings, and other dashboard statistics with proper filtering and caching.
Instance Attribute Summary collapse
-
#restaurant_ids ⇒ Object
Returns the value of attribute restaurant_ids.
Attributes inherited from ApplicationService
Instance Method Summary collapse
-
#current_month_bookings_revenue ⇒ String
Returns revenue for the current month.
-
#current_restaurant_time ⇒ Time
Returns the current time in the first restaurant's timezone.
-
#identifiers(start_date, end_date) ⇒ Array<Hash>
Returns rating identifiers with scores for a date range.
-
#initialize(restaurants) ⇒ CalculateService
constructor
Initialize the service with a collection of restaurants.
-
#last_8_weeks_bookings_revenue ⇒ Array<Hash>
Returns revenue data for the last 8 weeks.
-
#last_month_bookings ⇒ Hash
Returns booking statistics for the previous month.
-
#last_month_bookings_revenue ⇒ String
Returns revenue for the previous month.
-
#package_best_revenue(start_date, end_date) ⇒ String?
Finds the package with the highest revenue for a given date range.
-
#package_summary ⇒ Hash
Returns package summary with online count and best seller.
-
#pending_bookings ⇒ Hash
Calculates pending bookings count and revenue.
-
#ratings ⇒ Hash
Returns rating statistics for the last 30 days.
-
#ratings_score(start_date, end_date) ⇒ Float
Calculates average rating score for a date range.
-
#reservations ⇒ ActiveRecord::Relation
Returns reservations for the configured restaurant IDs.
-
#revenue_bookings_with_filtering(start_date, end_date) ⇒ String
Calculates total revenue for bookings within a specified date range.
-
#revenue_by_date ⇒ Hash
Returns revenue comparison between current and previous month.
-
#revenue_with_filtering(reservations_collection) ⇒ String, Integer
Calculates total revenue for a given collection of reservations.
-
#reviews(start_date, end_date) ⇒ ActiveRecord::Relation
Returns reviews for a date range.
-
#seat_available_percent ⇒ Integer
Calculates seat availability percentage for the next 7 days.
-
#this_month_bookings ⇒ Hash
Returns booking statistics for the current month.
-
#today_bookings ⇒ Hash
Returns booking statistics for today.
-
#total_confirm_bookings(start_date, end_date) ⇒ Integer
Returns total confirmed bookings for a date range.
-
#total_covers_bookings(start_date, end_date) ⇒ Integer
Returns total covers for bookings in a date range.
-
#total_reviews(start_date, end_date) ⇒ Integer
Returns total count of reviews for a date range.
-
#two_months_before_bookings ⇒ Hash
Returns booking statistics for two months ago.
-
#two_months_before_bookings_revenue ⇒ String
Returns revenue for two months ago.
-
#upcoming_bookings ⇒ Hash
Calculates upcoming bookings for the next 7 days.
-
#voucher_sales ⇒ Hash
Calculates voucher sales for the current month.
Methods inherited from ApplicationService
Constructor Details
#initialize(restaurants) ⇒ CalculateService
Initialize the service with a collection of restaurants.
17 18 19 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 17 def initialize(restaurants) @restaurant_ids = Array(restaurants).map(&:id) end |
Instance Attribute Details
#restaurant_ids ⇒ Object
Returns the value of attribute restaurant_ids.
12 13 14 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 12 def restaurant_ids @restaurant_ids end |
Instance Method Details
#current_month_bookings_revenue ⇒ String
Returns revenue for the current month.
168 169 170 171 172 173 174 175 176 177 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 168 def current_month_bookings_revenue start_date = Date.current_date.beginning_of_month end_date = Date.current_date.end_of_month cache_key = "current_month_revenue:#{start_date}:#{end_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do revenue = revenue_bookings_with_filtering(start_date, end_date) format_decimal(revenue) end end |
#current_restaurant_time ⇒ Time
Returns the current time in the first restaurant's timezone.
428 429 430 431 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 428 def current_restaurant_time restaurant = Restaurant.find(restaurant_ids.first) Time.now_in_tz(restaurant.time_zone) end |
#identifiers(start_date, end_date) ⇒ Array<Hash>
Returns rating identifiers with scores for a date range.
307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 307 def identifiers(start_date, end_date) avg = [] reviews = reviews(start_date, end_date).joins(rates: :dimension). select('rates.stars as stars, dimensions.identifier as identifier'). group_by(&:identifier) reviews.transform_values do |reviews| avg << { score: (reviews.sum(&:stars) / reviews.size).round(1), identifier: reviews.first.identifier, } end avg end |
#last_8_weeks_bookings_revenue ⇒ Array<Hash>
Returns revenue data for the last 8 weeks.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 213 def last_8_weeks_bookings_revenue current_date = Date.current_date cache_key = "last_8_weeks_revenue:#{current_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key) do weeks_data = [] days_since_sunday = current_date.wday == 0 ? 0 : current_date.wday most_recent_sunday = current_date - days_since_sunday.days (0..7).each do |week_offset| week_end = most_recent_sunday - (week_offset * 7).days week_start = week_end - 6.days week_revenue = revenue_bookings_with_filtering(week_start, week_end) weeks_data << { week: week_offset + 1, start_date: week_start, end_date: week_end, revenue: format_decimal(week_revenue), } end { weeks: weeks_data.reverse, total_revenue: format_decimal(weeks_data.sum { |week| week[:revenue] }), } end end |
#last_month_bookings ⇒ Hash
Returns booking statistics for the previous month.
120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 120 def last_month_bookings start_date = Date.current_date.prev_month.beginning_of_month end_date = start_date.end_of_month cache_key = "last_month_bookings:#{start_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { bookings: total_confirm_bookings(start_date, end_date), covers: total_covers_bookings(start_date, end_date), } end end |
#last_month_bookings_revenue ⇒ String
Returns revenue for the previous month.
183 184 185 186 187 188 189 190 191 192 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 183 def last_month_bookings_revenue start_date = Date.current_date.prev_month.beginning_of_month end_date = start_date.end_of_month cache_key = "last_month_revenue:#{start_date}:#{end_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do revenue = revenue_bookings_with_filtering(start_date, end_date) format_decimal(revenue) end end |
#package_best_revenue(start_date, end_date) ⇒ String?
Finds the package with the highest revenue for a given date range.
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 407 def package_best_revenue(start_date, end_date) best_package = reservations.active_and_show_scope. exclude_temporary. where(date: start_date..end_date). joins(reservation_packages: :restaurant_package). where(hh_package_restaurant_packages: { active: true }). select('hh_package_restaurant_packages.id as rpid, SUM(reservations.total_price_v2_cents) as package_total_price_cents'). group('hh_package_restaurant_packages.id'). order('package_total_price_cents DESC'). limit(1). first return nil if best_package.blank? restaurant_package = HhPackage::RestaurantPackage.find_by(id: best_package.rpid) restaurant_package&.package&.name end |
#package_summary ⇒ Hash
Returns package summary with online count and best seller.
94 95 96 97 98 99 100 101 102 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 94 def package_summary cache_key = "package_summary:#{Date.current_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { online: HhPackage::RestaurantPackage.where(restaurant_id: restaurant_ids).active_scope.exclude_preview.size, best_seller: package_best_revenue(Date.current - 30.days, Date.current), } end end |
#pending_bookings ⇒ Hash
Calculates pending bookings count and revenue.
31 32 33 34 35 36 37 38 39 40 41 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 31 def pending_bookings cache_key = "pending_bookings:#{Date.current_date}:#{restaurant_ids.join(',')}" data = Rails.cache.fetch(cache_key, expires_in: 1.hour) do reservations.upcoming. exclude_temporary. exclude_cancel_scope. no_show. where(ack: false) end { bookings: data.size, revenue: revenue_with_filtering(data) } end |
#ratings ⇒ Hash
Returns rating statistics for the last 30 days.
260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 260 def end_date = current_restaurant_time start_date = 30.days.ago cache_key = "ratings:#{start_date.to_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { score: (start_date, end_date), identifiers: identifiers(start_date, end_date), count: total_reviews(start_date, end_date), } end end |
#ratings_score(start_date, end_date) ⇒ Float
Calculates average rating score for a date range.
278 279 280 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 278 def (start_date, end_date) reviews(start_date, end_date).average(:rating).to_f.round(1) end |
#reservations ⇒ ActiveRecord::Relation
Returns reservations for the configured restaurant IDs.
24 25 26 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 24 def reservations @reservations ||= Reservation.where(restaurant_id: restaurant_ids) end |
#revenue_bookings_with_filtering(start_date, end_date) ⇒ String
Calculates total revenue for bookings within a specified date range.
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 359 def revenue_bookings_with_filtering(start_date, end_date) cache_key = "revenue_with_filtering:#{start_date}:#{end_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do query = ReservationProperty.select('SUM(price_cents) revenue'). joins(:reservation). where.not(reservations: { restaurant_id: nil }). where(reservations: { restaurant_id: restaurant_ids, active: true, no_show: false, is_temporary: false, for_locking_system: false }). where.not(package: nil). where('reservations.date between ? and ?', start_date, end_date) revenue_cents = query[0]['revenue'] return format_decimal(0) if revenue_cents.nil? revenue = Money.new(revenue_cents, primary_currency).to_f format_decimal(revenue) end end |
#revenue_by_date ⇒ Hash
Returns revenue comparison between current and previous month.
152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 152 def revenue_by_date beginning_of_month = Date.current_date.prev_month.beginning_of_month end_of_month = beginning_of_month.end_of_month cache_key = "revenue_by_date:#{beginning_of_month}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { this_month: format_decimal(revenue_bookings_with_filtering(Date.current_date.beginning_of_month, Date.current_date.end_of_month)), last_month: format_decimal(revenue_bookings_with_filtering(beginning_of_month, end_of_month)), } end end |
#revenue_with_filtering(reservations_collection) ⇒ String, Integer
Calculates total revenue for a given collection of reservations.
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 384 def revenue_with_filtering(reservations_collection) return 0 if reservations_collection.blank? reservation_ids = reservations_collection.pluck(:id) query = ReservationProperty.select('SUM(price_cents) revenue'). joins(:reservation). where(reservations: { id: reservation_ids }). where.not(package: nil) revenue_cents = query[0]['revenue'] return format_decimal(0) if revenue_cents.nil? revenue = Money.new(revenue_cents, primary_currency).to_f format_decimal(revenue) end |
#reviews(start_date, end_date) ⇒ ActiveRecord::Relation
Returns reviews for a date range.
287 288 289 290 291 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 287 def reviews(start_date, end_date) @reviews ||= Review.joins(:reservation). where(reservations: { active: true, restaurant_id: restaurant_ids }). where('reviews.created_at >= ? AND reviews.created_at <= ?', start_date.to_date.beginning_of_day, end_date.to_date.end_of_day) end |
#seat_available_percent ⇒ Integer
Calculates seat availability percentage for the next 7 days.
325 326 327 328 329 330 331 332 333 334 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 325 def seat_available_percent inventories = Inventory.where(restaurant_id: @restaurant_ids). next_7_days total_capacity = inventories.sum(:quantity_available) total_booked_seat = inventories.sum(:total_booked_seat) return 0 if total_capacity.zero? ((1 - (total_booked_seat.to_f / total_capacity)) * 100).round end |
#this_month_bookings ⇒ Hash
Returns booking statistics for the current month.
107 108 109 110 111 112 113 114 115 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 107 def this_month_bookings cache_key = "this_month_bookings:#{Date.current_date.beginning_of_month}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { bookings: total_confirm_bookings(Date.current_date.beginning_of_month, Date.current_date.end_of_month), covers: total_covers_bookings(Date.current_date.beginning_of_month, Date.current_date.end_of_month), } end end |
#today_bookings ⇒ Hash
Returns booking statistics for today.
247 248 249 250 251 252 253 254 255 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 247 def today_bookings cache_key = "today_bookings:#{Date.current_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { bookings: total_confirm_bookings(Date.current_date, Date.current_date), covers: total_covers_bookings(Date.current_date, Date.current_date), } end end |
#total_confirm_bookings(start_date, end_date) ⇒ Integer
Returns total confirmed bookings for a date range.
341 342 343 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 341 def total_confirm_bookings(start_date, end_date) PartnerService::Reservations::MetricsService.new(start_date, end_date, restaurant_ids).total_confirm_bookings end |
#total_covers_bookings(start_date, end_date) ⇒ Integer
Returns total covers for bookings in a date range.
350 351 352 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 350 def total_covers_bookings(start_date, end_date) PartnerService::Reservations::MetricsService.new(start_date, end_date, restaurant_ids).total_covers_bookings end |
#total_reviews(start_date, end_date) ⇒ Integer
Returns total count of reviews for a date range.
298 299 300 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 298 def total_reviews(start_date, end_date) reviews = reviews(start_date, end_date).group(:id).count.size end |
#two_months_before_bookings ⇒ Hash
Returns booking statistics for two months ago.
136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 136 def two_months_before_bookings start_date = 2.months.ago.beginning_of_month end_date = start_date.end_of_month cache_key = "two_months_before_bookings:#{start_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do { bookings: total_confirm_bookings(start_date, end_date), covers: total_covers_bookings(start_date, end_date), } end end |
#two_months_before_bookings_revenue ⇒ String
Returns revenue for two months ago.
198 199 200 201 202 203 204 205 206 207 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 198 def two_months_before_bookings_revenue start_date = 2.months.ago.beginning_of_month end_date = start_date.end_of_month cache_key = "two_months_before_revenue:#{start_date}:#{end_date}:#{restaurant_ids.join(',')}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do revenue = revenue_bookings_with_filtering(start_date, end_date) format_decimal(revenue) end end |
#upcoming_bookings ⇒ Hash
Calculates upcoming bookings for the next 7 days.
46 47 48 49 50 51 52 53 54 55 56 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 46 def upcoming_bookings cache_key = "upcoming_bookings:#{Date.current_date}:#{restaurant_ids.join(',')}" collections = Rails.cache.fetch(cache_key, expires_in: 1.hour) do reservations.active_and_show_scope. exclude_temporary. where(date: Date.next_7_days) end { booking: collections.size, covers: collections.sum(:party_size), seat_available: seat_available_percent } end |
#voucher_sales ⇒ Hash
Calculates voucher sales for the current month.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'app/services/partner_service/dashboards/calculate_service.rb', line 61 def voucher_sales start_date = current_restaurant_time.beginning_of_month end_date = start_date.end_of_month cache_key = "voucher_sales:#{start_date}:#{restaurant_ids.join(',')}" vouchers = Rails.cache.fetch(cache_key, expires_in: 1.hour) do Ticket.joins(:ticket_transaction).where(ticket_transactions: { restaurant_id: restaurant_ids }).where( 'DATE(redeemed_at) >= ? AND DATE(redeemed_at) <= ?', start_date, end_date ) end total_revenue = vouchers.sum do |ticket| ticket_money = Money.new(ticket.amount_cents, ticket.amount_currency) # If ticket currency matches primary currency, use as-is # Otherwise, convert to primary currency (this is a simplified approach) if ticket.amount_currency == primary_currency ticket_money.to_f else # For now, we'll use the amount as-is since currency conversion requires exchange rates # In a real implementation, you'd want to use a currency conversion service ticket_money.to_f end end { redeemed: vouchers.size, revenue: format_decimal(total_revenue), } end |