credit_card_gateway.rb

 1# frozen_string_literal: true
 2
 3require "braintree"
 4require_relative "customer"
 5
 6class CreditCardGateway
 7	class ErrorResult < StandardError
 8		def self.for(result)
 9			if result.verification&.status == "gateway_rejected" &&
10			   result.verification&.gateway_rejection_reason == "cvv"
11				new("fieldInvalidForCvv")
12			else
13				new(result.message)
14			end
15		end
16	end
17
18	def initialize(currency, antifraud)
19		@currency = currency
20		@antifraud = antifraud
21
22		@gateway = Braintree::Gateway.new(
23			environment: BRAINTREE_CONFIG[:environment].to_s,
24			merchant_id: BRAINTREE_CONFIG[:merchant_id].to_s,
25			public_key: BRAINTREE_CONFIG[:public_key].to_s,
26			private_key: BRAINTREE_CONFIG[:private_key].to_s
27		)
28	end
29
30	def merchant_account
31		BRAINTREE_CONFIG[:merchant_accounts][@currency]
32	end
33
34	def client_token(**kwargs)
35		kwargs[:merchant_account_id] = merchant_account.to_s if merchant_account
36		@gateway.client_token.generate(**kwargs)
37	end
38
39	def antifraud
40		REDIS.mget(@antifraud.map { |k| "jmp_antifraud-#{k}" }).find do |anti|
41			anti.to_i > 2
42		end &&
43			Braintree::ErrorResult.new(
44				@gateway, errors: {}, message: "Please contact support"
45			)
46	end
47
48	def with_antifraud
49		result = antifraud || yield
50		return result if result.success?
51
52		@antifraud.each do |k|
53			REDIS.incr("jmp_antifraud-#{k}")
54			REDIS.expire("jmp_antifraud-#{k}", 60 * 60 * 24)
55		end
56
57		raise ErrorResult.for(result)
58	end
59
60	def sale(nonce, amount, **kwargs)
61		with_antifraud do
62			@gateway.transaction.sale(
63				payment_method_nonce: nonce,
64				amount: amount, merchant_account_id: merchant_account.to_s,
65				options: {
66					store_in_vault_on_success: true, submit_for_settlement: true
67				}, **kwargs
68			)
69		end
70	end
71
72	def customer
73		@gateway.customer
74	end
75
76	def payment_method
77		@gateway.payment_method
78	end
79end