Class: Order

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/order.rb

Overview

Schema Information

Table name: orders

id              :integer(4)      not null, primary key
number          :string(255)
ip_address      :string(255)
email           :string(255)
state           :string(255)
user_id         :integer(4)
bill_address_id :integer(4)
ship_address_id :integer(4)
coupon_id       :integer(4)
active          :boolean(1)      default(TRUE), not null
shipped         :boolean(1)      default(FALSE), not null
shipments_count :integer(4)      default(0)
calculated_at   :datetime
completed_at    :datetime
created_at      :datetime
updated_at      :datetime
credited_amount :decimal(8, 2)   default(0.0)

Constant Summary

NUMBER_SEED =
1001001001000
CHARACTERS_SEED =
21

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Instance Attribute Details

- (Object) deal_amount

after_find :set_beginning_values



63
64
65
# File 'app/models/order.rb', line 63

def deal_amount
  @deal_amount
end

- (Object) sub_total

after_find :set_beginning_values



63
64
65
# File 'app/models/order.rb', line 63

def sub_total
  @sub_total
end

- (Object) taxed_total

after_find :set_beginning_values



63
64
65
# File 'app/models/order.rb', line 63

def taxed_total
  @taxed_total
end

- (Object) total

after_find :set_beginning_values



63
64
65
# File 'app/models/order.rb', line 63

def total
  @total
end

Class Method Details

+ (Object) create_subscription_order(user)



458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# File 'app/models/order.rb', line 458

def self.create_subscription_order(user)
  order = Order.new(
            :user   => user,
            :email  => user.email,
            :bill_address => user.billing_address,
            :ship_address => user.shipping_address
                    )
  oi = OrderItem.new( :total            => user..monthly_charge,
                      :price            => user..monthly_charge,
                      :variant_id       => Variant::MONTHLY_BILLING_ID,
                      :shipping_rate_id => ShippingRate::MONTHLY_BILLING_RATE_ID
                    )
  order.push(oi)
  order.save
  order
end

+ (Order) find_by_number(num)

finds the Order from the orders number. Is more optimal than the normal rails find by id

because if calculates the order's id which is indexed

Parameters:

  • represents (String)

    the order.number

Returns:



428
429
430
# File 'app/models/order.rb', line 428

def self.find_by_number(num)
  find(id_from_number(num))##  now we can search by id which should be much faster
end

+ (Array[Order]) find_finished_order_grid(params = {})

paginated results from the admin orders that are completed grid

Parameters:

  • (Optional params)

Returns:



479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'app/models/order.rb', line 479

def self.find_finished_order_grid(params = {})

  grid = Order
  grid = grid.includes([:user])
  grid = grid.where({:active => true })                     unless  params[:show_all].present? &&
                                                                    params[:show_all] == 'true'
  grid = grid.where("orders.shipment_counter = ?", 0)             if params[:shipped].present? && params[:shipped] == 'true'
  grid = grid.where("orders.shipment_counter > ?", 0)            if params[:shipped].present? && params[:shipped] == 'false'
  grid = grid.where("orders.completed_at IS NOT NULL")
  grid = grid.where("orders.number LIKE ?", "#{params[:number]}%")  if params[:number].present?
  grid = grid.where("orders.email LIKE ?", "#{params[:email]}%")    if params[:email].present?
  grid = grid.order("#{params[:sidx]} #{params[:sord]}")

end

+ (Object) find_myaccount_details



156
157
158
# File 'app/models/order.rb', line 156

def self.find_myaccount_details
  includes([:completed_invoices, :invoices])
end

+ (Array[Order]) fulfillment_grid(params = {})

paginated results from the admin order fulfillment grid

Parameters:

  • (Optional params)

Returns:



498
499
500
501
502
503
504
505
506
507
508
509
# File 'app/models/order.rb', line 498

def self.fulfillment_grid(params = {})
  grid = self
  grid = grid.includes([:user])
  grid = grid.where({:active => true })                     unless  params[:show_all].present? &&
                                                                    params[:show_all] == 'true'
  grid = grid.where({ :orders => {:shipped => false }} )
  grid = grid.where("orders.completed_at IS NOT NULL")
  grid = grid.where("orders.number LIKE ?", "#{params[:number]}%")  if params[:number].present?
  grid = grid.where("orders.shipped = ?", true)               if (params[:shipped].present? && params[:shipped] == 'true')
  grid = grid.where("orders.email LIKE ?", "#{params[:email]}%")    if params[:email].present?
  grid
end

+ (Integer) id_from_number(num)

determines the order id from the order.number

Parameters:

  • represents (String)

    the order.number

Returns:

  • (Integer)

    id of the order to find



419
420
421
# File 'app/models/order.rb', line 419

def self.id_from_number(num)
  num.to_i(CHARACTERS_SEED) - NUMBER_SEED
