abank 0.2.0 → 0.2.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: 2a59c02ce2b0191c7352505afee9cc70a9cb089e13f8eff6bdb9fadd8033b71c
4
- data.tar.gz: c010bc3136f075a8323403b147e064cfc4b34e3eacb38a71fddb88b84f5204eb
3
+ metadata.gz: 357eabd6927351fcd006bf58dda24c7b323395749b4ab6ef4ecf6f596a126241
4
+ data.tar.gz: 0c3fc3b9e2ebda8bfe13b0ba072f50b0ff303668dfde4ffa7378e04f1470b81e
5
5
  SHA512:
6
- metadata.gz: 174bdd47142b4344abafeadff04c89a8cbea380d508667ba68ea27c602d98eb10a5920972fd017058e6f260712519b4e2d952ff3cdf854f893b9fffd79ee4e33
7
- data.tar.gz: f62757b9667bfbcdfe8efbf85083d6bc2cd1351af83e8b3f7307fff9b4cffd13feff922242fdb0e23db1fdce25704dac89f88ba00f8123819302c31fed8fbc0c
6
+ metadata.gz: b11a19c0f7039ff253776441e4f7b7de443808c4bf90dfec078a65dab3342b40197017d36e69d30d09d35500afd6e187ebe7113580e36ef921737085599c26af
7
+ data.tar.gz: 98daf017bef2b5860fe498c9f11f6881374ebaa87451a10bf24fe1fa95006230c734a6dc1176e036983ec0e991777e59cfebaa34f2c2bc67828d3b95563163ae
@@ -0,0 +1,33 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+ EnabledByDefault: true
4
+
5
+ Style/ClassAndModuleChildren:
6
+ EnforcedStyle: compact
7
+
8
+ Style/Copyright:
9
+ Enabled: false
10
+
11
+ Style/DocumentationMethod:
12
+ Enabled: false
13
+
14
+ Style/MethodCallWithArgsParentheses:
15
+ Enabled: false
16
+
17
+ Style/ConstantVisibility:
18
+ Enabled: false
19
+
20
+ Layout/MultilineMethodArgumentLineBreaks:
21
+ Enabled: false
22
+
23
+ Layout/MultilineHashKeyLineBreaks:
24
+ Enabled: false
25
+
26
+ Layout/FirstMethodParameterLineBreak:
27
+ Enabled: false
28
+
29
+ Layout/FirstHashElementLineBreak:
30
+ Enabled: false
31
+
32
+ Style/MissingElse:
33
+ Enabled: false
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in abank.gemspec
4
6
  gemspec
5
7
 
6
- gem "rake", "~> 12.0"
8
+ gem 'rake', '~> 12.0'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- abank (0.2.0)
4
+ abank (0.2.5)
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.38.0)
20
+ google-api-client (0.40.1)
21
21
  addressable (~> 2.5, >= 2.5.1)
22
22
  googleauth (~> 0.9)
23
23
  httpclient (>= 2.8.1, < 3.0)
@@ -25,7 +25,7 @@ GEM
25
25
  representable (~> 3.0)
26
26
  retriable (>= 2.0, < 4.0)
27
27
  signet (~> 0.12)
28
- google-cloud-bigquery (1.21.0)
28
+ google-cloud-bigquery (1.21.1)
29
29
  concurrent-ruby (~> 1.0)
30
30
  google-api-client (~> 0.33)
31
31
  google-cloud-core (~> 1.2)
@@ -34,9 +34,9 @@ GEM
34
34
  google-cloud-core (1.5.0)
35
35
  google-cloud-env (~> 1.0)
36
36
  google-cloud-errors (~> 1.0)
37
- google-cloud-env (1.3.1)
37
+ google-cloud-env (1.3.2)
38
38
  faraday (>= 0.17.3, < 2.0)
39
- google-cloud-errors (1.0.0)
39
+ google-cloud-errors (1.0.1)
40
40
  googleauth (0.12.0)
41
41
  faraday (>= 0.17.3, < 2.0)
42
42
  jwt (>= 1.4, < 3.0)
@@ -54,7 +54,7 @@ GEM
54
54
  nokogiri (1.10.9)
55
55
  mini_portile2 (~> 2.4.0)
56
56
  os (1.1.0)
57
- public_suffix (4.0.4)
57
+ public_suffix (4.0.5)
58
58
  rake (12.3.3)
59
59
  representable (3.0.4)
60
60
  declarative (< 0.1.0)
@@ -72,7 +72,7 @@ GEM
72
72
  multi_json (~> 1.10)
73
73
  thor (1.0.1)
74
74
  uber (0.1.0)
75
- yard (0.9.24)
75
+ yard (0.9.25)
76
76
 
77
77
  PLATFORMS
