Class: Spina::Shop::Order

Inherits:
ApplicationRecord show all
Includes:
Statesman::Adapters::ActiveRecordQueries
Defined in:
app/models/spina/shop/order.rb,
app/models/spina/shop/order/billing.rb,
app/models/spina/shop/order/state_machine_transitions.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#passwordObject

Returns the value of attribute password.



12
13
14
# File 'app/models/spina/shop/order.rb', line 12

def password
  @password
end

#validate_deliveryObject

Returns the value of attribute validate_delivery.



12
13
14
# File 'app/models/spina/shop/order.rb', line 12

def validate_delivery
  @validate_delivery
end

#validate_detailsObject

Returns the value of attribute validate_details.



12
13
14
# File 'app/models/spina/shop/order.rb', line 12

def validate_details
  @validate_details
end

#validate_paymentObject

Returns the value of attribute validate_payment.



12
13
14
# File 'app/models/spina/shop/order.rb', line 12

def validate_payment
  @validate_payment
end

#validate_stockObject

Returns the value of attribute validate_stock.



12
13
14
# File 'app/models/spina/shop/order.rb', line 12

def validate_stock
  @validate_stock
end

Class Method Details

.transition_nameObject



92
93
94
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 92

def self.transition_name
  :order_transitions
end

Instance Method Details

#ageObject



157
158
159
160
161
162
# File 'app/models/spina/shop/order.rb', line 157

def age
  now = Time.zone.now
  if date_of_birth
    now.year - date_of_birth.year - ((now.month > date_of_birth.month || (now.month == date_of_birth.month && now.day >= date_of_birth.day)) ? 0 : 1)
  end
end

#apply_gift_card!Object



168
169
170
171
172
173
# File 'app/models/spina/shop/order.rb', line 168

def apply_gift_card!
  transaction do
    update_attributes!(gift_card_amount: gift_card_amount)
    gift_card.update_attributes!(remaining_balance: gift_card.remaining_balance - gift_card_amount)
  end
end

#assign_address(address, address_type:) ⇒ Object



78
79
80
81
82
# File 'app/models/spina/shop/order.rb', line 78

def assign_address(address, address_type:)
  [:street1, :postal_code, :city, :house_number, :house_number_addition, :country].each do |f|
    send("#{address_type}_#{f}=", address.send(f))
  end
end

#billing_addressObject



70
71
72
# File 'app/models/spina/shop/order.rb', line 70

def billing_address
  "#{billing_street1} #{billing_house_number}#{billing_house_number_addition}".strip
end

#billing_first_nameObject



24
25
26
# File 'app/models/spina/shop/order/billing.rb', line 24

def billing_first_name
  first_name
end

#billing_last_nameObject



28
29
30
# File 'app/models/spina/shop/order/billing.rb', line 28

def billing_last_name
  last_name
end

#billing_nameObject



125
126
127
128
# File 'app/models/spina/shop/order.rb', line 125

def billing_name
  full_name = "#{first_name} #{last_name}".strip
  company.present? ? "#{company} (#{full_name})" : full_name
end

#building?Boolean

Returns:

  • (Boolean)


43
44
45
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 43

def building?
  current_state == 'building'
end

#cancelled?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 15

def cancelled?
  cancelled_at.present?
end

#confirmed?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 19

def confirmed?
  confirming_at.present?
end

#confirming?Boolean

Returns:

  • (Boolean)


47
48
49
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 47

def confirming?
  current_state == 'confirming'
end

#delivered?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 35

def delivered?
  delivered_at.present?
end

#delivery_addressObject



74
75
76
# File 'app/models/spina/shop/order.rb', line 74

def delivery_address
  "#{delivery_street1} #{delivery_house_number}#{delivery_house_number_addition}".strip
end

#delivery_optionsObject



84
85
86
# File 'app/models/spina/shop/order.rb', line 84

def delivery_options
  DeliveryOption.all
end

#delivery_priceObject



8
9
10
# File 'app/models/spina/shop/order/billing.rb', line 8

def delivery_price
  read_attribute(:delivery_price) || delivery_option.try(:price_for_order, self) || BigDecimal(0)
end

#delivery_tax_modifierObject



16
17
18
# File 'app/models/spina/shop/order/billing.rb', line 16

def delivery_tax_modifier
  (delivery_tax_rate + BigDecimal(100)) / BigDecimal(100)
end

#delivery_tax_rateObject



