Class: Order
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Order
- Defined in:
- app/models/order.rb
Instance Attribute Summary collapse
-
#out_of_stock_items ⇒ Object
Returns the value of attribute out_of_stock_items.
-
#use_billing ⇒ Object
Returns the value of attribute use_billing.
Class Method Summary collapse
-
.register_update_hook(hook) ⇒ Object
Use this method in other gems that wish to register their own custom logic that should be called after Order#updat.
Instance Method Summary collapse
- #add_variant(variant, quantity = 1) ⇒ Object
- #allow_cancel? ⇒ Boolean
- #allow_resume? ⇒ Boolean
- #available_payment_methods ⇒ Object
-
#available_shipping_methods(display_on = nil) ⇒ Object
Helper methods for checkout steps.
-
#backordered? ⇒ Boolean
Indicates whether there are any backordered InventoryUnits associated with the Order.
- #billing_firstname ⇒ Object
- #billing_lastname ⇒ Object
-
#checkout_allowed? ⇒ Boolean
Indicates whether or not the user is allowed to proceed to checkout.
- #clone_billing_address ⇒ Object
- #completed? ⇒ Boolean
- #contains?(variant) ⇒ Boolean
-
#create_shipment! ⇒ Object
Creates a new shipment (adjustment is created by shipment model).
-
#create_tax_charge! ⇒ Object
Creates a new tax charge if applicable.
- #creditcards ⇒ Object
- #destroy_inapplicable_adjustments ⇒ Object
-
#finalize! ⇒ Object
Finalizes an in progress order after checkout is complete.
-
#generate_order_number ⇒ Object
FIXME refactor this method and implement validation using validates_* utilities.
-
#ip_address ⇒ Object
delegate :ip_address, :to => :checkout.
-
#item_count ⇒ Object
Indicates the number of items in the order.
- #name ⇒ Object
- #outstanding_balance ⇒ Object
- #outstanding_balance? ⇒ Boolean
- #payment ⇒ Object
- #payment_method ⇒ Object
- #process_payments! ⇒ Object
- #products ⇒ Object
- #rate_hash ⇒ Object
- #restore_state ⇒ Object
- #ship_total ⇒ Object
-
#shipment ⇒ Object
convenience method since many stores will not allow user to create multiple shipments.
- #tax_total ⇒ Object
- #to_param ⇒ Object
-
#update! ⇒ Object
This is a multi-purpose method for processing logic related to changes in the Order.
Instance Attribute Details
#out_of_stock_items ⇒ Object
Returns the value of attribute out_of_stock_items.
47 48 49 |
# File 'app/models/order.rb', line 47 def out_of_stock_items @out_of_stock_items end |
#use_billing ⇒ Object
Returns the value of attribute use_billing.
179 180 181 |
# File 'app/models/order.rb', line 179 def use_billing @use_billing end |
Class Method Details
.register_update_hook(hook) ⇒ Object
Use this method in other gems that wish to register their own custom logic that should be called after Order#updat
53 54 55 |
# File 'app/models/order.rb', line 53 def self.register_update_hook(hook) self.update_hooks.add(hook) end |
Instance Method Details
#add_variant(variant, quantity = 1) ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'app/models/order.rb', line 203 def add_variant(variant, quantity = 1) current_item = contains?(variant) if current_item current_item.quantity += quantity current_item.save else current_item = LineItem.new(:quantity => quantity) current_item.variant = variant current_item.price = variant.price self.line_items << current_item end # populate line_items attributes for additional_fields entries # that have populate => [:line_item] Variant.additional_fields.select{|f| !f[:populate].nil? && f[:populate].include?(:line_item) }.each do |field| value = "" if field[:only].nil? || field[:only].include?(:variant) value = variant.send(field[:name].gsub(" ", "_").downcase) elsif field[:only].include?(:product) value = variant.product.send(field[:name].gsub(" ", "_").downcase) end current_item.update_attribute(field[:name].gsub(" ", "_").downcase, value) end current_item end |
#allow_cancel? ⇒ Boolean
192 193 194 195 |
# File 'app/models/order.rb', line 192 def allow_cancel? return false unless completed? and state != 'canceled' %w{ready backorder pending}.include? shipment_state end |
#allow_resume? ⇒ Boolean
197 198 199 200 201 |
# File 'app/models/order.rb', line 197 def allow_resume? # we shouldn't allow resume for legacy orders b/c we lack the information necessary to restore to a previous state return false if state_events.empty? || state_events.last.previous_state.nil? true end |
#available_payment_methods ⇒ Object
347 348 349 |
# File 'app/models/order.rb', line 347 def available_payment_methods @available_payment_methods ||= PaymentMethod.available(:front_end) end |
#available_shipping_methods(display_on = nil) ⇒ Object
Helper methods for checkout steps
327 328 329 330 |
# File 'app/models/order.rb', line 327 def available_shipping_methods(display_on = nil) return [] unless ship_address ShippingMethod.all_available(self, display_on) end |
#backordered? ⇒ Boolean
Indicates whether there are any backordered InventoryUnits associated with the Order.
126 127 128 129 |
# File 'app/models/order.rb', line 126 def backordered? return false unless Spree::Config[:track_inventory_levels] inventory_units.backorder.present? end |
#billing_firstname ⇒ Object
359 360 361 |
# File 'app/models/order.rb', line 359 def billing_firstname bill_address.try(:firstname) end |
#billing_lastname ⇒ Object
363 364 365 |
# File 'app/models/order.rb', line 363 def billing_lastname bill_address.try(:lastname) end |
#checkout_allowed? ⇒ Boolean
Indicates whether or not the user is allowed to proceed to checkout. Currently this is implemented as a check for whether or not there is at least one LineItem in the Order. Feel free to override this logic in your own application if you require additional steps before allowing a checkout.
68 69 70 |
# File 'app/models/order.rb', line 68 def checkout_allowed? line_items.count > 0 end |
#clone_billing_address ⇒ Object
181 182 183 184 185 186 187 188 |
# File 'app/models/order.rb', line 181 def clone_billing_address if bill_address and self.ship_address.nil? self.ship_address = bill_address.clone else self.ship_address.attributes = bill_address.attributes.except("id", "updated_at", "created_at") end true end |
#completed? ⇒ Boolean
61 62 63 |
# File 'app/models/order.rb', line 61 def completed? !! completed_at end |
#contains?(variant) ⇒ Boolean
247 248 249 |
# File 'app/models/order.rb', line 247 def contains?(variant) line_items.detect{|line_item| line_item.variant_id == variant.id} end |
#create_shipment! ⇒ Object
Creates a new shipment (adjustment is created by shipment model)
267 268 269 270 271 272 273 274 275 276 277 |
# File 'app/models/order.rb', line 267 def create_shipment! shipping_method(true) if shipment.present? shipment.update_attributes(:shipping_method => shipping_method) else self.shipments << Shipment.create(:order => self, :shipping_method => shipping_method, :address => self.ship_address) end end |
#create_tax_charge! ⇒ Object
Creates a new tax charge if applicable. Uses the highest possible matching rate and destroys any previous tax charges if they were created by rates that no longer apply.
261 262 263 264 |
# File 'app/models/order.rb', line 261 def create_tax_charge! adjustments.tax.each {|e| e.destroy } TaxRate.match(ship_address).each {|r| r.create_adjustment(I18n.t(:tax), self, self, true) } end |
#creditcards ⇒ Object
298 299 300 301 |
# File 'app/models/order.rb', line 298 def creditcards creditcard_ids = payments.from_creditcard.map(&:source_id).uniq Creditcard.scoped(:conditions => {:id => creditcard_ids}) end |
#destroy_inapplicable_adjustments ⇒ Object
287 288 289 290 |
# File 'app/models/order.rb', line 287 def destroy_inapplicable_adjustments destroyed = adjustments.reject(&:applicable?).map(&:destroy) adjustments.reload if destroyed.any? end |
#finalize! ⇒ Object
Finalizes an in progress order after checkout is complete. Called after transition to complete state when payments will have been processed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'app/models/order.rb', line 309 def finalize! update_attribute(:completed_at, Time.now) self.out_of_stock_items = InventoryUnit.assign_opening_inventory(self) # lock any optional adjustments (coupon promotions, etc.) adjustments.optional.each { |adjustment| adjustment.update_attribute("locked", true) } OrderMailer.confirm_email(self).deliver self.state_events.create({ :previous_state => "cart", :next_state => "complete", :name => "order" , :user_id => (User.respond_to?(:current) && User.current.try(:id)) || self.user_id }) end |
#generate_order_number ⇒ Object
FIXME refactor this method and implement validation using validates_* utilities
232 233 234 235 236 237 238 239 240 |
# File 'app/models/order.rb', line 232 def generate_order_number record = true while record random = "R#{Array.new(9){rand(9)}.join}" record = self.class.find(:first, :conditions => ["number = ?", random]) end self.number = random if self.number.blank? self.number end |
#ip_address ⇒ Object
delegate :ip_address, :to => :checkout
34 35 36 |
# File 'app/models/order.rb', line 34 def ip_address '192.168.1.100' end |
#item_count ⇒ Object
Indicates the number of items in the order
73 74 75 |
# File 'app/models/order.rb', line 73 def item_count line_items.map(&:quantity).sum end |
#name ⇒ Object
292 293 294 295 296 |
# File 'app/models/order.rb', line 292 def name if (address = bill_address || ship_address) "#{address.firstname} #{address.lastname}" end end |
#outstanding_balance ⇒ Object
279 280 281 |
# File 'app/models/order.rb', line 279 def outstanding_balance total - payment_total end |
#outstanding_balance? ⇒ Boolean
283 284 285 |
# File 'app/models/order.rb', line 283 def outstanding_balance? self.outstanding_balance != 0 end |
#payment ⇒ Object
343 344 345 |
# File 'app/models/order.rb', line 343 def payment payments.first end |
#payment_method ⇒ Object
351 352 353 354 355 356 357 |
# File 'app/models/order.rb', line 351 def payment_method if payment and payment.payment_method payment.payment_method else available_payment_methods.first end end |
#process_payments! ⇒ Object
303 304 305 |
# File 'app/models/order.rb', line 303 def process_payments! ret = payments.each(&:process!) end |
#products ⇒ Object
367 368 369 |
# File 'app/models/order.rb', line 367 def products line_items.map{|li| li.variant.product} end |
#rate_hash ⇒ Object
332 333 334 335 336 337 338 339 340 341 |
# File 'app/models/order.rb', line 332 def rate_hash @rate_hash ||= available_shipping_methods(:front_end).collect do |ship_method| next unless cost = ship_method.calculator.compute(self) { :id => ship_method.id, :shipping_method => ship_method, :name => ship_method.name, :cost => cost } end.compact.sort_by{|r| r[:cost]} end |
#restore_state ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'app/models/order.rb', line 164 def restore_state # pop the resume event so we can see what the event before that was state_events.pop if state_events.last.name == "resume" update_attribute("state", state_events.last.previous_state) if paid? raise "do something with inventory" #InventoryUnit.assign_opening_inventory(self) if inventory_units.empty? #shipment.inventory_units = inventory_units #shipment.ready! end end |
#ship_total ⇒ Object
251 252 253 |
# File 'app/models/order.rb', line 251 def ship_total adjustments.shipping.map(&:amount).sum end |
#shipment ⇒ Object
convenience method since many stores will not allow user to create multiple shipments
243 244 245 |
# File 'app/models/order.rb', line 243 def shipment @shipment ||= shipments.last end |
#tax_total ⇒ Object
255 256 257 |
# File 'app/models/order.rb', line 255 def tax_total adjustments.tax.map(&:amount).sum end |
#to_param ⇒ Object
57 58 59 |
# File 'app/models/order.rb', line 57 def to_param number.to_s.parameterize.upcase end |
#update! ⇒ Object
This is a multi-purpose method for processing logic related to changes in the Order. It is meant to be called from various observers so that the Order is aware of changes that affect totals and other values stored in the Order. This method should never do anything to the Order that results in a save call on the object (otherwise you will end up in an infinite recursion as the associations try to save and then in turn try to call update!
again.)
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'app/models/order.rb', line 135 def update! update_totals update_payment_state # give each of the shipments a chance to update themselves shipments.each { |shipment| shipment.update!(self) }#(&:update!) update_shipment_state update_adjustments # update totals a second time in case updated adjustments have an effect on the total update_totals update_attributes_without_callbacks({ :payment_state => payment_state, :shipment_state => shipment_state, :item_total => item_total, :adjustment_total => adjustment_total, :payment_total => payment_total, :total => total }) puts "ensure checkout payment" #ensure checkout payment always matches order total if payment and payment.checkout? and payment.amount != total puts "payment update" payment.update_attributes_without_callbacks(:amount => total) end puts "update hook" update_hooks.each { |hook| self.send hook } end |