Class: PartnerService::Reservations::SummarySync

Inherits:
ApplicationService show all
Includes:
ElasticAPM::SpanHelpers
Defined in:
app/services/partner_service/reservations/summary_sync.rb

Constant Summary collapse

DATE_RANGE_DAYS =

Only sync reservations within 90 days

90

Instance Attribute Summary collapse

Attributes inherited from ApplicationService

#object

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationService

#execute, #execute!

Constructor Details

#initialize(reservation) ⇒ SummarySync

Initialize the summary sync service

Parameters:

  • reservation (Reservation)

    the reservation to sync



25
26
27
28
# File 'app/services/partner_service/reservations/summary_sync.rb', line 25

def initialize(reservation)
  @reservation = reservation
  @summary = find_or_initialize_summary
end

Instance Attribute Details

#reservationReservation, Partners::ReservationSummary (readonly)

Returns:



20
21
22
# File 'app/services/partner_service/reservations/summary_sync.rb', line 20

def reservation
  @reservation
end

#summaryReservation, Partners::ReservationSummary (readonly)

Returns:



20
21
22
# File 'app/services/partner_service/reservations/summary_sync.rb', line 20

def summary
  @summary
end

Class Method Details

.batch_sync_loyalty_data(reservations) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'app/services/partner_service/reservations/summary_sync.rb', line 127

def self.batch_sync_loyalty_data(reservations)
  return if reservations.blank?

  # Group reservations by user to optimize loyalty data fetching
  reservations_by_user = reservations.group_by(&:user_id).compact

  # Pre-fetch loyalty levels once for all users
  loyalty_levels = ::LoyaltyLevel.fetch_data
  default_level = loyalty_levels.detect { |level| level.code.to_s.downcase == 'hunger' }

  # Pre-fetch user loyalty data for all users
  user_ids = reservations_by_user.keys
  user_loyalties = ::UserLoyalty.where(user_id: user_ids).includes(:user).index_by(&:user_id)

  # Process in deterministic order to prevent deadlocks
  total_updated = 0
  sorted_user_ids = reservations_by_user.keys.compact.sort

  # Single transaction for all updates to reduce lock contention
  Partners::ReservationSummary.transaction do
    sorted_user_ids.each do |user_id|
      user_reservations = reservations_by_user[user_id]
      user_loyalty = user_loyalties[user_id]

      # Build loyalty data once per user
      loyalty_data = build_loyalty_data_for_user(user_reservations.first, user_loyalty, default_level)

      # Single bulk update per user to reduce database operations
      reservation_ids = user_reservations.map(&:id)
      updated_count = Partners::ReservationSummary.
        where(reservation_id: reservation_ids).
        update_all(
          customer_loyalty_data: loyalty_data.to_json,
          last_synced_at: Time.current,
        )

      total_updated += updated_count
    end

    # Handle reservations without user_id separately
    nil_user_reservations = reservations.select { |r| r.user_id.nil? }
    if nil_user_reservations.any?
      nil_reservation_ids = nil_user_reservations.map(&:id)
      Partners::ReservationSummary.
        where(reservation_id: nil_reservation_ids).
        update_all(
          customer_loyalty_data: nil,
          last_synced_at: Time.current,
        )
      total_updated += nil_user_reservations.size
    end
  end
rescue StandardError => e
  APMErrorHandler.report('Batch loyalty sync failed', {
                           reservation_count: reservations.size,
                           unique_users: reservations_by_user&.keys&.size || 0,
                           total_updated: total_updated || 0,
                           exception: e,
                         })
  raise e
end

.build_loyalty_data_for_user(reservation, user_loyalty, default_level) ⇒ Hash

Build loyalty data for a specific user (used in batch operations)

Parameters:

  • reservation (Reservation)

    sample reservation for the user

  • user_loyalty (UserLoyalty)

    the user's loyalty record

  • default_level (LoyaltyLevel)

    the default loyalty level

Returns:

  • (Hash)

    loyalty data with icon and loyalty_level_id



616
617
618
619
620
621
622
623
624
# File 'app/services/partner_service/reservations/summary_sync.rb', line 616

def self.build_loyalty_data_for_user(reservation, user_loyalty, default_level)
  icon_value = reservation.customer_icon(default_level&.icon_badge&.url)
  loyalty_level_id = user_loyalty&.loyalty_level_id

  {
    icon: icon_value,
    loyalty_level_id: loyalty_level_id,
  }
end

Instance Method Details

#batch_sync_loyalty_datavoid

This method returns an undefined value.

Batch sync loyalty data for multiple reservations This is more efficient than individual sync when processing many reservations for the same user Optimized to prevent deadlocks and reduce database operations

Parameters:

  • reservations (Array<Reservation>)

    reservations to sync loyalty data for



126
# File 'app/services/partner_service/reservations/summary_sync.rb', line 126

span_method :batch_sync_loyalty_data

#destroy_summaryvoid

This method returns an undefined value.

Destroy the summary record



192
# File 'app/services/partner_service/reservations/summary_sync.rb', line 192

span_method :destroy_summary

#sync_allvoid

This method returns an undefined value.

Perform full synchronization of reservation data to summary table



33
# File 'app/services/partner_service/reservations/summary_sync.rb', line 33

span_method :sync_all

#sync_financial_onlyvoid

This method returns an undefined value.

Sync only financial-related fields



81
# File 'app/services/partner_service/reservations/summary_sync.rb', line 81

span_method :sync_financial_only

#sync_loyalty_infovoid

This method returns an undefined value.

Sync only loyalty-related data



110
# File 'app/services/partner_service/reservations/summary_sync.rb', line 110

span_method :sync_loyalty_info

#sync_package_info_onlyvoid

This method returns an undefined value.

Sync only package and add-on information



95
# File 'app/services/partner_service/reservations/summary_sync.rb', line 95

span_method :sync_package_info_only

#sync_status_onlyvoid

This method returns an undefined value.

Sync only status-related fields



67
# File 'app/services/partner_service/reservations/summary_sync.rb', line 67

span_method :sync_status_only