Class: Spree::Shipment

Inherits:
Base
  • Object
show all
Extended by:
DisplayMoney
Defined in:
app/models/spree/shipment.rb

Overview

An order's planned shipments including tracking and cost.

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Methods included from DisplayMoney

money_methods

Methods inherited from Base

display_includes, #initialize_preference_defaults, page, preference

Methods included from Preferences::Preferable

#default_preferences, #defined_preferences, #get_preference, #has_preference!, #has_preference?, #preference_default, #preference_type, #set_preference

Instance Attribute Details

- (Object) special_instructions

TODO: remove the suppress_mailer temporary variable once we are calling 'ship' from outside of the state machine and can actually pass variables through.



21
22
23
# File 'app/models/spree/shipment.rb', line 21

def special_instructions
  @special_instructions
end

- (Object) suppress_mailer

TODO: remove the suppress_mailer temporary variable once we are calling 'ship' from outside of the state machine and can actually pass variables through.



21
22
23
# File 'app/models/spree/shipment.rb', line 21

def suppress_mailer
  @suppress_mailer
end

Instance Method Details

- (Object) add_shipping_method(shipping_method, selected = false)



95
96
97
# File 'app/models/spree/shipment.rb', line 95

def add_shipping_method(shipping_method, selected = false)
  shipping_rates.create(shipping_method: shipping_method, selected: selected, cost: cost)
end

- (Object) address



360
361
362
363
# File 'app/models/spree/shipment.rb', line 360

def address
  Spree::Deprecation.warn("Calling Shipment#address is deprecated. Use Order#ship_address instead", caller)
  order.ship_address if order
end

- (Object) after_cancel



99
100
101
# File 'app/models/spree/shipment.rb', line 99

def after_cancel
  manifest.each { |item| manifest_restock(item) }
end

- (Object) after_resume



103
104
105
# File 'app/models/spree/shipment.rb', line 103

def after_resume
  manifest.each { |item| manifest_unstock(item) }
end

- (Boolean) backordered?

Returns:

  • (Boolean)


107
108
109
# File 'app/models/spree/shipment.rb', line 107

def backordered?
  inventory_units.any?(&:backordered?)
end

- (Boolean) can_transition_from_canceled_to_ready?

Returns:

  • (Boolean)


87
88
89
# File 'app/models/spree/shipment.rb', line 87

def can_transition_from_canceled_to_ready?
  can_transition_from_pending_to_ready?
end

- (Boolean) can_transition_from_pending_to_ready?

Returns:

  • (Boolean)


81
82
83
84
85
# File 'app/models/spree/shipment.rb', line 81

def can_transition_from_pending_to_ready?
  order.can_ship? &&
    inventory_units.all? { |iu| iu.allow_ship? || iu.canceled? } &&
    (order.paid? || !Spree::Config[:require_payment_to_ship])
end

- (Boolean) can_transition_from_pending_to_shipped?

Returns:

  • (Boolean)


77
78
79
# File 'app/models/spree/shipment.rb', line 77

def can_transition_from_pending_to_shipped?
  !requires_shipment?
end

- (Object) currency



111
112
113
# File 'app/models/spree/shipment.rb', line 111

def currency
  order ? order.currency : Spree::Config[:currency]
end

- (Object) determine_state(order)

Determines the appropriate state according to the following logic:

canceled if order is canceled pending unless order is complete and order.payment_state is paid shipped if already shipped (ie. does not change the state) ready all other cases



227
228
229
230
231
232
233
234
235
236
# File 'app/models/spree/shipment.rb', line 227

def determine_state(order)
  return 'canceled' if order.canceled?
  return 'shipped' if shipped?
  return 'pending' unless order.can_ship?
  if can_transition_from_pending_to_ready?
    'ready'
  else
    'pending'
  end
end

- (Object) discounted_cost Also known as: discounted_amount



115
116
117
# File 'app/models/spree/shipment.rb', line 115

def discounted_cost
  cost + promo_total
end

- (Boolean) editable_by?(_user)

Returns:

  • (Boolean)


120
121
122
# File 'app/models/spree/shipment.rb', line 120

def editable_by?(_user)
  !shipped?
end

- (Object) final_price



124
125
126
# File 'app/models/spree/shipment.rb', line 124

def final_price
  cost + adjustment_total
end

- (Object) final_price_with_items



