abank 0.4.3 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a808298a6ff4b9e8ee6d29c1088dd3f0195af3981fbb5e586f4fec0548a93d0
4
- data.tar.gz: 9e9b16ac7a215b35dbac0dd88d4b50beafd8197df0f82ab0a089bd809f9a59ce
3
+ metadata.gz: 919ed7397ffc15a6ff4f0f99865da47b8a090f6bf838798f1ca122e667e7f0a2
4
+ data.tar.gz: cf1d5cc84cc1bbc765969e183ff4cda28c70ca19de7a9c59c95da56ca3e41830
5
5
  SHA512:
6
- metadata.gz: 327723d64f377a8f8e279b4914f270e0dd27922a97af218e0744dde8a4bbab4f887d776da1bf543eba9fa3f2e17d9edbcc7545631a05f6d5bf9a707d586349d4
7
- data.tar.gz: f2ca3c359e176d829e23dfc95b57f18b6c83f9d1212bee32fceccaef242cf7e37a4db653324f28208150bf813881d19dfb6018e4bf57cf62255b43b8ef667973
6
+ metadata.gz: d7bb91bb62ec11e4051d06e4b007dec13a3f6cd904da1cdc7c1096c07e6b95676f756f8cac5faee0dc732f4f2abf50f7fe72760efcf82e909743f64f4dcf182e
7
+ data.tar.gz: 9750de979e437b44cf210b9245bb22b91b39d289049a84f373ab714632d4ab6c15e55688a17c8d8b8c61df8a4add2663cc8b9b3b606986a888152ebc5ada9d2d
data/Gemfile CHANGED
@@ -6,3 +6,4 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  gem 'rake', '~> 12.0'
9
+ gem 'nokogiri', '~> 1.18.1', platforms: [:ruby], require: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abank (0.4.3)
4
+ abank (0.4.5)
5
5
  google-cloud-bigquery
6
6
  roo
7
7
  thor
@@ -9,79 +9,122 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- addressable (2.8.4)
13
- public_suffix (>= 2.0.2, < 6.0)
12
+ addressable (2.8.7)
13
+ public_suffix (>= 2.0.2, < 7.0)
14
14
  ast (2.4.2)
15
15
  backport (1.2.0)
16
- benchmark (0.2.1)
17
- concurrent-ruby (1.2.2)
16
+ base64 (0.2.0)
17
+ benchmark (0.4.0)
18
+ bigdecimal (3.1.9)
19
+ concurrent-ruby (1.3.4)
18
20
  declarative (0.0.20)
19
- diff-lcs (1.5.0)
21
+ diff-lcs (1.5.1)
22
+ dry-configurable (1.3.0)
23
+ dry-core (~> 1.1)
24
+ zeitwerk (~> 2.6)
25
+ dry-core (1.1.0)
26
+ concurrent-ruby (~> 1.0)
27
+ logger
28
+ zeitwerk (~> 2.6)
29
+ dry-inflector (1.2.0)
30
+ dry-initializer (3.2.0)
31
+ dry-logic (1.6.0)
32
+ bigdecimal
33
+ concurrent-ruby (~> 1.0)
34
+ dry-core (~> 1.1)
35
+ zeitwerk (~> 2.6)
36
+ dry-schema (1.13.4)
37
+ concurrent-ruby (~> 1.0)
38
+ dry-configurable (~> 1.0, >= 1.0.1)
39
+ dry-core (~> 1.0, < 2)
40
+ dry-initializer (~> 3.0)
41
+ dry-logic (>= 1.4, < 2)
42
+ dry-types (>= 1.7, < 2)
43
+ zeitwerk (~> 2.6)
44
+ dry-types (1.8.0)
45
+ bigdecimal (~> 3.0)
46
+ concurrent-ruby (~> 1.0)
47
+ dry-core (~> 1.0)
48
+ dry-inflector (~> 1.0)
49
+ dry-logic (~> 1.4)
50
+ zeitwerk (~> 2.6)
20
51
  e2mmap (0.1.0)
21
- faraday (2.7.10)
22
- faraday-net_http (>= 2.0, < 3.1)
23
- ruby2_keywords (>= 0.0.4)
24
- faraday-net_http (3.0.2)
25
- google-apis-bigquery_v2 (0.57.0)
26
- google-apis-core (>= 0.11.0, < 2.a)
27
- google-apis-core (0.11.1)
52
+ faraday (2.12.2)
53
+ faraday-net_http (>= 2.0, < 3.5)
54
+ json
55
+ logger
56
+ faraday-net_http (3.4.0)
57
+ net-http (>= 0.5.0)
58
+ google-apis-bigquery_v2 (0.83.0)
59
+ google-apis-core (>= 0.15.0, < 2.a)
60
+ google-apis-core (0.15.1)
28
61
  addressable (~> 2.5, >= 2.5.1)
29
- googleauth (>= 0.16.2, < 2.a)
30
- httpclient (>= 2.8.1, < 3.a)
62
+ googleauth (~> 1.9)
63
+ httpclient (>= 2.8.3, < 3.a)
31
64
  mini_mime (~> 1.0)
65
+ mutex_m
32
66
  representable (~> 3.0)
33
67
  retriable (>= 2.0, < 4.a)
34
- rexml
35
- webrick
36
- google-cloud-bigquery (1.43.1)
68
+ google-cloud-bigquery (1.51.1)
69
+ bigdecimal (~> 3.0)
37
70
  concurrent-ruby (~> 1.0)
38
- google-apis-bigquery_v2 (~> 0.1)
71
+ google-apis-bigquery_v2 (~> 0.71)
72
+ google-apis-core (~> 0.13)
39
73
  google-cloud-core (~> 1.6)
40
- googleauth (>= 0.16.2, < 2.a)
74
+ googleauth (~> 1.9)
41
75
  mini_mime (~> 1.0)
42
- google-cloud-core (1.6.0)
43
- google-cloud-env (~> 1.0)
76
+ google-cloud-core (1.7.1)
77
+ google-cloud-env (>= 1.0, < 3.a)
44
78
  google-cloud-errors (~> 1.0)
