cardflex-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +125 -0
  4. data/cardflex.gemspec +14 -0
  5. data/lib/cardflex.rb +32 -0
  6. data/lib/cardflex/base_module.rb +34 -0
  7. data/lib/cardflex/configuration.rb +96 -0
  8. data/lib/cardflex/customer_vault.rb +35 -0
  9. data/lib/cardflex/customer_vault_gateway.rb +26 -0
  10. data/lib/cardflex/error_response.rb +18 -0
  11. data/lib/cardflex/errors.rb +11 -0
  12. data/lib/cardflex/gateway.rb +35 -0
  13. data/lib/cardflex/http.rb +68 -0
  14. data/lib/cardflex/plan.rb +22 -0
  15. data/lib/cardflex/plan_gateway.rb +23 -0
  16. data/lib/cardflex/subscription.rb +24 -0
  17. data/lib/cardflex/subscription_gateway.rb +22 -0
  18. data/lib/cardflex/success_response.rb +15 -0
  19. data/lib/cardflex/test/test_values.rb +26 -0
  20. data/lib/cardflex/three_step.rb +42 -0
  21. data/lib/cardflex/three_step_gateway.rb +41 -0
  22. data/lib/cardflex/transaction.rb +52 -0
  23. data/lib/cardflex/transaction_gateway.rb +23 -0
  24. data/lib/cardflex/version.rb +9 -0
  25. data/lib/cardflex/xml.rb +11 -0
  26. data/lib/cardflex/xml/parser.rb +48 -0
  27. data/lib/cardflex/xml/serializer.rb +70 -0
  28. data/lib/ssl/ca-certificates.ca.crt +4190 -0
  29. data/spec/integration/cardflex/http_spec.rb +72 -0
  30. data/spec/integration/cardflex/plan_spec.rb +24 -0
  31. data/spec/integration/cardflex/three_step_gateway_spec.rb +47 -0
  32. data/spec/integration/cardflex/three_step_spec.rb +37 -0
  33. data/spec/integration/spec_helper.rb +24 -0
  34. data/spec/spec.opts +4 -0
  35. data/spec/spec_helper.rb +45 -0
  36. data/spec/ssl/certificate.crt +21 -0
  37. data/spec/ssl/geotrust_global.crt +20 -0
  38. data/spec/ssl/private_key.pem +30 -0
  39. data/spec/unit/cardflex/base_module_spec.rb +34 -0
  40. data/spec/unit/cardflex/configuration_spec.rb +61 -0
  41. data/spec/unit/cardflex/customer_vault_gateway_spec.rb +10 -0
  42. data/spec/unit/cardflex/errors_spec.rb +8 -0
  43. data/spec/unit/cardflex/gateway_spec.rb +11 -0
  44. data/spec/unit/cardflex/http_spec.rb +18 -0
  45. data/spec/unit/cardflex/three_step_gateway_spec.rb +29 -0
  46. data/spec/unit/cardflex/xml_spec.rb +90 -0
  47. data/spec/unit/spec_helper.rb +1 -0
  48. metadata +103 -0
@@ -0,0 +1,68 @@
1
+ module Cardflex
2
+ class Http
3
+ attr_reader :config
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def post(params={})
10
+ params = _add_api_key(params)
11
+ response = _do_http(Net::HTTP::Post, Xml.hash_to_xml(params))
12
+ Xml.parse(response.body)
13
+ end
14
+
15
+ def _do_http(http_verb, body=nil)
16
+ connection = Net::HTTP.new(@config.server, @config.port)
17
+ connection.open_timeout = 60
18
+ connection.read_timeout = 60
19
+ if @config.ssl?
20
+ connection.use_ssl = true
21
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
22
+ connection.ca_file = @config.ca_file
23
+ connection.verify_callback = proc { |preverify_ok, ssl_context| _verify_ssl_certificate(preverify_ok, ssl_context) }
24
+ end
25
+
26
+ connection.start do |http|
27
+ request = http_verb.new("#{@config.three_step_path}")
28
+ request['Accept'] = 'text/xml'
29
+ @config.logger.debug("[Cardflex] [#{_current_time}] #{request.method} as text/xml")
30
+ if body
31
+ request['Content-Type'] = 'text/xml'
32
+ request.body = body
33
+ @config.logger.debug _format_body_for_log(body)
34
+ end
35
+
36
+ response = http.request(request)
37
+ @config.logger.info "[Cardflex] [#{_current_time}] #{request.method} #{response.code}"
38
+ @config.logger.debug _format_body_for_log(response.body)
39
+ response
40
+ end
41
+ rescue OpenSSL::SSL::SSLError
42
+ raise Cardflex::SSLCertificateError
43
+ end
44
+
45
+ def _current_time
46
+ Time.now.utc.strftime("%d/%b/%Y %H:%M:%S %Z")
47
+ end
48
+
49
+ def _verify_ssl_certificate(preverify_ok, ssl_context)
50
+ if preverify_ok != true || ssl_context.error != 0
51
+ err_msg = "SSL Verification failed -- Preverify: #{preverify_ok}, Error: #{ssl_context.error_string} (#{ssl_context.error})"
52
+ @config.logger.error err_msg
53
+ false
54
+ else
55
+ true
56
+ end
57
+ end
58
+
59
+ def _add_api_key(params)
60
+ key = params.keys[0]
61
+ { key => params[key].merge(:api_key => @config.api_key) }
62
+ end
63
+
64
+ def _format_body_for_log(body)
65
+ body.gsub(/^/, "[Cardflex] ")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,22 @@
1
+ module Cardflex
2
+ class Plan
3
+ include BaseModule
4
+
5
+ module Type
6
+ Add = 'add_plan'
7
+ end
8
+
9
+ attr_reader :result, :result_text, :result_code, :action_type
10
+ attr_reader :plan
11
+
12
+ def initialize(gateway, attributes)
13
+ @gateway = gateway
14
+ @type = attributes[:action_type]
15
+ set_instance_variables_from_hash(attributes)
16
+ end
17
+
18
+ def self.create(attributes)
19
+ Configuration.gateway.plan.request(:add_plan => attributes)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Cardflex
2
+ class PlanGateway
3
+ attr_reader :config
4
+
5
+ def initialize(gateway)
6
+ @gateway = gateway
7
+ @config = gateway.config
8
+ end
9
+
10
+ def request(attributes)
11
+ res = config.http.post(attributes)
12
+ _handle_response(res)
13
+ end
14
+
15
+ def _handle_response(res)
16
+ if res[:response][:result] == '1'
17
+ SuccessResponse.new(:plan => Plan.new(@gateway, res[:response]))
18
+ else
19
+ ErrorResponse.new(@gatway, res[:response])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ module Cardflex
2
+ class Subscription
3
+ include BaseModule
4
+
5
+ module Type
6
+ Delete = 'delete_subscription'
7
+ end
8
+
9
+ attr_reader :result, :result_text, :result_code, :action_type
10
+ attr_reader :subscription_id
11
+ attr_reader :type, :plan, :billing, :shipping
12
+
13
+ def initialize(gateway, attributes)
14
+ @gateway = gateway
15
+ @type = attributes[:action_type]
16
+ set_instance_variables_from_hash(attributes)
17
+ end
18
+
19
+ def self.delete(subscription_id)
20
+ attributes = { :delete_subscription => { :subscription_id => subscription_id }}
21
+ Configuration.gateway.subscription.request(attributes)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ module Cardflex
2
+ class SubscriptionGateway
3
+ attr_reader :config
4
+
5
+ def initialize(gateway)
6
+ @gateway = gateway
7
+ @config = gateway.config
8
+ end
9
+
10
+ def request(attributes)
11
+ @config.http.post(attributes)
12
+ end
13
+
14
+ def _handle_response(res)
15
+ if res[:response][:result] == '1'
16
+ SuccessResponse.new(:subscription => Subscription.new(@gateway, res[:response]))
17
+ else
18
+ ErrorResponse.new(@gateway, res[:response])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Cardflex
2
+ class SuccessResponse
3
+ include BaseModule
4
+
5
+ attr_reader :transaction, :three_step, :plan, :subscription, :customer_vault
6
+
7
+ def initialize(hash={})
8
+ set_instance_variables_from_hash(hash)
9
+ end
10
+
11
+ def success?
12
+ true
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Cardflex
2
+ module Test
3
+ module Cards
4
+ Visa = "4111111111111111"
5
+ MasterCard = "5431111111111111"
6
+ Discover = "6011601160116611"
7
+ AmEx = "341111111111111"
8
+ ACHAccount = "123123123"
9
+ ACHRouting = "123123123"
10
+
11
+ Expiration = "10/25"
12
+
13
+ # Failures
14
+ Declined = "100"
15
+ CVVMatch = "999"
16
+
17
+ AVSMatchAddress1 = "888"
18
+ AVSMatchZip = "77777"
19
+ end
20
+
21
+ module Charges
22
+ Accepted = "1.50"
23
+ Declined = "0.50"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ module Cardflex
2
+ class ThreeStep
3
+ include BaseModule
4
+
5
+ module Type
6
+ Sale = 'sale'
7
+ Auth = 'auth'
8
+ Credit = 'credit'
9
+ Validate = 'validate'
10
+ Offline = 'offline'
11
+ AddSubscription = 'add_subscription'
12
+ UpdateSubscription = 'update_subscription'
13
+ AddCustomer = 'add_customer'
14
+ UpdateCustomer = 'update_customer'
15
+ AddBilling = 'add_billing'
16
+ UpdateBilling = 'update_billing'
17
+ end
18
+
19
+ attr_reader :config
20
+ attr_reader :form_url
21
+ attr_reader :transaction_id
22
+ attr_reader :result, :result_text, :result_code
23
+
24
+ def initialize(gateway, attributes={})
25
+ @gateway = gateway
26
+ @config = gateway.config
27
+ set_instance_variables_from_hash(attributes)
28
+ end
29
+
30
+ def self.get_form_url(attributes)
31
+ Configuration.gateway.three_step.get_form_url(attributes)
32
+ end
33
+
34
+ def self.complete(token_id)
35
+ Configuration.gateway.three_step.complete(token_id)
36
+ end
37
+
38
+ create_helper_methods(Type) do |attributes|
39
+ get_form_url(attributes)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ module Cardflex
2
+ class ThreeStepGateway
3
+ attr_reader :config
4
+
5
+ def initialize(gateway)
6
+ @gateway = gateway
7
+ @config = gateway.config
8
+ end
9
+
10
+ def get_form_url(attributes)
11
+ root = attributes.keys[0]
12
+ raise ArgumentError, 'missing :redirect_url' unless attributes[root][:redirect_url]
13
+
14
+ res = @config.http.post(attributes)
15
+ _handle_intermediate_response(res)
16
+ end
17
+
18
+ def complete(token_id)
19
+ raise ArgumentError, 'you must provide a token_id' unless token_id
20
+
21
+ res = @config.http.post(:complete_action => { :token_id => token_id })
22
+ _handle_response(res)
23
+ end
24
+
25
+ def _handle_response(res)
26
+ if res[:response][:result] == '1'
27
+ SuccessResponse.new(:transaction => Transaction.new(@gateway, res[:response]))
28
+ else
29
+ ErrorResponse.new(@gateway, res[:response])
30
+ end
31
+ end
32
+
33
+ def _handle_intermediate_response(res)
34
+ if res[:response][:result] == '1'
35
+ SuccessResponse.new(:three_step => ThreeStep.new(@gateway, res[:response]))
36
+ else
37
+ ErrorResponse.new(@gateway, res[:response])
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,52 @@
1
+ module Cardflex
2
+ class Transaction
3
+ include BaseModule
4
+
5
+ module Type
6
+ Capture = 'capture'
7
+ Void = 'void'
8
+ Refund = 'refund'
9
+ end
10
+
11
+ attr_reader :result, :result_code, :result_text, :authorization_code
12
+ attr_reader :avs_result, :cvv_result, :avs_reject, :cvv_reject
13
+ attr_reader :amount, :currency
14
+ attr_reader :ip_address
15
+ attr_reader :industry
16
+ attr_reader :billing_method
17
+ attr_reader :processor_id
18
+ attr_reader :sec_code
19
+ attr_reader :descriptor, :descriptor_phone, :descriptor_address, :descriptor_city, :descriptor_state,
20
+ :descriptor_postal, :descriptor_country, :descriptor_mcc, :descriptor_merchant_id, :descriptor_url
21
+ attr_reader :order_description, :order_date
22
+ attr_reader :customer_id, :customer_vault_id
23
+ attr_reader :merchant_receipt_email
24
+ attr_reader :customer_receipt
25
+ attr_reader :tracking_number, :shipping_carrier, :shipping_amount, :ship_from_postal
26
+ attr_reader :po_number, :order_id
27
+ attr_reader :tax_amount, :duty_amount, :national_tax_amount, :alternate_tax_amount, :alternate_tax_id
28
+ attr_reader :vat_tax_amount, :vat_tax_rate, :vat_invoice_reference_number, :customer_vat_registration,
29
+ :merchant_vat_registration
30
+ attr_reader :summary_commodity_code
31
+ attr_reader :discount_amount
32
+ attr_reader :cardholder_auth
33
+ attr_reader :eci
34
+ attr_reader :cavv, :xid
35
+ attr_reader :dup_seconds
36
+ attr_reader :type, :action_type, :transaction_id, :billing, :plan, :shipping, :product
37
+
38
+ def initialize(gateway, attributes)
39
+ @gateway = gateway
40
+ @type = attributes[:action_type]
41
+ set_instance_variables_from_hash(attributes)
42
+ end
43
+
44
+ def self.request(attributes)
45
+ Configuration.gateway.transaction.request(attributes)
46
+ end
47
+
48
+ create_helper_methods(Type) do |attributes|
49
+ request(attributes)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ module Cardflex
2
+ class TransactionGateway
3
+ attr_reader :config
4
+
5
+ def initialize(gateway)
6
+ @gateway = gateway
7
+ @config = gateway.config
8
+ end
9
+
10
+ def request(attributes)
11
+ res = @config.http.post(attributes)
12
+ _handle_response(res)
13
+ end
14
+
15
+ def _handle_response(res)
16
+ if res[:response][:result] == '1'
17
+ SuccessResponse.new(:transaction => Transaction.new(@gateway, res[:response]))
18
+ else
19
+ ErrorResponse.new(@gateway, res[:response])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ module Cardflex
2
+ module Version
3
+ Major = '0'
4
+ Minor = '0'
5
+ Tiny = '1'
6
+
7
+ Full = "#{Major}.#{Minor}.#{Tiny}"
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Cardflex
2
+ module Xml
3
+ def self.parse(xml)
4
+ Parser.xml_to_hash(xml)
5
+ end
6
+
7
+ def self.hash_to_xml(hash)
8
+ Serializer.hash_to_xml(hash)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ module Cardflex
2
+ module Xml
3
+ module Parser
4
+ require 'rexml/document' unless defined? REXML::Document
5
+
6
+ def self.xml_to_hash(xml)
7
+ return {} if xml.nil?
8
+
9
+ document = REXML::Document.new(xml)
10
+ { _snakecase(document.root.name) => _parse_children(document.root) }
11
+ end
12
+
13
+ def self._parse_children(elem)
14
+ if elem.has_elements?
15
+ children = {}
16
+ elem.each_element do |child|
17
+ children[_snakecase(child.name)] = _parse_children(child)
18
+ end
19
+ children
20
+ else
21
+ elem.text
22
+ end
23
+ end
24
+
25
+ def self._snakecase(key)
26
+ key.tr('-', '_').to_sym
27
+ end
28
+
29
+ def self.parse(string)
30
+ return {} if string.nil?
31
+
32
+ doc = REXML::Document.new(string)
33
+ { _snakecase(doc.root.name).to_sym => _to_hash({}, doc.root) }
34
+ end
35
+
36
+ def self._to_hash(hash, element)
37
+ if element.has_elements?
38
+ element.each_element do |child|
39
+ hash[_snakecase(child.name).to_sym] = child.text
40
+ end
41
+ end
42
+
43
+ hash
44
+ end
45
+
46
+ end
47
+ end
48
+ end