end

+ (Object) include_checkout_objects



254
255
256
257
258
259
260
# File 'app/models/order.rb', line 254

def self.include_checkout_objects
  includes([{:ship_address => :state},
            {:bill_address => :state},
            {:order_items =>
              {:variant =>
                {:product => :images }}}])
end

Instance Method Details

- (Object) add_cart_item(item, state_id = nil)



160
161
162
163
164
165
166
167
168
169
170
171
# File 'app/models/order.rb', line 160

def add_cart_item( item, state_id = nil)
  self.save! if self.new_record?
  tax_rate_id = state_id ? item.variant.product.tax_rate(state_id) : nil
  item.quantity.times do
    oi =  OrderItem.create(
        :order        => self,
        :variant_id   => item.variant.id,
        :price        => item.variant.price,
        :tax_rate_id  => tax_rate_id)
    self.order_items.push(oi)
  end
end

- (none) add_items(variant, quantity, state_id = nil)

add the variant to the order items in the order, normally called at order creation

Parameters:

  • variant (Variant)

    to add

  • quantity (Integer)

    to add to the order

  • state_id (Optional Integer) (defaults to: nil)

    (for taxes) to assign to the order_item

Returns:

  • (none)


385
386
387
388
389
390
391
# File 'app/models/order.rb', line 385

def add_items(variant, quantity, state_id = nil)
  self.save! if self.new_record?
  tax_rate_id = state_id ? variant.product.tax_rate(state_id) : nil
  quantity.times do
    self.order_items.push(OrderItem.create(:order => self,:variant_id => variant.id, :price => variant.price, :tax_rate_id => tax_rate_id))
  end
end

- (Boolean) all_order_items_have_a_shipping_rate?

Returns:

  • (Boolean)


228
229
230
# File 'app/models/order.rb', line 228

def all_order_items_have_a_shipping_rate?
  !order_items.any?{ |item| item.shipping_rate_id.nil? }
end

- (Float) amount_to_credit

amount to credit based off the user store credit

Parameters:

  • (none)

Returns:

  • (Float)

    amount to remove from store credit



324
325
326
# File 'app/models/order.rb', line 324

def amount_to_credit
  [find_total, user.store_credit.amount].min.to_f.round_at( 2 )
end

- (none) calculate_totals

This method will go to every order_item and calculate the total for that item.

if calculated at is set this order does not need to be calculated unless any single item in the order has been updated since the order was calculated

Also if any item is not ready to calculate then dont calculate

Parameters:

  • the (none)

    param is not used right now

Returns:

  • (none)


216
217
218
219
220
221
222
223
224
225
226
# File 'app/models/order.rb', line 216

def calculate_totals
  # if calculated at is nil then this order hasn't been calculated yet
  # also if any single item in the order has been updated, the order needs to be re-calculated
  if any_order_item_needs_to_be_calculated? && all_order_items_are_ready_to_calculate?
    calculate_each_order_items_total
    sub_total = total
    self.total = total + shipping_charges
    self.calculated_at = Time.zone.now
    save
  end
end

- (none) cancel_unshipped_order(invoice)

cancel the order and payment

> sets the order inactive and cancels the authorized payments

Parameters:

Returns:

  • (none)


140
141
142
143
144
145
# File 'app/models/order.rb', line 140

def cancel_unshipped_order(invoice)
  transaction do
    self.update_attributes(:active => false)
    invoice.cancel_authorized_payment
  end
end

- (Payment) capture_invoice(invoice)

captures the payment of the invoice by the payment processor

Parameters:

Returns:



177
178
179
180
181
# File 'app/models/order.rb', line 177

def capture_invoice(invoice)
  payment = invoice.capture_payment({})
  self.pay! if payment.success
  payment
end

- (Float) coupon_amount

amount the coupon reduces the value of the order

Parameters:

  • (none)

Returns:

  • (Float)

    amount the coupon reduces the value of the order



308
309
310
# File 'app/models/order.rb', line 308

def coupon_amount
  coupon_id ? coupon.value(item_prices, self) : 0.0
end

- (Object) create_invoice(credit_card, charge_amount, args, credited_amount = 0.0)

This method creates the invoice and payment method. If the payment is not authorized the whole transaction is roled back



185
186
187
188
189
190
191
192
193
194
# File 'app/models/order.rb', line 185

def create_invoice(credit_card, charge_amount, args, credited_amount = 0.0)
  transaction do
    new_invoice = create_invoice_transaction(credit_card, charge_amount, args, credited_amount)
    if new_invoice.succeeded?
      remove_user_store_credits
      Notifier.order_confirmation(@order, new_invoice).deliver rescue puts( 'do nothing...  dont blow up over an email')
    end
    new_invoice
  end
end

- (Float) credited_total

called when creating the invoice. This does not change the store_credit amount