45
- google-cloud-env (1.6.0)
46
- faraday (>= 0.17.3, < 3.0)
47
- google-cloud-errors (1.3.1)
48
- googleauth (1.7.0)
49
- faraday (>= 0.17.3, < 3.a)
79
+ google-cloud-env (2.2.1)
80
+ faraday (>= 1.0, < 3.a)
81
+ google-cloud-errors (1.4.0)
82
+ google-logging-utils (0.1.0)
83
+ googleauth (1.12.2)
84
+ faraday (>= 1.0, < 3.a)
85
+ google-cloud-env (~> 2.2)
86
+ google-logging-utils (~> 0.1)
50
87
  jwt (>= 1.4, < 3.0)
51
- memoist (~> 0.16)
52
88
  multi_json (~> 1.11)
53
89
  os (>= 0.9, < 2.0)
54
90
  signet (>= 0.16, < 2.a)
55
91
  httpclient (2.8.3)
56
- jaro_winkler (1.5.6)
57
- json (2.6.3)
58
- jwt (2.7.1)
59
- kramdown (2.4.0)
60
- rexml
92
+ jaro_winkler (1.6.0)
93
+ json (2.9.1)
94
+ jwt (2.10.1)
95
+ base64
96
+ kramdown (2.5.1)
97
+ rexml (>= 3.3.9)
61
98
  kramdown-parser-gfm (1.1.0)
62
99
  kramdown (~> 2.0)
63
- kwalify (0.7.2)
64
100
  language_server-protocol (3.17.0.3)
65
- memoist (0.16.2)
66
- mini_mime (1.1.2)
101
+ logger (1.6.5)
102
+ mini_mime (1.1.5)
103
+ mini_portile2 (2.8.8)
67
104
  multi_json (1.15.0)
68
- nokogiri (1.15.3-x86_64-linux)
105
+ mutex_m (0.3.0)
106
+ net-http (0.6.0)
107
+ uri
108
+ nokogiri (1.18.1)
109
+ mini_portile2 (~> 2.8.2)
69
110
  racc (~> 1.4)
70
111
  os (1.1.4)
71
- parallel (1.23.0)
72
- parser (3.2.2.3)
112
+ parallel (1.26.3)
113
+ parser (3.3.6.0)
73
114
  ast (~> 2.4.1)
74
115
  racc
75
- public_suffix (5.0.3)
76
- racc (1.7.1)
116
+ public_suffix (6.0.1)
117
+ racc (1.8.1)
77
118
  rainbow (3.1.1)
78
119
  rake (12.3.3)
79
120
  rbs (2.8.4)
80
- reek (6.1.4)
81
- kwalify (~> 0.7.0)
82
- parser (~> 3.2.0)
121
+ reek (6.4.0)
122
+ dry-schema (~> 1.13.0)
123
+ logger (~> 1.6)
124
+ parser (~> 3.3.0)
83
125
  rainbow (>= 2.0, < 4.0)
84
- regexp_parser (2.8.1)
126
+ rexml (~> 3.1)
127
+ regexp_parser (2.10.0)
85
128
  representable (3.2.0)
86
129
  declarative (< 0.1.0)
87
130
  trailblazer-option (>= 0.1.1, < 0.2.0)
@@ -89,32 +132,30 @@ GEM
89
132
  retriable (3.1.2)
90
133
  reverse_markdown (2.1.1)
91
134
  nokogiri
92
- rexml (3.2.6)
93
- roo (2.10.0)
135
+ rexml (3.4.0)
136
+ roo (2.10.1)
94
137
  nokogiri (~> 1)
95
138
  rubyzip (>= 1.3.0, < 3.0.0)
96
- rubocop (1.55.1)
139
+ rubocop (1.70.0)
97
140
  json (~> 2.3)
98
141
  language_server-protocol (>= 3.17.0)
99
142
  parallel (~> 1.10)
100
- parser (>= 3.2.2.3)
143
+ parser (>= 3.3.0.2)
101
144
  rainbow (>= 2.2.2, < 4.0)
102
- regexp_parser (>= 1.8, < 3.0)
103
- rexml (>= 3.2.5, < 4.0)
104
- rubocop-ast (>= 1.28.1, < 2.0)
145
+ regexp_parser (>= 2.9.3, < 3.0)
146
+ rubocop-ast (>= 1.36.2, < 2.0)
105
147
  ruby-progressbar (~> 1.7)
106
- unicode-display_width (>= 2.4.0, < 3.0)
107
- rubocop-ast (1.29.0)
108
- parser (>= 3.2.1.0)
148
+ unicode-display_width (>= 2.4.0, < 4.0)
149
+ rubocop-ast (1.37.0)
150
+ parser (>= 3.3.1.0)
109
151
  ruby-progressbar (1.13.0)
110
- ruby2_keywords (0.0.5)
111
- rubyzip (2.3.2)
112
- signet (0.17.0)
152
+ rubyzip (2.4.1)
153
+ signet (0.19.0)
113
154
  addressable (~> 2.8)
114
155
  faraday (>= 0.17.5, < 3.a)
115
156
  jwt (>= 1.5, < 3.0)
116
157
  multi_json (~> 1.10)
117
- solargraph (0.49.0)
158
+ solargraph (0.50.0)
118
159
  backport (~> 1.2)
119
160
  benchmark
120
161
  bundler (~> 2.0)
@@ -130,20 +171,25 @@ GEM
130
171
  thor (~> 1.0)
131
172
  tilt (~> 2.0)
132
173
  yard (~> 0.9, >= 0.9.24)
133
- thor (1.2.2)
134
- tilt (2.2.0)
174
+ thor (1.3.2)
175
+ tilt (2.6.0)
135
176
  trailblazer-option (0.1.2)
136
177
  uber (0.1.0)
