swisspay 0.2.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 +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: []
|