Module: ReservationExportHelpers
- Extended by:
- ActiveSupport::Concern
- Includes:
- ExportConstants
- Included in:
- Admin::VoucherGroupsController, Admin::VouchersController, NotificationWorkers::ReservationReport, NotificationWorkers::VoucherGroupReport, Partner::BookingExportWorker, ProgressTrackableReportPdf, ReportPdf
- Defined in:
- app/workers/concerns/reservation_export_helpers.rb
Overview
Shared helper methods for reservation export workers. This module extracts common functionality from NotificationWorkers::ReservationReport and Partner::BookingExportWorker to ensure consistency and eliminate code duplication.
Constant Summary
Constants included from ExportConstants
ExportConstants::CHANNEL_IDS_TO_SKIP, ExportConstants::DEFAULT_QUEUE, ExportConstants::EMAIL_BATCH_SIZE, ExportConstants::ERROR_CATEGORIES, ExportConstants::EXCEL_FILE_EXTENSION, ExportConstants::LARGE_DATASET_WARNING_THRESHOLD, ExportConstants::LONG_PROCESS_DAYS_THRESHOLD, ExportConstants::LONG_PROCESS_QUEUE, ExportConstants::MAX_RETRIES, ExportConstants::PDF_FILE_EXTENSION, ExportConstants::PROGRESS_MESSAGES, ExportConstants::PROGRESS_PHASES, ExportConstants::PROGRESS_UPDATE_BATCH_SIZE, ExportConstants::RESERVATION_BATCH_SIZE, ExportConstants::RETRY_BASE_INTERVAL, ExportConstants::RETRY_MAX_ELAPSED_TIME, ExportConstants::ZERO_COMMISSION_CHANNEL_ID
Instance Method Summary collapse
-
#calc_prepayment(reservation) ⇒ String
Calculate prepayment amount for a reservation.
-
#calculate_commission(reservation) ⇒ Numeric
(also: #revenue_amount)
Calculate commission for a reservation (FIXED VERSION from main branch) This includes both package and add-on revenue as per the latest fix.
-
#calculate_restaurant_revenue(reservation) ⇒ Numeric
(also: #restaurant_revenue_amount)
Calculate restaurant revenue amount (sum of package and add-on amounts).
-
#calculate_total_package_price(reservation) ⇒ Numeric
Calculate total package price for a reservation.
-
#date_format(date) ⇒ String
Format date in DD/MM/YYYY format.
-
#decimal_format(number) ⇒ Numeric
Format decimal numbers consistently.
-
#format_add_on_names_with_quantity(reservation) ⇒ Object
Enhanced formatter for add-ons adding explicit quantity suffix if missing.
-
#format_addon_names_for_report(reservation) ⇒ String
Formats add-on names for report display with quantity information.
-
#format_money(amount) ⇒ String?
Format money amount using the same formatting as existing system.
-
#format_package_names(reservation) ⇒ String?
Format package names for display in exports (wrapper for compatibility).
-
#format_package_names_for_report(reservation) ⇒ String
Formats package names for report display with quantity information.
-
#format_package_names_with_quantity(reservation) ⇒ Object
Enhanced formatter adding explicit quantity suffix (e.g. “DIY Choose All You Need STP ฿670 NET/Set x6”) Logic: - Iterate packages_bought (already localized via i18n) aligned with formatted_packages - If localized string does not already contain an “x<digits>” quantity and the formatted package hash contains :quantity > 0, append “ x<quantity>” - Special case AYCE (type “ayce”) where the i18n template omits quantity: append party_size if quantity blank - Preserve existing spacing & sanitization; collapse whitespace - Return a to_sentence string like original implementation for multi-package reservations Compatible with Ruby 2.7.8 & Rails 5.1.7 (no pattern matching / newer methods used).
-
#format_voucher_amount(reservation) ⇒ String
Format voucher amounts for a reservation (combines HH and restaurant voucher amounts).
-
#format_voucher_code(reservation) ⇒ String
Format voucher codes for a reservation.
-
#get_reservation_distance(distance) ⇒ Numeric?
Get reservation distance with proper formatting.
-
#paid_amount(reservation) ⇒ Numeric
Get paid amount for a reservation.
-
#restaurant_delivery_fee(reservation) ⇒ Numeric
Calculate restaurant delivery fee.
-
#sanitize_package_name(packages) ⇒ String
Sanitize package names for display in exports (exact same as original).
-
#sanitizer ⇒ Object
Get sanitizer instance for HTML sanitization (same as existing system).
-
#valid_email?(email) ⇒ Boolean
Validate email format.
-
#voucher_amount(vouchers, reservation, by:) ⇒ String
Calculate voucher amount by subsidizer (same logic as existing system).
-
#voucher_code(vouchers, by:) ⇒ String
Get voucher codes by subsidizer.
Instance Method Details
#calc_prepayment(reservation) ⇒ String
Calculate prepayment amount for a reservation
283 284 285 286 287 288 289 290 291 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 283 def calc_prepayment(reservation) prepayment = 0 if reservation.property&.is_prepayment && reservation.property&.prepayment_cents prepayment += HhMoney.new(reservation.property.prepayment_cents, reservation.property.prepayment_currency).amount end prepayment += reservation.paid_amount.amount prepayment.to_s end |
#calculate_commission(reservation) ⇒ Numeric Also known as: revenue_amount
Calculate commission for a reservation (FIXED VERSION from main branch) This includes both package and add-on revenue as per the latest fix
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 27 def calculate_commission(reservation) return 0 unless reservation.package? return 0 if reservation.rejected? # requested by Ravi # he said "I need to have channel ID 1114 to be set as 0 commission" if reservation.channel != 1114 package_revenue = reservation.package_obj&.revenue_amount.to_d || 0 add_on_revenue = reservation.add_on_obj&.revenue_amount.to_d || 0 total_revenue = package_revenue + add_on_revenue total_revenue = if total_revenue % 1 == 0 total_revenue.to_i else total_revenue end return total_revenue end 0 end |
#calculate_restaurant_revenue(reservation) ⇒ Numeric Also known as: restaurant_revenue_amount
Calculate restaurant revenue amount (sum of package and add-on amounts)
53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 53 def calculate_restaurant_revenue(reservation) return 0 unless reservation.package? return 0 if reservation.rejected? package_revenue = reservation&.package_obj&.amount.to_d || 0 add_on_revenue = reservation&.add_on_obj&.amount.to_d || 0 total_restaurant_revenue = package_revenue + add_on_revenue if total_restaurant_revenue % 1 == 0 total_restaurant_revenue.to_i else total_restaurant_revenue end end |
#calculate_total_package_price(reservation) ⇒ Numeric
Calculate total package price for a reservation
307 308 309 310 311 312 313 314 315 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 307 def calculate_total_package_price(reservation) return 0 unless reservation.package? total = reservation.package_obj.formatted_packages.sum do |item| Money.new(item['price_cents'], item['price_currency']).amount end decimal_format(total) end |
#date_format(date) ⇒ String
Format date in DD/MM/YYYY format
297 298 299 300 301 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 297 def date_format(date) return '' if date.blank? date&.strftime('%d/%m/%Y') end |
#decimal_format(number) ⇒ Numeric
Format decimal numbers consistently
244 245 246 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 244 def decimal_format(number) number % 1 == 0 ? number.to_i : number.to_f end |
#format_add_on_names_with_quantity(reservation) ⇒ Object
Enhanced formatter for add-ons adding explicit quantity suffix if missing. Similar logic to packages: localized strings may already contain x<quantity> (per_item template). If pricing_type per_person and localized string lacks quantity, append x<quantity> when available.
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 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 144 def format_add_on_names_with_quantity(reservation) return nil unless reservation.add_on? add_on_obj = reservation.add_on_obj return nil unless add_on_obj && add_on_obj.add_ons_bought.is_a?(Array) bought = add_on_obj.add_ons_bought formatted = add_on_obj.formatted_add_ons || [] enriched = [] bought.each_with_index do |raw, idx| next if raw.blank? base = sanitizer.(raw.to_s).gsub(/\s+/, ' ') addon_hash = formatted[idx] || {} quantity = addon_hash[:quantity].to_i unless base =~ /x\s*\d+/ || quantity <= 0 base = base + " x#{quantity}" end enriched << base end enriched.to_sentence end |
#format_addon_names_for_report(reservation) ⇒ String
Formats add-on names for report display with quantity information. Returns a final sanitized string ready for Excel export.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 394 def format_addon_names_for_report(reservation) return '' unless reservation.add_on.present? && reservation.add_on_obj.present? prop_cache_key = reservation.property.id.nil? ? rand(1000) : reservation.property.cache_key res_cache_key = reservation.id.nil? ? rand(1000) : reservation.cache_key addon_data = Rails.cache.fetch("#{res_cache_key}:addon_names_for_report:#{prop_cache_key}") do add_ons = reservation.add_on[:add_on_data].map do |data| get_add_on = AddOns::AddOn.find_by(id: data[:id]) name = get_add_on&.name || '' price = HhMoney.new(data[:price_cents], data[:price_currency]) pricing_type = get_add_on&.pricing&.pricing_type { name: name, net_price: price.default_format, quantity: data[:quantity], pricing_type: pricing_type, } end add_ons.map do |aob| I18n.t("views.booking.add_on_data_for_report.#{aob[:pricing_type]}", name: aob[:name], net_price: aob[:net_price], quantity: aob[:quantity]) end end # Return final sanitized string ready for export addon_data.present? ? sanitizer.(addon_data.to_sentence).gsub(/\s+/, ' ') : '' end |
#format_money(amount) ⇒ String?
Format money amount using the same formatting as existing system
174 175 176 177 178 179 180 181 182 183 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 174 def format_money(amount) return nil if amount.blank? # Use formatting with symbol for exports (booking export worker needs currency symbol) if respond_to?(:humanized_money_with_symbol) humanized_money_with_symbol(amount) else humanized_money(amount) end end |
#format_package_names(reservation) ⇒ String?
Format package names for display in exports (wrapper for compatibility)
86 87 88 89 90 91 92 93 94 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 86 def format_package_names(reservation) return nil unless reservation.package? packages = reservation.package_obj&.packages_bought return nil unless packages # Use same sanitization as existing system sanitize_package_name(packages) end |
#format_package_names_for_report(reservation) ⇒ String
Formats package names for report display with quantity information. Returns a final sanitized string ready for Excel export.
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 351 def format_package_names_for_report(reservation) return '' unless reservation.package? && reservation.package_obj.present? prop_cache_key = reservation.property.id.nil? ? rand(1000) : reservation.property.cache_key res_cache_key = reservation.id.nil? ? rand(1000) : reservation.cache_key package_data = Rails.cache.fetch("#{res_cache_key}:package_names_for_report:#{prop_cache_key}") do sym = reservation.package[:package_type].to_s.to_sym klass = "HhPackage::Package::#{HhPackage::PACKAGE_SHORT_TO_LIST[sym]}".constantize packages = reservation.package[:package_data].map do |data| get_package = klass.find_by(id: data[:id]) name = get_package&.name || '' price = HhMoney.new(data[:price_cents], data[:price_currency]) { name: name, net_price: price.default_format, quantity: data[:quantity], package_type: reservation.package[:package_type], } end packages.map do |p| I18n.t("views.booking.package_data_for_report.#{p[:package_type]}", name: p[:name], net_price: p[:net_price], quantity: p[:quantity]) end end # Return final sanitized string ready for export package_data.present? ? sanitizer.(package_data.to_sentence).gsub(/\s+/, ' ') : '' end |
#format_package_names_with_quantity(reservation) ⇒ Object
Enhanced formatter adding explicit quantity suffix (e.g. “DIY Choose All You Need STP ฿670 NET/Set x6”) Logic:
- Iterate packages_bought (already localized via i18n) aligned with formatted_packages
- If localized string does not already contain an "x<digits>" quantity and the formatted package hash
contains :quantity > 0, append " x<quantity>"
- Special case AYCE (type "ayce") where the i18n template omits quantity: append party_size if quantity blank
- Preserve existing spacing & sanitization; collapse whitespace
- Return a to_sentence string like original implementation for multi-package reservations
Compatible with Ruby 2.7.8 & Rails 5.1.7 (no pattern matching / newer methods used)
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 105 def format_package_names_with_quantity(reservation) return nil unless reservation.package? pkg_obj = reservation.package_obj return nil unless pkg_obj && pkg_obj.packages_bought.is_a?(Array) bought = pkg_obj.packages_bought formatted = pkg_obj.formatted_packages || [] enriched = [] bought.each_with_index do |raw, idx| next if raw.blank? base = sanitizer.(raw.to_s).gsub(/\s+/, ' ') pkg_hash = formatted[idx] || {} quantity = pkg_hash[:quantity].to_i # Append quantity if missing and available unless base =~ /x\s*\d+/ || quantity <= 0 base = base + " x#{quantity}" end # AYCE fallback: use party_size if ayce and still no x<digits> if base !~ /x\s*\d+/ && quantity <= 0 && reservation.respond_to?(:party_size) && reservation.party_size.to_i > 0 type_short = pkg_hash[:type_short] || pkg_hash[:dynamic_type_short] || pkg_obj.respond_to?(:type_short) && pkg_obj.type_short if type_short.to_s == 'ayce' base = base + " x#{reservation.party_size}" end end enriched << base end enriched.to_sentence end |
#format_voucher_amount(reservation) ⇒ String
Format voucher amounts for a reservation (combines HH and restaurant voucher amounts)
200 201 202 203 204 205 206 207 208 209 210 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 200 def format_voucher_amount(reservation) return '' if reservation.vouchers.blank? # Use same approach as existing system - combine HH and restaurant voucher amounts hh_amount = voucher_amount(reservation.vouchers, reservation, by: :hungryhub) restaurant_amount = voucher_amount(reservation.vouchers, reservation, by: :restaurant) # Return combined amounts or empty if both are empty amounts = [hh_amount, restaurant_amount].reject(&:blank?) amounts.any? ? amounts.join(' + ') : '' end |
#format_voucher_code(reservation) ⇒ String
Format voucher codes for a reservation
189 190 191 192 193 194 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 189 def format_voucher_code(reservation) return '' if reservation.vouchers.blank? # Use same approach as existing system reservation.vouchers.map(&:voucher_code).join(', ') end |
#get_reservation_distance(distance) ⇒ Numeric?
Get reservation distance with proper formatting
252 253 254 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 252 def get_reservation_distance(distance) distance.to_f.positive? ? distance.round(1) : nil end |
#paid_amount(reservation) ⇒ Numeric
Get paid amount for a reservation
275 276 277 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 275 def paid_amount(reservation) reservation.paid_amount end |
#restaurant_delivery_fee(reservation) ⇒ Numeric
Calculate restaurant delivery fee
260 261 262 263 264 265 266 267 268 269 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 260 def restaurant_delivery_fee(reservation) return 0 if reservation.property&.covered_by_hh? return 0 unless reservation.service_type.delivery? return reservation.delivery_subsidize.amount if reservation.delivery_subsidize_cents.positive? return 0 if reservation.address.blank? reservation.delivery_channel&.restaurant_fee&.amount || 0 end |
#sanitize_package_name(packages) ⇒ String
Sanitize package names for display in exports (exact same as original)
78 79 80 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 78 def sanitize_package_name(packages) sanitizer.(packages.to_sentence).gsub(/\s+/, ' ') end |
#sanitizer ⇒ Object
Get sanitizer instance for HTML sanitization (same as existing system)
328 329 330 331 332 333 334 335 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 328 def sanitizer @sanitizer ||= begin sanitizer_class = Class.new do include ActionView::Helpers::SanitizeHelper end sanitizer_class.new end end |
#valid_email?(email) ⇒ Boolean
Validate email format
321 322 323 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 321 def valid_email?(email) email.present? && email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i) end |
#voucher_amount(vouchers, reservation, by:) ⇒ String
Calculate voucher amount by subsidizer (same logic as existing system)
218 219 220 221 222 223 224 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 218 def voucher_amount(vouchers, reservation, by:) return '' if vouchers.blank? return humanized_money(reservation.used_voucher_amount_by_hh.amount.to_i) if by == :hungryhub humanized_money(reservation.used_voucher_amount_by_restaurant.amount.to_i) end |
#voucher_code(vouchers, by:) ⇒ String
Get voucher codes by subsidizer
231 232 233 234 235 236 237 238 |
# File 'app/workers/concerns/reservation_export_helpers.rb', line 231 def voucher_code(vouchers, by:) return '' if vouchers.blank? subsidized_vouchers = vouchers.select { |v| v.subsidized_by.to_s == by.to_s } return subsidized_vouchers.map(&:voucher_code).to_sentence if subsidized_vouchers.present? '' end |