Class: VendorsService::GenerateMemoService
- Inherits:
-
BaseOperationService
- Object
- BaseOperationService
- VendorsService::GenerateMemoService
- Includes:
- DefaultErrorContainer, ElasticAPM::SpanHelpers, MoneyRails::ActionViewExtension
- Defined in:
- app/services/vendors_service/generate_memo_service.rb
Overview
Service for creating memo/notes for our inventory suppliers
Instance Attribute Summary collapse
-
#reservation ⇒ Object
readonly
Returns the value of attribute reservation.
Attributes inherited from BaseOperationService
Instance Method Summary collapse
-
#build_other_payment_info(reservation, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) ⇒ Object
Builds payment info string for other payment scenarios.
-
#build_paid_by_voucher_full_info(discount_cents, discount) ⇒ Object
Builds payment info string for reservations fully paid by voucher.
-
#build_paid_by_voucher_partial_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) ⇒ Object
Builds payment info string for reservations partially paid by voucher.
-
#build_partial_paid_payment_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int, charge_percent) ⇒ Object
Builds payment info string for partially paid reservations.
- #calculate_reservation_amounts(reservation) ⇒ Object
- #discount_amount(amount, currency) ⇒ Object
- #due_amount(reservation) ⇒ Object
- #execute ⇒ Object
-
#get_formatted_packages ⇒ Object
Returns memoized formatted packages array (never nil) to avoid repeated chained calls.
-
#initialize(reservation = nil, is_vendor_prepaid_reservation = false, reference_id = nil, reseller_reference_id = nil) ⇒ GenerateMemoService
constructor
A new instance of GenerateMemoService.
- #money_with_currency(price, currency) ⇒ Object
- #package_names(reservation) ⇒ Object
- #parsed_vendor_name(reservation) ⇒ Object
- #payment_method(reservation) ⇒ Object
- #prepaid_amount(reservation) ⇒ Object
-
#restaurant_packages_map(formatted) ⇒ Object
Preloads all restaurant packages referenced by formatted packages to avoid N+1 DB queries.
- #total_amount(reservation) ⇒ Object
- #update_vendor_reservation_status(reservation, vendor_reservation_memo_payment_status) ⇒ Object
Methods included from DefaultErrorContainer
#error, #error_message_simple, #merge_errors
Methods inherited from BaseOperationService
Constructor Details
#initialize(reservation = nil, is_vendor_prepaid_reservation = false, reference_id = nil, reseller_reference_id = nil) ⇒ GenerateMemoService
Returns a new instance of GenerateMemoService.
11 12 13 14 15 16 17 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 11 def initialize(reservation = nil, is_vendor_prepaid_reservation = false, reference_id = nil, reseller_reference_id = nil) super() @reservation = reservation @is_vendor_prepaid_reservation = is_vendor_prepaid_reservation @reference_id = reference_id @reseller_reference_id = reseller_reference_id end |
Instance Attribute Details
#reservation ⇒ Object (readonly)
Returns the value of attribute reservation.
9 10 11 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 9 def reservation @reservation end |
Instance Method Details
#build_other_payment_info(reservation, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) ⇒ Object
Builds payment info string for other payment scenarios.
268 269 270 271 272 273 274 275 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 268 def build_other_payment_info(reservation, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) payment_info = '' payment_info += "Discount: #{discount_cents}\n" if discount > 0 && reservation.created_by.to_sym == :user total_prepaid = reservation.paid_amount.to_i > 0 ? prepaid_amount : total_amount(reservation) payment_info += "PrePaid: #{total_prepaid}\n" payment_info += "Due: #{due_amount}\n" if due_amount_int > 0 payment_info end |
#build_paid_by_voucher_full_info(discount_cents, discount) ⇒ Object
Builds payment info string for reservations fully paid by voucher.
252 253 254 255 256 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 252 def build_paid_by_voucher_full_info(discount_cents, discount) payment_info = "100% Fully Paid by promo code\n" payment_info += "Discount: #{discount_cents}\n" if discount > 0 payment_info end |
#build_paid_by_voucher_partial_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) ⇒ Object
Builds payment info string for reservations partially paid by voucher.
259 260 261 262 263 264 265 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 259 def build_paid_by_voucher_partial_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) payment_info = "#{paid_percentage}% Paid\n" payment_info += "Discount: #{discount_cents}\n" if discount > 0 payment_info += "PrePaid: #{prepaid_amount}\n" if reservation.paid_amount.to_i > 0 payment_info += "Due: #{due_amount}\n" if due_amount_int > 0 payment_info end |
#build_partial_paid_payment_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int, charge_percent) ⇒ Object
Builds payment info string for partially paid reservations. Handles due, prepaid, and discount details. Refactored for readability, complexity, and style compliance.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 232 def build_partial_paid_payment_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int, charge_percent) having_due = reservation.paid_amount.positive? && due_amount_int.positive? && due_amount_int.to_i < reservation.total_amount.to_i payment_info = '' if having_due || (charge_percent.positive? && charge_percent < 100) payment_info += "#{paid_percentage}% Paid\n" elsif reservation.prepaid_full? payment_info += "100% Fully Paid\n" end payment_info += "Discount: #{discount_cents}\n" if discount > 0 payment_info += "PrePaid: #{prepaid_amount}\n" if reservation.paid_amount.to_i > 0 payment_info += "Due: #{due_amount}\n" if due_amount_int > 0 payment_info end |
#calculate_reservation_amounts(reservation) ⇒ Object
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 277 def calculate_reservation_amounts(reservation) adult = reservation.adult kids = reservation.kids reservation_date = reservation.date vendor_channel = reservation.booking_channel restaurant = reservation.restaurant calculator = HhPackage::ReservationPackages::ChargeCalculator.new formatted_packages = get_formatted_packages rest_packs_map = restaurant_packages_map(formatted_packages) package_bought = formatted_packages.map do |pack_bought| rest_pack_id = pack_bought['restaurant_package_id'] || pack_bought[:restaurant_package_id] rest_pack = rest_packs_map[rest_pack_id] if rest_pack.nil? BUSINESS_LOGGER.error('Restaurant package not found', package_id: rest_pack_id) APMErrorHandler.report('Missing restaurant package in vendor payment calculation', package_id: rest_pack_id) next end pack_bought['package'] = rest_pack.package pack_bought end.compact calculator.use_dynamic_pricing = vendor_channel&.support_dynamic_pricing || false begin data = calculator.calculate(package_bought, adult, kids, 0.0, restaurant, reservation_date) data.presence rescue StandardError => e BUSINESS_LOGGER.error('Error calculating reservation amount', error: e., reservation_id: reservation.id) APMErrorHandler.report('Calculator error in vendor payment calculation', error: e.) {} end end |
#discount_amount(amount, currency) ⇒ Object
193 194 195 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 193 def discount_amount(amount, currency) money_with_currency(amount, currency) end |
#due_amount(reservation) ⇒ Object
189 190 191 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 189 def due_amount(reservation) money_with_currency(reservation.due_amount, reservation.package_price_currency) end |
#execute ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 19 def execute BUSINESS_LOGGER.set_business_context(reservation_id: reservation&.id) if reservation.nil? BUSINESS_LOGGER.error('Generated Supplier Notes/Memo', error: 'Reservation is nil') return '' end special_request = reservation. occasion = reservation.dining_occasion notes = [] return notes if reservation.blank? notes << package_names(reservation) notes << "Big Group Booking\n" if reservation.group_booking? notes << payment_method(reservation) notes << "Occasion: #{occasion.name_en}\n" if occasion.present? notes << "Total Price: #{total_amount(reservation)}\n" notes << "\nCustomer Request: #{special_request}\n" if special_request.present? notes << if reservation.old_reservation_id.present? "\nReservation Old ID: #{reservation.old_reservation_id}\nReservation New ID: #{reservation.id}\n" else "\nReservation ID: #{reservation.id}\n" end is_show_in_owner_dashboard = reservation&.booking_channel&.show_in_owner_dashboard? if is_show_in_owner_dashboard vendor_name = parsed_vendor_name(reservation) notes << "Vendor: #{vendor_name}\n" if vendor_name.present? vendor_reference_id = reservation.vendor_reservation&.reference_id || @reference_id notes << "Vendor Reference ID: #{vendor_reference_id}\n" if vendor_reference_id.present? reseller_reference_id = reservation.vendor_reservation&.reseller_reference_id || @reseller_reference_id notes << "Reseller Reference ID: #{reseller_reference_id}\n" if reseller_reference_id.present? else notes << "Vendor: Hungry Hub\n" end owner = reservation.restaurant.owner notes << Rails.application.routes.url_helpers.owner_confirmation_reservation_url(owner_hash: owner.to_url_hash, reservation_hash: reservation.to_url_hash) BUSINESS_LOGGER.info('Generated Supplier Notes/Memo', memo: notes) notes.join('') rescue StandardError => e BUSINESS_LOGGER.error('Error in GenerateMemoService', error: e.) APMErrorHandler.report(e, reservation_id: reservation&.id) end |
#get_formatted_packages ⇒ Object
Returns memoized formatted packages array (never nil) to avoid repeated chained calls.
318 319 320 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 318 def get_formatted_packages @formatted_packages ||= reservation.package_obj&.formatted_packages || [] end |
#money_with_currency(price, currency) ⇒ Object
197 198 199 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 197 def money_with_currency(price, currency) HhMoney.new(price, currency).default_format end |
#package_names(reservation) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 146 def package_names(reservation) formatted_packages = get_formatted_packages return if formatted_packages.blank? package_obj = reservation.package_obj&.type_short per_party_total = total_amount(reservation) # compute once packages = [] formatted_packages.each do |package| net_price = HhMoney.new(package[:price_cents], package['price_currency']).default_format package_info = I18n.with_locale(:en) do I18n.t("views.booking.package_data_price.#{package_obj}", net_price: net_price, quantity: package[:quantity]) end package_name = I18n.with_locale(:en) do I18n.t("views.booking.package_data_name.#{package_obj}", name: package[:name]) end package_detail = "(#{package_obj.upcase}) #{package_name} #{package_info} x #{reservation.party_size}\n#{per_party_total}" packages << package_detail end "Plan: #{packages.join(', ')}\n\n" if packages.present? end |
#parsed_vendor_name(reservation) ⇒ Object
201 202 203 204 205 206 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 201 def parsed_vendor_name(reservation) vendor_name = reservation&.booking_channel&.name return '' if vendor_name.blank? vendor_name.to_s.split('HH x ').last end |
#payment_method(reservation) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 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 140 141 142 143 144 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 72 def payment_method(reservation) package_price_currency = reservation.package_price_currency charge_type = reservation.charge_type paid_amount = reservation.paid_amount.to_i due_amount_int = reservation.due_amount.to_i total_amount = reservation.total_amount.to_i charge_percent = reservation.charge_percent.to_i prepaid_amount = prepaid_amount(reservation) due_amount = due_amount(reservation) active_reservation_vouchers = reservation.active_reservation_vouchers discount = active_reservation_vouchers.map(&:amount).sum.amount if active_reservation_vouchers.present? discount = discount.to_i discount_cents = HhMoney.new(discount, package_price_currency, from_amount: true).default_format total_paid = paid_amount + discount paid_percentage = total_amount.positive? ? ((total_paid.to_f / total_amount) * 100).to_i : 0 payment_type_provider = reservation&.payment_type_provider if @is_vendor_prepaid_reservation calc_amounts = calculate_reservation_amounts(reservation) payment_info = "100% Fully Paid\n" if calc_amounts.present? payment_info += "PrePaid: #{money_with_currency(calc_amounts[:total_price_cents], reservation.package_price_currency)}\n" end vendor_reservation_memo_payment_status = :paid elsif payment_type_provider.present? && payment_type_provider == reservation.channel_uri_name # for pre-paid vendors if reservation.created_by.to_sym == :user payment_info = "100% Fully Paid\n" payment_info += "PrePaid: #{prepaid_amount}\n" if reservation.paid_amount.to_i > 0 elsif [:admin, :owner].include?(reservation.created_by.to_sym) payment_info = build_partial_paid_payment_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int, charge_percent) end vendor_reservation_memo_payment_status = :paid elsif reservation.status_as_symbol == :cancelled && (reservation&.cancel_reason&.include?('Payment canceled') || reservation&.payment_expired?) payment_info = "CANCEL BECAUSE OF PAYMENT FAILED\n" vendor_reservation_memo_payment_status = :failed elsif !reservation.payment_is_confirmed? # reservation requires payment but payment is not confirmed yet # this memo will be updated after payment is confirmed from mark_reservation_as_paid_service payment_info = "Payment is Pending\n" vendor_reservation_memo_payment_status = :pending elsif payment_type_provider.present? || reservation.paid_by_voucher_full? || reservation.paid_by_voucher_partially? if (charge_type.present? && reservation.paid_charges.present? && !reservation.paid_by_voucher_full?) || (charge_type.present? && reservation.paid_charges.present? && !reservation.paid_by_voucher_partially?) payment_info = build_partial_paid_payment_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int, charge_percent) elsif reservation.paid_by_voucher_full? payment_info = build_paid_by_voucher_full_info(discount_cents, discount) elsif reservation.paid_by_voucher_partially? payment_info = build_paid_by_voucher_partial_info(reservation, paid_percentage, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) else payment_info = build_other_payment_info(reservation, discount_cents, discount, prepaid_amount, due_amount, due_amount_int) end payment_info += "Payment Method: #{payment_type_provider.to_s.split('_').join(' ').titleize}\n" if payment_type_provider.present? && reservation.created_by.to_sym == :user vendor_reservation_memo_payment_status = :paid else payment_info = "Pay at the restaurant\n#{total_amount(reservation)}\n" vendor_reservation_memo_payment_status = :postpaid end update_vendor_reservation_status(reservation, vendor_reservation_memo_payment_status) payment_info rescue StandardError => e BUSINESS_LOGGER.error('Error in payment_method', error: e.) APMErrorHandler.report(e, reservation_id: reservation&.id) end |
#prepaid_amount(reservation) ⇒ Object
185 186 187 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 185 def prepaid_amount(reservation) money_with_currency(reservation.paid_amount, reservation.package_price_currency) end |
#restaurant_packages_map(formatted) ⇒ Object
Preloads all restaurant packages referenced by formatted packages to avoid N+1 DB queries. Returns a hash keyed by restaurant_package_id.
324 325 326 327 328 329 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 324 def restaurant_packages_map(formatted) ids = formatted.map { |p| p['restaurant_package_id'] || p[:restaurant_package_id] }.compact return {} if ids.empty? HhPackage::RestaurantPackage.includes(:package, :restaurant).where(id: ids).index_by(&:id) end |
#total_amount(reservation) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 171 def total_amount(reservation) package_price_currency = reservation.package_price_currency total_detail_amount = HhMoney.new(0, package_price_currency).default_format if reservation.package.present? total_net_amount = Money.from_amount( (reservation.total_amount - reservation.original_delivery_fee.to_d), package_price_currency ) total_detail_amount = HhMoney.new(total_net_amount, package_price_currency).default_format end total_detail_amount end |
#update_vendor_reservation_status(reservation, vendor_reservation_memo_payment_status) ⇒ Object
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'app/services/vendors_service/generate_memo_service.rb', line 208 def update_vendor_reservation_status(reservation, vendor_reservation_memo_payment_status) vr = reservation.vendor_reservation return if vr.blank? vr.update!(supplier_memo_payment_status: vendor_reservation_memo_payment_status) BUSINESS_LOGGER.info( 'Updated supplier_memo_payment_status', vendor_reservation_id: vr.id, status: vendor_reservation_memo_payment_status, reservation_id: reservation.id, ) rescue StandardError => e BUSINESS_LOGGER.error( 'Failed to update supplier_memo_payment_status', error: e., reservation_id: reservation&.id, vendor_reservation_id: vr&.id, ) APMErrorHandler.report(e, reservation_id: reservation&.id) end |