abank 0.2.0 → 0.2.5

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: 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