abank 0.2.5 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,134 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'google/cloud/bigquery'
4
-
5
- # @see Abank::Big
6
- class Abank::Big
7
- DF = '%Y-%m-%d'
8
-
9
- # @return [Hash] opcoes trabalho
10
- attr_reader :opcao
11
-
12
- # @return [Google::Cloud::Bigquery] API bigquery
13
- attr_reader :bqapi
14
-
15
- # @return [Google::Cloud::Bigquery::QueryJob] job bigquery
16
- attr_reader :bqjob
17
-
18
- # @return [Google::Cloud::Bigquery::Data] resultado do select
19
- attr_reader :bqres
20
-
21
- # @return [Integer] numero linhas afetadas pela Data Manipulation Language (DML)
22
- attr_reader :bqnrs
23
-
24
- # @return [String] movimentos a inserir (values.mv)
25
- attr_reader :mvvls
26
-
27
- # @return [String] movimentos a apagar (keysin.mv)
28
- attr_reader :mvkys
29
-
30
- # acesso a base dados abank no bigquery
31
- #
32
- # @param [Hash] opc opcoes trabalho
33
- # @option opc [String] :k ('') movimentos a apagar (keysin.mv)
34
- # @option opc [String] :c ('') id contrato arrendamento (re)
35
- # @option opc [String] :d ('') data inicio contrato arrendamento (re)
36
- # @option opc [Boolean] :t (false) trabalha todas as rendas? (re)
37
- # @return [Hash] opcoes trabalho
38
- def initialize(opc = {})
39
- @opcao = opc
40
- @bqapi = Google::Cloud::Bigquery.new
41
- @mvvls = ''
42
- @mvkys = opc.fetch(:k, '')
43
- @ctide = opc.fetch(:c, '')
44
- # p ['B', opcao]
45
- opcao
46
- end
47
-
48
- # (see CLI#tag)
49
- def mv_classifica
50
- dml('update hernanilr.ab.mv set mv.ct=tt.nct ' \
51
- 'from (select * from hernanilr.ab.cl) as tt ' \
52
- "where #{ky_mv}=tt.ky")
53
- puts 'MOVIMENTOS CLASSIFICADOS ' + bqnrs.to_s
54
- end
55
-
56
- # apaga movimentos & suas rendas associadas no bigquery
57
- #
58
- # @return [Big] acesso a base dados abank no bigquery
59
- def mv_delete
60
- vars_mv_work
61
- if mvkys.size.positive?
62
- # obtem lista contratos arrendamento associados aos movimentos a apagar
63
- @ctlct = sel("select ct from hernanilr.ab.mv where #{ky_mv} in(#{mvkys}) and substr(ct,1,1)='r' group by 1")
64
-
65
- # apaga rendas associadas e depois movimentos
66
- @opcao[:t] = true
67
- lr_apaga.mv_delete_dml
68
-
69
- # para obrigar re_work a trabalhar com lista contratos (ctlct)
70
- @bqnrs = 0
71
- end
72
- self
73
- end
74
-
75
- # insere & classifica movimentos no bigquery
76
- #
77
- # @return [Big] acesso a base dados abank no bigquery
78
- def mv_insert
79
- if mvvls.size.positive?
80
- dml('insert hernanilr.ab.mv VALUES' + mvvls)
81
- puts 'MOVIMENTOS INSERIDOS ' + bqnrs.to_s
82
- mv_classifica if bqnrs.positive?
83
- end
84
- self
85
- end
86
-
87
- # inicializa variaveis para delete/insert movimentos
88
- def vars_mv_work
89
- @bqnrs = 0
90
- @ctlct = []
91
- @mvkys = mvkys[1..] if mvkys[0] == ','
92
- @mvvls = mvvls[1..] if mvvls[0] == ','
93
- end
94
-
95
- # apaga movimentos no bigquery
96
- def mv_delete_dml
97
- dml("delete from hernanilr.ab.mv where #{ky_mv} in(#{mvkys})")
98
- puts 'MOVIMENTOS APAGADOS ' + bqnrs.to_s
99
- end
100
-
101
- # @return [String] expressao sql da chave de movimentos
102
- def ky_mv
103
- 'FARM_FINGERPRINT(CONCAT(CAST(mv.nc as STRING),mv.ds,CAST(mv.dl as STRING),CAST(mv.vl as STRING)))'
104
- end
105
-
106
- # cria job bigquery & verifica execucao
107
- #
108
- # @param [String] sql comando a executar
109
- # @return [Boolean] job ok?
110
- def job?(sql)
111
- # p sql
112
- @bqjob = bqapi.query_job(sql)
113
- @bqjob.wait_until_done!
114
- puts @bqjob.error['message'] if @bqjob.failed?
115
- @bqjob.failed?
116
- end
117
-
118
- # executa sql & devolve resultado do bigquery
119
- #
120
- # @param (see job?)
121
- # @param [Array] erro quando da erro no bigquery
122
- # @return [Google::Cloud::Bigquery::Data] resultado do sql
123
- def sel(sql, erro = [])
124
- @bqres = job?(sql) ? erro : bqjob.data
125
- end
126
-
127
- # executa Data Manipulation Language (DML) no bigquery
128
- #
129
- # @param (see job?)
130
- # @return [Integer] numero rows afetadas pelo dml
131
- def dml(sql)
132
- @bqnrs = job?(sql) ? 0 : bqjob.num_dml_affected_rows
133
- end
134
- end
@@ -1,107 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # acesso a base dados abank no bigquery
4
- class Abank::Big
5
- # @return [String] id contrato arrendamento
6
- attr_reader :ctide
7
-
8
- # @return [Array<Hash>] lista ids contratos arrendamento
9
- # @example
10
- # [{ ct: 'r03000' }, ...]
11
- attr_reader :ctlct
12
-
13
- # @return [Array<Hash>] lista dados contrato arrendamento (inclui lista movimentos novos)
14
- # @example
15
- # [{ct: 'r03000', dc: '2020-03-01', ano: 2020, cnt: 0, dl: '2020-03-01', mv: [{dl: '2020-03-02', vl: 30}, ...] }]
16
- attr_reader :ctlcm
17
-
18
- # (see CLI#criact)
19
- def ct_cria
20
- if existe_contrato?
21
- @bqnrs = 1
22
- puts 'CONTRATO JA EXISTE'
23
- else
24
- dml('insert into hernanilr.ab.re ' + sql_contrato_mv)
25
- puts "CONTRATO #{ctide} " + (bqnrs.zero? ? 'NAO EXISTE' : 'INSERIDO')
26
- end
27
- return unless existem_rendas?
28
-
29
- # processa rendas associadas ao contrato arrendamento
30
- cm_cria.vr_cria.re_insert
31
- end
32
-
33
- # (see CLI#apagact)
34
- def ct_apaga
35
- @ctlct = [{ ct: ctide }]
36
- lc_apaga
37
- end
38
-
39
- # apaga rendas da lista de contrato arrendamento
40
- #
41
- # @return [Big] acesso a base dados abank no bigquery
42
- def lr_apaga
43
- return self unless opcao[:t] && ctlct.count.positive?
44
-
45
- # para nao apagar contrato arrendamento - somente as rendas
46
- @opcao[:t] = false
47
-
48
- lc_apaga
49
- self
50
- end
51
-
52
- # apaga rendas da lista de contratos arrendamento
53
- def lc_apaga
54
- dml("delete from hernanilr.ab.re where ct in(#{str_lc})#{opcao[:t] ? '' : ' and cnt>0'}")
55
- puts "RENDAS #{str_lc('')} APAGADAS " + bqnrs.to_s
56
- end
57
-
58
- # @return [String] texto formatado que representa lista de contratos arrendamento
59
- def str_lc(sep = "'")
60
- ctlct.map { |c| sep + c[:ct] + sep }.join(',')
61
- end
62
-
63
- # optem lista dados contrato arrendamento (inclui lista movimentos novos)
64
- #
65
- # @return [Big] acesso a base dados abank no bigquery
66
- def cm_cria
67
- @ctlcm = []
68
- ctlct.each do |c|
69
- @ctide = c[:ct]
70
- sel(sql_last_re)
71
- @ctlcm << bqres[0].merge({ mv: sel(sql_novo_mv(bqres[0][:dl])) })
72
- end
73
- self
74
- end
75
-
76
- # @return [Boolean] existem rendas para processar sim/nao?
77
- def existem_rendas?
78
- @ctlct = [{ ct: ctide }]
79
- bqnrs.positive? && opcao[:t]
80
- end
81
-
82
- # @return [Boolean] contrato arrendamento ja existe sim/nao?
83
- def existe_contrato?
84
- sel("select ct from hernanilr.ab.re where ct='#{ctide}' and cnt=0").count.positive?
85
- end
86
-
87
- # @return [String] sql para obter ultima renda do contrato arrendamento
88
- def sql_last_re
89
- 'select ct,DATE_SUB(DATE_SUB(dl,INTERVAL dias DAY),INTERVAL IF(cnt=0,0,cnt-1) MONTH) as dc,ano,cnt,dl ' \
90
- "from hernanilr.ab.re where ct='#{ctide}' order by ano desc,cnt desc limit 1"
91
- end
92
-
93
- # @return [String] sql para obter movimentos novos (depois da ultima renda do contrato arrendamento)
94
- def sql_novo_mv(mdl)
95
- "select dl,vl from hernanilr.ab.mv where ct='#{ctide}' and dl>='#{(mdl + 1).strftime(DF)}' order by dl,dv"
96
- end
97
-
98
- # @return [String] sql para obter dados do inicio contrato arrendamento
99
- def sql_contrato_mv
100
- if opcao[:d].size.zero?
101
- 'select ct,EXTRACT(YEAR FROM DATE_TRUNC(dl,MONTH)) as ano,0 as cnt,DATE_TRUNC(dl,MONTH) as dl,0 dias ' \
102
- "from hernanilr.ab.mv where ct='#{ctide}' order by dl limit 1"
103
- else
104
- "select '#{ctide}' as ct,EXTRACT(YEAR FROM DATE '#{opcao[:d]}') as ano,0 as cnt,DATE '#{opcao[:d]}' as dl,0 dias"
105
- end
106
- end
107
- end
@@ -1,154 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'roo'
4
-
5
- # acesso a folha calculo & base dados abank no bigquery
6
- class Abank::Big::Folha < Abank::Big
7
- # @return [Roo::Excelx] folha calculo a processar
8
- attr_reader :folha
9
-
10
- # @return [Integer] numero conta associado a folha calculo
11
- # @example
12
- # mov*.xlsx --> 1 --> conta-corrente
13
- # movCard*.xlsx --> 2 --> conta-cartao
14
- attr_reader :conta
15
-
16
- # @return [Array] row folha calculo em processamento
17
- attr_reader :rowfc
18
-
19
- # acesso a folha calculo & base dados abank no bigquery
20
- #
21
- # @param [Hash] opc opcoes trabalho
22
- # @option opc [String] :f ('') folha calculo a processar
23
- # @option opc [Boolean] :s (false) apaga movimento similar? (mv)
24
- # @option opc [Boolean] :e (false) apaga movimento igual? (mv)
25
- # @option opc [Boolean] :i (false) insere movimento novo? (mv)
26
- # @option opc [String] :v ('') data valor movimentos (mv)
27
- # @option opc [String] :g ('') classificacao movimentos (mv)
28
- def initialize(opc = {})
29
- @opcao = super
30
- @folha = Roo::Spreadsheet.open(opc.fetch(:f))
31
- @conta = opc.fetch(:f).match?(/card/i) ? 2 : 1
32
- @opcao[:s] = opc.fetch(:s, false)
33
- @opcao[:e] = opc.fetch(:e, false)
34
- @opcao[:i] = opc.fetch(:i, false)
35
- @opcao[:v] = opc.fetch(:v, '')
36
- @opcao[:g] = opc.fetch(:g, '')
37
- end
38
-
39
- # carrega/mostra folha calculo
40
- def processa_xls
41
- n = 0
42
- folha.sheet(0).parse(header_search: ['Data Lanc.', 'Data Valor', 'Descrição', 'Valor']) do |r|
43
- n += 1
44
- puts n == 1 ? "\n" + folha.info : processa_linha(r)
45
- end
46
- return unless opcao[:i]
47
-
48
- # processa movimentos & atualiza rendas
49
- mv_delete.mv_insert.re_work
50
- end
51
-
52
- # processa linha folha calculo
53
- #
54
- # @param [Hash] linha da folha calculo em processamento
55
- # @return [String] texto informativo formatado da linha em processamento
56
- def processa_linha(linha)
57
- vars_xls(linha)
58
- # pesquisa existencia linha folha calculo no bigquery
59
- # array.count = 0 ==> pode carregar esta linha
60
- # array.count = 1 ==> mais testes necessarios
61
- # array.count > 1 ==> nao pode carregar esta linha
62
- sel(sql_existe_mv, [{}, {}])
63
- if linha_naoexiste? then linha_base + values_mv
64
- elsif linha_existe? then linha_existe
65
- elsif linha_simila? then linha_similar
66
- else linha_multiplas
67
- end
68
- end
69
-
70
- # inicializa variavel para processar linha folha calculo
71
- #
72
- # @param (see processa_linha)
73
- def vars_xls(linha)
74
- @rowfc = linha.values
75
- @rowfc[2] = rowfc[2].strip
76
- @rowfc[3] = -1 * rowfc[3] if conta > 1
77
- end
78
-
79
- # @return [String] texto base formatado para display
80
- def linha_base
81
- "#{rowfc[0].strftime(DF)} #{format('%<v3>-34.34s %<v4>8.2f', v3: rowfc[2], v4: rowfc[3])}"
82
- end
83
-
84
- # @return [String] texto linha existente formatada para display
85
- def linha_existe
86
- add_kys if opcao[:e]
87
- linha_base + ' EXIS ' + format('%<v1>20d', v1: bqres.first[:ky])
88
- end
89
-
90
- # @return [String] texto linha similar formatada para display
91
- def linha_similar
92
- add_kys if opcao[:s]
93
- linha_base + ' SIMI ' + format('%<v1>-20.20s', v1: bqres.first[:ds].strip)
94
- end
95
-
96
- # @return [String] texto linha existencia multipla formatada para display
97
- def linha_multiplas
98
- linha_base + ' MULT(' + bqres.count.to_s + ')'
99
- end
100
-
101
- # obtem chaves movimento (keysin.mv) para apagar
102
- def add_kys
103
- bqres.each { |r| @mvkys += ",#{r[:ky]}" }
104
- end
105
-
106
- # @return [Boolean] linha folha calculo nao existe no bigquery?
107
- def linha_naoexiste?
108
- bqres.count.zero?
109
- end
110
-
111
- # @return [Boolean] linha folha calculo existe no bigquery?
112
- def linha_existe?
113
- bqres.count == 1 && bqres.first[:ds].strip == rowfc[2]
114
- end
115
-
116
- # @return [Boolean] linha folha calculo existe parecida no bigquery?
117
- def linha_simila?
118
- bqres.count == 1 && bqres.first[:ds].strip != rowfc[2]
119
- end
120
-
121
- # @return [String] sql para movimentos no bigquery
122
- def sql_existe_mv
123
- "select *,#{ky_mv} as ky from hernanilr.ab.mv " \
124
- "where nc=#{conta} and dl='#{rowfc[0].strftime(DF)}' and vl=#{rowfc[3]}"
125
- end
126
-
127
- # obtem movimento (values.mv) para inserir
128
- #
129
- # @return [String] ' NOVO'
130
- def values_mv
131
- @mvvls += ",('#{rowfc[0].strftime(DF)}','#{dvc.strftime(DF)}','#{rowfc[2]}',#{rowfc[3]}" + values_mv_extra
132
- ' NOVO'
133
- end
134
-
135
- # @return [String] campos extra do movimento (values.mv) para inserir
136
- def values_mv_extra
137
- ",#{conta},#{dvc.year},#{dvc.month},'#{tpc}',#{ctc})"
138
- end
139
-
140
- # @return [Date] data valor corrigida
141
- def dvc
142
- opcao[:v].size.zero? ? rowfc[1] : Date.parse(opcao[:v])
143
- end
144
-
145
- # @return [String] classificacao do movimento (null --> classificacao automatica)
146
- def ctc
147
- opcao[:g].size.zero? ? 'null' : ("'" + opcao[:g] + "'")
148
- end
149
-
150
- # @return [String] tipo movimento c[redito] ou d[ebito]
151
- def tpc
152
- rowfc[3].positive? ? 'c' : 'd'
153
- end
154
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @see Abank::Big
4
- class Abank::Big
5
- # @return [Integer] ano renda em tratamento
6
- attr_reader :reano
7
-
8
- # @return [Integer] mes renda em tratamento
9
- attr_reader :repos
10
-
11
- # @return [Float] valor renda mensal
12
- attr_reader :revre
13
-
14
- # @return [String] rendas a inserir (values.re)
15
- attr_reader :revls
16
-
17
- # @return [Integer] movimento em tratamento
18
- attr_reader :mvpos
19
-
20
- # @return [Date] data lancamento movimento em tratamento
21
- attr_reader :mvdlm
22
-
23
- # @return [Float] valor movimento em tratamento
24
- attr_reader :mvvlm
25
-
26
- # (see CLI#recriare)
27
- def re_atualiza
28
- # obtem contratos ativos
29
- @ctlct = sel('SELECT ct from hernanilr.ab.re group by 1')
30
-
31
- # [re]cria rendas [novas|todas]
32
- lr_apaga.cm_cria.vr_cria.re_insert
33
- end
34
-
35
- # cria rendas associadas a lista ids contratos arrendamento
36
- def re_work
37
- bqnrs.zero? || ctlct.count.positive? ? cm_cria.vr_cria.re_insert : re_atualiza
38
- end
39
-
40
- # obtem rendas a inserir (values.re)
41
- #
42
- # @return [Big] acesso a base dados abank no bigquery
43
- def vr_cria
44
- @revls = ctlcm.map { |c| rendas_novas(c) }.flatten(1).join(',')
45
- self
46
- end
47
-
48
- # insere rendas no bigquery
49
- def re_insert
50
- if revls.size.zero?
51
- puts 'NAO EXISTEM RENDAS NOVAS'
52
- else
53
- dml('insert hernanilr.ab.re VALUES' + revls)
54
- puts "RENDAS #{str_lc('')} CRIADAS " + bqnrs.to_s
55
- end
56
- end
57
-
58
- # @param [Hash] cmv dados contrato arrendamento (inclui lista movimentos novos)
59
- # @return [Array<String>] lista rendas novas dum contrato arrendamento (values.re)
60
- def rendas_novas(cmv)
61
- return [] unless cmv[:mv].count.positive?
62
-
63
- vars_re(cmv)
64
- r = []
65
- while mvvlm >= revre && mvpos < cmv[:mv].count
66
- r << nova_re(cmv)
67
- proximo_mv(cmv)
68
- end
69
- r
70
- end
71
-
72
- # inicializa variaveis para processar rendas do contrato arrendamento
73
- # @param (see rendas_novas)
74
- def vars_re(cmv)
75
- @reano = cmv[:ano]
76
- @repos = cmv[:cnt]
77
- @revre = Float(cmv[:ct][/\d+/]) / 100
78
- @mvpos = 0
79
- vars_re_mv(cmv)
80
- end
81
-
82
- # inicializa variaveis para processar movimentos associados ao contrato arrendamento
83
- # @param (see rendas_novas)
84
- def vars_re_mv(cmv)
85
- @mvdlm = cmv[:mv][mvpos][:dl]
86
- @mvvlm = cmv[:mv][mvpos][:vl]
87
- end
88
-
89
- # @param (see rendas_novas)
90
- # @return [String] renda formatada (values.re)
91
- def nova_re(cmv)
92
- # inicializa proxima renda
93
- if repos == 12
94
- @repos = 1
95
- @reano += 1
96
- else
97
- @repos += 1
98
- end
99
- "('#{cmv[:ct]}',#{reano},#{repos},'#{mvdlm.strftime(DF)}',#{dias(cmv)})"
100
- end
101
-
102
- # @param (see rendas_novas)
103
- # @return [Integer] dias atraso no pagamento da renda
104
- def dias(cmv)
105
- mvdlm.mjd - (Date.new(reano, repos, 1) >> (cmv[:dc].month - 1)).mjd
106
- end
107
-
108
- # inicializa variaveis para processar proximo movimento
109
- # @param (see rendas_novas)
110
- def proximo_mv(cmv)
111
- # valor renda paga retirado do valor do movimento
112
- @mvvlm -= revre
113
- return unless mvvlm < revre
114
-
115
- # avanca na lista de movimentos
116
- @mvpos += 1
117
- return unless mvpos < cmv[:mv].count
118
-
119
- vars_re_mv(cmv)
120
- end
121
- end