Parameters:

  • (none)

Returns:

  • (Float)

    amount that the order is charged after store credit is applyed



316
317
318
# File 'app/models/order.rb', line 316

def credited_total
  (find_total - amount_to_credit).round_at( 2 )
end

- (String) display_completed_at(format = :us_date)

formated date of the complete_at datetime on the order

Parameters:

  • (none)

Returns:

  • (String)

    formated date or 'Not Finished.' if the order is not completed



122
123
124
# File 'app/models/order.rb', line 122

def display_completed_at(format = :us_date)
  completed_at ? I18n.localize(completed_at, :format => format) : 'Not Finished.'
end

- (Object) display_shipping_charges



341
342
343
344
345
# File 'app/models/order.rb', line 341

def display_shipping_charges
  items = OrderItem.order_items_in_cart(self.id)
  return 'TBD' if items.any?{|i| i.shipping_rate_id.nil? }
  shipping_charges(items)
end

- (Object) find_sub_total



276
277
278
279
280
281
282
# File 'app/models/order.rb', line 276

def find_sub_total
  self.total = 0.0
  order_items.each do |item|
    self.total = self.total + item.item_total
  end
  self.sub_total = self.total
end

- (none) find_total(force = false)

calculates the total price of the order this method will set sub_total and total for the order even if the order is not ready for final checkout

Parameters:

  • the (none)

    param is not used right now

Returns:

  • (none)

    Sets sub_total and total for the object



267
268
269
270
271
272
273
274
# File 'app/models/order.rb', line 267

def find_total(force = false)
  calculate_totals if self.calculated_at.nil? || order_items.any? {|item| (item.updated_at > self.calculated_at) }
  self.deal_amount = Deal.best_qualifing_deal(self)
  self.find_sub_total
  taxable_money     = (self.sub_total - deal_amount - coupon_amount) * ((100.0 + order_tax_percentage) / 100.0)
  self.total        = (self.sub_total + shipping_charges - deal_amount - coupon_amount ).round_at( 2 )
  self.taxed_total  = (taxable_money + shipping_charges).round_at( 2 )
end

- (String) first_invoice_amount

how much you initially charged the customer

Parameters:

  • (none)

Returns:

  • (String)

    amount in dollars as decimal or a blank string



130
131
132
133
# File 'app/models/order.rb', line 130

def first_invoice_amount
  return '' if completed_invoices.empty?
  completed_invoices.first.amount
end

- (Object) get_taxed_total



288
289
290
# File 'app/models/order.rb', line 288

def get_taxed_total
  taxed_total || find_total
end

- (Boolean) has_shipment?

if the order has a shipment this is true... else false

Parameters:

  • (none)

Returns:

  • (Boolean)


454
455
456
# File 'app/models/order.rb', line 454

def has_shipment?
  shipments_count > 0
end

- (Object) mark_items_paid

This method is used when the session in admin orders is ready to authorize the credit card

 The cart has the following format

session[:admin_cart] = {
  :user             => nil,
  :shipping_address => nil,
  :billing_address  => nil,
  :coupon           => nil,
  :shipping_method  => nil,
  :order_items => {}# the key is variant_id , a hash of {variant, shipping_rate, quantity, tax_rate, total, shipping_category_id}
}


102
103
104
# File 'app/models/order.rb', line 102

def mark_items_paid
  order_items.map(&:pay!)
end

- (String) name

user name on the order

Parameters:

  • (none)

Returns:

  • (String)

    user name on the order



110
111
112
# File 'app/models/order.rb', line 110

def name
  self.user.name
end

- (Hash) number_of_a_given_product_type

This returns a hash where product_type_id is the key and an Array of prices are the values.

This method is specifically used for Deal.rb

Returns:

  • (Hash)

    This returns a hash of { product_type_id => [price, price]}



236
237
238
239
240
241
242
243
244
245
# File 'app/models/order.rb', line 236

def number_of_a_given_product_type
   return_hash = order_items.inject({}) do |hash, oi|
     oi.product_type_ids.each do |product_type_id|
       hash[product_type_id] ||= []
       hash[product_type_id] << oi.price#.to_s
     end
     hash
   end#.sort_by{|v| v.values.first.size }.reverse
   return_hash#.delete_if{|k,v| k == 1}
end

- (Payment) order_complete!

call after the order is completed (authorized the payment)

> sets the order.state to completed, sets completed_at to time.now and updates the inventory

Parameters:

  • (none)

Returns:



201
202
203
204
205
# File 'app/models/order.rb', line 201

def order_complete!
  self.state = 'complete'
  self.completed_at = Time.zone.now
  update_inventory
end

- (Float) order_tax_percentage

Turns out in order to determine the order.total_price correctly (to include coupons and deals and all the items)

it is much easier to multiply the tax times to whole order's price.  This should work for most use cases.  It