78
78
  ruby
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Abank [![Build Status](https://travis-ci.com/hernanirvaz/abank.svg?branch=master)](https://travis-ci.com/hernanirvaz/abank)
2
2
 
3
- Arquiva movimentos conta-corrente, conta-cartao do activobank no bigquery. Permite apagar movimentos similares/existentes ja no bigquery. Permite ainda classificar movimentos ja no bigquery.
3
+ Arquiva movimentos conta-corrente, conta-cartao do activobank no bigquery. Permite apagar/recriar movimentos/rendas ja no bigquery. Permite ainda classificar movimentos no bigquery.
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,10 +20,14 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- $ abank help [COMANDO] # ajuda aos comandos
24
- $ abank mostra # mostra dados da folha calculo
25
- $ abank load # carrega dados da folha calculo no bigquery
26
- $ abank classifica # classifica arquivo no bigquery
23
+ $ abank apagamv -k=KEY[,KEY...] # apaga movimentos
24
+ $ abank apagact -c=CONTRATO # apaga contrato arrendamento
25
+ $ abank criact -c=CONTRATO # cria contrato arrendamento
26
+ $ abank recriact -c=CONTRATO # atualiza rendas de contrato arrendamento
27
+ $ abank recriare # atualiza rendas dos contratos ativos
28
+ $ abank load # carrega dados da folha calculo
29
+ $ abank show # mostra dados da folha calculo
30
+ $ abank tag # classifica movimentos
27
31
 
28
32
  ## Development
29
33
 
data/Rakefile CHANGED
@@ -1,2 +1,4 @@
1
- require "bundler/gem_tasks"
2
- task :default => :build
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ task default: :build
@@ -10,12 +10,9 @@ Gem::Specification.new do |spec|
10
10
  spec.homepage = 'https://github.com/hernanirvaz/abank'
11
11
  spec.license = 'MIT'
12
12
 
13
- spec.summary = 'Arquiva <conta-corrente>.xlsx,' \
14
- ' <conta-cartao>.xlsx no bigquery.'
15
- spec.description = spec.summary +
16
- ' Pode apagar movimentos similares/existentes' \
17
- ' ja no bigquery.' \
18
- ' Pode ainda classificar movimentos ja no bigquery.'
13
+ spec.summary = 'Arquiva movimentos conta-corrente, conta-cartao do activobank no bigquery.'
14
+ spec.description = spec.summary + ' Permite apagar/recriar movimentos/rendas ja no bigquery. ' \
15
+ ' Permite ainda classificar movimentos no bigquery.'
19
16
 
20
17
  spec.metadata['homepage_uri'] = spec.homepage
21
18
  spec.metadata['yard.run'] = 'yard'
@@ -24,10 +21,10 @@ Gem::Specification.new do |spec|
24
21
 
25
22
  # Specify which files should be added to the gem when it is released.
26
23
  # The `git ls-files -z` loads files in RubyGem that have been added into git.
27
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
- `git ls-files -z`.split("\x0")
29
- .reject { |f| f.match(%r{^(test|spec|features)/}) }
30
- end
24
+ spec.files =
25
+ Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
31
28
  spec.bindir = 'exe'
32
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
30
  spec.require_paths = ['lib']
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "abank"
4
+ require 'bundler/setup'
5
+ require 'abank'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "abank"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start(__FILE__)
@@ -1,55 +1,94 @@
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
9
11
  module Abank
10
- ID = `whoami`.chomp
12
+ DR = "/home/#{`whoami`.chomp}/Downloads"
11
13
 
12
14
  class Error < StandardError; end
13
15
 
14
16
  # CLI para carregar folhas calculo comuns no bigquery
15
17
  class CLI < Thor
16
- desc 'load', 'carrega dados da folha calculo no bigquery'
17
- option :d, banner: 'DIR', default: "/home/#{ID}/Downloads",
18
- desc: 'Onde procurar folhas calculo'
19
- option :x, banner: 'EXT', default: '.xlsx',
20
- desc: 'Extensao das folhas calculo'
21
- option :s, type: :boolean, default: false,
22
- desc: 'apaga linha similar no bigquery'
23
- option :e, type: :boolean, default: false,
24
- desc: 'apaga linha igual no bigquery'
25
- option :m, type: :boolean, default: false,
26
- desc: 'apaga linhas existencia multipla no bigquery'
27
- # processa folha calculo
18
+ desc 'tag', 'classifica movimentos'
19
+ # classifica movimentos
20
+ def tag
21
+ Big.new.mv_classifica
22
+ end
23
+
24
+ desc 'apagamv', 'apaga movimentos'
25
+ option :k, banner: 'KEY[,KEY...]', required: true, desc: 'keys movimentos a apagar'
26
+ # apaga movimentos
27
+ def apagamv
28
+ Big.new(k: options[:k]).mv_delete.mv_insert.re_work
29
+ end
30
+
31
+ desc 'criact', 'cria contrato arrendamento'
32
+ option :c, banner: 'CONTRATO', required: true, desc: 'Identificador contrato arrendamento'
33
+ option :t, type: :boolean, default: true, desc: 'cria todas as rendas?'
34
+ option :d, banner: 'DATA', default: '', desc: 'data contrato arrendamento'
35
+ # cria contrato arrendamento
36
+ def criact
37
+ Big.new(c: options[:c], t: options[:t], d: options[:d]).ct_cria
38
+ end
39
+
40
+ desc 'apagact', 'apaga contrato arrendamento'
41
+ option :c, banner: 'CONTRATO', required: true, desc: 'Identificador contrato arrendamento'
42
+ option :t, type: :boolean, default: false, desc: 'apaga todas as rendas?'
43
+ # apaga contrato arrendamento
44
+ def apagact
45
+ Big.new(c: options[:c], t: options[:t]).ct_apaga
46
+ end
47
+
48
+ desc 'recriact', 'atualiza rendas de contrato arrendamento'
49
+ option :c, banner: 'CONTRATO', required: true, desc: 'Identificador contrato arrendamento'
50
+ option :t, type: :boolean, default: false, desc: 'apaga todas as rendas?'
51
+ option :d, banner: 'DATA', default: '', desc: 'data contrato arrendamento'
52
+ # atualiza rendas de contrato arrendamento
53
+ def recriact
54
+ Big.new(c: options[:c], t: options[:t]).ct_apaga
55
+ Big.new(c: options[:c], t: true, d: options[:d]).ct_cria
56
+ end
57
+
58
+ desc 'recriare', 'atualiza rendas dos contratos ativos'
59
+ option :t, type: :boolean, default: false, desc: 'atualiza todas as rendas?'
60
+ # atualiza rendas dos contratos ativos
61
+ def recriare
62
+ Big.new(t: options[:t]).re_atualiza
63
+ end
64
+
65
+ desc 'load', 'carrega dados da folha calculo'
66
+ option :s, type: :boolean, default: false, desc: 'apaga movimento similar'
67
+ option :e, type: :boolean, default: false, desc: 'apaga movimento igual'
68
+ option :v, banner: 'DATA', default: '', desc: 'data valor para movimentos a carregar'
69
+ option :g, banner: 'TAG', default: '', desc: 'classificacao para movimentos a carregar'
70
+ # carrega folha calculo
28
71
  def load
29
- Dir.glob("#{options[:d]}/*#{options[:x]}").sort.each do |f|
30
- Bigquery.new(f, { s: options[:s], e: options[:e],
31
- m: options[:m], i: true }).processa
72
+ Dir.glob("#{DR}/*.xlsx").sort.each do |f|
73
+ Big::Folha.new(load_opc.merge(f: f)).processa_xls
32
74
  end
33
75
  end
34
76
 
35
- desc 'mostra', 'mostra dados da folha calculo'
36
- option :d, banner: 'DIR', default: "/home/#{ID}/Downloads",
37
- desc: 'Onde procurar folhas calculo'
38
- option :x, banner: 'EXT', default: '.xlsx',
39
- desc: 'Extensao das folhas calculo'
77
+ desc 'show', 'mostra dados da folha calculo'
40
78
  # mostra folha calculo
41
- def mostra
42
- Dir.glob("#{options[:d]}/*#{options[:x]}").sort.each do |f|
43
- Bigquery.new(f).processa
79
+ def show
80
+ Dir.glob("#{DR}/*.xlsx").sort.each do |f|
81
+ Big::Folha.new(f: f).processa_xls
44
82
  end
45
83
  end
46
84
 
47
- desc 'classifica', 'classifica arquivo no bigquery'
48
- # classifica arquivo no bigquery
49
- def classifica
50
- Bigquery.new.classifica
85
+ no_commands do
86
+ # @return [Hash] opcoes trabalho com movimentos para load
87
+ def load_opc
88
+ { s: options[:s], e: options[:e], i: true, v: options[:v], g: options[:g] }
89
+ end
51
90
  end
52
91
 
53
- default_task :mostra
92
+ default_task :show
54
93
  end
55
94
  end
@@ -0,0 +1,134 @@
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
@@ -0,0 +1,107 @@
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
@@ -0,0 +1,154 @@
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
@@ -0,0 +1,121 @@
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Abank
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.5'
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.0
4
+ version: 0.2.5
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-03 00:00:00.000000000 Z
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,9 +94,9 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- description: Arquiva <conta-corrente>.xlsx, <conta-cartao>.xlsx no bigquery. Pode
98
- apagar movimentos similares/existentes ja no bigquery. Pode ainda classificar movimentos
99
- ja no bigquery.
97
+ description: Arquiva movimentos conta-corrente, conta-cartao do activobank no bigquery.
98
+ Permite apagar/recriar movimentos/rendas ja no bigquery. Permite ainda classificar
99
+ movimentos no bigquery.
100
100
  email:
101
101
  - hernanirvaz@gmail.com
102
102
  executables:
@@ -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:
@@ -140,8 +143,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
143
  - !ruby/object:Gem::Version
141
144
  version: '0'
142
145
  requirements: []
143
- rubygems_version: 3.0.3
146
+ rubygems_version: 3.0.8
144
147
  signing_key:
145
148
  specification_version: 4
146
- summary: Arquiva <conta-corrente>.xlsx, <conta-cartao>.xlsx no bigquery.
149
+ summary: Arquiva movimentos conta-corrente, conta-cartao do activobank no bigquery.
147
150
  test_files: []
@@ -1,115 +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<Symbol, Boolean>] 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<Symbol, Boolean>] 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
- # @return [Bigquery] acesso folhas calculo activobank
34
- # & correspondente bigquery dataset
35
- def initialize(xls = '', ops = { s: false, e: false, m: false, i: false })
36
- # usa env GOOGLE_APPLICATION_CREDENTIALS para obter credentials
37
- # @see https://cloud.google.com/bigquery/docs/authentication/getting-started
38
- @apibq = Google::Cloud::Bigquery.new
39
- @folha = Roo::Spreadsheet.open(xls) if xls.size.positive?
40
- @linha = ops
41
- @conta = xls.match?(/card/i) ? 2 : 1
42
- end
43
-
44
- # cria job bigquery & verifica execucao
45
- #
46
- # @param [String] sql a executar
47
- # @return [Boolean] job ok?
48
- def job_bigquery?(sql)
49
- @job = apibq.query_job(sql)
50
- @job.wait_until_done!
51
- puts @job.error['message'] if @job.failed?
52
- @job.failed?
53
- end
54
-
55
- # cria Data Manipulation Language (DML) job bigquery
56
- #
57
- # @param (see job_bigquery?)
58
- # @return [Integer] numero linhas afetadas
59
- def dml(sql)
60
- job_bigquery?(sql) ? 0 : job.num_dml_affected_rows
61
- end
62
-
63
- # pesquisa existencia linha folha calculo no bigquery
64
- #
65
- # @return [Google::Cloud::Bigquery::Data] resultado do sql num array<hash>
66
- def sql_select
67
- # array.count = 0 ==> pode carregar esta linha
68
- # array.count = 1 ==> mais testes necessarios
69
- # array.count > 1 ==> nao carregar esta linha
70
- @sql = job_bigquery?('select * ' + sql_where) ? [{}, {}] : job.data
71
- end
72
-
73
- # @return [String] parte sql para processamento linhas similares
74
- def sql_where
75
- "from hernanilr.ab.mv where nc=#{conta}" \
76
- " and dl='#{row[0].strftime(DF)}'" \
77
- " and vl=#{row[3]}"
78
- end
79
-
80
- # (see CLI#classifica)
81
- def classifica
82
- return unless linha[:i]
83
-
84
- puts 'LINHAS CLASSIFICADAS ' +
85
- dml('update hernanilr.ab.mv set mv.ct=tt.nct' \
86
- ' from (select * from hernanilr.ab.cl) as tt' \
87
- ' where mv.dl=tt.dl and mv.dv=tt.dv' \
88
- ' and mv.ds=tt.ds and mv.vl=tt.vl').to_s
89
- end
90
-
91
- # @return [Integer] numero linhas inseridas
92
- def sql_insert
93
- return 1 unless linha[:i]
94
-
95
- dml('insert hernanilr.ab.mv(dl,dv,ds,vl,nc,ano,mes,ct,tp) VALUES(' \
96
- "'#{row[0].strftime(DF)}','#{row[1].strftime(DF)}','#{row[2]}'" +
97
- str_insert1)
98
- end
99
-
100
- # @return [String] campos extra da linha bigquery
101
- def str_insert1
102
- ",#{row[3]},#{conta}" + str_insert2
103
- end
104
-
105
- # @return [String] campos calculados da linha bigquery
106
- def str_insert2
107
- ",#{row[1].year},#{row[1].month},null,'#{row[3].positive? ? 'c' : 'd'}')"
108
- end
109
-
110
- # @return [Integer] numero linhas apagadas
111
- def sql_delete
112
- dml('delete ' + sql_where + " and ds='#{sql.first[:ds].strip}'")
113
- end
114
- end
115
- 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