137
- unicode-display_width (2.4.2)
138
- webrick (1.8.1)
139
- yard (0.9.34)
178
+ unicode-display_width (3.1.4)
179
+ unicode-emoji (~> 4.0, >= 4.0.4)
180
+ unicode-emoji (4.0.4)
181
+ uri (1.0.2)
182
+ yard (0.9.37)
183
+ zeitwerk (2.6.18)
140
184
 
141
185
  PLATFORMS
186
+ ruby
142
187
  x86_64-linux
143
188
 
144
189
  DEPENDENCIES
145
190
  abank!
146
191
  bundler
192
+ nokogiri (~> 1.18.1)
147
193
  rake (~> 12.0)
148
194
  reek
149
195
  rubocop
data/lib/abank/big.rb ADDED
@@ -0,0 +1,301 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('google/cloud/bigquery')
4
+
5
+ module Abank
6
+ BD = 'hernanilr.ab'
7
+
8
+ # @see Big
9
+ class Big
10
+ DF = '%Y-%m-%d'
11
+
12
+ # @return [Hash] opcoes trabalho
13
+ attr_reader :opcao
14
+
15
+ # @return [Google::Cloud::Bigquery::Data] resultado do Structured Query Language (SQL) no bigquery
16
+ attr_reader :bqres
17
+
18
+ # @return [Integer] numero linhas afetadas pelo Data Manipulation Language (DML) no bigquery
19
+ attr_reader :bqnrs
20
+
21
+ # @return [Integer] contrato arrendamento em tratamento
22
+ attr_reader :ctpos
23
+
24
+ # @return [Integer] movimento do contrato arrendamento em tratamento
25
+ attr_reader :mvpos
26
+
27
+ # acesso a base dados abank no bigquery
28
+ #
29
+ # @param [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
30
+ # @option opcoes [String] :k ('') movimentos a apagar (keysin.mv)
31
+ # @option opcoes [String] :c ('') id contrato arrendamento (re)
32
+ # @option opcoes [String] :d ('') data inicio contrato arrendamento (re)
33
+ # @option opcoes [Boolean] :t (false) trabalha todas as rendas? (re)
34
+ # @return [Hash] opcoes trabalho
35
+ def initialize(opcoes = {})
36
+ @opcao = opcoes
37
+ opcao
38
+ end
39
+
40
+ # @return [Google::Cloud::Bigquery] API bigquery
41
+ def bqapi
42
+ @bqapi ||= Google::Cloud::Bigquery.new
43
+ end
44
+
45
+ # @return [String] movimentos a apagar (keysin.mv)
46
+ def mvkys
47
+ opcao[:k][/([-+]*\d)+(,[-+]*\d+)*/].to_s
48
+ end
49
+
50
+ # apaga movimentos & suas rendas associadas no bigquery
51
+ #
52
+ # @return [Big] acesso a base dados abank no bigquery
53
+ def mv_delete
54
+ @ctlct = []
55
+ unless mvkys.empty?
56
+ # obtem lista contratos arrendamento associados aos movimentos a apagar
57
+ @ctlct = sql("select distinct ct from #{BD}.mv where #{ky_mv} in(#{mvkys}) and substr(ct,1,1)='r'")
58
+
59
+ # apaga todas as rendas dos contratos arrendamento associados aos movimentos a apagar
60
+ opcao[:t] = true unless ctlct.empty?
61
+ re_apaga.mv_delete_dml
62
+ end
63
+ self
64
+ end
65
+
66
+ # apaga movimentos no bigquery
67
+ def mv_delete_dml
68
+ dml("delete from #{BD}.mv where #{ky_mv} in(#{mvkys})")
69
+ puts("MOVIMENTOS APAGADOS #{bqnrs}")
70
+ end
71
+
72
+ # (see CLI#tag)
73
+ def mv_classifica
74
+ dml("update #{BD}.mv set mv.ct=tt.nct from (select * from #{BD}.cl) as tt where #{ky_mv}=tt.ky")
75
+ puts("MOVIMENTOS CLASSIFICADOS #{bqnrs}")
76
+ @ctlct = sql("select distinct ct from #{BD}.re") if bqnrs.positive?
77
+ self
78
+ end
79
+
80
+ # @return [String] expressao sql da chave de movimentos
81
+ def ky_mv
82
+ 'FARM_FINGERPRINT(CONCAT(CAST(mv.nc as STRING),mv.ds,CAST(mv.dl as STRING),CAST(mv.vl as STRING)))'
83
+ end
84
+
85
+ # (see CLI#criact)
86
+ def ct_cria
87
+ unless ct_existe?
88
+ dml("insert into #{BD}.re #{sql_contrato_mv}")
89
+ puts("CONTRATO #{opcao[:c]} #{bqnrs.zero? ? 'NAO ' : ''}INSERIDO")
90
+ end
91
+ # processar rendas sim/nao?
92
+ return unless bqnrs.positive? && opcao[:t]
93
+
94
+ # processa rendas associadas ao contrato arrendamento
95
+ ct_dados.re_insert
96
+ end
97
+
98
+ # @return [Boolean] contrato arrendamento ja existe sim/nao?
99
+ def ct_existe?
100
+ @ctlct = [{ ct: opcao[:c] }]
101
+ vaz = sql("select ct from #{BD}.re where ct in(#{str_lc}) and cnt=0").empty?
102
+ unless vaz
103
+ @bqnrs = 1
104
+ puts('CONTRATO JA EXISTE')
105
+ end
106
+ !vaz
107
+ end
108
+
109
+ # (see CLI#apagact)
110
+ def ct_apaga
111
+ @ctlct = [{ ct: opcao[:c] }]
112
+ re_delete_dml
113
+ end
114
+
115
+ # optem lista dados contrato arrendamento (inclui lista movimentos novos)
116
+ #
117
+ # @return [Big] acesso a base dados abank no bigquery
118
+ def ct_dados
119
+ ctlct.map! do |ctr|
120
+ opcao[:c] = ctr[:ct]
121
+ lre = sql(sql_last_re)[0]
122
+ ctr.merge(lre, mv: sql(sql_novo_mv(lre[:dl])))
123
+ end
124
+ self
125
+ end
126
+
127
+ # @param [Array] are lista rendas novas atual
128
+ # @return [Array<String>] lista rendas novas duma lista contratos arrendamento
129
+ def ct_rendas(lre = [])
130
+ while ctpos < ctlct.size
131
+ @mvpos = 0
132
+ lre += re_rendas
133
+ @ctpos += 1
134
+ end
135
+ lre
136
+ end
137
+
138
+ # @example sem dados movimentos
139
+ # [{ ct: 'r03000' }, ...]
140
+ # @example com dados movimentos
141
+ # [{ct: 'r03000', dc: '2020-03-01', ano: 2020, cnt: 0, dl: '2020-03-01', mv: [{dl: '2020-03-02', vl: 30}, ...] }]
142
+ # @return [Array<Hash>] lista dados contrato arrendamento (inclui lista movimentos novos)
143
+ def ctlct
144
+ @ctlct ||= []
145
+ end
146
+
147
+ # @return [String] texto formatado que representa lista de contratos arrendamento
148
+ def str_lc(sep = "'")
149
+ ctlct.map { |cid| sep + cid[:ct] + sep }.join(',')
150
+ end
151
+
152
+ # @return [String] sql para obter ultima renda do contrato arrendamento
153
+ def sql_last_re
154
+ 'select ct,DATE_SUB(DATE_SUB(dl,INTERVAL dias DAY),INTERVAL IF(cnt=0,0,cnt-1) MONTH) dc,ano,cnt,dl'\
155
+ ',CAST(REGEXP_EXTRACT(ct,r"\d+") as numeric)/100 vr '\
156
+ "from #{BD}.re where ct='#{opcao[:c]}' order by ano desc,cnt desc limit 1"
157
+ end
158
+
159
+ # @return [String] sql para obter movimentos novos (depois da ultima renda do contrato arrendamento)
160
+ def sql_novo_mv(mdl)
161
+ "select dl,vl from #{BD}.mv where ct='#{opcao[:c]}' and dl>='#{(mdl + 1).strftime(DF)}' order by dl,dv"
162
+ end
163
+
164
+ # @return [String] sql para obter dados do inicio contrato arrendamento
165
+ def sql_contrato_mv
166
+ cti = opcao[:c]
167
+ dat = opcao[:d]
168
+ if dat.empty?
169
+ 'select ct,EXTRACT(YEAR FROM DATE_TRUNC(dl,MONTH)) ano,0 cnt,DATE_TRUNC(dl,MONTH) dl,0 dias '\
170
+ "from #{BD}.mv where ct='#{cti}' order by dl limit 1"
171
+ else
172
+ "select '#{cti}' ct,EXTRACT(YEAR FROM DATE '#{dat}') ano,0 cnt,DATE '#{dat}' dl,0 dias"
173
+ end
174
+ end
175
+
176
+ # (see CLI#recriare)
177
+ def re_atualiza
178
+ # [re]cria rendas novas/todas dos contratos ativos
179
+ @ctlct = sql("select distinct ct from #{BD}.re")
180
+ re_apaga.ct_dados.re_insert
181
+ end
182
+
183
+ # insere rendas associadas a lista contratos arrendamento no bigquery
184
+ def re_insert
185
+ @ctpos = 0
186
+ vls = ct_rendas.join(',')
187
+ if vls.empty?
188
+ puts('NAO EXISTEM RENDAS NOVAS')
189
+ else
190
+ dml("insert #{BD}.re VALUES#{vls}")
191
+ puts("RENDAS #{str_lc('')} CRIADAS #{bqnrs}")
192
+ end
193
+ end
194
+
195
+ # apaga rendas da lista de contrato arrendamento
196
+ #
197
+ # @return [Big] acesso a base dados abank no bigquery
198
+ def re_apaga
199
+ return self if !opcao[:t] || ctlct.empty?
200
+
201
+ # para nao apagar contrato arrendamento - somente as rendas
202
+ opcao[:t] = false
203
+
204
+ re_delete_dml
205
+ self
206
+ end
207
+
208
+ # @return [Array<String>] lista rendas novas dum contrato arrendamento
209
+ def re_rendas
210
+ lre = []
211
+ while mvpos < re_atual[:mv].size && re_saldo_mv?
212
+ lre << re_nova_renda
213
+ @mvpos += 1 unless re_saldo_mv?
214
+ end
215
+ lre
216
+ end
217
+
218
+ # @return [String] renda formatada (values.re)
219
+ def re_nova_renda
220
+ re_proximos_dados
221
+ "('#{re_atual[:ct]}',#{ano},#{cnt},'#{re_atual_mv[:dl].strftime(DF)}',#{dias})"
222
+ end
223
+
224
+ # @return [Hash] dados contrato arrendamento (inclui lista movimentos novos)
225
+ def re_proximos_dados
226
+ # valor renda paga retirada do movimento
227
+ re_atual_mv[:vl] -= re_atual[:vr]
228
+ dre = cnt.zero? ? Date.new(ano, 1, 1) : Date.new(ano, cnt, 1) >> 1
229
+ re_atual.merge!(ano: dre.year, cnt: dre.month)
230
+ end
231
+
232
+ # apaga rendas da lista de contratos arrendamento
233
+ def re_delete_dml
234
+ dml("delete from #{BD}.re where ct in(#{str_lc})#{opcao[:t] ? '' : ' and cnt>0'}")
235
+ puts("RENDAS #{str_lc('')} APAGADAS #{bqnrs}")
236
+ end
237
+
238
+ # @return [Boolean] movimento com saldo suficiente?
239
+ def re_saldo_mv?
240
+ re_atual_mv[:vl] >= re_atual[:vr]
241
+ end
242
+
243
+ # @return [Hash] dados contrato arrendamento atual (inclui lista movimentos novos)
244
+ def re_atual
245
+ ctlct[ctpos]
246
+ end
247
+
248
+ # @return [Hash] movimento atual contrato arrendamento
249
+ def re_atual_mv
250
+ re_atual[:mv][mvpos]
251
+ end
252
+
253
+ # @return [Integer] ano da renda
254
+ def ano
255
+ re_atual[:ano]
256
+ end
257
+
258
+ # @return [Integer] numero da renda (0-12)
259
+ def cnt
260
+ re_atual[:cnt]
261
+ end
262
+
263
+ # @return [Integer] dias atraso/antecipo neste pagamento renda
264
+ def dias
265
+ re_atual_mv[:dl].mjd - (Date.new(ano, cnt, 1) >> (re_atual[:dc].month - 1)).mjd
266
+ end
267
+
268
+ # @param [String] cmd comando a executar
269
+ # @return [Google::Cloud::Bigquery::QueryJob] tarefa SQL/DML no bigquery
270
+ def job(cmd)
271
+ bqjob = bqapi.query_job(cmd)
272
+ bqjob.wait_until_done!
273
+ err = bqjob.error
274
+ puts(err['message']) if err
275
+ bqjob
276
+ end
277
+
278
+ # executa Structured Query Language (SQL) no bigquery
279
+ #
280
+ # @param (see job)
281
+ # @param [Array] erro resultado quando falha execucao
282
+ # @return [Google::Cloud::Bigquery::Data] resultado do SQL
283
+ def sql(cmd, erro = [])
284
+ # se job.failed? executa job(cmd).data => StandardError
285
+ @bqres = job(cmd).data
286
+ rescue StandardError
287
+ @bqres = erro
288
+ end
289
+
290
+ # executa Data Manipulation Language (DML) no bigquery
291
+ #
292
+ # @param (see job)
293
+ # @return [Integer] numero rows afetadas pelo DML
294
+ def dml(cmd)
295
+ # se job.failed? executa Integer(nil) => StandardError
296
+ @bqnrs = Integer(job(cmd).num_dml_affected_rows)
297
+ rescue StandardError
298
+ @bqnrs = 0
299
+ end
300
+ end
301
+ end
@@ -79,10 +79,14 @@ module Abank
79
79
  # array.count > 1 ==> nao pode carregar esta linha
