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.
@@ -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
@@ -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.
@@ -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.
@@ -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,2 @@
1
+ //= link_directory ../javascripts/swisspay .js
2
+ //= link_directory ../stylesheets/swisspay .css
@@ -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,5 @@
1
+ module Swisspay
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -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,4 @@
1
+ module Swisspay
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Swisspay
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Swisspay
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ 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 %>
@@ -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
@@ -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,9 @@
1
+ module Swisspay
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Swisspay
4
+
5
+ initializer "swisspay.view_helpers" do
6
+ ActiveSupport.on_load( :action_view ){ include Swisspay::ViewHelpers }
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,3 @@
1
+ module Swisspay
2
+ VERSION = '0.2.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :swisspay do
3
+ # # Task goes here
4
+ # 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: []