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
/
package.rb
140 lines (122 loc) · 5.1 KB
/
package.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
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
module Spree
module Stock
class Package
attr_reader :stock_location, :contents
attr_accessor :shipment
# @param stock_location [Spree::StockLocation] the stock location this package originates from
# @param contents [Array<Spree::Stock::ContentItem>] the contents of this package
def initialize(stock_location, contents = [])
@stock_location = stock_location
@contents = contents
end
# Adds an inventory unit to this package.
#
# @param inventory_unit [Spree::InventoryUnit] an inventory unit to be
# added to this package
# @param state [:on_hand, :backordered] the state of the item to be
# added to this package
def add(inventory_unit, state = :on_hand)
contents << ContentItem.new(inventory_unit, state) unless find_item(inventory_unit)
end
# Adds multiple inventory units to this package.
#
# @param inventory_units [Array<Spree::InventoryUnit>] a collection of
# inventory units to be added to this package
# @param state [:on_hand, :backordered] the state of the items to be
# added to this package
def add_multiple(inventory_units, state = :on_hand)
inventory_units.each { |inventory_unit| add(inventory_unit, state) }
end
# Removes a given inventory unit from this package.
#
# @param inventory_unit [Spree::InventoryUnit] the inventory unit to be
# removed from this package
def remove(inventory_unit)
item = find_item(inventory_unit)
@contents -= [item] if item
end
# @return [Spree::Order] the order associated with this package
def order
# Fix regression that removed package.order.
# Find it dynamically through an inventory_unit.
contents.detect { |item| !!item.try(:inventory_unit).try(:order) }.try(:inventory_unit).try(:order)
end
# @return [Float] the summed weight of the contents of this package
def weight
contents.sum(&:weight)
end
# @return [Array<Spree::Stock::ContentItem>] the content items in this
# package which are on hand
def on_hand
contents.select(&:on_hand?)
end
# @return [Array<Spree::Stock::ContentItem>] the content items in this
# package which are backordered
def backordered
contents.select(&:backordered?)
end
# Find a content item in this package by inventory unit and optionally
# state.
#
# @param inventory_unit [Spree::InventoryUnit] the desired inventory
# unit
# @param state [:backordered, :on_hand, nil] the state of the desired
# content item, or nil for any state
def find_item(inventory_unit, state = nil)
contents.detect do |item|
item.inventory_unit == inventory_unit &&
(!state || item.state.to_s == state.to_s)
end
end
# @param state [:backordered, :on_hand, nil] the state of the content
# items of which we want the quantity, or nil for the full quantity
# @return [Fixnum] the number of inventory units in the package,
# counting only those in the given state if it was specified
def quantity(state = nil)
matched_contents = state.nil? ? contents : contents.select { |c| c.state.to_s == state.to_s }
matched_contents.map(&:quantity).sum
end
# @return [Boolean] true if there are no inventory units in this
# package
def empty?
quantity == 0
end
# @return [String] the currency of the order this package belongs to
def currency
order.currency
end
# @return [Array<Spree::ShippingCategory>] the shipping categories of the
# variants in this package
def shipping_categories
ShippingCategory.where(id: shipping_category_ids)
end
# @return [ActiveRecord::Relation] the [Spree::ShippingMethod]s available
# for this pacakge based on the stock location and shipping categories.
def shipping_methods
Spree::ShippingMethod.
with_all_shipping_category_ids(shipping_category_ids).
available_in_stock_location(stock_location)
end
# @return [Spree::Shipment] a new shipment containing this package's
# inventory units, with the appropriate shipping rates and associated
# with the correct stock location
def to_shipment
# At this point we should only have one content item per inventory unit
# across the entire set of inventory units to be shipped, which has
# been taken care of by the Prioritizer
contents.each { |content_item| content_item.inventory_unit.state = content_item.state.to_s }
Spree::Shipment.new(
order: order,
stock_location: stock_location,
inventory_units: contents.map(&:inventory_unit)
)
end
private
# @return [Array<Fixnum>] the unique ids of all shipping categories of
# variants in this package
def shipping_category_ids
contents.map { |item| item.variant.shipping_category_id }.compact.uniq
end
end
end
end