inss_calculator 0.4.0 → 0.4.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 +4 -4
- data/.rubocop.yml +2 -1
- data/Gemfile.lock +2 -2
- data/README.md +15 -0
- data/lib/dinheiro.rb +303 -0
- data/lib/inss_calculator/decorator/text.rb +43 -0
- data/lib/inss_calculator/discount_previdence_calculator.rb +4 -0
- data/lib/inss_calculator/error/no_method_error.rb +5 -0
- data/lib/inss_calculator/version.rb +1 -1
- data/lib/inss_calculator.rb +4 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0c5d044bf05b0f50ac8c9b4b6fe0634e0f809fd18918fd84a8a15a5fcbfd09a
|
4
|
+
data.tar.gz: 56906b9378630a07cb21ab2fab31caf77511a2808b78d347270ccde37df6ea08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54a10e9bda6faff9e6ce0765aa5ae6ceb92dbd0fe333995312860acc68bb15a6c085eb0a17097a0937fdb56d392f4fb61f4912676ae77e80d2bfd387e17e244a
|
7
|
+
data.tar.gz: 1ed31865a00db8bd38a9b782bcd0d7cd2e899e3743b221de2de85e8ffcf391e3dfaa5fb7308d7763c0df02c777fbbbad1554ecf82a6bf61b087f39166c732cd3
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
inss_calculator (0.
|
4
|
+
inss_calculator (0.4.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
diff-lcs (1.5.1)
|
11
11
|
json (2.7.2)
|
12
12
|
language_server-protocol (3.17.0.3)
|
13
|
-
parallel (1.26.
|
13
|
+
parallel (1.26.3)
|
14
14
|
parser (3.3.4.2)
|
15
15
|
ast (~> 2.4.1)
|
16
16
|
racc
|
data/README.md
CHANGED
@@ -78,6 +78,21 @@ Desta forma, uma requisição que busca somente a primeira faixa salarial seria:
|
|
78
78
|
YourModel.where("salary <= ?", InssCalculator::FIRST_SALARY_LIMIT)
|
79
79
|
```
|
80
80
|
|
81
|
+
## Decorators
|
82
|
+
|
83
|
+
`InssCalculator::Decorator::Text` explica no formato de texto o que o trabalhador precisa saber.
|
84
|
+
Ideal para uso no parágrafo do HTML. Retire da view esta responsabildade e deixe com este decorator.
|
85
|
+
Você ainda tem acesso à classe original com `#calculator`.
|
86
|
+
|
87
|
+
```
|
88
|
+
calculator = InssCalculator::DiscountPrevidenceCalculator.new(3000)
|
89
|
+
text_decorator = InssCalculator::Decorator::Text.new(calculator)
|
90
|
+
text_decorator.present => "Com o salário de R$ 3.000,00, sua contribuição é de R$ 258,81. Seu salário líquido, portanto, é de R$ 2.741,19."
|
91
|
+
|
92
|
+
text_decorator.calculator => InssCalculator::DiscountPrevidenceCalculator.new(3000)
|
93
|
+
|
94
|
+
```
|
95
|
+
|
81
96
|
## Nota sobre trabalhar com números decimais em Ruby
|
82
97
|
|
83
98
|
Após investigar os resultados dos exemplos contábeis, concluiu-se que os números são truncados.
|
data/lib/dinheiro.rb
ADDED
@@ -0,0 +1,303 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Com base em https://github.com/tapajos/brazilian-rails/blob/master/brdinheiro/lib/brdinheiro/dinheiro.rb
|
4
|
+
class Dinheiro
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
attr_reader :quantia
|
8
|
+
|
9
|
+
FORMATO_VALIDO_BR = /^([R|r]\$\s*)?(([+-]?\d{1,3}(\.?\d{3})*))?(,\d{0,2})?$/
|
10
|
+
FORMATO_VALIDO_EUA = /^([R|r]\$\s*)?(([+-]?\d{1,3}(,?\d{3})*))?(\.\d{0,2})?$/
|
11
|
+
SEPARADOR_MILHAR = '.'
|
12
|
+
SEPARADOR_FRACIONARIO = ','
|
13
|
+
QUANTIDADE_DIGITOS = 3
|
14
|
+
PRECISAO_DECIMAL = 100
|
15
|
+
|
16
|
+
def initialize(quantia)
|
17
|
+
self.quantia = quantia
|
18
|
+
end
|
19
|
+
|
20
|
+
# Retorna o valor em Float quando uma coleção
|
21
|
+
# ou objeto é convertido para JSON
|
22
|
+
#
|
23
|
+
# Exemplo:
|
24
|
+
# produto = Produto.find 1
|
25
|
+
# produto.to_json // {"nome": "MacBook", "valor": 3500.0}
|
26
|
+
def as_json
|
27
|
+
to_f
|
28
|
+
end
|
29
|
+
|
30
|
+
# Retorna o valor armazenado em string.
|
31
|
+
#
|
32
|
+
# Exemplo:
|
33
|
+
# 1000.to_s ==> '1.000,00'
|
34
|
+
def to_s
|
35
|
+
inteiro_com_milhar(parte_inteira) + parte_decimal
|
36
|
+
end
|
37
|
+
|
38
|
+
# Compara com outro dinheiro se eh igual.
|
39
|
+
#
|
40
|
+
# Exemplo:
|
41
|
+
# um_real = Dinheiro.new(1)
|
42
|
+
# um_real == Dinheiro.new(1) ==> true
|
43
|
+
# um_real == Dinheiro.new(2) ==> false
|
44
|
+
def ==(other)
|
45
|
+
begin
|
46
|
+
other = Dinheiro.new(other) unless other.is_a?(Dinheiro)
|
47
|
+
rescue StandardError
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
@quantia == other.quantia
|
51
|
+
end
|
52
|
+
|
53
|
+
# Compara com outro dinheiro se eh maior ou menor.
|
54
|
+
#
|
55
|
+
# Exemplo:
|
56
|
+
# 1.real < 2.reais ==> true
|
57
|
+
# 1.real > 2.reais ==> false
|
58
|
+
# 2.real < 1.reais ==> false
|
59
|
+
# 2.real > 1.reais ==> true
|
60
|
+
def <=>(other)
|
61
|
+
other = Dinheiro.new(other) unless other.is_a?(Dinheiro)
|
62
|
+
@quantia <=> other.quantia
|
63
|
+
end
|
64
|
+
|
65
|
+
# Retorna a adicao entre dinheiros.
|
66
|
+
#
|
67
|
+
# Exemplo:
|
68
|
+
# 1.real + 1.real == 2.reais
|
69
|
+
# 1.real + 1 == 2.reais
|
70
|
+
def +(other)
|
71
|
+
Dinheiro.new(transforma_em_string_que_represente_a_quantia(@quantia + quantia_de(other)))
|
72
|
+
end
|
73
|
+
|
74
|
+
# Retorna a subtracao entre dinheiros.
|
75
|
+
#
|
76
|
+
# Exemplo:
|
77
|
+
# 10.reais - 2.reais == 8.reais
|
78
|
+
# 10.reais - 2 == 8.reais
|
79
|
+
def -(other)
|
80
|
+
Dinheiro.new(transforma_em_string_que_represente_a_quantia(@quantia - quantia_de(other)))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Retorna a multiplicacao entre dinheiros.
|
84
|
+
#
|
85
|
+
# Exemplo:
|
86
|
+
# 5.reais * 2 == 10.reais
|
87
|
+
# 5.reais * 2.reais == 10.reais
|
88
|
+
def *(other)
|
89
|
+
return Dinheiro.new(to_f * other) unless other.is_a? Dinheiro
|
90
|
+
|
91
|
+
other * to_f
|
92
|
+
end
|
93
|
+
|
94
|
+
# Retorna a divisao entre dinheiros.
|
95
|
+
#
|
96
|
+
# Exemplo:
|
97
|
+
# 5.reais / 2 == (2.5).reais
|
98
|
+
# 5.reais / 2.reais == DivisaPorNaoEscalarError
|
99
|
+
# 5.reais / 0 == ZeroDivisionError
|
100
|
+
#
|
101
|
+
# Veja também o método parcelar
|
102
|
+
def /(other)
|
103
|
+
raise DivisaPorNaoEscalarError unless other.is_a?(Numeric)
|
104
|
+
return @quantia / other if other.zero?
|
105
|
+
|
106
|
+
Dinheiro.new(to_f / other)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Retorna um array de dinheiro com as parcelas
|
110
|
+
#
|
111
|
+
# Exemplo:
|
112
|
+
# 6.reais.parcelar(2) == [3.reais, 3.reais]
|
113
|
+
# 6.reais.parcelar(2.reais) == DisivaPorNaoEscalarError
|
114
|
+
# 6.reais.parcelar(0) == ZeroDivisionError
|
115
|
+
def parcelar(numero_de_parcelar)
|
116
|
+
raise DivisaPorNaoEscalarError unless numero_de_parcelar.is_a?(Integer)
|
117
|
+
|
118
|
+
resto = @quantia % numero_de_parcelar
|
119
|
+
valor_menor = Dinheiro.new((@quantia / numero_de_parcelar) / 100.0)
|
120
|
+
valor_maior = Dinheiro.new((@quantia / numero_de_parcelar + 1) / 100.0)
|
121
|
+
[valor_menor] * (numero_de_parcelar - resto) + [valor_maior] * resto
|
122
|
+
end
|
123
|
+
|
124
|
+
# Escreve o valor por extenso.
|
125
|
+
#
|
126
|
+
# Exemplo:
|
127
|
+
# 1.real.to_extenso ==> 'um real'
|
128
|
+
# (100.58).to_extenso ==> 'cem reais e cinquenta e oito centavos'
|
129
|
+
def to_extenso
|
130
|
+
(@quantia / 100.0).por_extenso_em_reais
|
131
|
+
end
|
132
|
+
|
133
|
+
# Alias para o metodo to_extenso.
|
134
|
+
alias por_extenso to_extenso
|
135
|
+
|
136
|
+
# Alias para o metodo to_extenso.
|
137
|
+
alias por_extenso_em_reais to_extenso
|
138
|
+
|
139
|
+
# Verifica se o valor é zero.
|
140
|
+
def zero?
|
141
|
+
to_f.zero?
|
142
|
+
end
|
143
|
+
|
144
|
+
# Retorna um Float.
|
145
|
+
def to_f
|
146
|
+
to_s.gsub('.', '').gsub(',', '.').to_f
|
147
|
+
end
|
148
|
+
|
149
|
+
def coerce(outro) # :nodoc:
|
150
|
+
[Dinheiro.new(outro), self]
|
151
|
+
end
|
152
|
+
|
153
|
+
# Retorna a própria instância/
|
154
|
+
def real
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
# Alias para real.
|
159
|
+
alias reais real
|
160
|
+
|
161
|
+
# Retorna uma string formatada com sigla em valor monetário.
|
162
|
+
# Exemplo:
|
163
|
+
# Dinheiro.new(1).real_formatado ==> 'R$ 1,00'
|
164
|
+
# Dinheiro.new(-1).real_formatado ==> 'R$ -1,00'
|
165
|
+
def real_formatado
|
166
|
+
"R$ #{self}"
|
167
|
+
end
|
168
|
+
|
169
|
+
# Alias para real_formatado.
|
170
|
+
alias reais_formatado real_formatado
|
171
|
+
|
172
|
+
# Retorna uma string formatada com sigla em valor contábil.
|
173
|
+
#
|
174
|
+
# Exemplo:
|
175
|
+
# Dinheiro.new(1).real_contabil ==> 'R$ 1,00'
|
176
|
+
# Dinheiro.new(-1).real_contabil ==> 'R$ (1,00)'
|
177
|
+
def real_contabil
|
178
|
+
"R$ #{contabil}"
|
179
|
+
end
|
180
|
+
|
181
|
+
# Alias para real_contabil.
|
182
|
+
alias reais_contabeis real_contabil
|
183
|
+
|
184
|
+
# Retorna uma string formatada sem sigla.
|
185
|
+
#
|
186
|
+
# Exemplo:
|
187
|
+
# Dinheiro.new(1).contabil ==> '1,00'
|
188
|
+
# Dinheiro.new(-1).contabil ==> '(1,00)'
|
189
|
+
def contabil
|
190
|
+
if @quantia >= 0
|
191
|
+
to_s
|
192
|
+
else
|
193
|
+
"(#{to_s[1..]})"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Method missing para retorna um BigDecinal quando chamada .
|
198
|
+
def method_missing(symbol, *args) # :nodoc:
|
199
|
+
# Ex: Chama ao método valor_decimal()
|
200
|
+
if (symbol.to_s =~ /^(.*)_decimal$/) && args.empty?
|
201
|
+
BigDecimal quantia_sem_separacao_milhares.gsub(',', '.')
|
202
|
+
else
|
203
|
+
super.method_missing(symbol, *args)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def quantia_de(outro)
|
210
|
+
outro = outro.to_f if outro.is_a?(BigDecimal)
|
211
|
+
return outro.quantia if outro.is_a?(Dinheiro)
|
212
|
+
|
213
|
+
(outro * 100).round
|
214
|
+
end
|
215
|
+
|
216
|
+
def transforma_em_string_que_represente_a_quantia(quantia)
|
217
|
+
if /^([+-]?)(\d)$/ =~ quantia.to_s
|
218
|
+
return "#{::Regexp.last_match(1)}0.0#{::Regexp.last_match(2)}"
|
219
|
+
end
|
220
|
+
|
221
|
+
/^([+-]?)(\d*)(\d\d)$/ =~ quantia.to_s
|
222
|
+
"#{::Regexp.last_match(1)}#{::Regexp.last_match(2).to_i}.#{::Regexp.last_match(3)}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def quantia=(quantia)
|
226
|
+
@quantia = (quantia * 100).round if quantia.is_a?(Numeric)
|
227
|
+
@quantia = extrai_quantia_como_inteiro(quantia) if quantia.is_a?(String)
|
228
|
+
end
|
229
|
+
|
230
|
+
def parte_inteira
|
231
|
+
quantia_sem_separacao_milhares[0, quantia_sem_separacao_milhares.length - QUANTIDADE_DIGITOS]
|
232
|
+
end
|
233
|
+
|
234
|
+
def parte_decimal
|
235
|
+
quantia_sem_separacao_milhares[-QUANTIDADE_DIGITOS, QUANTIDADE_DIGITOS]
|
236
|
+
end
|
237
|
+
|
238
|
+
def inteiro_com_milhar(inteiro)
|
239
|
+
return inteiro if quantidade_de_passos(inteiro).zero?
|
240
|
+
|
241
|
+
resultado = ''
|
242
|
+
quantidade_de_passos(inteiro).times do |passo|
|
243
|
+
resultado = ".#{inteiro[-QUANTIDADE_DIGITOS + passo * -QUANTIDADE_DIGITOS, QUANTIDADE_DIGITOS]}#{resultado}"
|
244
|
+
end
|
245
|
+
resultado = inteiro[0, digitos_que_sobraram(inteiro)] + resultado
|
246
|
+
resultado.gsub(/^(-?)\./, '\1')
|
247
|
+
end
|
248
|
+
|
249
|
+
def quantia_sem_separacao_milhares
|
250
|
+
format('%.2f', (@quantia.to_f / PRECISAO_DECIMAL)).gsub(SEPARADOR_MILHAR, SEPARADOR_FRACIONARIO)
|
251
|
+
end
|
252
|
+
|
253
|
+
def quantidade_de_passos(inteiro)
|
254
|
+
resultado = inteiro.length / QUANTIDADE_DIGITOS
|
255
|
+
resultado = (resultado - 1) if (inteiro.length % QUANTIDADE_DIGITOS).zero?
|
256
|
+
resultado
|
257
|
+
end
|
258
|
+
|
259
|
+
def digitos_que_sobraram(inteiro)
|
260
|
+
inteiro.length - (quantidade_de_passos(inteiro) * QUANTIDADE_DIGITOS)
|
261
|
+
end
|
262
|
+
|
263
|
+
def quantia_valida?(quantia)
|
264
|
+
return false if quantia.is_a?(String) && !quantia_respeita_formato?(quantia)
|
265
|
+
|
266
|
+
quantia.is_a?(String) || quantia.is_a?(Numeric)
|
267
|
+
end
|
268
|
+
|
269
|
+
def extrai_quantia_como_inteiro(quantia)
|
270
|
+
return sem_milhar(::Regexp.last_match(2), ::Regexp.last_match(5), '.') if FORMATO_VALIDO_BR =~ quantia
|
271
|
+
return unless FORMATO_VALIDO_EUA =~ quantia
|
272
|
+
|
273
|
+
sem_milhar(::Regexp.last_match(2), ::Regexp.last_match(5), ',')
|
274
|
+
end
|
275
|
+
|
276
|
+
def sem_milhar(parte_inteira, parte_decimal, delimitador_de_milhar)
|
277
|
+
(inteiro(parte_inteira, delimitador_de_milhar) + decimal(parte_decimal)).to_i
|
278
|
+
end
|
279
|
+
|
280
|
+
def inteiro(inteiro_com_separador_milhar, separador)
|
281
|
+
return inteiro_com_separador_milhar.gsub(separador, '') unless inteiro_com_separador_milhar.blank?
|
282
|
+
|
283
|
+
''
|
284
|
+
end
|
285
|
+
|
286
|
+
def decimal(parte_fracionaria)
|
287
|
+
unless parte_fracionaria.blank?
|
288
|
+
return sem_delimitador_decimal(parte_fracionaria) if parte_fracionaria.length == 3
|
289
|
+
return "#{sem_delimitador_decimal(parte_fracionaria)}0" if parte_fracionaria.length == 2
|
290
|
+
end
|
291
|
+
'00'
|
292
|
+
end
|
293
|
+
|
294
|
+
def sem_delimitador_decimal(parte_fracionaria)
|
295
|
+
parte_fracionaria.to_s.gsub(/[.|,]/, '')
|
296
|
+
end
|
297
|
+
|
298
|
+
def quantia_respeita_formato?(quantia)
|
299
|
+
return true if FORMATO_VALIDO_BR.match(quantia) || FORMATO_VALIDO_EUA.match(quantia)
|
300
|
+
|
301
|
+
false
|
302
|
+
end
|
303
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InssCalculator
|
4
|
+
# It extends Calculator contribution to a presentable format.
|
5
|
+
module Decorator
|
6
|
+
require 'forwardable'
|
7
|
+
# InssCalculator::Decorator::Text implements the same Calculator interface
|
8
|
+
# and its #present method presents the contribution result in a text format.
|
9
|
+
class Text
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def_delegators :@calculator, :salary, :net_salary
|
13
|
+
|
14
|
+
attr_reader :calculator
|
15
|
+
|
16
|
+
def initialize(inss_calculator)
|
17
|
+
@calculator = inss_calculator
|
18
|
+
end
|
19
|
+
|
20
|
+
def contribution
|
21
|
+
Dinheiro.new(calculator.contribution).real_formatado
|
22
|
+
end
|
23
|
+
|
24
|
+
def present
|
25
|
+
"#{salary_text} #{contribution_text} #{net_salary_text}"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def salary_text
|
31
|
+
"Com o salário de #{Dinheiro.new(calculator.salary).real_formatado},"
|
32
|
+
end
|
33
|
+
|
34
|
+
def contribution_text
|
35
|
+
"sua contribuição é de #{Dinheiro.new(calculator.contribution).real_formatado}."
|
36
|
+
end
|
37
|
+
|
38
|
+
def net_salary_text
|
39
|
+
"Seu salário líquido, portanto, é de #{Dinheiro.new(calculator.net_salary).real_formatado}."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/inss_calculator.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'inss_calculator/version'
|
4
|
+
require_relative './dinheiro'
|
4
5
|
require_relative 'inss_calculator/discount_calculator_base'
|
5
6
|
require_relative 'inss_calculator/discount_previdence_calculator'
|
6
7
|
require_relative 'inss_calculator/public_inss_calculator'
|
@@ -12,6 +13,7 @@ require_relative 'inss_calculator/fifth_discount_calculator'
|
|
12
13
|
require_relative 'inss_calculator/sixth_discount_calculator'
|
13
14
|
require_relative 'inss_calculator/seventh_discount_calculator'
|
14
15
|
require_relative 'inss_calculator/eigth_discount_calculator'
|
16
|
+
require_relative 'inss_calculator/decorator/text'
|
15
17
|
|
16
18
|
module InssCalculator
|
17
19
|
class Error < StandardError; end
|
@@ -40,3 +42,5 @@ module InssCalculator
|
|
40
42
|
EIGTH_SALARY_BASE = 52_000.55
|
41
43
|
EIGTH_SALARY_LIMIT = Float::INFINITY
|
42
44
|
end
|
45
|
+
|
46
|
+
require_relative 'inss_calculator/error/no_method_error'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inss_calculator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paulo Felipe Souza
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Calcula o valor a descontar de acordo com a faixa salarial. Os novos
|
14
14
|
valores corrente em 2024.
|
@@ -29,10 +29,13 @@ files:
|
|
29
29
|
- README.md
|
30
30
|
- Rakefile
|
31
31
|
- inss_calculator.gemspec
|
32
|
+
- lib/dinheiro.rb
|
32
33
|
- lib/inss_calculator.rb
|
34
|
+
- lib/inss_calculator/decorator/text.rb
|
33
35
|
- lib/inss_calculator/discount_calculator_base.rb
|
34
36
|
- lib/inss_calculator/discount_previdence_calculator.rb
|
35
37
|
- lib/inss_calculator/eigth_discount_calculator.rb
|
38
|
+
- lib/inss_calculator/error/no_method_error.rb
|
36
39
|
- lib/inss_calculator/fifth_discount_calculator.rb
|
37
40
|
- lib/inss_calculator/first_discount_calculator.rb
|
38
41
|
- lib/inss_calculator/fourth_discount_calculator.rb
|