12
13
14
# File 'app/models/spina/shop/order/billing.rb', line 12

def delivery_tax_rate
  read_attribute(:delivery_tax_rate) || delivery_option.try(:tax_group).try(:tax_rate_for_order, self) || BigDecimal(0)
end

#duplicate!Object



182
183
184
185
186
187
188
189
190
191
192
193
# File 'app/models/spina/shop/order.rb', line 182

def duplicate!
  # Duplicate order
  transaction do
    shopping_cart = Order.create!(attributes.reject{|key, value| key.in? %w(id delivery_price delivery_tax_rate status received_at shipped_at paid_at delivered_at order_prepared_at payment_id payment_url failed_at cancelled_at delivery_tracking_ids picked_up_at order_number confirming_at created_at updated_at)})
    shopping_cart.discount = discount
    shopping_cart.gift_card = gift_card
    order_items.each do |order_item|
      OrderItem.create!(order_item.attributes.reject{|key, value| key.in? %w(id created_at updated_at unit_price unit_cost_price discount_amount weight tax_rate order_id)}.merge(order_id: shopping_cart.id))
    end
    update_attributes!(duplicate: shopping_cart)
  end
end

#empty?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'app/models/spina/shop/order.rb', line 92

def empty?
  order_items.none?
end

#everything_valid?Boolean

Returns:

  • (Boolean)


195
196
197
198
199
200
201
# File 'app/models/spina/shop/order.rb', line 195

def everything_valid?
  self.validate_details = true
  self.validate_stock = true
  self.validate_payment = true
  self.validate_delivery = true
  valid?
end

#failed?Boolean

Returns:

  • (Boolean)


11
12
13
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 11

def failed?
  failed_at.present?
end

#gift_card_amountObject



20
21
22
# File 'app/models/spina/shop/order/billing.rb', line 20

def gift_card_amount
  read_attribute(:gift_card_amount) || gift_card.try(:amount_for_order, self) || BigDecimal(0)
end

#merge!(order) ⇒ Object

Raises:



142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'app/models/spina/shop/order.rb', line 142

def merge!(order)
  raise Error if confirmed? || order.confirmed?

  transaction do
    order.order_items.where(orderable: order_items.map(&:orderable)).each do |duplicate|
      current_order_item = order_items.find_by(orderable: duplicate.orderable)
      current_order_item.increment(:quantity, duplicate.quantity)
      current_order_item.save
    end

    order.order_items.where(orderable: order_items.map(&:orderable)).destroy_all
    order.order_items.update_all(order_id: id)
  end
end

#nothing_owed?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'app/models/spina/shop/order/billing.rb', line 54

def nothing_owed?
  paid? || to_be_paid == BigDecimal(0)
end

#numberObject

Order number with zeroes



121
122
123
# File 'app/models/spina/shop/order.rb', line 121

def number
  order_number ? order_number.to_s.rjust(8, '0') : nil
end

#of_age?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'app/models/spina/shop/order.rb', line 164

def of_age?
  age >= 18 if age
end

#order_prepared?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 27

def order_prepared?
  order_prepared_at.present?
end

#order_totalObject



4
5
6
# File 'app/models/spina/shop/order/billing.rb', line 4

def order_total
  order_items.inject(BigDecimal(0)) { |t, i| t + i.total }
end

#paid?Boolean

Returns:

  • (Boolean)


23
24
25
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 23

def paid?
  paid_at.present?
end

#picked_up?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 39

def picked_up?
  picked_up_at.present?
end

#prices_include_taxObject

If VAT is reverse charged, all prices must be excluding VAT



116
117
118
# File 'app/models/spina/shop/order.rb', line 116

def prices_include_tax
  vat_reverse_charge? ? false : read_attribute(:prices_include_tax)
end

#productsObject



100
101
102
103
104
105
106
107
108
# File 'app/models/spina/shop/order.rb', line 100

def products
  order_items.map do |order_item|
    if order_item.is_product_bundle?
      order_item.orderable.products
    else
      order_item.orderable
    end
  end.flatten.uniq
end

#received?Boolean

Returns:

  • (Boolean)


7
8
9
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 7

def received?
  received_at.present?
end

#remove_gift_card!Object



175
176
177
178
179
180
# File 'app/models/spina/shop/order.rb', line 175

def remove_gift_card!
  transaction do
    gift_card.update_attributes!(remaining_balance: gift_card.remaining_balance + gift_card_amount)
    update_attributes!(gift_card_amount: nil)
  end
