nmi_direct_post 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.simplecov +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +83 -0
- data/Rakefile +1 -0
- data/lib/nmi_direct_post.rb +7 -0
- data/lib/nmi_direct_post/base.rb +102 -0
- data/lib/nmi_direct_post/customer_vault.rb +245 -0
- data/lib/nmi_direct_post/logger.rb +17 -0
- data/lib/nmi_direct_post/transaction.rb +168 -0
- data/lib/nmi_direct_post/version.rb +3 -0
- data/nmi_direct_post.gemspec +30 -0
- data/spec/base_spec.rb +37 -0
- data/spec/customer_vault_spec.rb +243 -0
- data/spec/logger_spec.rb +77 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/credentials.rb.example +13 -0
- data/spec/support/test_credentials.rb +11 -0
- data/spec/transaction_spec.rb +303 -0
- metadata +217 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d376bc5d9401a3274444f713f3ef40f04a4a41e3
|
4
|
+
data.tar.gz: 383d6fb624a33d30f1121904b76c5b77eb0af761
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d40ddf52eceb8174336a6b9675d8a3a0e7161135cbdaed6effd7c1a361c54ebcb84432e08391a9b8829ffed9dd366401123cd750ecbe488e5b9cccf13b77e8a4
|
7
|
+
data.tar.gz: 9ac20fafa098b00e4069d05b994f0d15175033cd6b7408c617c10cd32e0318f1c6984039db20d95606fdb7375803c5413bef446914629ef29d74120cd3a53229
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.simplecov
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Isaac Betesh
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# NmiDirectPost
|
2
|
+
|
3
|
+
NmiDirectPost is a gem that encapsulates the NMI Direct Post API in an ActiveRecord-like syntax.
|
4
|
+
For more information on the NMI Direct Post API, see:
|
5
|
+
https://secure.nmi.com/merchants/resources/integration/integration_portal.php
|
6
|
+
|
7
|
+
To mimic ActivRecord syntax, it is necessary to blur, from the client's standpoint, the boundary between NMI's Direct Post API and its Query API. This fuzziness is part of the encapsulation.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'nmi_direct_post'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install nmi_direct_post
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
1) Before you can query or post, establish the connection:
|
26
|
+
|
27
|
+
NmiDirectPost::Base.establish_connection("MY_NMI_USERNAME", "MY_NMI_PASSWORD")
|
28
|
+
|
29
|
+
Theoretically, you can use a different connection for NmiDirectPost::Transaction or NmiDirectPost::CustomerVault by calling establish_connection on either of those derived classes, instead of on Base.
|
30
|
+
However, it's hard to imagine a case where this would be useful; the option is only present to mimic the syntax of ActiveRecord.
|
31
|
+
|
32
|
+
2) Query the API:
|
33
|
+
|
34
|
+
NmiDirectPost::Transaction.find_by_transaction_id(123456789)
|
35
|
+
NmiDirectPost::CustomerVault.find_by_customer_vault_id(123123123)
|
36
|
+
|
37
|
+
3) Create a CustomerVault:
|
38
|
+
|
39
|
+
george = NmiDirectPostCustomerVault.new(:first_name => 'George', :last_name => 'Washington', :cc_number => '4111111111111111', :cc_exp => '03/17')
|
40
|
+
george.create
|
41
|
+
|
42
|
+
4) Update a CustomerVault:
|
43
|
+
|
44
|
+
george.update!(:email => 'el_primero_presidente@whitehouse.gov', :address_1 => '1600 Pennsylvania Ave NW', :city => 'Washington', :state => 'DC', :postal_code => '20500')
|
45
|
+
|
46
|
+
ALTERNATIVELY:
|
47
|
+
|
48
|
+
george.email = 'el_primero_presidente@whitehouse.gov'
|
49
|
+
george.address_1 = '1600 Pennsylvania Ave NW'
|
50
|
+
george.city = 'Washington'
|
51
|
+
george.state = 'DC'
|
52
|
+
george.postal_code = '20500'
|
53
|
+
george.save! # Returns true
|
54
|
+
|
55
|
+
5) Delete a CustomerVault:
|
56
|
+
|
57
|
+
george.destroy # Returns the CustomerVault
|
58
|
+
|
59
|
+
6) Reload a CustomerVault:
|
60
|
+
|
61
|
+
george.email = 'el_primero_presidente@whitehouse.gov'
|
62
|
+
george.reload # Returns the Customer Vault
|
63
|
+
george.email # Returns the previously set email
|
64
|
+
|
65
|
+
7) CustomerVault class methods:
|
66
|
+
|
67
|
+
NmiDirectPost::CustomerVault.all_ids # Returns array of `customer_vault_id`s
|
68
|
+
NmiDirectPost::CustomerVault.first
|
69
|
+
NmiDirectPost::CustomerVault.last
|
70
|
+
NmiDirectPost::CustomerVault.all # Returns very, very big array. This method had very poor performance and could be optimized significantly in a future version of this gem.
|
71
|
+
|
72
|
+
8) Create a Transaction:
|
73
|
+
|
74
|
+
parking_ticket = NmiDirectPost::Transaction(:type => :sale, :amount => 150.01, :customer_vault_id => george.customer_vault_id)
|
75
|
+
parking_ticket.save! # Returns true
|
76
|
+
|
77
|
+
## Contributing
|
78
|
+
|
79
|
+
1. Fork it
|
80
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
81
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
82
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
83
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
require 'active_support/concern'
|
5
|
+
require 'active_support/callbacks'
|
6
|
+
require 'active_model/conversion'
|
7
|
+
require 'active_model/validator'
|
8
|
+
require 'active_model/callbacks'
|
9
|
+
require 'active_support/core_ext/module/delegation'
|
10
|
+
require 'active_model/naming'
|
11
|
+
require 'active_model/translation'
|
12
|
+
require 'active_model/validations'
|
13
|
+
require 'active_model/errors'
|
14
|
+
require 'active_support/core_ext/object/blank'
|
15
|
+
require 'addressable/uri'
|
16
|
+
require_relative 'logger'
|
17
|
+
|
18
|
+
module NmiDirectPost
|
19
|
+
class Base
|
20
|
+
POST_URI = "https://secure.nmi.com/api/transact.php"
|
21
|
+
GET_URI = "https://secure.nmi.com/api/query.php"
|
22
|
+
|
23
|
+
AUTH_PARAMS = [:username, :password]
|
24
|
+
attr_reader *AUTH_PARAMS
|
25
|
+
attr_reader :response, :response_text, :response_code
|
26
|
+
|
27
|
+
include ActiveModel::Validations
|
28
|
+
include ActiveModel::Conversion
|
29
|
+
validates_presence_of :username, :password
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@username, @password = self.class.username, self.class.password
|
33
|
+
end
|
34
|
+
|
35
|
+
def persisted?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def success?
|
40
|
+
1 == self.response
|
41
|
+
end
|
42
|
+
|
43
|
+
def logger
|
44
|
+
NmiDirectPost.logger
|
45
|
+
end
|
46
|
+
|
47
|
+
class << self
|
48
|
+
NO_CONNECTION = "Please set a username by calling NmiDirectPost::Base.establish_connection(ENV['NMI_USERNAME'], ENV['NMI_PASSWORD'])"
|
49
|
+
def establish_connection(username, password)
|
50
|
+
@username, @password = username, password
|
51
|
+
end
|
52
|
+
|
53
|
+
def username
|
54
|
+
@username || (in_base? ? raise_no_connection_error : superclass.username).tap { |_| raise_no_connection_error if _.blank? }
|
55
|
+
end
|
56
|
+
|
57
|
+
def password
|
58
|
+
@password || (in_base? ? raise_no_connection_error : superclass.password).tap { |_| raise_no_connection_error if _.blank? }
|
59
|
+
end
|
60
|
+
|
61
|
+
def generate_query_string(attributes, target = self)
|
62
|
+
((attributes.reject { |attr| target.__send__(attr).blank? }).collect { |attr| "#{attr}=#{Addressable::URI.escape(target.__send__(attr).to_s)}"}).join('&')
|
63
|
+
end
|
64
|
+
|
65
|
+
def get(query)
|
66
|
+
uri = [GET_URI, query].join('?')
|
67
|
+
data = get_http_response(uri).body
|
68
|
+
Hash.from_xml(data)["nm_response"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def post(query)
|
72
|
+
uri = [POST_URI, query].join('?')
|
73
|
+
data = get_http_response(uri)
|
74
|
+
Addressable::URI.parse([POST_URI, data.body].join('?')).query_values
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
def get_http_response(uri)
|
79
|
+
request = Net::HTTP::Get.new(uri)
|
80
|
+
url = URI.parse(uri)
|
81
|
+
http = Net::HTTP.new(url.host, url.port)
|
82
|
+
http.use_ssl = true
|
83
|
+
http.ssl_version = :TLSv1
|
84
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
85
|
+
http.request(request)
|
86
|
+
end
|
87
|
+
|
88
|
+
def in_base?
|
89
|
+
'Object' == superclass.name
|
90
|
+
end
|
91
|
+
|
92
|
+
def raise_no_connection_error
|
93
|
+
raise(StandardError, NO_CONNECTION)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
def generate_query_string(attributes)
|
99
|
+
self.class.generate_query_string(attributes, self)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'active_model/serialization'
|
2
|
+
require 'active_model/serializers/xml'
|
3
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
4
|
+
require_relative 'base'
|
5
|
+
|
6
|
+
module NmiDirectPost
|
7
|
+
class CustomerVaultNotFoundError < StandardError; end
|
8
|
+
|
9
|
+
class CustomerVaultInvalidPostActionError < StandardError; end
|
10
|
+
|
11
|
+
module MassAssignmentSecurity
|
12
|
+
class Error < StandardError; end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CustomerVault < Base
|
16
|
+
private
|
17
|
+
def self.attr_accessor_with_tracking_of_changes(*list)
|
18
|
+
list.each do |attr|
|
19
|
+
attr_reader attr
|
20
|
+
define_method("#{attr}=") do |val|
|
21
|
+
(@attributes_to_save ||=[]) << attr
|
22
|
+
instance_variable_set("@#{attr}", val)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
public
|
27
|
+
READ_ONLY_ATTRIBUTES ||= [:check_hash, :cc_hash]
|
28
|
+
attr_reader *READ_ONLY_ATTRIBUTES
|
29
|
+
attr_reader :customer_vault_id, :customer_vault, :report_type
|
30
|
+
|
31
|
+
MERCHANT_DEFINED_FIELDS ||= 20.times.collect { |i| :"merchant_defined_field_#{i+1}" }
|
32
|
+
WHITELIST_ATTRIBUTES ||= [:id, :first_name, :last_name, :address_1, :address_2, :company, :city, :state, :postal_code, :country, :email, :phone, :fax, :cell_phone, :customertaxid, :website, :shipping_first_name, :shipping_last_name, :shipping_address_1, :shipping_address_2, :shipping_company, :shipping_city, :shipping_state, :shipping_postal_code, :shipping_country, :shipping_email, :shipping_carrier, :tracking_number, :shipping_date, :shipping, :cc_number, :cc_exp, :cc_issue_number, :check_account, :check_aba, :check_name, :account_holder_type, :account_type, :sec_code, :processor_id, :cc_bin, :cc_start_date] + MERCHANT_DEFINED_FIELDS
|
33
|
+
attr_accessor_with_tracking_of_changes *WHITELIST_ATTRIBUTES
|
34
|
+
|
35
|
+
validate :billing_information_present?, :if => Proc.new { |record| :add_customer == record.customer_vault }
|
36
|
+
validates_presence_of :customer_vault_id, :message => "You must specify a %{attribute} ID when looking up an individual customer vault", :if => Proc.new { |record| :customer_vault == record.report_type }
|
37
|
+
validates_presence_of :customer_vault_id, :message => "You must specify a %{attribute} ID when updating a customer vault", :if => Proc.new { |record| :update_customer == record.customer_vault }
|
38
|
+
validates_inclusion_of :customer_vault_id, :in => [nil], :message => "You cannot specify a %{attribute} ID when creating a new customer vault. NMI will assign one upon creating the record",
|
39
|
+
:if => Proc.new { |record| :add_customer == record.customer_vault }
|
40
|
+
|
41
|
+
def initialize(attributes)
|
42
|
+
super()
|
43
|
+
if attributes[:customer_vault_id].blank?
|
44
|
+
set_attributes(attributes.dup) unless attributes.empty?
|
45
|
+
else
|
46
|
+
@customer_vault_id = attributes[:customer_vault_id].to_i
|
47
|
+
reload
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def create
|
52
|
+
post_action(:add)
|
53
|
+
self.success?
|
54
|
+
end
|
55
|
+
|
56
|
+
def update!(attributes)
|
57
|
+
begin
|
58
|
+
set_attributes(attributes)
|
59
|
+
post_action(:update)
|
60
|
+
ensure
|
61
|
+
@attributes_to_save.delete_if {|v| @attributes_to_update.include?(v) } if @attributes_to_save
|
62
|
+
@attributes_to_update = nil
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def save!
|
68
|
+
post_action(:update)
|
69
|
+
reload
|
70
|
+
self.success?
|
71
|
+
end
|
72
|
+
|
73
|
+
def destroy
|
74
|
+
post_action(:delete)
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def reload
|
79
|
+
@report_type = :customer_vault
|
80
|
+
if invalid?
|
81
|
+
@report_type = nil
|
82
|
+
return self
|
83
|
+
end
|
84
|
+
begin
|
85
|
+
safe_params = customer_vault_instance_params
|
86
|
+
logger.debug { "Loading NMI customer vault from customer_vault_id(#{customer_vault_id}) using query: #{safe_params}" }
|
87
|
+
response = self.class.get(self.class.all_params(safe_params))["customer_vault"]
|
88
|
+
raise CustomerVaultNotFoundError, "No record found for customer vault ID #{self.customer_vault_id}" if response.nil?
|
89
|
+
attributes = response["customer"].with_indifferent_access
|
90
|
+
READ_ONLY_ATTRIBUTES.each do |a|
|
91
|
+
if attributes.key?(a)
|
92
|
+
val = attributes.delete(a)
|
93
|
+
instance_variable_set("@#{a}",val)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
set_attributes(attributes.tap { |_| _.delete(:customer_vault_id) })
|
97
|
+
ensure
|
98
|
+
@report_type = nil
|
99
|
+
@attributes_to_update = nil
|
100
|
+
@attributes_to_save = nil
|
101
|
+
end
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
def credit_card?
|
106
|
+
!@cc_hash.blank?
|
107
|
+
end
|
108
|
+
|
109
|
+
def checking?
|
110
|
+
!@check_hash.blank?
|
111
|
+
end
|
112
|
+
|
113
|
+
def find!
|
114
|
+
begin
|
115
|
+
@report_type = :customer_vault
|
116
|
+
safe_params = generate_query_string(MERCHANT_DEFINED_FIELDS + [:last_name, :email, :report_type]) # These are the only fields you can use when looking up without a customer_vault_id
|
117
|
+
logger.info { "Querying NMI customer vault: #{safe_params}" }
|
118
|
+
@customer_vault_id = self.class.get(self.class.all_params(safe_params))['customer_vault'][0]['customer_vault_id'] # This assumes there is only 1 result.
|
119
|
+
# TODO: When there are multiple results, we don't know which one you want. Maybe raise an error in that case?
|
120
|
+
reload
|
121
|
+
ensure
|
122
|
+
@report_type = nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class << self
|
127
|
+
attr_reader :report_type
|
128
|
+
|
129
|
+
def find_by_customer_vault_id(customer_vault_id)
|
130
|
+
raise StandardError, "CustomerVaultID cannot be blank" if customer_vault_id.blank?
|
131
|
+
begin
|
132
|
+
new(:customer_vault_id => customer_vault_id)
|
133
|
+
rescue CustomerVaultNotFoundError
|
134
|
+
return nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def first(limit = 1)
|
139
|
+
limit(0, limit-1).first
|
140
|
+
end
|
141
|
+
|
142
|
+
def last(limit = 1)
|
143
|
+
limit(-limit, -1).first
|
144
|
+
end
|
145
|
+
|
146
|
+
def all_ids
|
147
|
+
@report_type = :customer_vault
|
148
|
+
safe_params = generate_query_string([:report_type])
|
149
|
+
NmiDirectPost.logger.debug { "Loading all NMI customer vaults using query: #{safe_params}" }
|
150
|
+
begin
|
151
|
+
customers = get(all_params(safe_params))["customer_vault"]
|
152
|
+
ensure
|
153
|
+
@report_type = nil
|
154
|
+
end
|
155
|
+
return [] if customers.nil?
|
156
|
+
customers = customers["customer"]
|
157
|
+
customers.collect { |customer| customer["customer_vault_id"].to_i }
|
158
|
+
end
|
159
|
+
|
160
|
+
def all
|
161
|
+
limit
|
162
|
+
end
|
163
|
+
|
164
|
+
def all_params(safe_params)
|
165
|
+
[safe_params, generate_query_string(Base::AUTH_PARAMS)].join('&')
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
def limit(first = 0, last = -1)
|
170
|
+
all_ids[first..last].collect { |id| new(:customer_vault_id => id) }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
def customer_vault_instance_params
|
176
|
+
generate_query_string([:customer_vault, :customer_vault_id, :report_type])
|
177
|
+
end
|
178
|
+
|
179
|
+
def post(safe_params)
|
180
|
+
logger.info { "Sending Direct Post to NMI: #{safe_params}" }
|
181
|
+
response = self.class.post(self.class.all_params(safe_params))
|
182
|
+
@response, @response_text, @response_code = response["response"].to_i, response["responsetext"], response["response_code"].to_i
|
183
|
+
@customer_vault_id = response["customer_vault_id"].to_i if :add_customer == self.customer_vault
|
184
|
+
end
|
185
|
+
|
186
|
+
def set_attributes(attributes)
|
187
|
+
attributes = attributes.with_indifferent_access
|
188
|
+
@attributes_to_update = []
|
189
|
+
merchant_defined_fields = []
|
190
|
+
if attributes.key?(:merchant_defined_field) && attributes[:merchant_defined_field].is_a?(String)
|
191
|
+
self.merchant_defined_field_1 = attributes.delete(:merchant_defined_field)
|
192
|
+
end
|
193
|
+
WHITELIST_ATTRIBUTES.each do |a|
|
194
|
+
if attributes.key?(a)
|
195
|
+
val = attributes.delete(a)
|
196
|
+
@attributes_to_update << a
|
197
|
+
end
|
198
|
+
merchant_defined_field_index = a.to_s.split('merchant_defined_field_')[1]
|
199
|
+
if (!merchant_defined_field_index.nil? && val.nil? && attributes.key?(:merchant_defined_field) && attributes[:merchant_defined_field].is_a?(Array))
|
200
|
+
index = merchant_defined_field_index.to_i - 1
|
201
|
+
if attributes[:merchant_defined_field].size > index
|
202
|
+
val = attributes[:merchant_defined_field][index]
|
203
|
+
attributes[:merchant_defined_field][index] = nil
|
204
|
+
@attributes_to_update << a
|
205
|
+
end
|
206
|
+
end
|
207
|
+
self.__send__("#{a}=", val) if @attributes_to_update.include?(a)
|
208
|
+
end
|
209
|
+
attributes.delete(:merchant_defined_field) unless attributes.key?(:merchant_defined_field) && attributes[:merchant_defined_field].any?
|
210
|
+
@id = @id.to_i if @id
|
211
|
+
raise MassAssignmentSecurity::Error, "Cannot mass-assign the following attributes: #{attributes.keys.join(", ")}" unless attributes.empty?
|
212
|
+
end
|
213
|
+
|
214
|
+
def billing_information_present?
|
215
|
+
self.errors.add(:billing_information, "Either :cc_number (a credit card number) and :cc_exp (the credit card expiration date), or :check_account, :check_aba (the routing number of the checking account) and :check_name (a nickname for the account), must be present") if (missing_cc_information? && missing_checking_information?)
|
216
|
+
end
|
217
|
+
|
218
|
+
def missing_checking_information?
|
219
|
+
self.check_account.blank? || self.check_aba.blank? || self.check_name.blank?
|
220
|
+
end
|
221
|
+
|
222
|
+
def missing_cc_information?
|
223
|
+
self.cc_exp.blank? || self.cc_number.blank?
|
224
|
+
end
|
225
|
+
|
226
|
+
def post_action(action)
|
227
|
+
@customer_vault = :"#{action}_customer"
|
228
|
+
safe_params = case action.to_sym
|
229
|
+
when :delete
|
230
|
+
customer_vault_instance_params
|
231
|
+
when :add
|
232
|
+
[customer_vault_instance_params, generate_query_string(WHITELIST_ATTRIBUTES)].join("&")
|
233
|
+
when :update
|
234
|
+
[customer_vault_instance_params, generate_query_string(@attributes_to_update || @attributes_to_save)].join("&")
|
235
|
+
else
|
236
|
+
raise CustomerVaultInvalidPostActionError, "#{action} is not a valid post action. NmiDirectPost allows the following post actions: :add, :update, :delete"
|
237
|
+
end
|
238
|
+
begin
|
239
|
+
post(safe_params) if valid?
|
240
|
+
ensure
|
241
|
+
@customer_vault = nil
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|