kount 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MjI5YTNkMmZiZTcxYWVlMmU1MzUyZWViMjc0ZmIzN2Y0ZDc2ZWExOA==
5
+ data.tar.gz: !binary |-
6
+ NmFhNWQ2MzEzYzYyMzU5ZmJkZTRjN2ZmOGFiZTRiMTZjYjlmNjBkNw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YTYwZTgxMmE2NjVlMjkxM2NmMWFmZTg2ZTk2YWRiYTYwYjA4OTA1MTlmMDdl
10
+ ZGZjOWM4MzUzYzRlMTI3YzcxOWZlNzg5Y2ZjZDc0NjhhMzQ2YTdjYmJlYjAz
11
+ Mzk2N2E4YWE2YmYxNjg5ZDkzM2VhOGM3M2FiMzlmNTg1NzI1N2E=
12
+ data.tar.gz: !binary |-
13
+ ODRkZjYzNThmM2UyZTNkN2IwMzY0ZTRkN2YyMWFlZTE0OWM0ODAzNWE4Y2Zh
14
+ MDg2NjlkMDEzYjg0YjNiOTU1NjYxZGQ2ODQ4ZjRmMmYxODViZWY5YTU1OGQ2
15
+ OGQ1NzBlNzFlMzIyNDEzMTI5ZThlZmFlZGQxM2Q0MTM5MGZhMTc=
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Don Pflaster
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,122 @@
1
+ # Kount
2
+
3
+ Ruby interface for the Kount fraud detection service
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'kount'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install kount
18
+
19
+ ## Usage
20
+
21
+ ### Setup
22
+
23
+ Set up your credentials that you configured within the Kount administrative interface.
24
+ If you have a login for Kount, the folks at Kount should also have supplied you with a guide for generating your API and Risk Inquiry service certificates. The ultimate result is a certificate and key file in .pem format. There should be one of these each for the API and Risk Inquiry services, and for the test and production environments for a total of 8 files.
25
+
26
+ Suggested set up for a Rails app (place in an initializer):
27
+
28
+ # Set custom variables within gem
29
+
30
+ if Rails.env == 'production'
31
+ # API certificate
32
+ Kount.api_cert = 'config/keys/awc.kount.net.cert.pem'
33
+ Kount.api_cert_key = 'config/keys/awc.kount.net.key.pem'
34
+
35
+ # Risk Inquiry System Certificate
36
+ Kount.ris_cert = 'config/keys/ris.kount.net.cert.pem'
37
+ Kount.ris_cert_key = 'config/keys/ris.kount.net.key.pem'
38
+
39
+ Kount.mode = :production
40
+ else
41
+ # API certificate
42
+ Kount.api_cert = 'config/keys/awc.test.kount.net.cert.pem'
43
+ Kount.api_cert_key = 'config/keys/awc.test.kount.net.key.pem'
44
+
45
+ # Risk Inquiry System Certificate
46
+ Kount.ris_cert = 'config/keys/ris.test.kount.net.cert.pem'
47
+ Kount.ris_cert_key = 'config/keys/ris.test.kount.net.key.pem'
48
+
49
+ Kount.mode = :test
50
+ end
51
+
52
+ Also set up your merchant ID (this should also have been supplied to you by Kount):
53
+
54
+ Kount.merchant_id = '123456'
55
+
56
+ ### Making calls
57
+
58
+ In the following example, I am updating the status of an order to Declined through an API call to the Orders status endpoint.
59
+ The basic usage is to first create a payload hash:
60
+
61
+ payload = {
62
+ ['status[',kount_transaction_id,']'].join => 'D',
63
+ ['note[',kount_transaction_id,']'].join => text
64
+ }
65
+
66
+ Then instantiate a Kount::Request object and call "transmit" on it. Arguments:
67
+
68
+ 1: The symbol :api to indicate it is an API call, as opposed to the Risk Inquiry service which would be :risk
69
+ 2: The endpoint to call
70
+ 3: 'get' or 'post'
71
+ 4: The payload hash constructed in the previous step
72
+
73
+ ou = Kount::Request.new
74
+ ou.transmit(:api,'v1/orders/status.json','post',payload)
75
+
76
+ ### Risk Inquiry Service
77
+
78
+ Since the Risk Inquiry service has a very specific set of inputs, the Kount::RiskInquiry class is a layer of abstraction which accepts all of the input fields described in the Kount docs as accessor methods.
79
+
80
+ Instantiate the object:
81
+
82
+ ri = Kount::RiskInquiry.new
83
+
84
+ Set all the necessary fields to make a successful call:
85
+
86
+ ri.mode = 'Q' # Standard mode for initial post
87
+ ri.mack = 'Y'
88
+
89
+ ri.ipad = created_by_ip_address
90
+ ri.uniq = buyer.id
91
+ ri.name = buyer.name
92
+ # et cetera
93
+
94
+ Array fields accept arrays. You can set the array directly or iterate over another array you have prepared:
95
+
96
+ ri.prod_type = prods.map(&:name)
97
+
98
+ # or
99
+
100
+ ri.prod_type = []
101
+ prods.each { |prod|
102
+ ri.prod_type << prod.name
103
+ }
104
+
105
+ Custom fields that you have configured within Kount can be passed as a hash:
106
+
107
+ ri.custom_fields = {
108
+ :customfield1 => 'value1',
109
+ :customfield2 => 'value2'
110
+ }
111
+
112
+ Transmit the inquiry, which will return a Kount::Response object:
113
+
114
+ ri.request
115
+
116
+ ## Contributing
117
+
118
+ 1. Fork it
119
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
120
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
121
+ 4. Push to the branch (`git push origin my-new-feature`)
122
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kount/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kount"
8
+ spec.version = Kount::VERSION
9
+ spec.authors = ["Don Pflaster"]
10
+ spec.email = ["don@ticketevolution.com"]
11
+ spec.description = %q{Interfaces with Kount Endpoints}
12
+ spec.summary = %q{}
13
+ spec.homepage = ""
14
+
15
+ spec.add_dependency 'curb'
16
+ spec.add_dependency 'json'
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", ">= 2.0.0"
26
+ end
@@ -0,0 +1,23 @@
1
+ require "kount/version"
2
+ require 'kount/request'
3
+ require 'kount/response'
4
+ require 'kount/error'
5
+ require 'kount/defaults'
6
+
7
+ require 'curb'
8
+ require 'json'
9
+
10
+ module Kount
11
+ class << self
12
+ attr_accessor :api_cert
13
+ attr_accessor :api_cert_key
14
+ attr_accessor :ris_cert
15
+ attr_accessor :ris_cert_key
16
+ attr_accessor :mode
17
+ attr_accessor :merchant_id
18
+ # Your code goes here...
19
+ end
20
+ end
21
+
22
+ require 'kount/risk_inquiry'
23
+
@@ -0,0 +1,12 @@
1
+ module Kount
2
+ KOUNT_SERVER_URLS = {
3
+ :api => {
4
+ :test => 'https://api.test.kount.net/rpc/',
5
+ :production => 'https://api.kount.net/rpc/'
6
+ },
7
+ :risk => {
8
+ :test => 'https://risk.test.kount.net',
9
+ :production => 'https://risk.kount.net'
10
+ }
11
+ }
12
+ end
@@ -0,0 +1,11 @@
1
+ module Kount
2
+ class Error
3
+ attr_accessor :error_object
4
+
5
+ def initialize(error = nil)
6
+ @error_object = error
7
+ end
8
+ end
9
+ end
10
+
11
+
@@ -0,0 +1,45 @@
1
+ module Kount
2
+ class Request
3
+ def transmit(service_type,endpoint_url,get_or_post,query_params={})
4
+ url = [Kount::KOUNT_SERVER_URLS[service_type][Kount.mode],endpoint_url].join
5
+
6
+ Rails.logger.info ["Kount request: ",url].join if defined?(Rails)
7
+
8
+ c = Curl::Easy.new(url) do |curl|
9
+ curl.certtype = 'PEM'
10
+ if service_type == :api
11
+ curl.cert = Kount.api_cert
12
+ curl.cert_key = Kount.api_cert_key
13
+ elsif service_type == :risk
14
+ curl.cert = Kount.ris_cert
15
+ curl.cert_key = Kount.ris_cert_key
16
+ end
17
+ curl.connect_timeout = 5
18
+ end
19
+
20
+ if get_or_post.downcase == 'get'
21
+ c.http_get
22
+ elsif get_or_post.downcase == 'post'
23
+ c.http_post(get_post_fields(query_params))
24
+ end
25
+ Kount::Response.new(service_type,c)
26
+ rescue Exception => e
27
+ Kount::Error.new(e)
28
+ end
29
+
30
+ def get_post_fields(query_params)
31
+ fields = []
32
+ query_params.each { |k,v|
33
+ if v.is_a?(Array)
34
+ v.each { |element|
35
+ fields << Curl::PostField.content(k,element)
36
+ }
37
+ else
38
+ fields << Curl::PostField.content(k,v)
39
+ end
40
+ }
41
+ fields
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,40 @@
1
+ module Kount
2
+ class Response
3
+ attr_accessor :attributes
4
+ attr_reader :body
5
+
6
+ def initialize(service_type,response = nil)
7
+ raise ArgumentError, 'Missing response object' unless response
8
+ begin
9
+ if service_type == :api
10
+ @body = JSON.parse(response.body_str)
11
+ elsif service_type == :risk
12
+ @body = Hash[response.body_str.split("\n").map {|l| l.split("=") }]
13
+ end
14
+ rescue
15
+ raise ["Could not parse JSON response. Raw response: ",response.body_str].join("\n")
16
+ end
17
+ end
18
+
19
+ def result
20
+ @body['result']
21
+ end
22
+
23
+ def count
24
+ @body['count']
25
+ end
26
+
27
+ def errors
28
+ @body['errors']
29
+ end
30
+
31
+ def status
32
+ @body['status']
33
+ end
34
+
35
+ def is_risk_error?
36
+ @body['ERRO'].present?
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,92 @@
1
+ module Kount
2
+ class RiskInquiry < Request
3
+ MODES = ['Q','P','X','U']
4
+ REQUIRED_FIELDS = [
5
+ :anid, # Automatic Number Identification
6
+ :auth, # A or D, for accept or decline
7
+ :curr, # Country of currency submitted on order (USD)
8
+ :emal, # Customer's email
9
+ :ipad, # IP Address of Customer
10
+ :mack, # Merchant's acknowledgement to ship/process the order (Y)
11
+ :merc, # Merchant ID assigned to merchant by Kount
12
+ :mode, # Q, P, D, U
13
+ :ptok, # Payment token
14
+ :ptyp, # Payment type (CARD = Credit Card)
15
+ :sess, # Unique Session ID
16
+ :site, # Website Identifier of where order originated
17
+ :totl, # Total amount in currency (in pennies)
18
+ :tran, # Kount transaction ID (required for update modes U and X)
19
+ :vers # Version of Kount
20
+ ]
21
+
22
+ REQUIRED_ARRAY_FIELDS = [
23
+ :prod_type, # High level item descriptions
24
+ :prod_item, # Typically the SKU
25
+ :prod_desc, # Specific description
26
+ :prod_quant, # Quantity of item purchased
27
+ :prod_price # Price per unit item (in pennies)
28
+ ]
29
+ OPTIONAL_KEYS = [
30
+ :avst, # AVS Street (M, N, X)
31
+ :avsz, # AVS Zip (M, N, X)
32
+ :b2a1, # Billing address line 1
33
+ :b2a2, # Billing address Line 2
34
+ :b2cc, # Billing address Country
35
+ :b2ci, # Billing address City
36
+ :b2pc, # Billing Address Postal Code
37
+ :b2pn, # Bill-to Phone Number
38
+ :b2st, # Billing Address State/Province
39
+ :bpremise, #Bill-to premise for UK
40
+ :bstreet, # Bill-to street address for UK
41
+ :cash, # Total cash amount in currency submitted
42
+ :cvvr, # CVV response (M, N, X)
43
+ :dob, # Date of birth
44
+ :epoc, # Date customer account was created by merchant
45
+ :frmt, # Format of response (XML, JSON, YAML)
46
+ :gender, # M or F
47
+ :name, # Name submitted with order
48
+ :ordr, # Merchant's order number
49
+ :s2a1, # Shipping street address - Line 1
50
+ :s2a2, # Shipping street address - Line 2
51
+ :s2cc, # Shipping address - Country
52
+ :s2ci, # Shipping address - City
53
+ :s2em, # Shipping address - Email address
54
+ :s2nm, # Shipping address - Name
55
+ :s2pc, # Shipping address - Postal Code
56
+ :s2pn, # Shipping address - Ship-to Phone Number
57
+ :s2st, # Shipping address - State/Province
58
+ :shtp, # Shipping type
59
+ :spremise, # Ship-to premise for UK
60
+ :sstreet, # Ship-to Street for UK
61
+ :uniq, # Merchant assigned account number for consumer
62
+ :uagt # Consumer User-Agent HTTP Header
63
+ ]
64
+
65
+ (REQUIRED_FIELDS + REQUIRED_ARRAY_FIELDS + OPTIONAL_KEYS).each { |key| attr_accessor key }
66
+ attr_accessor :custom_fields # Hash
67
+
68
+ def initialize
69
+ @merc = Kount.merchant_id
70
+ @vers = Kount::API_VERSION
71
+ @custom_fields = {}
72
+ end
73
+
74
+ def payload
75
+ payload = {}
76
+ (REQUIRED_FIELDS + OPTIONAL_KEYS).each { |key|
77
+ payload[key.to_s.upcase] = self.send(key) unless self.send(key).nil?
78
+ }
79
+ (REQUIRED_ARRAY_FIELDS).each { |key|
80
+ payload[[key.to_s.upcase,'[]'].join] = self.send(key) unless self.send(key).nil?
81
+ }
82
+ custom_fields.each { |k,v|
83
+ payload.merge!({ ['UDF[',k.to_s.upcase,']'].join => v })
84
+ }
85
+ payload
86
+ end
87
+
88
+ def request
89
+ transmit(:risk,'','post',payload)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,4 @@
1
+ module Kount
2
+ VERSION = "0.0.1"
3
+ API_VERSION = '0555'
4
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kount::Request do
4
+ before do
5
+ Kount.cert = 'cert'
6
+ Kount.cert_key = 'cert_key'
7
+ @request = Kount::Request.new
8
+ end
9
+
10
+ it "requires a certificate and key" do
11
+ expect { Kount.cert }.to_not be_nil
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kount::Response do
4
+ before do
5
+ Kount.cert = 'cert'
6
+ Kount.cert_key = 'cert_key'
7
+
8
+ request = Kount::Request.new
9
+ @response = request.process!
10
+ end
11
+
12
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'kount'
5
+ require 'json'
6
+
7
+ RSpec.configure do |config|
8
+
9
+ end
10
+
11
+ def load_fixture(*filename)
12
+ #File.open(File.join('spec', 'data', *filename)).read
13
+ end
14
+
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kount
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Don Pflaster
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: 2.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: 2.0.0
83
+ description: Interfaces with Kount Endpoints
84
+ email:
85
+ - don@ticketevolution.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - kount.gemspec
96
+ - lib/kount.rb
97
+ - lib/kount/defaults.rb
98
+ - lib/kount/error.rb
99
+ - lib/kount/request.rb
100
+ - lib/kount/response.rb
101
+ - lib/kount/risk_inquiry.rb
102
+ - lib/kount/version.rb
103
+ - spec/kount/request_spec.rb
104
+ - spec/kount/response_spec.rb
105
+ - spec/spec_helper.rb
106
+ homepage: ''
107
+ licenses: []
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.1.11
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: ''
129
+ test_files:
130
+ - spec/kount/request_spec.rb
131
+ - spec/kount/response_spec.rb
132
+ - spec/spec_helper.rb
133
+ has_rdoc: