Class: Order::CreateVcProcurementOrdersFromCsv
- Inherits:
-
BaseService
- Object
- BaseService
- Order::CreateVcProcurementOrdersFromCsv
- Defined in:
- app/services/order/create_vc_procurement_orders_from_csv.rb
Defined Under Namespace
Classes: Result
Instance Attribute Summary collapse
-
#csv_attachment ⇒ Object
Returns the value of attribute csv_attachment.
-
#csv_file_path ⇒ Object
Returns the value of attribute csv_file_path.
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#user ⇒ Object
Returns the value of attribute user.
Instance Method Summary collapse
-
#initialize(options = {}) ⇒ CreateVcProcurementOrdersFromCsv
constructor
A new instance of CreateVcProcurementOrdersFromCsv.
- #process ⇒ Object
Methods inherited from BaseService
#log_debug, #log_error, #log_info, #log_warning, #options, #tagged_logger
Constructor Details
#initialize(options = {}) ⇒ CreateVcProcurementOrdersFromCsv
Returns a new instance of CreateVcProcurementOrdersFromCsv.
8 9 10 11 12 13 14 |
# File 'app/services/order/create_vc_procurement_orders_from_csv.rb', line 8 def initialize( = {}) @options = @logger = [:logger] || Rails.logger @csv_attachment = [:csv_attachment] # this comes in as an http form attachment @csv_file_path = @csv_attachment.tempfile.path.to_s # this is the temp file path @user = [:user] # this is the user that is doing the import end |
Instance Attribute Details
#csv_attachment ⇒ Object
Returns the value of attribute csv_attachment.
2 3 4 |
# File 'app/services/order/create_vc_procurement_orders_from_csv.rb', line 2 def @csv_attachment end |
#csv_file_path ⇒ Object
Returns the value of attribute csv_file_path.
2 3 4 |
# File 'app/services/order/create_vc_procurement_orders_from_csv.rb', line 2 def csv_file_path @csv_file_path end |
#logger ⇒ Object
Returns the value of attribute logger.
2 3 4 |
# File 'app/services/order/create_vc_procurement_orders_from_csv.rb', line 2 def logger @logger end |
#user ⇒ Object
Returns the value of attribute user.
2 3 4 |
# File 'app/services/order/create_vc_procurement_orders_from_csv.rb', line 2 def user @user end |
Instance Method Details
#process ⇒ Object
16 17 18 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 70 71 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 |
# File 'app/services/order/create_vc_procurement_orders_from_csv.rb', line 16 def process errors = [] orders = [] info_msgs = [] CSV.foreach(csv_file_path, liberal_parsing: true, headers: true, encoding: 'iso-8859-1:utf-8') do |row| Order.transaction do if row.first[1].present? # skip blank rows po_number = row['PO'] vendor_code = row['Vendor'] ship_to_location = row['Ship to location'] # 'MSP6 - LAKEVILLE, MN' ship_to_code = ship_to_location.split(' - ').first # MSP6 asin = row['ASIN'] sku = row['Model Number'] window_start = begin Date.strptime(row['Window Start'] || row['Window start'], '%m/%d/%Y') rescue StandardError errors << 'Cannot parse date from Window Start column' end window_end = begin Date.strptime(row['Window End'] || row['Window end'], '%m/%d/%Y') rescue StandardError errors << 'Cannot parse date from Window End column' end qty_requested = row['Quantity Requested'].to_i unit_cost = row['Unit Cost'].to_f is_bulk_order = (window_start > 1.week.from_now) # determine Amazon VC customer record for long-term bulk order vs short-term replenishment order based on 1 week from now shipping window vendor_code_to_customer_id_map = is_bulk_order ? CustomerConstants::AMAZON_VENDOR_CENTRAL_BULK_ORDER_CUSTOMER_ID_BY_VENDOR_CODE : CustomerConstants::AMAZON_VENDOR_CENTRAL_CUSTOMER_ID_BY_VENDOR_CODE # get appropruate type of Amazon VC customer customer = Customer.find(vendor_code_to_customer_id_map[vendor_code.to_sym]) # get customer from vendor code errors << "Cannot find a corresponding Amazon VC procurement customer for vendor code #{vendor_code}!" unless customer.present? # here we want to only process non-cancelled pending orders, because multiple lines can be added to the same order within the CSV, but we don't want to touch an order that is already processing, i.e. beyond pending, so find or create the order in pending state order = customer&.orders&.not_cancelled&.where(edi_po_number: po_number)&.first || customer&.orders&.new(edi_po_number: po_number, state: 'pending') if customer unless customer.present? && order.pending? errors << "Order #{order.reference_number} with PO #{po_number} in state: #{order.state} already exists! Skipping import of ASIN: #{asin} (qty #{qty_requested}) for PO #{po_number}. If you are reimporting, please cancel this order and try importing again." end ci = customer&.catalog&.catalog_items&.by_asins([asin])&.first # find corresponding Amazon VC customer catalog item with the ASIN errors << ("Item with ASIN: #{asin} (SKU: #{sku}) not found in customer catalog #{customer&.catalog&.name}.") if ci&.id.nil? # here we don't want to keep on adding more quantity if re-importing the same CSV, so just find or create the line item and set its quantity and price unless ci&.id.nil? line_updated = false li = order&.line_items&.detect do |li| li.item&.amazon_asin == asin end || order.add_line_item(catalog_item_id: ci.id, quantity: qty_requested, price: unit_cost, discounted_price: unit_cost, edi_unit_cost: unit_cost) end line_updated = li.update(quantity: qty_requested, price: unit_cost, discounted_price: unit_cost, edi_unit_cost: unit_cost) unless li&.id.nil? # we want everything to work # report errors on line item update if line item is present but not updated errors << ("Line item with ASIN: #{asin} (SKU: #{sku}) in order #{order.reference_number} with PO #{po_number} did not update correctly: #{li.errors_to_s}.") if !line_updated && li&.id.present? if customer.present? && order&.pending? && ci&.id.present? && li&.id.present? && line_updated # finally, assuming everything went well, set the order address if possible and flag if address was not found by location ship_to_code, add notes etc. order.shipping_address_id = customer.addresses.where(person_name_override: ship_to_code)&.first&.id order.requested_ship_on_or_after = window_start order.requested_ship_before = window_end order.save order.reload order.activities.create(new_note: "Created or updated by import of #{&.original_filename} on #{DateTime.now} by #{user.name}.") order.activities.create(new_note: "Ship Window: #{window_start} - #{window_end}") errors += order.errors. unless order.valid? orders << order order_msg = "Order #{order.reference_number} with PO <strong>#{po_number}</strong>, created or updated in customer #{customer.name}, with line items: #{order.line_items.parents_only.to_a.map do |l| "#{l.quantity.abs} x #{l.sku}/#{l&.item&.amazon_asin} at unit cost: $#{li.discounted_price}" end.join(', ')}." info_msgs << order_msg order.activities.create(new_note: order_msg) if order&.shipping_address.nil? # report if address was not found by location ship_to_code, we can't create the address because we only get a basic location snippet in the CSV ship_to_msg = "<strong>Ship to location #{ship_to_location} not found in customer addresses</strong>, please create it and set as the shipping address for this order." order.activities.create(new_note: ship_to_msg) info_msgs << ship_to_msg end end end rescue StandardError => e offending_line = e.backtrace.first # Gets the first line of the backtrace (most likely the line that caused the error) errors << "Exception: #{e} at #{offending_line}, offending row: #{row}" ErrorReporting.error(e, line: offending_line) end end orders.uniq! orders.each do |order| if order.valid? order.retrieve_shipping_costs order.reload order.payments.build.tap do |payment| payment.category = Payment::PO payment.currency = order.currency payment.amount = order.total payment.state = 'authorized' payment.po_number = order.edi_po_number payment.delivery = order.deliveries.quoting.first payment.save! end order.request_estimated_packaging! end rescue StandardError => e # report any errors errors << "Exception in order #{order.reference_number} with PO #{order.edi_po_number}: #{e}" ErrorReporting.error(e) end # End begin rescue block Result.new(orders: orders, info_msgs: info_msgs, errors: errors) end |