128
129
130
# File 'app/models/spree/shipment.rb', line 128

def final_price_with_items
  item_cost + final_price
end

- (Object) finalize!

Decrement the stock counts for all pending inventory units in this shipment and mark. Any previous non-pending inventory units are skipped as their stock had already been allocated.



136
137
138
139
140
141
142
143
# File 'app/models/spree/shipment.rb', line 136

def finalize!
  transaction do
    pending_units = inventory_units.select(&:pending?)
    pending_manifest = Spree::ShippingManifest.new(inventory_units: pending_units)
    pending_manifest.items.each { |item| manifest_unstock(item) }
    Spree::InventoryUnit.finalize_units!(pending_units)
  end
end

- (Boolean) include?(variant)

Returns:

  • (Boolean)


145
146
147
# File 'app/models/spree/shipment.rb', line 145

def include?(variant)
  inventory_units_for(variant).present?
end

- (Object) inventory_units_for(variant)



149
150
151
# File 'app/models/spree/shipment.rb', line 149

def inventory_units_for(variant)
  inventory_units.where(variant_id: variant.id)
end

- (Object) inventory_units_for_item(line_item, variant = nil)



153
154
155
# File 'app/models/spree/shipment.rb', line 153

def inventory_units_for_item(line_item, variant = nil)
  inventory_units.where(line_item_id: line_item.id, variant_id: line_item.variant.id || variant.id)
end

- (Object) item_cost



157
158
159
# File 'app/models/spree/shipment.rb', line 157

def item_cost
  line_items.map(&:final_amount).sum
end

- (Object) line_items



161
162
163
# File 'app/models/spree/shipment.rb', line 161

def line_items
  inventory_units.includes(:line_item).map(&:line_item).uniq
end

- (Object) manifest



202
203
204
# File 'app/models/spree/shipment.rb', line 202

def manifest
  @manifest ||= Spree::ShippingManifest.new(inventory_units: inventory_units).items
end

- (Object) pre_tax_amount



165
166
167
# File 'app/models/spree/shipment.rb', line 165

def pre_tax_amount
  discounted_amount - included_tax_total
end

- (Boolean) ready_or_pending?

Returns:

  • (Boolean)


169
170
171
# File 'app/models/spree/shipment.rb', line 169

def ready_or_pending?
  ready? || pending?
end

- (Object) refresh_rates



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'app/models/spree/shipment.rb', line 173

def refresh_rates
  return shipping_rates if shipped? || order.completed?
  return [] unless can_get_rates?

  # StockEstimator.new assigment below will replace the current shipping_method
  original_shipping_method_id = shipping_method.try!(:id)

  new_rates = Spree::Config.stock.estimator_class.new.shipping_rates(to_package)

  # If one of the new rates matches the previously selected shipping
  # method, select that instead of the default provided by the estimator.
  # Otherwise, keep the default.
  selected_rate = new_rates.detect{ |rate| rate.shipping_method_id == original_shipping_method_id }
  if selected_rate
    new_rates.each do |rate|
      rate.selected = (rate == selected_rate)
    end
  end

  self.shipping_rates = new_rates
  save!

  shipping_rates
end

- (Boolean) requires_shipment?

Returns:

  • (Boolean)


356
357
358
# File 'app/models/spree/shipment.rb', line 356

def requires_shipment?
  !stock_location || stock_location.fulfillable?
end

- (Object) selected_shipping_rate



198
199
200
# File 'app/models/spree/shipment.rb', line 198

def selected_shipping_rate
  shipping_rates.detect(&:selected?)
end

- (Object) selected_shipping_rate_id



206
207
208
# File 'app/models/spree/shipment.rb', line 206

def selected_shipping_rate_id
  selected_shipping_rate.try(:id)
end

- (Object) selected_shipping_rate_id=(id)



210
211
212
213
214
215
216
217
218
219
# File 'app/models/spree/shipment.rb', line 210

def selected_shipping_rate_id=(id)
  selected_shipping_rate.update(selected: false) if selected_shipping_rate
  new_rate = shipping_rates.detect { |rate| rate.id == id.to_i }
  fail(
    ArgumentError,
    "Could not find shipping rate id #{id} for shipment #{number}"
  ) unless new_rate
  new_rate.update(selected: true)
  save!
end

- (Object) set_up_inventory(state, variant, order, line_item)



