offsite_payments 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|