besepa 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/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
|