prismpay 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+