Skip to content

Commit

Permalink
define states and events for withdraw
Browse files Browse the repository at this point in the history
  • Loading branch information
tomlion committed Mar 12, 2014
1 parent 55c708e commit bdf74e2
Show file tree
Hide file tree
Showing 17 changed files with 260 additions and 153 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ gem 'pusher'
gem 'http_accept_language'
gem "globalize", "~> 4.0.0"

gem 'aasm'

group :development, :test do
gem 'factory_girl_rails'
gem 'faker'
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
aasm (3.1.1)
actionmailer (4.0.2)
actionpack (= 4.0.2)
mail (~> 2.5.4)
Expand Down Expand Up @@ -338,6 +339,7 @@ PLATFORMS
ruby

DEPENDENCIES
aasm
active_hash
acts-as-taggable-on
bcrypt-ruby (~> 3.1.2)
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/admin/withdraws_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ def edit
end

def update
Withdrawing.new(@withdraw).transact
@withdraw.process!
flash[:notice] = t('.success')
redirect_to admin_withdraws_path
end

def destroy
Withdrawing.new(@withdraw).reject
@withdraw.reject!
flash[:notice] = t('.success')
redirect_to admin_withdraws_path
end
Expand Down
11 changes: 4 additions & 7 deletions app/controllers/private/withdraws_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ def new

def create
@withdraw = Withdraw.new(withdraw_params)
withdrawing = Withdrawing.new(@withdraw)

if withdrawing.request
if @withdraw.save
redirect_to edit_withdraw_path(@withdraw)
else
@withdraw_addresses = current_user.withdraw_addresses
Expand All @@ -21,15 +20,13 @@ def create

def update
@withdraw = current_user.withdraws.find(params[:id])
@withdraw.update_attribute(:state, :wait) if @withdraw.state.apply?
@withdraw.examine
@withdraw.submit!
redirect_to new_withdraw_path, flash: {notice: t('.request_accepted')}
end

def destroy
@withdraw = current_user.withdraws.find(params[:id])
withdrawing = Withdrawing.new(@withdraw)
withdrawing.cancel
@withdraw.cancel!
redirect_to new_withdraw_path
end

Expand All @@ -47,7 +44,7 @@ def load_history
def withdraw_params
params[:withdraw][:state] = :apply
params[:withdraw][:member_id] = current_user.id
params.require(:withdraw).permit(:sum, :password, :member_id, :withdraw_address_id, :state)
params.require(:withdraw).permit(:sum, :password, :member_id, :withdraw_address_id)
end
end
end
4 changes: 2 additions & 2 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Account < ActiveRecord::Base
ZERO = 0.to_d

FUNS = {:unlock_funds => 1, :lock_funds => 2, :plus_funds => 3, :sub_funds => 4, :unlock_and_sub_funds => 5}

belongs_to :member
has_many :payment_addresses
has_many :withdraw_addresses
Expand Down Expand Up @@ -49,7 +49,7 @@ def plus_funds(amount, fee: ZERO, reason: nil, ref: nil)
self.save
self
end

def sub_funds(amount, fee: ZERO, reason: nil, ref: nil)
(amount <= ZERO or amount > self.balance) and raise AccountError
self.balance -= amount
Expand Down
10 changes: 3 additions & 7 deletions app/models/account_version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,12 @@ def amount_change
balance + locked
end

def modify_amount
@modify_amount ||= self.locked + self.balance
end

def in
modify_amount > 0 ? modify_amount : nil
amount_change > 0 ? amount_change : nil
end

def out
modify_amount < 0 ? modify_amount : nil
def out
amount_change < 0 ? amount_change : nil
end

alias :template :detail_template
Expand Down
27 changes: 9 additions & 18 deletions app/models/job/coin.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
module Job
class Coin
@queue = :coin

def self.perform(withdraw_id)
ActiveRecord::Base.transaction do
withdraw = Withdraw.find(withdraw_id).lock!
raise :unknown_state unless withdraw.state.coin_ready?
withdraw = Withdraw.find(withdraw_id)

amount = withdraw.amount
balance = CoinRPC[withdraw.currency].getbalance.to_d

amount = withdraw.amount
balance = CoinRPC[withdraw.currency].getbalance.to_d
raise Account::BalanceError, 'Insufficient coins' if balance < amount

if balance >= amount
withdraw.update_attribute(:state, :coin_done)
end
end
CoinRPC[withdraw.currency].settxfee 0.0005
tx_id = CoinRPC[withdraw.currency].sendtoaddress withdraw.address, withdraw.amount.to_f

