This repository has been archived by the owner on Apr 26, 2022. It is now read-only.
forked from solidusio/solidus
-
Notifications
You must be signed in to change notification settings - Fork 1
/
order_shipping.rb
92 lines (80 loc) · 3.7 KB
/
order_shipping.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
# A service layer that handles generating Carton objects when inventory units
# are actually shipped. It also takes care of things like updating order and
# shipment states and delivering shipment emails as needed.
class Spree::OrderShipping
def initialize(order)
@order = order
end
# A shortcut method that ships *all* inventory units in a shipment in a single
# carton. See also {#ship}.
#
# @param shipment The shipment to create a carton from.
# @param external_number An optional external number. e.g. from a shipping company or 3PL.
# @param tracking_number An optional tracking number.
# @return The carton created.
def ship_shipment(shipment, external_number: nil, tracking_number: nil, suppress_mailer: false)
ship(
inventory_units: shipment.inventory_units.shippable,
stock_location: shipment.stock_location,
address: shipment.order.ship_address,
shipping_method: shipment.shipping_method,
shipped_at: Time.current,
external_number: external_number,
# TODO: Remove the `|| shipment.tracking` once Shipment#ship! is called by
# OrderShipping#ship rather than vice versa
tracking_number: tracking_number || shipment.tracking,
suppress_mailer: suppress_mailer
)
end
# Generate a carton from the supplied inventory units and marks those units
# as shipped. Also sends shipment emails if appropriate and updates
# shipment_states for associated orders.
#
# @param inventory_units The units to put in a carton together.
# @param stock_location The location the carton shipped from.
# @param address The address the carton was shipped to.
# @param shipping_method Shipping method used for the carton.
# @param shipped_at The time at which the shipment was shipped.
# @param external_number An optional external number. e.g. from a shipping company or 3PL.
# @param tracking_number An option tracking number.
# @return The carton created.
def ship(inventory_units:, stock_location:, address:, shipping_method:,
shipped_at: Time.current, external_number: nil, tracking_number: nil, suppress_mailer: false)
carton = nil
Spree::InventoryUnit.transaction do
inventory_units.each(&:ship!)
carton = Spree::Carton.create!(
stock_location: stock_location,
address: address,
shipping_method: shipping_method,
inventory_units: inventory_units,
shipped_at: shipped_at,
external_number: external_number,
tracking: tracking_number
)
end
inventory_units.map(&:shipment).uniq.each do |shipment|
# Temporarily propagate the tracking number to the shipment as well
# TODO: Remove tracking numbers from shipments.
shipment.update_attributes!(tracking: tracking_number)
next unless shipment.inventory_units.reload.all? { |iu| iu.shipped? || iu.canceled? }
# TODO: make OrderShipping#ship_shipment call Shipment#ship! rather than
# having Shipment#ship! call OrderShipping#ship_shipment. We only really
# need this `update_columns` for the specs, until we make that change.
shipment.update_columns(state: 'shipped', shipped_at: Time.current)
end
send_shipment_emails(carton) if stock_location.fulfillable? && !suppress_mailer # e.g. digital gift cards that aren't actually shipped
fulfill_order_stock_locations(stock_location)
@order.update!
carton
end
private
def fulfill_order_stock_locations(stock_location)
Spree::OrderStockLocation.fulfill_for_order_with_stock_location(@order, stock_location)
end
def send_shipment_emails(carton)
carton.orders.each do |order|
Spree::Config.carton_shipped_email_class.shipped_email(order: order, carton: carton).deliver_later
end
end
end