swisspay 0.2.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 +92 -0
- data/Rakefile +24 -0
- data/app/assets/config/swisspay_manifest.js +2 -0
- data/app/assets/javascripts/swisspay/application.js +13 -0
- data/app/assets/stylesheets/swisspay/application.css +15 -0
- data/app/controllers/swisspay/application_controller.rb +5 -0
- data/app/controllers/swisspay/paypals_controller.rb +89 -0
- data/app/controllers/swisspay/postfinances_controller.rb +35 -0
- data/app/controllers/swisspay/saferpays_controller.rb +25 -0
- data/app/controllers/swisspay/stripes_controller.rb +34 -0
- data/app/helpers/swisspay/view_helpers.rb +10 -0
- data/app/jobs/swisspay/application_job.rb +4 -0
- data/app/mailers/swisspay/application_mailer.rb +6 -0
- data/app/models/swisspay/application_record.rb +5 -0
- data/app/views/swisspay/shop/_payment.html.erb +15 -0
- data/app/views/swisspay/shop/_payment_paypal.html.erb +47 -0
- data/app/views/swisspay/shop/_payment_postfinance.html.erb +12 -0
- data/app/views/swisspay/shop/_payment_saferpay.html.erb +6 -0
- data/app/views/swisspay/shop/_payment_stripe.html.erb +55 -0
- data/config/routes.rb +16 -0
- data/lib/swisspay.rb +26 -0
- data/lib/swisspay/configuration.rb +34 -0
- data/lib/swisspay/engine.rb +9 -0
- data/lib/swisspay/postfinance.rb +48 -0
- data/lib/swisspay/saferpay.rb +80 -0
- data/lib/swisspay/version.rb +3 -0
- data/lib/tasks/swisspay_tasks.rake +4 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1503403d48175f3f78a716d205373db04e20a892128fd1a020d5de2d5e726e1e
|
4
|
+
data.tar.gz: edf30f7e5be4e8f7e7bc802f08a21c556c6567e123b2c05310e74bd2cdbb5f64
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: df82a8c224bbf266f0c61273950f5398f3fe678c5858027b43af57d61ab2b4e1792704b4cdea0bdbbfcb113043b0f2b657c0e741728ed333884e3dbbfd0b97ed
|
7
|
+
data.tar.gz: ac6070a77da9e090ca31300176cf640eb3e0f48da97ee983cf007f24f511566297cecba3da45c28504541380d19f849fb9e7b57bd6c7f05aae2645871b2d2d1c
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Lukas_Skywalker
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Swisspay
|
2
|
+
|
3
|
+
Rails integration for Swiss payment service providers.
|
4
|
+
|
5
|
+
Swisspay is a gem that helps you accept payments using various Payment Processing Providers (PSPs). At the moment, it includes support vor Paypal, Stripe and Postfinance (card and e-finance) and SIX Payment Services (Saferpay) payments.
|
6
|
+
|
7
|
+
It features a simple integration but stays flexible to fit your needs.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'swisspay'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
```bash
|
18
|
+
$ bundle
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Embed the payment partial on your site:
|
24
|
+
|
25
|
+
```erb
|
26
|
+
<%= swisspay_payment_form(@order.id, 200, {
|
27
|
+
description: @order.id,
|
28
|
+
buyer: {
|
29
|
+
name: current_user.full_name,
|
30
|
+
email: current_user.email,
|
31
|
+
street: current_user.street,
|
32
|
+
country: 'Schweiz',
|
33
|
+
zip: current_user.zip,
|
34
|
+
city: current_user.city
|
35
|
+
},
|
36
|
+
image: asset_path('my_logo.jpg')
|
37
|
+
}) %>
|
38
|
+
```
|
39
|
+
|
40
|
+
The first two parameters, `identifier` and `amount` are required. The amount must be in **Rappen**. The options are all optional.
|
41
|
+
|
42
|
+
You can use the `identifier` parameter to keep track of the payment. The parameter you pass in here will be returned to you in the callbacks described below (still called `identifier`).
|
43
|
+
|
44
|
+
Define after payment actions in the initializer, e.g. `config/initializers/swisspay.rb`:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
Swisspay.configure do |config|
|
48
|
+
config.payment_success = -> (controller, app, identifier) do
|
49
|
+
order = Order.find(identifier)
|
50
|
+
order.update(status: :paid)
|
51
|
+
|
52
|
+
controller.redirect_to app.order_confirmation_path
|
53
|
+
end
|
54
|
+
|
55
|
+
config.payment_error = -> (controller, app, identifier, error) do
|
56
|
+
Rails.logger.error "Payment error: #{error}"
|
57
|
+
|
58
|
+
controller.redirect_to app.checkout_error_path, alert: error
|
59
|
+
end
|
60
|
+
|
61
|
+
config.vendor_name = 'TRM Schweiz'
|
62
|
+
|
63
|
+
config.stripe = {
|
64
|
+
secret_key: "sk_test_78nv4zna03vnttab8nw93nsv",
|
65
|
+
public_key: "pk_test_nsven89s4nv3497vts9svfgg"
|
66
|
+
}
|
67
|
+
|
68
|
+
config.postfinance = {
|
69
|
+
pspid: 'mytestPSPID',
|
70
|
+
sha_in_pswd: 'dkjfhiurnviyfhjk'
|
71
|
+
}
|
72
|
+
|
73
|
+
config.saferpay = {
|
74
|
+
customer_id: '123456',
|
75
|
+
terminal_id: '87654321',
|
76
|
+
api_user: 'API_123456_12345678',
|
77
|
+
api_pass: 'a8379a37v9a37o9yv73wvc2r9'
|
78
|
+
}
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
## License
|
83
|
+
|
84
|
+
All rights reserved.
|
85
|
+
|
86
|
+
## Terms of Service
|
87
|
+
|
88
|
+
Usage of this gem is bound to the following TOS.
|
89
|
+
|
90
|
+
1. Licences are granted for a single application. One application may be installed on multiple machines, for instance in a development setup and multistage / CI deploy.
|
91
|
+
2. Licences are granted for an unlimited time.
|
92
|
+
3. This gem's source code must not be published or modified.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Swisspay'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
load 'rails/tasks/statistics.rake'
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
require 'bundler/gem_tasks'
|
24
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'paypal-sdk-rest'
|
2
|
+
|
3
|
+
module Swisspay
|
4
|
+
class PaypalsController < ApplicationController
|
5
|
+
protect_from_forgery :except => [:create] #Otherwise the request from PayPal wouldn't make it to the controller
|
6
|
+
before_action :load_session
|
7
|
+
|
8
|
+
include PayPal::SDK::REST
|
9
|
+
|
10
|
+
def create
|
11
|
+
PayPal::SDK.configure(
|
12
|
+
mode: "sandbox",
|
13
|
+
client_id: Swisspay.configuration.paypal[:api_id],
|
14
|
+
client_secret: Swisspay.configuration.paypal[:api_secret],
|
15
|
+
ssl_options: { } )
|
16
|
+
|
17
|
+
|
18
|
+
case params[:step]
|
19
|
+
when 'create_payment'
|
20
|
+
create_payment
|
21
|
+
when 'execute_payment'
|
22
|
+
execute_payment
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def show
|
27
|
+
if params[:action] == 'accept'
|
28
|
+
Swisspay.configuration.payment_success.call(self, main_app, @identifier, :paypal)
|
29
|
+
elsif params[:action] == 'cancel'
|
30
|
+
Swisspay.configuration.payment_error(self, main_app, @identifier, :paypal, :cancel)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def create_payment
|
37
|
+
# send a create payment request to the API
|
38
|
+
payment = Payment.new({
|
39
|
+
intent: 'sale',
|
40
|
+
payer: {
|
41
|
+
payment_method: 'paypal'
|
42
|
+
},
|
43
|
+
transactions: [{
|
44
|
+
amount: {
|
45
|
+
currency: 'CHF',
|
46
|
+
total: (@amount / 100.0)
|
47
|
+
},
|
48
|
+
invoice_number: @identifier
|
49
|
+
}],
|
50
|
+
# PayPal does not automatically call these URLs. PayPal invokes your onAuthorize function
|
51
|
+
# when the buyer authorizes the payment. At this point you can choose to redirect the buyer.
|
52
|
+
redirect_urls: {
|
53
|
+
return_url: Swisspay::Engine.routes.url_helpers.paypal_url(host: request.base_url, action: :return),
|
54
|
+
cancel_url: Swisspay::Engine.routes.url_helpers.paypal_url(host: request.base_url, action: :cancel)
|
55
|
+
}
|
56
|
+
})
|
57
|
+
if payment.create
|
58
|
+
# send payment id back to js script
|
59
|
+
render json: { paymentID: payment.id }
|
60
|
+
else
|
61
|
+
render json: { error: payment.error }, status: 400
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def execute_payment
|
66
|
+
payment_id = params[:paymentID]
|
67
|
+
payer_id = params[:payerID]
|
68
|
+
payment = Payment.find(payment_id)
|
69
|
+
remote_identifier = payment.transactions.first.invoice_number
|
70
|
+
remote_amount = payment.transactions.first.amount.total
|
71
|
+
|
72
|
+
raise StandardError, 'AMOUNT MISMATCH' if (@amount / 100.to_f).to_f != remote_amount.to_f
|
73
|
+
raise StandardError, 'IDENTIFIER MISMATCH' if @identifier != remote_identifier
|
74
|
+
|
75
|
+
if payment.execute(payer_id: payer_id)
|
76
|
+
Swisspay.configuration.payment_success.call(self, main_app, @identifier, :paypal)
|
77
|
+
else
|
78
|
+
Swisspay.configuration.payment_error.call(self, main_app, @identifier, :paypal, payment.error)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def load_session
|
85
|
+
@amount = session['swisspay']['amount']
|
86
|
+
@identifier = session['swisspay']['identifier']
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Swisspay
|
2
|
+
class PostfinancesController < ApplicationController
|
3
|
+
before_action :load_session
|
4
|
+
|
5
|
+
def accept
|
6
|
+
valid = Swisspay::Postfinance.check_signature(params.except(:action, :controller))
|
7
|
+
|
8
|
+
Rails.logger.error "SIGNATURE DOES NOT MATCH FINGERPRINT" if !valid
|
9
|
+
|
10
|
+
raise StandardError, 'AMOUNT MISMATCH' if (@amount / 100.to_f).to_f != params['amount'].to_f
|
11
|
+
raise StandardError, 'IDENTIFIER MISMATCH' if @identifier != params[:orderID]
|
12
|
+
|
13
|
+
Swisspay.configuration.payment_success.call(self, main_app, @identifier, :postfinance)
|
14
|
+
end
|
15
|
+
|
16
|
+
def cancel
|
17
|
+
Swisspay.configuration.payment_error.call(self, main_app, @identifier, :postfinance, :user_cancelled)
|
18
|
+
end
|
19
|
+
|
20
|
+
def decline
|
21
|
+
Swisspay.configuration.payment_error.call(self, main_app, @identifier, :postfinance, :card_declined)
|
22
|
+
end
|
23
|
+
|
24
|
+
def exception
|
25
|
+
Swisspay.configuration.payment_error.call(self, main_app, @identifier, :postfinance, :server_error)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def load_session
|
31
|
+
@amount = session['swisspay']['amount']
|
32
|
+
@identifier = session['swisspay']['identifier']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Swisspay
|
2
|
+
class SaferpaysController < ApplicationController
|
3
|
+
before_action :load_session
|
4
|
+
|
5
|
+
def success
|
6
|
+
token = session['swisspay']['token']
|
7
|
+
identifier = session['swisspay']['identifier']
|
8
|
+
valid = Swisspay::Saferpay.check_payment(identifier, token)
|
9
|
+
Rails.logger.error "NOT PAID" if !valid
|
10
|
+
|
11
|
+
Swisspay.configuration.payment_success.call(self, main_app, @identifier, :saferpay)
|
12
|
+
end
|
13
|
+
|
14
|
+
def fail
|
15
|
+
Swisspay.configuration.payment_error.call(self, main_app, @identifier, :saferpay, :fail)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def load_session
|
21
|
+
@amount = session['swisspay']['amount']
|
22
|
+
@identifier = session['swisspay']['identifier']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Swisspay
|
2
|
+
class StripesController < ApplicationController
|
3
|
+
protect_from_forgery except: [:create]
|
4
|
+
before_action :load_session
|
5
|
+
|
6
|
+
def create
|
7
|
+
Stripe.api_key = Swisspay.configuration.stripe[:secret_key]
|
8
|
+
|
9
|
+
customer = Stripe::Customer.create(
|
10
|
+
email: params[:stripeEmail],
|
11
|
+
source: params[:stripeToken]
|
12
|
+
)
|
13
|
+
|
14
|
+
charge = Stripe::Charge.create(
|
15
|
+
customer: customer.id,
|
16
|
+
amount: @amount,
|
17
|
+
description: 'Bestellung ' + @identifier.to_s,
|
18
|
+
currency: 'chf'
|
19
|
+
)
|
20
|
+
|
21
|
+
Swisspay.configuration.payment_success.call(self, main_app, @identifier, :stripe)
|
22
|
+
|
23
|
+
rescue Stripe::CardError => e
|
24
|
+
Swisspay.configuration.payment_error(self, main_app, @identifier, :stripe, e.message)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def load_session
|
30
|
+
@amount = session['swisspay']['amount']
|
31
|
+
@identifier = session['swisspay']['identifier']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Swisspay
|
2
|
+
module ViewHelpers
|
3
|
+
def swisspay_payment_form(identifier, amount, options = {})
|
4
|
+
identifier = identifier.to_s + Swisspay::order_id_suffix
|
5
|
+
session['swisspay'] = { 'amount' => amount, 'identifier' => identifier }
|
6
|
+
render partial: 'swisspay/shop/payment',
|
7
|
+
locals: { identifier: identifier, amount: amount, base_url: request.base_url, options: options }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% if Swisspay.configuration.stripe? %>
|
2
|
+
<%= render partial: 'swisspay/shop/payment_stripe', locals: { identifier: identifier, amount: amount, options: options } %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% if Swisspay.configuration.paypal? %>
|
6
|
+
<%= render partial: 'swisspay/shop/payment_paypal', locals: { identifier: identifier, amount: amount, options: options } %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<% if Swisspay.configuration.postfinance? %>
|
10
|
+
<%= render partial: 'swisspay/shop/payment_postfinance', locals: { base_url: base_url, identifier: identifier, amount: amount, options: options } %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<% if Swisspay.configuration.saferpay? %>
|
14
|
+
<%= render partial: 'swisspay/shop/payment_saferpay', locals: { base_url: base_url, identifier: identifier, amount: amount, options: options } %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
|
2
|
+
|
3
|
+
<div id="paypal-button"></div>
|
4
|
+
|
5
|
+
<script>
|
6
|
+
paypal.Button.render({
|
7
|
+
env: 'sandbox', // Optional: specify 'sandbox' environment
|
8
|
+
locale: 'de_DE',
|
9
|
+
commit: true,
|
10
|
+
|
11
|
+
style: {
|
12
|
+
size: 'small',
|
13
|
+
color: 'blue', // gold, blue, silver
|
14
|
+
shape: 'rect', // pill, rect
|
15
|
+
label: 'checkout'
|
16
|
+
},
|
17
|
+
|
18
|
+
payment: function(resolve, reject) {
|
19
|
+
// call Rails server
|
20
|
+
var CREATE_PAYMENT_URL = '<%= Swisspay::Engine.routes.url_helpers.paypal_path(step: 'create_payment').html_safe %>';
|
21
|
+
|
22
|
+
// passes the paymentID from the JSON response to the checkout.js script
|
23
|
+
// The Express Checkout flow is launched in a lightbox on your page and gets
|
24
|
+
// the buyer's approval for payment.
|
25
|
+
return paypal.request.post(CREATE_PAYMENT_URL)
|
26
|
+
.then(function(data) { resolve(data.paymentID); })
|
27
|
+
.catch(function(err) { reject(err); });
|
28
|
+
},
|
29
|
+
|
30
|
+
onAuthorize: function(data, actions) {
|
31
|
+
// Note: you can display a confirmation page before executing
|
32
|
+
|
33
|
+
var EXECUTE_PAYMENT_URL = '<%= Swisspay::Engine.routes.url_helpers.paypal_path(step: 'execute_payment').html_safe %>';
|
34
|
+
|
35
|
+
// When the buyer approves the payment, the checkout.js script calls your onAuthorize call back.
|
36
|
+
return paypal.request.post(EXECUTE_PAYMENT_URL,
|
37
|
+
{ paymentID: data.paymentID, payerID: data.payerID })
|
38
|
+
|
39
|
+
.then(function(data) { console.log(data); console.log(this); })
|
40
|
+
.catch(function(err) { console.log(err); });
|
41
|
+
},
|
42
|
+
|
43
|
+
onCancel: function(data, actions) {
|
44
|
+
return actions.redirect();
|
45
|
+
}
|
46
|
+
}, '#paypal-button');
|
47
|
+
</script>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= form_tag postfinance_payment_processing_url do %>
|
2
|
+
|
3
|
+
<% form_data = Swisspay::Postfinance.form_data(base_url, identifier, amount, options) %>
|
4
|
+
|
5
|
+
<% form_data.each do |name, value| %>
|
6
|
+
<%= hidden_field_tag(name, value) %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<%= hidden_field_tag(:SHASIGN, Swisspay::Postfinance.generate_signature(form_data)) %>
|
10
|
+
|
11
|
+
<%= submit_tag t('payment.postcard'), class: 'button' %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<% url, token = Swisspay::Saferpay.payment_url(base_url, identifier, amount, options) %>
|
2
|
+
<% session['swisspay']['token'] = token %>
|
3
|
+
|
4
|
+
<%= form_tag url, method: :get, enforce_utf8: false do %>
|
5
|
+
<%= submit_tag t('payment.saferpay'), class: 'button', name: nil %>
|
6
|
+
<% end %>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
<%= form_tag Swisspay::Engine.routes.url_helpers.stripe_path(identifier: identifier) do %>
|
2
|
+
|
3
|
+
<script src="https://checkout.stripe.com/checkout.js"></script>
|
4
|
+
|
5
|
+
<%= submit_tag t('payment.creditcard'), class: 'button', id: 'stripe-button' %>
|
6
|
+
|
7
|
+
<script>
|
8
|
+
var handler = StripeCheckout.configure({
|
9
|
+
key: '<%= Swisspay.configuration.stripe[:public_key] %>',
|
10
|
+
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
|
11
|
+
locale: 'auto',
|
12
|
+
token: function(token) {
|
13
|
+
$.ajax({
|
14
|
+
type: 'POST',
|
15
|
+
url: '<%= Swisspay::Engine.routes.url_helpers.stripe_path(identifier: identifier) %>',
|
16
|
+
data: {
|
17
|
+
stripeEmail: token.email,
|
18
|
+
stripeToken: token.id
|
19
|
+
},
|
20
|
+
success: function(response) {
|
21
|
+
console.log('successful payment: ', response);
|
22
|
+
},
|
23
|
+
error: function(response) {
|
24
|
+
console.log('error payment: ', response);
|
25
|
+
}
|
26
|
+
})
|
27
|
+
}
|
28
|
+
});
|
29
|
+
|
30
|
+
document.getElementById('stripe-button').addEventListener('click', function(e) {
|
31
|
+
// Open Checkout with further options:
|
32
|
+
handler.open({
|
33
|
+
image: '<%= options[:image] %>',
|
34
|
+
name: '<%= Swisspay.configuration.vendor_name %>',
|
35
|
+
description: '<%= options[:description].to_s %>',
|
36
|
+
amount: <%= amount %>,
|
37
|
+
locale: 'auto',
|
38
|
+
//zipCode: false,
|
39
|
+
//billingAddress: false,
|
40
|
+
currency: 'CHF',
|
41
|
+
//panelLabel: '<%= t('stripe.popup_button_label') %>',
|
42
|
+
//shippingAddress: false,
|
43
|
+
email: '<%= options[:buyer][:email] %>',
|
44
|
+
//allowRememberMe: true,
|
45
|
+
//bitcoin: false
|
46
|
+
});
|
47
|
+
e.preventDefault();
|
48
|
+
});
|
49
|
+
|
50
|
+
// Close Checkout on page navigation:
|
51
|
+
window.addEventListener('popstate', function() {
|
52
|
+
handler.close();
|
53
|
+
});
|
54
|
+
</script>
|
55
|
+
<% end %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Swisspay::Engine.routes.draw do
|
2
|
+
resource :paypal, only: [:create, :show]
|
3
|
+
resource :stripe, only: [:create]
|
4
|
+
resource :postfinance, only: [] do
|
5
|
+
get :accept
|
6
|
+
get :cancel
|
7
|
+
get :decline
|
8
|
+
get :exception
|
9
|
+
end
|
10
|
+
|
11
|
+
resource :saferpay, only: [] do
|
12
|
+
get :success
|
13
|
+
get :fail
|
14
|
+
post :start
|
15
|
+
end
|
16
|
+
end
|
data/lib/swisspay.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "swisspay/engine"
|
2
|
+
require 'swisspay/configuration'
|
3
|
+
require 'swisspay/postfinance'
|
4
|
+
require 'swisspay/saferpay'
|
5
|
+
|
6
|
+
module Swisspay
|
7
|
+
class << self
|
8
|
+
attr_accessor :configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.configuration
|
12
|
+
@configuration ||= Configuration.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure
|
16
|
+
yield(configuration)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.order_id_suffix
|
20
|
+
if Rails.env.production?
|
21
|
+
''
|
22
|
+
else
|
23
|
+
"_TEST_" + (100 + rand(899)).to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Swisspay
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :payment_success, :payment_error,
|
4
|
+
:description, :vendor_name,
|
5
|
+
:stripe, :postfinance, :paypal, :saferpay
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@payment_success = -> { }
|
9
|
+
@payment_error = -> { }
|
10
|
+
@description = ''
|
11
|
+
@vendor_name = ''
|
12
|
+
@stripe = {}
|
13
|
+
@postfinance = {}
|
14
|
+
@paypal = {}
|
15
|
+
@saferpay = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def stripe?
|
19
|
+
@stripe != {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def paypal?
|
23
|
+
@paypal != {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def postfinance?
|
27
|
+
@postfinance != {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def saferpay?
|
31
|
+
@saferpay != {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Swisspay
|
2
|
+
class Postfinance
|
3
|
+
def self.form_data(base_url, identifier, amount, options)
|
4
|
+
{
|
5
|
+
ACCEPTURL: Swisspay::Engine.routes.url_helpers.accept_postfinance_url(host: base_url, identifier: identifier),
|
6
|
+
AMOUNT: amount,
|
7
|
+
CANCELURL: Swisspay::Engine.routes.url_helpers.cancel_postfinance_url(host: base_url, identifier: identifier),
|
8
|
+
CN: options[:buyer][:name],
|
9
|
+
CURRENCY: 'CHF',
|
10
|
+
DECLINEURL: Swisspay::Engine.routes.url_helpers.decline_postfinance_url(host: base_url, identifier: identifier),
|
11
|
+
EMAIL: options[:buyer][:email],
|
12
|
+
EXCEPTIONURL: Swisspay::Engine.routes.url_helpers.exception_postfinance_url(host: base_url, identifier: identifier),
|
13
|
+
LANGUAGE: 'de_DE',
|
14
|
+
ORDERID: identifier,
|
15
|
+
OWNERADDRESS: options[:buyer][:street],
|
16
|
+
OWNERCTY: options[:buyer][:country],
|
17
|
+
#OWNERTELNO: '031 331 83 83',
|
18
|
+
OWNERTOWN: options[:buyer][:city],
|
19
|
+
OWNERZIP: options[:buyer][:zip],
|
20
|
+
PSPID: Swisspay.configuration.postfinance[:pspid]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.generate_signature(form_data)
|
25
|
+
self.sha_for(form_data)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.check_signature(params)
|
29
|
+
upper = []
|
30
|
+
params.each{|k,v| upper.push([k.upcase, v])}
|
31
|
+
up_sorted = upper.sort_by{|k,v| k}
|
32
|
+
shasig = up_sorted.select { |k,v| k == "SHASIGN" }.first.last.downcase
|
33
|
+
other_params = up_sorted.reject { |k,v| k == "SHASIGN" || v == "" }
|
34
|
+
calc_sig = self.sha_for(other_params)
|
35
|
+
shasig == calc_sig
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.sha_for(data)
|
41
|
+
secret_sig = Swisspay.configuration.postfinance[:sha_in_pswd]
|
42
|
+
string = data.reject { |k,v| v.nil? }.map { |k, v| "#{k}=#{v}" }.join(secret_sig)
|
43
|
+
string << secret_sig
|
44
|
+
digest = Digest::SHA1.hexdigest(string)
|
45
|
+
digest
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Swisspay
|
6
|
+
class Saferpay
|
7
|
+
API_BASE = 'https://test.saferpay.com/api'
|
8
|
+
PAYMENT_PAGE_INIT = '/Payment/v1/PaymentPage/Initialize'
|
9
|
+
PAYMENT_PAGE_ASSERT = '/Payment/v1/PaymentPage/Assert'
|
10
|
+
|
11
|
+
def self.payment_url(base_url, identifier, amount, options)
|
12
|
+
response = post(API_BASE + PAYMENT_PAGE_INIT, payment_page_init_data(base_url, identifier, amount, options))
|
13
|
+
data = JSON.parse(response.delete("\\")[1..-2])
|
14
|
+
token = data['Token']
|
15
|
+
redirect_url = data['RedirectUrl']
|
16
|
+
return redirect_url, token
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.check_payment(identifier, token)
|
20
|
+
response = post(API_BASE + PAYMENT_PAGE_ASSERT, payment_page_assert_data(identifier, token))
|
21
|
+
data = JSON.parse(response.delete("\\")[1..-2])
|
22
|
+
data["Transaction"]["Status"] == 'AUTHORIZED'
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def self.payment_page_init_data(base_url, identifier, amount, options)
|
28
|
+
{
|
29
|
+
"RequestHeader": {
|
30
|
+
"SpecVersion": "1.6",
|
31
|
+
"CustomerId": Swisspay.configuration.saferpay[:customer_id],
|
32
|
+
"RequestId": identifier,
|
33
|
+
"RetryIndicator": 0
|
34
|
+
},
|
35
|
+
"TerminalId": Swisspay.configuration.saferpay[:terminal_id],
|
36
|
+
"Payment": {
|
37
|
+
"Amount": {
|
38
|
+
"Value": amount,
|
39
|
+
"CurrencyCode": "CHF"
|
40
|
+
},
|
41
|
+
"OrderId": identifier,
|
42
|
+
"Description": options[:description]
|
43
|
+
},
|
44
|
+
"ReturnUrls": {
|
45
|
+
"Success": Swisspay::Engine.routes.url_helpers.success_saferpay_url(host: base_url),
|
46
|
+
"Fail": Swisspay::Engine.routes.url_helpers.fail_saferpay_url(host: base_url)
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.payment_page_assert_data(identifier, token)
|
52
|
+
{
|
53
|
+
"RequestHeader": {
|
54
|
+
"SpecVersion": "1.6",
|
55
|
+
"CustomerId": Swisspay.configuration.saferpay[:customer_id],
|
56
|
+
"RequestId": identifier,
|
57
|
+
"RetryIndicator": 0
|
58
|
+
},
|
59
|
+
"Token": token
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.post(url, data)
|
64
|
+
uri = URI(url)
|
65
|
+
api_user = Swisspay.configuration.saferpay[:api_user]
|
66
|
+
api_pass = Swisspay.configuration.saferpay[:api_pass]
|
67
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
68
|
+
http.use_ssl = true
|
69
|
+
http.set_debug_output($stdout)
|
70
|
+
req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json; charset=utf-8', 'Accept' => 'application/json')
|
71
|
+
req.body = data.to_json
|
72
|
+
req.basic_auth api_user, api_pass
|
73
|
+
res = http.request(req)
|
74
|
+
res.body.inspect
|
75
|
+
rescue => e
|
76
|
+
puts "failed #{e.inspect}"
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swisspay
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lukas_Skywalker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: paypal-sdk-rest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.0
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1.6'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.6.0
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.6'
|
47
|
+
description: Easily accept payments from different payment providers such as Stripe,
|
48
|
+
Paypal, Postfinance and SIX.
|
49
|
+
email:
|
50
|
+
- lukas.diener@hotmail.com
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- MIT-LICENSE
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- app/assets/config/swisspay_manifest.js
|
59
|
+
- app/assets/javascripts/swisspay/application.js
|
60
|
+
- app/assets/stylesheets/swisspay/application.css
|
61
|
+
- app/controllers/swisspay/application_controller.rb
|
62
|
+
- app/controllers/swisspay/paypals_controller.rb
|
63
|
+
- app/controllers/swisspay/postfinances_controller.rb
|
64
|
+
- app/controllers/swisspay/saferpays_controller.rb
|
65
|
+
- app/controllers/swisspay/stripes_controller.rb
|
66
|
+
- app/helpers/swisspay/view_helpers.rb
|
67
|
+
- app/jobs/swisspay/application_job.rb
|
68
|
+
- app/mailers/swisspay/application_mailer.rb
|
69
|
+
- app/models/swisspay/application_record.rb
|
70
|
+
- app/views/swisspay/shop/_payment.html.erb
|
71
|
+
- app/views/swisspay/shop/_payment_paypal.html.erb
|
72
|
+
- app/views/swisspay/shop/_payment_postfinance.html.erb
|
73
|
+
- app/views/swisspay/shop/_payment_saferpay.html.erb
|
74
|
+
- app/views/swisspay/shop/_payment_stripe.html.erb
|
75
|
+
- config/routes.rb
|
76
|
+
- lib/swisspay.rb
|
77
|
+
- lib/swisspay/configuration.rb
|
78
|
+
- lib/swisspay/engine.rb
|
79
|
+
- lib/swisspay/postfinance.rb
|
80
|
+
- lib/swisspay/saferpay.rb
|
81
|
+
- lib/swisspay/version.rb
|
82
|
+
- lib/tasks/swisspay_tasks.rake
|
83
|
+
homepage: https://code-fabrik.ch
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata:
|
87
|
+
allowed_push_host: https://rubygems.org
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubygems_version: 3.0.6
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Swiss PSP gem
|
107
|
+
test_files: []
|