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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f7e8e249cdf49bffd9bbda0825018bc6406e0c52
4
- data.tar.gz: 6241892718864310e112ec3c39eb6cdc7efac26f
3
+ metadata.gz: 6af86a7de326ef53708c81f07ed025792c44841c
4
+ data.tar.gz: 5a670c2177f9b7ac326f34ea1c3e34decd5ea37c
5
5
  SHA512:
6
- metadata.gz: d604d1ca794b016047390a7bd9915a54ae3ef4d4b25d4514808ac28f109a5f2aeb9e328793f58df4b706ddc7b3557800c15906df9893e6d23d68687a6beec605
7
- data.tar.gz: 7a46b389c6aaeec686a189e5add88b864929ffe1be3169fa5f5e40c285da37efb5e593d8635367ce722329d12dc24d5781aa33970717ca6dc6d0c9c0dd35e65b
6
+ metadata.gz: ca0333c53125849ca415b73a10d9a4c659d54cff80879bc0f2aadd3aa502ffecc3af758ed87709ce83ba7016d57679b7a6f023f672952d7e9f3788fda29f7ad1
7
+ data.tar.gz: 0bea0ef881a98bd593a99a20883de46f2b94f1d6cf384caa39dbeaed8f95f53a99afa8855a22becba76f0e0f6b5ac90017263dda9d2473a4564e7938c525d7a9
data/Gemfile CHANGED
@@ -4,5 +4,4 @@ gemspec
4
4
 
5
5
  gem 'virtus'
6
6
  gem 'rest_client'
7
- gem 'rack'
8
7
  gem 'coveralls', require: false
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'alpha_card'
3
- gem.version = '0.1.6'
4
- gem.date = '2014-06-26'
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']
@@ -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
- # DirectPost API URL
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
- # AlphaCard.request(params, account) -> AlphaCardResponse
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
- # Do the POST request to the AlphaCard Gateway with <i>params</i>
31
- # from specified AlphaCard <i>account</i>.
49
+ # @raise [AlphaCard::AlphaCardError]
50
+ # AlphaCardError Exception if request failed.
32
51
  #
33
- # account = AlphaCard::Account.new('user', 'pass')
34
- # params = {amount: '10.00'}
35
- # r = AlphaCard.request(params, account) #=> AlphaCardResponse
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
- # AlphaCard.handle_errors(response) -> Exception
56
- # AlphaCard.handle_errors(response) -> nil
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
- # Raise an exception if AlphaCard Gateway return an error or decline
59
- # the request.
96
+ # @raise [AlphaCard::AlphaCardError]
97
+ # AlphaCardError Exception if request failed.
60
98
  #
61
- # response = AlphaCard.request(params, account)
62
- # handle_errors(response) #=> nil or Exception
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
- # AlphaCard.handle_connection_errors(exception) -> Exception
106
+ ##
107
+ # Raises an exception if a network error occurs. It
108
+ # could be request timeout, socket error or anything else.
69
109
  #
70
- # Raise an exception if AlphaCard Gateway return some exception
71
- # due to connection problems or some other net errors.
110
+ # @param [Exception] e
111
+ # Exception object.
72
112
  #
73
- # response = RestClient.post(URL, {param: 'value'})
74
- # handle_connection_errors(response) #=> Exception
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
@@ -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,4 +1,6 @@
1
1
  module AlphaCard
2
+ ##
3
+ # Class for Alpha Card Gateway errors and exceptions.
2
4
  class AlphaCardError < StandardError
3
5
  end
4
6
  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
- # filled_attributes -> Hash
8
+ ##
9
+ # Returns the <code>Hash</code> with only filled attributes
10
+ # of the <code>AlphaCard::AlphaCardObject</code>.
6
11
  #
7
- # Returns only filled attributes, not nil ones.
12
+ # @return [Hash]
13
+ # Filled attributes of the <code>AlphaCard::AlphaCardObject</code>.
8
14
  #
9
- # order = AlphaCard::Order.new({})
10
- # order.filled_attributes #=> {}
11
-
12
- # order = AlphaCard::Order.new({orderid: '1'})
13
- # order.filled_attributes #=> {orderid: '1'}
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 = Rack::Utils.parse_nested_query(request_body)
17
+ @data = AlphaCard::Utils.parse_query(request_body)
11
18
  end
12
19
 
13
20
  def text
@@ -1,4 +1,7 @@
1
1
  module AlphaCard
2
+ ##
3
+ # Implementation of Alpha Card Services order billing information.
4
+ # Contains all the billing information (customer name, email, email, etc).
2
5
  class Billing < AlphaCardObject
3
6
  attribute :firstname, String
4
7
  attribute :lastname, String
@@ -1,17 +1,47 @@
1
- # Object class needed to implement some nice
2
- # active_support features for projects, that
3
- # doesn't need active_support.
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
@@ -1,4 +1,7 @@
1
1
  module AlphaCard
2
+ ##
3
+ # Implementation of Alpha Card Services Order object.
4
+ # Contains all the information about order (id, description, etc).
2
5
  class Order < AlphaCardObject
3
6
  attribute :orderid, Integer
4
7
  attribute :orderdescription, String
@@ -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
- # Not writable attribute, define the type of transaction (default is 'sale')
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
- # create(order, account) -> true
12
- # create(order, account) -> false
13
- # create(order, account) -> Exception
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
- # Creates the sale for the <i>order</i> with specified
16
- # attributes, such as <i>ccexp</i>, <i>ccnumber</i>, <i>amount</i>
17
- # and <i>cvv</i>.
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
- # attrs = {ccexp: '0117', ccnumber: '123', amount: '10.00'}
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?
@@ -1,4 +1,7 @@
1
1
  module AlphaCard
2
+ ##
3
+ # Implementation of Alpha Card Services order shipping information.
4
+ # Contains all the shipping information (address, city, zip, etc).
2
5
  class Shipping < AlphaCardObject
3
6
  attribute :address_1, String
4
7
  attribute :address_2, String
@@ -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.6
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-26 00:00:00.000000000 Z
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: