Created
August 3, 2017 08:03
-
-
Save InsilicoSoft/94d3570ef328ed505cefe4b55fde9fc9 to your computer and use it in GitHub Desktop.
The order model
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # == 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