invoicegenerator 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2a2ae2f90644130b064a3f74f499282010910997c1b01f91bb54b2262e9f26d0
4
+ data.tar.gz: 7f182917dad778dce5e3e957d130b6d28d07782bccf37a1d1b511f06909336d9
5
+ SHA512:
6
+ metadata.gz: 8360844a20cdbcddd216504f8d724f99d5e3cddcbf131542ad7a534aa89ebeb0fc09f2bea23469b146e8fadb5796f3d7f40065ca20123d0ac5b198a121973ea4
7
+ data.tar.gz: 66c310273372f90b18123e40d530e470dc6dde89473e0bac870873d798d2a008c59acfcd8edaaaf91b2695a6c01aa1823c1339760f7d72324b636ccb4d5b8784
@@ -0,0 +1,5 @@
1
+ *.pdf
2
+ Gemfile.lock
3
+ *.yml
4
+ *.rubyproject
5
+ invoicegenerator-*.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Stupid invoice generator
2
+
3
+ Put the data you usualy uses to create your invoices into a YML file, run this
4
+ gem and done, you have a nice pdf invoice
5
+
6
+ To see an example the fast possible way run:
7
+
8
+ ```
9
+ $ gem install invoicegenerator
10
+ $ invoicegenerator --show-yml-example | invoicegenerator --stdin
11
+ ```
12
+
13
+ To have a starting point to write your YAML describing your invoice, type:
14
+
15
+ ```
16
+ $ invoicegenerator --show-yml-example > invoice.yml
17
+ ```
18
+
19
+ Then change the generated invoice.yml
20
+
21
+ ## How to change the invoice template?
22
+
23
+ Use the --template command line switch to specify an HTML template, to have a look in a example, type:
24
+
25
+ ```
26
+ $ invoicegenerator --show-template-example
27
+ ```
28
+
29
+ ## What to write in the YAML file?
30
+
31
+ Run `invoicegenerator.rb --show-yml-example` and you will see an example, basically you can use all keys you find as a command line option.
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'invoicegenerator'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'invoicegenerator'
4
+
5
+ InvoiceGenerator.main
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'invoicegenerator/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'invoicegenerator'
7
+ spec.version = InvoiceGenerator::VERSION
8
+ spec.authors = ['Hugo Parente Lima']
9
+ spec.email = ['hugo.pl@gmail.com']
10
+
11
+ spec.summary = 'Invoice generator'
12
+ spec.description = 'A stupid and simple invoice generator'
13
+ spec.homepage = 'https://github.com/hugopl/invoicegenerator'
14
+ spec.license = 'MIT'
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_dependency('money', '~> 6.13')
26
+ spec.add_dependency('optimist', '~> 3.0')
27
+ spec.add_dependency('pdfkit', '~> 0.8')
28
+ spec.add_development_dependency('bundler', '~> 1.17')
29
+ spec.add_development_dependency('rake', '~> 10.0')
30
+ end
@@ -0,0 +1 @@
1
+ require 'invoicegenerator/invoicegenerator'
@@ -0,0 +1,114 @@
1
+ <html>
2
+ <head>
3
+ <style>
4
+ h1 {
5
+ text-align: center;
6
+ background-color: black;
7
+ color: white;
8
+ border-radius: 10px;
9
+ }
10
+
11
+ td {
12
+ padding: 5px;
13
+ vertical-align: top;
14
+ white-space: pre;
15
+ }
16
+
17
+ table {
18
+ border-spacing: 0px;
19
+ border-collapse: separate;
20
+ margin-bottom: 40px;
21
+ }
22
+
23
+ table td:first-child {
24
+ font-weight: bold;
25
+ white-space: nowrap;
26
+ }
27
+
28
+ table.items td:first-child {
29
+ font-weight: normal;
30
+ }
31
+
32
+ .summary > td {
33
+ white-space: nowrap;
34
+ }
35
+
36
+ .client {
37
+ float: left;
38
+ }
39
+
40
+ .summary {
41
+ float: right;
42
+ }
43
+
44
+ .items {
45
+ clear: both;
46
+ width: 100%;
47
+ }
48
+ .items th {
49
+ padding: 4px;
50
+ background-color: #e9e9e9;
51
+ text-align: left;
52
+ }
53
+ .items th:first-child {
54
+ border-radius: 5px 0px 0px 5px;
55
+ }
56
+ .items th:last-child {
57
+ border-radius: 0px 5px 5px 0px;
58
+ }
59
+ .notes {
60
+ white-space: pre;
61
+ }
62
+ </style>
63
+ </head>
64
+ <body>
65
+ <h1>%header%</h1>
66
+
67
+ <table class="from">
68
+ <tr>
69
+ <td>From</td>
70
+ <td>%from%</td>
71
+ </tr>
72
+ </table>
73
+
74
+ <table class="client">
75
+ <tr>
76
+ <td>Client</td>
77
+ <td>%client%</td>
78
+ </tr>
79
+ </table>
80
+
81
+
82
+ <table class="summary">
83
+ <tr>
84
+ <td>Invoice Number</td>
85
+ <td>%number%</td>
86
+ </tr>
87
+ <tr>
88
+ <td>Date</td>
89
+ <td>%date%</td>
90
+ </tr>
91
+ <tr>
92
+ <td>Due date</td>
93
+ <td>%due-date%</td>
94
+ </tr>
95
+ <tr>
96
+ <td>Balance Due</td>
97
+ <td>%balance%</td>
98
+ </tr>
99
+ </table>
100
+
101
+ <table class="items">
102
+ <tr>
103
+ <th>Item</th>
104
+ <th>Quantity</th>
105
+ <th>Rate</th>
106
+ <th>Amount</th>
107
+ </tr>
108
+ %items%
109
+ </table>
110
+
111
+ <h2>Notes</h2>
112
+ <p class="notes">%notes%</p>
113
+ </body>
114
+ </html>
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pdfkit'
4
+ require 'yaml'
5
+ require 'optimist'
6
+ require 'date'
7
+ require 'money'
8
+
9
+ I18n.enforce_available_locales = false
10
+ Money.locale_backend = :currency
11
+
12
+ module InvoiceGenerator
13
+ def show_yml_example_and_exit
14
+ puts <<eot
15
+ from: |
16
+ My multiline name
17
+ Here's a second line
18
+ client: |
19
+ My multiline client
20
+ Hey ho, second line here
21
+ number: 2019-123
22
+ notes: |
23
+ If all your data are always the same, just the invoice number changes,
24
+ save the the static data in a yml and pass the invoice number on command line
25
+ by using (--number).
26
+
27
+ Note that the date is always default to today, and the due-date to today + 15
28
+ items:
29
+ -
30
+ - Nice item for %past_month% %year%
31
+ - 1
32
+ - 12334
33
+ -
34
+ - Other item, for %month%
35
+ - 0.5
36
+ - 100000
37
+ currency: GBP
38
+ eot
39
+ exit
40
+ end
41
+
42
+ def show_template_example_and_exit
43
+ puts File.read(template_path)
44
+ exit
45
+ end
46
+
47
+ def map_date_fields(opts)
48
+ [:date, 'due-date'].each do |i|
49
+ opts[i] = yield(opts[i])
50
+ end
51
+ end
52
+
53
+ def read_params
54
+ Optimist.options do
55
+ opt :client, 'Contents of client field.', type: :string
56
+ opt :currency, 'Currency used.', type: :string, default: 'USD'
57
+ opt :date, 'Invoice date.', type: :date, default: Date.today
58
+ opt 'due-date', 'Due date.', type: :date, default: (Date.today + 15)
59
+ opt :from, 'Contents of from field.', type: :string
60
+ opt :header, 'Contents of the header.', type: :string, default: 'Invoice'
61
+ opt :notes, 'Contents of notes field.', type: :string
62
+ opt :number, 'Invoice number.', type: :string
63
+ opt 'show-yml-example', 'Show an example of a YML file that can be used by this script.'
64
+ opt 'show-template-example', 'Show an example of a HTML template.'
65
+ opt :stdin, 'Read YML file from STDIN.'
66
+ opt :template, 'HTML template to use', type: :string
67
+ opt :yml, 'YML file with values for parameters not given into command line.', default: 'invoice.yml'
68
+ end
69
+ end
70
+
71
+ def read_yml(opts)
72
+ if opts[:stdin]
73
+ data = StringIO.new
74
+ data << STDIN.read until STDIN.eof?
75
+ yaml = data.string
76
+ else
77
+ yaml = File.read(opts[:yml])
78
+ end
79
+ YAML.safe_load(yaml).inject(opts) do |memo, item|
80
+ memo[item[0].to_sym] = item[1]
81
+ memo
82
+ end
83
+ fail('Items not in the right format, something is missing.') unless opts[:items].is_a?(Array)
84
+
85
+ opts
86
+ rescue Errno::ENOENT
87
+ raise "YML file #{opts[:yml]} not found or can't be read."
88
+ end
89
+
90
+ def fix_date_options(opts)
91
+ map_date_fields(opts) do |value|
92
+ value.is_a?(Date) ? value : Date.parse(value)
93
+ end
94
+ end
95
+
96
+ def add_extra_options(opts)
97
+ today = Date.today
98
+ opts[:month] = today.strftime('%B')
99
+ opts[:past_month] = (today << 1).strftime('%B')
100
+ opts[:year] = today.strftime('%Y')
101
+
102
+ raw_balance = opts[:items].inject(0) do |balance, item|
103
+ balance + (item[2] * item[1])
104
+ end
105
+ opts[:balance] = Money.new(raw_balance, opts[:currency]).format
106
+ end
107
+
108
+ def format_items(opts)
109
+ opts[:items].map! do |i|
110
+ fail 'Items must have 3 values' if i.size != 3
111
+
112
+ i[3] = Money.new(i[2] * i[1], opts[:currency]).format
113
+ i[2] = Money.new(i[2], opts[:currency]).format
114
+ "<tr><td>#{i.join('</td><td>')}</td></tr>"
115
+ end
116
+ opts[:items] = opts[:items].join
117
+ end
118
+
119
+ def template_path
120
+ File.join(File.dirname(__FILE__), 'invoicegenerator.html')
121
+ end
122
+
123
+ def generate_html(opts)
124
+ map_date_fields(opts) do |value|
125
+ value.strftime('%B %-d, %Y')
126
+ end
127
+
128
+ html = File.read(opts[:template] || template_path)
129
+ opts.each do |opt, value|
130
+ html.gsub!("%#{opt}%", value.to_s)
131
+ end
132
+ html
133
+ end
134
+
135
+ def main
136
+ opts = read_params
137
+ show_yml_example_and_exit if opts[:'show-yml-example_given']
138
+ show_template_example_and_exit if opts[:'show-template-example_given']
139
+
140
+ read_yml(opts)
141
+ fix_date_options(opts)
142
+ add_extra_options(opts)
143
+ format_items(opts)
144
+ html = generate_html(opts)
145
+
146
+ kit = PDFKit.new(html.encode('iso-8859-1'))
147
+ name = "invoice-#{opts[:number]}.pdf"
148
+ puts "Generating #{name}..."
149
+ kit.to_file(name)
150
+ rescue Errno::ENOENT => e
151
+ abort e.message
152
+ rescue RuntimeError => e
153
+ abort e.message
154
+ end
155
+
156
+ extend self
157
+ end
@@ -0,0 +1,3 @@
1
+ module InvoiceGenerator
2
+ VERSION = '1.0.0'
3
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: invoicegenerator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Hugo Parente Lima
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-02-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: money
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: optimist
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pdfkit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.8'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.17'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.17'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ description: A stupid and simple invoice generator
84
+ email:
85
+ - hugo.pl@gmail.com
86
+ executables:
87
+ - invoicegenerator
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - exe/invoicegenerator
99
+ - invoicegenerator.gemspec
100
+ - lib/invoicegenerator.rb
101
+ - lib/invoicegenerator/invoicegenerator.html
102
+ - lib/invoicegenerator/invoicegenerator.rb
103
+ - lib/invoicegenerator/version.rb
104
+ homepage: https://github.com/hugopl/invoicegenerator
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.7.8
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Invoice generator
128
+ test_files: []