bitfluent-activemerchant 1.5.1.1 → 1.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/CHANGELOG +168 -0
  2. data/CONTRIBUTORS +96 -1
  3. data/README.rdoc +33 -5
  4. data/lib/active_merchant.rb +12 -0
  5. data/lib/active_merchant/billing/credit_card.rb +59 -46
  6. data/lib/active_merchant/billing/credit_card_methods.rb +3 -3
  7. data/lib/active_merchant/billing/gateway.rb +16 -9
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +19 -9
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +134 -12
  10. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +309 -0
  11. data/lib/active_merchant/billing/gateways/beanstream.rb +39 -2
  12. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +64 -26
  13. data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
  14. data/lib/active_merchant/billing/gateways/bogus.rb +33 -3
  15. data/lib/active_merchant/billing/gateways/braintree.rb +11 -11
  16. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  17. data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
  18. data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
  19. data/lib/active_merchant/billing/gateways/cyber_source.rb +5 -1
  20. data/lib/active_merchant/billing/gateways/data_cash.rb +6 -2
  21. data/lib/active_merchant/billing/gateways/efsnet.rb +8 -2
  22. data/lib/active_merchant/billing/gateways/epay.rb +268 -0
  23. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  24. data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
  25. data/lib/active_merchant/billing/gateways/first_pay.rb +8 -3
  26. data/lib/active_merchant/billing/gateways/garanti.rb +132 -92
  27. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
  28. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  29. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  30. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
  31. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  32. data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
  33. data/lib/active_merchant/billing/gateways/jetpay.rb +12 -6
  34. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -1
  35. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +10 -8
  36. data/lib/active_merchant/billing/gateways/merchant_ware.rb +7 -1
  37. data/lib/active_merchant/billing/gateways/moneris.rb +6 -2
  38. data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
  39. data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
  40. data/lib/active_merchant/billing/gateways/ogone.rb +16 -3
  41. data/lib/active_merchant/billing/gateways/orbital.rb +317 -0
  42. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  43. data/lib/active_merchant/billing/gateways/pay_junction.rb +9 -9
  44. data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
  45. data/lib/active_merchant/billing/gateways/payflow.rb +26 -9
  46. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +11 -11
  47. data/lib/active_merchant/billing/gateways/payflow_express.rb +122 -38
  48. data/lib/active_merchant/billing/gateways/payment_express.rb +7 -2
  49. data/lib/active_merchant/billing/gateways/paypal.rb +5 -5
  50. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +33 -8
  51. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +26 -15
  52. data/lib/active_merchant/billing/gateways/paypal_ca.rb +1 -1
  53. data/lib/active_merchant/billing/gateways/paypal_express.rb +55 -13
  54. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
  55. data/lib/active_merchant/billing/gateways/plugnpay.rb +9 -3
  56. data/lib/active_merchant/billing/gateways/psigate.rb +5 -0
  57. data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
  58. data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
  59. data/lib/active_merchant/billing/gateways/quickpay.rb +7 -2
  60. data/lib/active_merchant/billing/gateways/realex.rb +187 -76
  61. data/lib/active_merchant/billing/gateways/sage_pay.rb +16 -5
  62. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  63. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +39 -3
  64. data/lib/active_merchant/billing/gateways/smart_ps.rb +9 -3
  65. data/lib/active_merchant/billing/gateways/trust_commerce.rb +7 -2
  66. data/lib/active_merchant/billing/gateways/usa_epay.rb +1 -1
  67. data/lib/active_merchant/billing/gateways/verifi.rb +6 -1
  68. data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
  69. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  70. data/lib/active_merchant/billing/integrations.rb +0 -12
  71. data/lib/active_merchant/billing/integrations/action_view_helper.rb +13 -24
  72. data/lib/active_merchant/billing/integrations/bogus.rb +2 -2
  73. data/lib/active_merchant/billing/integrations/chronopay.rb +2 -2
  74. data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
  75. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
  76. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  77. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  78. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  79. data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
  80. data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
  81. data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
  82. data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
  83. data/lib/active_merchant/billing/integrations/gestpay.rb +2 -2
  84. data/lib/active_merchant/billing/integrations/helper.rb +14 -11
  85. data/lib/active_merchant/billing/integrations/hi_trust.rb +2 -2
  86. data/lib/active_merchant/billing/integrations/ipay88.rb +4 -4
  87. data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
  88. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
  89. data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
  90. data/lib/active_merchant/billing/integrations/nochex.rb +2 -2
  91. data/lib/active_merchant/billing/integrations/notification.rb +1 -1
  92. data/lib/active_merchant/billing/integrations/paypal.rb +2 -2
  93. data/lib/active_merchant/billing/integrations/quickpay.rb +6 -2
  94. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +1 -1
  95. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +2 -2
  96. data/lib/active_merchant/billing/integrations/return.rb +10 -3
  97. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  98. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  99. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
  100. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
  101. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
  102. data/lib/active_merchant/billing/integrations/two_checkout.rb +2 -2
  103. data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +5 -5
  104. data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
  105. data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
  106. data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
  107. data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +88 -0
  108. data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
  109. data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
  110. data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
  111. data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
  112. data/lib/active_merchant/common.rb +1 -1
  113. data/lib/active_merchant/common/connection.rb +13 -8
  114. data/lib/active_merchant/common/country.rb +15 -6
  115. data/lib/active_merchant/common/post_data.rb +1 -1
  116. data/lib/active_merchant/common/posts_data.rb +21 -5
  117. data/lib/active_merchant/common/utils.rb +4 -0
  118. data/lib/active_merchant/common/validateable.rb +20 -15
  119. data/lib/active_merchant/version.rb +3 -0
  120. data/lib/support/gateway_support.rb +1 -1
  121. metadata +65 -27
@@ -0,0 +1,207 @@
1
+ require 'iconv'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class PayboxDirectGateway < Gateway
6
+ TEST_URL = 'https://preprod-ppps.paybox.com/PPPS.php'
7
+ LIVE_URL = 'https://ppps.paybox.com/PPPS.php'
8
+ LIVE_URL_BACKUP = 'https://ppps1.paybox.com/PPPS.php'
9
+
10
+ # Payment API Version
11
+ API_VERSION = '00103'
12
+
13
+ # Transactions hash
14
+ TRANSACTIONS = {
15
+ :authorization => '00001',
16
+ :capture => '00002',
17
+ :purchase => '00003',
18
+ :unreferenced_credit => '00004',
19
+ :void => '00005',
20
+ :refund => '00014'
21
+ }
22
+
23
+ CURRENCY_CODES = {
24
+ "AUD"=> '036',
25
+ "CAD"=> '124',
26
+ "CZK"=> '203',
27
+ "DKK"=> '208',
28
+ "HKD"=> '344',
29
+ "ICK"=> '352',
30
+ "JPY"=> '392',
31
+ "NOK"=> '578',
32
+ "SGD"=> '702',
33
+ "SEK"=> '752',
34
+ "CHF"=> '756',
35
+ "GBP"=> '826',
36
+ "USD"=> '840',
37
+ "EUR"=> '978'
38
+ }
39
+
40
+ SUCCESS_CODES = ['00000']
41
+ UNAVAILABILITY_CODES = ['00001', '00097', '00098']
42
+ FRAUD_CODES = ['00102','00104','00105','00134','00138','00141','00143','00156','00157','00159']
43
+ SUCCESS_MESSAGE = 'The transaction was approved'
44
+ FAILURE_MESSAGE = 'The transaction failed'
45
+
46
+ # Money is referenced in cents
47
+ self.money_format = :cents
48
+ self.default_currency = 'EUR'
49
+
50
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
51
+ self.supported_countries = ['FR']
52
+
53
+ # The card types supported by the payment gateway
54
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
55
+
56
+ # The homepage URL of the gateway
57
+ self.homepage_url = 'http://www.paybox.com/'
58
+
59
+ # The name of the gateway
60
+ self.display_name = 'Paybox Direct'
61
+
62
+ def initialize(options = {})
63
+ requires!(options, :login, :password)
64
+ @options = options
65
+ super
66
+ end
67
+
68
+ def authorize(money, creditcard, options = {})
69
+ post = {}
70
+ add_invoice(post, options)
71
+ add_creditcard(post, creditcard)
72
+ commit('authorization', money, post)
73
+ end
74
+
75
+ def purchase(money, creditcard, options = {})
76
+ post = {}
77
+ add_invoice(post, options)
78
+ add_creditcard(post, creditcard)
79
+ commit('purchase', money, post)
80
+ end
81
+
82
+ def capture(money, authorization, options = {})
83
+ requires!(options, :order_id)
84
+ post = {}
85
+ add_invoice(post, options)
86
+ post[:numappel] = authorization[0,10]
87
+ post[:numtrans] = authorization[10,10]
88
+ commit('capture', money, post)
89
+ end
90
+
91
+ def void(identification, options = {})
92
+ requires!(options, :order_id, :amount)
93
+ post ={}
94
+ add_invoice(post, options)
95
+ add_reference(post, identification)
96
+ post[:porteur] = '000000000000000'
97
+ post[:dateval] = '0000'
98
+ commit('void', options[:amount], post)
99
+ end
100
+
101
+ def credit(money, identification, options = {})
102
+ deprecated CREDIT_DEPRECATION_MESSAGE
103
+ refund(money, identification, options)
104
+ end
105
+
106
+ def refund(money, identification, options = {})
107
+ post = {}
108
+ add_invoice(post, options)
109
+ add_reference(post, identification)
110
+ commit('refund', money, post)
111
+ end
112
+
113
+ def test?
114
+ @options[:test] || Base.gateway_mode == :test
115
+ end
116
+
117
+ private
118
+
119
+ def add_invoice(post, options)
120
+ post[:reference] = options[:order_id]
121
+ end
122
+
123
+ def add_creditcard(post, creditcard)
124
+ post[:porteur] = creditcard.number
125
+ post[:dateval] = expdate(creditcard)
126
+ post[:cvv] = creditcard.verification_value if creditcard.verification_value?
127
+ end
128
+
129
+ def add_reference(post, identification)
130
+ post[:numappel] = identification[0,10]
131
+ post[:numtrans] = identification[10,10]
132
+ end
133
+
134
+ def parse(body)
135
+ body = Iconv.iconv("UTF-8","LATIN1", body.to_s).join
136
+ results = {}
137
+ body.split(/&/).each do |pair|
138
+ key,val = pair.split(/\=/)
139
+ results[key.downcase.to_sym] = CGI.unescape(val) if val
140
+ end
141
+ results
142
+ end
143
+
144
+ def commit(action, money = nil, parameters = nil)
145
+ parameters[:montant] = ('0000000000' + (money ? amount(money) : ''))[-10..-1]
146
+ parameters[:devise] = CURRENCY_CODES[options[:currency] || currency(money)]
147
+ request_data = post_data(action,parameters)
148
+ response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, request_data))
149
+ response = parse(ssl_post(LIVE_URL_BACKUP, request_data)) if service_unavailable?(response) && !test?
150
+ Response.new(success?(response), message_from(response), response.merge(
151
+ :timestamp => parameters[:dateq]),
152
+ :test => test?,
153
+ :authorization => response[:numappel].to_s + response[:numtrans].to_s,
154
+ :fraud_review => fraud_review?(response),
155
+ :sent_params => parameters.delete_if{|key,value| ['porteur','dateval','cvv'].include?(key.to_s)}
156
+ )
157
+ end
158
+
159
+ def success?(response)
160
+ SUCCESS_CODES.include?(response[:codereponse])
161
+ end
162
+
163
+ def fraud_review?(response)
164
+ FRAUD_CODES.include?(response[:codereponse])
165
+ end
166
+
167
+ def service_unavailable?(response)
168
+ UNAVAILABILITY_CODES.include?(response[:codereponse])
169
+ end
170
+
171
+ def message_from(response)
172
+ success?(response) ? SUCCESS_MESSAGE : (response[:commentaire] || FAILURE_MESSAGE)
173
+ end
174
+
175
+ def post_data(action, parameters = {})
176
+
177
+ parameters.update(
178
+ :version => API_VERSION,
179
+ :type => TRANSACTIONS[action.to_sym],
180
+ :dateq => Time.now.strftime('%d%m%Y%H%M%S'),
181
+ :numquestion => unique_id(parameters[:order_id]),
182
+ :site => @options[:login].to_s[0,7],
183
+ :rang => @options[:login].to_s[7..-1],
184
+ :cle => @options[:password],
185
+ :pays => '',
186
+ :archivage => parameters[:order_id]
187
+ )
188
+
189
+ parameters.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join("&")
190
+ end
191
+
192
+ def unique_id(seed = 0)
193
+ randkey = "#{seed}#{Time.now.usec}".to_i % 2147483647 # Max paybox value for the question number
194
+
195
+ "0000000000#{randkey}"[-10..-1]
196
+ end
197
+
198
+ def expdate(credit_card)
199
+ year = sprintf("%.4i", credit_card.year)
200
+ month = sprintf("%.2i", credit_card.month)
201
+
202
+ "#{month}#{year[-2..-1]}"
203
+ end
204
+
205
+ end
206
+ end
207
+ end
@@ -16,27 +16,30 @@ module ActiveMerchant #:nodoc:
16
16
  def authorize(money, credit_card_or_reference, options = {})
