module ActiveMerchant #:nodoc: module Billing #:nodoc: class WepayGateway < Gateway self.test_url = 'https://stage.wepayapi.com/v2' self.live_url = 'https://wepayapi.com/v2' self.supported_countries = ['US'] self.supported_cardtypes = [:visa, :master, :american_express, :discover] self.homepage_url = 'https://www.wepay.com/' self.default_currency = 'USD' self.display_name = 'WePay' API_VERSION = "2017-02-01" def initialize(options = {}) requires!(options, :client_id, :account_id, :access_token) super(options) end def purchase(money, payment_method, options = {}) post = {} if payment_method.is_a?(String) MultiResponse.run do |r| r.process { authorize_with_token(post, money, payment_method, options) } r.process { capture(money, r.authorization, options) } end else MultiResponse.run do |r| r.process { store(payment_method, options) } r.process { authorize_with_token(post, money, r.authorization, options) } r.process { capture(money, r.authorization, options) } end end end def authorize(money, payment_method, options = {}) post = {} if payment_method.is_a?(String) authorize_with_token(post, money, payment_method, options) else MultiResponse.run do |r| r.process { store(payment_method, options) } r.process { authorize_with_token(post, money, r.authorization, options) } end end end def capture(money, identifier, options = {}) checkout_id, original_amount = split_authorization(identifier) post = {} post[:checkout_id] = checkout_id if(money && (original_amount != amount(money))) post[:amount] = amount(money) end commit('/checkout/capture', post, options) end def void(identifier, options = {}) post = {} post[:checkout_id] = split_authorization(identifier).first post[:cancel_reason] = (options[:description] || "Void") commit('/checkout/cancel', post, options) end def refund(money, identifier, options = {}) checkout_id, original_amount = split_authorization(identifier) post = {} post[:checkout_id] = checkout_id if(money && (original_amount != amount(money))) post[:amount] = amount(money) end post[:refund_reason] = (options[:description] || "Refund") post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message] post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message] commit("/checkout/refund", post, options) end def store(creditcard, options = {}) requires!(options, :email) post = {} post[:client_id] = @options[:client_id] post[:user_name] = "#{creditcard.first_name} #{creditcard.last_name}" post[:email] = options[:email] || "unspecified@example.com" post[:cc_number] = creditcard.number post[:cvv] = creditcard.verification_value unless options[:recurring] post[:expiration_month] = creditcard.month post[:expiration_year] = creditcard.year post[:original_ip] = options[:ip] if options[:ip] post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint] if(billing_address = (options[:billing_address] || options[:address])) post[:address] = {} post[:address]["address1"] = billing_address[:address1] if billing_address[:address1] post[:address]["city"] = billing_address[:city] if billing_address[:city] post[:address]["country"] = billing_address[:country] if billing_address[:country] post[:address]["region"] = billing_address[:state] if billing_address[:state] post[:address]["postal_code"] = billing_address[:zip] end if options[:recurring] == true post[:client_secret] = @options[:client_secret] commit('/credit_card/transfer', post, options) else commit('/credit_card/create', post, options) end end def supports_scrubbing? true end def scrub(transcript) transcript. gsub(%r((\\?"cc_number\\?":\\?")[^\\"]+(\\?"))i, '\1[FILTERED]\2'). gsub(%r((\\?"cvv\\?":\\?")[^\\"]+(\\?"))i, '\1[FILTERED]\2'). gsub(%r((Authorization: Bearer )\w+)i, '\1[FILTERED]\2') end private def authorize_with_token(post, money, token, options) add_token(post, token) add_product_data(post, money, options) commit('/checkout/create', post, options) end def add_product_data(post, money, options) post[:account_id] = @options[:account_id] post[:amount] = amount(money) post[:short_description] = (options[:description] || "Purchase") post[:type] = (options[:type] || "goods") post[:currency] = (options[:currency] || currency(money)) post[:long_description] = options[:long_description] if options[:long_description] post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message] post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message] post[:reference_id] = options[:order_id] if options[:order_id] post[:unique_id] = options[:unique_id] if options[:unique_id] post[:redirect_uri] = options[:redirect_uri] if options[:redirect_uri] post[:callback_uri] = options[:callback_uri] if options[:callback_uri] post[:fallback_uri] = options[:fallback_uri] if options[:fallback_uri] post[:require_shipping] = options[:require_shipping] if options[:require_shipping] post[:shipping_fee] = options[:shipping_fee] if options[:shipping_fee] post[:charge_tax] = options[:charge_tax] if options[:charge_tax] post[:mode] = options[:mode] if options[:mode] post[:preapproval_id] = options[:preapproval_id] if options[:preapproval_id] post[:prefill_info] = options[:prefill_info] if options[:prefill_info] post[:funding_sources] = options[:funding_sources] if options[:funding_sources] add_fee(post, options) end def add_token(post, token) payment_method = {} payment_method[:type] = "credit_card" payment_method[:credit_card] = { id: token, auto_capture: false } post[:payment_method] = payment_method end def add_fee(post, options) if options[:application_fee] || options[:fee_payer] post[:fee] = {} post[:fee][:app_fee] = options[:application_fee] if options[:application_fee] post[:fee][:fee_payer] = options[:fee_payer] if options[:fee_payer] end end def parse(response) JSON.parse(response) end def commit(action, params, options={}) begin response = parse(ssl_post( ((test? ? test_url : live_url) + action), params.to_json, headers(options) )) rescue ResponseError => e response = parse(e.response.body) end return Response.new( success_from(response), message_from(response), response, authorization: authorization_from(response, params), test: test? ) rescue JSON::ParserError return unparsable_response(response) end def success_from(response) (!response["error"]) end def message_from(response) (response["error"] ? response["error_description"] : "Success") end def authorization_from(response, params) return response["credit_card_id"].to_s if response["credit_card_id"] original_amount = response["amount"].nil? ? nil : sprintf("%0.02f", response["amount"]) [response["checkout_id"], original_amount].join('|') end def split_authorization(authorization) auth, original_amount = authorization.to_s.split("|") [auth, original_amount] end def unparsable_response(raw_response) message = "Invalid JSON response received from WePay. Please contact WePay support if you continue to receive this message." message += " (The raw response returned by the API was #{raw_response.inspect})" return Response.new(false, message) end def headers(options) { "Content-Type" => "application/json", "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}", "Authorization" => "Bearer #{@options[:access_token]}", "Api-Version" => api_version(options) } end def api_version(options) options[:version] || API_VERSION end end end end