besepa 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +46 -0
- data/LICENSE.txt +22 -0
- data/README.md +132 -0
- data/Rakefile +1 -0
- data/besepa-ruby.gemspec +31 -0
- data/lib/besepa.rb +14 -0
- data/lib/besepa/activity.rb +11 -0
- data/lib/besepa/api_calls/create.rb +26 -0
- data/lib/besepa/api_calls/destroy.rb +15 -0
- data/lib/besepa/api_calls/list.rb +36 -0
- data/lib/besepa/api_calls/update.rb +23 -0
- data/lib/besepa/bank_account.rb +63 -0
- data/lib/besepa/business_account.rb +37 -0
- data/lib/besepa/customer.rb +134 -0
- data/lib/besepa/debit.rb +64 -0
- data/lib/besepa/errors/besepa_error.rb +28 -0
- data/lib/besepa/errors/invalid_resource_error.rb +11 -0
- data/lib/besepa/errors/resource_not_found_error.rb +11 -0
- data/lib/besepa/group.rb +27 -0
- data/lib/besepa/mandate.rb +18 -0
- data/lib/besepa/product.rb +19 -0
- data/lib/besepa/remittance.rb +32 -0
- data/lib/besepa/resource.rb +96 -0
- data/lib/besepa/subscription.rb +50 -0
- data/lib/besepa/utils/config.rb +51 -0
- data/lib/besepa/utils/connection.rb +27 -0
- data/lib/besepa/utils/request.rb +60 -0
- data/lib/besepa/utils/version.rb +6 -0
- data/lib/besepa/webhook.rb +16 -0
- data/spec/besepa/customer_spec.rb +119 -0
- data/spec/fixtures/customer.json +17 -0
- data/spec/fixtures/customer_add_debit.json +54 -0
- data/spec/fixtures/customer_bank_accounts.json +22 -0
- data/spec/fixtures/customer_debits.json +71 -0
- data/spec/fixtures/customer_removed.json +17 -0
- data/spec/fixtures/customers.json +20 -0
- data/spec/helper.rb +46 -0
- metadata +174 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class BusinessAccount < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
include Besepa::ApiCalls::Create
|
7
|
+
include Besepa::ApiCalls::Update
|
8
|
+
# include Besepa::ApiCalls::Destroy
|
9
|
+
|
10
|
+
FIELDS = [:id, :iban, :bic, :bank_name, :status, :default, :core_enabled, :core_suffix, :b2b_enabled, :b2b_suffix]
|
11
|
+
|
12
|
+
FIELDS.each do |f|
|
13
|
+
attr_accessor f
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.klass_name
|
17
|
+
"bank_account"
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_as_default
|
21
|
+
response = put "/#{api_path}/set_as_default"
|
22
|
+
process_attributes(response['response'])
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def self.api_path(filters={})
|
29
|
+
"/account/bank_accounts"
|
30
|
+
end
|
31
|
+
|
32
|
+
def api_path(filters={})
|
33
|
+
"/account/bank_accounts/#{CGI.escape(id)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class Customer < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
include Besepa::ApiCalls::Create
|
7
|
+
include Besepa::ApiCalls::Update
|
8
|
+
include Besepa::ApiCalls::Destroy
|
9
|
+
|
10
|
+
FIELDS = [:id, :name, :taxid, :reference,
|
11
|
+
:contact_name, :contact_email, :contact_phone, :contact_language,
|
12
|
+
:address_street, :address_city, :address_postalcode, :address_state, :address_country,
|
13
|
+
:status]
|
14
|
+
|
15
|
+
FIELDS.each do |f|
|
16
|
+
attr_accessor f
|
17
|
+
end
|
18
|
+
|
19
|
+
# Customer's bank accounts
|
20
|
+
#
|
21
|
+
# @return collection of Besepa::BankAccount
|
22
|
+
def bank_accounts
|
23
|
+
BankAccount.all( {:customer_id => id} )
|
24
|
+
end
|
25
|
+
|
26
|
+
# Debits sent to this customer
|
27
|
+
#
|
28
|
+
# @return collection of Besepa::Debits
|
29
|
+
def debits
|
30
|
+
Debit.all( {:customer_id => id} )
|
31
|
+
end
|
32
|
+
|
33
|
+
# Subscriptions from this customer
|
34
|
+
#
|
35
|
+
# @return collection of Besepa::Subscription
|
36
|
+
def subscriptions
|
37
|
+
Subscription.all( {:customer_id => id} )
|
38
|
+
end
|
39
|
+
|
40
|
+
# List of groups this customers blongs to
|
41
|
+
#
|
42
|
+
# @return collection of Besepa::Group
|
43
|
+
def groups
|
44
|
+
Group.all( {:customer_id => id} )
|
45
|
+
end
|
46
|
+
|
47
|
+
# Adds this customer to the given group
|
48
|
+
#
|
49
|
+
# @param group_id The ID of the group to which this user should be added
|
50
|
+
#
|
51
|
+
# @return true if user is now a member of the group
|
52
|
+
def add_to_group(group_id)
|
53
|
+
response = post "/#{self.class.api_path}/#{id}/memberships/#{group_id}"
|
54
|
+
response['response'].select{|c| c['id'] == group_id}.any?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Removed this customer from the given group
|
58
|
+
#
|
59
|
+
# @param group_id The ID of the group from which this user should be removed
|
60
|
+
#
|
61
|
+
# @return true if user is no longer a member of the group
|
62
|
+
def remove_from_group(group_id)
|
63
|
+
response = delete "/#{self.class.api_path}/#{id}/memberships/#{group_id}"
|
64
|
+
response['response'].select{|c| c['id'] == group_id}.empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates a new subscription for this customer
|
68
|
+
#
|
69
|
+
# @param starts_at The date this subscription should start (Format: YYYY-MM-DD)
|
70
|
+
# @param product_code The ID of the product the customer is subscribing to
|
71
|
+
# @param bank_account_code The ID of the bank account where debits should be sent to
|
72
|
+
# @param setup_fee Initial set-up fee. Optional, default: 0
|
73
|
+
# @param metadata Optional Hash with metadata related to this subscription, if any.
|
74
|
+
#
|
75
|
+
# @return new created Besepa::Subscription
|
76
|
+
def add_subscription(starts_at, product_code, bank_account_code, setup_fee=0, metadata=nil)
|
77
|
+
params = {:starts_at => starts_at, :product_id => product_code, :debtor_bank_account_id => bank_account_code}
|
78
|
+
params[:setup_fee] = setup_fee if setup_fee
|
79
|
+
params[:metadata] = metadata if metadata
|
80
|
+
Subscription.create( params, {:customer_id => id} )
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds a bank account to this customer.
|
84
|
+
# IBAN and BIC are the only mandatory fields. If you already have the mandate signed, you can pass mandate
|
85
|
+
# detail's and account will be activated by default. Otherwise BankAccount will be marked as inactive (not usable
|
86
|
+
# for creating debits or subscriptions) until mandate is signed. BankAccount includes mandate's info, including
|
87
|
+
# signature URL.
|
88
|
+
#
|
89
|
+
# @param iban
|
90
|
+
# @param bic
|
91
|
+
# @param bank_name
|
92
|
+
# @param scheme CORE|COR1|B2B. Default: CORE
|
93
|
+
# @param mandate_signature_date Date in which this mandate was signed if already signed (Format: YYYY-MM-DD)
|
94
|
+
# @param mandate_ref Mandate's reference. If none, Besepa will create one.
|
95
|
+
# @param used Says if this mandate has already been used or not.
|
96
|
+
# @param signature_type Signature to be used: checkbox|sms|biometric
|
97
|
+
# @param phone_number Phone number where the signature SMS will be sent in case signature_type==sms is used.
|
98
|
+
#
|
99
|
+
# @return new created Besepa::BankAccount
|
100
|
+
def add_bank_account(iban, bic, bank_name=nil, scheme='CORE', mandate_signature_date=nil, mandate_ref=nil, used=false, signature_type='checkbox', phone_number=nil)
|
101
|
+
params = {:iban => iban, :bic => bic }
|
102
|
+
params[:mandate] = {scheme: scheme, used: used}
|
103
|
+
if mandate_signature_date
|
104
|
+
params[:mandate][:signed_at] = mandate_signature_date if mandate_signature_date
|
105
|
+
params[:mandate][:reference] = mandate_ref if mandate_ref
|
106
|
+
else
|
107
|
+
params[:mandate][:signature_type] = signature_type
|
108
|
+
params[:mandate][:phone_number] = phone_number if phone_number
|
109
|
+
end
|
110
|
+
params[:bank_name] = bank_name if bank_name
|
111
|
+
BankAccount.create( params, {:customer_id => id} )
|
112
|
+
end
|
113
|
+
|
114
|
+
# Generates a direct debit that will be charged to this customer.
|
115
|
+
#
|
116
|
+
# @param debtor_bank_account_id Customer's BankAccount code this Debit shouyd be charged to.
|
117
|
+
# @param reference Debit's unique reference
|
118
|
+
# @param description Debit's description. Customer will see this in his Bank's statements
|
119
|
+
# @param amount Amount to be charged. Integer, last two digits represent decimals: 10.25 should be 1025
|
120
|
+
# @param collect_at Date in which the charge should be made (Format: YYYY-MM-DD).
|
121
|
+
# @param creditor_account_id Business' BankAccount that should receive the money. If none passed, account marked as default in Besepa's dashboard will be used.
|
122
|
+
# @param metadata Optional Hash with metadata related to this debit, if any.
|
123
|
+
#
|
124
|
+
# @return new created Besepa::Debit
|
125
|
+
def add_debit(debtor_bank_account_id, reference, description, amount, collect_at, creditor_account_id=nil, metadata=nil)
|
126
|
+
params = {:reference => reference, :description => description, :debtor_bank_account_id => debtor_bank_account_id,
|
127
|
+
:amount => amount, :collect_at => collect_at}
|
128
|
+
params[:creditor_account_id] = creditor_account_id if creditor_account_id
|
129
|
+
params[:metadata] = metadata if metadata
|
130
|
+
Debit.create( params, {:customer_id => id} )
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
data/lib/besepa/debit.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class Debit < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
include Besepa::ApiCalls::Create
|
7
|
+
include Besepa::ApiCalls::Update
|
8
|
+
include Besepa::ApiCalls::Destroy
|
9
|
+
|
10
|
+
FIELDS = [:id, :reference, :amount, :currency, :status,
|
11
|
+
:collect_at, :sent_at, :description, :metadata,
|
12
|
+
:error_code, :platform_error_code]
|
13
|
+
|
14
|
+
FIELDS.each do |f|
|
15
|
+
attr_accessor f
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :debtor_bank_account, :creditor_bank_account, :customer, :remittance, :subscription
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
values = {}
|
22
|
+
self.class::FIELDS.each do |key|
|
23
|
+
values[key] = self.send("#{key.to_s}")
|
24
|
+
end
|
25
|
+
values[:debtor_bank_account] = debtor_bank_account.to_hash if debtor_bank_account
|
26
|
+
values[:creditor_bank_account] = creditor_bank_account.to_hash if creditor_bank_account
|
27
|
+
values[:customer] = customer.to_hash if customer
|
28
|
+
values[:remittance] = remittance.to_hash if remittance
|
29
|
+
values[:subscription] = subscription.to_hash if subscription
|
30
|
+
values
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def self.api_path(filters={})
|
36
|
+
if filters[:customer_id]
|
37
|
+
"#{Customer.api_path}/#{CGI.escape(filters[:customer_id])}/debits"
|
38
|
+
else
|
39
|
+
"#{Group.api_path}/#{CGI.escape(filters[:group_id])}/debits"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def api_path(filters={})
|
44
|
+
if filters[:customer_id]
|
45
|
+
"#{Customer.api_path}/#{CGI.escape(filters[:customer_id])}/debits/#{CGI.escape(id)}"
|
46
|
+
else
|
47
|
+
"#{Group.api_path}/#{CGI.escape(filters[:group_id])}/debits/#{CGI.escape(id)}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_attributes(attrs)
|
52
|
+
self.class::FIELDS.each do |key|
|
53
|
+
self.send("#{key.to_s}=", attrs[key.to_s] || attrs[key.to_sym])
|
54
|
+
end
|
55
|
+
self.debtor_bank_account = Besepa::BankAccount.new(attrs['debtor_bank_account']) if attrs['debtor_bank_account']
|
56
|
+
self.creditor_bank_account = Besepa::BusinessAccount.new(attrs['creditor_bank_account']) if attrs['creditor_bank_account']
|
57
|
+
self.customer = Besepa::Customer.new(attrs['customer']) if attrs['customer']
|
58
|
+
self.remittance = Besepa::Remittance.new(attrs['remittance']) if attrs['remittance']
|
59
|
+
self.subscription = Besepa::Subscription.new(attrs['subscription']) if attrs['subscription']
|
60
|
+
process_activities(attrs)
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
module Errors
|
4
|
+
|
5
|
+
class BesepaError < StandardError
|
6
|
+
|
7
|
+
attr_reader :error
|
8
|
+
attr_reader :description
|
9
|
+
attr_reader :http_status
|
10
|
+
attr_reader :messages
|
11
|
+
|
12
|
+
def initialize(error=nil, description=nil, http_status=nil, messages=nil)
|
13
|
+
@messages = messages
|
14
|
+
@http_status = http_status
|
15
|
+
@description = description
|
16
|
+
@error = error
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
|
21
|
+
"#{status_string}#{@error} (#{@description})"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/besepa/group.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class Group < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
include Besepa::ApiCalls::Create
|
7
|
+
include Besepa::ApiCalls::Update
|
8
|
+
include Besepa::ApiCalls::Destroy
|
9
|
+
|
10
|
+
FIELDS = [:id, :name, :reference]
|
11
|
+
|
12
|
+
FIELDS.each do |f|
|
13
|
+
attr_accessor f
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def self.api_path(filters={})
|
19
|
+
if filters[:customer_id]
|
20
|
+
"#{Customer.api_path}/#{CGI.escape(filters[:customer_id])}/groups"
|
21
|
+
else
|
22
|
+
"/groups"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class Mandate < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
|
7
|
+
FIELDS = [:id, :signed_at, :status, :description, :signature_type, :mandate_type, :reference, :url, :used, :phone_number, :scheme, :signature_url]
|
8
|
+
|
9
|
+
FIELDS.each do |f|
|
10
|
+
attr_accessor f
|
11
|
+
end
|
12
|
+
|
13
|
+
def api_path
|
14
|
+
"/customers/#{self.customer_id}/#{self.class.api_path}"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class Product < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
include Besepa::ApiCalls::Create
|
7
|
+
include Besepa::ApiCalls::Update
|
8
|
+
include Besepa::ApiCalls::Destroy
|
9
|
+
|
10
|
+
FIELDS = [:id, :name, :amount, :currency, :reference,
|
11
|
+
:recurrent, :max_charges, :periodicity,
|
12
|
+
:status]
|
13
|
+
|
14
|
+
FIELDS.each do |f|
|
15
|
+
attr_accessor f
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Besepa
|
2
|
+
|
3
|
+
class Remittance < Besepa::Resource
|
4
|
+
|
5
|
+
include Besepa::ApiCalls::List
|
6
|
+
|
7
|
+
FIELDS = [:id, :collect_at, :send_at, :sent_at, :status, :scheme]
|
8
|
+
|
9
|
+
attr_accessor :bank_account
|
10
|
+
|
11
|
+
FIELDS.each do |f|
|
12
|
+
attr_accessor f
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.api_path(filters={})
|
16
|
+
"/remittances"
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def process_attributes(attrs)
|
22
|
+
self.class::FIELDS.each do |key|
|
23
|
+
self.send("#{key.to_s}=", attrs[key.to_s] || attrs[key.to_sym])
|
24
|
+
end
|
25
|
+
self.bank_account = Besepa::BusinessAccount.new(attrs['bank_account']) if attrs['bank_account']
|
26
|
+
process_activities(attrs)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'besepa/utils/request'
|
2
|
+
require 'besepa/utils/connection'
|
3
|
+
require 'besepa/utils/config'
|
4
|
+
|
5
|
+
module Besepa
|
6
|
+
|
7
|
+
class Resource
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
|
11
|
+
include Besepa::Utils::Connection
|
12
|
+
include Besepa::Utils::Request
|
13
|
+
|
14
|
+
def api_path(filters={})
|
15
|
+
"#{klass_name}s"
|
16
|
+
end
|
17
|
+
|
18
|
+
def klass_name
|
19
|
+
name.split('::')[-1].downcase
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_errors(http_status, response)
|
23
|
+
error = response['error']
|
24
|
+
desc = response['error_description']
|
25
|
+
msgs = response['messages']
|
26
|
+
if error == 'invalid_resource'
|
27
|
+
raise Besepa::Errors::InvalidResourceError.new(error, desc, http_status, msgs)
|
28
|
+
elsif error == 'not_found'
|
29
|
+
raise Besepa::Errors::ResourceNotFoundError.new(error, desc, http_status, msgs)
|
30
|
+
else
|
31
|
+
raise Besepa::Errors::BesepaError.new(error, desc, http_status, msgs)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
include Besepa::Utils::Connection
|
38
|
+
include Besepa::Utils::Request
|
39
|
+
|
40
|
+
attr_accessor :activities
|
41
|
+
|
42
|
+
def initialize(attrs={})
|
43
|
+
process_attributes(attrs)
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_hash
|
47
|
+
values = {}
|
48
|
+
self.class::FIELDS.each do |key|
|
49
|
+
values[key] = self.send("#{key.to_s}")
|
50
|
+
end
|
51
|
+
values
|
52
|
+
end
|
53
|
+
|
54
|
+
def serializable_hash
|
55
|
+
to_hash
|
56
|
+
end
|
57
|
+
|
58
|
+
def as_json
|
59
|
+
to_hash.as_json
|
60
|
+
end
|
61
|
+
|
62
|
+
def klass_name
|
63
|
+
self.class.name.split('::')[-1].downcase
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
def handle_errors(http_status, response)
|
69
|
+
Module.const_get(self.class.name).handle_errors(http_status, response)
|
70
|
+
end
|
71
|
+
|
72
|
+
def process_attributes(attrs)
|
73
|
+
self.class::FIELDS.each do |key|
|
74
|
+
self.send("#{key.to_s}=", attrs[key.to_s] || attrs[key.to_sym])
|
75
|
+
end
|
76
|
+
process_activities(attrs)
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_activities(attrs)
|
80
|
+
if attrs['activities']
|
81
|
+
self.activities = Array.new
|
82
|
+
attrs['activities'].each do |a|
|
83
|
+
self.activities << Besepa::Activity.new(a)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# def api_path(filters={})
|
89
|
+
# self.class.api_path
|
90
|
+
# end
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
end
|