end

#requires_shipping?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'app/models/spina/shop/order.rb', line 96

def requires_shipping?
  delivery_option.try(:requires_shipping)
end

#shipped?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 31

def shipped?
  shipped_at.present?
end

#soonest_delivery_dateObject



88
89
90
# File 'app/models/spina/shop/order.rb', line 88

def soonest_delivery_date
  delivery_option.try(:soonest_delivery_date_for_order, self)
end

#state_machineObject



88
89
90
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 88

def state_machine
  @state_machine ||= OrderStateMachine.new(self, transition_class: OrderTransition, association_name: :order_transitions)
end

#status_css_classObject



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 67

def status_css_class
  case current_state
  when 'preparing'
    'primary'
  when 'paid'
    'primary'
  when 'shipped'
    'success'
  when 'delivered'
    'success'
  when 'picked_up'
    'success'
  when 'failed'
    'danger'
  when 'cancelled'
    'danger'
  else
    ''
  end
end

#status_progressObject



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/models/spina/shop/order/state_machine_transitions.rb', line 51

def status_progress
  if delivered? || picked_up?
    100
  elsif shipped?
    80
  elsif order_prepared?
    60
  elsif paid?
    40
  elsif received?
    20
  else
    0
  end
end

#tax_amountObject



58
59
60
# File 'app/models/spina/shop/order/billing.rb', line 58

def tax_amount
  tax_amount_by_rates.inject(BigDecimal.new(0)) { |t, r| t + r[1][:tax_amount] }
end

#tax_amount_by_ratesObject



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/models/spina/shop/order/billing.rb', line 62

def tax_amount_by_rates
  if vat_reverse_charge?
    rates = {"0": {tax_amount: BigDecimal.new(0), total: BigDecimal.new(0)}}
  else
    items = [order_items]
    items << OpenStruct.new(tax_rate: delivery_tax_rate, tax_modifier: delivery_tax_modifier, total: delivery_price) if delivery_option.present?
    rates = items.flatten.inject({}) do |h, item|
      rate = h[item.tax_rate] ||= { tax_amount: BigDecimal(0), total: BigDecimal(0) }
      if prices_include_tax
        rate[:total] += (item.total / item.tax_modifier).round(2)
        rate[:tax_amount] += item.total - (item.total / item.tax_modifier).round(2)
      else
        rate[:total] += item.total
        rate[:tax_amount] += (item.total * (BigDecimal(item.tax_rate) / BigDecimal(100))).round(2)
      end
      h
    end
  end

  rates.sort{|x, y| y[0] <=> x[0]}.to_h
end

#to_be_paidObject



41
42
43
# File 'app/models/spina/shop/order/billing.rb', line 41

def to_be_paid
  total - gift_card_amount
end

#to_be_paid_roundObject

Mandatory rounding to 0.05 for cash payments in a store



46
47
48
# File 'app/models/spina/shop/order/billing.rb', line 46

def to_be_paid_round
  (to_be_paid * 2).round(1, :half_up) / 2
end

#to_be_paid_rounding_differenceObject



50
51
52
# File 'app/models/spina/shop/order/billing.rb', line 50

def to_be_paid_rounding_difference
  to_be_paid_round - to_be_paid
end

#totalObject

Total of the order



33
34
35
# File 'app/models/spina/shop/order/billing.rb', line 33

def total
  order_total + delivery_price + (prices_include_tax ? 0 : tax_amount)
end

#total_excluding_taxObject



37
38
39
# File 'app/models/spina/shop/order/billing.rb', line 37

def total_excluding_tax
  total - tax_amount
end

#total_itemsObject



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

def total_items
  order_items.sum(:quantity)
end

#total_weightObject



134
135
136
# File 'app/models/spina/shop/order.rb', line 134

def total_weight
  order_items.inject(BigDecimal(0)) { |t, i| t + i.total_weight }
end

#total_weight_in_ouncesObject



138
139
140
# File 'app/models/spina/shop/order.rb', line 138

def total_weight_in_ounces
  Measurement.parse("#{total_weight} gr").convert_to(:oz).quantity
end

#vat_reverse_charge?Boolean

By default this method returns false, but you can override it and add your own logic

Returns:

  • (Boolean)


111
112
113
# File 'app/models/spina/shop/order.rb', line 111

def vat_reverse_charge?
  false
end