17
17
  request = build_sale_or_authorization_request(:authorization, money, credit_card_or_reference, options)
18
18
 
19
- commit(request)
19
+ commit(request, options)
20
20
  end
21
21
 
22
22
  def purchase(money, credit_card_or_reference, options = {})
23
23
  request = build_sale_or_authorization_request(:purchase, money, credit_card_or_reference, options)
24
24
 
25
- commit(request)
25
+ commit(request, options)
26
26
  end
27
27
 
28
28
  def credit(money, identification_or_credit_card, options = {})
29
29
  if identification_or_credit_card.is_a?(String)
30
+ deprecated CREDIT_DEPRECATION_MESSAGE
30
31
  # Perform referenced credit
31
- request = build_reference_request(:credit, money, identification_or_credit_card, options)
32
+ refund(money, identification_or_credit_card, options)
32
33
  else
33
34
  # Perform non-referenced credit
34
35
  request = build_credit_card_request(:credit, money, identification_or_credit_card, options)
36
+ commit(request, options)
35
37
  end
36
-
37
- commit(request)
38
38
  end
39
39
 
40
+ def refund(money, reference, options = {})
41
+ commit(build_reference_request(:credit, money, reference, options), options)
42
+ end
40
43
  # Adds or modifies a recurring Payflow profile. See the Payflow Pro Recurring Billing Guide for more details:
