Class: Edi::Amazon::FbaOrderMessageProcessor
- Inherits:
-
BaseEdiService
- Object
- BaseService
- BaseEdiService
- Edi::Amazon::FbaOrderMessageProcessor
- Defined in:
- app/services/edi/amazon/fba_order_message_processor.rb
Defined Under Namespace
Classes: BatchProcessResult, LineCreationResult, Result
Constant Summary
Constants included from Edi::AddressAbbreviator
Edi::AddressAbbreviator::MAX_LENGTH
Instance Attribute Summary
Attributes inherited from BaseEdiService
Instance Method Summary collapse
- #create_invoice_shipping_address(order_hash) ⇒ Object
- #customer(segment = nil) ⇒ Object
- #is_vine_promotion_order?(order_hash) ⇒ Boolean
-
#process(edi_logs = nil, edi_transaction_id: nil) ⇒ Object
Picks up the edi communication log in the queue ready to process, generate acknowledgements.
-
#process_order(order_hash = nil) ⇒ Object
Process a single FBA order into a consignment invoice.
-
#process_orders(orders_data, edi_transaction_id: nil, edi_log_id: nil) ⇒ Object
Iterates through the batch order data.
Methods inherited from BaseEdiService
#duplicate_po_already_notified?, #initialize, #mark_duplicate_po_as_notified, #report_order_creation_issues, #safe_process_edi_communication_log
Methods included from Edi::AddressAbbreviator
#abbreviate_street, #collect_street_originals, #record_address_abbreviation_notes
Methods inherited from BaseService
#initialize, #log_debug, #log_error, #log_info, #log_warning, #logger, #options, #tagged_logger
Constructor Details
This class inherits a constructor from Edi::BaseEdiService
Instance Method Details
#create_invoice_shipping_address(order_hash) ⇒ Object
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 |
# File 'app/services/edi/amazon/fba_order_message_processor.rb', line 143 def create_invoice_shipping_address(order_hash) # { # "StateOrRegion" => "MN", # "AddressLine1" => "1805 HAVEN RD", # "Phone" => "+1 929-436-4790 ext. 38661", # "PostalCode" => "56345-2286", # "City" => "LITTLE FALLS", # "CountryCode" => "US", # "AddressType" => "Commercial", # "Name" => "XXX XXX" # } # { # "StateOrRegion": "Manitoba", # "AddressLine1": "PO Box 412", # "PostalCode": "R0L0C0", # "City": "Benito", # "CountryCode": "CA", # "Name": "David Pleli" # } if order_hash.dig(:ShippingAddressPii).nil? && order_hash.dig(:ShippingAddress).nil? # || is_vine_promotion_order?(order_hash) # per @orders team use warehouse address fpr Vine promo FBAs # later overidden by Prabhakar, who said to use address if we get it, it is not available via the Seller Central portal address = customer.store.warehouse_address else raw_street1 = order_hash.dig(:ShippingAddressPii, :AddressLine1) || order_hash.dig(:ShippingAddress, :AddressLine1) || order_hash.dig(:ShippingAddress, :City) raw_street2 = order_hash.dig(:ShippingAddressPii, :AddressLine2) address = Address.new # Here we are using the ShippingAddressPii we extracted using a restricted data token address.person_name_override = order_hash.dig(:ShippingAddressPii, :Name)&.to_s&.titleize&.strip || order_hash.dig(:BuyerInfo, :BuyerEmail) || 'Customer' address.street1 = abbreviate_street(raw_street1) address.street2 = abbreviate_street(raw_street2) address.city = order_hash.dig(:ShippingAddressPii, :City) address.country_iso = order_hash.dig(:ShippingAddressPii, :CountryCode) state_or_province_string_or_code = order_hash.dig(:ShippingAddressPii, :StateOrRegion) state_or_province_string_or_code = 'Quebec' if state_or_province_string_or_code == 'QU' # don't ask me why they send this code instead of spelled-out 'Quebec', like the other provinces address.state_code = State.code_for_string(state_or_province_string_or_code, countries_iso3: [Country.iso3_for_string(address.country_iso)]) # we get state code for US but Province name for Canada! address.zip = order_hash.dig(:ShippingAddressPii, :PostalCode).to_s.upcase.delete(' ').strip address.disable_address_correction = true address.override_all_address_validation = true address.save! end address end |
#customer(segment = nil) ⇒ Object
15 16 17 |
# File 'app/services/edi/amazon/fba_order_message_processor.rb', line 15 def customer(segment = nil) orchestrator.customer(segment) end |
#is_vine_promotion_order?(order_hash) ⇒ Boolean
188 189 190 |
# File 'app/services/edi/amazon/fba_order_message_processor.rb', line 188 def is_vine_promotion_order?(order_hash) order_hash.dig(:OrderItems)&.any? { |line_hash| line_hash.dig(:PromotionIds)&.any? { |pid| pid&.downcase&.include?('vine.') } } end |
#process(edi_logs = nil, edi_transaction_id: nil) ⇒ Object
Picks up the edi communication log in the queue ready to process, generate acknowledgements
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 |
# File 'app/services/edi/amazon/fba_order_message_processor.rb', line 20 def process(edi_logs = nil, edi_transaction_id: nil) edi_logs ||= EdiCommunicationLog.requiring_processing.where(partner: orchestrator.partner, category: 'fba_order_batch') edi_logs = [edi_logs].flatten # This way you can pass a single edi communication log # Wrap in one big transaction batch_process_results = [] edi_logs.each do |edi_log| log_info "Starting processing edi communication log #{edi_log.id}" EdiCommunicationLog.transaction do # Process the orders in the batch batch_process_result = process_orders(edi_log.data, edi_transaction_id: edi_transaction_id, edi_log_id: edi_log.id) # Record some meta data in file info edi_log.file_info ||= {} edi_log.file_info[:orders_in_batch] = batch_process_result.orders_in_batch batch_process_results << batch_process_result edi_log.complete! # Mark our edi log as processed, we need some error handling at one point # Associate the created invoices batch_process_result.invoices_created.each do |invoice| edi_log.edi_documents.create(invoice: invoice) end rescue StandardError => e edi_log.notes = "#{e} at #{e&.backtrace_locations}" edi_log.error ErrorReporting.error(e, edi_communication_log_id: edi_log.id) # End begin rescue block end # End transaction end # End edi log iteration Result.new(batch_process_results: batch_process_results) end |
#process_order(order_hash = nil) ⇒ Object
Process a single FBA order into a consignment invoice
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 |
# File 'app/services/edi/amazon/fba_order_message_processor.rb', line 88 def process_order(order_hash = nil) cust = customer fba_store = Store.find(orchestrator.fba_store_id) purchase_date = Time.zone.parse(order_hash.dig(:PurchaseDate)) invoice = Invoice.new( company: fba_store.company, customer: cust, store: fba_store, invoice_type: Invoice::CI, total: BigDecimal(order_hash.dig(:OrderTotal, :Amount).to_s), currency: order_hash.dig(:OrderTotal, :CurrencyCode), document_date: Time.zone.now.to_date, gl_date: purchase_date.to_date, tax_date: purchase_date.to_date, due_date: Time.zone.now.to_date, shipped_date: purchase_date.to_date, terms: 'Due', po_number: order_hash[:AmazonOrderId], report_grouping: 'E-commerce - Amazon', state: 'draft', transmission_state: 'awaiting_transmission', tax_exempt: false # discount: 0.0, # shipping_cost: 0.0, # shipping_coupon: 0.0, # profit: 0.0, # profit_consolidated: 0.0 ) Invoice.transaction do # Set addresses invoice.shipping_address = create_invoice_shipping_address(order_hash) invoice.billing_address_id = cust.billing_address_id invoice.billing_customer_id = cust.id # Set the consignment offset account invoice.gl_offset_account = LedgerCompanyAccount.for_company_and_account(invoice.company_id, TRADE_ACCOUNTS_RECEIVABLE_ACCOUNT) # Create line items and calculate totals line_creation_result = create_line_items(invoice, fba_store, order_hash) raise line_creation_result. unless line_creation_result.all_skus_valid # Set consolidated amounts invoice.revenue_consolidated = line_creation_result.line_total invoice.consolidated_exchange_rate = invoice.currency == CONSOLIDATED_CURRENCY ? 1.0 : ExchangeRate.get_exchange_rate(invoice.currency, CONSOLIDATED_CURRENCY, invoice.gl_date) invoice.save! # Add notes invoice.quick_note('Amazon FBA Order') invoice.quick_note('Replacement Order') if order_hash[:IsReplacementOrder].to_b end invoice end |
#process_orders(orders_data, edi_transaction_id: nil, edi_log_id: nil) ⇒ Object
Iterates through the batch order data
51 52 53 54 55 56 57 58 59 60 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 |
# File 'app/services/edi/amazon/fba_order_message_processor.rb', line 51 def process_orders(orders_data, edi_transaction_id: nil, edi_log_id: nil) json_hash = JSON.parse(orders_data).with_indifferent_access invoices_created = [] orders_in_batch = 0 (json_hash.dig(:payload, :Orders) || []).each do |order_hash| log_info "Processing order #{order_hash.inspect}" orders_in_batch += 1 po_number = order_hash[:AmazonOrderId] begin # Check for existing invoices with this PO number existing_invoices = Invoice.where(po_number: po_number).where('created_at > ?', 12.months.ago) is_replacement_order = order_hash[:IsReplacementOrder].to_b is_shipped_order = order_hash[:OrderStatus] == 'Shipped' if existing_invoices.none? && is_shipped_order && !is_replacement_order # skip orders not in Shipped status and also replacement orders, so accounting team can deal with replacement orders manually for now invoices_created << process_order(order_hash) elsif is_replacement_order || !is_shipped_order reason_blurb = "we do not process replacement FBA orders" if is_replacement_order reason_blurb = "we do not process FBA orders unless they are in Shipped status" if !is_shipped_order subj = "EDI FBA invoice message for orchestrator: #{orchestrator.partner}, SKIPPED, order message PO: #{po_number}, reason: #{reason_blurb}." msg = "We skipped processing amazon FBA order #{po_number} with orchestrator #{orchestrator.partner}, and edi log id #{edi_log_id}, reason: #{reason_blurb}." InternalMailer.notify_edi_admin_of_warning(subj, msg).deliver_later end rescue StandardError => e subj = "EDI FBA invoice message for orchestrator: #{orchestrator.partner}, ERROR, SKIPPED, order message PO: #{po_number}, #{e.}" msg = "Exception #{e.} while processing amazon FBA order #{po_number} with orchestrator #{orchestrator.partner}, and edi log id #{edi_log_id}" ErrorReporting.error e, msg InternalMailer.notify_edi_admin_of_warning(subj, msg).deliver_later end end # As a temporary measure, notify ap, orders team and EDI Admin of new Amazon Seller Central orders InternalMailer.amazon_seller_central_fba_ci_invoices_notification(invoices_created).deliver_later if invoices_created.any? BatchProcessResult.new(batch_number: nil, invoices_created: invoices_created, orders_in_batch: orders_in_batch) end |