80
80
  sql(sql_existe_mv, [{}, {}])
81
81
 
82
- if linha_naoexiste? then linha_base + values_mv
83
- elsif linha_existe? then linha_existe
84
- elsif linha_simila? then linha_similar
85
- else linha_multiplas
82
+ if linha_naoexiste?
83
+ linha_base + values_mv
84
+ elsif linha_existe?
85
+ linha_existe
86
+ elsif linha_simila?
87
+ linha_similar
88
+ else
89
+ linha_multiplas
86
90
  end
87
91
  end
88
92
 
@@ -98,5 +102,78 @@ module Abank
98
102
  end
99
103
  self
100
104
  end
105
+
106
+ # @return [Boolean] linha folha calculo nao existe no bigquery?
107
+ def linha_naoexiste?
108
+ bqres.empty?
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] texto base formatado para display
122
+ def linha_base
123
+ "#{rowfc[0].strftime(DF)} #{format('%<v3>-34.34s %<v4>8.2f', v3: rowfc[2], v4: rowfc[3])}"
124
+ end
125
+
126
+ # @return [String] texto linha existente formatada para display
127
+ def linha_existe
128
+ add_kys if opcao[:e]
129
+ "#{linha_base} EXIS #{format('%<v1>20d', v1: bqres.first[:ky])}"
130
+ end
131
+
132
+ # @return [String] texto linha similar formatada para display
133
+ def linha_similar
134
+ add_kys if opcao[:s]
135
+ "#{linha_base} SIMI #{format('%<v1>-20.20s', v1: bqres.first[:ds].strip)}"
136
+ end
137
+
138
+ # @return [String] texto linha existencia multipla formatada para display
139
+ def linha_multiplas
140
+ "#{linha_base} MULT(#{bqres.count})"
141
+ end
142
+
143
+ # obtem chaves movimento (keysin.mv) para apagar
144
+ def add_kys
145
+ bqres.each { |row| opcao[:k] += ",#{row[:ky]}" }
146
+ end
147
+
148
+ # @return [String] sql para movimentos no bigquery
149
+ def sql_existe_mv
150
+ "select *,#{ky_mv} as ky from #{BD}.mv where nc=#{conta} and dl='#{rowfc[0].strftime(DF)}' and vl=#{rowfc[3]}"
151
+ end
152
+
153
+ # obtem movimento (values.mv) para inserir
154
+ #
155
+ # @return [String] ' NOVO'
156
+ def values_mv
157
+ @mvvls += ",('#{rowfc[0].strftime(DF)}','#{dvc.strftime(DF)}','#{rowfc[2]}',#{rowfc[3]}"\
158
+ ",#{conta},#{dvc.year},#{dvc.month},'#{tpc}',#{ctc})"
159
+ ' NOVO'
160
+ end
161
+
162
+ # @return [Date] data valor corrigida
163
+ def dvc
164
+ dvl = opcao[:v]
165
+ dvl.empty? ? rowfc[1] : Date.parse(dvl)
166
+ end
167
+
168
+ # @return [String] classificacao do movimento (null --> classificacao automatica)
169
+ def ctc
170
+ cmv = opcao[:g]
171
+ cmv.empty? ? 'null' : "'#{cmv}'"
172
+ end
173
+
174
+ # @return [String] tipo movimento c[redito] ou d[ebito]
175
+ def tpc
176
+ rowfc[3].positive? ? 'c' : 'd'
177
+ end
101
178
  end