ActiveRecord::Base.transaction do
withdraw = Withdraw.find(withdraw_id).lock!
raise :unknown_state unless withdraw.state.coin_done?
CoinRPC[withdraw.currency].settxfee 0.0005
tx_id = CoinRPC[withdraw.currency].sendtoaddress withdraw.address, withdraw.amount.to_f
withdraw.update_attributes(tx_id: tx_id, state: :done)
end
withdraw.update_column :tx_id, tx_id
end
end
end

16 changes: 5 additions & 11 deletions app/models/job/examine.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
module Job
class Examine
@queue = :examine

def self.perform(withdraw_id)
withdraw = Withdraw.find(withdraw_id)
return unless withdraw.state.wait?

ActiveRecord::Base.transaction do
withdraw = Withdraw.find(withdraw_id).lock!
return unless withdraw.state.wait?

if withdraw.account.examine
withdraw.update_attribute(:state, :examined)
else
withdraw.update_attribute(:state, :examined_warning)
end
if withdraw.account.examine
withdraw.accept!
else
withdraw.mark_suspect!
end
end
end
Expand Down
97 changes: 89 additions & 8 deletions app/models/withdraw.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class Withdraw < ActiveRecord::Base
include AASM
include Concerns::Withdraws::Bank
include Concerns::Withdraws::Satoshi

Expand All @@ -17,10 +18,10 @@ class Withdraw < ActiveRecord::Base
belongs_to :member
belongs_to :account
has_many :account_versions, :as => :modifiable
attr_accessor :withdraw_address_id, :sum
attr_accessor :withdraw_address_id

after_create :generate_sn
before_validation :populate_fields_from_address, :fix_fee
after_create :generate_sn
after_update :bust_last_done_cache, if: :state_changed_to_done

validates :address_type, :address, :address_label,
Expand All @@ -31,7 +32,7 @@ class Withdraw < ActiveRecord::Base

validates :sum, presence: true, on: :create
validates :sum, numericality: {greater_than: 0}, on: :create
validates :tx_id, presence: true, uniqueness: true, on: :update
validates :tx_id, uniqueness: true, allow_nil: true, on: :update

validate :ensure_account_balance, on: :create

Expand All @@ -40,7 +41,7 @@ def coin?
end

def examine
Resque.enqueue(Job::Examine, self.id) if self.state.wait?
Resque.enqueue(Job::Examine, self.id) if submitted?
end

def position_in_queue
Expand All @@ -65,10 +66,90 @@ def generate_sn
update_column(:sn, sn)
end

def sum
@sum || ((self.amount || 0.to_d) + (self.fee || 0.to_d))
aasm do
state :submitting, initial: true
state :submitted, after_enter: :lock_funds, after_commit: [:send_withdraw_confirm_email, :examine]
state :canceled
state :accepted
state :suspect
state :rejected
state :processing
state :almost_done
state :done
state :failed

event :submit do
transitions from: :submitting, to: :submitted
end

event :cancel do
transitions from: [:submitting, :submitted, :accepted], to: :canceled
before do
unlock_funds unless submitting?
end
end

event :mark_suspect do
transitions from: :submitted, to: :suspect
end

event :accept do
transitions from: :submitted, to: :accepted
end

event :reject do
transitions from: :accepted, to: :rejected
after :unlock_funds
end

event :process do
transitions from: :accepted, to: :processing
end

event :succeed do
transitions from: :processing, to: :done, on_transition: -> (obj) do
obj.update_column :aasm_state, 'almost_done'
obj.send_coins
end

before [:set_tx_id, :unlock_and_sub_funds]

error do |e|
#warn e
#@reason = e.to_s
end
end

event :fail do
transitions from: :processing, to: :failed
end
end

def lock_funds
account.lock_funds sum, reason: Account::WITHDRAW_LOCK, ref: self
end

def unlock_funds
account.unlock_funds sum, reason: Account::WITHDRAW_UNLOCK, ref: self
end

def unlock_and_sub_funds
account.unlock_and_sub_funds sum, locked: sum, fee: fee, reason: Account::WITHDRAW, ref: self
end

def set_tx_id
@tx_id = @sn unless coin?
end

def send_withdraw_confirm_email
puts 'Sending withdraw confirm email!'
end

def send_coins
Resque.enqueue(Job::Coin, self.id) if coin?
end


private

def last_completed_withdraw_cache_key
Expand Down Expand Up @@ -100,8 +181,6 @@ def populate_fields_from_address
end

def fix_fee
self.sum = self.sum.to_d

if self.respond_to? valid_method = "_valid_#{self.address_type}_sum"
error = self.instance_eval(valid_method)
self.errors.add('sum', "#{self.address_type}_#{error}".to_sym) if error
Expand All @@ -123,4 +202,6 @@ def state_changed_to_done
def bust_last_done_cache
Rails.cache.delete(last_completed_withdraw_cache_key)
end


end
Loading

0 comments on commit bdf74e2

Please sign in to comment.