238
239
240
241
242
243
244
245
# File 'app/models/spree/shipment.rb', line 238

def set_up_inventory(state, variant, order, line_item)
  inventory_units.create(
    state: state,
    variant_id: variant.id,
    order_id: order.id,
    line_item_id: line_item.id
  )
end

- (Object) shipped=(value)



247
248
249
250
# File 'app/models/spree/shipment.rb', line 247

def shipped=(value)
  return unless value == '1' && shipped_at.nil?
  self.shipped_at = Time.current
end

- (Object) shipping_method



252
253
254
# File 'app/models/spree/shipment.rb', line 252

def shipping_method
  selected_shipping_rate.try(:shipping_method) || shipping_rates.first.try(:shipping_method)
end

- (Object) tax_total

Only one of either included_tax_total or additional_tax_total is set This method returns the total of the two. Saves having to check if tax is included or additional.



259
260
261
# File 'app/models/spree/shipment.rb', line 259

def tax_total
  included_tax_total + additional_tax_total
end

- (Object) to_package



263
264
265
266
267
268
269
270
# File 'app/models/spree/shipment.rb', line 263

def to_package
  package = Stock::Package.new(stock_location)
  package.shipment = self
  inventory_units.includes(:variant).joins(:variant).group_by(&:state).each do |state, state_inventory_units|
    package.add_multiple state_inventory_units, state.to_sym
  end
  package
end

- (Object) to_param



272
273
274
# File 'app/models/spree/shipment.rb', line 272

def to_param
  number
end

- (Object) tracking_url



276
277
278
279
280
# File 'app/models/spree/shipment.rb', line 276

def tracking_url
  return nil unless tracking && shipping_method

  @tracking_url ||= shipping_method.build_tracking_url(tracking)
end

- (Object) transfer_to_location(variant, quantity, stock_location)



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'app/models/spree/shipment.rb', line 323

def transfer_to_location(variant, quantity, stock_location)
  if quantity <= 0
    raise ArgumentError
  end

  transaction do
    new_shipment = order.shipments.create!(stock_location: stock_location)

    order.contents.remove(variant, quantity, { shipment: self })
    order.contents.add(variant, quantity, { shipment: new_shipment })

    refresh_rates
    save!
    new_shipment.save!
  end
end

- (Object) transfer_to_shipment(variant, quantity, shipment_to_transfer_to)



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'app/models/spree/shipment.rb', line 340

def transfer_to_shipment(variant, quantity, shipment_to_transfer_to)
  if quantity <= 0 || self == shipment_to_transfer_to
    raise ArgumentError
  end

  transaction do
    order.contents.remove(variant, quantity, { shipment: self })
    order.contents.add(variant, quantity, { shipment: shipment_to_transfer_to })

    refresh_rates
    save!
    shipment_to_transfer_to.refresh_rates
    shipment_to_transfer_to.save!
  end
end

- (Object) update!(order)

Updates various aspects of the Shipment while bypassing any callbacks. Note that this method takes an explicit reference to the Order object. This is necessary because the association actually has a stale (and unsaved) copy of the Order and so it will not yield the correct results.



311
312
313
314
315
316
317
318
319
320
321
# File 'app/models/spree/shipment.rb', line 311

def update!(order)
  old_state = state
  new_state = determine_state(order)
  if new_state != old_state
    update_columns(
      state: new_state,
      updated_at: Time.current
    )
    after_ship if new_state == 'shipped'
  end
end

- (Object) update_amounts



282
283
284
285
286
287
288
289
290
291
292
# File 'app/models/spree/shipment.rb', line 282

def update_amounts
  if selected_shipping_rate
    self.cost = selected_shipping_rate.cost
    if changed?
      update_columns(
        cost: cost,
        updated_at: Time.current
      )
    end
  end
end

- (Object) update_attributes_and_order(params = {})

Update Shipment and make sure Order states follow the shipment changes



295
296
297
298
299
300
301
302
303
304
305
306
# File 'app/models/spree/shipment.rb', line 295

def update_attributes_and_order(params = {})
  if update_attributes params
    if params.key? :selected_shipping_rate_id
      # Changing the selected Shipping Rate won't update the cost (for now)
      # so we persist the Shipment#cost before running `order.update!`
      update_amounts
      order.update!
    end

    true
  end
end