Class: ReservationDecorator

Inherits:
Draper::Decorator
  • Object
show all
Defined in:
app/decorators/reservation_decorator.rb

Overview

No comment

Instance Method Summary collapse

Instance Method Details

#been_passed?Boolean

Returns:

  • (Boolean)


297
298
299
300
301
302
# File 'app/decorators/reservation_decorator.rb', line 297

def been_passed?
  now = Time.use_zone object.restaurant.time_zone do
    Time.zone.now
  end
  now > object.reservation_time
end

#cancelled_with_refund?Boolean

Returns:

  • (Boolean)


444
445
446
# File 'app/decorators/reservation_decorator.rb', line 444

def cancelled_with_refund?
  object.status_as_symbol == :cancelled_with_refund
end

#due_amountObject



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'app/decorators/reservation_decorator.rb', line 44

def due_amount
  total_amount_value = total_amount
  amount = total_amount_value - object.paid_amount.to_d -
    used_voucher_amount_by_restaurant.to_d - used_voucher_amount_by_hh.to_d

  amount = 0 unless amount.positive? && object.package.present?

  if object.package.blank?
    return Money.from_amount(amount, object.restaurant.default_currency)
  end

  Money.from_amount(amount, object.package[:price_currency])
end

#having_due?Boolean

Returns:

  • (Boolean)


413
414
415
# File 'app/decorators/reservation_decorator.rb', line 413

def having_due?
  object.paid_amount.amount.positive? && due_amount.amount.positive? && due_amount.amount < total_amount
end

#loyalty_level_logoObject



179
180
181
182
183
184
185
186
187
188
# File 'app/decorators/reservation_decorator.rb', line 179

def 
  if object.user.present?
    user_loyalty_level_id = user.user_loyalty&.loyalty_level_id
    hunger_id = LoyaltyLevel.hunger.id

    LoyaltyLevel.find(user_loyalty_level_id.presence || hunger_id).icon_badge
  else
    LoyaltyLevel.hunger.icon_badge
  end
end

#modifierObject



343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'app/decorators/reservation_decorator.rb', line 343

def modifier
  audit = object.audits.select { |audit| audit.user_type.present? }.last

  if audit.present?
    @audit_user_type = audit.user_type
    @modifier = @audit_user_type.camelize.constantize.find_by(id: audit.user_id) if @audit_user_type.present?
  end

  {
    'user_type' => @audit_user_type,
    'data' => @modifier,
  }
end

#modifier_nameObject



357
358
359
360
361
362
363
# File 'app/decorators/reservation_decorator.rb', line 357

def modifier_name
  if modifier['data'].present? && (%w[owner user staff].include? modifier['user_type'].downcase)
    @name = modifier['user_type'].downcase == 'owner' ? modifier['data'].owner_name : modifier['data'].name
  end

  @name
end

#non_voucher_payment_with_due_or_partial_charge_or_prepayment?Boolean

Returns:

  • (Boolean)


405
406
407
# File 'app/decorators/reservation_decorator.rb', line 405

def non_voucher_payment_with_due_or_partial_charge_or_prepayment?
  having_due? || partial_charge? || prepaid_full?
end

#package_type_nameObject



190
191
192
193
194
195
196
197
198
199
# File 'app/decorators/reservation_decorator.rb', line 190

def package_type_name
  service_type = object.service_type
  if service_type.to_sym == :dine_in
    I18n.t('views.d.dine_in')
  elsif %w[delivery pick_up].include? service_type
    I18n.t('views.d.delivery')
  else
    service_type ? service_type.titleize : ''
  end
end

Returns:

  • (Boolean)


152
153
154
155
# File 'app/decorators/reservation_decorator.rb', line 152

def paid_by_admin_or_owner?
  %I[admin owner].include?(object.created_by.to_s.to_sym) &&
    (object.property.present? && object.property.prepayment_cents > 0)
end

Returns:

  • (Boolean)


409
410
411
# File 'app/decorators/reservation_decorator.rb', line 409

def paid_by_voucher?
  paid_by_voucher_full? || paid_by_voucher_partially?
end

Returns:

  • (Boolean)


169
170
171
172
# File 'app/decorators/reservation_decorator.rb', line 169

def paid_by_voucher_full?
  object.active_reservation_vouchers.present? &&
    object.active_reservation_vouchers.map(&:amount).sum.amount == total_amount
end

Returns:

  • (Boolean)


174
175
176
177
# File 'app/decorators/reservation_decorator.rb', line 174

def paid_by_voucher_partially?
  object.active_reservation_vouchers.present? &&
    object.active_reservation_vouchers.map(&:amount).sum.amount != total_amount
end


157
158
159
160
161
162
163
164
165
166
167
# File 'app/decorators/reservation_decorator.rb', line 157