41
44
  # https://www.paypal.com/en_US/pdf/PayflowPro_RecurringBilling_Guide.pdf
42
45
  #
@@ -54,17 +57,17 @@ module ActiveMerchant #:nodoc:
54
57
  request = build_recurring_request(options[:profile_id] ? :modify : :add, money, options) do |xml|
55
58
  add_credit_card(xml, credit_card) if credit_card
56
59
  end
57
- commit(request, :recurring)
60
+ commit(request, options.merge(:request_type => :recurring))
58
61
  end
59
62
 
60
63
  def cancel_recurring(profile_id)
61
64
  request = build_recurring_request(:cancel, 0, :profile_id => profile_id)
62
- commit(request, :recurring)
65
+ commit(request, options.merge(:request_type => :recurring))
63
66
  end
64
67
 
65
68
  def recurring_inquiry(profile_id, options = {})
66
69
  request = build_recurring_request(:inquiry, nil, options.update( :profile_id => profile_id ))
67
- commit(request, :recurring)
70
+ commit(request, options.merge(:request_type => :recurring))
68
71
  end
69
72
 
70
73
  def express
@@ -81,10 +84,21 @@ module ActiveMerchant #:nodoc:
81
84
  end
82
85
 
83
86
  def build_reference_sale_or_authorization_request(action, money, reference, options)
84
- xml = Builder::XmlMarkup.new
87
+ xml = Builder::XmlMarkup.new
85
88
  xml.tag! TRANSACTIONS[action] do
86
89
  xml.tag! 'PayData' do
87
90
  xml.tag! 'Invoice' do