102
179
  end
data/lib/abank/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Abank
4
- VERSION = '0.4.3'
4
+ VERSION = '0.4.5'
5
5
  end
data/lib/abank.rb CHANGED
@@ -1,17 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require('thor')
4
- require('abank/big1')
5
- require('abank/big2')
6
- require('abank/big3')
7
- require('abank/folha1')
8
- require('abank/folha2')
4
+ require('abank/big')
5
+ require('abank/folha')
9
6
  require('abank/version')
10
7
 
11
8
  # @author Hernani Rodrigues Vaz
12
9
  module Abank
13
10
  DR = "/home/#{`whoami`.chomp}/Downloads"
14
- BD = 'hernanilr.ab'
15
11
 
16
12
  # CLI para carregar folhas calculo comuns no bigquery
17
13
  class CLI < Thor
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.4.3
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hernâni Rodrigues Vaz
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-02 00:00:00.000000000 Z
11
+ date: 2025-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -159,11 +159,8 @@ files:
159
159
  - bin/setup
160
160
  - exe/abank
161
161
  - lib/abank.rb
162
- - lib/abank/big1.rb
163
- - lib/abank/big2.rb
164
- - lib/abank/big3.rb
165
- - lib/abank/folha1.rb
166
- - lib/abank/folha2.rb
162
+ - lib/abank/big.rb
163
+ - lib/abank/folha.rb
167
164
  - lib/abank/version.rb
