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 +7 -0
- data/lib/faktura/cli.rb +52 -0
- data/lib/faktura/helpers.rb +46 -0
- data/lib/faktura/pdf.rb +87 -0
- data/lib/faktura/stamp.rb +78 -0
- data/lib/faktura.rb +11 -0
- metadata +96 -0
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
|
data/lib/faktura/cli.rb
ADDED
@@ -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
|
data/lib/faktura/pdf.rb
ADDED
@@ -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
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: []
|