prismpay 0.0.0

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.
@@ -0,0 +1,119 @@
1
+ class PrismCreditResponse
2
+ # this class will be responsible for handling the SOAP response
3
+ def initialize(prism_savon_result_obj)
4
+ # keys from successful response were :status, :result, :historyid,
5
+ # :orderid, :refcode, :authcode, :total, :merchantordernumber,
6
+ # :transdate, :paytype, :duplicate
7
+ @result = prism_savon_result_obj
8
+ end
9
+
10
+ def active_merchant_response
11
+ params = options = { }
12
+
13
+ # options[:avs_result]
14
+ # options[:cvv_result]
15
+ message = @result.body[:multi_ref][:status]
16
+
17
+ if @result.body[:multi_ref][:status] =~ /Approved/
18
+ success = true
19
+ else
20
+ success = false
21
+ end
22
+
23
+ options[:authorization] = @result.body[:multi_ref][:historyid]
24
+ options[:external_identifier] = @result.body[:multi_ref][:orderid]
25
+
26
+ ActiveMerchant::Billing::Response.new(success, message,
27
+ params, options)
28
+ end
29
+
30
+ def parse_auth(authstr)
31
+ # parses the authorization specification string returned by prismpay
32
+
33
+ trasaction_types = %w(SALE, AVSALE, AUTH, AVSAUTH, POST, AVSPOST,
34
+ VOICEPOST, VOID, CREDIT)
35
+
36
+ approval_fields = [:transaction_type, :auth_code, :ref_number,
37
+ :batch_number, :transaction_id, :avs_code,
38
+ :auth_net_message, :cvv_code, :partial_auth]
39
+
40
+ decline_fields = [:result, :decline_code, :info]
41
+
42
+ # first digit of the decline code has these meanings
43
+ decline_code_map = {
44
+ '0' => "Authorizing network declined the transaction",
45
+ '1' => "Gateway declined the transaction",
46
+ '2' => "Authorizing network returned an error, forcing a decline",
47
+ '3' => "Gateway returned an error, forcing a decline"
48
+ }
49
+
50
+ # map cvv and avs response codes to meanings
51
+ avs_map = { 'A'=> "Street addresses matches, but the ZIP code does " +
52
+ "not. The first five numerical characters contained in the " +
53
+ "address match. However, the ZIP code does not match.",
54
+
55
+ 'E' => "Ineligible transaction. The card issuing institution is " +
56
+ "not supporting AVS on the card in question. N Neither address " +
57
+ "nor ZIP matches. The first five numerical characters contained " +
58
+ "in the address do not match, and the ZIP code does not match. ",
59
+
60
+ 'R'=> "Retry (system unavailable or timed out).",
61
+
62
+ 'S' => "Card type not supported. The card type for this " +
63
+ "transaction is not supported by AVS. AVS can verify " +
64
+ "addresses for Visa cards, MasterCard, proprietary cards, and " +
65
+ "private label transactions.",
66
+
67
+ 'U' => "Address information unavailable. The address information "+
68
+ "was not available at the issuer.",
69
+
70
+ 'W' => "9 digit ZIP code match, address does not. The nine digit " +
71
+ "ZIP code matches that stored at the issuer. However, the first " +
72
+ "five numerical characters contained in the address do not match.",
73
+
74
+ 'X' => "Exact match (9 digit zip and address) Both the nine digit " +
75
+ "postal ZIP code as well as the first five numerical characters " +
76
+ "contained in the address match.",
77
+
78
+ 'Y' => "Address and 5 digits zip match. Both the five digit " +
79
+ "postal ZIP code as well as the first five numerical characters " +
80
+ "contained in the address match.",
81
+
82
+ 'Z' => "5 digit ZIP matches, but the address does not. The five " +
83
+ "digit postal ZIP code matches that stored at the VIC or card " +
84
+ "issuer's center. However, the first five numerical characters " +
85
+ "contained in the address do not match.",
86
+
87
+ 'B' => "Street address matches for international transaction. " +
88
+ "Postal Code not verified due to incompatible formats.",
89
+
90
+ 'C' => "Street address and Postal Code not verified for " +
91
+ "international transaction due to incompatible format.",
92
+
93
+ 'D' => "Street address and Postal Code match for international " +
94
+ "transaction.",
95
+
96
+ 'P' => "Postal Code match for international transaction. Street " +
97
+ "address not verified due to incompatible formats."
98
+ } # end avs_map
99
+
100
+ cvv_map = { " "=> "cvv not requested",
101
+ 'M' => "cvv Match",
102
+ 'N' => "cvv not matched",
103
+ 'P' => "Not processed",
104
+ 'S' => "cvv should be on card, but it indicated the value not present",
105
+ 'U' => "Issuer doesn't support cvv2",
106
+ 'X' => "Service provider did not respond"
107
+ }
108
+
109
+ hash = {}
110
+ fields = authstr.split /:/
111
+ if fields.size > 3 # approval
112
+ approval_fields.each_index{|x| hash[approval_fields[x]] = fields[x]}
113
+ else
114
+ decline_fields.each_index{|x| hash[decline_fields[x]] = fields[x] }
115
+ end
116
+ hash
117
+ end
118
+
119
+ end # PrismCreditResponse
@@ -0,0 +1,352 @@
1
+ require 'savon'
2
+ require 'activemerchant'
3
+ require 'prism_credit_response'
4
+ require 'builder'
5
+
6
+
7
+ class PrismPay
8
+ # this class will manage the connection to the gateway and handle
9
+ # transactions
10
+
11
+ # WSDL = "https://trans.myprismpay.com/MPWeb/services/TransactionService?wsdl"
12
+ WSDL = File.expand_path("../TransactionService.xml", __FILE__)
13
+
14
+ attr_accessor :acctid, :password
15
+ attr_reader :client
16
+
17
+ def initialize(options = {})
18
+ merchant_info = options
19
+ merchant_info = {:login => 'TEST0'} unless merchant_info[:login]
20
+
21
+ if merchant_info.respond_to?("has_key?")
22
+ @acctid = merchant_info[:login] if merchant_info.has_key?(:login)
23
+ @password = merchant_info[:password] if merchant_info.has_key?(:password)
24
+ end
25
+
26
+ @client = Savon::Client.new(WSDL) # initialize savon client
27
+
28
+ end
29
+
30
+ def build_address(addr, type= "bill")
31
+ # receives a hash that contains the keys for active_merchant
32
+ # address and type which should be 'bill' or 'ship'
33
+ # returns a str to be eval and included in xml builder block
34
+
35
+ if type != "bill" && type != "ship"
36
+ type = "bill"
37
+ end
38
+
39
+ retstr =
40
+ "xml.#{type}address('xsi:type' => 'urn:address'){
41
+ xml.addr1 '#{addr[:address1]}'
42
+ xml.addr2 '#{addr[:address2]}'
43
+ xml.city '#{addr[:city]}'
44
+ xml.state '#{addr[:state]}'
45
+ xml.zip '#{addr[:zip]}'
46
+ xml.country '#{addr[:country]}'
47
+ }"
48
+ end
49
+
50
+ def build_credit(amount, id, options)
51
+ xml_block = Proc.new { |xml|
52
+ xml.miscprocess("xsi:type" => "urn:VoidCreditPost"){
53
+ xml.acctid @acctid
54
+ xml.amount amount
55
+ xml.orderid options[:orderid]
56
+ xml.historyid id
57
+ xml.ipaddress
58
+ }
59
+ }
60
+
61
+ return xml_block
62
+ end
63
+
64
+ def build_cc_void(auth, options)
65
+ # needs to have orderid and amount in options
66
+ xml_block = Proc.new {|xml|
67
+ xml.miscprocess("xsi:type" => "urn:VoidCreditPost"){
68
+ xml.acctid @acctid
69
+ xml.amount options[:amount]
70
+ xml.orderid options[:orderid]
71
+ # xml.customizedfields{
72
+ # xml.custom1
73
+ # xml.custom2
74
+ # xml.custom3
75
+ # xml.custom4
76
+ # xml.custom5
77
+ # xml.custom6
78
+ # }
79
+ xml.historyid auth
80
+ xml.ipaddress
81
+ }
82
+ }
83
+
84
+ return xml_block
85
+ end
86
+
87
+ def build_cc_capture(amount, auth, options)
88
+ # as of now auth is historyid and we need :orderid set in options
89
+ xml_block = Proc.new {|xml|
90
+ xml.miscprocess("xsi:type" => "urn:VoidCreditPost"){
91
+ xml.acctid @acctid
92
+ xml.amount amount
93
+ xml.orderid options[:orderid]
94
+ xml.historyid auth
95
+ xml.merchantordernumber auth
96
+ xml.merchantpin auth
97
+ xml.ipaddress
98
+ }
99
+ }
100
+ return xml_block
101
+ end
102
+
103
+ def build_cc_sale_auth(amount, credit_card, options)
104
+ # return a proc object to be used as a block for builder
105
+ # passed to response.body {|xml| my xml block}
106
+
107
+ missing_fields_for_options = {
108
+ :acctid => '',
109
+ :accountkey => '',
110
+ :subid => ''
111
+ }
112
+
113
+ # to map the active_merchant option keys to prismpay
114
+ active_merchant_credit_card = {
115
+ :first_name => '',
116
+ :last_name => '',
117
+ :month => '',
118
+ :number => '',
119
+ :type => '',
120
+ :verification_value => '',
121
+ :year => ''
122
+ }
123
+
124
+ active_merchant_option_map = {
125
+ :order_id => :merchantordernumber,
126
+ :ip => :ipaddress,
127
+ :customer => '', # customer info
128
+ :invoice => '', # invoice
129
+ :merchant => '', # name of merchant offering the product
130
+ :description => '', # A description of the transaction
131
+ :email => :email, # The email address of the customer
132
+ :currency => :currencycode,
133
+ :address => '', # if this is set it is both billing and shipping
134
+ :billing_address => {
135
+ :name => '',
136
+ :company => '',
137
+ :address1 => '',
138
+ :address2 => '',
139
+ :city => '',
140
+ :state => '',
141
+ :country => '',
142
+ :zip => '',
143
+ :phone => ''
144
+ },
145
+ :shipping_address => {
146
+ :name => '',
147
+ :company => '',
148
+ :address1 => '',
149
+ :address2 => '',
150
+ :city => '',
151
+ :state => '',
152
+ :country => '',
153
+ :zip => '',
154
+ :phone => ''
155
+ }
156
+ }
157
+
158
+ if options.has_key?(:address)
159
+ bill_address = ship_address = options[:address]
160
+ else
161
+ # assigns nil to variables if keys aren't present
162
+ bill_address = options[:billing_address]
163
+ ship_address = options[:shipping_address]
164
+ end
165
+
166
+ xml_block = Proc.new{ |xml|
167
+ xml.ccinfo("xsi:type" => "urn:CreditCardInfo") {
168
+ xml.acctid @acctid
169
+ xml.accountkey options[:password] if options.has_key?(:password)
170
+ # xml.subid "xsi:nil" => "true"
171
+ xml.ccname "#{credit_card.first_name} #{credit_card.last_name}"
172
+ # xml.swipedata "xsi:nil" => "true"
173
+ # xml.cardpresent "xsi;nil" => "true"
174
+ # xml.cardreaderpresent "xsi:nil" => "true"
175
+ # xml.voiceauth "xsi:nil" => "true"
176
+ # xml.track1 "xsi:nil" => "true"
177
+ # xml.track2 "xsi:nil" => "true"
178
+ xml.ccnum credit_card.number
179
+ xml.cctype credit_card.type
180
+ xml.expmon credit_card.month
181
+ xml.expyear credit_card.year
182
+ xml.cvv2 credit_card.verification_value
183
+ xml.amount amount
184
+ xml.merchantordernumber options[:order_id] if options.has_key?(:order_id) # or invoice?
185
+ # xml.companyname # says its our companyname
186
+ eval(build_address(bill_address)) if bill_address
187
+ eval(build_address(ship_address, "ship")) if ship_address
188
+ xml.email options[:email] if options.has_key?(:email)
189
+ # xml.dlnum
190
+ # xml.ssnum
191
+ xml.phone bill_address[:phone] if bill_address
192
+ # xml.dobday
193
+ # xml.dobmonth
194
+ # xml.dobyear
195
+ # xml.memo
196
+ # xml.customizedemail("xsi:type" => "urn:customEmail"){ #method
197
+ # xml.emailto "vpat@comcast.net"
198
+ # xml.emailfrom "null@atsbank.com"
199
+ # xml.emailsubject "Transaction Service Test"
200
+ # xml.emailtext "This is just a test"
201
+ # }
202
+ # xml.recurring("xsi:type" => "urn:Recur") { #nees method
203
+ # xml.create 0
204
+ # xml.billingcycle 0
205
+ # xml.billingmax 0
206
+ # xml.start 0
207
+ # xml.amount 0
208
+ # }
209
+ xml.ipaddress options[:ip] # req field ... nil if !(exists?)
210
+ # xml.accttype ---> #have no clue
211
+ # xml.merchantpin ----> #believe this is password
212
+ # xml.currencycode
213
+ # xml.industrycode ----> # no clue
214
+ # xml.dynamicdescriptor ---> carries onto receipt for VITAL auths
215
+ # xml.profileactiontype # no clue
216
+ # xml.manualrecurring #number 1 if manual recurring
217
+ }
218
+ }
219
+
220
+ return xml_block
221
+ end
222
+
223
+ def cc_purchase(amount, creditcard, options ={})
224
+ # process a credit card sale and right now return the savon response
225
+ # The savon response needs to be mapped back into the proper response
226
+ # fields
227
+
228
+ # need to merge the gateway instance options with the options
229
+
230
+ response = @client.request :process_cc_sale do
231
+ soap.body &build_cc_sale_auth(amount, creditcard, options)
232
+ end
233
+
234
+ PrismCreditResponse.new(response)
235
+
236
+ end
237
+
238
+ def cc_authorize(amount, creditcard, options = {})
239
+ # reserve funds for future captures
240
+ response = @client.request :process_cc_auth do
241
+ soap.body &build_cc_sale_auth(amount, creditcard, options)
242
+ end
243
+ end
244
+
245
+ def cc_capture(amount, authorization, options = {})
246
+ # Captures reservered funds from previous auths
247
+ # need to put some validation into these methods before
248
+ # making the call to the build methods
249
+
250
+ response = @client.request :process_cc_post do
251
+ soap.body &build_cc_capture(amount, authorization, options)
252
+ end
253
+ end
254
+
255
+ def cc_void(identification, options = {})
256
+ # voids previous transactions
257
+ response = @client.request :process_cc_void do
258
+ soap.body &build_cc_void(identification, options)
259
+ end
260
+ end
261
+
262
+ def credit(amount, identification, options = {})
263
+ # applies credit back against previous transaction
264
+ response = @client.request :process_credit do
265
+ soap.body &build_credit(amount, identification, options)
266
+ end
267
+ end
268
+
269
+ end # PrismPay
270
+
271
+
272
+
273
+ # class CreditCard
274
+ # # credit card information... mimic ActiveMerchant
275
+ # attr_accessor :number, :month, :year, :first_name,
276
+ # :verification_value, :type, :last_name
277
+
278
+ # def [](method)
279
+ # eval ("self.#{method}")
280
+ # end
281
+
282
+ # def name
283
+ # join(@first_name, @last_name)
284
+ # end
285
+
286
+ # def name=(n)
287
+ # names = n.split(' ')
288
+ # @first_name = names[0]
289
+ # @last_name = names[1]
290
+ # end
291
+
292
+ # def []=(method, rval)
293
+ # eval ("self.#{method} = rval")
294
+ # end
295
+
296
+ # def initialize(ccinfo)
297
+ # if ccinfo.respond_to?("has_key?")
298
+ # @number = ccinfo[:number] if ccinfo.has_key?(:number)
299
+ # @month = ccinfo[:month] if ccinfo.has_key?(:month)
300
+ # @year = ccinfo[:year] if ccinfo.has_key?(:year)
301
+ # @name = ccinfo[:name] if ccinfo.has_key?(:name)
302
+ # @verification_value = ccinfo[:verification_value] if ccinfo.has_key?(:verification_value)
303
+ # @type = ccinfo[:type] if ccinfo.has_key?(:type)
304
+ # end
305
+ # end
306
+ # end # CreditCard
307
+
308
+
309
+ # #####################
310
+ # # Demo driver
311
+ # #####################
312
+
313
+ # cc = CreditCard.new({})
314
+ # cc.number = 5454545454545454
315
+ # cc.month = 7
316
+ # cc.year = 14
317
+ # cc.name = "JohnDoe Soap"
318
+ # cc.verification_value = 123
319
+ # cc.type = "Visa"
320
+
321
+ # addr2 = {
322
+ # :name => "Fathead Don",
323
+ # :address1 => "1501 S Delany Ave",
324
+ # :city => "Orlando",
325
+ # :state => "FL",
326
+ # :zip => "32806",
327
+ # :country => "US"
328
+ # }
329
+
330
+ # options = {
331
+ # :login => "TEST0",
332
+ # :order_id => Time.now.strftime("%y%m%d%H%M%S"),
333
+ # :address => addr2
334
+ # }
335
+
336
+ # gateway = PrismPay.new(options)
337
+
338
+ # purchase_amount = "23.32"
339
+
340
+ # response = gateway.cc_purchase(purchase_amount, cc, options)
341
+
342
+ # ########################################
343
+ # # NOTE
344
+ # ########################################
345
+ # # as of now the cc_purchase and cc_auth method will return the soap
346
+ # # response object from the client that objects meaningful values are
347
+ # # accessible from response.body[:multi_ref].keys()
348
+
349
+ # response = gateway.credit_sale(purchase_amount, credit_card)
350
+
351
+ # puts "The unparsed authcode is #{response.body[:multi_ref][:authcode]}"
352
+