Class: Spree::Shipment
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Spree::Shipment
- Defined in:
- app/models/spree/shipment.rb
Defined Under Namespace
Classes: ManifestItem
Instance Attribute Summary collapse
-
#special_instructions ⇒ Object
Returns the value of attribute special_instructions.
Instance Method Summary collapse
- #add_shipping_method(shipping_method, selected = false) ⇒ Object
- #after_cancel ⇒ Object
- #after_resume ⇒ Object
- #backordered? ⇒ Boolean
- #currency ⇒ Object
-
#determine_state(order) ⇒ Object
Determines the appropriate
state
according to the following logic:. - #discounted_cost ⇒ Object (also: #discounted_amount)
- #display_cost ⇒ Object (also: #display_amount)
- #display_discounted_cost ⇒ Object
- #display_final_price ⇒ Object
- #display_item_cost ⇒ Object
- #editable_by?(user) ⇒ Boolean
- #final_price ⇒ Object
- #finalize! ⇒ Object
- #include?(variant) ⇒ Boolean
- #inventory_units_for(variant) ⇒ Object
- #inventory_units_for_item(line_item, variant = nil) ⇒ Object
- #item_cost ⇒ Object
- #line_items ⇒ Object
- #manifest ⇒ Object
- #ready_or_pending? ⇒ Boolean
- #refresh_rates ⇒ Object
- #selected_shipping_rate ⇒ Object
- #selected_shipping_rate_id ⇒ Object
- #selected_shipping_rate_id=(id) ⇒ Object
- #set_up_inventory(state, variant, order, line_item) ⇒ Object
- #shipped=(value) ⇒ Object
- #shipping_method ⇒ Object
- #tax_category ⇒ Object
-
#tax_total ⇒ Object
Only one of either included_tax_total or additional_tax_total is set This method returns the total of the two.
- #to_package ⇒ Object
- #to_param ⇒ Object
- #tracking_url ⇒ Object
-
#update!(order) ⇒ Object
Updates various aspects of the Shipment while bypassing any callbacks.
- #update_amounts ⇒ Object
-
#update_attributes_and_order(params = {}) ⇒ Object
Update Shipment and make sure Order states follow the shipment changes.
Instance Attribute Details
#special_instructions ⇒ Object
Returns the value of attribute special_instructions.
19 20 21 |
# File 'app/models/spree/shipment.rb', line 19 def special_instructions @special_instructions end |
Instance Method Details
#add_shipping_method(shipping_method, selected = false) ⇒ Object
96 97 98 |
# File 'app/models/spree/shipment.rb', line 96 def add_shipping_method(shipping_method, selected = false) shipping_rates.create(shipping_method: shipping_method, selected: selected, cost: cost) end |
#after_cancel ⇒ Object
209 210 211 |
# File 'app/models/spree/shipment.rb', line 209 def after_cancel manifest.each { |item| manifest_restock(item) } end |
#after_resume ⇒ Object
213 214 215 |
# File 'app/models/spree/shipment.rb', line 213 def after_resume manifest.each { |item| manifest_unstock(item) } end |
#backordered? ⇒ Boolean
79 80 81 |
# File 'app/models/spree/shipment.rb', line 79 def backordered? inventory_units.any? { |inventory_unit| inventory_unit.backordered? } end |
#currency ⇒ Object
137 138 139 |
# File 'app/models/spree/shipment.rb', line 137 def currency order ? order.currency : Spree::Config[:currency] end |
#determine_state(order) ⇒ Object
Determines the appropriate state
according to the following logic:
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
235 236 237 238 239 240 241 |
# File 'app/models/spree/shipment.rb', line 235 def determine_state(order) return 'canceled' if order.canceled? return 'pending' unless order.can_ship? return 'pending' if inventory_units.any? &:backordered? return 'shipped' if state == 'shipped' order.paid? ? 'ready' : 'pending' end |
#discounted_cost ⇒ Object Also known as: discounted_amount
150 151 152 |
# File 'app/models/spree/shipment.rb', line 150 def discounted_cost cost + promo_total end |
#display_cost ⇒ Object Also known as: display_amount
141 142 143 |
# File 'app/models/spree/shipment.rb', line 141 def display_cost Spree::Money.new(cost, { currency: currency }) end |
#display_discounted_cost ⇒ Object
166 167 168 |
# File 'app/models/spree/shipment.rb', line 166 def display_discounted_cost Spree::Money.new(discounted_cost, { currency: currency }) end |
#display_final_price ⇒ Object
170 171 172 |
# File 'app/models/spree/shipment.rb', line 170 def display_final_price Spree::Money.new(final_price, { currency: currency }) end |
#display_item_cost ⇒ Object
174 175 176 |
# File 'app/models/spree/shipment.rb', line 174 def display_item_cost Spree::Money.new(item_cost, { currency: currency }) end |
#editable_by?(user) ⇒ Boolean
178 179 180 |
# File 'app/models/spree/shipment.rb', line 178 def editable_by?(user) !shipped? end |
#final_price ⇒ Object
162 163 164 |
# File 'app/models/spree/shipment.rb', line 162 def final_price discounted_cost + tax_total end |
#finalize! ⇒ Object
204 205 206 207 |
# File 'app/models/spree/shipment.rb', line 204 def finalize! InventoryUnit.finalize_units!(inventory_units) manifest.each { |item| manifest_unstock(item) } end |
#include?(variant) ⇒ Boolean
247 248 249 |
# File 'app/models/spree/shipment.rb', line 247 def include?(variant) inventory_units_for(variant).present? end |
#inventory_units_for(variant) ⇒ Object
251 252 253 |
# File 'app/models/spree/shipment.rb', line 251 def inventory_units_for(variant) inventory_units.where(variant_id: variant.id) end |
#inventory_units_for_item(line_item, variant = nil) ⇒ Object
255 256 257 |
# File 'app/models/spree/shipment.rb', line 255 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 |
#item_cost ⇒ Object
146 147 148 |
# File 'app/models/spree/shipment.rb', line 146 def item_cost line_items.map(&:amount).sum end |
#line_items ⇒ Object
200 201 202 |
# File 'app/models/spree/shipment.rb', line 200 def line_items inventory_units.includes(:line_item).map(&:line_item).uniq end |
#manifest ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'app/models/spree/shipment.rb', line 184 def manifest # Grouping by the ID means that we don't have to call out to the association accessor # This makes the grouping by faster because it results in less SQL cache hits. inventory_units.group_by(&:variant_id).map do |variant_id, units| units.group_by(&:line_item_id).map do |line_item_id, units| states = {} units.group_by(&:state).each { |state, iu| states[state] = iu.count } line_item = units.first.line_item variant = units.first.variant ManifestItem.new(line_item, variant, units.length, states) end end.flatten end |
#ready_or_pending? ⇒ Boolean
83 84 85 |
# File 'app/models/spree/shipment.rb', line 83 def ready_or_pending? self.ready? || self.pending? end |
#refresh_rates ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'app/models/spree/shipment.rb', line 118 def refresh_rates return shipping_rates if shipped? return [] unless can_get_rates? # StockEstimator.new assigment below will replace the current shipping_method original_shipping_method_id = shipping_method.try(:id) self.shipping_rates = Stock::Estimator.new(order).shipping_rates(to_package) if shipping_method selected_rate = shipping_rates.detect { |rate| rate.shipping_method_id == original_shipping_method_id } self.selected_shipping_rate_id = selected_rate.id if selected_rate end shipping_rates end |
#selected_shipping_rate ⇒ Object
100 101 102 |
# File 'app/models/spree/shipment.rb', line 100 def selected_shipping_rate shipping_rates.where(selected: true).first end |
#selected_shipping_rate_id ⇒ Object
104 105 106 |
# File 'app/models/spree/shipment.rb', line 104 def selected_shipping_rate_id selected_shipping_rate.try(:id) end |
#selected_shipping_rate_id=(id) ⇒ Object
108 109 110 111 112 |
# File 'app/models/spree/shipment.rb', line 108 def selected_shipping_rate_id=(id) shipping_rates.update_all(selected: false) shipping_rates.update(id, selected: true) self.save! end |
#set_up_inventory(state, variant, order, line_item) ⇒ Object
271 272 273 274 275 276 277 278 |
# File 'app/models/spree/shipment.rb', line 271 def set_up_inventory(state, variant, order, line_item) self.inventory_units.create( state: state, variant_id: variant.id, order_id: order.id, line_item_id: line_item.id ) end |
#shipped=(value) ⇒ Object
87 88 89 90 |
# File 'app/models/spree/shipment.rb', line 87 def shipped=(value) return unless value == '1' && shipped_at.nil? self.shipped_at = Time.now end |
#shipping_method ⇒ Object
92 93 94 |
# File 'app/models/spree/shipment.rb', line 92 def shipping_method selected_shipping_rate.try(:shipping_method) || shipping_rates.first.try(:shipping_method) end |
#tax_category ⇒ Object
114 115 116 |
# File 'app/models/spree/shipment.rb', line 114 def tax_category selected_shipping_rate.try(:tax_rate).try(:tax_category) end |
#tax_total ⇒ Object
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.
158 159 160 |
# File 'app/models/spree/shipment.rb', line 158 def tax_total included_tax_total + additional_tax_total end |
#to_package ⇒ Object
259 260 261 262 263 264 265 266 267 268 269 |
# File 'app/models/spree/shipment.rb', line 259 def to_package package = Stock::Package.new(stock_location, order) grouped_inventory_units = inventory_units.includes(:line_item).group_by do |iu| [iu.line_item, iu.state_name] end grouped_inventory_units.each do |(line_item, state_name), inventory_units| package.add line_item, inventory_units.count, state_name end package end |
#to_param ⇒ Object
75 76 77 |
# File 'app/models/spree/shipment.rb', line 75 def to_param number end |
#tracking_url ⇒ Object
243 244 245 |
# File 'app/models/spree/shipment.rb', line 243 def tracking_url @tracking_url ||= shipping_method.build_tracking_url(tracking) end |
#update!(order) ⇒ Object
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.
220 221 222 223 224 225 226 227 228 |
# File 'app/models/spree/shipment.rb', line 220 def update!(order) old_state = state new_state = determine_state(order) update_columns( state: new_state, updated_at: Time.now, ) after_ship if new_state == 'shipped' and old_state != 'shipped' end |
#update_amounts ⇒ Object
280 281 282 283 284 285 286 287 288 |
# File 'app/models/spree/shipment.rb', line 280 def update_amounts if selected_shipping_rate self.update_columns( cost: selected_shipping_rate.cost, adjustment_total: adjustments.additional.map(&:update!).compact.sum, updated_at: Time.now, ) end end |
#update_attributes_and_order(params = {}) ⇒ Object
Update Shipment and make sure Order states follow the shipment changes
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'app/models/spree/shipment.rb', line 291 def update_attributes_and_order(params = {}) if self.update_attributes params if params.has_key? :selected_shipping_rate_id # Changing the selected Shipping Rate won't update the cost (for now) # so we persist the Shipment#cost before calculating order shipment # total and updating payment state (given a change in shipment cost # might change the Order#payment_state) self.update_amounts order.updater.update_shipment_total order.updater.update_payment_state # Update shipment state only after order total is updated because it # (via Order#paid?) affects the shipment state (YAY) self.update_columns( state: determine_state(order), updated_at: Time.now ) # And then it's time to update shipment states and finally persist # order changes order.updater.update_shipment_state order.updater.persist_totals end true end end |