br_boleto 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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +15 -0
  3. data/Gemfile.lock +145 -0
  4. data/History.txt +4 -0
  5. data/LICENSE +20 -0
  6. data/README.markdown +156 -0
  7. data/Rakefile +8 -0
  8. data/br_boleto.gemspec +26 -0
  9. data/lib/br_boleto.rb +87 -0
  10. data/lib/br_boleto/calculos/digitos.rb +35 -0
  11. data/lib/br_boleto/calculos/fator_vencimento.rb +129 -0
  12. data/lib/br_boleto/calculos/fatores_de_multiplicacao.rb +67 -0
  13. data/lib/br_boleto/calculos/linha_digitavel.rb +158 -0
  14. data/lib/br_boleto/calculos/modulo10.rb +83 -0
  15. data/lib/br_boleto/calculos/modulo11.rb +54 -0
  16. data/lib/br_boleto/calculos/modulo11_fator3197.rb +88 -0
  17. data/lib/br_boleto/calculos/modulo11_fator_de2a7.rb +97 -0
  18. data/lib/br_boleto/calculos/modulo11_fator_de2a9.rb +83 -0
  19. data/lib/br_boleto/calculos/modulo11_fator_de2a9_resto_zero.rb +29 -0
  20. data/lib/br_boleto/calculos/modulo11_fator_de9a2.rb +65 -0
  21. data/lib/br_boleto/calculos/modulo11_fator_de9a2_resto_x.rb +55 -0
  22. data/lib/br_boleto/calculos/modulo_numero_de_controle.rb +117 -0
  23. data/lib/br_boleto/core/boleto.rb +558 -0
  24. data/lib/br_boleto/core/sicoob.rb +169 -0
  25. data/lib/br_boleto/version.rb +8 -0
  26. data/test/br_boleto/calculos/digitos_test.rb +15 -0
  27. data/test/br_boleto/calculos/fator_vencimento_test.rb +56 -0
  28. data/test/br_boleto/calculos/fatores_de_multiplicacao_test.rb +66 -0
  29. data/test/br_boleto/calculos/linha_digitavel_test.rb +58 -0
  30. data/test/br_boleto/calculos/modulo10_test.rb +54 -0
  31. data/test/br_boleto/calculos/modulo11_fator3197_test.rb +43 -0
  32. data/test/br_boleto/calculos/modulo11_fator_de2a7_test.rb +44 -0
  33. data/test/br_boleto/calculos/modulo11_fator_de2a9_resto_zero_test.rb +40 -0
  34. data/test/br_boleto/calculos/modulo11_fator_de2a9_test.rb +68 -0
  35. data/test/br_boleto/calculos/modulo11_fator_de9a2_resto_x_test.rb +38 -0
  36. data/test/br_boleto/calculos/modulo11_fator_de9a2_test.rb +32 -0
  37. data/test/br_boleto/calculos/modulo11_test.rb +28 -0
  38. data/test/br_boleto/calculos/modulo_numero_de_controle_test.rb +38 -0
  39. data/test/br_boleto/core/boleto_test.rb +221 -0
  40. data/test/br_boleto/core/sicoob_test.rb +138 -0
  41. data/test/factories/boleto.rb +22 -0
  42. data/test/factories/boleto_sicoob.rb +23 -0
  43. data/test/inheritance/boleto_test.rb +15 -0
  44. data/test/inheritance/sicoob_test.rb +25 -0
  45. data/test/test_helper.rb +37 -0
  46. metadata +151 -0
