slimpay_client 0.1.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,18 @@
1
+ module SlimpayClient
2
+ # An abstract CardAlias to be inherited from.
3
+ #
4
+ # Defines API CardAlias non-semantic methods.
5
+ class Card < Resource
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ def get_one(id = 1)
12
+ url = "#{@endpoint}/cards/#{id}"
13
+ response = HTTParty.get(url, headers: options)
14
+ generate_api_methods(JSON.parse(response.body))
15
+ SlimpayClient.answer(response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module SlimpayClient
2
+ # An abstract CardAlias to be inherited from.
3
+ #
4
+ # Defines API CardAlias non-semantic methods.
5
+ class CardAlias < Resource
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ def get_one(id = 1)
12
+ url = "#{@endpoint}/card_aliases/#{id}"
13
+ response = HTTParty.get(url, headers: options)
14
+ generate_api_methods(JSON.parse(response.body))
15
+ SlimpayClient.answer(response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ module SlimpayClient
2
+ class Configuration
3
+ attr_accessor :client_id
4
+ attr_accessor :client_secret
5
+ attr_accessor :creditor_reference
6
+ attr_accessor :sandbox
7
+ attr_accessor :success_url
8
+ attr_accessor :failure_url
9
+ attr_accessor :cancel_url
10
+ attr_accessor :return_url
11
+ attr_accessor :notify_url
12
+ attr_accessor :username
13
+ attr_accessor :password
14
+
15
+ def initialize
16
+ @client_id = SlimpayClient::SANDBOX_CLIENT_ID
17
+ @client_secret = SlimpayClient::SANDBOX_SECRET_ID
18
+ @creditor_reference = SlimpayClient::SANDBOX_CREDITOR
19
+ @sandbox = true
20
+ @success_url = 'localhost:5000'
21
+ @failure_url = 'localhost:5000'
22
+ @cancel_url = 'localhost:5000'
23
+ @return_url = 'localhost:5000'
24
+ @notify_url = 'localhost:5000'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module SlimpayClient
2
+ # An abstract Creditor to be inherited from.
3
+ #
4
+ # Defines API Creditor non-semantic methods.
5
+ class Creditor < Resource
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ def get_one(reference = 1)
12
+ url = "#{@endpoint}/creditors/#{reference}"
13
+ response = HTTParty.get(url, headers: options)
14
+ generate_api_methods(JSON.parse(response.body))
15
+ SlimpayClient.answer(response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ module SlimpayClient
2
+ class DirectDebit < Resource
3
+ # Override the Resource#get_one method because the url is not the same for DirectDebits
4
+ #
5
+ def get_one(reference = 1)
6
+ url = "#{@endpoint}/#{@resource_name}/#{reference}"
7
+ response = HTTParty.get(url, headers: options)
8
+ generate_api_methods(JSON.parse(response.body))
9
+ SlimpayClient.answer(response)
10
+ end
11
+
12
+ # Alias method for create_direct_debits
13
+ # ===== Arguments
14
+ # debit_hash: (Hash) Your payment informations. See API DirectDebit documentation for details.
15
+ #
16
+ # /!\ Amount as to be rounded to maximum 2 numbers after comma.
17
+ # If not you'll receive an error : { "code" : 100, "message" : "Internal error : Rounding necessary" }
18
+ def make_payment(debit_hash = default_debit_hash)
19
+ self.create_direct_debits(debit_hash)
20
+ end
21
+
22
+ private
23
+
24
+ def default_debit_hash
25
+ {
26
+ creditor: {
27
+ reference: @creditor_reference
28
+ },
29
+ mandate: {
30
+ rum: '1'
31
+ },
32
+ amount: 100.00,
33
+ label: 'The label',
34
+ paymentReference: 'Payment 123'
35
+ }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,80 @@
1
+ module SlimpayClient
2
+ # To display SlimpayClient error messages with the HTTP code.
3
+ #
4
+ # ==== Possible API errors
5
+ # * code: 906 message: "Error : Could not find acceptable representation"
6
+ # * code: 906 message: "Error : Request method 'POST' not supported"
7
+ # * code: 906 message: "Error : Content type 'application/x-www-form-urlencoded' not supported"
8
+ # * code: 904 message: "Access denied : cannot access creditor democreditor"
9
+ # * error:"invalid_token", error_description: "Invalid access token: 1234-123456-abcdef-123456"
10
+ # * code: 205, message: "Client data are inconsistent : missing query parameters creditorReference and/or rum"
11
+ class Error < StandardError
12
+ attr_reader :message
13
+ # If the HTTP response is nil or empty returns an actual message.
14
+ def self.empty
15
+ @message = {code: 418, message: 'The answer was empty.'}
16
+ end
17
+
18
+ # Returns either formated error with its HTTP code or the raw HTTP response.
19
+ # ===== Arguments:
20
+ # http_response: (HTTParty::Response)
21
+ def initialize(http_response)
22
+ if defined?(http_response.code)
23
+ display_http_error(http_response)
24
+ else
25
+ @message = JSON.parse(http_response.body)
26
+ end
27
+ fail self, @message.to_s
28
+ end
29
+
30
+ def to_s
31
+ @message
32
+ end
33
+
34
+ private
35
+
36
+ def display_http_error(http_response)
37
+ @message = case http_response.code
38
+ when 400
39
+ bad_request(http_response)
40
+ when 401
41
+ unauthorized(http_response)
42
+ when 403
43
+ forbidden(http_response)
44
+ when 404
45
+ not_found
46
+ when 406
47
+ not_acceptable(http_response)
48
+ else
49
+ http_response
50
+ end
51
+ end
52
+
53
+ def bad_request(http_message)
54
+ {code: 400, message: "HTTP Bad Request. #{slimpay_error(http_message)}"}
55
+ end
56
+
57
+ def unauthorized(http_message)
58
+ {code: 401, message: "HTTP Unauthorized. #{slimpay_error(http_message)}"}
59
+ end
60
+
61
+ def forbidden(http_message)
62
+ {code: 403, message: "HTTP Forbidden. #{slimpay_error(http_message)}"}
63
+ end
64
+
65
+ def not_found
66
+ {code: 404, message: 'URI not found.'}
67
+ end
68
+
69
+ def not_acceptable(http_message)
70
+ {code: 406, message: "HTTP Not Acceptable. #{slimpay_error(http_message)}"}
71
+ end
72
+
73
+ def slimpay_error(http_message)
74
+ slimpay_error = http_message.is_a?(Hash) ? http_message : JSON.parse(http_message.body)
75
+ slimpay_code = slimpay_error['code']
76
+ slimpay_message = slimpay_error['message'] || slimpay_error['error_description']
77
+ "SlimpayClient #{slimpay_code} : #{slimpay_message}"
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,18 @@
1
+ module SlimpayClient
2
+ class Mandate < Resource
3
+ # POST
4
+ def revoke(id = 'mandate01')
5
+ url = "mandates/#{id}/revocation"
6
+ body_options = {}
7
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
8
+ follow_up_api(response)
9
+ end
10
+
11
+ def document(id = 'mandate01')
12
+ url = "mandates/#{id}/document"
13
+ body_options = {}
14
+ response = HTTParty.get("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
15
+ follow_up_api(response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,108 @@
1
+ module SlimpayClient
2
+ # Inherits from Resouce and thus defines its associated resource's methods.
3
+ #
4
+ # Defines shortcut methods for the create_order method with various arguments.
5
+ class Order < Resource
6
+ # Override the Resource#get_one method because the url is not the same for Orders
7
+ #
8
+ # ===== Example:
9
+ # orders = SlimpayClient::Order.new
10
+ # orders.get_one
11
+ # =>
12
+ # {"_links"=>
13
+ # {"self"=>{"href"=>"https://api-sandbox.slimpay.net/creditors/democreditor/orders/1"},
14
+ # "https://api.slimpay.net/alps#get-creditor"=>{"href"=>"https://api-sandbox.slimpay.net/creditors/democreditor"},
15
+ # "https://api.slimpay.net/alps#get-subscriber" =>
16
+ # {"href"=>"https://api-sandbox.slimpay.net/creditors/democreditor/orders/1/subscribers/subscriber01"},
17
+ # "https://api.slimpay.net/alps#user-approval" =>
18
+ # {"href"=>"https://slimpay.net/slimpaytpe16/userApproval?accessCode=spK534N0cuZztBGwj2FjC6eKzcsKFRzXbfy8buloUHiZV6p9PhIfcPgV7c507R"},
19
+ # "https://api.slimpay.net/alps#get-order-items"=>{"href"=>"https://api-sandbox.slimpay.net/creditors/democreditor/orders/1/items"},
20
+ # "https://api.slimpay.net/alps#get-mandate"=>{"href"=>"https://api-sandbox.slimpay.net/creditors/democreditor/mandates/1"}},
21
+ # "reference"=>"1",
22
+ # "state"=>"closed.completed",
23
+ # "started"=>true,
24
+ # "dateCreated"=>"2014-12-12T09:35:39.000+0000",
25
+ # "mandateReused"=>false}
26
+ # ===== Arguments:
27
+ # reference: (String)
28
+ def get_one(reference = 1)
29
+ query_options = "creditorReference=#{@creditor_reference}&reference=#{reference}"
30
+ response = HTTParty.get("#{@endpoint}/#{@resource_name}?#{query_options}", headers: options)
31
+ follow_up_api(response)
32
+ end
33
+
34
+ # POST
35
+ def login(reference = 'subscriber01')
36
+ url = 'orders'
37
+ body_options = {
38
+ creditor: {
39
+ reference: @creditor_reference
40
+ },
41
+ subscriber: {
42
+ reference: reference
43
+ },
44
+ items: [
45
+ {
46
+ type: 'subscriberLogin'
47
+ }
48
+ ],
49
+ started: true
50
+ }
51
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
52
+ follow_up_api(response)
53
+ end
54
+
55
+ # POST
56
+ # This will send a create_order request with given signatory (subscriber Hash with infos)
57
+ #
58
+ # In case of success, this will generate a method accessible via the _.api_methods_ method.
59
+ # This method let you redirect the customer to the approval page : orders.api_methods['user_approval']
60
+ # ===== Arguments
61
+ # reference: (String) The reference to your User in your application. Use a unique key. SlimpayClient will refer to it for future answers.
62
+ # signatory: (Hash) Your customer informations. See API Order documentation for details.
63
+ # ===== Returns
64
+ # a Hash representing the Mandate.
65
+ def sign_mandate(reference = 'subscriber01', signatory = default_signatory)
66
+ url = 'orders'
67
+ body_options = {
68
+ creditor: {
69
+ reference: @creditor_reference
70
+ },
71
+ subscriber: {
72
+ reference: reference
73
+ },
74
+ items: [
75
+ {
76
+ type: 'signMandate',
77
+ mandate: {
78
+ standard: 'SEPA',
79
+ signatory: signatory
80
+ }
81
+ }
82
+ ],
83
+ started: true
84
+ }
85
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
86
+ JSON.parse(follow_up_api(response))
87
+ end
88
+
89
+ private
90
+
91
+ def default_signatory
92
+ {
93
+ honorificPrefix: 'Mr',
94
+ familyName: 'Doe',
95
+ givenName: 'John',
96
+ telephone: '+33612345678',
97
+ email: 'john.doe@gmail.com',
98
+ billingAddress: {
99
+ street1: '27 rue des fleurs',
100
+ street2: 'Bat 2',
101
+ postalCode: '75008',
102
+ city: 'Paris',
103
+ country: 'FR'
104
+ }
105
+ }
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,39 @@
1
+ module SlimpayClient
2
+ # An abstract Payment to be inherited from.
3
+ #
4
+ # Defines API Payment non-semantic methods.
5
+ class Payment < Resource
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ def get_one(id = 1)
12
+ url = "#{@endpoint}/payments/#{id}"
13
+ response = HTTParty.get(url, headers: options)
14
+ generate_api_methods(JSON.parse(response.body))
15
+ SlimpayClient.answer(response)
16
+ end
17
+
18
+ def issues(id = 1)
19
+ url = "#{@endpoint}/payments/#{id}/issues"
20
+ response = HTTParty.get(url, headers: options)
21
+ generate_api_methods(JSON.parse(response.body))
22
+ SlimpayClient.answer(response)
23
+ end
24
+
25
+ def refund(id, amount)
26
+ url = "payments/#{id}/refund"
27
+ body_options = {amount: amount}
28
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
29
+ follow_up_api(response)
30
+ end
31
+
32
+ def cancel(id)
33
+ url = "payments/#{id}/cancellation"
34
+ body_options = {}
35
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
36
+ follow_up_api(response)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ module SlimpayClient
2
+ # An abstract CardAlias to be inherited from.
3
+ #
4
+ # Defines API CardAlias non-semantic methods.
5
+ class RecurrentCardTransaction < Resource
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ def get_one(id = 1)
12
+ url = "#{@endpoint}/recurrent_card_transaction/#{id}"
13
+ response = HTTParty.get(url, headers: options)
14
+ generate_api_methods(JSON.parse(response.body))
15
+ SlimpayClient.answer(response)
16
+ end
17
+
18
+ def cancel(id = 'card-transac-1')
19
+ url = "recurrent-card-transactions/#{id}/cancellation"
20
+ body_options = {}
21
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
22
+ follow_up_api(response)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module SlimpayClient
2
+ # An abstract CardAlias to be inherited from.
3
+ #
4
+ # Defines API CardAlias non-semantic methods.
5
+ class RecurrentDirectDebit < Resource
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ def get_one(id = 1)
12
+ url = "#{@endpoint}/recurrent-direct-debits/#{id}"
13
+ response = HTTParty.get(url, headers: options)
14
+ generate_api_methods(JSON.parse(response.body))
15
+ SlimpayClient.answer(response)
16
+ end
17
+
18
+ def cancel(id = 'rec-direct-debit1')
19
+ url = "recurrent-direct-debits/#{id}/cancellation"
20
+ body_options = {}
21
+ response = HTTParty.post("#{@endpoint}/#{url}", body: body_options.to_json, headers: options)
22
+ follow_up_api(response)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ module SlimpayClient
2
+ # An abstract resource to be inherited from.
3
+ #
4
+ # Defines API resource non-semantic methods.
5
+ class Resource < Base
6
+ def initialize
7
+ @resource_name = self.class.to_s.demodulize.underscore.dasherize.pluralize
8
+ super
9
+ end
10
+
11
+ # Shortcut method to get a resource with only resource's reference.
12
+ #
13
+ # The above example shall return the same result as
14
+ # mandates = SlimpayClient::Mandate.new
15
+ # mandates.get_mandates({creditorReference: @creditor_reference, reference: 1})
16
+ #
17
+ # ===== Example:
18
+ # mandates = SlimpayClient::Mandate.new
19
+ # mandates.get_one(1)
20
+ # ===== Arguments:
21
+ # reference: (String)
22
+ def get_one(reference = 1)
23
+ url = "#{@endpoint}/creditors/#{@creditor_reference}/#{@resource_name}/#{reference}"
24
+ response = HTTParty.get(url, headers: options)
25
+ generate_api_methods(JSON.parse(response.body))
26
+ SlimpayClient.answer(response)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlimpayClient
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "slimpay_client/version"
4
+ require 'oauth2'
5
+ require 'httparty'
6
+
7
+ require 'active_support/core_ext/string/inflections'
8
+
9
+ require 'slimpay_client/configuration'
10
+ require 'slimpay_client/error'
11
+ require 'slimpay_client/base'
12
+ require 'slimpay_client/resource'
13
+ require 'slimpay_client/app'
14
+ require 'slimpay_client/mandate'
15
+ require 'slimpay_client/order'
16
+ require 'slimpay_client/direct_debit'
17
+ require 'slimpay_client/creditor'
18
+ require 'slimpay_client/card_alias'
19
+ require 'slimpay_client/card'
20
+ require 'slimpay_client/recurrent_card_transaction'
21
+ require 'slimpay_client/recurrent_direct_debit'
22
+ require 'slimpay_client/payment'
23
+
24
+ # SlimpayClient module defines Simpay's HAPI constants and require dependencies.
25
+ # TODO: If-None-Match support. (next answer ?= 304)
26
+ # TODO: wiki/doc full worflow: 1. App to change URls, 2. Order to sign mandate, 3. DirectDebit to pay with mandate.
27
+ module SlimpayClient
28
+ PRODUCTION_ENDPOINT = 'https://api.slimpay.net'.freeze
29
+ SANDBOX_ENDPOINT = 'https://api.preprod.slimpay.com'.freeze
30
+ SANDBOX_CLIENT_ID = 'democreditor01'.freeze
31
+ SANDBOX_SECRET_ID = 'demosecret01'.freeze
32
+ SANDBOX_CREDITOR = 'democreditor'.freeze
33
+
34
+ class << self
35
+ attr_accessor :configuration
36
+ end
37
+
38
+ # Sets the initial configuration for client_id, client_secret and creditor_reference
39
+ # ===== Usage:
40
+ # SlimpayClient.configure do |config|
41
+ # config.client_id = "your_client_id"
42
+ # config.client_secret = "your_client_secret"
43
+ # config.creditor_reference = "your_creditor_reference"
44
+ # config.sandbox = true
45
+ # config.notify_url = 'you_notifications_url'
46
+ # config.success_url = 'your_success_url'
47
+ # config.failure_url = 'your_failure_url'
48
+ # config.cancel_url = 'your_cancel_url'
49
+ # config.return_url = 'your_return_url'
50
+ # end
51
+ def self.configure
52
+ self.configuration ||= Configuration.new
53
+ yield(configuration)
54
+ end
55
+
56
+ # Used to display HTTP requests responses nicely in case of error.
57
+ #
58
+ # ===== Arguments:
59
+ # http_response: (HTTParty::Response)
60
+ def self.answer(http_response)
61
+ # return SlimpayClient::Error.empty if http_response.try(:body).nil?
62
+ return SlimpayClient::Error.empty if ( http_response.blank? || http_response.body.blank? )
63
+
64
+ if http_response.code >= 400
65
+ SlimpayClient::Error.new(http_response)
66
+ else
67
+ http_response.body
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,4 @@
1
+ module SlimpayClient
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end