def paid_percentage_by_admin_or_owner
  return 0 if object.paid_amount.zero?

  total = total_amount.to_f
  paid = object.paid_amount.to_f

  return 100 if paid >= total

  percentage = (paid / total) * 100
  object.format_percentage(percentage)
end

#partial_charge?Boolean

Returns:

  • (Boolean)


417
418
419
# File 'app/decorators/reservation_decorator.rb', line 417

def partial_charge?
  charge_percent.positive? && charge_percent < 100
end

#payment_expired?Boolean

Returns:

  • (Boolean)


436
437
438
439
440
441
442
# File 'app/decorators/reservation_decorator.rb', line 436

def payment_expired?
  !object.active? && !object.for_locking_system? && object.is_temporary? &&
    (object.cc_provider.present? ||
    object.promptpay_provider.present? ||
    object.alipay_provider.present? ||
    object.wechat_pay_provider.present?)
end

#payment_is_confirmed?Boolean

Returns:

  • (Boolean)


397
398
399
400
401
402
403
# File 'app/decorators/reservation_decorator.rb', line 397

def payment_is_confirmed?
  return true if reservation&.payment_type_provider.blank?
  return false if object.charge_type.blank? && object.paid_charges.blank?
  return true if paid_by_voucher?

  non_voucher_payment_with_due_or_partial_charge_or_prepayment?
end

#payment_status(format: nil, locale: 'en') ⇒ Object

return nil if the booking no need any payment



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'app/decorators/reservation_decorator.rb', line 128

def payment_status(format: nil, locale: 'en')
  if object.charge_type.present? && object.paid_charges.present?
    if (object.paid_amount.to_i.positive? && due_amount.to_i.positive? && due_amount.to_i < total_amount.to_i) || (object.charge_percent.to_i.positive? && object.charge_percent < 100)
      if format == 'email'
        I18n.t('date.pre_paid', locale: locale.to_sym) + "(#{object.charge_percent}%)"
      elsif object.restaurant.use_third_party_inventory?
        "Pre-Paid (#{object.format_percentage(paid_percentage_by_admin_or_owner)}%)"
      else
        "Pre-Paid (#{object.charge_percent}%)"
      end
    elsif format == 'email'
      I18n.t('date.paid', locale: locale.to_sym) + "(#{object.charge_percent}%)"
    else
      "Paid (#{object.charge_percent}%)"
    end
  elsif paid_by_voucher_full?
    I18n.t('date.paid_voucher_full', locale: locale.to_sym)
  elsif paid_by_voucher_partially?
    I18n.t('date.paid_voucher', locale: locale.to_sym)
  elsif paid_by_admin_or_owner? && object.property.is_prepayment
    "Paid (#{object.format_percentage(paid_percentage_by_admin_or_owner)}%)"
  end
end

#phone_format(format: nil) ⇒ Object



119
120
121
122
123
124
125
# File 'app/decorators/reservation_decorator.rb', line 119

def phone_format(format: nil)
  phone_lib = Phonelib.parse(object.phone || '-')
  return '' unless phone_lib.valid?

  separator = format == 'email' ? '' : ' '
  "+#{phone_lib.country_code}#{separator}#{phone_lib.raw_national}"
end

#prepaid_full?Boolean

Returns:

  • (Boolean)


21
22
23
24
25
# File 'app/decorators/reservation_decorator.rb', line 21

def prepaid_full?
  return false if object.paid_charges.blank?

  due_amount.zero?
end

#prepaid_partially?Boolean

Returns:

  • (Boolean)


27
28
29
30
31
# File 'app/decorators/reservation_decorator.rb', line 27

def prepaid_partially?
  return false if object.paid_charges.blank?

  !due_amount.zero?
end

#qrcode_data_urlObject



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'app/decorators/reservation_decorator.rb', line 326

def qrcode_data_url
  qrcode = RQRCode::QRCode.new(object.id.to_s)
  png = qrcode.as_png(
    bit_depth: 1,
    border_modules: 4,
    color_mode: ChunkyPNG::COLOR_GRAYSCALE,
    color: 'black',
    file: nil,
    fill: 'white',
    module_px_size: 6,
    resize_exactly_to: false,
    resize_gte_to: false,
    size: 500,
  )
  png.to_data_url
end

#self_check_in_timeObject



384
385
386
387
388
389
390
391
392
393
394
395
# File 'app/decorators/reservation_decorator.rb', line 384

def self_check_in_time
  self_checkin_setting = object.restaurant&.self_checkin_restaurant&.self_checkin_setting

  reservation_time = object.reservation_time
  before_booking_time = self_checkin_setting&.before_booking_time.to_i
  after_booking_time = self_checkin_setting&.after_booking_time.to_i

  checkin_start_time = reservation_time - before_booking_time.minutes
  checkin_end_time = reservation_time + after_booking_time.minutes

  [checkin_start_time, checkin_end_time]
