gimme_gimme 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
- data/Gemfile.lock +143 -0
- data/README.md +37 -0
- data/Rakefile +10 -0
- data/features/run_features.feature +40 -0
- data/features/step_definitions/rails_steps.rb +62 -0
- data/features/support/env.rb +2 -0
- data/features/support/file_helpers.rb +11 -0
- data/lib/generators/gimme_gimme/base.rb +17 -0
- data/lib/generators/gimme_gimme/install/install_generator.rb +34 -0
- data/lib/generators/gimme_gimme/install/templates/controllers/credit_cards_controller.rb +3 -0
- data/lib/generators/gimme_gimme/install/templates/create_gimme_gimme_tables.rb +29 -0
- data/lib/generators/gimme_gimme/install/templates/models/credit_card.rb +3 -0
- data/lib/generators/gimme_gimme/test_support/templates/factories/factories.rb +10 -0
- data/lib/generators/gimme_gimme/test_support/templates/support/fake_cim.rb +9 -0
- data/lib/generators/gimme_gimme/test_support/templates/testing/fake_cim_gateway.rb +15 -0
- data/lib/generators/gimme_gimme/test_support/templates/testing/fake_cim_server.rb +329 -0
- data/lib/generators/gimme_gimme/test_support/templates/testing/fake_cim_spec_helpers.rb +21 -0
- data/lib/generators/gimme_gimme/test_support/test_support_generator.rb +23 -0
- data/lib/gimme_gimme.rb +7 -0
- data/lib/gimme_gimme/cim_gateway.rb +16 -0
- data/lib/gimme_gimme/credit_card.rb +125 -0
- data/lib/gimme_gimme/credit_cards_controller.rb +18 -0
- data/lib/gimme_gimme/engine.rb +7 -0
- data/lib/gimme_gimme/user.rb +43 -0
- data/lib/gimme_gimme/version.rb +3 -0
- data/spec/environment.rb +94 -0
- data/spec/factories/clearance.rb +8 -0
- data/spec/models/credit_card_spec.rb +219 -0
- data/spec/models/user_spec.rb +20 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/testapp/config/routes.rb +4 -0
- metadata +226 -0
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module GimmeGimme
|
4
|
+
class FakeCimServer
|
5
|
+
|
6
|
+
attr_accessor :customer_profiles, :customer_payment_profiles, :transactions
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@customer_profiles = ActiveSupport::OrderedHash.new
|
10
|
+
@customer_payment_profiles = ActiveSupport::OrderedHash.new
|
11
|
+
@transactions = []
|
12
|
+
@errors = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
@customer_payment_profiles.clear
|
17
|
+
@customer_profiles.clear
|
18
|
+
@transactions.clear
|
19
|
+
@errors.clear
|
20
|
+
end
|
21
|
+
|
22
|
+
def last_customer_profile
|
23
|
+
@customer_profiles.values.last
|
24
|
+
end
|
25
|
+
|
26
|
+
def last_transaction
|
27
|
+
@transactions.last
|
28
|
+
end
|
29
|
+
|
30
|
+
def last_customer_payment_profile
|
31
|
+
@customer_payment_profiles.values.last
|
32
|
+
end
|
33
|
+
|
34
|
+
def register_error_for(request, message, type = nil)
|
35
|
+
@errors[request] = {
|
36
|
+
:type => type,
|
37
|
+
:message => message
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def request(method, url, data, headers)
|
42
|
+
Rails.logger.debug "[CIM Request] #{method} #{url}\n#{data}"
|
43
|
+
document = Nokogiri::XML.parse(data)
|
44
|
+
request_type = document.root.name
|
45
|
+
response = process_request(request_type, document)
|
46
|
+
Rails.logger.debug "[CIM Response]\n#{response}"
|
47
|
+
response
|
48
|
+
end
|
49
|
+
|
50
|
+
def customer_profile_exists?(customer_profile_id)
|
51
|
+
customer_profiles.key?(customer_profile_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def customer_payment_profile_exists?(payment_profile_id)
|
55
|
+
customer_payment_profiles.key?(payment_profile_id)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def process_request(request_type, document)
|
61
|
+
error = @errors[request_type]
|
62
|
+
auth_type = document.at('profileTransAuthOnly').present? ? :auth_only : :capture_only
|
63
|
+
|
64
|
+
if error && (error[:type].nil? || error[:type] == auth_type)
|
65
|
+
response_type = request_type.sub('Request', 'Response')
|
66
|
+
response(response_type, :message_text => error, :result_code => 'Failure')
|
67
|
+
else
|
68
|
+
case request_type
|
69
|
+
when 'createCustomerProfileRequest'
|
70
|
+
create_customer_profile(document)
|
71
|
+
when 'createCustomerProfileTransactionRequest'
|
72
|
+
create_transaction(document)
|
73
|
+
when 'getCustomerProfileRequest'
|
74
|
+
get_customer_profile(document)
|
75
|
+
when 'deleteCustomerProfileRequest'
|
76
|
+
delete_customer_profile(document)
|
77
|
+
when 'createCustomerPaymentProfileRequest'
|
78
|
+
create_customer_payment_profile(document)
|
79
|
+
when 'deleteCustomerPaymentProfileRequest'
|
80
|
+
delete_customer_payment_profile(document)
|
81
|
+
when 'updateCustomerPaymentProfileRequest'
|
82
|
+
update_customer_payment_profile(document)
|
83
|
+
else
|
84
|
+
raise "No such request type: #{request_type}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_customer_profile(document)
|
90
|
+
customer_profile_id = next_id
|
91
|
+
profile = CustomerProfile.new(customer_profile_id, document)
|
92
|
+
@customer_profiles[customer_profile_id] = profile
|
93
|
+
response('createCustomerProfileResponse', :customerProfileId => profile.customer_profile_id)
|
94
|
+
end
|
95
|
+
|
96
|
+
def create_customer_payment_profile(document)
|
97
|
+
customer_payment_profile_id = next_id
|
98
|
+
profile = CustomerPaymentProfile.new(customer_payment_profile_id, document)
|
99
|
+
@customer_profiles[profile.customer_profile_id].customer_payment_profile_id = profile.customer_payment_profile_id
|
100
|
+
@customer_payment_profiles[customer_payment_profile_id] = profile
|
101
|
+
response('createCustomerPaymentProfileResponse', :customerPaymentProfileId => profile.customer_payment_profile_id)
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_transaction(document)
|
105
|
+
xml_root = 'createCustomerProfileTransactionResponse'
|
106
|
+
transaction = Transaction.create(customer_profiles, customer_payment_profiles, document, transactions)
|
107
|
+
|
108
|
+
if transaction.success?
|
109
|
+
@transactions << transaction
|
110
|
+
response(xml_root, transaction.extra_response_opts)
|
111
|
+
else
|
112
|
+
response(xml_root, :result_code => 'Failure')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_customer_profile(document)
|
117
|
+
id = document.at("customerProfileId").text.to_i
|
118
|
+
profile = customer_profiles[id]
|
119
|
+
response('getCustomerProfileResponse', profile.to_hash)
|
120
|
+
end
|
121
|
+
|
122
|
+
def delete_customer_profile(document)
|
123
|
+
id = document.at("customerProfileId").text.to_i
|
124
|
+
customer_profiles.delete(id)
|
125
|
+
response('deleteCustomerProfileResponse', {})
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete_customer_payment_profile(document)
|
129
|
+
customer_profile_id = document.at("customerProfileId").text.to_i
|
130
|
+
customer_payment_profile_id = document.at("customerPaymentProfileId").text.to_i
|
131
|
+
customer_payment_profiles.delete(customer_payment_profile_id)
|
132
|
+
response('deleteCustomerPaymentProfileResponse', {})
|
133
|
+
end
|
134
|
+
|
135
|
+
def update_customer_payment_profile(document)
|
136
|
+
customer_payment_profile_id = document.at("customerPaymentProfileId").text.to_i
|
137
|
+
profile = CustomerPaymentProfile.new(customer_payment_profile_id, document)
|
138
|
+
@customer_profiles[profile.customer_profile_id].customer_payment_profile_id = profile.customer_payment_profile_id
|
139
|
+
@customer_payment_profiles[customer_payment_profile_id] = profile
|
140
|
+
response('updateCustomerPaymentProfileResponse', :customerPaymentProfileId => profile.customer_payment_profile_id)
|
141
|
+
end
|
142
|
+
|
143
|
+
def response(root, options)
|
144
|
+
options = {
|
145
|
+
:refId => options.delete(:ref_id) || next_id,
|
146
|
+
:messages => {
|
147
|
+
:resultCode => options.delete(:result_code) || 'Ok',
|
148
|
+
:message => {
|
149
|
+
:code => options.delete(:message_code) || 'I00001',
|
150
|
+
:text => options.delete(:message_text) || 'Successful.'
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}.update(options)
|
154
|
+
options.to_xml(:root => root)
|
155
|
+
end
|
156
|
+
|
157
|
+
def next_id
|
158
|
+
Sequencer.next_id
|
159
|
+
end
|
160
|
+
|
161
|
+
module RequestParser
|
162
|
+
def at(xpath)
|
163
|
+
@document.at(xpath).try(:text)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class CustomerProfile
|
168
|
+
attr_reader :customer_profile_id,
|
169
|
+
:customer_type, :first_name, :last_name, :expiration_date, :card_number,
|
170
|
+
:merchant_customer_id, :city, :zip, :phone_number, :address, :state
|
171
|
+
attr_accessor :customer_payment_profile_id
|
172
|
+
|
173
|
+
def initialize(customer_profile_id, document)
|
174
|
+
@document = document
|
175
|
+
|
176
|
+
@customer_profile_id = customer_profile_id
|
177
|
+
|
178
|
+
@customer_type = at("customerType")
|
179
|
+
@merchant_customer_id = at("merchantCustomerId")
|
180
|
+
end
|
181
|
+
|
182
|
+
include RequestParser
|
183
|
+
|
184
|
+
def to_hash
|
185
|
+
{
|
186
|
+
:profile => {
|
187
|
+
:customerProfileId => customer_profile_id,
|
188
|
+
:paymentProfiles => { :customerPaymentProfileId => customer_payment_profile_id }
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class CustomerPaymentProfile
|
195
|
+
include RequestParser
|
196
|
+
|
197
|
+
attr_reader :customer_profile_id, :customer_payment_profile_id, :expiration_date,
|
198
|
+
:card_number, :city, :zip, :address, :state, :first_name, :last_name
|
199
|
+
|
200
|
+
def initialize(customer_payment_profile_id, document)
|
201
|
+
@document = document
|
202
|
+
@customer_payment_profile_id = customer_payment_profile_id
|
203
|
+
|
204
|
+
@customer_profile_id = at("customerProfileId").to_i
|
205
|
+
@card_number = at("cardNumber")
|
206
|
+
@expiration_date = at("expirationDate")
|
207
|
+
@address = at("address")
|
208
|
+
@city = at("city")
|
209
|
+
@state = at("state")
|
210
|
+
@zip = at("zip")
|
211
|
+
@first_name = at("firstName")
|
212
|
+
@last_name = at("lastName")
|
213
|
+
end
|
214
|
+
|
215
|
+
def expiration_month
|
216
|
+
expiration.month
|
217
|
+
end
|
218
|
+
|
219
|
+
def expiration_year
|
220
|
+
expiration.year
|
221
|
+
end
|
222
|
+
|
223
|
+
def expiration
|
224
|
+
year, month = expiration_date.split('-')
|
225
|
+
ActiveMerchant::Billing::CreditCard::ExpiryDate.new(month, year).expiration
|
226
|
+
end
|
227
|
+
private :expiration
|
228
|
+
|
229
|
+
def to_hash
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
class Transaction
|
234
|
+
class NotImplementedError < StandardError; end
|
235
|
+
include RequestParser
|
236
|
+
|
237
|
+
attr_reader :amount, :customer_profile_id, :customer_profile, :customer_payment_profile, :transactions
|
238
|
+
|
239
|
+
def self.create(customer_profiles, customer_payment_profiles, document, transactions)
|
240
|
+
if document.at("profileTransAuthOnly").present?
|
241
|
+
AuthOnlyTransaction.new(customer_profiles, customer_payment_profiles, document, transactions)
|
242
|
+
elsif document.at("profileTransCaptureOnly").present?
|
243
|
+
CaptureOnlyTransaction.new(customer_profiles, customer_payment_profiles, document, transactions)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def initialize(customer_profiles, customer_payment_profiles, document, transactions)
|
248
|
+
@document = document
|
249
|
+
@amount = at("amount").to_f
|
250
|
+
@customer_profile_id = at("customerProfileId")
|
251
|
+
@customer_profile_payment_id = at("customerPaymentProfileId")
|
252
|
+
@customer_profile = customer_profiles[@customer_profile_id.to_i]
|
253
|
+
@customer_payment_profile = customer_payment_profiles[@customer_profile_payment_id.to_i]
|
254
|
+
end
|
255
|
+
|
256
|
+
def card_number
|
257
|
+
customer_payment_profile.card_number
|
258
|
+
end
|
259
|
+
|
260
|
+
def success?
|
261
|
+
!customer_profile.nil? &&
|
262
|
+
customer_profile.customer_payment_profile_id == @customer_profile_payment_id.to_i
|
263
|
+
end
|
264
|
+
|
265
|
+
def extra_response_opts
|
266
|
+
raise NotImplementedError
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
class AuthOnlyTransaction < Transaction
|
271
|
+
attr_accessor :authorization_code
|
272
|
+
|
273
|
+
def initialize(customer_profiles, customer_payment_profiles, document, transactions)
|
274
|
+
super
|
275
|
+
@authorization_code = Sequencer.next_id
|
276
|
+
end
|
277
|
+
|
278
|
+
def extra_response_opts
|
279
|
+
success = success? ? 1 : 0
|
280
|
+
{
|
281
|
+
:directResponse => "#{success},,,,#{@authorization_code},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
|
282
|
+
}
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
class CaptureOnlyTransaction < Transaction
|
287
|
+
attr_accessor :transaction_id
|
288
|
+
|
289
|
+
def initialize(customer_profiles, customer_payment_profiles, document, transactions)
|
290
|
+
super
|
291
|
+
@transaction_id = Sequencer.next_id
|
292
|
+
@document = document
|
293
|
+
@authorize_transaction =
|
294
|
+
transactions.detect do |transaction|
|
295
|
+
transaction.customer_payment_profile == customer_payment_profile &&
|
296
|
+
transaction.amount == amount &&
|
297
|
+
transaction.authorization_code.to_s == authorization_code.to_s
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def extra_response_opts
|
302
|
+
success = success? ? 1 : 0
|
303
|
+
{
|
304
|
+
:directResponse => "#{success},,,,,,#{@transaction_id},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
|
305
|
+
}
|
306
|
+
#{:direct_response => { :transaction_id => @transaction_id} }
|
307
|
+
end
|
308
|
+
|
309
|
+
def success?
|
310
|
+
super && !@authorize_transaction.nil?
|
311
|
+
end
|
312
|
+
|
313
|
+
def authorization_code
|
314
|
+
at("approvalCode")
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
|
321
|
+
module Sequencer
|
322
|
+
extend self
|
323
|
+
@@next_id = 0
|
324
|
+
|
325
|
+
def self.next_id
|
326
|
+
@@next_id += 1
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GimmeGimme
|
2
|
+
module FakeCimHelpers
|
3
|
+
def with_gateway(new_gateway)
|
4
|
+
old_gateway = CimGateway.instance.gateway
|
5
|
+
CimGateway.instance.gateway = new_gateway
|
6
|
+
begin
|
7
|
+
yield
|
8
|
+
ensure
|
9
|
+
CimGateway.instance.gateway = old_gateway
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def fake_cim(&block)
|
14
|
+
FakeCimServer.new.tap do |server|
|
15
|
+
with_gateway(FakeCimGateway.new(:server => server)) do
|
16
|
+
yield(server)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'generators/gimme_gimme/base'
|
2
|
+
|
3
|
+
module GimmeGimme
|
4
|
+
module Generators
|
5
|
+
class TestSupportGenerator < Base
|
6
|
+
|
7
|
+
desc <<DESC
|
8
|
+
Description:
|
9
|
+
Copy gimme_gimme fake server and spec helper files to your application.
|
10
|
+
DESC
|
11
|
+
|
12
|
+
def copy_support_files
|
13
|
+
empty_directory 'lib/gimme_gimme/testing'
|
14
|
+
empty_directory 'features/support'
|
15
|
+
empty_directory 'spec/factories'
|
16
|
+
directory 'testing', 'lib/gimme_gimme/testing'
|
17
|
+
directory 'support', 'features/support'
|
18
|
+
directory 'factories', 'spec/factories'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/gimme_gimme.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module GimmeGimme
|
4
|
+
class CimGateway
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_accessor :gateway
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@gateway = ActiveMerchant::Billing::AuthorizeNetCimGateway.new(
|
11
|
+
:login => AUTHORIZE_NET_API_LOGIN_ID,
|
12
|
+
:password => AUTHORIZE_NET_TRANSACTION_KEY
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module GimmeGimme
|
2
|
+
module CreditCard
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
class ChargeError < StandardError; end
|
5
|
+
class AuthorizationError < StandardError; end
|
6
|
+
class InvalidCreditCard < StandardError; end
|
7
|
+
|
8
|
+
included do
|
9
|
+
CARD_TYPES = ['Visa', 'Master Card', 'American Express', 'Discover'].freeze
|
10
|
+
attr_accessor :card_number, :security_code, :store_card
|
11
|
+
|
12
|
+
belongs_to :user
|
13
|
+
|
14
|
+
validates_presence_of :card_number, :security_code
|
15
|
+
validates_presence_of :expiration_month, :expiration_year, :card_type
|
16
|
+
validates_inclusion_of :card_type, :in => CARD_TYPES
|
17
|
+
validates_inclusion_of :expiration_month, :in => (1..12)
|
18
|
+
before_save :store_last_four_digits
|
19
|
+
before_create :create_customer_payment_profile
|
20
|
+
before_update :update_customer_payment_profile
|
21
|
+
after_destroy :delete_customer_payment_profile
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
def authorize(opts)
|
26
|
+
amount = opts[:amount]
|
27
|
+
amount = amount.round(2) unless amount.kind_of?(Integer)
|
28
|
+
response = self.class.gateway.create_customer_profile_transaction(
|
29
|
+
:transaction => {
|
30
|
+
:customer_profile_id => self.user.remote_customer_profile_id,
|
31
|
+
:customer_payment_profile_id => self.remote_customer_payment_profile_id,
|
32
|
+
:type => :auth_only,
|
33
|
+
:amount => amount
|
34
|
+
}
|
35
|
+
)
|
36
|
+
|
37
|
+
if response.success?
|
38
|
+
response.params['direct_response']['approval_code']
|
39
|
+
else
|
40
|
+
raise AuthorizationError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def charge(opts)
|
45
|
+
amount = opts[:amount]
|
46
|
+
amount = amount.round(2) unless amount.kind_of?(Integer)
|
47
|
+
opts[:amount] = amount
|
48
|
+
response = self.class.gateway.create_customer_profile_transaction(
|
49
|
+
:transaction => {
|
50
|
+
:customer_profile_id => self.user.remote_customer_profile_id,
|
51
|
+
:customer_payment_profile_id => self.remote_customer_payment_profile_id,
|
52
|
+
:type => :capture_only
|
53
|
+
}.merge(opts)
|
54
|
+
)
|
55
|
+
|
56
|
+
if response.success?
|
57
|
+
response.params['direct_response']['transaction_id']
|
58
|
+
else
|
59
|
+
raise ChargeError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def store_card?
|
64
|
+
!!store_card
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_customer_payment_profile
|
68
|
+
response = self.class.gateway.create_customer_payment_profile(:customer_profile_id => user.remote_customer_profile_id,
|
69
|
+
:payment_profile => {
|
70
|
+
:payment => { :credit_card => credit_card_object },
|
71
|
+
:bill_to => { :first_name => first_name, :last_name => last_name }
|
72
|
+
})
|
73
|
+
if response.success?
|
74
|
+
self.remote_customer_payment_profile_id = response.params['customer_payment_profile_id']
|
75
|
+
else
|
76
|
+
raise InvalidCreditCard
|
77
|
+
end
|
78
|
+
end
|
79
|
+
private :create_customer_payment_profile
|
80
|
+
|
81
|
+
def update_customer_payment_profile
|
82
|
+
response = self.class.gateway.update_customer_payment_profile(:customer_profile_id => user.remote_customer_profile_id,
|
83
|
+
:payment_profile => {
|
84
|
+
:payment => { :credit_card => credit_card_object },
|
85
|
+
:bill_to => { :first_name => first_name, :last_name => last_name },
|
86
|
+
:customer_payment_profile_id => remote_customer_payment_profile_id
|
87
|
+
})
|
88
|
+
unless response.success?
|
89
|
+
raise InvalidCreditCard
|
90
|
+
end
|
91
|
+
end
|
92
|
+
private :update_customer_payment_profile
|
93
|
+
|
94
|
+
def credit_card_object
|
95
|
+
ActiveMerchant::Billing::CreditCard.new(
|
96
|
+
:first_name => self.first_name.try(:dup),
|
97
|
+
:last_name => self.last_name.try(:dup),
|
98
|
+
:number => self.card_number.try(:dup),
|
99
|
+
:month => self.expiration_month.to_s.try(:dup),
|
100
|
+
:year => self.expiration_year.to_s.try(:dup),
|
101
|
+
:type => self.card_type.try(:dup),
|
102
|
+
:verification_value => self.security_code.try(:dup)
|
103
|
+
)
|
104
|
+
end
|
105
|
+
private :credit_card_object
|
106
|
+
|
107
|
+
def store_last_four_digits
|
108
|
+
self.last_four_digits = self.card_number.strip.last(4)
|
109
|
+
end
|
110
|
+
private :store_last_four_digits
|
111
|
+
|
112
|
+
def delete_customer_payment_profile
|
113
|
+
self.class.gateway.delete_customer_payment_profile(:customer_profile_id => self.user.remote_customer_profile_id,
|
114
|
+
:customer_payment_profile_id => self.remote_customer_payment_profile_id)
|
115
|
+
end
|
116
|
+
private :delete_customer_payment_profile
|
117
|
+
end
|
118
|
+
|
119
|
+
module ClassMethods
|
120
|
+
def gateway
|
121
|
+
::GimmeGimme::CimGateway.instance.gateway
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|