offsite_payments 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +70 -0
- data/lib/offsite_payments.rb +46 -0
- data/lib/offsite_payments/action_view_helper.rb +72 -0
- data/lib/offsite_payments/helper.rb +119 -0
- data/lib/offsite_payments/integrations.rb +14 -0
- data/lib/offsite_payments/integrations/a1agregator.rb +245 -0
- data/lib/offsite_payments/integrations/authorize_net_sim.rb +580 -0
- data/lib/offsite_payments/integrations/bit_pay.rb +150 -0
- data/lib/offsite_payments/integrations/bogus.rb +32 -0
- data/lib/offsite_payments/integrations/chronopay.rb +283 -0
- data/lib/offsite_payments/integrations/citrus.rb +227 -0
- data/lib/offsite_payments/integrations/direc_pay.rb +339 -0
- data/lib/offsite_payments/integrations/directebanking.rb +237 -0
- data/lib/offsite_payments/integrations/doku.rb +171 -0
- data/lib/offsite_payments/integrations/dotpay.rb +166 -0
- data/lib/offsite_payments/integrations/dwolla.rb +160 -0
- data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
- data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
- data/lib/offsite_payments/integrations/epay.rb +161 -0
- data/lib/offsite_payments/integrations/first_data.rb +133 -0
- data/lib/offsite_payments/integrations/gestpay.rb +201 -0
- data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
- data/lib/offsite_payments/integrations/ipay88.rb +240 -0
- data/lib/offsite_payments/integrations/klarna.rb +291 -0
- data/lib/offsite_payments/integrations/liqpay.rb +216 -0
- data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
- data/lib/offsite_payments/integrations/mollie_ideal.rb +213 -0
- data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
- data/lib/offsite_payments/integrations/nochex.rb +228 -0
- data/lib/offsite_payments/integrations/pag_seguro.rb +255 -0
- data/lib/offsite_payments/integrations/paxum.rb +114 -0
- data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
- data/lib/offsite_payments/integrations/paydollar.rb +142 -0
- data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
- data/lib/offsite_payments/integrations/paypal.rb +362 -0
- data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
- data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
- data/lib/offsite_payments/integrations/payu_in.rb +266 -0
- data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
- data/lib/offsite_payments/integrations/platron.rb +153 -0
- data/lib/offsite_payments/integrations/pxpay.rb +271 -0
- data/lib/offsite_payments/integrations/quickpay.rb +232 -0
- data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
- data/lib/offsite_payments/integrations/robokassa.rb +154 -0
- data/lib/offsite_payments/integrations/sage_pay_form.rb +425 -0
- data/lib/offsite_payments/integrations/two_checkout.rb +332 -0
- data/lib/offsite_payments/integrations/universal.rb +180 -0
- data/lib/offsite_payments/integrations/valitor.rb +200 -0
- data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
- data/lib/offsite_payments/integrations/web_pay.rb +186 -0
- data/lib/offsite_payments/integrations/webmoney.rb +119 -0
- data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
- data/lib/offsite_payments/integrations/world_pay.rb +273 -0
- data/lib/offsite_payments/notification.rb +71 -0
- data/lib/offsite_payments/return.rb +37 -0
- data/lib/offsite_payments/version.rb +3 -0
- metadata +270 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module Ipay88
|
4
|
+
def self.service_url
|
5
|
+
"https://www.mobile88.com/epayment/entry.asp"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.requery_url
|
9
|
+
"https://www.mobile88.com/epayment/enquiry.asp"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.return(query_string, options={})
|
13
|
+
Return.new(query_string, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
class Helper < OffsitePayments::Helper
|
17
|
+
include ActiveMerchant::RequiresParameters
|
18
|
+
|
19
|
+
# Currencies supported
|
20
|
+
# MYR (Malaysian Ringgit - for all payment methods except China Union Pay and PayPal)
|
21
|
+
# USD (US Dollar - only for PayPal)
|
22
|
+
# CNY (Yuan Renminbi - only for China Union Pay)
|
23
|
+
SUPPORTED_CURRENCIES = %w[MYR USD CNY]
|
24
|
+
|
25
|
+
# Languages supported
|
26
|
+
# ISO-8859-1 (English)
|
27
|
+
# UTF-8 (Unicode)
|
28
|
+
# GB2312 (Chinese Simplified)
|
29
|
+
# GD18030 (Chinese Simplified)
|
30
|
+
# BIG5 (Chinese Traditional)
|
31
|
+
SUPPORTED_LANGS = %w[ISO-8859-1 UTF-8 GB2312 GD18030 BIG5]
|
32
|
+
|
33
|
+
# Payment methods supported
|
34
|
+
# 8 (Alliance Online Transfer)
|
35
|
+
# 10 (AmBank)
|
36
|
+
# 21 (China Union Pay)
|
37
|
+
# 20 (CIMB Click)
|
38
|
+
# 2 (Credit Card MYR)
|
39
|
+
# 16 (FPX)
|
40
|
+
# 15 (Hong Leong Bank Transfer)
|
41
|
+
# 6 (Maybank2u.com)
|
42
|
+
# 23 (MEPS Cash)
|
43
|
+
# 17 (Mobile Money)
|
44
|
+
# 33 (PayPal)
|
45
|
+
# 14 (RHB)
|
46
|
+
PAYMENT_METHODS = %w[8 10 21 20 2 16 15 6 23 17 33 14]
|
47
|
+
|
48
|
+
attr_reader :amount_in_cents, :merchant_key
|
49
|
+
|
50
|
+
def initialize(order, account, options = {})
|
51
|
+
requires!(options, :amount, :currency, :credential2)
|
52
|
+
@merchant_key = options[:credential2]
|
53
|
+
@amount_in_cents = options[:amount]
|
54
|
+
super
|
55
|
+
add_field mappings[:signature], signature
|
56
|
+
end
|
57
|
+
|
58
|
+
def amount_in_dollars
|
59
|
+
sprintf("%.2f", @amount_in_cents.to_f/100)
|
60
|
+
end
|
61
|
+
|
62
|
+
def amount=(money)
|
63
|
+
@amount_in_cents = money.respond_to?(:cents) ? money.cents : money
|
64
|
+
raise ArgumentError, "amount must be a Money object or an integer" if money.is_a?(String)
|
65
|
+
raise ActionViewHelperError, "amount must be greater than $0.00" if @amount_in_cents.to_i <= 0
|
66
|
+
|
67
|
+
add_field mappings[:amount], amount_in_dollars
|
68
|
+
end
|
69
|
+
|
70
|
+
def currency(symbol)
|
71
|
+
raise ArgumentError, "unsupported currency" unless SUPPORTED_CURRENCIES.include?(symbol)
|
72
|
+
add_field mappings[:currency], symbol
|
73
|
+
end
|
74
|
+
|
75
|
+
def language(lang)
|
76
|
+
raise ArgumentError, "unsupported language" unless SUPPORTED_LANGS.include?(lang)
|
77
|
+
add_field mappings[:language], lang
|
78
|
+
end
|
79
|
+
|
80
|
+
def payment(pay_method)
|
81
|
+
raise ArgumentError, "unsupported payment method" unless PAYMENT_METHODS.include?(pay_method.to_s)
|
82
|
+
add_field mappings[:payment], pay_method
|
83
|
+
end
|
84
|
+
|
85
|
+
def customer(params = {})
|
86
|
+
add_field(mappings[:customer][:name], "#{params[:first_name]} #{params[:last_name]}")
|
87
|
+
add_field(mappings[:customer][:email], params[:email])
|
88
|
+
add_field(mappings[:customer][:phone], params[:phone])
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.sign(str)
|
92
|
+
[Digest::SHA1.digest(str)].pack("m").chomp
|
93
|
+
end
|
94
|
+
|
95
|
+
def signature
|
96
|
+
self.class.sign(self.sig_components)
|
97
|
+
end
|
98
|
+
|
99
|
+
mapping :account, "MerchantCode"
|
100
|
+
mapping :amount, "Amount"
|
101
|
+
mapping :currency, "Currency"
|
102
|
+
mapping :order, "RefNo"
|
103
|
+
mapping :description, "ProdDesc"
|
104
|
+
mapping :customer, :name => "UserName",
|
105
|
+
:email => "UserEmail",
|
106
|
+
:phone => "UserContact"
|
107
|
+
mapping :remark, "Remark"
|
108
|
+
mapping :language, "Lang"
|
109
|
+
mapping :payment, "PaymentId"
|
110
|
+
mapping :return_url, "ResponseURL"
|
111
|
+
mapping :signature, "Signature"
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
def sig_components
|
116
|
+
components = [merchant_key]
|
117
|
+
components << fields[mappings[:account]]
|
118
|
+
components << fields[mappings[:order]]
|
119
|
+
components << amount_in_dollars.gsub(/[.,]/, '')
|
120
|
+
components << fields[mappings[:currency]]
|
121
|
+
components.join
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Notification < OffsitePayments::Notification
|
126
|
+
include ActiveMerchant::PostsData
|
127
|
+
|
128
|
+
def status
|
129
|
+
params["Status"] == '1' ? 'Completed' : 'Failed'
|
130
|
+
end
|
131
|
+
|
132
|
+
def complete?
|
133
|
+
status == 'Completed'
|
134
|
+
end
|
135
|
+
|
136
|
+
def item_id
|
137
|
+
params["RefNo"]
|
138
|
+
end
|
139
|
+
|
140
|
+
def gross
|
141
|
+
params["Amount"]
|
142
|
+
end
|
143
|
+
|
144
|
+
def currency
|
145
|
+
params["Currency"]
|
146
|
+
end
|
147
|
+
|
148
|
+
def account
|
149
|
+
params["MerchantCode"]
|
150
|
+
end
|
151
|
+
|
152
|
+
def payment
|
153
|
+
params["PaymentId"].to_i
|
154
|
+
end
|
155
|
+
|
156
|
+
def remark
|
157
|
+
params["Remark"]
|
158
|
+
end
|
159
|
+
|
160
|
+
def transaction_id
|
161
|
+
params["TransId"]
|
162
|
+
end
|
163
|
+
|
164
|
+
def auth_code
|
165
|
+
params["AuthCode"]
|
166
|
+
end
|
167
|
+
|
168
|
+
def error
|
169
|
+
params["ErrDesc"]
|
170
|
+
end
|
171
|
+
|
172
|
+
def signature
|
173
|
+
params["Signature"]
|
174
|
+
end
|
175
|
+
|
176
|
+
def secure?
|
177
|
+
generated_signature == signature
|
178
|
+
end
|
179
|
+
|
180
|
+
def success?
|
181
|
+
status == 'Completed'
|
182
|
+
end
|
183
|
+
|
184
|
+
def acknowledge
|
185
|
+
secure? && success? && requery == "00"
|
186
|
+
end
|
187
|
+
|
188
|
+
protected
|
189
|
+
|
190
|
+
def generated_signature
|
191
|
+
Helper.sign(sig_components)
|
192
|
+
end
|
193
|
+
|
194
|
+
def sig_components
|
195
|
+
components = [@options[:credential2]]
|
196
|
+
[:account, :payment, :item_id, :amount_in_cents, :currency].each do |i|
|
197
|
+
components << send(i)
|
198
|
+
end
|
199
|
+
components << params["Status"]
|
200
|
+
components.join
|
201
|
+
end
|
202
|
+
|
203
|
+
def requery
|
204
|
+
data = { "MerchantCode" => account, "RefNo" => item_id, "Amount" => gross }
|
205
|
+
params = parameterize(data)
|
206
|
+
ssl_post Ipay88.requery_url, params, { "Content-Length" => params.size.to_s, "User-Agent" => "Active Merchant -- http://activemerchant.org" }
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def parameterize(params)
|
212
|
+
params.reject { |k, v| v.blank? }.keys.sort.collect { |key| "#{key}=#{CGI.escape(params[key].to_s)}" }.join("&")
|
213
|
+
end
|
214
|
+
|
215
|
+
def amount_in_cents
|
216
|
+
@amount_in_cents ||= (gross || "").gsub(/[.,]/, "")
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class Return < OffsitePayments::Return
|
221
|
+
def initialize(query_string, options = {})
|
222
|
+
super
|
223
|
+
@notification = Notification.new(query_string, options)
|
224
|
+
end
|
225
|
+
|
226
|
+
def success?
|
227
|
+
params["Status"] == "1"
|
228
|
+
end
|
229
|
+
|
230
|
+
def cancelled?
|
231
|
+
params["ErrDesc"] == 'Customer Cancel Transaction'
|
232
|
+
end
|
233
|
+
|
234
|
+
def message
|
235
|
+
params["ErrDesc"]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,291 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module Klarna
|
4
|
+
mattr_accessor :service_url
|
5
|
+
self.service_url = 'https://api.hostedcheckout.io/api/v1/checkout'
|
6
|
+
|
7
|
+
def self.notification(post_body, options = {})
|
8
|
+
Notification.new(post_body, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.return(query_string, options = {})
|
12
|
+
Return.new(query_string, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.cart_items_payload(fields, cart_items)
|
16
|
+
check_required_fields!(fields)
|
17
|
+
|
18
|
+
payload = fields['purchase_country'].to_s +
|
19
|
+
fields['purchase_currency'].to_s +
|
20
|
+
fields['locale'].to_s
|
21
|
+
|
22
|
+
cart_items.each_with_index do |item, i|
|
23
|
+
payload << fields["cart_item-#{i}_type"].to_s +
|
24
|
+
fields["cart_item-#{i}_reference"].to_s +
|
25
|
+
fields["cart_item-#{i}_quantity"].to_s +
|
26
|
+
fields["cart_item-#{i}_unit_price"].to_s +
|
27
|
+
fields.fetch("cart_item-#{i}_discount_rate", '').to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
payload << fields['merchant_id'].to_s +
|
31
|
+
fields['merchant_terms_uri'].to_s +
|
32
|
+
fields['merchant_checkout_uri'].to_s +
|
33
|
+
fields['merchant_base_uri'].to_s +
|
34
|
+
fields['merchant_confirmation_uri'].to_s
|
35
|
+
|
36
|
+
payload
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.sign(fields, cart_items, shared_secret)
|
40
|
+
payload = cart_items_payload(fields, cart_items)
|
41
|
+
|
42
|
+
digest(payload, shared_secret)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.digest(payload, shared_secret)
|
46
|
+
Digest::SHA256.base64digest(payload + shared_secret.to_s)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def self.check_required_fields!(fields)
|
52
|
+
%w(purchase_country
|
53
|
+
purchase_currency
|
54
|
+
locale
|
55
|
+
merchant_id
|
56
|
+
merchant_terms_uri
|
57
|
+
merchant_checkout_uri
|
58
|
+
merchant_base_uri
|
59
|
+
merchant_confirmation_uri).each do |required_field|
|
60
|
+
raise ArgumentError, "Missing required field #{required_field}" if fields[required_field].nil?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Helper < OffsitePayments::Helper
|
65
|
+
mapping :currency, 'purchase_currency'
|
66
|
+
mapping :cancel_return_url, ['merchant_terms_uri', 'merchant_checkout_uri', 'merchant_base_uri']
|
67
|
+
mapping :account, 'merchant_id'
|
68
|
+
mapping :customer, email: 'shipping_address_email'
|
69
|
+
|
70
|
+
def initialize(order, account, options = {})
|
71
|
+
super
|
72
|
+
@shared_secret = options[:credential2]
|
73
|
+
@order = order
|
74
|
+
|
75
|
+
add_field('platform_type', application_id)
|
76
|
+
add_field('test_mode', test?.to_s)
|
77
|
+
end
|
78
|
+
|
79
|
+
def notify_url(url)
|
80
|
+
url = append_order_query_param(url)
|
81
|
+
add_field('merchant_push_uri', url)
|
82
|
+
end
|
83
|
+
|
84
|
+
def return_url(url)
|
85
|
+
url = append_order_query_param(url)
|
86
|
+
add_field('merchant_confirmation_uri', url)
|
87
|
+
end
|
88
|
+
|
89
|
+
def line_item(item)
|
90
|
+
@line_items ||= []
|
91
|
+
@line_items << item
|
92
|
+
|
93
|
+
i = @line_items.size - 1
|
94
|
+
|
95
|
+
add_field("cart_item-#{i}_type", type_for(item))
|
96
|
+
add_field("cart_item-#{i}_reference", item.fetch(:reference, ''))
|
97
|
+
add_field("cart_item-#{i}_name", item.fetch(:name, ''))
|
98
|
+
add_field("cart_item-#{i}_quantity", item.fetch(:quantity, ''))
|
99
|
+
add_field("cart_item-#{i}_unit_price", tax_included_unit_price(item)).to_s
|
100
|
+
add_field("cart_item-#{i}_discount_rate", item.fetch(:discount_rate, ''))
|
101
|
+
add_field("cart_item-#{i}_tax_rate", tax_rate_for(item)).to_s
|
102
|
+
|
103
|
+
@fields
|
104
|
+
end
|
105
|
+
|
106
|
+
def billing_address(billing_fields)
|
107
|
+
country = billing_fields[:country]
|
108
|
+
|
109
|
+
add_field('purchase_country', country)
|
110
|
+
add_field('locale', guess_locale_based_on_country(country))
|
111
|
+
end
|
112
|
+
|
113
|
+
def shipping_address(shipping_fields)
|
114
|
+
add_field('shipping_address_given_name', shipping_fields[:first_name])
|
115
|
+
add_field('shipping_address_family_name', shipping_fields[:last_name])
|
116
|
+
|
117
|
+
street_address = [shipping_fields[:address1], shipping_fields[:address2]].compact.join(', ')
|
118
|
+
add_field('shipping_address_street_address', street_address)
|
119
|
+
|
120
|
+
add_field('shipping_address_postal_code', shipping_fields[:zip])
|
121
|
+
add_field('shipping_address_city', shipping_fields[:city])
|
122
|
+
add_field('shipping_address_country', shipping_fields[:country])
|
123
|
+
add_field('shipping_address_phone', shipping_fields[:phone])
|
124
|
+
end
|
125
|
+
|
126
|
+
def form_fields
|
127
|
+
sign_fields
|
128
|
+
|
129
|
+
super
|
130
|
+
end
|
131
|
+
|
132
|
+
def sign_fields
|
133
|
+
merchant_digest = Klarna.sign(@fields, @line_items, @shared_secret)
|
134
|
+
add_field('merchant_digest', merchant_digest)
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def type_for(item)
|
140
|
+
case item.fetch(:type, '')
|
141
|
+
when 'shipping'
|
142
|
+
'shipping_fee'
|
143
|
+
when 'line item'
|
144
|
+
'physical'
|
145
|
+
when 'discount'
|
146
|
+
'discount'
|
147
|
+
else
|
148
|
+
raise StandardError, "Unable to determine type for item #{item.to_yaml}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def append_order_query_param(url)
|
153
|
+
u = URI.parse(url)
|
154
|
+
params = Rack::Utils.parse_nested_query(u.query)
|
155
|
+
params["order"] = @order
|
156
|
+
u.query = params.to_query
|
157
|
+
|
158
|
+
u.to_s
|
159
|
+
end
|
160
|
+
|
161
|
+
def guess_locale_based_on_country(country_code)
|
162
|
+
case country_code
|
163
|
+
when /no/i
|
164
|
+
"nb-no"
|
165
|
+
when /fi/i
|
166
|
+
"fi-fi"
|
167
|
+
when /se/i
|
168
|
+
"sv-se"
|
169
|
+
else
|
170
|
+
"sv-se"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def tax_included_unit_price(item)
|
175
|
+
item.fetch(:unit_price, '').to_i + item.fetch(:tax_amount, '').to_i
|
176
|
+
end
|
177
|
+
|
178
|
+
def tax_rate_for(item)
|
179
|
+
subtotal_price = item.fetch(:unit_price, 0).to_f * item.fetch(:quantity, 0).to_i
|
180
|
+
tax_amount = item.fetch(:tax_amount, 0).to_f
|
181
|
+
|
182
|
+
if subtotal_price > 0
|
183
|
+
tax_rate = tax_amount / subtotal_price
|
184
|
+
tax_rate = tax_rate.round(4)
|
185
|
+
|
186
|
+
percentage_to_two_decimal_precision_whole_number(tax_rate)
|
187
|
+
else
|
188
|
+
0
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def percentage_to_two_decimal_precision_whole_number(percentage)
|
193
|
+
(percentage * 10000).to_i
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class Notification < OffsitePayments::Notification
|
198
|
+
def initialize(post, options = {})
|
199
|
+
super
|
200
|
+
@shared_secret = @options[:credential2]
|
201
|
+
end
|
202
|
+
|
203
|
+
def complete?
|
204
|
+
status == 'Completed'
|
205
|
+
end
|
206
|
+
|
207
|
+
def item_id
|
208
|
+
order
|
209
|
+
end
|
210
|
+
|
211
|
+
def transaction_id
|
212
|
+
params["reference"]
|
213
|
+
end
|
214
|
+
|
215
|
+
def received_at
|
216
|
+
params["completed_at"]
|
217
|
+
end
|
218
|
+
|
219
|
+
def payer_email
|
220
|
+
params["billing_address"]["email"]
|
221
|
+
end
|
222
|
+
|
223
|
+
def receiver_email
|
224
|
+
params["shipping_address"]["email"]
|
225
|
+
end
|
226
|
+
|
227
|
+
def currency
|
228
|
+
params["purchase_currency"].upcase
|
229
|
+
end
|
230
|
+
|
231
|
+
def gross
|
232
|
+
amount = Float(gross_cents) / 100
|
233
|
+
sprintf("%.2f", amount)
|
234
|
+
end
|
235
|
+
|
236
|
+
def gross_cents
|
237
|
+
params["cart"]["total_price_including_tax"]
|
238
|
+
end
|
239
|
+
|
240
|
+
def status
|
241
|
+
case params['status']
|
242
|
+
when 'checkout_complete'
|
243
|
+
'Completed'
|
244
|
+
else
|
245
|
+
params['status']
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def acknowledge(authcode = nil)
|
250
|
+
Verifier.new(@options[:authorization_header], @raw, @shared_secret).verify
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
def order
|
256
|
+
query = Rack::Utils.parse_nested_query(@options[:query_string])
|
257
|
+
query["order"]
|
258
|
+
end
|
259
|
+
|
260
|
+
def parse(post)
|
261
|
+
@raw = post.to_s
|
262
|
+
@params = JSON.parse(post)
|
263
|
+
end
|
264
|
+
|
265
|
+
class Verifier
|
266
|
+
attr_reader :header, :payload, :digest, :shared_secret
|
267
|
+
def initialize(header, payload, shared_secret)
|
268
|
+
@header, @payload, @shared_secret = header, payload, shared_secret
|
269
|
+
|
270
|
+
@digest = extract_digest
|
271
|
+
end
|
272
|
+
|
273
|
+
def verify
|
274
|
+
digest_matches?
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
|
279
|
+
def extract_digest
|
280
|
+
match = header.match(/^Klarna (?<digest>.+)$/)
|
281
|
+
match && match[:digest]
|
282
|
+
end
|
283
|
+
|
284
|
+
def digest_matches?
|
285
|
+
Klarna.digest(payload, shared_secret) == digest
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|