91
+ # Fields accepted by PayFlow and recommended to be provided even for Reference Transaction, per Payflow docs.
92
+ xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
93
+ xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank?
94
+ xml.tag! 'Description', options[:description] unless options[:description].blank?
95
+ xml.tag! 'Comment', options[:comment] unless options[:comment].blank?
96
+ xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank?
97
+
98
+ billing_address = options[:billing_address] || options[:address]
99
+ add_address(xml, 'BillTo', billing_address, options) if billing_address
100
+ add_address(xml, 'ShipTo', options[:shipping_address],options) if options[:shipping_address]
101
+
88
102
  xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
89
103
  end
90
104
  xml.tag! 'Tender' do
@@ -105,6 +119,9 @@ module ActiveMerchant #:nodoc:
105
119
  xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
106
120
  xml.tag! 'InvNum', options[:order_id].to_s.gsub(/[^\w.]/, '') unless options[:order_id].blank?
107
121
  xml.tag! 'Description', options[:description] unless options[:description].blank?
122
+ # Comment and Comment2 will show up in manager.paypal.com as Comment1 and Comment2
123
+ xml.tag! 'Comment', options[:comment] unless options[:comment].blank?
124
+ xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].blank?
108
125
 
109
126
  billing_address = options[:billing_address] || options[:address]
110
127
  add_address(xml, 'BillTo', billing_address, options) if billing_address
@@ -4,14 +4,14 @@ module ActiveMerchant #:nodoc:
4
4
  def self.included(base)
5
5
  base.default_currency = 'USD'
6
6
 
7
- base.class_inheritable_accessor :partner
7
+ base.class_attribute :partner
8
8
 
9
9
  # Set the default partner to PayPal
10
10
  base.partner = 'PayPal'
11
11
 
12
12
  base.supported_countries = ['US', 'CA', 'SG', 'AU']
13
13
 
14
- base.class_inheritable_accessor :timeout
14
+ base.class_attribute :timeout
15
15
  base.timeout = 60
16
16
 
17
17
  # Enable safe retry of failed connections
@@ -67,27 +67,27 @@ module ActiveMerchant #:nodoc:
67
67
 
68
68
  def capture(money, authorization, options = {})
69
69
  request = build_reference_request(:capture, money, authorization, options)
70
- commit(request)
70
+ commit(request, options)
71
71
  end
72
72
 
73
73
  def void(authorization, options = {})
74
74
  request = build_reference_request(:void, nil, authorization, options)
75
- commit(request)
75
+ commit(request, options)
76
76
  end
77
77
 
78
78
  private
79
- def build_request(body, request_type = nil)
79
+ def build_request(body, options = {})
80
80
  xml = Builder::XmlMarkup.new
81
81
  xml.instruct!
82
- xml.tag! 'XMLPayRequest', 'Timeout' => 30, 'version' => "2.1", "xmlns" => XMLNS do
82
+ xml.tag! 'XMLPayRequest', 'Timeout' => timeout.to_s, 'version' => "2.1", "xmlns" => XMLNS do
83
83
  xml.tag! 'RequestData' do
84
84
  xml.tag! 'Vendor', @options[:login]
85
85
  xml.tag! 'Partner', @options[:partner]
86
- if request_type == :recurring
86
+ if options[:request_type] == :recurring
87
87
  xml << body
88
88
  else
89
89
  xml.tag! 'Transactions' do
90
- xml.tag! 'Transaction' do
90
+ xml.tag! 'Transaction', 'CustRef' => options[:customer] do
91
91
  xml.tag! 'Verbosity', 'MEDIUM'
92
92
  xml << body
93
93
  end
@@ -189,8 +189,8 @@ module ActiveMerchant #:nodoc:
189
189
  }
190
190
  end
191
191
 
192
- def commit(request_body, request_type = nil)
193
- request = build_request(request_body, request_type)
192
+ def commit(request_body, options = {})
193
+ request = build_request(request_body, options)
194
194
  headers = build_headers(request.size)
195
195
 
196
196
  response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, request, headers))
@@ -204,4 +204,4 @@ module ActiveMerchant #:nodoc:
204
204
  end
205
205
  end
206
206
  end
207
- end
207
+ end
@@ -4,48 +4,109 @@ require File.dirname(__FILE__) + '/paypal_express_common'
4
4
 
5
5
  module ActiveMerchant #:nodoc:
6
6
  module Billing #:nodoc:
7
- class PayflowExpressGateway < Gateway
7
+ # ==General Parameters
8
+ # The following parameters are supported for #setup_authorization, #setup_purchase, #authorize and #purchase transactions. I've read
9
+ # in the docs that they recommend you pass the exact same parameters to both setup and authorize/purchase.
10
+ #
11
+ # This information was gleaned from a mix of:
12
+ # * PayFlow documentation
13
+ # * for key value pairs: {Express Checkout for Payflow Pro (PDF)}[https://cms.paypal.com/cms_content/US/en_US/files/developer/PFP_ExpressCheckout_PP.pdf]
14
+ # * XMLPay: {Payflow Pro XMLPay Developer's Guide (PDF)}[https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_PayflowPro_XMLPay_Guide.pdf]
15
+ # * previous ActiveMerchant code
16
+ # * trial & error
17
+ #
18
+ # The following parameters are currently supported.
19
+ # [<tt>:ip</tt>] (opt) Customer IP Address
20
+ # [<tt>:order_id</tt>] (opt) An order or invoice number. This will be passed through to the Payflow backend at manager.paypal.com, and show up as "Supplier Reference #"
21
+ # [<tt>:description</tt>] (opt) Order description, shown to buyer (after redirected to PayPal). If Order Line Items are used (see below), then the description is suppressed. This will not be passed through to the Payflow backend.
22
+ # [<tt>:billing_address</tt>] (opt) See ActiveMerchant::Billing::Gateway for details
23
+ # [<tt>:shipping_address</tt>] (opt) See ActiveMerchant::Billing::Gateway for details
24
+ # [<tt>:currency</tt>] (req) Currency of transaction, will be set to USD by default for PayFlow Express if not specified
25
+ # [<tt>:email</tt>] (opt) Email of buyer; used to pre-fill PayPal login screen
26
+ # [<tt>:payer_id</tt>] (opt) Unique PayPal buyer account identification number, as returned by details_for request
27
+ # [<tt>:token</tt>] (req for #authorize & #purchase) Token returned by setup transaction
28
+ # [<tt>:no_shipping</tt>] (opt) Boolean for whether or not to display shipping address to buyer
29
+ # [<tt>:address_override</tt>] (opt) Boolean. If true, display shipping address passed by parameters, rather than shipping address on file with PayPal
30
+ # [<tt>:allow_note</tt>] (opt) Boolean for permitting buyer to add note during checkout. Note contents can be retrieved with details_for transaction
31
+ # [<tt>:return_url</tt>] (req) URL to which the buyer’s browser is returned after choosing to pay.
32
+ # [<tt>:cancel_return_url</tt>] (req) URL to which the buyer is returned if the buyer cancels the order.
33
+ # [<tt>:notify_url</tt>] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction.
34
+ # [<tt>:comment</tt>] (opt) Comment field which will be reported to Payflow backend (at manager.paypal.com) as Comment1
35
+ # [<tt>:comment2</tt>] (opt) Comment field which will be reported to Payflow backend (at manager.paypal.com) as Comment2
36
+ #
37
+ # ==Line Items
38
+ # Support for order line items is available, but has to be enabled on the PayFlow backend. This is what I was told by Todd Sieber at Technical Support:
39
+ #
40
+ # <em>You will need to call Payflow Support at 1-888-883-9770, choose option #2. Request that they update your account in "Pandora" under Product Settings >> PayPal Mark and update the Features Bitmap to 1111111111111112. This is 15 ones and a two.</em>
41
+ #
42
+ # See here[https://www.x.com/message/206214#206214] for the forum discussion (requires login to {x.com}[https://x.com]
43
+ #
44
+ # [<tt>:items</tt>] (opt) Array of Order Line Items hashes. These are shown to the buyer after redirect to PayPal.
45
+ #
46
+ #
47
+ #
48
+ # The following keys are supported for line items:
49
+ # [<tt>:name</tt>] Name of line item
50
+ # [<tt>:description</tt>] Description of line item
51
+ # [<tt>:amount</tt>] Line Item Amount in Cents (as Integer)
52
+ # [<tt>:quantity</tt>] Line Item Quantity (default to 1 if left blank)
53
+ #
54
+ # ====Customization of Payment Page
55
+ # [<tt>:page_style</tt>] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction.
56
+ # [<tt>:header_image</tt>] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction.
57
+ # [<tt>:background_color</tt>] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction.
58
+ # ====Additional options for old Checkout Experience, being phased out in 2010 and 2011
59
+ # [<tt>:header_background_color</tt>] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction.
60
+ # [<tt>:header_border_color</tt>] (opt) Your URL for receiving Instant Payment Notification (IPN) about this transaction.
61
+
62
+
63
+ class PayflowExpressGateway < Gateway
8
64
  include PayflowCommonAPI