@@ -0,0 +1,169 @@
1
+ # encoding: utf-8
2
+ module BrBoleto
3
+ module Core
4
+ # Implementação de emissão de boleto bancário pelo Banco Sicoob.
5
+ #
6
+ # === Documentação Implementada
7
+ #
8
+ # A documentação na qual essa implementação foi baseada está localizada na pasta
9
+ # 'documentacoes_dos_boletos/sicoob' dentro dessa biblioteca.
10
+ #
11
+ # === Código da Carteira
12
+ #
13
+ # '1' - Cobrança SEM registro
14
+ # '9' - Cobrança COM registro
15
+ #
16
+ class Sicoob < Boleto
17
+ # Tamanho máximo de uma agência no Banco Sicoob.
18
+ # <b>Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente.</b>
19
+ #
20
+ # @return [Fixnum] 4
21
+ #
22
+ def self.tamanho_maximo_agencia
23
+ 4
24
+ end
25
+
26
+ # Tamanho máximo do codigo cedente no Banco Sicoob.
27
+ # <b>Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente.</b>
28
+ #
29
+ # @return [Fixnum] 7
30
+ #
31
+ def self.tamanho_maximo_codigo_cedente
32
+ 7
33
+ end
34
+
35
+ # Tamanho máximo do numero do documento no Boleto.
36
+ # <b>Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente.</b>
37
+ #
38
+ # @return [Fixnum] 6
39
+ #
40
+ def self.tamanho_maximo_numero_documento
41
+ 7
42
+ end
43
+
44
+ # <b>Carteiras suportadas.</b>
45
+ #
46
+ # <b>Método criado para validar se a carteira informada é suportada.</b>
47
+ #
48
+ # @return [Array]
49
+ #
50
+ def self.carteiras_suportadas
51
+ %w[1 3]
52
+ end
53
+
54
+ # Validações para os campos abaixo:
55
+ #
56
+ # * Agencia
57
+ # * Codigo Cedente
58
+ # * Número do documento
59
+ #
60
+ # Se você quiser sobrescrever os metodos, <b>ficará a sua responsabilidade.</b>
61
+ # Basta você sobrescrever os métodos de validação:
62
+ #
63
+ # class Sicoob < BrBoleto::Core::Sicoob
64
+ # def self.tamanho_maximo_agencia
65
+ # 6
66
+ # end
67
+ #
68
+ # def self.tamanho_maximo_codigo_cedente
69
+ # 9
70
+ # end
71
+ #
72
+ # def self.tamanho_maximo_numero_documento
73
+ # 10
74
+ # end
75
+ # end
76
+ #
77
+ # Obs.: Mudar as regras de validação podem influenciar na emissão do boleto em si.
78
+ # Talvez você precise analisar o efeito no #codigo_de_barras e na #linha_digitável (ambos podem ser
79
+ # sobreescritos também).
80
+ #
81
+ validates :agencia, :codigo_cedente, presence: true
82
+
83
+ validates :agencia, length: { maximum: tamanho_maximo_agencia }, if: :deve_validar_agencia?
84
+ validates :codigo_cedente, length: { maximum: tamanho_maximo_codigo_cedente }, if: :deve_validar_codigo_cedente?
85
+ validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento }, if: :deve_validar_numero_documento?
86
+
87
+ validates :carteira, inclusion: { in: ->(object) { object.class.carteiras_suportadas } }, if: :deve_validar_carteira?
88
+
89
+ # @return [String] 4 caracteres
90
+ #
91
+ def agencia
92
+ @agencia.to_s.rjust(4, '0') if @agencia.present?
93
+ end
94
+
95
+ # @return [String] 7 caracteres
96
+ # O Código do cedente é o mesmo que o codigo do beneficiário
97
+ def codigo_cedente
98
+ @codigo_cedente.to_s.rjust(7, '0') if @codigo_cedente.present?
99
+ end
100
+
101
+ # @return [String] 6 caracteres
102
+ #
103
+ def numero_documento
104
+ @numero_documento.to_s.rjust(7, '0') if @numero_documento.present?
105
+ end
106
+
107
+ # @return [String] Código do Banco descrito na documentação.
108
+ #
109
+ def codigo_banco
110
+ '756'
111
+ end
112
+
113
+ # @return [String] Dígito do código do banco descrito na documentação.
114
+ #
115
+ def digito_codigo_banco
116
+ '0'
117
+ end
118
+
119
+ # Campo Agência / Código do Cedente
120
+ #
121
+ # @return [String]
122
+ #
123
+ def agencia_codigo_cedente
124
+ "#{agencia} / #{codigo_cedente}"
125
+ end
126
+
127
+ # O nosso número descrino na documentação é formado pelo dois ultimos digitos do ano autal e
128
+ # por outros 6 digitos que o clinte usara para numerar os documentos, assim sendo composto por 8 dígitos.
129
+ #
130
+ # @return [String]
131
+ #
132
+ def nosso_numero
133
+ "#{numero_documento}-#{digito_verificador_nosso_numero}"
134
+ end
135
+
136
+
137
+ # === Código de barras do banco
138
+ #
139
+ # ___________________________________________________________
140
+ # | Posição | Tamanho | Descrição |
141
+ # |---------|---------|---------------------------------------|
142
+ # | 20 - 20 | 01 | Código da carteira |
143
+ # | 21 - 24 | 04 | Código da agência |
144
+ # | 25 - 26 | 02 | Código da modalidade de cobrança (01) |
145
+ # | 27 - 33 | 07 | Código do Cedente |
146
+ # | 34 - 41 | 08 | Nosso Número do título |
147
+ # | 42 - 44 | 03 | Número da Parcela do Título (001) |
148
+ # |___________________________________________________________|
149
+ #
150
+ # @return [String]
151
+ #
152
+ def codigo_de_barras_do_banco
153
+ "#{carteira}#{agencia}#{modalidade_cobranca}#{codigo_cedente}#{nosso_numero.gsub('-','')}#{parcelas}"
154
+ end
155
+
156
+ def digito_verificador_nosso_numero
157
+ BrBoleto::Calculos::Modulo11Fator3197.new("#{agencia}#{codigo_cedente.rjust(10, '0')}#{numero_documento}")
158
+ end
159
+
160
+ def modalidade_cobranca
161
+ '01'
162
+ end
163
+
164
+ def parcelas
165
+ '001'
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,8 @@
1
+ module BrBoleto
2
+ module Version
3
+ MAJOR = 0 #inclui alterações de API e pode quebrar compatibilidade com versões anteriores
4
+ MINOR = 1 #inclui novas funcionalidades, sem quebrar APIs existentes
5
+ PATCH = 0 #corrige bugs ou traz melhorias em implementações já existentes
6
+ CURRENT = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ describe BrBoleto::Calculos::Digitos do
5
+ (0..9).each do |number|
6
+ it "should return self when is #{number}" do
7
+ BrBoleto::Calculos::Digitos.new(number).sum.must_equal number
8
+ end
9
+ end
10
+ { 11 => 2, '18' => 9, 99 => 18, '58' => 13, 112 => 4, '235' => 10 }.each do |number, expecting|
11
+ it "should sum the sum of the digits when is '#{number}', expecting to be '#{expecting}'" do
12
+ BrBoleto::Calculos::Digitos.new(number).sum.must_equal expecting
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ describe BrBoleto::Calculos::FatorVencimento do
5
+ describe "#base_date" do
6
+ it "should be 1997-10-07" do
7
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2012-02-01")).base_date.must_equal Date.new(1997, 10, 7)
8
+ end
9
+ end
10
+
11
+ describe "#calculate" do
12
+ it 'should return an empty string when passing nil value' do
13
+ BrBoleto::Calculos::FatorVencimento.new(nil).must_equal ''
14
+ end
15
+
16
+ it 'should return an empty string when passing empty value' do
17
+ BrBoleto::Calculos::FatorVencimento.new('').must_equal ''
18
+ end
19
+
20
+ it "should calculate the days between expiration date and base date" do
21
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2012-12-2")).must_equal "5535"
22
+ end
23
+
24
+ it "should calculate equal to itau documentation example" do
25
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2000-07-04")).must_equal "1001"
26
+ end
27
+
28
+ it "should calculate equal to itau documentation last section of the docs" do
29
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2002-05-01")).must_equal "1667"
30
+ end
31
+
32
+ it "should calculate to the maximum date equal to itau documentation example" do
33
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2025-02-21")).must_equal "9999"
34
+ end
35
+
36
+ it "should calculate the days between expiration date one year ago" do
37
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2011-05-25")).must_equal "4978"
38
+ end
39
+
40
+ it "should calculate the days between expiration date two years ago" do
41
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2010-10-02")).must_equal "4743"
42
+ end
43
+
44
+ it "should calculate the days between expiration date one year from now" do
45
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2013-02-01")).must_equal "5596"
46
+ end
47
+
48
+ it "should calculate the days between expiration date eigth years from now" do
49
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("2020-02-01")).must_equal "8152"
50
+ end
51
+
52
+ it "should calculate the days between expiration date formating with 4 digits" do
53
+ BrBoleto::Calculos::FatorVencimento.new(Date.parse("1997-10-08")).must_equal "0001"
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ describe BrBoleto::Calculos::FatoresDeMultiplicacao do
5
+ context 'with factors of 2 and 1' do
6
+ let(:factors) { [2, 1] }
7
+
8
+ context 'with one digit' do
9
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(1, fatores: factors) }
10
+
11
+ it { subject.must_equal [2] }
12
+ end
13
+
14
+ context 'with four digits' do
15
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(1234, fatores: factors) }
16
+
17
+ it { subject.must_equal [1, 4, 3, 8] }
18
+ end
19
+
20
+ context 'with five digits' do
21
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(11385, fatores: factors) }
22
+
23
+ it { subject.must_equal [2, 1, 6, 8, 10] }
24
+ end
25
+
26
+ context 'with ten digits' do
27
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(1234567890, fatores: factors) }
28
+
29
+ it { subject.must_equal [1, 4, 3, 8, 5, 12, 7, 16, 9, 0] }
30
+ end
31
+ end
32
+
33
+ context 'with factors of 2..9' do
34
+ let(:factors) { (2..9).to_a }
35
+
36
+ context 'with one digit' do
37
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(4, fatores: factors) }
38
+
39
+ it { subject.must_equal [8] }
40
+ end
41
+
42
+ context 'with four digits' do
43
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(1864, fatores: factors) }
44
+
45
+ it { subject.must_equal [ 5, 32, 18, 8] }
46
+ end
47
+
48
+ context 'with ten digits' do
49
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(1234567890, fatores: factors) }
50
+ end
51
+
52
+ context 'with bradesco documentation example' do
53
+ let(:bradesco_example) { '9999101200000350007772130530150081897500000' }
54
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(bradesco_example, fatores: factors) }
55
+
56
+ it { subject.must_equal [36, 27, 18, 81, 8, 0, 6, 10, 0, 0, 0, 0, 0, 21, 30, 0, 0, 0, 14, 63, 56, 14, 6, 15, 0, 15, 6, 0, 8, 35, 0, 0, 32, 3, 16, 81, 56, 35, 0, 0, 0, 0, 0] }
57
+ end
58
+
59
+ context 'with itau documentation example' do
60
+ let(:itau_example) { '3419166700000123451101234567880057123457000' }
61
+ subject { BrBoleto::Calculos::FatoresDeMultiplicacao.new(itau_example, fatores: factors) }
62
+
63
+ it { subject.must_equal [12, 12, 2, 81, 8, 42, 36, 35, 0, 0, 0, 0, 0, 7, 12, 15, 16, 15, 2, 9, 0, 7, 12, 15, 16, 15, 12, 63, 64, 56, 0, 0, 20, 21, 2, 18, 24, 28, 30, 35, 0, 0, 0] }
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ module BrBoleto
5
+ module Calculos
6
+ describe LinhaDigitavel do
7
+ context "using the Itau documentation example" do
8
+ subject { LinhaDigitavel.new('34196166700000123451091234567880057123457000') }
9
+
10
+ it { subject.must_equal '34191.09123 34567.880058 71234.570001 6 16670000012345' }
11
+ end
12
+
13
+ context "using the Bradesco documentation example" do
14
+ subject { LinhaDigitavel.new('99991101200000350007772130530150081897500000') }
15
+
16
+ it { subject.must_equal '99997.77213 30530.150082 18975.000003 1 10120000035000' }
17
+ end
18
+
19
+ context "using the HSBC documentation example" do
20
+ subject { LinhaDigitavel.new('39998100100000311551111122222500546666666001') }
21
+
22
+ it { subject.must_equal '39991.11119 22222.500542 66666.660015 8 10010000031155' }
23
+ end
24
+
25
+ context "using the Caixa documentation example" do
26
+ subject { LinhaDigitavel.new('10491107400000160000001100128701000901200200') }
27
+
28
+ it { subject.must_equal '10490.00118 00128.701000 09012.002003 1 10740000016000' }
29
+ end
30
+
31
+ describe "when 'codigo_de_barras' invalid" do
32
+ context "when is empty" do
33
+ subject { LinhaDigitavel.new('') }
34
+
35
+ it { subject.must_equal '' }
36
+ end
37
+
38
+ context "when nil" do
39
+ subject { LinhaDigitavel.new(nil) }
40
+
41
+ it { subject.must_equal '' }
42
+ end
43
+
44
+ context "when have less than 44 positions" do
45
+ subject { LinhaDigitavel.new('121212121') }
46
+
47
+ it { subject.must_equal '' }
48
+ end
49
+
50
+ context "when have more than 44 positions" do
51
+ subject { LinhaDigitavel.new('12345678901234567890123456789012345678901234567890') }
52
+
53
+ it { subject.must_equal '' }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ module BrBoleto
5
+ module Calculos
6
+ describe Modulo10 do
7
+ it "should accept the examples by the 'Itau documentation'" do
8
+ Modulo10.new('341911012').must_equal '1'
9
+ Modulo10.new('3456788005').must_equal '8'
10
+ Modulo10.new('7123457000').must_equal '1'
11
+ end
12
+
13
+ it "should accept the example from Banrisul" do
14
+ Modulo10.new('00009274').must_equal '2'
15
+ end
16
+
17
+ it "returns zero when number is 0" do
18
+ Modulo10.new('0').must_equal '0'
19
+ end
20
+
21
+ it "returns zero when mod 10 is zero" do
22
+ Modulo10.new('99906').must_equal '0'
23
+ end
24
+
25
+ it "calculate when number had 1 digit" do
26
+ Modulo10.new('1').must_equal '8'
27
+ end
28
+
29
+ it "calculate when number had 2 digits" do
30
+ Modulo10.new('10').must_equal '9'
31
+ end
32
+
33
+ it "calculate when number had 3 digits" do
34
+ Modulo10.new('994').must_equal '4'
35
+ end
36
+
37
+ it "calculate when number had 5 digits" do
38
+ Modulo10.new('97831').must_equal '2'
39
+ end
40
+
41
+ it "calculate when number had 6 digits" do
42
+ Modulo10.new('147966').must_equal '6'
43
+ end
44
+
45
+ it "calculate when number had 10 digits" do
46
+ Modulo10.new('3456788005').must_equal '8'
47
+ end
48
+
49
+ it "should accept numbers too" do
50
+ Modulo10.new(12345).must_equal '5'
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ module BrBoleto
5
+ module Calculos
6
+ describe Modulo11Fator3197 do
7
+ context 'with Sicoob documentation example' do
8
+ subject { Modulo11Fator3197.new('000100000000190000021') }
9
+
10
+ it { subject.must_equal '8' }
11
+ end
12
+
13
+ context "quando o resultado do mod_division for 0 então deve retornar zero e não o resultado do total" do
14
+ subject { Modulo11Fator3197.new('123') }
15
+ before do
16
+ Modulo11Fator3197.any_instance.stubs(:mod_division).returns(0)
17
+ Modulo11Fator3197.any_instance.stubs(:total).returns(9)
18
+ end
19
+ it { subject.must_equal '0' }
20
+ end
21
+
22
+ context "quando o resultado do mod_division for 1 então deve retornar zero e não o resultado do total" do
23
+ subject { Modulo11Fator3197.new('123') }
24
+ before do
25
+ Modulo11Fator3197.any_instance.stubs(:mod_division).returns(1)
26
+ Modulo11Fator3197.any_instance.stubs(:total).returns(9)
27
+ end
28
+ it { subject.must_equal '0' }
29
+ end
30
+
31
+ [1..9].each do |numero|
32
+ context "quando o resultado do mod_division for #{numero} então deve o resultado do total" do
33
+ subject { Modulo11Fator3197.new('123') }
34
+ before do
35
+ Modulo11Fator3197.any_instance.stubs(:mod_division).returns(numero)
36
+ Modulo11Fator3197.any_instance.stubs(:total).returns(9)
37
+ end
38
+ it { subject.must_equal '9' }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end