Skip to content

Instantly share code, notes, and snippets.

@InsilicoSoft
Created August 3, 2017 08:03
Show Gist options
  • Select an option

  • Save InsilicoSoft/94d3570ef328ed505cefe4b55fde9fc9 to your computer and use it in GitHub Desktop.

Select an option

Save InsilicoSoft/94d3570ef328ed505cefe4b55fde9fc9 to your computer and use it in GitHub Desktop.
The order model
# == Schema Information
#
# Table name: orders
#
# id :integer not null, primary key
# user_id :integer
# product_id :integer
# quantity :integer
# payment_kind :string
# aasm_state :string
# arrival_date :datetime
# total :decimal(8, 2)
# created_at :datetime not null
# updated_at :datetime not null
# completed_at :datetime
#
# Indexes
#
# index_orders_on_product_id (product_id)
# index_orders_on_user_id (user_id)
#
class Order < ApplicationRecord
ALLOWED_SORT_OPTIONS_FOR_BUSINESS = %w(products.title orders.arrival_date users.first_name orders.created_at).freeze
include AASM
include OrderValidations # validate, before_validation
include OrderScopes
has_one :balance_withdrawal, -> { withdrawal },
class_name: 'BalanceTransaction', foreign_key: 'withdrawal_order_id'
has_one :payment, foreign_key: 'future_order_id' # optional - payment when user chooses to pay without balance
belongs_to :user
belongs_to :product
enum payment_kind: %w(balance payment_service).map { |v| [v, v] }.to_h
before_save :recalculate_total, if: :quantity_changed?
after_create :generate_payment, if: :payment_service?
# We need to do this after commit so that update validations (order closed for modification) pass
after_create :withdraw_and_acknowledge, if: :balance?
aasm do
state :pending, initial: true
state :paid_for
state :completed
state :canceled
state :product_buying_failed
event :acknowledge_payment, after: :on_paid_actions do
transitions from: :pending, to: :paid_for
end
event :complete, before: -> { self.completed_at = Time.current } do
transitions from: :paid_for, to: :completed
end
event :cancel do
transitions to: :canceled
end
event :fail_product_buying do
transitions to: :product_buying_failed
end
end
def price_for_product
Product::ORDER_PRICE_FORMULA.call(product) if product.present?
end
# Calculates order total according to formula stored in product
def order_total
price_for_product.to_f * quantity
end
# @callback after_create if order is being paid with balance
# Withdraws funds from balance and acknowledges payment. Creates instant balance withdrawal transaction when user
# chooses to pay for product with option other than balance withdrawal.
def withdraw_and_acknowledge
create_balance_withdrawal(amount: order_total, user: user)
acknowledge_payment!
end
def payment_redirect_url
payment&.service_redirect_url
end
private
# @callback after_create if order is being paid by payment_service
def generate_payment
create_payment!(amount: order_total, user: user)
end
# @callback before_save
def recalculate_total
self.total = order_total
end
def on_paid_actions
fail_product_buying! unless product.decrease_amount(quantity)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment