Class: Order
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Order
- Defined in:
- app/models/order.rb
Instance Attribute Summary collapse
-
#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
-
#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.
- #insufficient_stock_lines ⇒ Object
-
#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
-
#payment_required? ⇒ Boolean
Is this a free order in which case the payment step should be skipped.
- #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
#use_billing ⇒ Object
Returns the value of attribute use_billing.
183 184 185 |
# File 'app/models/order.rb', line 183 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
52 53 54 |
# File 'app/models/order.rb', line 52 def self.register_update_hook(hook) self.update_hooks.add(hook) end |
Instance Method Details
#add_variant(variant, quantity = 1) ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'app/models/order.rb', line 207 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
196 197 198 199 |
# File 'app/models/order.rb', line 196 def allow_cancel? return false unless completed? and state != 'canceled' %w{ready backorder pending}.include? shipment_state end |
#allow_resume? ⇒ Boolean
201 202 203 204 205 |
# File 'app/models/order.rb', line 201 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
355 356 357 |
# File 'app/models/order.rb', line 355 def available_payment_methods @available_payment_methods ||= PaymentMethod.available(:front_end) end |
#available_shipping_methods(display_on = nil) ⇒ Object
Helper methods for checkout steps
335 336 337 338 |
# File 'app/models/order.rb', line 335 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.
131 132 133 134 |
# File 'app/models/order.rb', line 131 def backordered? return false unless Spree::Config[:track_inventory_levels] inventory_units.backorder.present? end |
#billing_firstname ⇒ Object
367 368 369 |
# File 'app/models/order.rb', line 367 def billing_firstname bill_address.try(:firstname) end |
#billing_lastname ⇒ Object
371 372 373 |
# File 'app/models/order.rb', line 371 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.
67 68 69 |
# File 'app/models/order.rb', line 67 def checkout_allowed? line_items.count > 0 end |
#clone_billing_address ⇒ Object
185 186 187 188 189 190 191 192 |
# File 'app/models/order.rb', line 185 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
60 61 62 |
# File 'app/models/order.rb', line 60 def completed? !! completed_at end |
#contains?(variant) ⇒ Boolean
251 252 253 |
# File 'app/models/order.rb', line 251 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)
280 281 282 283 284 285 286 287 288 289 290 |
# File 'app/models/order.rb', line 280 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. for the vat case adjutments according to default country are created
266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'app/models/order.rb', line 266 def create_tax_charge! adjustments.tax.each {|e| e.destroy } matching_rates = TaxRate.match(ship_address) if matching_rates.empty? and Spree::Config[:show_price_inc_vat] # somebody may be able to make the search shorter here , some unremember bug caused this matching_rates = TaxRate.all.select{|rate| # get all rates that apply to default country rate.zone.country_list.collect{|c| c.id}.include?(Spree::Config[:default_country_id]) } end matching_rates.each do |rate| rate.create_adjustment( "#{rate.calculator.description} #{rate.amount*100}%" , self, self, true) end end |
#creditcards ⇒ Object
306 307 308 309 |
# File 'app/models/order.rb', line 306 def creditcards creditcard_ids = payments.from_creditcard.map(&:source_id).uniq Creditcard.scoped(:conditions => {:id => creditcard_ids}) end |
#finalize! ⇒ Object
Finalizes an in progress order after checkout is complete. Called after transition to complete state when payments will have been processed
317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'app/models/order.rb', line 317 def finalize! update_attribute(:completed_at, Time.now) 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
236 237 238 239 240 241 242 243 244 |
# File 'app/models/order.rb', line 236 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 |
#insufficient_stock_lines ⇒ Object
379 380 381 |
# File 'app/models/order.rb', line 379 def insufficient_stock_lines line_items.select &:insufficient_stock? end |
#ip_address ⇒ Object
delegate :ip_address, :to => :checkout
35 36 37 |
# File 'app/models/order.rb', line 35 def ip_address '192.168.1.100' end |
#item_count ⇒ Object
Indicates the number of items in the order
77 78 79 |
# File 'app/models/order.rb', line 77 def item_count line_items.map(&:quantity).sum end |
#name ⇒ Object
300 301 302 303 304 |
# File 'app/models/order.rb', line 300 def name if (address = bill_address || ship_address) "#{address.firstname} #{address.lastname}" end end |
#outstanding_balance ⇒ Object
292 293 294 |
# File 'app/models/order.rb', line 292 def outstanding_balance total - payment_total end |
#outstanding_balance? ⇒ Boolean
296 297 298 |
# File 'app/models/order.rb', line 296 def outstanding_balance? self.outstanding_balance != 0 end |
#payment ⇒ Object
351 352 353 |
# File 'app/models/order.rb', line 351 def payment payments.first end |
#payment_method ⇒ Object
359 360 361 362 363 364 365 |
# File 'app/models/order.rb', line 359 def payment_method if payment and payment.payment_method payment.payment_method else available_payment_methods.first end end |
#payment_required? ⇒ Boolean
Is this a free order in which case the payment step should be skipped
72 73 74 |
# File 'app/models/order.rb', line 72 def payment_required? total.to_f > 0.0 end |
#process_payments! ⇒ Object
311 312 313 |
# File 'app/models/order.rb', line 311 def process_payments! ret = payments.each(&:process!) end |
#products ⇒ Object
375 376 377 |
# File 'app/models/order.rb', line 375 def products line_items.map{|li| li.variant.product} end |
#rate_hash ⇒ Object
340 341 342 343 344 345 346 347 348 349 |
# File 'app/models/order.rb', line 340 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
168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'app/models/order.rb', line 168 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
255 256 257 |
# File 'app/models/order.rb', line 255 def ship_total adjustments.shipping.map(&:amount).sum end |
#shipment ⇒ Object
convenience method since many stores will not allow user to create multiple shipments
247 248 249 |
# File 'app/models/order.rb', line 247 def shipment @shipment ||= shipments.last end |
#tax_total ⇒ Object
259 260 261 |
# File 'app/models/order.rb', line 259 def tax_total adjustments.tax.map(&:amount).sum end |
#to_param ⇒ Object
56 57 58 |
# File 'app/models/order.rb', line 56 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.)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'app/models/order.rb', line 140 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 }) #ensure checkout payment always matches order total if payment and payment.checkout? and payment.amount != total payment.update_attributes_without_callbacks(:amount => total) end update_hooks.each { |hook| self.send hook } end |