faktura 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f8106f0a71c88bb63b5c373b997d9e80b2a4266f
4
+ data.tar.gz: 0a9919fd9724752398d3e810cc1ed088a168846a
5
+ SHA512:
6
+ metadata.gz: f5c8b0f90048ca37693b9b89f795cd6db632f756370059e3c0a90fb92ed70cf5f088f1a6f7bb9092cc2cfd7c6a1d8f338a12a2116fd260f711895cd1268a50a1
7
+ data.tar.gz: 17620b0414d2867957938552d33b9cbfc8b73b118e665f038114e1e343eceae30340395aa052f9f5120d6db756a323d743034595ed49a4eb587ffb969947970b
@@ -0,0 +1,52 @@
1
+
2
+ module Faktura
3
+ class CLI < Clamp::Command
4
+ include Faktura::Helpers
5
+ option ['-n', '--directory'], :flag, 'param is directory'
6
+ option ['-D', '--dump'], :flag, 'dump content'
7
+ option ['-s', '--stamp'], :flag, 'stamp invoice'
8
+ option ['-p', '--printer'], 'PRINTER', 'print (stamped) invoice'
9
+ option ['-o', '--open'], :flag, 'open (stamped) invoice'
10
+ option ['-w', '--window'], :flag, 'Ask using a dialog window'
11
+ parameter 'names ...', 'files or directories', attribute_name: :names
12
+
13
+ def execute
14
+ names.each do |name|
15
+ if directory?
16
+ Dir["#{name}/**/*.pdf"].each do |fn|
17
+ process fn
18
+ end
19
+ else
20
+ process name
21
+ end
22
+ end
23
+ end
24
+
25
+ def process(filename)
26
+ pdf = PDF.new filename
27
+ stamped_filename = nil
28
+
29
+ puts "#{filename}: #{pdf}".colorize(:light_blue)
30
+ if dump?
31
+ puts pdf.content
32
+ end
33
+
34
+ if stamp?
35
+ stamper = Faktura::Stamp.new(pdf)
36
+ stamped = stamper.stamp(get_name, get_description(pdf))
37
+ stamped_filename = output_file(filename)
38
+ stamped.write stamped_filename
39
+ puts "Created file #{stamped_filename}".colorize(:light_yellow)
40
+ end
41
+
42
+ if printer
43
+ puts "Printing #{stamped_filename || filename} to printer #{printer}".colorize(:green)
44
+ system('lpr', '-P', printer, stamped_filename || filename)
45
+ end
46
+
47
+ if open?
48
+ system('xdg-open', stamped_filename || filename)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,46 @@
1
+ module Faktura
2
+ module Helpers
3
+ def output_file(filename, postfix = '_stamped')
4
+ dir = File.dirname(filename)
5
+ ext = File.extname(filename)
6
+ base = File.basename(filename, ext)
7
+ File.expand_path "#{base}#{postfix}#{ext}", dir
8
+ end
9
+
10
+ def get_name
11
+ pw = Etc.getpwnam Etc.getlogin
12
+ fn = pw.gecos.split(',').first
13
+ if fn.nil?
14
+ ask_for "I don't know your full name, please specify: "
15
+ STDIN.gets.chomp
16
+ else
17
+ fn
18
+ end
19
+ end
20
+
21
+ def get_description(invoice)
22
+ prov = invoice.provider
23
+ if prov && (desc = description_for(prov))
24
+ return desc
25
+ else
26
+ ask_for "Can't out the invoice description. Write one: "
27
+ end
28
+ end
29
+
30
+ def ask_for(question)
31
+ if window?
32
+ IO.popen(['zenity', '--entry', '--text=' + question]) do |pin, _pout|
33
+ pin.gets.chomp
34
+ end
35
+ else
36
+ print question.colorize(:light_red)
37
+ STDIN.gets.chomp
38
+ end
39
+ end
40
+
41
+ def description_for(provider)
42
+ @providerdb ||= YAML.safe_load(open(File.expand_path('faktura.yml', File.dirname(__FILE__))))
43
+ @providerdb['description'][provider.to_s]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,87 @@
1
+ # coding: utf-8
2
+ class Faktura::PDF
3
+ attr_reader :filename
4
+ attr_reader :content
5
+ attr_reader :date
6
+ attr_reader :amount
7
+ attr_reader :provider
8
+ attr_reader :currency
9
+
10
+ def initialize(filename)
11
+ @filename = filename
12
+ @content = read
13
+ @date = nil
14
+ @provider = nil
15
+ @currency = nil
16
+
17
+ analyze
18
+ end
19
+
20
+ def read
21
+ IO.popen(['pdftotext', @filename, '-']) do |io|
22
+ io.read
23
+ end
24
+ end
25
+
26
+ def analyze
27
+ SIGNATURES.each do |prv, opt|
28
+ if content =~ opt[:name]
29
+ @provider = prv
30
+ @currency = opt[:currency]
31
+
32
+ if opt.has_key? :date and date_m = content.match(opt[:date])
33
+ @date = date_m[1]
34
+ end
35
+
36
+ if opt.has_key? :amount and amount_m = content.match(opt[:amount])
37
+ @amount = amount_m[1]
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+
44
+ SIGNATURES = {
45
+ csl: {
46
+ name: /ChangeSprout Inc./,
47
+ date: /Issue Date:\n+(\d+ \w+ \d+)/,
48
+ amount: /Amount Due\n\n([\d.]+)/,
49
+ currency: 'USD'
50
+ },
51
+ aws: {
52
+ name: /Amazon Web Services/,
53
+ date: /Invoice Date:\n+\d+\n(\w+ \d+ *, *\d+)/,
54
+ amount: /TOTAL AMOUNT DUE[^\n]+\n\n[$]([\d.]+)/,
55
+ currency: 'USD'
56
+ },
57
+ freshdesk: {
58
+ name: /Freshworks Inc./,
59
+ date: /Invoice Date (\w+ \d+, \d+)/,
60
+ amount: /Invoice Amount ([\d,]+) €/,
61
+ currency: 'EUR'
62
+ },
63
+ newrelic: {
64
+ name: /New Relic Inc./,
65
+ date: /Description\n+\w+ \d+ - (\w+ \d+ \d+)/,
66
+ amount: /Total Due[^\n]+\n+[$]([\d.]+)/,
67
+ currency: 'USD'
68
+ },
69
+ ovh: {
70
+ name: /OVH Sp. z o.o./,
71
+ date: /Data wystawienia: ([\d-]+)/,
72
+ amount: /Razem brutto.+(^[\d.]+) PLN/m,
73
+ currency: 'PLN'
74
+ },
75
+ zoom: {
76
+ name: /Zoom Video Communications/,
77
+ date: /Transaction\nType\n+([\d\/]+)/,
78
+ amount: /Applied\nAmount\n[($]+([\d.]+)[)]/,
79
+ currency: 'USD'
80
+ }
81
+
82
+ }
83
+
84
+ def to_s
85
+ "#{provider} (#{date}) #{currency}#{amount or '???'}"
86
+ end
87
+ end
@@ -0,0 +1,78 @@
1
+ # coding: utf-8
2
+ require 'hexapdf'
3
+
4
+ class Faktura::Stamp
5
+ TIMES_NEW_ROMAN = '/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf'
6
+
7
+ def initialize(pdf)
8
+ @filename = pdf
9
+ if pdf.class == Faktura::PDF
10
+ @filename = pdf.filename
11
+ end
12
+ @start_y = 400
13
+ @cursor_y = @start_y
14
+ end
15
+
16
+ RED = [200, 0, 0]
17
+ INDENT=50
18
+ RIGHT_END=400
19
+ SKIP_LINE=18
20
+
21
+ def stamp(name, description, output_file=nil)
22
+ pdf = HexaPDF::Document.open(@filename)
23
+ @canvas = pdf.pages.add.canvas
24
+
25
+ style = HexaPDF::Layout::Style.new
26
+ style.font = pdf.fonts.add(TIMES_NEW_ROMAN)
27
+ style.font_size = 12
28
+ style.stroke_color = RED
29
+ style.fill_color = RED
30
+ @style = style
31
+
32
+
33
+ put_line "Imie i nazwisko: #{name}", dashes: false
34
+ put_line "Forma płatności: zwrot poniesionych kosztów/przelew/karta służbowa", dashes: false
35
+ put_line "Opis kosztu: #{description}", dashes: false
36
+ put_line "Data i podpis: #{Time.now.strftime("%d-%m-%Y")}"
37
+ hr INDENT, RIGHT_END, @cursor_y + SKIP_LINE/2
38
+ @cursor_y -= SKIP_LINE / 2
39
+ put_line "Sprawdzono pod względem merytorycznym:"
40
+ put_line "Sprawdzono pod względem formalnym i rachunkowym:"
41
+ put_line "Zatwierdzono do wypłaty:"
42
+ put_line "Data:"
43
+ put_line "Koszt finansowany z:"
44
+ if output_file
45
+ pdf.write output_file
46
+ end
47
+ pdf
48
+ end
49
+
50
+ def put_line(text, dashes: true)
51
+ @canvas.font(@style.font, size: 12)
52
+ @canvas.fill_color(@style.fill_color)
53
+
54
+ @canvas.move_text_cursor(offset: [INDENT, @cursor_y], absolute: true)
55
+ @canvas.text(text)
56
+ text_end = @canvas.text_cursor[0]
57
+
58
+ if dashes
59
+ finish_dash(text_end + 10,
60
+ RIGHT_END,
61
+ @cursor_y)
62
+ end
63
+
64
+ @cursor_y -= SKIP_LINE
65
+ end
66
+
67
+ def hr(x1, x2, y)
68
+ @canvas.stroke_color(RED).line_dash_pattern(0).line_width(1).line(x1, y, x2, y).stroke
69
+ end
70
+
71
+ def finish_dash(x1, x2, y)
72
+ @canvas.stroke_color RED
73
+ @canvas.line_dash_pattern = [1, 5]
74
+ @canvas.line_width = 0.5
75
+ @canvas.line(x1, y, x2, y)
76
+ @canvas.stroke
77
+ end
78
+ end
data/lib/faktura.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'clamp'
2
+ require 'colorize'
3
+ require 'yaml'
4
+ require 'etc'
5
+
6
+ require 'faktura/helpers'
7
+ require 'faktura/cli'
8
+ require 'faktura/pdf'
9
+ require 'faktura/stamp'
10
+
11
+
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: faktura
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Marcin Koziej
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: clamp
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.3.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.3.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: colorize
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.8.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.8.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: hexapdf
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.9.0
61
+ description: This tool shows invocies issuers, and summarizes which invoices are downloaded
62
+ email: marcin@akcjademokracja.pl
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - "./lib/faktura.rb"
68
+ - "./lib/faktura/cli.rb"
69
+ - "./lib/faktura/helpers.rb"
70
+ - "./lib/faktura/pdf.rb"
71
+ - "./lib/faktura/stamp.rb"
72
+ homepage: http://rubygems.org/gems/faktura
73
+ licenses:
74
+ - 0BSD
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.6.14.1
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Fakturator is a command line tool to help with gathering invoices
96
+ test_files: []