c6_bank 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.
- checksums.yaml +7 -0
- data/.env.example +11 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +15 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +318 -0
- data/Rakefile +12 -0
- data/docs/NEXT_STEPS.md +17 -0
- data/docs/openapi/bolepix.yaml +850 -0
- data/docs/openapi/pix-api.yaml +4446 -0
- data/docs/rails_initializer_example.rb +17 -0
- data/docs/roteiro_mapping.md +31 -0
- data/examples/auth_probe.rb +14 -0
- data/examples/boleto_cases.rb +56 -0
- data/examples/env.rb +22 -0
- data/examples/live_sandbox.rb +90 -0
- data/examples/pix_cases.rb +42 -0
- data/exe/c6_bank +4 -0
- data/lib/c6_bank/boleto/request.rb +163 -0
- data/lib/c6_bank/client.rb +255 -0
- data/lib/c6_bank/configuration.rb +120 -0
- data/lib/c6_bank/errors.rb +33 -0
- data/lib/c6_bank/pix/payload.rb +132 -0
- data/lib/c6_bank/pix.rb +16 -0
- data/lib/c6_bank/resources/base.rb +34 -0
- data/lib/c6_bank/resources/boleto.rb +72 -0
- data/lib/c6_bank/resources/dda.rb +40 -0
- data/lib/c6_bank/resources/pix.rb +111 -0
- data/lib/c6_bank/resources.rb +11 -0
- data/lib/c6_bank/version.rb +5 -0
- data/lib/c6_bank.rb +68 -0
- data/sig/c6_bank.rbs +4 -0
- metadata +122 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "openssl"
|
|
4
|
+
|
|
5
|
+
module C6Bank
|
|
6
|
+
class Configuration
|
|
7
|
+
SANDBOX_BASE_URL = "https://baas-api-sandbox.c6bank.info"
|
|
8
|
+
PRODUCTION_BASE_URL = "https://baas-api.c6bank.info"
|
|
9
|
+
SANDBOX_BILLING_SCHEME = "21"
|
|
10
|
+
PRODUCTION_BILLING_SCHEME = "15"
|
|
11
|
+
|
|
12
|
+
attr_accessor :client_id,
|
|
13
|
+
:client_secret,
|
|
14
|
+
:certificate_path,
|
|
15
|
+
:private_key_path,
|
|
16
|
+
:certificate,
|
|
17
|
+
:private_key,
|
|
18
|
+
:base_url,
|
|
19
|
+
:auth_base_url,
|
|
20
|
+
:open_timeout,
|
|
21
|
+
:read_timeout,
|
|
22
|
+
:write_timeout,
|
|
23
|
+
:max_retries,
|
|
24
|
+
:token_path,
|
|
25
|
+
:boleto_path,
|
|
26
|
+
:pix_path,
|
|
27
|
+
:dda_path,
|
|
28
|
+
:partner_software_name,
|
|
29
|
+
:partner_software_version,
|
|
30
|
+
:pix_key,
|
|
31
|
+
:billing_scheme
|
|
32
|
+
attr_reader :environment
|
|
33
|
+
|
|
34
|
+
def initialize
|
|
35
|
+
@environment = :sandbox
|
|
36
|
+
@open_timeout = 10
|
|
37
|
+
@read_timeout = 30
|
|
38
|
+
@write_timeout = 30
|
|
39
|
+
@max_retries = 2
|
|
40
|
+
|
|
41
|
+
@token_path = "/v1/auth"
|
|
42
|
+
@boleto_path = "/v2/bank_slips"
|
|
43
|
+
@pix_path = "/v2/pix"
|
|
44
|
+
@dda_path = "/api/v1/pagamentos"
|
|
45
|
+
|
|
46
|
+
@auth_base_url = nil
|
|
47
|
+
@partner_software_name = "c6_bank-gem"
|
|
48
|
+
@partner_software_version = C6Bank::VERSION
|
|
49
|
+
@pix_key = nil
|
|
50
|
+
@billing_scheme = nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def environment=(env)
|
|
54
|
+
@environment = env.to_sym
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def sandbox?
|
|
58
|
+
environment == :sandbox
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def production?
|
|
62
|
+
environment == :production
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def effective_base_url
|
|
66
|
+
return base_url if base_url
|
|
67
|
+
|
|
68
|
+
sandbox? ? SANDBOX_BASE_URL : PRODUCTION_BASE_URL
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def effective_auth_base_url
|
|
72
|
+
return auth_base_url if auth_base_url
|
|
73
|
+
|
|
74
|
+
effective_base_url
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def effective_billing_scheme
|
|
78
|
+
billing_scheme.to_s.empty? ? default_billing_scheme : billing_scheme.to_s
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def default_billing_scheme
|
|
82
|
+
production? ? PRODUCTION_BILLING_SCHEME : SANDBOX_BILLING_SCHEME
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def ssl_certificate
|
|
86
|
+
return certificate if certificate
|
|
87
|
+
|
|
88
|
+
OpenSSL::X509::Certificate.new(File.read(certificate_path)) if certificate_path
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def ssl_private_key
|
|
92
|
+
return private_key if private_key
|
|
93
|
+
|
|
94
|
+
OpenSSL::PKey::RSA.new(File.read(private_key_path)) if private_key_path
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def validate!
|
|
98
|
+
raise C6Bank::ConfigurationError, "client_id and client_secret are required" unless client_id && client_secret
|
|
99
|
+
|
|
100
|
+
unless ssl_certificate && ssl_private_key
|
|
101
|
+
raise C6Bank::ConfigurationError,
|
|
102
|
+
"Either certificate_path + private_key_path or certificate + private_key must be provided for mTLS"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
warn_if_certificate_expired!
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def warn_if_certificate_expired!
|
|
111
|
+
cert = ssl_certificate
|
|
112
|
+
expiry = cert.respond_to?(:not_after) ? cert.not_after : nil
|
|
113
|
+
return unless expiry.is_a?(Time) && expiry < Time.now.utc && expiry.year > 1980
|
|
114
|
+
|
|
115
|
+
warn "[c6_bank] mTLS certificate expired on #{expiry}. Replace C6_CERT_PATH / C6_KEY_PATH."
|
|
116
|
+
rescue OpenSSL::X509::CertificateError, ArgumentError, TypeError
|
|
117
|
+
nil
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module C6Bank
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
|
|
6
|
+
class ConfigurationError < Error; end
|
|
7
|
+
|
|
8
|
+
class AuthenticationError < Error; end
|
|
9
|
+
|
|
10
|
+
class ApiError < Error
|
|
11
|
+
attr_reader :status, :body, :response
|
|
12
|
+
|
|
13
|
+
def initialize(message = nil, status: nil, body: nil, response: nil)
|
|
14
|
+
@status = status
|
|
15
|
+
@body = body
|
|
16
|
+
@response = response
|
|
17
|
+
super(message || default_message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def default_message
|
|
23
|
+
msg = "C6 Bank API error"
|
|
24
|
+
msg += " (status: #{status})" if status
|
|
25
|
+
msg += ": #{body}" if body
|
|
26
|
+
msg
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class NotFoundError < ApiError; end
|
|
31
|
+
class RateLimitError < ApiError; end
|
|
32
|
+
class ServerError < ApiError; end
|
|
33
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module C6Bank
|
|
4
|
+
module Pix
|
|
5
|
+
# Normalizes Ruby-friendly hashes into the BACEN Pix JSON contract.
|
|
6
|
+
module Payload
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
TOP_LEVEL_ALIASES = {
|
|
10
|
+
"pix_key" => "chave",
|
|
11
|
+
"key" => "chave",
|
|
12
|
+
"amount" => "valor",
|
|
13
|
+
"payer" => "devedor",
|
|
14
|
+
"message" => "solicitacaoPagador",
|
|
15
|
+
"solicitacao_pagador" => "solicitacaoPagador",
|
|
16
|
+
"additional_info" => "infoAdicionais",
|
|
17
|
+
"info_adicionais" => "infoAdicionais"
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def immediate(params, default_key:)
|
|
21
|
+
data = stringify(params)
|
|
22
|
+
txid = data.delete("txid")
|
|
23
|
+
apply_aliases!(data)
|
|
24
|
+
data["chave"] = present(data["chave"]) || present(default_key)
|
|
25
|
+
require_chave!(data["chave"])
|
|
26
|
+
|
|
27
|
+
expiracao = data.delete("expiracao") || data.delete("expiration")
|
|
28
|
+
calendario = stringify(data["calendario"] || {})
|
|
29
|
+
calendario["expiracao"] ||= expiracao || 3600
|
|
30
|
+
data["calendario"] = calendario
|
|
31
|
+
data["valor"] = normalize_valor(data["valor"])
|
|
32
|
+
data["devedor"] = normalize_devedor(data["devedor"]) if data["devedor"]
|
|
33
|
+
[txid, compact(data)]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def due(params, default_key:)
|
|
37
|
+
data = stringify(params)
|
|
38
|
+
txid = data.delete("txid") || Pix.generate_txid
|
|
39
|
+
apply_aliases!(data)
|
|
40
|
+
data["chave"] = present(data["chave"]) || present(default_key)
|
|
41
|
+
require_chave!(data["chave"])
|
|
42
|
+
|
|
43
|
+
due_date = data.delete("dataDeVencimento") || data.delete("due_date") || data.delete("data_vencimento")
|
|
44
|
+
days_after = data.delete("validadeAposVencimento") ||
|
|
45
|
+
data.delete("days_after_due") ||
|
|
46
|
+
data.delete("validade_apos_vencimento")
|
|
47
|
+
calendario = stringify(data["calendario"] || {})
|
|
48
|
+
calendario["dataDeVencimento"] ||= due_date
|
|
49
|
+
calendario["validadeAposVencimento"] ||= days_after unless days_after.nil?
|
|
50
|
+
data["calendario"] = calendario
|
|
51
|
+
data["valor"] = normalize_valor(data["valor"])
|
|
52
|
+
data["devedor"] = normalize_devedor(data["devedor"]) if data["devedor"]
|
|
53
|
+
[txid, compact(data)]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def stringify(value)
|
|
57
|
+
case value
|
|
58
|
+
when Hash
|
|
59
|
+
value.each_with_object({}) { |(key, nested), memo| memo[key.to_s] = stringify(nested) }
|
|
60
|
+
when Array
|
|
61
|
+
value.map { |item| stringify(item) }
|
|
62
|
+
else
|
|
63
|
+
value
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def apply_aliases!(data)
|
|
68
|
+
TOP_LEVEL_ALIASES.each do |from, to|
|
|
69
|
+
data[to] = data.delete(from) if data.key?(from) && !present(data[to])
|
|
70
|
+
end
|
|
71
|
+
data
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def normalize_valor(value)
|
|
75
|
+
case value
|
|
76
|
+
when Hash
|
|
77
|
+
money = stringify(value)
|
|
78
|
+
money["original"] = format_money(money["original"]) if money.key?("original")
|
|
79
|
+
money
|
|
80
|
+
else
|
|
81
|
+
{ "original" => format_money(value) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def normalize_devedor(value)
|
|
86
|
+
return unless value
|
|
87
|
+
|
|
88
|
+
person = stringify(value)
|
|
89
|
+
tax_id = person.delete("tax_id") || person.delete("cpf_cnpj") || person.delete("document")
|
|
90
|
+
if present(tax_id)
|
|
91
|
+
digits = tax_id.to_s.gsub(/\D/, "")
|
|
92
|
+
if digits.length == 14
|
|
93
|
+
person["cnpj"] ||= digits
|
|
94
|
+
else
|
|
95
|
+
person["cpf"] ||= digits
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
person
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def format_money(value)
|
|
102
|
+
format("%.2f", Float(value))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def require_chave!(chave)
|
|
106
|
+
return if present(chave)
|
|
107
|
+
|
|
108
|
+
raise ConfigurationError,
|
|
109
|
+
"A Pix key is required. Set C6Bank pix_key (C6_PIX_KEY) or pass chave: in the request."
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def present(value)
|
|
113
|
+
str = value.to_s.strip
|
|
114
|
+
str.empty? ? nil : value
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def compact(value)
|
|
118
|
+
case value
|
|
119
|
+
when Hash
|
|
120
|
+
value.each_with_object({}) do |(key, nested), memo|
|
|
121
|
+
compacted = compact(nested)
|
|
122
|
+
memo[key] = compacted unless compacted.nil?
|
|
123
|
+
end
|
|
124
|
+
when Array
|
|
125
|
+
value.map { |item| compact(item) }
|
|
126
|
+
else
|
|
127
|
+
value
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
data/lib/c6_bank/pix.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
require_relative "pix/payload"
|
|
5
|
+
|
|
6
|
+
module C6Bank
|
|
7
|
+
# Helpers for the BACEN Pix API (cob / cobv) exposed by C6 Bank at `/v2/pix`.
|
|
8
|
+
module Pix
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def generate_txid(length = 32)
|
|
12
|
+
length = length.clamp(26, 35)
|
|
13
|
+
SecureRandom.alphanumeric(length)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module C6Bank
|
|
4
|
+
module Resources
|
|
5
|
+
class Base
|
|
6
|
+
attr_reader :client
|
|
7
|
+
|
|
8
|
+
def initialize(client)
|
|
9
|
+
@client = client
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
|
|
14
|
+
def request(*args, **kwargs)
|
|
15
|
+
client.request(*args, **kwargs)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns the configured path for this resource.
|
|
19
|
+
# Resources override #default_path
|
|
20
|
+
def path
|
|
21
|
+
config_path = begin
|
|
22
|
+
client.config.public_send("#{self.class.name.split("::").last.downcase}_path")
|
|
23
|
+
rescue StandardError
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
config_path || default_path
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def default_path
|
|
30
|
+
raise NotImplementedError
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module C6Bank
|
|
4
|
+
module Resources
|
|
5
|
+
class Boleto < Base
|
|
6
|
+
def create(params_or_request)
|
|
7
|
+
body = payload_from(params_or_request)
|
|
8
|
+
request(:post, boleto_path, body: body)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
alias emit create
|
|
12
|
+
alias issue create
|
|
13
|
+
|
|
14
|
+
def find(external_reference_id)
|
|
15
|
+
request(:get, "#{boleto_path}/#{external_reference_id}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def list(params = {})
|
|
19
|
+
request(:get, "#{boleto_path}/list", params: stringify(params))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def update(external_reference_id, params = {})
|
|
23
|
+
request(:patch, "#{boleto_path}/#{external_reference_id}", body: stringify(params))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def pdf(external_reference_id)
|
|
27
|
+
# C6 sandbox returns 406 for `Accept: application/pdf` alone and
|
|
28
|
+
# serves `Content-Type: application/pdf` when Accept is `*/*` or JSON.
|
|
29
|
+
response = client.request(
|
|
30
|
+
:get,
|
|
31
|
+
"#{boleto_path}/#{external_reference_id}/pdf",
|
|
32
|
+
headers: { "Accept" => "*/*" },
|
|
33
|
+
raw: true
|
|
34
|
+
)
|
|
35
|
+
response.body
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def cancel(external_reference_id)
|
|
39
|
+
request(:put, "#{boleto_path}/#{external_reference_id}/cancel")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
alias baixa cancel
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def boleto_path
|
|
47
|
+
client.config.boleto_path || "/v2/bank_slips"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def payload_from(params_or_request)
|
|
51
|
+
omit_pix = false
|
|
52
|
+
body =
|
|
53
|
+
if params_or_request.is_a?(C6Bank::Boleto::Request)
|
|
54
|
+
omit_pix = params_or_request.omit_pix?
|
|
55
|
+
params_or_request.to_h
|
|
56
|
+
else
|
|
57
|
+
hash = stringify(params_or_request)
|
|
58
|
+
omit_pix = hash["pix"] == false || hash["omit_pix"] == true
|
|
59
|
+
hash.delete("pix") if hash["pix"] == false
|
|
60
|
+
hash.delete("omit_pix")
|
|
61
|
+
hash
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
C6Bank::Boleto::Request.apply_defaults(body, client.config, omit_pix: omit_pix)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def stringify(value)
|
|
68
|
+
C6Bank::Pix::Payload.stringify(value)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module C6Bank
|
|
4
|
+
module Resources
|
|
5
|
+
# DDA + scheduled payment groups (agendamento de pagamentos).
|
|
6
|
+
# Covers roteiro section 8.
|
|
7
|
+
class Dda < Base
|
|
8
|
+
# 8.1 - Query open DDA boletos for a customer
|
|
9
|
+
def query_dda(params)
|
|
10
|
+
request(:get, "#{dda_path}/dda", params: params)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# 8.2 - Submit a payment group for consultation
|
|
14
|
+
def create_payment_group(params)
|
|
15
|
+
request(:post, "#{dda_path}/grupos", body: params)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Get items of a group
|
|
19
|
+
def get_group_items(group_id)
|
|
20
|
+
request(:get, "#{dda_path}/grupos/#{group_id}/itens")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Remove items (list or single)
|
|
24
|
+
def remove_from_group(group_id, params)
|
|
25
|
+
request(:delete, "#{dda_path}/grupos/#{group_id}/itens", body: params)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Approve/submit group
|
|
29
|
+
def approve_group(group_id)
|
|
30
|
+
request(:post, "#{dda_path}/grupos/#{group_id}/aprovar")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def dda_path
|
|
36
|
+
client.config.dda_path || "/api/v1/pagamentos"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
|
|
5
|
+
module C6Bank
|
|
6
|
+
module Resources
|
|
7
|
+
# BACEN Pix API (C6 Bank) — `/v2/pix`.
|
|
8
|
+
#
|
|
9
|
+
# Immediate charges (cob), due-date charges (cobv), received Pix, refunds
|
|
10
|
+
# and webhook configuration.
|
|
11
|
+
class Pix < Base
|
|
12
|
+
def create_immediate_charge(params = {})
|
|
13
|
+
txid, body = C6Bank::Pix::Payload.immediate(params, default_key: default_pix_key)
|
|
14
|
+
if txid
|
|
15
|
+
request(:put, "#{pix_path}/cob/#{txid}", body: body)
|
|
16
|
+
else
|
|
17
|
+
request(:post, "#{pix_path}/cob", body: body)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def revise_immediate(txid, params = {})
|
|
22
|
+
request(:patch, "#{pix_path}/cob/#{txid}", body: stringify_params(params))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def find_immediate(txid)
|
|
26
|
+
request(:get, "#{pix_path}/cob/#{txid}")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def list_immediate(params = {})
|
|
30
|
+
request(:get, "#{pix_path}/cob", params: stringify_params(params))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_due_charge(params = {})
|
|
34
|
+
txid, body = C6Bank::Pix::Payload.due(params, default_key: default_pix_key)
|
|
35
|
+
request(:put, "#{pix_path}/cobv/#{txid}", body: body)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def revise_due(txid, params = {})
|
|
39
|
+
request(:patch, "#{pix_path}/cobv/#{txid}", body: stringify_params(params))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def find_due(txid)
|
|
43
|
+
request(:get, "#{pix_path}/cobv/#{txid}")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def list_due(params = {})
|
|
47
|
+
request(:get, "#{pix_path}/cobv", params: stringify_params(params))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def received(e2eid)
|
|
51
|
+
request(:get, "#{pix_path}/pix/#{e2eid}")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def list_received(params = {})
|
|
55
|
+
request(:get, "#{pix_path}/pix", params: stringify_params(params))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def refund(e2eid, id, params = {})
|
|
59
|
+
request(:put, "#{pix_path}/pix/#{e2eid}/devolucao/#{id}", body: stringify_params(params))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def find_refund(e2eid, id)
|
|
63
|
+
request(:get, "#{pix_path}/pix/#{e2eid}/devolucao/#{id}")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def configure_webhook(params = {})
|
|
67
|
+
chave = webhook_chave(params)
|
|
68
|
+
url = params[:webhookUrl] || params["webhookUrl"] || params[:webhook_url] ||
|
|
69
|
+
params["webhook_url"] || params[:url] || params["url"]
|
|
70
|
+
request(:put, "#{pix_path}/webhook/#{encode_chave(chave)}", body: { "webhookUrl" => url })
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def webhook(chave = nil)
|
|
74
|
+
request(:get, "#{pix_path}/webhook/#{encode_chave(webhook_chave(chave: chave))}")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def delete_webhook(chave = nil)
|
|
78
|
+
request(:delete, "#{pix_path}/webhook/#{encode_chave(webhook_chave(chave: chave))}")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def list_webhooks(params = {})
|
|
82
|
+
request(:get, "#{pix_path}/webhook", params: stringify_params(params))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def pix_path
|
|
88
|
+
client.config.pix_path
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def default_pix_key
|
|
92
|
+
client.config.pix_key
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def stringify_params(params)
|
|
96
|
+
C6Bank::Pix::Payload.stringify(params)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def webhook_chave(params = {})
|
|
100
|
+
params = { chave: params } unless params.is_a?(Hash)
|
|
101
|
+
chave = params[:chave] || params["chave"] || params[:key] || params["key"] || default_pix_key
|
|
102
|
+
C6Bank::Pix::Payload.require_chave!(chave)
|
|
103
|
+
chave
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def encode_chave(chave)
|
|
107
|
+
CGI.escapeURIComponent(chave.to_s)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
data/lib/c6_bank.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "c6_bank/version"
|
|
4
|
+
require_relative "c6_bank/errors"
|
|
5
|
+
require_relative "c6_bank/configuration"
|
|
6
|
+
require_relative "c6_bank/client"
|
|
7
|
+
require_relative "c6_bank/pix"
|
|
8
|
+
require_relative "c6_bank/resources"
|
|
9
|
+
require_relative "c6_bank/boleto/request"
|
|
10
|
+
|
|
11
|
+
module C6Bank
|
|
12
|
+
class << self
|
|
13
|
+
attr_writer :client
|
|
14
|
+
|
|
15
|
+
def client
|
|
16
|
+
@client ||= begin
|
|
17
|
+
unless @config_block_ran
|
|
18
|
+
raise ConfigurationError, "C6Bank not configured. Call C6Bank.configure or C6Bank.client= first."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
build_default_client
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def configure
|
|
26
|
+
config = Configuration.new
|
|
27
|
+
yield config if block_given?
|
|
28
|
+
config.validate!
|
|
29
|
+
@config_block_ran = true
|
|
30
|
+
@client = Client.new(
|
|
31
|
+
client_id: config.client_id,
|
|
32
|
+
client_secret: config.client_secret,
|
|
33
|
+
certificate: config.ssl_certificate,
|
|
34
|
+
private_key: config.ssl_private_key,
|
|
35
|
+
environment: config.environment,
|
|
36
|
+
base_url: config.base_url,
|
|
37
|
+
auth_base_url: config.auth_base_url,
|
|
38
|
+
token_path: config.token_path,
|
|
39
|
+
boleto_path: config.boleto_path,
|
|
40
|
+
pix_path: config.pix_path,
|
|
41
|
+
dda_path: config.dda_path,
|
|
42
|
+
partner_software_name: config.partner_software_name,
|
|
43
|
+
partner_software_version: config.partner_software_version,
|
|
44
|
+
pix_key: config.pix_key,
|
|
45
|
+
billing_scheme: config.billing_scheme
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def from_env(**overrides)
|
|
50
|
+
@config_block_ran = true
|
|
51
|
+
@client = Client.from_env(**overrides)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def boletos = client.boletos
|
|
55
|
+
def pix = client.pix
|
|
56
|
+
def dda = client.dda
|
|
57
|
+
|
|
58
|
+
def boleto_request(params = {})
|
|
59
|
+
Boleto::Request.new(params)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def build_default_client
|
|
65
|
+
raise ConfigurationError, "No global client configured"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/sig/c6_bank.rbs
ADDED