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.
- data/CHANGELOG +168 -0
- data/CONTRIBUTORS +96 -1
- data/README.rdoc +33 -5
- data/lib/active_merchant.rb +12 -0
- data/lib/active_merchant/billing/credit_card.rb +59 -46
- data/lib/active_merchant/billing/credit_card_methods.rb +3 -3
- data/lib/active_merchant/billing/gateway.rb +16 -9
- data/lib/active_merchant/billing/gateways/authorize_net.rb +19 -9
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +134 -12
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +309 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +39 -2
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +64 -26
- data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +33 -3
- data/lib/active_merchant/billing/gateways/braintree.rb +11 -11
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +5 -1
- data/lib/active_merchant/billing/gateways/data_cash.rb +6 -2
- data/lib/active_merchant/billing/gateways/efsnet.rb +8 -2
- data/lib/active_merchant/billing/gateways/epay.rb +268 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
- data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
- data/lib/active_merchant/billing/gateways/first_pay.rb +8 -3
- data/lib/active_merchant/billing/gateways/garanti.rb +132 -92
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
- data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +12 -6
- data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -1
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +10 -8
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +7 -1
- data/lib/active_merchant/billing/gateways/moneris.rb +6 -2
- data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +16 -3
- data/lib/active_merchant/billing/gateways/orbital.rb +317 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +9 -9
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +26 -9
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +11 -11
- data/lib/active_merchant/billing/gateways/payflow_express.rb +122 -38
- data/lib/active_merchant/billing/gateways/payment_express.rb +7 -2
- data/lib/active_merchant/billing/gateways/paypal.rb +5 -5
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +33 -8
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +26 -15
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +55 -13
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
- data/lib/active_merchant/billing/gateways/plugnpay.rb +9 -3
- data/lib/active_merchant/billing/gateways/psigate.rb +5 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
- data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +7 -2
- data/lib/active_merchant/billing/gateways/realex.rb +187 -76
- data/lib/active_merchant/billing/gateways/sage_pay.rb +16 -5
- data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +39 -3
- data/lib/active_merchant/billing/gateways/smart_ps.rb +9 -3
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +7 -2
- data/lib/active_merchant/billing/gateways/usa_epay.rb +1 -1
- data/lib/active_merchant/billing/gateways/verifi.rb +6 -1
- data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
- data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
- data/lib/active_merchant/billing/integrations.rb +0 -12
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +13 -24
- data/lib/active_merchant/billing/integrations/bogus.rb +2 -2
- data/lib/active_merchant/billing/integrations/chronopay.rb +2 -2
- data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
- data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
- data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
- data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
- data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
- data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
- data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
- data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
- data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
- data/lib/active_merchant/billing/integrations/gestpay.rb +2 -2
- data/lib/active_merchant/billing/integrations/helper.rb +14 -11
- data/lib/active_merchant/billing/integrations/hi_trust.rb +2 -2
- data/lib/active_merchant/billing/integrations/ipay88.rb +4 -4
- data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
- data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
- data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
- data/lib/active_merchant/billing/integrations/nochex.rb +2 -2
- data/lib/active_merchant/billing/integrations/notification.rb +1 -1
- data/lib/active_merchant/billing/integrations/paypal.rb +2 -2
- data/lib/active_merchant/billing/integrations/quickpay.rb +6 -2
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +1 -1
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +2 -2
- data/lib/active_merchant/billing/integrations/return.rb +10 -3
- data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
- data/lib/active_merchant/billing/integrations/two_checkout.rb +2 -2
- data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +5 -5
- data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
- data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
- data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
- data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +88 -0
- data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
- data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
- data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
- data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
- data/lib/active_merchant/common.rb +1 -1
- data/lib/active_merchant/common/connection.rb +13 -8
- data/lib/active_merchant/common/country.rb +15 -6
- data/lib/active_merchant/common/post_data.rb +1 -1
- data/lib/active_merchant/common/posts_data.rb +21 -5
- data/lib/active_merchant/common/utils.rb +4 -0
- data/lib/active_merchant/common/validateable.rb +20 -15
- data/lib/active_merchant/version.rb +3 -0
- data/lib/support/gateway_support.rb +1 -1
- 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
|
-
|
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.
|
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.
|
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,
|
79
|
+
def build_request(body, options = {})
|
80
80
|
xml = Builder::XmlMarkup.new
|
81
81
|
xml.instruct!
|
82
|
-
xml.tag! 'XMLPayRequest', 'Timeout' =>
|
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,
|
193
|
-
request = build_request(request_body,
|
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
|
-
|
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
|
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
|
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
|
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
|
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! '
|
212
|
+
xml.tag! 'ExtData', 'Name' => 'ALLOWNOTE', 'Value' => options[:allow_note]
|
129
213
|
end
|
130
214
|
end
|
131
215
|
|