I am new to rails and new to active merchant, just want to know if the following code is good enough for payment processing using active merchant.
As you can see, I am using authorize and capture instead of the purchase method. My main concern is the "brought_quantity" subtraction in the code (and it's counter part, when the payment processing fails), I am not quite sure how to deal with it in case of race condition or error from the payment gateway.
Please note that the variable transactions is a instance variable for a model/table where I store the information of the payment gateways responses.
def purchase(item)
price = price_in_cents(item.value)
if !item.can_purchase
errors[:base] << "We are sorry, all items are sold out at the moment."
return false
else
response = GATEWAY.authorize(price, credit_card, purchase_options)
transactions.create!(:action => "authorize", :value => price, :params => response)
#p response
if response.success?
item.brought_quantity = item.brought_quantity + 1
if item.save!
response = GATEWAY.capture(price, response.authorization)
transactions.create!(:action => "capture", :value => price, :params => response)
if !response.success?
errors[:base] << "There were some problem processing your payment, please either try again or contact us at [email protected] with this error id: 111"
@rd = RunningDeal.find_by_id(@item.id)
@rd.brought_quantity = @rd.brought_quantity - 1
@rd.save!
return false
end
else
errors[:base] << "We are sorry, all items are sold out at the moment."
return false
end
else
# problem process their payment, put out error
errors[:base] << "There were some problem processing your payment, please either try again or contact us at [email protected] with this error id: 111"
return false
end
end
return true
end
Edit Ok, did some refactoring and here is the updated code, any comments and suggestions are welcome. I removed the ! on transaction.create since that not a important enough operation to raise an exception.
Here is the updated code based on the feedback.
#from running_deal.rb
def decrement_deal_quantity
self.brought_quantity = self.brought_quantity + 1
return self.save!
end
def purchase(running_deal)
price = price_in_cents(running_deal.value)
if !running_deal.can_purchase
errors[:base] << "We are sorry, all items are sold out at the moment."
return false
else
auth_resp = GATEWAY.authorize(price, credit_card, purchase_options)
transactions.create(:action => "authorize", :value => price, :success => auth_resp.success?, :message => auth_resp.message, :authorization => auth_resp.authorization, :params => auth_resp)
if auth_resp.success?
begin
running_deal.decrement_deal_quantity
cap_resp = GATEWAY.capture(price, auth_resp.authorization)
transactions.create(:action => "capture", :value => price, :success => cap_resp.success?, :message => cap_resp.message, :authorization => cap_resp.authorization, :params => cap_resp)
rescue
GATEWAY.void(auth_resp.authorization, purchase_options) if auth_resp.success?
errors[:base] << "There were some problem processing your payment, please either try again or contact us at [email protected]"
return false
end
else
# problem process their payment, put out error
errors[:base] << "There were some problem processing your payment, please either try again or contact us at [email protected]"
return false
end
end
return true
end
processing transactions is tricky.
Couple of thoughts:
this code needs to be moved into a model method:
@rd = RunningDeal.find_by_id(@item.id)
@rd.brought_quantity = @rd.brought_quantity - 1
@rd.save!
you need to add clause to the bottom of your method to catch exceptions, since you are calling create!() not create() (which return true if it saves)
rescue Exception => e # error handing end
it is unclear why if item.save! fails your error message indicates that the item is sold out? That is totally obscure.
Overall, you want to do someting like this:
Hope this helps.