abank 0.2.3 → 0.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90945827ff39ea567dd16f073018ef56215da38498e9ca317a2aff12a23e9a6d
4
- data.tar.gz: a2797459015e62c0a3bacc5eb2897ca58b52be346d885ce2494d9dd81cc08ba0
3
+ metadata.gz: f1720d3e8b1de4bc6ea635712404363e460b3550af47a665a06652fae028f917
4
+ data.tar.gz: eef494213d2f5bf45887a1f643ec2f1becf2d470e9cc5451c2412dd41d9696c2
5
5
  SHA512:
6
- metadata.gz: 87b7130b7a34943a80dad48903c083b5a06074f35d951575d435d4c4f58a466141bf0ef3021bca22515110e14cd179c64d7991292207d1fb029e309832d3258b
7
- data.tar.gz: 48562e6cdae584b35bacea3c9a7ab5149922c244fe1b6248b57527577c288675e2da1b9eb082e7bd5ee9bb075b26199a34368e52cc3a3d18bcf575e9369fd6c7
6
+ metadata.gz: eb2aa5a87322b5cb27fb2fac24cd99d5288eb3be339a0976cd2d2cd12c3ee46b63c2e09e8060c16dd3f07197ba837ecf6fa612a658f86cb3c7875a5546dd16b5
7
+ data.tar.gz: 9498f7fa1b1a5cbdf4c56b39cd770073eb13642d669847fecdd5a1b3285dd3ffc15fb0e6437a8e2758d6223e4e128e7eb0664e6f6ffb42cc73d3d1ce46380ea9
@@ -0,0 +1,29 @@
1
+ AllCops:
2
+ EnabledByDefault: true
3
+
4
+ Style/ClassAndModuleChildren:
5
+ EnforcedStyle: compact
6
+
7
+ Style/Copyright:
8
+ Enabled: false
9
+
10
+ Style/DocumentationMethod:
11
+ Enabled: false
12
+
13
+ Style/MethodCallWithArgsParentheses:
14
+ Enabled: false
15
+
16
+ Style/ConstantVisibility:
17
+ Enabled: false
18
+
19
+ Layout/MultilineMethodArgumentLineBreaks:
20
+ Enabled: false
21
+
22
+ Layout/MultilineHashKeyLineBreaks:
23
+ Enabled: false
24
+
25
+ Layout/FirstMethodParameterLineBreak:
26
+ Enabled: false
27
+
28
+ Layout/FirstHashElementLineBreak:
29
+ Enabled: false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abank (0.2.3)
4
+ abank (0.2.4)
5
5
  google-cloud-bigquery
6
6
  roo
7
7
  thor
@@ -17,7 +17,7 @@ GEM
17
17
  declarative-option (0.1.0)
18
18
  faraday (1.0.1)
19
19
  multipart-post (>= 1.2, < 3)
20
- google-api-client (0.39.3)
20
+ google-api-client (0.39.5)
21
21
  addressable (~> 2.5, >= 2.5.1)
22
22
  googleauth (~> 0.9)
23
23
  httpclient (>= 2.8.1, < 3.0)
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thor'
4
- require 'abank/bigquery'
5
- require 'abank/folhacalculo'
4
+ require 'abank/big'
5
+ require 'abank/contrato'
6
+ require 'abank/folha'
7
+ require 'abank/rendas'
6
8
  require 'abank/version'
7
9
 
8
10
  # @author Hernani Rodrigues Vaz
@@ -13,78 +15,86 @@ module Abank
13
15
 
14
16
  # CLI para carregar folhas calculo comuns no bigquery
15
17
  class CLI < Thor
18
+ desc 'tag', 'classifica movimentos no bigquery'
19
+ # classifica movimentos no bigquery
20
+ def tag
21
+ Big.new(i: true).mv_classifica
22
+ end
23
+
24
+ desc 'rendas', 'atualiza rendas no bigquery'
25
+ # atualiza rendas no bigquery
26
+ def rendas
27
+ Big.new.re_atualiza
28
+ end
29
+
30
+ desc 'apaga', 'apaga movimentos no bigquery'
31
+ option :k, banner: 'k1[,k2,...]', required: true,
32
+ desc: 'Keys movimentos a apagar'
33
+ # apaga movimentos no bigquery
34
+ def apaga
35
+ Big.new(k: options[:k]).mv_apaga
36
+ end
37
+
16
38
  desc 'load', 'carrega dados da folha calculo no bigquery'
17
39
  option :d, banner: 'DIR', default: "/home/#{ID}/Downloads",
18
40
  desc: 'Onde procurar folhas calculo'
19
- option :x, banner: 'EXT', default: '.xlsx',
20
- desc: 'Extensao das folhas calculo'
21
- option :n, banner: 'NUM', type: :numeric, default: 0,
22
- desc: 'Correcao dias para data valor'
41
+ option :v, banner: 'DATA', default: '',
42
+ desc: 'data valor para movimentos a carregar'
43
+ option :g, banner: 'TAG', default: '',
44
+ desc: 'classificacao para movimentos a carregar'
23
45
  option :s, type: :boolean, default: false,
24
46
  desc: 'apaga linha similar no bigquery'
25
47
  option :e, type: :boolean, default: false,
26
48
  desc: 'apaga linha igual no bigquery'
27
49
  option :m, type: :boolean, default: false,
28
50
  desc: 'apaga linhas existencia multipla no bigquery'
29
- # processa folha calculo
51
+ # carrega folha calculo
30
52
  def load
31
- Dir.glob("#{options[:d]}/*#{options[:x]}").sort.each do |f|
32
- Bigquery.new(f, load_ops).processa
53
+ Dir.glob("#{options[:d]}/*.xlsx").sort.each do |f|
54
+ Big::Folha.new(f, load_ops).processa_folha
33
55
  end
34
56
  end
35
57
 
36
- desc 'mostra', 'mostra dados da folha calculo'
58
+ desc 'show', 'mostra dados da folha calculo'
37
59
  option :d, banner: 'DIR', default: "/home/#{ID}/Downloads",
38
60
  desc: 'Onde procurar folhas calculo'
39
- option :x, banner: 'EXT', default: '.xlsx',
40
- desc: 'Extensao das folhas calculo'
41
61
  # mostra folha calculo
42
- def mostra
43
- Dir.glob("#{options[:d]}/*#{options[:x]}").sort.each do |f|
44
- Bigquery.new(f).processa
62
+ def show
63
+ Dir.glob("#{options[:d]}/*.xlsx").sort.each do |f|
64
+ Big::Folha.new(f).processa_folha
45
65
  end
46
66
  end
47
67
 
48
- desc 'classifica', 'classifica movimentos no bigquery'
49
- # classifica movimentos no bigquery
50
- def classifica
51
- Bigquery.new('', { i: true }).classifica
52
- end
53
-
54
- desc 'atualiza', 'atualiza rendas no arquivo bigquery'
55
- # atualiza rendas no arquivo bigquery
56
- def atualiza
57
- Bigquery.new.atualiza
68
+ desc 'criare', 'cria contrato arrendamento/rendas no bigquery'
69
+ option :c, banner: 'CONTRATO', required: true,
70
+ desc: 'Identificador contrato arrendamento a criar'
71
+ option :t, type: :boolean, default: true,
72
+ desc: 'cria todas as rendas?'
73
+ option :v, banner: 'DATA', default: '',
74
+ desc: 'data contrato arrendamento a criar'
75
+ # cria contrato arrendamento/rendas no bigquery
76
+ def criare
77
+ Big::Contrato.new(options[:c], { t: options[:t], v: options[:v] }).re_cria
58
78
  end
59
79
 
60
- desc 'cria', 'cria contrato arrendamento/rendas no arquivo bigquery'
61
- option :r, banner: 'REN', required: true,
62
- desc: 'identificador contrato arrendamento a criar'
80
+ desc 'apagare', 'apaga contrato arrendamento/rendas no bigquery'
81
+ option :c, banner: 'CONTRATO', required: true,
82
+ desc: 'Identificador contrato arrendamento a apagar'
63
83
  option :t, type: :boolean, default: false,
64
- desc: 'trabalha com renda inicio ou todas'
65
- # cria contrato arrendamento/rendas no arquivo bigquery
66
- def cria
67
- Bigquery.new('', { r: options[:r], t: options[:t] }).cria
68
- end
69
-
70
- desc 'apaga', 'apaga contrato arrendamento/rendas no arquivo bigquery'
71
- option :r, banner: 'REN', required: true,
72
- desc: 'identificador contrato arrendamento a apagar'
73
- option :t, type: :boolean, default: false,
74
- desc: 'trabalha com renda inicio ou todas'
75
- # apaga contrato arrendamento/rendas no arquivo bigquery
76
- def apaga
77
- Bigquery.new('', { r: options[:r], t: options[:t] }).apaga
84
+ desc: 'apaga todas as rendas?'
85
+ # apaga contrato arrendamento/rendas no bigquery
86
+ def apagare
87
+ Big::Contrato.new(options[:c], { t: options[:t], v: '' }).re_apaga
78
88
  end
79
89
 
80
90
  no_commands do
81
- # @return [Hash] ops opcoes trabalho com linhas para load
91
+ # @return [Hash] opcoes trabalho com linhas para load
82
92
  def load_ops
83
- { s: options[:s], e: options[:e], m: options[:m],
84
- i: true, t: false, n: options[:n], r: '' }
93
+ { s: options[:s], e: options[:e], m: options[:m], i: true,
94
+ v: options[:v], g: options[:g] }
85
95
  end
86
96
  end
87
97
 
88
- default_task :mostra
98
+ default_task :rendas
89
99
  end
90
100
  end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'google/cloud/bigquery'
4
+
5
+ # class Contrato
6
+ class Abank::Big
7
+ DF = '%Y-%m-%d'
8
+
9
+ # @return [Google::Cloud::Bigquery] API bigquery
10
+ attr_reader :api
11
+ # @return [Hash] opcoes trabalho com linhas
12
+ attr_reader :opl
13
+
14
+ # @return [Google::Cloud::Bigquery::QueryJob] job bigquery
15
+ attr_reader :job
16
+ # @return [Google::Cloud::Bigquery::Data] lista devolvida pelo select
17
+ attr_reader :resultados
18
+
19
+ # @param [Hash] ops opcoes trabalho
20
+ # @option ops [Boolean] :s (false) apaga linha similar? (mv)
21
+ # @option ops [Boolean] :e (false) apaga linha igual? (mv)
22
+ # @option ops [Boolean] :m (false) apaga linhas existencia multipla? (mv)
23
+ # @option ops [Boolean] :i (false) insere linha nova? (mv)
24
+ # @option ops [String] :v ('') data valor (mv)/data contrato (re)
25
+ # @option ops [String] :g ('') classificacao movimentos (mv)
26
+ # @option ops [Boolean] :t (false) trabalha todoas as rendas? (re)
27
+ # @option ops [String] :k ('') keys movimentos a apagar (mv)
28
+ # @return [Big] acesso bigquery dataset
29
+ def initialize(ops = {})
30
+ @opl = ops
31
+ @api ||= Google::Cloud::Bigquery.new
32
+ p ['Big', ops, api]
33
+ end
34
+
35
+ # (see CLI#classifica)
36
+ def mv_classifica
37
+ return unless opl[:i]
38
+
39
+ i = dml('update hernanilr.ab.mv set mv.ct=tt.nct ' \
40
+ 'from (select * from hernanilr.ab.cl) as tt ' \
41
+ 'where mv.dl=tt.dl and mv.dv=tt.dv ' \
42
+ 'and mv.ds=tt.ds and mv.vl=tt.vl')
43
+ puts 'LINHAS CLASSIFICADAS ' + i.to_s
44
+ return unless i.positive?
45
+
46
+ re_atualiza
47
+ end
48
+
49
+ # (see CLI#atualiza)
50
+ def re_atualiza
51
+ r = re_join(lista_ativos)
52
+ if r.size.zero?
53
+ puts 'NAO EXISTEM RENDAS NOVAS'
54
+ else
55
+ puts 'RENDAS CRIADAS ' + dml('insert hernanilr.ab.re VALUES' + r).to_s
56
+ end
57
+ end
58
+
59
+ # (see CLI#apagamv)
60
+ def mv_apaga
61
+ e = ct_envolvidos
62
+ i = dml(sql_apaga_mv)
63
+ puts 'MOVIMENTOS APAGADOS ' + i.to_s
64
+ return unless i.positive? && e.count.positive?
65
+
66
+ e.map { |c| Contrato.new(c).re_apaga }
67
+
68
+ re_atualiza
69
+ end
70
+
71
+ def ct_envolvidos
72
+ sel(sql_sel_mv).group_by { |r| r[:ct] }
73
+ .delete_if { |k, _| !k || k[0] != 'r' }.keys
74
+ end
75
+
76
+ # @return [Array<Hash>] lista contratos com lista movimentos novos
77
+ def lista_ativos
78
+ sel(sql_ativos_re).map { |c| Contrato.new(c[:ct]).dados_contrato }.compact
79
+ end
80
+
81
+ # @param [Array<Hash>] lct lista contratos com lista movimentos novos
82
+ # @return [String] row formatada das novas rendas para inserir bigquery
83
+ def re_join(lct)
84
+ lct.map { |c| Contrato::Rendas.new(c).rendas }.flatten(1).join(',')
85
+ end
86
+
87
+ def sql_ativos_re
88
+ 'SELECT ct from hernanilr.ab.re group by 1 order by 1'
89
+ end
90
+
91
+ def sql_sel_mv
92
+ 'select * ' + sql_where_mv
93
+ end
94
+
95
+ # @return [String] sql apaga movimentos
96
+ def sql_apaga_mv
97
+ 'delete ' + sql_where_mv
98
+ end
99
+
100
+ # @return [String] parte sql para processamento movimentos
101
+ def sql_where_mv
102
+ "from hernanilr.ab.mv where #{sql_digest_mv} in(#{opl[:k]})"
103
+ end
104
+
105
+ def sql_digest_mv
106
+ 'FARM_FINGERPRINT(CONCAT(CAST(nc as STRING),' \
107
+ 'ds,CAST(dl as STRING),CAST(vl as STRING)))'
108
+ end
109
+
110
+ # cria job bigquery & verifica execucao
111
+ #
112
+ # @param [String] sql comando sql a executar
113
+ # @return [Boolean] job ok?
114
+ def job_bigquery?(sql)
115
+ p sql
116
+ @job = api.query_job(sql)
117
+ @job.wait_until_done!
118
+ puts @job.error['message'] if @job.failed?
119
+ @job.failed?
120
+ end
121
+
122
+ # executa Data Manipulation Language (DML) job no bigquery
123
+ #
124
+ # @param (see job_bigquery?)
125
+ # @return [Integer] numero linhas afetadas
126
+ def dml(sql)
127
+ job_bigquery?(sql) ? 0 : job.num_dml_affected_rows
128
+ end
129
+
130
+ # executa sql & devolve resultados do bigquery
131
+ #
132
+ # @param sql (see job_bigquery?)
133
+ # @param [Array] arr resultado quando da erro no bigquery
134
+ # @return [Google::Cloud::Bigquery::Data] resultado do sql num array<hash>
135
+ def sel(sql, arr = [])
136
+ @resultados = job_bigquery?(sql) ? arr : job.data
137
+ end
138
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ # class Big::Contrato
4
+ class Abank::Big::Contrato < Abank::Big
5
+ # @return [String] identificador contrato arrendamento
6
+ attr_reader :rct
7
+
8
+ # {:ct=>"r03000"}
9
+ def initialize(con, ops = { t: false, v: '' })
10
+ p ['Contrato', con, ops]
11
+ @rct = con
12
+ super(ops)
13
+ end
14
+
15
+ # (see CLI#cria)
16
+ def re_cria
17
+ if existe_contrato?
18
+ i = 0
19
+ puts 'JA EXISTE CONTRATO'
20
+ else
21
+ i = dml('insert into hernanilr.ab.re ' + sql_contrato_mv)
22
+ puts i.zero? ? 'NAO EXISTE CONTRATO' : "CONTRATO #{rct} INSERIDO"
23
+ end
24
+ return unless i.positive? && opl[:t]
25
+
26
+ re_atualiza
27
+ end
28
+
29
+ # (see CLI#apagare)
30
+ def re_apaga
31
+ puts "RENDAS #{rct} APAGADAS " + dml(sql_apaga_re).to_s
32
+ end
33
+
34
+ # @return [Hash] dados contrato & movimentos novos
35
+ def dados_contrato
36
+ c = sel(sql_last_re).first
37
+ sel(sql_novo_mv(c[:dl]))
38
+ return unless resultados.count.positive?
39
+
40
+ { mv: resultados }.merge(c)
41
+ end
42
+
43
+ def sql_last_re
44
+ 'select ct,DATE_SUB(DATE_SUB(dl,INTERVAL dias DAY)' \
45
+ ',INTERVAL IF(cnt=0,0,cnt-1) MONTH) as dc,ano,cnt,dl ' \
46
+ "from hernanilr.ab.re where ct='#{rct}' " \
47
+ 'order by ano desc,cnt desc limit 1'
48
+ end
49
+
50
+ def sql_novo_mv(mdl)
51
+ "select dl,vl from hernanilr.ab.mv where ct='#{rct}' " \
52
+ "and dl>='#{(mdl + 1).strftime(DF)}' order by dl,dv"
53
+ end
54
+
55
+ def existe_contrato?
56
+ sel(sql_contrato_re).count.positive?
57
+ end
58
+
59
+ def sql_contrato_re
60
+ "select * from hernanilr.ab.re where ct='#{rct}' and cnt=0"
61
+ end
62
+
63
+ # @return [String] sql obtem dados inicio contrato arrendamento
64
+ def sql_contrato_mv
65
+ if opl[:v].size.zero?
66
+ 'select ct,EXTRACT(YEAR FROM DATE_TRUNC(dl,MONTH)) as ano,0 as cnt' \
67
+ ',DATE_TRUNC(dl,MONTH) as dl,0 dias ' \
68
+ "from hernanilr.ab.mv where ct='#{rct}' order by dl limit 1"
69
+ else
70
+ "select '#{rct}' as ct" \
71
+ ",EXTRACT(YEAR FROM DATE '#{opl[:v]}') as ano,0 as cnt" \
72
+ ",DATE '#{opl[:v]}' as dl,0 dias "
73
+ end
74
+ end
75
+
76
+ def sql_apaga_re
77
+ "delete from hernanilr.ab.re where ct='#{rct}'" +
78
+ (opl[:t] ? '' : ' and cnt>0')
79
+ end
80
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'roo'
4
+
5
+ # class Big::Contrato
6
+ class Abank::Big::Folha < Abank::Big
7
+ HT = ['Data Lanc.', 'Data Valor', 'Descrição', 'Valor'].freeze
8
+ RF = '%<v3>-34.34s %<v4>8.2f'
9
+ EN = ' %<v1>20d'
10
+ ES = ' %<v1>-20.20s'
11
+
12
+ # @return [Roo::Excelx] folha calculo a processar
13
+ attr_reader :folha
14
+ # @return [Integer] numero conta
15
+ attr_reader :conta
16
+
17
+ # @return [Array] row folha calculo em processamento
18
+ attr_reader :row
19
+
20
+ def initialize(xls, ops = { s: false, e: false, m: false, i: false,
21
+ v: '', g: '' })
22
+ p ['Folha', xls, ops]
23
+ @folha = Roo::Spreadsheet.open(xls) if xls.size.positive?
24
+ @conta = xls.match?(/card/i) ? 2 : 1
25
+ super(ops)
26
+ end
27
+
28
+ # processa linhas folha calculo & classifica bigquery
29
+ def processa_folha
30
+ n = 0
31
+ folha.sheet(0).parse(header_search: HT) do |r|
32
+ n += 1
33
+ puts n == 1 ? "\n" + folha.info : processa_row(r)
34
+ end
35
+ mv_classifica
36
+ end
37
+
38
+ # processa linha folha calculo para arquivo
39
+ #
40
+ # @param (see corrige_hash)
41
+ # @return [String] texto informativo do processamento
42
+ def processa_row(has)
43
+ corrige_hash(has)
44
+ # pesquisa existencia linha folha calculo no bigquery
45
+ # array.count = 0 ==> pode carregar esta linha
46
+ # array.count = 1 ==> mais testes necessarios
47
+ # array.count > 1 ==> nao pode carregar esta linha
48
+ sel(sql_sel_mv, [{}, {}])
49
+ if row_naoexiste? then row_str + (insert_mv == 1 ? ' NOVA' : ' ERRO')
50
+ elsif row_simila? then row_similar
51
+ elsif row_existe? then row_existente
52
+ else row_multiplas
53
+ end
54
+ end
55
+
56
+ # corrige linha folha calculo para processamento
57
+ #
58
+ # @param [Hash] has da linha em processamento
59
+ def corrige_hash(has)
60
+ @row = has.values
61
+ @row[2] = row[2].strip
62
+ @row[3] = -1 * row[3] if conta > 1
63
+ end
64
+
65
+ # @return [String] linha folha calculo formatada
66
+ def row_str
67
+ "#{row[0].strftime(DF)} #{format(RF, v3: row[2], v4: row[3])}"
68
+ end
69
+
70
+ # @return [String] linha folha calculo similar
71
+ def row_similar
72
+ d = opl[:s] ? delete_mv : 0
73
+ row_str + ' SIMI' + str_apagadas(d) + str_extra_s(resultados.first[:ds])
74
+ end
75
+
76
+ # @return [String] linha folha calculo existente
77
+ def row_existente
78
+ d = opl[:e] ? delete_mv : 0
79
+ row_str + ' EXIS' + str_apagadas(d) + str_extra_n(resultados.first[:ky])
80
+ end
81
+
82
+ def str_extra_s(ext)
83
+ format(ES, v1: ext.strip)
84
+ end
85
+
86
+ def str_extra_n(ext)
87
+ format(EN, v1: ext)
88
+ end
89
+
90
+ # @return [String] linha folha calculo existencia multipla
91
+ def row_multiplas
92
+ d = opl[:m] ? delete_mv : 0
93
+ row_str + ' M(' + resultados.count.to_s + ')' + str_apagadas(d)
94
+ end
95
+
96
+ # @param [Integer] numero linhas apagadas
97
+ # @return [String] texto formatado linhas apagadas
98
+ def str_apagadas(num)
99
+ num.positive? ? ' A(' + num.to_s + ')' : ''
100
+ end
101
+
102
+ # @return [Boolean] linha folha calculo nao existe no bigquery?
103
+ def row_naoexiste?
104
+ resultados.count.zero?
105
+ end
106
+
107
+ # @return [Boolean] linha folha calculo existe no bigquery?
108
+ def row_existe?
109
+ resultados.count == 1 && resultados.first[:ds].strip == row[2]
110
+ end
111
+
112
+ # @return [Boolean] linha folha calculo existe parecida no bigquery?
113
+ def row_simila?
114
+ resultados.count == 1 && resultados.first[:ds].strip != row[2]
115
+ end
116
+
117
+ def sql_sel_mv
118
+ "select *,#{sql_digest_mv} as ky " + sql_where_mv
119
+ end
120
+
121
+ # @return [String] parte sql para processamento movimentos
122
+ def sql_where_mv
123
+ "from hernanilr.ab.mv where nc=#{conta} " \
124
+ "and dl='#{row[0].strftime(DF)}' " \
125
+ "and vl=#{row[3]}"
126
+ end
127
+
128
+ # @return [Integer] numero linhas inseridas
129
+ def insert_mv
130
+ return 1 unless opl[:i]
131
+
132
+ dml('insert hernanilr.ab.mv(dl,dv,ds,vl,nc,ano,mes,ct,tp) VALUES(' \
133
+ "'#{row[0].strftime(DF)}','#{dvc.strftime(DF)}','#{row[2]}',#{row[3]}" +
134
+ str_ins_pc)
135
+ end
136
+
137
+ # @return [Date] data valor corrigida
138
+ def dvc
139
+ opl[:v].size.zero? ? row[1] : Date.parse(opl[:v])
140
+ end
141
+
142
+ # @return [String] campos extra da linha bigquery
143
+ def str_ins_pc
144
+ ",#{conta},#{dvc.year},#{dvc.month},#{ctc},'#{tpc}')"
145
+ end
146
+
147
+ def ctc
148
+ opl[:g].size.zero? ? 'null' : ("'" + opl[:g] + "'")
149
+ end
150
+
151
+ def tpc
152
+ row[3].positive? ? 'c' : 'd'
153
+ end
154
+
155
+ # @return [Integer] numero linhas apagadas
156
+ def delete_mv
157
+ dml('delete ' + sql_where_mv + " and ds='#{resultados.first[:ds]}'")
158
+ end
159
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ # class Big::Renda
4
+ class Abank::Big::Contrato::Rendas < Abank::Big::Contrato
5
+ attr_reader :ren
6
+
7
+ # @return [Integer] ano renda
8
+ attr_reader :ran
9
+ # @return [Integer] mes renda
10
+ attr_reader :rcn
11
+ # @return [Float] valor renda mensal
12
+ attr_reader :rru
13
+
14
+ # @return [Integer] total de movimentos novos
15
+ attr_reader :mcn
16
+ # @return [Integer] movimento em tratamento
17
+ attr_reader :mpn
18
+ # @return [Date] data lancamento movimento em tratamento
19
+ attr_reader :mdl
20
+ # @return [Float] valor movimento em tratamento
21
+ attr_reader :mvl
22
+
23
+ # @return [Date] data contrato arrendamento
24
+ # {:mv=>[{:dl=>#<Date: 2020-03-02>, :vl=>0.3e2},...]
25
+ # ,:ct=>"r03000"
26
+ # ,:dc=>#<Date: 2020-03-01>
27
+ # ,:ano=>2020
28
+ # ,:cnt=>0
29
+ # ,:dl=>#<Date: 2020-03-01>}
30
+ def initialize(ren)
31
+ p ['Rendas', ren]
32
+ @ren = ren
33
+ super(ren[:ct])
34
+ end
35
+
36
+ # @param [Hash] con dados contrato & lista movimentos novos
37
+ # @return [Array<Hash>] lista rendas novas para criar
38
+ def rendas
39
+ vars_re
40
+ vars_mv
41
+ r = []
42
+ while mvl >= rru && mpn < mcn
43
+ r << nova_re
44
+ proximo_mv
45
+ end
46
+ r
47
+ end
48
+
49
+ # @param (see rendas)
50
+ def vars_mv
51
+ @mpn = 0
52
+ @mcn = ren[:mv].count
53
+ vars_dados_mv
54
+ end
55
+
56
+ # @param (see rendas)
57
+ def vars_dados_mv
58
+ @mdl = ren[:mv][mpn][:dl]
59
+ @mvl = ren[:mv][mpn][:vl]
60
+ end
61
+
62
+ # @param (see rendas)
63
+ def vars_re
64
+ @ran = ren[:ano]
65
+ @rcn = ren[:cnt]
66
+ @rru = Float(ren[:ct][/\d+/]) / 100
67
+ end
68
+
69
+ # @return [Array] lista dados da renda nova
70
+ def nova_re
71
+ if rcn == 12
72
+ @rcn = 1
73
+ @ran += 1
74
+ else
75
+ @rcn += 1
76
+ end
77
+ # [rct, ran, rcn, mdl, mdl.mjd - vencimento.mjd]
78
+ "('#{rct}',#{ran},#{rcn},'#{mdl.strftime(DF)}',#{dias})"
79
+ end
80
+
81
+ def dias
82
+ mdl.mjd - (Date.new(ran, rcn, 1) >> (ren[:dc].month - 1)).mjd
83
+ end
84
+
85
+ # @param (see rendas)
86
+ def proximo_mv
87
+ @mvl -= rru
88
+ return unless mvl < rru
89
+
90
+ @mpn += 1
91
+ return unless mpn < mcn
92
+
93
+ vars_dados_mv
94
+ end
95
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Abank
4
- VERSION = '0.2.3'
4
+ VERSION = '0.2.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abank
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hernâni Rodrigues Vaz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-17 00:00:00.000000000 Z
11
+ date: 2020-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -105,6 +105,7 @@ extensions: []
105
105
  extra_rdoc_files: []
106
106
  files:
107
107
  - ".gitignore"
108
+ - ".rubocop.yml"
108
109
  - ".travis.yml"
109
110
  - Gemfile
110
111
  - Gemfile.lock
@@ -116,8 +117,10 @@ files:
116
117
  - bin/setup
117
118
  - exe/abank
118
119
  - lib/abank.rb
119
- - lib/abank/bigquery.rb
120
- - lib/abank/folhacalculo.rb
120
+ - lib/abank/big.rb
121
+ - lib/abank/contrato.rb
122
+ - lib/abank/folha.rb
123
+ - lib/abank/rendas.rb
121
124
  - lib/abank/version.rb
122
125
  homepage: https://github.com/hernanirvaz/abank
123
126
  licenses:
@@ -1,176 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'roo'
4
- require 'google/cloud/bigquery'
5
-
6
- module Abank
7
- DF = '%Y-%m-%d'
8
-
9
- # (see Bigquery)
10
- class Bigquery
11
- # @return [Google::Cloud::Bigquery] API bigquery
12
- attr_reader :apibq
13
- # @return [Roo::Excelx] folha calculo a processar
14
- attr_reader :folha
15
- # @return [Hash] opcoes trabalho com linhas
16
- attr_reader :linha
17
- # @return [Integer] numero conta
18
- attr_reader :conta
19
-
20
- # @return [Array] row folha calculo em processamento
21
- attr_reader :row
22
- # @return [Google::Cloud::Bigquery::QueryJob] job bigquery
23
- attr_reader :job
24
- # @return (see sql_select)
25
- attr_reader :sql
26
-
27
- # @param [String] xls folha calculo para processar
28
- # @param [Hash] ops opcoes trabalho com linhas
29
- # @option ops [Boolean] :s (false) apaga linha similar?
30
- # @option ops [Boolean] :e (false) apaga linha igual?
31
- # @option ops [Boolean] :m (false) apaga linhas existencia multipla?
32
- # @option ops [Boolean] :i (false) insere linha nova?
33
- # @option ops [Boolean] :t (false) apaga rendas totalmente?
34
- # @option ops [Numeric] :n (0) numero dias correcao para data valor
35
- # @option ops [String] :r identificador contrato arrendamento
36
- # @return [Bigquery] acesso folhas calculo activobank
37
- # & correspondente bigquery dataset
38
- def initialize(xls = '', ops = { s: false, e: false, m: false,
39
- i: false, t: false, n: 0, r: '' })
40
- # usa env GOOGLE_APPLICATION_CREDENTIALS para obter credentials
41
- # @see https://cloud.google.com/bigquery/docs/authentication/getting-started
42
- @apibq = Google::Cloud::Bigquery.new
43
- @folha = Roo::Spreadsheet.open(xls) if xls.size.positive?
44
- @linha = ops
45
- @conta = xls.match?(/card/i) ? 2 : 1
46
- end
47
-
48
- # cria job bigquery & verifica execucao
49
- #
50
- # @param [String] sql a executar
51
- # @return [Boolean] job ok?
52
- def job_bigquery?(sql)
53
- @job = apibq.query_job(sql)
54
- @job.wait_until_done!
55
- puts @job.error['message'] if @job.failed?
56
- @job.failed?
57
- end
58
-
59
- # executa Stored procedure (SP) job bigquery
60
- #
61
- # @param (see job_bigquery?)
62
- # @return (see num_insert)
63
- def esp(sql)
64
- job_bigquery?(sql) ? 0 : num_insert(apibq.jobs(parent_job: job))
65
- end
66
-
67
- # @return [Integer] numero linhas inseridas
68
- def num_insert(sps)
69
- sps.find { |j| j.statement_type == 'INSERT' }.num_dml_affected_rows
70
- end
71
-
72
- # cria Data Manipulation Language (DML) job bigquery
73
- #
74
- # @param (see job_bigquery?)
75
- # @return [Integer] numero linhas afetadas
76
- def dml(sql)
77
- p sql
78
- job_bigquery?(sql) ? 0 : job.num_dml_affected_rows
79
- end
80
-
81
- # pesquisa existencia linha folha calculo no bigquery
82
- #
83
- # @return [Google::Cloud::Bigquery::Data] resultado do sql num array<hash>
84
- def sql_select
85
- # array.count = 0 ==> pode carregar esta linha
86
- # array.count = 1 ==> mais testes necessarios
87
- # array.count > 1 ==> nao carregar esta linha
88
- @sql = job_bigquery?('select * ' + sql_where) ? [{}, {}] : job.data
89
- end
90
-
91
- # @return [String] parte sql para processamento linhas similares
92
- def sql_where
93
- "from hernanilr.ab.mv where nc=#{conta}" \
94
- " and dl='#{row[0].strftime(DF)}'" \
95
- " and vl=#{row[3]}"
96
- end
97
-
98
- # (see CLI#classifica)
99
- def classifica
100
- return unless linha[:i]
101
-
102
- i = dml('update hernanilr.ab.mv set mv.ct=tt.nct' \
103
- ' from (select * from hernanilr.ab.cl) as tt' \
104
- ' where mv.dl=tt.dl and mv.dv=tt.dv' \
105
- ' and mv.ds=tt.ds and mv.vl=tt.vl')
106
- puts 'LINHAS CLASSIFICADAS ' + i.to_s
107
- return unless i.positive?
108
-
109
- atualiza
110
- end
111
-
112
- # (see CLI#atualiza)
113
- def atualiza
114
- puts 'RENDAS INSERIDAS ' + esp('call hernanilr.ab.rendas()').to_s
115
- end
116
-
117
- # (see CLI#cria)
118
- def cria
119
- i = dml('insert into hernanilr.ab.re ' + sql_contrato)
120
- puts i.zero? ? 'NAO EXISTE CONTRATO' : 'CONTRATO INSERIDO'
121
- return unless i.positive? && linha[:t]
122
-
123
- atualiza
124
- end
125
-
126
- # @return [String] sql obtem dados inicio contrato arrendamento
127
- def sql_contrato
128
- 'select ct,EXTRACT(YEAR FROM DATE_TRUNC(dl,MONTH)) as ano,0 as cnt' \
129
- ',DATE_TRUNC(dl,MONTH) as dl,0 dias' \
130
- ' from hernanilr.ab.mv' \
131
- " where ct='#{linha[:r]}' " \
132
- 'order by dl limit 1'
133
- end
134
-
135
- # (see CLI#apaga)
136
- def apaga
137
- puts 'RENDAS APAGADAS ' + dml(sql_apaga).to_s
138
- end
139
-
140
- # @return [String] sql apaga rendas
141
- def sql_apaga
142
- "delete from hernanilr.ab.re where ct='#{linha[:r]}'" +
143
- (linha[:t] ? '' : ' and cnt>0')
144
- end
145
-
146
- # @return [Integer] numero linhas inseridas
147
- def sql_insert
148
- return 1 unless linha[:i]
149
-
150
- dml('insert hernanilr.ab.mv(dl,dv,ds,vl,nc,ano,mes,ct,tp) VALUES(' \
151
- "'#{row[0].strftime(DF)}','#{data_valor.strftime(DF)}','#{row[2]}'" +
152
- str_insert1)
153
- end
154
-
155
- # @return [Date] data valor corrigida
156
- def data_valor
157
- row[1] + linha[:n].to_i
158
- end
159
-
160
- # @return [String] campos extra da linha bigquery
161
- def str_insert1
162
- ",#{row[3]},#{conta}" + str_insert2
163
- end
164
-
165
- # @return [String] campos calculados da linha bigquery
166
- def str_insert2
167
- ",#{data_valor.year},#{data_valor.month},null," \
168
- "'#{row[3].positive? ? 'c' : 'd'}')"
169
- end
170
-
171
- # @return [Integer] numero linhas apagadas
172
- def sql_delete
173
- dml('delete ' + sql_where + " and ds='#{sql.first[:ds].strip}'")
174
- end
175
- end
176
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abank
4
- HT = ['Data Lanc.', 'Data Valor', 'Descrição', 'Valor'].freeze
5
- RF = '%<v3>-35.35s %<v4>8.2f'
6
-
7
- # classifica & arquiva dados das folhas calculo activobank no bigquery
8
- class Bigquery
9
- # corrige linha folha calculo para processamento
10
- #
11
- # @param [Hash] has da linha em processamento
12
- def corrige_hash(has)
13
- @row = has.values
14
- @row[2] = row[2].strip
15
- @row[3] = -1 * row[3] if conta > 1
16
- end
17
-
18
- # processa linhas folha calculo & classifica bigquery
19
- def processa
20
- n = 0
21
- folha.sheet(0).parse(header_search: HT) do |r|
22
- n += 1
23
- puts n == 1 ? "\n" + folha.info : processa_row(r)
24
- end
25
- classifica
26
- end
27
-
28
- # processa linha folha calculo para arquivo
29
- #
30
- # @param (see corrige_hash)
31
- # @return [String] texto informativo do processamento
32
- def processa_row(has)
33
- corrige_hash(has)
34
- sql_select
35
- if row_naoexiste? then row_str + (sql_insert == 1 ? ' NOVA' : ' ERRO')
36
- elsif row_simila? then row_similar
37
- elsif row_existe? then row_existente
38
- else row_multiplas
39
- end
40
- end
41
-
42
- # @return [String] linha folha calculo formatada
43
- def row_str
44
- "#{row[0].strftime(DF)} #{row[1].strftime(DF)} " \
45
- "#{format(RF, v3: row[2], v4: row[3])}"
46
- end
47
-
48
- # @return [String] linha folha calculo similar
49
- def row_similar
50
- d = linha[:s] ? sql_delete : 0
51
- row_str + ' SIMILAR' + str_apagadas(d) + sql.first[:ds].strip
52
- end
53
-
54
- # @return [String] linha folha calculo existente
55
- def row_existente
56
- d = linha[:e] ? sql_delete : 0
57
- row_str + ' EXISTENTE' + str_apagadas(d)
58
- end
59
-
60
- # @return [String] linha folha calculo existencia multipla
61
- def row_multiplas
62
- d = linha[:m] ? sql_delete : 0
63
- row_str + ' MULTIPLAS ' + sql.count.to_s + str_apagadas(d)
64
- end
65
-
66
- # @param [Integer] numero linhas apagadas
67
- # @return [String] texto formatado linhas apagadas
68
- def str_apagadas(num)
69
- num.positive? ? ' & ' + num.to_s + ' APAGADA(S) ' : ' '
70
- end
71
-
72
- # @return [Boolean] linha folha calculo nao existe no bigquery?
73
- def row_naoexiste?
74
- sql.count.zero?
75
- end
76
-
77
- # @return [Boolean] linha folha calculo existe no bigquery?
78
- def row_existe?
79
- sql.count == 1 && sql.first[:ds].strip == row[2]
80
- end
81
-
82
- # @return [Boolean] linha folha calculo existe parecida no bigquery?
83
- def row_simila?
84
- sql.count == 1 && sql.first[:ds].strip != row[2]
85
- end
86
- end
87
- end