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