Skip to content

Instantly share code, notes, and snippets.

@IlyaDonskikh
Last active August 29, 2015 14:15
Show Gist options
  • Save IlyaDonskikh/5865f85aa756b1f0a653 to your computer and use it in GitHub Desktop.
Save IlyaDonskikh/5865f85aa756b1f0a653 to your computer and use it in GitHub Desktop.
Card Payment
class CardPayment < ActiveRecord::Base
include InterpolateModule
attr_accessor :refund_value
## Relations
belongs_to :money_operation
has_one :order, through: :money_operation
## Variables
OPERATIONS = %w(payment refund)
STATUSES = %w(process success failed holded deposited reversed deposited_and_refunded)
## Validates
validates :amount, numericality: { only_integer: true }
validates_inclusion_of :refund_value, in: 0..1000000, if: '!refund_value.blank?'
validates_inclusion_of :status, in: STATUSES, allow_blank: true
validates_inclusion_of :operation, in: OPERATIONS
## Callbacks
after_create :create_gateway_order, if: 'money_operation && operation == "payment" && status == "process"'
after_update :check_balance, if: 'money_operation'
## Etc
def cando?(method, current_user, *params)
case method
when 'index' then current_user && %w(manager admin).include?(current_user.role) ? true : false
when 'new', 'create' then current_user && %w(manager booking_manager).include?(current_user.role) ? true : false
when 'show' then self.operation == 'payment' && %w(manager booking_manager).include?(current_user.role) ? true : false
when 'status' then self.operation == 'payment' && (self.status == 'process' || (current_user && current_user.role == 'manager' || (order && order.booking_manager == current_user))) ? true : false
when 'pay' then self.operation == 'payment' && self.status == 'process' ? true : false
when 'deposit', 'reverse' then current_user && (current_user.role == 'manager' || (order && order.booking_manager == current_user)) && self.operation == 'payment' && self.status == 'holded' ? true : false
when 'refund' then current_user && (current_user.role == 'manager' || (order && order.booking_manager == current_user)) && self.money_operation_id && self.operation == 'payment' && %w(deposited deposited_and_refunded).include?(self.status) ? true : false
else false
end
end
def status_process
status_data = self.extended_status_gateway
self.status_code = status_data[:status]
self.status = case status_code
when '0' then 'process'
when '1' then 'holded'
when '2' then 'deposited'
when '3' then 'reversed'
when '4' then 'deposited_and_refunded'
else 'failed'
end
self.pan = status_data[:pan]
self.card_holder = status_data[:card_holder]
self.ip_client = status_data[:ip_client]
self.bank_name = status_data[:bank_name]
self.bank_country_code = status_data[:bank_country_code]
self.bank_country_name = status_data[:bank_country_name]
self.save
self
end
def card_converted_price(value = nil)
value ||= amount
currency = Currency.new price: value
if money_operation
currency.exchange_rate = money_operation.usd_rate
currency.exchange_ratio = money_operation.ratio
currency.convert if currency.valid?
end
currency.convert * 100
end
def check_balance
if self.operation == 'payment' && order.balance >= order.final_price && order.final_price != 0 && order.status.match('_paid').nil?
order.status = 'booked_paid'
order.save
end
end
def order_number
order_number = order ? (order.code + '_') : ''
timestamps = created_at || Time.now
order_number += created_at.now.strftime('%d%m%Y%H%M%S').to_s + '_'
order_number += case Rails.env
when 'production' then 'p'
when 'charter' then 'c'
when 'staging' then 's'
when 'avia' then 'a'
else 'n'
end
end
def create_gateway_order
converted_price = card_converted_price
client = sber_connect
response = client.call(:register_order_pre_auth,
attributes: { 'xmlns' => 'http://engine.paymentgate.ru/webservices/merchant' },
message: {
'order' => {
'returnUrl' => Rails.application.routes.url_helpers.status_panel_card_payment_url(self).to_s
},
:attributes! => {
'order' => {
'merchantOrderNumber' => order_number,
'xmlns' => '',
amount: converted_price
}
}
}
)
if response.body.first[1][:return][:@error_code].to_s == '0'
self.gateway_id = response.body.first[1][:return][:@order_id].to_s
self.gateway_url = response.body.first[1][:return][:form_url].to_s
self.save
true
else
errors.add(:gateway_id, :create)
money_operation.card_payments.create(amount: order.final_price, operation: 'register_order_pre_auth', status: 'fails')
false
end
end
def extended_status_gateway
client = sber_connect
response = client.call(:get_order_status_extended,
attributes: { 'xmlns' => 'http://engine.paymentgate.ru/webservices/merchant' },
message: {
'order' => {},
:attributes! => {
'order' => {
'orderId' => self.gateway_id,
'xmlns' => ''
}
}
}
)
data = {}
response = response.body.first[1][:return]
card_auth_info = response[:card_auth_info]
bank_info = response[:bank_info]
data[:status] = response[:@order_status].to_s
data[:ip_client] = response[:@ip].to_s
data[:card_holder] = card_auth_info[:@cardholder_name].to_s
data[:pan] = card_auth_info[:@masked_pan].to_s
data[:bank_name] = bank_info[:@bank_name].to_s
data[:bank_country_code] = bank_info[:@bank_country_code].to_s
data[:bank_country_name] = bank_info[:@bank_country_name].to_s
data
end
def deposit_process
client = sber_connect
response = client.call(:deposit_order,
attributes: { 'xmlns' => 'http://engine.paymentgate.ru/webservices/merchant' },
message: {
'order' => {},
:attributes! => {
'order' => {
'orderId' => self.gateway_id,
'depositAmount' => '0',
'xmlns' => ''
}
}
}
)
self.status_process
end
def reverse_process
client = sber_connect
response = client.call(:reverse_order,
attributes: { 'xmlns' => 'http://engine.paymentgate.ru/webservices/merchant' },
message: {
'order' => {},
:attributes! => {
'order' => {
'orderId' => self.gateway_id,
'xmlns' => ''
}
}
}
)
self.status_process
end
def refund_process
converted_price = card_converted_price(refund_value)
client = sber_connect
response = client.call(:refund_order,
attributes: { 'xmlns' => 'http://engine.paymentgate.ru/webservices/merchant' },
message: {
'order' => {},
:attributes! => {
'order' => {
'orderId' => self.gateway_id,
'refundAmount' => converted_price,
'xmlns' => ''
}
}
}
)
self.status_process
mo = self.money_operation
if response.body.first[1][:return][:@error_code].to_s == '0'
mo.card_payments.create(amount: refund_value, operation: 'refund', status: 'success')
mo.update(value: mo.value - refund_value)
end
end
private
def sber_connect
Savon.client(wsdl: Phuketcharter::Application::SBERBANK_HTTP + '/payment/webservices/merchant-ws?wsdl', wsse_auth: [Phuketcharter::Application::SBERBANK_USER, Phuketcharter::Application::SBERBANK_PASSWORD], env_namespace: :soap, namespace_identifier: nil, convert_request_keys_to: :camelcase)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment