alpha_card 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/alpha_card.gemspec +2 -2
- data/lib/alpha_card.rb +59 -19
- data/lib/alpha_card/account.rb +32 -0
- data/lib/alpha_card/alpha_card_error.rb +2 -0
- data/lib/alpha_card/alpha_card_object.rb +13 -7
- data/lib/alpha_card/alpha_card_response.rb +8 -1
- data/lib/alpha_card/billing.rb +3 -0
- data/lib/alpha_card/object.rb +35 -5
- data/lib/alpha_card/order.rb +3 -0
- data/lib/alpha_card/sale.rb +30 -10
- data/lib/alpha_card/shipping.rb +3 -0
- data/lib/alpha_card/utils.rb +90 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6af86a7de326ef53708c81f07ed025792c44841c
|
4
|
+
data.tar.gz: 5a670c2177f9b7ac326f34ea1c3e34decd5ea37c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca0333c53125849ca415b73a10d9a4c659d54cff80879bc0f2aadd3aa502ffecc3af758ed87709ce83ba7016d57679b7a6f023f672952d7e9f3788fda29f7ad1
|
7
|
+
data.tar.gz: 0bea0ef881a98bd593a99a20883de46f2b94f1d6cf384caa39dbeaed8f95f53a99afa8855a22becba76f0e0f6b5ac90017263dda9d2473a4564e7938c525d7a9
|
data/Gemfile
CHANGED
data/alpha_card.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'alpha_card'
|
3
|
-
gem.version = '0.1.
|
4
|
-
gem.date = '2014-06-
|
3
|
+
gem.version = '0.1.7'
|
4
|
+
gem.date = '2014-06-27'
|
5
5
|
gem.summary = 'Alpha Card Services DirectPost API for Ruby'
|
6
6
|
gem.description = 'Gem for creating sales with Alpha Card Services DirectPost API'
|
7
7
|
gem.authors = ['Nikita Bulaj']
|
data/lib/alpha_card.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# encoding:utf-8
|
1
2
|
require 'yaml'
|
2
3
|
require 'virtus'
|
3
|
-
require 'rack'
|
4
4
|
require 'rest_client'
|
5
5
|
|
6
|
+
require 'alpha_card/utils'
|
6
7
|
require 'alpha_card/object'
|
7
8
|
require 'alpha_card/alpha_card_object'
|
8
9
|
require 'alpha_card/alpha_card_response'
|
@@ -14,25 +15,55 @@ require 'alpha_card/billing'
|
|
14
15
|
require 'alpha_card/order'
|
15
16
|
require 'alpha_card/sale'
|
16
17
|
|
18
|
+
##
|
19
|
+
# AlphaCard is a library for processing payments with Alpha Card Services, Inc.
|
17
20
|
module AlphaCard
|
18
|
-
|
21
|
+
##
|
22
|
+
# Alpha Card Gateway DirectPost API URL
|
19
23
|
@api_base = 'https://secure.alphacardgateway.com/api/transact.php'
|
20
24
|
|
25
|
+
##
|
21
26
|
# Global Payment Systems (NDC) Credit Card Authorization Codes
|
27
|
+
#
|
28
|
+
# @see http://floristwiki.ftdi.com/images/c/ce/Appendix_A_-_Credit_Card_Authorization_Codes.pdf Credit Card Authorization Codes
|
22
29
|
CREDIT_CARD_CODES = YAML.load_file(File.expand_path('../alpha_card/data/codes.yml', __FILE__)) unless defined? CREDIT_CARD_CODES
|
23
30
|
|
24
31
|
class << self
|
32
|
+
# @return [String] Alpha Card Gateway DirectPost API URL.
|
25
33
|
attr_accessor :api_base
|
26
34
|
end
|
27
35
|
|
28
|
-
|
36
|
+
##
|
37
|
+
# Send the POST request to the AlphaCard Gateway from the
|
38
|
+
# specified account. Request must contains params - Alpha Card
|
39
|
+
# transcation variables.
|
40
|
+
#
|
41
|
+
# @param [Hash] params
|
42
|
+
# Alpha Card transaction variables.
|
43
|
+
# @param [AlphaCard::Account] account
|
44
|
+
# An <code>AlphaCard::Account</code> credentials object.
|
45
|
+
#
|
46
|
+
# @return [AlphaCard::AlphaCardResponse]
|
47
|
+
# Response from Alpha Card Gateway.
|
29
48
|
#
|
30
|
-
#
|
31
|
-
#
|
49
|
+
# @raise [AlphaCard::AlphaCardError]
|
50
|
+
# AlphaCardError Exception if request failed.
|
32
51
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
52
|
+
# @example
|
53
|
+
# account = AlphaCard::Account.new('demo', 'password')
|
54
|
+
# response = AlphaCard.request(
|
55
|
+
# {
|
56
|
+
# cexp: '0720',
|
57
|
+
# ccnumber: '4111111111111111',
|
58
|
+
# amount: '10.00'
|
59
|
+
# },
|
60
|
+
# account
|
61
|
+
# )
|
62
|
+
#
|
63
|
+
# #=> #<AlphaCard::AlphaCardResponse:0x1a0fda8 @data={"response"=>"1",
|
64
|
+
# "responsetext"=>"SUCCESS", "authcode"=>"123", "transactionid"=>"123",
|
65
|
+
# "avsresponse"=>"", "cvvresponse"=>"N", "orderid"=>"", "type"=>"",
|
66
|
+
# "response_code"=>"100"}>
|
36
67
|
def self.request(params = {}, account)
|
37
68
|
unless account.filled?
|
38
69
|
raise AlphaCardError.new('You must set credentials to create the sale!')
|
@@ -52,26 +83,35 @@ module AlphaCard
|
|
52
83
|
|
53
84
|
private
|
54
85
|
|
55
|
-
|
56
|
-
#
|
86
|
+
##
|
87
|
+
# Raises an exception if Alpha Card Gateway return an error or
|
88
|
+
# decline code for the request. Message is taken from the Global
|
89
|
+
# Payment Systems Credit Card Authorization Codes (codes.yml).
|
90
|
+
# If code wasn't found in <code>CREDIT_CARD_CODES</code>, then
|
91
|
+
# message = Alpha Card response text.
|
92
|
+
#
|
93
|
+
# @param [AlphaCard::AlphaCardResponse] response
|
94
|
+
# Alpha Card Response object.
|
57
95
|
#
|
58
|
-
#
|
59
|
-
#
|
96
|
+
# @raise [AlphaCard::AlphaCardError]
|
97
|
+
# AlphaCardError Exception if request failed.
|
60
98
|
#
|
61
|
-
#
|
62
|
-
#
|
99
|
+
# @return [String]
|
100
|
+
# Alpha Card Services response text.
|
63
101
|
def self.handle_alpha_card_errors(response)
|
64
102
|
code = response.text
|
65
103
|
raise AlphaCardError.new(CREDIT_CARD_CODES[code] || code) unless response.success?
|
66
104
|
end
|
67
105
|
|
68
|
-
|
106
|
+
##
|
107
|
+
# Raises an exception if a network error occurs. It
|
108
|
+
# could be request timeout, socket error or anything else.
|
69
109
|
#
|
70
|
-
#
|
71
|
-
#
|
110
|
+
# @param [Exception] e
|
111
|
+
# Exception object.
|
72
112
|
#
|
73
|
-
#
|
74
|
-
#
|
113
|
+
# @raise [AlphaCard::AlphaCardError]
|
114
|
+
# AlphaCardError Exception.
|
75
115
|
def self.handle_connection_errors(e)
|
76
116
|
case e
|
77
117
|
when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
|
data/lib/alpha_card/account.rb
CHANGED
@@ -1,13 +1,45 @@
|
|
1
1
|
module AlphaCard
|
2
|
+
##
|
3
|
+
# Implementation of Alpha Card Services account object.
|
4
|
+
# Contains credentials (username and password) for
|
5
|
+
# the Alpha Card Gateway API access.
|
2
6
|
class Account < AlphaCardObject
|
3
7
|
attribute :username, String
|
4
8
|
attribute :password, String
|
5
9
|
|
10
|
+
##
|
11
|
+
# <code>AlphaCard::Account</code> constructor.
|
12
|
+
#
|
13
|
+
# @param [String] username
|
14
|
+
# @param [String] password
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# AlphaCard::Account.new('demo', 'password')
|
18
|
+
#
|
19
|
+
# #=> #<AlphaCard::Account:0x000000039b18a8 @username="demo", @password="password">
|
6
20
|
def initialize(username, password)
|
7
21
|
self.username = username
|
8
22
|
self.password = password
|
9
23
|
end
|
10
24
|
|
25
|
+
##
|
26
|
+
# Say if all the credentials of Account is filled.
|
27
|
+
# Username and password can't be a <code>nil</code>
|
28
|
+
# object or an empty <code>String</code>.
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
31
|
+
# True if username and password is filled.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# account = AlphaCard::Account.new('demo', 'password')
|
35
|
+
# account.filled?
|
36
|
+
#
|
37
|
+
# #=> true
|
38
|
+
#
|
39
|
+
# account = AlphaCard::Account.new('', nil)
|
40
|
+
# account.filled?
|
41
|
+
#
|
42
|
+
# #=> false
|
11
43
|
def filled?
|
12
44
|
[self.username, self.password].all?(&:present?)
|
13
45
|
end
|
@@ -1,16 +1,22 @@
|
|
1
1
|
module AlphaCard
|
2
|
+
##
|
3
|
+
# Parent class for each Alpha Card Gateway object, such as
|
4
|
+
# Order, Billing, Sale and others.
|
2
5
|
class AlphaCardObject
|
3
6
|
include Virtus.model
|
4
7
|
|
5
|
-
|
8
|
+
##
|
9
|
+
# Returns the <code>Hash</code> with only filled attributes
|
10
|
+
# of the <code>AlphaCard::AlphaCardObject</code>.
|
6
11
|
#
|
7
|
-
#
|
12
|
+
# @return [Hash]
|
13
|
+
# Filled attributes of the <code>AlphaCard::AlphaCardObject</code>.
|
8
14
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
15
|
+
# @example
|
16
|
+
# order = AlphaCard::Order.new({orderid: '1', tax: nil, ponumber: 'PO123'})
|
17
|
+
# order.filled_attributes
|
18
|
+
#
|
19
|
+
# #=> {orderid: '1', ponumber: 'PO123'}
|
14
20
|
def filled_attributes
|
15
21
|
self.attributes.select { |key, value| value.present? }
|
16
22
|
end
|
@@ -1,13 +1,20 @@
|
|
1
1
|
module AlphaCard
|
2
|
+
##
|
3
|
+
# Implementation of Alpha Card Services response.
|
4
|
+
# Contains all the data, that Alpha Card Gateway
|
5
|
+
# returned for the request.
|
2
6
|
class AlphaCardResponse
|
3
7
|
attr_reader :data
|
4
8
|
|
9
|
+
# Success response code
|
5
10
|
APPROVED = '1'
|
11
|
+
# Decline response code
|
6
12
|
DECLINED = '2'
|
13
|
+
# Error response code
|
7
14
|
ERROR = '3'
|
8
15
|
|
9
16
|
def initialize(request_body)
|
10
|
-
@data =
|
17
|
+
@data = AlphaCard::Utils.parse_query(request_body)
|
11
18
|
end
|
12
19
|
|
13
20
|
def text
|
data/lib/alpha_card/billing.rb
CHANGED
data/lib/alpha_card/object.rb
CHANGED
@@ -1,17 +1,47 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Use-case: standalone Ruby scripts
|
1
|
+
##
|
2
|
+
# Some stolen methods from the active_support gem.
|
3
|
+
# For the clear dependencies.
|
4
|
+
# @todo Remove this class, rewrite library code
|
6
5
|
class Object
|
6
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
7
|
+
# For example, '', ' ', +nil+, [], and {} are all blank.
|
8
|
+
#
|
9
|
+
# This simplifies
|
10
|
+
#
|
11
|
+
# address.nil? || address.empty?
|
12
|
+
#
|
13
|
+
# to
|
14
|
+
#
|
15
|
+
# address.blank?
|
16
|
+
#
|
17
|
+
# @return [true, false]
|
7
18
|
def blank?
|
8
19
|
respond_to?(:empty?) ? !!empty? : !self
|
9
20
|
end
|
10
21
|
|
22
|
+
# An object is present if it's not blank.
|
23
|
+
#
|
24
|
+
# @return [true, false]
|
11
25
|
def present?
|
12
26
|
!blank?
|
13
27
|
end
|
14
28
|
|
29
|
+
# Invokes the public method whose name goes as first argument just like
|
30
|
+
# +public_send+ does, except that if the receiver does not respond to it the
|
31
|
+
# call returns +nil+ rather than raising an exception.
|
32
|
+
#
|
33
|
+
# This method is defined to be able to write
|
34
|
+
#
|
35
|
+
# @person.try(:name)
|
36
|
+
#
|
37
|
+
# instead of
|
38
|
+
#
|
39
|
+
# @person ? @person.name : nil
|
40
|
+
#
|
41
|
+
# +try+ returns +nil+ when called on +nil+ regardless of whether it responds
|
42
|
+
# to the method:
|
43
|
+
#
|
44
|
+
# nil.try(:to_i) # => nil, rather than 0
|
15
45
|
def try(*a, &b)
|
16
46
|
if a.empty? && block_given?
|
17
47
|
yield self
|
data/lib/alpha_card/order.rb
CHANGED
data/lib/alpha_card/sale.rb
CHANGED
@@ -1,24 +1,44 @@
|
|
1
1
|
module AlphaCard
|
2
|
+
##
|
3
|
+
# Implementation of Alpha Card Services Sale object.
|
4
|
+
# Contains all the information about Customer Credit Card,
|
5
|
+
# such as CVV, number, expiration date, etc.
|
6
|
+
# Process the Alpha Card Services payment.
|
2
7
|
class Sale < AlphaCardObject
|
3
8
|
attribute :ccexp, String
|
4
9
|
attribute :ccnumber, String
|
5
10
|
attribute :amount, String
|
6
11
|
attribute :cvv, String
|
7
12
|
|
8
|
-
|
13
|
+
##
|
14
|
+
# Not writable attribute, defines the type of transaction (default is 'sale')
|
15
|
+
#
|
16
|
+
# @attribute [r] type
|
9
17
|
attribute :type, String, default: 'sale', writer: :private
|
10
18
|
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
19
|
+
##
|
20
|
+
# Creates the sale for the specified <code>AlphaCard::Order</code>
|
21
|
+
# with the <code>AlphaCard::Account</code> credentials.
|
22
|
+
#
|
23
|
+
# @param [AlphaCard::Order] params
|
24
|
+
# An <code>AlphaCard::Order</code> object.
|
25
|
+
# @param [AlphaCard::Account] account
|
26
|
+
# An <code>AlphaCard::Account</code> object.
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
# True if sale was created successfully.
|
30
|
+
# Raise an AlphaCardError exception if some error occurred.
|
31
|
+
#
|
32
|
+
# @raise [Exception]
|
33
|
+
# Exception if one of required attributes doesn't specified.
|
14
34
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
35
|
+
# @example
|
36
|
+
# account = AlphaCard::Account.new('demo', 'password')
|
37
|
+
# order = AlphaCard::Order.new({orderid: 1, orderdescription: 'Test order'})
|
38
|
+
# sale = AlphaCard::Sale.new({ccexp: '0117', ccnumber: '4111111111111111', amount: "5.00" })
|
39
|
+
# sale.create(order, account)
|
18
40
|
#
|
19
|
-
#
|
20
|
-
# sale = AlphaCard::Sale.new(attrs)
|
21
|
-
# sale.create(order, account) #=> true or false
|
41
|
+
# #=> true
|
22
42
|
def create(order, account)
|
23
43
|
[:ccexp, :ccnumber, :amount].each do |attr|
|
24
44
|
raise Exception.new("No #{attr} information provided") if self[attr].blank?
|
data/lib/alpha_card/shipping.rb
CHANGED
@@ -0,0 +1,90 @@
|
|
1
|
+
module AlphaCard
|
2
|
+
##
|
3
|
+
# Some stolen methods to clear library dependencies.
|
4
|
+
class Utils
|
5
|
+
##
|
6
|
+
# This one is from the rack gem. It is useful for
|
7
|
+
# parsing of Alpha Card Gateway response body.
|
8
|
+
# @see https://github.com/rack/rack rack gem GitHub
|
9
|
+
class << self
|
10
|
+
##
|
11
|
+
# Default separators for query string.
|
12
|
+
DEFAULT_SEP = /[&;] */n
|
13
|
+
|
14
|
+
# A part of the rack gem.
|
15
|
+
class KeySpaceConstrainedParams
|
16
|
+
def initialize(limit = 65536)
|
17
|
+
@limit = limit
|
18
|
+
@size = 0
|
19
|
+
@params = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
@params[key]
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
@size += key.size if key && !@params.key?(key)
|
28
|
+
raise RangeError, 'exceeded available parameter key space' if @size > @limit
|
29
|
+
@params[key] = value
|
30
|
+
end
|
31
|
+
|
32
|
+
def key?(key)
|
33
|
+
@params.key?(key)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_params_hash
|
37
|
+
hash = @params
|
38
|
+
hash.keys.each do |key|
|
39
|
+
value = hash[key]
|
40
|
+
if value.kind_of?(self.class)
|
41
|
+
hash[key] = value.to_params_hash
|
42
|
+
elsif value.kind_of?(Array)
|
43
|
+
value.map! { |x| x.kind_of?(self.class) ? x.to_params_hash : x }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
hash
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
52
|
+
# target encoding of the string returned, and it defaults to UTF-8
|
53
|
+
if defined?(::Encoding)
|
54
|
+
def unescape(s, encoding = Encoding::UTF_8)
|
55
|
+
URI.decode_www_form_component(s, encoding)
|
56
|
+
end
|
57
|
+
else
|
58
|
+
def unescape(s, encoding = nil)
|
59
|
+
URI.decode_www_form_component(s, encoding)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Parses a query string to a Hash by breaking it up
|
65
|
+
# at the '&' and ';' characters.
|
66
|
+
def parse_query(qs, d = nil, &unescaper)
|
67
|
+
unescaper ||= method(:unescape)
|
68
|
+
|
69
|
+
params = KeySpaceConstrainedParams.new
|
70
|
+
|
71
|
+
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
72
|
+
next if p.empty?
|
73
|
+
k, v = p.split('=', 2).map(&unescaper)
|
74
|
+
|
75
|
+
if cur = params[k]
|
76
|
+
if cur.class == Array
|
77
|
+
params[k] << v
|
78
|
+
else
|
79
|
+
params[k] = [cur, v]
|
80
|
+
end
|
81
|
+
else
|
82
|
+
params[k] = v
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
params.to_params_hash
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alpha_card
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikita Bulaj
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/alpha_card/order.rb
|
50
50
|
- lib/alpha_card/sale.rb
|
51
51
|
- lib/alpha_card/shipping.rb
|
52
|
+
- lib/alpha_card/utils.rb
|
52
53
|
- spec/alpha_card/alpha_card_response_spec.rb
|
53
54
|
- spec/alpha_card/alpha_card_spec.rb
|
54
55
|
- spec/spec_helper.rb
|
@@ -77,3 +78,4 @@ signing_key:
|
|
77
78
|
specification_version: 4
|
78
79
|
summary: Alpha Card Services DirectPost API for Ruby
|
79
80
|
test_files: []
|
81
|
+
has_rdoc:
|