168
165
  - ruby-lint.yml
169
166
  homepage: https://github.com/hernanirvaz/abank
@@ -172,7 +169,7 @@ licenses:
172
169
  metadata:
173
170
  homepage_uri: https://github.com/hernanirvaz/abank
174
171
  yard.run: yard
175
- post_install_message:
172
+ post_install_message:
176
173
  rdoc_options: []
177
174
  require_paths:
178
175
  - lib
@@ -188,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
185
  version: '0'
189
186
  requirements: []
190
187
  rubygems_version: 3.3.7
191
- signing_key:
188
+ signing_key:
192
189
  specification_version: 4
193
190
  summary: Arquiva movimentos conta-corrente, conta-cartao do activobank no bigquery.
194
191
  test_files: []
data/lib/abank/big1.rb DELETED
@@ -1,108 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require('google/cloud/bigquery')
4
-
5
- module Abank
6
- # @see Big
7
- class Big
8
- # @return [Hash] opcoes trabalho
9
- attr_reader :opcao
10
-
11
- # @return [Google::Cloud::Bigquery::Data] resultado do Structured Query Language (SQL) no bigquery
12
- attr_reader :bqres
13
-
14
- # @return [Integer] numero linhas afetadas pelo Data Manipulation Language (DML) no bigquery
15
- attr_reader :bqnrs
16
-
17
- # acesso a base dados abank no bigquery
18
- #
19
- # @param [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
20
- # @option opcoes [String] :k ('') movimentos a apagar (keysin.mv)
21
- # @option opcoes [String] :c ('') id contrato arrendamento (re)
22
- # @option opcoes [String] :d ('') data inicio contrato arrendamento (re)
23
- # @option opcoes [Boolean] :t (false) trabalha todas as rendas? (re)
24
- # @return [Hash] opcoes trabalho
25
- def initialize(opcoes = {})
26
- @opcao = opcoes
27
- opcao
28
- end
29
-
30
- # @return [Google::Cloud::Bigquery] API bigquery
31
- def bqapi
32
- @bqapi ||= Google::Cloud::Bigquery.new
33
- end
34
-
35
- # @return [String] movimentos a apagar (keysin.mv)
36
- def mvkys
37
- opcao[:k][/([-+]*\d)+(,[-+]*\d+)*/].to_s
38
- end
39
-
40
- # apaga movimentos & suas rendas associadas no bigquery
41
- #
42
- # @return [Big] acesso a base dados abank no bigquery
43
- def mv_delete
44
- @ctlct = []
45
- unless mvkys.empty?
46
- # obtem lista contratos arrendamento associados aos movimentos a apagar
47
- @ctlct = sql("select distinct ct from #{BD}.mv where #{ky_mv} in(#{mvkys}) and substr(ct,1,1)='r'")
48
-
49
- # apaga todas as rendas dos contratos arrendamento associados aos movimentos a apagar
50
- opcao[:t] = true unless ctlct.empty?
51
- re_apaga.mv_delete_dml
52
- end
53
- self
54
- end
55
-
56
- # apaga movimentos no bigquery
57
- def mv_delete_dml
58
- dml("delete from #{BD}.mv where #{ky_mv} in(#{mvkys})")
59
- puts("MOVIMENTOS APAGADOS #{bqnrs}")
60
- end
61
-
62
- # (see CLI#tag)
63
- def mv_classifica
64
- dml("update #{BD}.mv set mv.ct=tt.nct from (select * from #{BD}.cl) as tt where #{ky_mv}=tt.ky")
65
- puts("MOVIMENTOS CLASSIFICADOS #{bqnrs}")
66
- @ctlct = sql("select distinct ct from #{BD}.re") if bqnrs.positive?
67
- self
68
- end
69
-
70
- # @return [String] expressao sql da chave de movimentos
71
- def ky_mv
72
- 'FARM_FINGERPRINT(CONCAT(CAST(mv.nc as STRING),mv.ds,CAST(mv.dl as STRING),CAST(mv.vl as STRING)))'
73
- end
74
-
75
- # @param [String] cmd comando a executar
76
- # @return [Google::Cloud::Bigquery::QueryJob] tarefa SQL/DML no bigquery
77
- def job(cmd)
78
- bqjob = bqapi.query_job(cmd)
79
- bqjob.wait_until_done!
80
- err = bqjob.error
81
- puts(err['message']) if err
82
- bqjob
83
- end
84
-
85
- # executa Structured Query Language (SQL) no bigquery
86
- #
87
- # @param (see job)
88
- # @param [Array] erro resultado quando falha execucao
89
- # @return [Google::Cloud::Bigquery::Data] resultado do SQL
90
- def sql(cmd, erro = [])
91
- # se job.failed? executa job(cmd).data => StandardError
92
- @bqres = job(cmd).data
93
- rescue StandardError
94
- @bqres = erro
95
- end
96
-
97
- # executa Data Manipulation Language (DML) no bigquery
98
- #
99
- # @param (see job)
100
- # @return [Integer] numero rows afetadas pelo DML
101
- def dml(cmd)
102
- # se job.failed? executa Integer(nil) => StandardError
103
- @bqnrs = Integer(job(cmd).num_dml_affected_rows)
104
- rescue StandardError
105
- @bqnrs = 0
106
- end
107
- end
108
- end
data/lib/abank/big2.rb DELETED
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abank
4
- # acesso a base dados abank no bigquery
5
- class Big
6
- DF = '%Y-%m-%d'
7
-
8
- # @return [Integer] contrato arrendamento em tratamento
9
- attr_reader :ctpos
10
-
11
- # (see CLI#criact)
12
- def ct_cria
13
- unless ct_existe?
14
- dml("insert into #{BD}.re #{sql_contrato_mv}")
15
- puts("CONTRATO #{opcao[:c]} #{bqnrs.zero? ? 'NAO ' : ''}INSERIDO")
16
- end
17
- # processar rendas sim/nao?
18
- return unless bqnrs.positive? && opcao[:t]
19
-
20
- # processa rendas associadas ao contrato arrendamento
21
- ct_dados.re_insert
22
- end
23
-
24
- # @return [Boolean] contrato arrendamento ja existe sim/nao?
25
- def ct_existe?
26
- @ctlct = [{ ct: opcao[:c] }]
27
- vaz = sql("select ct from #{BD}.re where ct in(#{str_lc}) and cnt=0").empty?
28
- unless vaz
29
- @bqnrs = 1
30
- puts('CONTRATO JA EXISTE')
31
- end
32
- !vaz
33
- end
34
-
35
- # (see CLI#apagact)
36
- def ct_apaga
37
- @ctlct = [{ ct: opcao[:c] }]
38
- re_delete_dml
39
- end
40
-
41
- # optem lista dados contrato arrendamento (inclui lista movimentos novos)
42
- #
43
- # @return [Big] acesso a base dados abank no bigquery
44
- def ct_dados
45
- ctlct.map! do |ctr|
46
- opcao[:c] = ctr[:ct]
47
- lre = sql(sql_last_re)[0]
48
- ctr.merge(lre, mv: sql(sql_novo_mv(lre[:dl])))
49
- end
50
- self
51
- end
52
-
53
- # @param [Array] are lista rendas novas atual
54
- # @return [Array<String>] lista rendas novas duma lista contratos arrendamento
55
- def ct_rendas(lre = [])
56
- while ctpos < ctlct.size
57
- @mvpos = 0
58
- lre += re_rendas
59
- @ctpos += 1
60
- end
61
- lre
62
- end
63
-
64
- # @example sem dados movimentos
65
- # [{ ct: 'r03000' }, ...]
66
- # @example com dados movimentos
67
- # [{ct: 'r03000', dc: '2020-03-01', ano: 2020, cnt: 0, dl: '2020-03-01', mv: [{dl: '2020-03-02', vl: 30}, ...] }]
68
- # @return [Array<Hash>] lista dados contrato arrendamento (inclui lista movimentos novos)
69
- def ctlct
70
- @ctlct ||= []
71
- end
72
-
73
- # @return [String] texto formatado que representa lista de contratos arrendamento
74
- def str_lc(sep = "'")
75
- ctlct.map { |cid| sep + cid[:ct] + sep }.join(',')
76
- end
77
-
78
- # @return [String] sql para obter ultima renda do contrato arrendamento
79
- def sql_last_re
80
- 'select ct,DATE_SUB(DATE_SUB(dl,INTERVAL dias DAY),INTERVAL IF(cnt=0,0,cnt-1) MONTH) dc,ano,cnt,dl'\
81
- ',CAST(REGEXP_EXTRACT(ct,r"\d+") as numeric)/100 vr '\
82
- "from #{BD}.re where ct='#{opcao[:c]}' order by ano desc,cnt desc limit 1"
83
- end
84
-
85
- # @return [String] sql para obter movimentos novos (depois da ultima renda do contrato arrendamento)
86
- def sql_novo_mv(mdl)
87
- "select dl,vl from #{BD}.mv where ct='#{opcao[:c]}' and dl>='#{(mdl + 1).strftime(DF)}' order by dl,dv"
88
- end
89
-
90
- # @return [String] sql para obter dados do inicio contrato arrendamento
91
- def sql_contrato_mv
92
- cti = opcao[:c]
93
- dat = opcao[:d]
94
- if dat.empty?
95
- 'select ct,EXTRACT(YEAR FROM DATE_TRUNC(dl,MONTH)) ano,0 cnt,DATE_TRUNC(dl,MONTH) dl,0 dias '\
96
- "from #{BD}.mv where ct='#{cti}' order by dl limit 1"
97
- else
98
- "select '#{cti}' ct,EXTRACT(YEAR FROM DATE '#{dat}') ano,0 cnt,DATE '#{dat}' dl,0 dias"
99
- end
100
- end
101
- end
102
- end
data/lib/abank/big3.rb DELETED
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abank
4
- # @see Big
5
- class Big
6
- # @return [Integer] movimento do contrato arrendamento em tratamento
7
- attr_reader :mvpos
8
-
9
- # (see CLI#recriare)
10
- def re_atualiza
11
- # [re]cria rendas novas/todas dos contratos ativos
12
- @ctlct = sql("select distinct ct from #{BD}.re")
13
- re_apaga.ct_dados.re_insert
14
- end
15
-
16
- # insere rendas associadas a lista contratos arrendamento no bigquery
17
- def re_insert
18
- @ctpos = 0
19
- vls = ct_rendas.join(',')
20
- if vls.empty?
21
- puts('NAO EXISTEM RENDAS NOVAS')
22
- else
23
- dml("insert #{BD}.re VALUES#{vls}")
24
- puts("RENDAS #{str_lc('')} CRIADAS #{bqnrs}")
25
- end
26
- end
27
-
28
- # apaga rendas da lista de contrato arrendamento
29
- #
30
- # @return [Big] acesso a base dados abank no bigquery
31
- def re_apaga
32
- return self if !opcao[:t] || ctlct.empty?
33
-
34
- # para nao apagar contrato arrendamento - somente as rendas
35
- opcao[:t] = false
36
-
37
- re_delete_dml
38
- self
39
- end
40
-
41
- # @return [Array<String>] lista rendas novas dum contrato arrendamento
42
- def re_rendas
43
- lre = []
44
- while mvpos < re_atual[:mv].size && re_saldo_mv?
45
- lre << re_nova_renda
46
- @mvpos += 1 unless re_saldo_mv?
47
- end
48
- lre
49
- end
50
-
51
- # @return [String] renda formatada (values.re)
52
- def re_nova_renda
53
- re_proximos_dados
54
- "('#{re_atual[:ct]}',#{ano},#{cnt},'#{re_atual_mv[:dl].strftime(DF)}',#{dias})"
55
- end
56
-
57
- # @return [Hash] dados contrato arrendamento (inclui lista movimentos novos)
58
- def re_proximos_dados
59
- # valor renda paga retirada do movimento
60
- re_atual_mv[:vl] -= re_atual[:vr]
61
- dre = cnt.zero? ? Date.new(ano, 1, 1) : Date.new(ano, cnt, 1) >> 1
62
- re_atual.merge!(ano: dre.year, cnt: dre.month)
63
- end
64
-
65
- # apaga rendas da lista de contratos arrendamento
66
- def re_delete_dml
67
- dml("delete from #{BD}.re where ct in(#{str_lc})#{opcao[:t] ? '' : ' and cnt>0'}")
68
- puts("RENDAS #{str_lc('')} APAGADAS #{bqnrs}")
69
- end
70
-
71
- # @return [Boolean] movimento com saldo suficiente?
72
- def re_saldo_mv?
73
- re_atual_mv[:vl] >= re_atual[:vr]
74
- end
75
-
76
- # @return [Hash] dados contrato arrendamento atual (inclui lista movimentos novos)
77
- def re_atual
78
- ctlct[ctpos]
79
- end
80
-
81
- # @return [Hash] movimento atual contrato arrendamento
82
- def re_atual_mv
83
- re_atual[:mv][mvpos]
84
- end
85
-
86
- # @return [Integer] ano da renda
87
- def ano
88
- re_atual[:ano]
89
- end
90
-
91
- # @return [Integer] numero da renda (0-12)
92
- def cnt
93
- re_atual[:cnt]
94
- end
95
-
96
- # @return [Integer] dias atraso/antecipo neste pagamento renda
97
- def dias
98
- re_atual_mv[:dl].mjd - (Date.new(ano, cnt, 1) >> (re_atual[:dc].month - 1)).mjd
99
- end
100
- end
101
- end
data/lib/abank/folha2.rb DELETED
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abank
4
- # acesso a folha calculo & base dados abank no bigquery
5
- class Folha < Big
6
- # @return [Boolean] linha folha calculo nao existe no bigquery?
7
- def linha_naoexiste?
8
- bqres.empty?
9
- end
10
-
11
- # @return [Boolean] linha folha calculo existe no bigquery?
12
- def linha_existe?
13
- bqres.count == 1 && bqres.first[:ds].strip == rowfc[2]
14
- end
15
-
16
- # @return [Boolean] linha folha calculo existe parecida no bigquery?
17
- def linha_simila?
18
- bqres.count == 1 && bqres.first[:ds].strip != rowfc[2]
19
- end
20
-
21
- # @return [String] texto base formatado para display
22
- def linha_base
23
- "#{rowfc[0].strftime(DF)} #{format('%<v3>-34.34s %<v4>8.2f', v3: rowfc[2], v4: rowfc[3])}"
24
- end
25
-
26
- # @return [String] texto linha existente formatada para display
27
- def linha_existe
28
- add_kys if opcao[:e]
29
- "#{linha_base} EXIS #{format('%<v1>20d', v1: bqres.first[:ky])}"
30
- end
31
-
32
- # @return [String] texto linha similar formatada para display
33
- def linha_similar
34
- add_kys if opcao[:s]
35
- "#{linha_base} SIMI #{format('%<v1>-20.20s', v1: bqres.first[:ds].strip)}"
36
- end
37
-
38
- # @return [String] texto linha existencia multipla formatada para display
39
- def linha_multiplas
40
- "#{linha_base} MULT(#{bqres.count})"
41
- end
42
-
43
- # obtem chaves movimento (keysin.mv) para apagar
44
- def add_kys
45
- bqres.each { |row| opcao[:k] += ",#{row[:ky]}" }
46
- end
47
-
48
- # @return [String] sql para movimentos no bigquery
49
- def sql_existe_mv
50
- "select *,#{ky_mv} as ky from #{BD}.mv where nc=#{conta} and dl='#{rowfc[0].strftime(DF)}' and vl=#{rowfc[3]}"
51
- end
52
-
53
- # obtem movimento (values.mv) para inserir
54
- #
55
- # @return [String] ' NOVO'
56
- def values_mv
57
- @mvvls += ",('#{rowfc[0].strftime(DF)}','#{dvc.strftime(DF)}','#{rowfc[2]}',#{rowfc[3]}"\
58
- ",#{conta},#{dvc.year},#{dvc.month},'#{tpc}',#{ctc})"
59
- ' NOVO'
60
- end
61
-
62
- # @return [Date] data valor corrigida
63
- def dvc
64
- dvl = opcao[:v]
65
- dvl.empty? ? rowfc[1] : Date.parse(dvl)
66
- end
67
-
68
- # @return [String] classificacao do movimento (null --> classificacao automatica)
69
- def ctc
70
- cmv = opcao[:g]
71
- cmv.empty? ? 'null' : "'#{cmv}'"
72
- end
73
-
74
- # @return [String] tipo movimento c[redito] ou d[ebito]
75
- def tpc
76
- rowfc[3].positive? ? 'c' : 'd'
77
- end
78
- end
79
- end