Class: Spree::Fulfillment

Inherits:
Object
  • Object
show all
Defined in:
app/models/spree/fulfillment.rb

Defined Under Namespace

Classes: TrackingInfo

Constant Summary collapse

CONFIG_FILE =
Rails.root.join('config/fulfillment.yml')
CONFIG =
HashWithIndifferentAccess.new(YAML.load_file(CONFIG_FILE)[Rails.env])

Class Method Summary collapse

Class Method Details

.adapterObject



25
26
27
28
29
30
31
32
33
34
35
# File 'app/models/spree/fulfillment.rb', line 25

def self.adapter
  return @adapter if defined?(@adapter)

  @adapter = config[:adapter]

  unless @adapter
    raise "Missing adapter for #{Rails.env} -- Check config/fulfillment.yml"
  end

  @adapter
end

.configObject



41
42
43
# File 'app/models/spree/fulfillment.rb', line 41

def self.config
  CONFIG
end

.fulfill(shipment) ⇒ Object



37
38
39
# File 'app/models/spree/fulfillment.rb', line 37

def self.fulfill(shipment)
  service(shipment).fulfill
end

.log(msg) ⇒ Object



45
46
47
# File 'app/models/spree/fulfillment.rb', line 45

def self.log(msg)
  Rails.logger.info "**** solidus_fulfillment: #{msg}"
end

.process_fulfillingObject

Gets tracking number and sends ship email when fulfillment house is done



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
# File 'app/models/spree/fulfillment.rb', line 71

def self.process_fulfilling
  log 'Spree::Fulfillment.process_fulfilling start'

  Spree::Shipment.fulfilling.each do |shipment|
    next if shipment.shipped?

    tracking_info = remote_tracking_info(shipment)
    log "Spree::Fulfillment.process_fulfilling: tracking_info #{tracking_info}"
    next unless tracking_info

    if tracking_info == :error
      log 'Spree::Fulfillment.process_fulfilling: Could not retrieve' \
        "tracking information for shipment #{shipment.id} (order ID: "\
        "#{shipment.number})"
      shipment.cancel
    else
      log 'Spree::Fulfillment.process_fulfilling: Tracking information: ' \
        "#{tracking_info.inspect}"
      shipment.attributes = {
        shipped_at: tracking_info.ship_time,
        tracking: "#{tracking_info.carrier}::#{tracking_info.tracking_number}"
      }
      shipment.ship!
    end
  end
end

.process_readyObject

Passes any shipments that are ready to the fulfillment service



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'app/models/spree/fulfillment.rb', line 50

def self.process_ready
  log 'Spree::Fulfillment.process_ready start'

  Spree::Shipment.ready.ids.each do |shipment_id|
    shipment = Spree::Shipment.find(shipment_id)

    next unless shipment && shipment.ready?

    log "Request to ship shipment ##{shipment.id}"
    begin
      shipment.ship!
    rescue => ex
      log "Spree::Fulfillment.process_ready: Failed to ship id #{shipment.id} due to #{ex}"
      Airbrake.notify(e) if defined?(Airbrake)
      # continue on and try other shipments so that one bad shipment doesn't
      # block an entire queue
    end
  end
end

.process_stock_levelsObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/spree/fulfillment.rb', line 98

def self.process_stock_levels
  log 'Spree::Fulfillment.process_stock_levels start'

  skus = Spree::Variant.pluck(:sku)
  default_stock_location = Spree::StockLocation.find_by(name: 'default')

  response = service.fetch_stock_levels(skus)

  response.params['stock_levels'].each do |sku, stock|
    variant = Spree::Variant.find_by(sku: sku)
    variant.stock_items.
      find_by(stock_location_id: default_stock_location.id).
      set_count_on_hand(stock)
    log "Spree::Fulfillment.process_stock_levels: variant #{variant.inspect} has a new stock level of #{stock}"
  end
end

.remote_tracking_info(shipment) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'app/models/spree/fulfillment.rb', line 115

def self.remote_tracking_info(shipment)
  response = service(shipment).fetch_tracking_data
  return unless response

  tracking_info = TrackingInfo.new(
    response.params.dig('tracking_companies', shipment.number.to_s)&.first,
    response.params.dig('tracking_numbers', shipment.number.to_s)&.first,
    response.params.dig('shipping_date_times', shipment.number.to_s)&.first
  )

  unless tracking_info.carrier &&
    tracking_info.tracking_number &&
    tracking_info.ship_time
    return :error
  end

  tracking_info.to_hash
end

.service(shipment = nil) ⇒ Object



16
17
18
19
20
21
22
23
# File 'app/models/spree/fulfillment.rb', line 16

def self.service(shipment = nil)
  ('Solidus::Fulfillment::' + "#{adapter}_fulfillment".camelize).constantize.new(shipment)
rescue NameError
  require "solidus/fulfillment/#{adapter}_fulfillment"
  retry
rescue LoadError
  log "Spree::Fulfillment.service: cannot load #{'Solidus::Fulfillment::' + "#{adapter}_fulfillment".camelize}"
end