9
65
  include PaypalExpressCommon
10
66
 
11
- self.test_redirect_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='
67
+ self.test_redirect_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
12
68
  self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside'
13
69
  self.display_name = 'PayPal Express Checkout'
14
-
70
+
15
71
  def authorize(money, options = {})
16
72
  requires!(options, :token, :payer_id)
17
73
  request = build_sale_or_authorization_request('Authorization', money, options)
18
- commit(request)
74
+ commit(request, options)
19
75
  end
20
76
 
21
77
  def purchase(money, options = {})
22
78
  requires!(options, :token, :payer_id)
23
79
  request = build_sale_or_authorization_request('Sale', money, options)
24
- commit(request)
80
+ commit(request, options)
25
81
  end
26
82
 
27
- def credit(money, identification, options = {})
83
+ def refund(money, identification, options = {})
28
84
  request = build_reference_request(:credit, money, identification, options)
29
- commit(request)
85
+ commit(request, options)
30
86
  end
31
87
 
88
+ def credit(money, identification, options = {})
89
+ deprecated CREDIT_DEPRECATION_MESSAGE
90
+ refund(money, identification, options)
91
+ end
92
+
32
93
  def setup_authorization(money, options = {})
33
94
  requires!(options, :return_url, :cancel_return_url)
34
95
 
35
96
  request = build_setup_express_sale_or_authorization_request('Authorization', money, options)
36
- commit(request)
97
+ commit(request, options)
37
98
  end
38
99
 
39
100
  def setup_purchase(money, options = {})
40
101
  requires!(options, :return_url, :cancel_return_url)
41
102
 
42
103
  request = build_setup_express_sale_or_authorization_request('Sale', money, options)
43
- commit(request)
104
+ commit(request, options)
44
105
  end
45
106
 
46
107
  def details_for(token)
47
108
  request = build_get_express_details_request(token)
48
- commit(request)
109
+ commit(request, options)
49
110
  end
50
111
 
51
112
  private
@@ -64,28 +125,12 @@ module ActiveMerchant #:nodoc:
64
125
  end
65
126
  xml.target!
66
127
  end
67
-
128
+
68
129
  def build_setup_express_sale_or_authorization_request(action, money, options = {})
69
130
  xml = Builder::XmlMarkup.new :indent => 2
70
131
  xml.tag! 'SetExpressCheckout' do
71
132
  xml.tag! action do
72
- xml.tag! 'PayData' do
73
- xml.tag! 'Invoice' do
74
- xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
75
- xml.tag! 'InvNum', options[:order_id] unless options[:order_id].blank?
76
- xml.tag! 'Description', options[:description] unless options[:description].blank?
77
-
78
- billing_address = options[:billing_address] || options[:address]
79
- add_address(xml, 'BillTo', billing_address, options) if billing_address
80
- add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
81
-
82
- xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
83
- end
84
-
85
- xml.tag! 'Tender' do
86
- add_paypal_details(xml, options)
87
- end
88
- end
133
+ add_pay_data xml, money, options
89
134
  end
90
135
  end
91
136
  xml.target!
@@ -95,19 +140,55 @@ module ActiveMerchant #:nodoc:
95
140
  xml = Builder::XmlMarkup.new :indent => 2
96
141
  xml.tag! 'DoExpressCheckout' do
97
142
  xml.tag! action do
98
- xml.tag! 'PayData' do
99
- xml.tag! 'Invoice' do
100
- xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
101
- end
102
- xml.tag! 'Tender' do
103
- add_paypal_details xml, options
104
- end
105
- end
143
+ add_pay_data xml, money, options
106
144
  end