end

#self_check_in_url(use_user_locale = false) ⇒ Object



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'app/decorators/reservation_decorator.rb', line 365

def self_check_in_url(use_user_locale = false)
  language = if use_user_locale
               object.guest_id.present? ? 'th' : (object.user&.language.presence || 'th')
             else
               MyLocaleManager.normalize_locale
             end

  self_checkin_setting = object.restaurant&.self_checkin_restaurant&.self_checkin_setting

  if self_checkin_setting.present?
    base_url = AdminSetting.self_checkin_host
    slug = self_checkin_setting.slug
    booking_id = object.id
    email = object.email

    "#{base_url}/#{language}/checkin/#{slug}?booking_id=#{booking_id}&email=#{email}"
  end
end

#status_active?Boolean

Returns:

  • (Boolean)


308
309
310
# File 'app/decorators/reservation_decorator.rb', line 308

def status_active?
  object.active && !object.no_show?
end

#status_arrived?Boolean

Returns:

  • (Boolean)


318
319
320
# File 'app/decorators/reservation_decorator.rb', line 318

def status_arrived?
  object.active && object.arrived?
end

#status_canceled?Boolean Also known as: status_cancelled?

Returns:

  • (Boolean)


312
313
314
# File 'app/decorators/reservation_decorator.rb', line 312

def status_canceled?
  !object.active && !object.no_show?
end

#status_modified?Boolean

Returns:

  • (Boolean)


322
323
324
# File 'app/decorators/reservation_decorator.rb', line 322

def status_modified?
  object.adjusted?
end

#status_no_show?Boolean

Returns:

  • (Boolean)


304
305
306
# File 'app/decorators/reservation_decorator.rb', line 304

def status_no_show?
  object.active && object.no_show?
end

#status_propertyObject



201
202
203
204
205
206
207
208
209
210
211
212
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'app/decorators/reservation_decorator.rb', line 201

def status_property
  driver = object.driver || object.build_driver
  if object.active?
    if object.service_type.to_sym == :delivery
      if object.paid_charges.present? || (paid_by_voucher_full? || paid_by_voucher_partially?)
        if driver.new_record? || driver.status.nil?
          status = I18n.t('views.d.no_driver_yet')
          text_color = '#E40028'
          bg_color = '#FFEAEB'
        elsif driver.status == 'Delivered'
          status = I18n.t('views.d.delivery_completed')
          text_color = '#2EC743'
          bg_color = '#EEFCEF'
        else
          status = object.delivery_status
          text_color = '#FBA400'
          bg_color = '#FAEFD8'
        end
      else
        status = object.paid_amount.positive? ? I18n.t('views.booking.pending_arrival') : 'Unpaid'
        text_color = '#E40028'
        bg_color = '#FFEAEB'
      end
    else
      status = case object.status_as_symbol
               when :waiting_for_payment
                 object.paid_amount.positive? ? I18n.t('views.booking.pending_arrival') : 'Unpaid'
               when :cancel_modified
                 I18n.t('views.booking.cancel_modified')
               when :cancelled
                 I18n.t('views.d.canceled')
               when :pending_arrival
                 I18n.t('views.booking.pending_arrival')
               when :arrived
                 I18n.t('views.booking.arrived')
               when :no_show
                 I18n.t('views.booking.no_show')
               when :refund
                 I18n.t('views.booking.refund')
               when :pending_confirmation
                 I18n.t('views.booking.pending_confirmation')
               when :rejected
                 I18n.t('views.booking.rejected')
               when :order_being_prepared
                 I18n.t('views.booking.order_being_prepared')
               when :cancelled_with_refund
                 I18n.t('views.booking.cancelled_with_refund')
               else
                 object.status_as_symbol ? object.status_as_symbol.to_s.split('_').join(' ').titleize : '-'
               end
      if %i[
        waiting_for_payment
        no_show
        cancelled
        rejected
        cancel_modified
        cancelled_with_refund
      ].include?(object.status_as_symbol)
        text_color = '#E40028'
        bg_color = '#FFEAEB'
      elsif %i[
        refund
        pending_confirmation
        order_being_prepared
        pending_arrival
      ].include?(object.status_as_symbol)
        text_color = '#FBA400'
        bg_color = '#FAEFD8'
      elsif object.status_as_symbol == :arrived
        text_color = '#125EAF'
        bg_color = '#DAECFF'
      else
        text_color = ''
        bg_color = ''
      end
    end
  else
    status = if object.for_locking_system?
               'Temporary booking to lock the seats'
             elsif payment_expired?
               'Payment expired'
             elsif cancelled_with_refund?
               I18n.t('views.booking.cancelled_with_refund')
             else
               I18n.t('views.d.canceled').titlecase
             end
    text_color = '#E40028'
    bg_color = '#FFEAEB'
  end
  {
    'status' => status,
    'text_color' => text_color,
    'bg_color' => bg_color,
  }