For now this method will just look at the first item's tax rate. In the future tax_rate_id will move to the order object

Parameters:

  • none

Returns:

  • (Float)

    tax rate 10.5% === 10.5



300
301
302
# File 'app/models/order.rb', line 300

def order_tax_percentage
  (!order_items.blank? && order_items.first.tax_rate.try(:percentage)) ? order_items.first.tax_rate.try(:percentage) : 0.0
end

- (Boolean) ready_to_checkout?

looks at all the order items and determines if the order has all the required elements to complete a checkout

Parameters:

  • (none)

Returns:

  • (Boolean)


250
251
252
# File 'app/models/order.rb', line 250

def ready_to_checkout?
  order_items.all? {|item| item.ready_to_calculate? }
end

- (none) remove_items(variant, final_quantity)

remove the variant from the order items in the order

THIS METHOD IS COMPLEX FOR A REASON!!!
USING slice! ALLOWS THE ORDER_ITEMS TO BE DESTROYED AND UNASSOCIATED FROM THE ORDER OBJECT

Parameters:

  • variant (Variant)

    to add

  • final (Integer)

    quantity that should be in the order

Returns:

  • (none)


400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'app/models/order.rb', line 400

def remove_items(variant, final_quantity)

  current_qty = 0
  items_to_remove = []
  self.order_items.each_with_index do |order_item, i|
    if order_item.variant_id == variant.id
      current_qty = current_qty + 1
      items_to_remove << i  if (current_qty - final_quantity) > 0
    end
  end
  items_to_remove.reverse.each do |i|
    self.order_items.slice!(i ,1).first.destroy # remove from order.order_items object and destroy from DB
  end
end

- (Object) remove_user_store_credits



328
329
330
# File 'app/models/order.rb', line 328

def remove_user_store_credits
  user.store_credit.remove_credit(amount_to_credit) if amount_to_credit > 0.0
end

- (Decimal) shipping_charges(items = nil)

calculates the total shipping charges for all the items in the cart

Parameters:

  • (none)

Returns:

  • (Decimal)

    amount of the shipping charges



336
337
338
339
# File 'app/models/order.rb', line 336

def shipping_charges(items = nil)
  return @order_shipping_charges if defined?(@order_shipping_charges)
  @order_shipping_charges = shipping_rates(items).inject(0.0) {|sum, shipping_rate|  sum + shipping_rate.rate  }
end

- (Array) shipping_rates(items = nil)

all the shipping rate to apply to the order

Parameters:

  • (none)

Returns:

  • (Array)

    array of shipping rates that will be charged, it will return the same shipping rate more than once if it can be charged more than once



352
353
354
355
356
357
358
# File 'app/models/order.rb', line 352

def shipping_rates(items = nil)
  items ||= OrderItem.order_items_in_cart(self.id)
  rates = items.inject([]) do |rates, item|
    rates << item.shipping_rate if item.shipping_rate.individual? || !rates.include?(item.shipping_rate)
    rates
  end
end

- (String) status

status of the invoice

Parameters:

  • (none)

Returns:

  • (String)

    state of the latest invoice or 'not processed' if there aren't any invoices



151
152
153
154
# File 'app/models/order.rb', line 151

def status
  return 'not processed' if invoices.empty?
  invoices.last.state
end

- (Array) tax_charges

all the tax charges to apply to the order

Parameters:

  • (none)

Returns:

  • (Array)

    array of tax charges that will be charged



364
365
366
367
368
369
# File 'app/models/order.rb', line 364

def tax_charges
  charges = order_items.inject([]) do |charges, item|
    charges << item.tax_charge
    charges
  end
end

- (Object) taxed_amount



284
285
286
# File 'app/models/order.rb', line 284

def taxed_amount
  (get_taxed_total - total).round_at( 2 )
end

- (Decimal) total_tax_charges

sum of all the tax charges to apply to the order

Parameters:

  • (none)

Returns:

  • (Decimal)


375
376
377
# File 'app/models/order.rb', line 375

def total_tax_charges
  tax_charges.sum
end

- (Object) transaction_time



114
115
116
# File 'app/models/order.rb', line 114

def transaction_time
  calculated_at || Time.zone.now
end

- (none) update_inventory

This method is called when the order transitions to paid

it will add the number of variants pending to be sent to the customer

Parameters:

  • none

Returns:

  • (none)


437
438
439
# File 'app/models/order.rb', line 437

def update_inventory
  self.order_items.each { |item| item.variant.add_pending_to_customer }
end

- (Integer) variant_ids

variant ids in the order.

Parameters:

  • (none)

Returns:

  • (Integer)

    all the variant_id's in the order



445
446
447
# File 'app/models/order.rb', line 445

def variant_ids
  order_items.collect{|oi| oi.variant_id }
end