107
145
  end
108
146
  xml.target!
109
147
  end
110
-
148
+
149
+ def add_pay_data(xml, money, options)
150
+ xml.tag! 'PayData' do
151
+ xml.tag! 'Invoice' do
152
+ xml.tag! 'CustIP', options[:ip] unless options[:ip].blank?
153
+ xml.tag! 'InvNum', options[:order_id] unless options[:order_id].blank?
154
+ # Description field will be shown to buyer, unless line items are also being supplied (then only line items are shown).
155
+ xml.tag! 'Description', options[:description] unless options[:description].blank?
156
+ # Comment, Comment2 should make it to the backend at manager.paypal.com, as with Payflow credit card transactions
157
+ # but that doesn't seem to work (yet?). See: https://www.x.com/thread/51908?tstart=0
158
+ xml.tag! 'Comment', options[:comment] unless options[:comment].nil?
159
+ xml.tag!('ExtData', 'Name'=> 'COMMENT2', 'Value'=> options[:comment2]) unless options[:comment2].nil?
160
+
161
+ billing_address = options[:billing_address] || options[:address]
162
+ add_address(xml, 'BillTo', billing_address, options) if billing_address
163
+ add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
164
+
165
+ # Note: To get order line-items to show up with Payflow Express, this feature has to be enabled on the backend.
166
+ # Call Support at 888 883 9770, press 2. Then request that they update your account in "Pandora" under Product Settings >> PayPal
167
+ # Mark and update the Features Bitmap to 1111111111111112. This is 15 ones and a two.
168
+ # See here for the forum discussion: https://www.x.com/message/206214#206214
169
+ items = options[:items] || []
170
+ items.each_with_index do |item, index|
171
+ xml.tag! 'ExtData', 'Name' => "L_DESC#{index}", 'Value' => item[:description]
172
+ xml.tag! 'ExtData', 'Name' => "L_COST#{index}", 'Value' => amount(item[:amount])
173
+ xml.tag! 'ExtData', 'Name' => "L_QTY#{index}", 'Value' => item[:quantity] || '1'
174
+ xml.tag! 'ExtData', 'Name' => "L_NAME#{index}", 'Value' => item[:name]
175
+ # Note: An ItemURL is supported in Paypal Express (different API), but not PayFlow Express, as far as I can tell.
176
+ # L_URLn nor L_ITEMURLn seem to work
177
+ end
178
+ if items.any?
179
+ xml.tag! 'ExtData', 'Name' => 'CURRENCY', 'Value' => options[:currency] || currency(money)
180
+ xml.tag! 'ExtData', 'Name' => "ITEMAMT", 'Value' => amount(money)
181
+ end
182
+
183
+ xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
184
+ end
185
+
186
+ xml.tag! 'Tender' do
187
+ add_paypal_details(xml, options)
188
+ end
189
+ end
190
+ end
191
+
111
192
  def add_paypal_details(xml, options)
112
193
  xml.tag! 'PayPal' do
113
194
  xml.tag! 'EMail', options[:email] unless options[:email].blank?
@@ -123,9 +204,12 @@ module ActiveMerchant #:nodoc:
123
204
  # Customization of the payment page
124
205
  xml.tag! 'PageStyle', options[:page_style] unless options[:page_style].blank?
125
206
  xml.tag! 'HeaderImage', options[:header_image] unless options[:header_image].blank?
207
+ xml.tag! 'PayflowColor', options[:background_color] unless options[:background_color].blank?
208
+ # Note: HeaderImage and PayflowColor apply to both the new (as of 2010) and the old checkout experience
209
+ # HeaderBackColor and HeaderBorderColor apply only to the old checkout experience which is being phased out.
126
210
  xml.tag! 'HeaderBackColor', options[:header_background_color] unless options[:header_background_color].blank?
127
211
  xml.tag! 'HeaderBorderColor', options[:header_border_color] unless options[:header_border_color].blank?
128
- xml.tag! 'PayflowColor', options[:background_color] unless options[:background_color].blank?
212
+ xml.tag! 'ExtData', 'Name' => 'ALLOWNOTE', 'Value' => options[:allow_note]
129
213
  end
130
214
  end
131
215