end

#third_party_indicatorObject



11
12
13
14
15
16
17
18
19
# File 'app/decorators/reservation_decorator.rb', line 11

def third_party_indicator
  if [
    ApiVendorV1::Constants::VENDOR_CHANNEL_GROUP_NAME,
  ].include?(object.channel_group_name)
    object.channel_name
  else
    ''
  end
end

#total_amountObject



33
34
35
36
37
38
39
40
41
42
# File 'app/decorators/reservation_decorator.rb', line 33

def total_amount
  # Use the numeric value returned by `total_price`
  total_price = object.total_price
  adjusted_total_price = total_price % 1 == 0 ? total_price.to_i : total_price

  Money.from_amount(
    (adjusted_total_price + object.delivery_fee.to_d.ceil),
    object.used_voucher_amount_by_restaurant_currency,
  ).amount + used_voucher_amount_by_restaurant.to_d + used_voucher_amount_by_hh.to_d
end

#used_voucher_amount_by_hhNumeric

Calculates the total amount of voucher or discount subsidized by Hungry Hub

This method iterates through all active reservation vouchers associated with the reservation. For each voucher, it checks if the voucher is present and is subsidized by Hungry Hub (i.e., not subsidized by the restaurant). Only such vouchers are included in the total.

Previously, we can use this object.used_voucher_amount_by_hh but that is not accurate when booking cancelled then mark as arrived, the value will be 0

Returns 0 if there are no active reservation vouchers.

Edge cases:

  • Returns 0 if there are no active reservation vouchers.

  • Skips vouchers that are blank or subsidized by the restaurant.

Returns:

  • (Numeric)

    The total amount of vouchers subsidized by Hungry Hub for this reservation.



75
76
77
78
79
80
81
82
83
84
85
# File 'app/decorators/reservation_decorator.rb', line 75

def used_voucher_amount_by_hh
  return 0 if object.active_reservation_vouchers.blank?

  total_used_voucher_amount_by_hh = 0
  object.active_reservation_vouchers.find_each do |rv|
    next if rv.voucher.blank? || rv.voucher.subsidized_by_restaurant?

    total_used_voucher_amount_by_hh += rv.amount
  end
  total_used_voucher_amount_by_hh
end

#used_voucher_amount_by_restaurantNumeric

Calculates the total amount of voucher or discount subsidized by the restaurant

This method iterates through all active reservation vouchers associated with the reservation. For each voucher, it checks if the voucher is present and is subsidized by the restaurant (i.e., not subsidized by Hungry Hub). Only such vouchers are included in the total.

Previously, we can use this object.used_voucher_amount_by_restaurant but that is not accurate when booking cancelled then mark as arrived, the value will be

Returns 0 if there are no active reservation vouchers.

Edge cases:

  • Returns 0 if there are no active reservation vouchers.

  • Skips vouchers that are blank or subsidized by Hungry Hub.

Returns:

  • (Numeric)

    The total amount of vouchers subsidized by the restaurant for this reservation.



103
104
105
106
107
108
109
110
111
112
113
# File 'app/decorators/reservation_decorator.rb', line 103

def used_voucher_amount_by_restaurant
  return 0 if object.active_reservation_vouchers.blank?

  total_used_voucher_amount_by_restaurant = 0
  object.active_reservation_vouchers.find_each do |rv|
    next if rv.voucher.blank? || rv.voucher.subsidized_by_hungryhub?

    total_used_voucher_amount_by_restaurant += rv.amount
  end
  total_used_voucher_amount_by_restaurant
end

#user_booking_summary(user, restaurant_id) ⇒ Object



115
116
117
# File 'app/decorators/reservation_decorator.rb', line 115

def user_booking_summary(user, restaurant_id)
  user&.formatted_booking_summary(restaurant_id) || BookingSummary.default_data
end

#user_image_tierObject



421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'app/decorators/reservation_decorator.rb', line 421

def user_image_tier
  case object.user&.user_loyalty&.loyalty_level&.name.to_s.downcase
  when 'red'
    'red-tier.png'
  when 'silver'
    'silver-tier.png'
  when 'gold'
    'gold-tier.png'
  when 'platinum'
    'platinum-tier.png'
  else
    'red-tier.png'
  end
end

#view_menu_urlObject



448
449
450
451
452
453
# File 'app/decorators/reservation_decorator.rb', line 448

def view_menu_url
  web_v2_host = AdminSetting.web_v2_host
  return '' if web_v2_host.blank?

  "#{web_v2_host}/#{I18n.locale}/view-menu/#{object.id}"
end