invoice_printer 2.0.0.beta3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +7 -6
- data/Gemfile +1 -1
- data/Gemfile.lock +29 -16
- data/README.md +9 -3
- data/assets/fonts/opensans/OpenSans-Bold.ttf +0 -0
- data/assets/fonts/overpass/Overpass-Bold.ttf +0 -0
- data/assets/fonts/roboto/Roboto-Bold.ttf +0 -0
- data/benchmarks/render.yml +19 -13
- data/bin/invoice_printer +7 -0
- data/docs/COMMAND_LINE.md +122 -0
- data/docs/LIBRARY.md +16 -12
- data/docs/SERVER.md +8 -2
- data/examples/breakdown.rb +77 -0
- data/examples/international_invoice.rb +2 -2
- data/examples/long_invoice.rb +8 -8
- data/examples/picture.jpg +0 -0
- data/examples/promo.rb +19 -13
- data/examples/provider_purchaser_lines.rb +6 -15
- data/examples/simple_invoice.rb +15 -16
- data/examples/variable_field_invoice.rb +96 -0
- data/invoice_printer.gemspec +3 -2
- data/invoice_printer_fonts.gemspec +4 -1
- data/lib/invoice_printer.rb +27 -2
- data/lib/invoice_printer/document.rb +90 -148
- data/lib/invoice_printer/document/item.rb +34 -28
- data/lib/invoice_printer/pdf_document.rb +201 -208
- data/lib/invoice_printer/version.rb +1 -1
- data/test/api_test.rb +2 -2
- data/test/background_test.rb +1 -1
- data/test/cli_test.rb +1 -1
- data/test/dates_box_test.rb +4 -4
- data/test/examples_test.rb +2 -0
- data/test/inputs_test.rb +4 -4
- data/test/invoice_printer_test.rb +2 -2
- data/test/items_table_test.rb +2 -2
- data/test/labels_test.rb +2 -2
- data/test/notes_test.rb +1 -1
- data/test/page_numbers_test.rb +4 -4
- data/test/payment_box_test.rb +5 -5
- data/test/test_ext.rb +2 -1
- data/test/test_helper.rb +1 -1
- metadata +15 -15
- data/assets/logo.png +0 -0
- data/examples/background.png +0 -0
- data/examples/logo.png +0 -0
- data/examples/prawn.png +0 -0
- data/examples/stamp.png +0 -0
data/invoice_printer.gemspec
CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
package_files = `git ls-files -z`.split("\x0")
|
34
34
|
.reject{ |file| ONLY_SERVER_FILES.include?(file) }
|
35
35
|
.reject{ |file| ONLY_FONTS_FILES.include?(file) }
|
36
|
+
.reject{ |file| file.match /.*\.png/ }
|
36
37
|
.reject{ |file| file.match /.*\.pdf/ }
|
37
38
|
|
38
39
|
spec.files = package_files
|
@@ -44,8 +45,8 @@ Gem::Specification.new do |spec|
|
|
44
45
|
spec.required_ruby_version = '>= 2.4'
|
45
46
|
|
46
47
|
spec.add_dependency 'json', '~> 2.1'
|
47
|
-
spec.add_dependency 'prawn', '~> 2.
|
48
|
-
spec.add_dependency 'prawn-
|
48
|
+
spec.add_dependency 'prawn', '~> 2.2'
|
49
|
+
spec.add_dependency 'prawn-table', '~> 0.2.2'
|
49
50
|
|
50
51
|
spec.add_development_dependency 'bundler', '>= 1.7'
|
51
52
|
spec.add_development_dependency 'rake', '>= 10.0'
|
@@ -7,10 +7,13 @@ FONTS_FILES = [
|
|
7
7
|
'FONTS_LICENSE.txt',
|
8
8
|
'assets/fonts/overpass/OFL-1.1.txt',
|
9
9
|
'assets/fonts/overpass/Overpass-Regular.ttf',
|
10
|
+
'assets/fonts/overpass/Overpass-Bold.ttf',
|
10
11
|
'assets/fonts/opensans/Apache-2.0.txt',
|
11
12
|
'assets/fonts/opensans/OpenSans-Regular.ttf',
|
13
|
+
'assets/fonts/opensans/OpenSans-Bold.ttf',
|
12
14
|
'assets/fonts/roboto/Apache-2.0.txt',
|
13
15
|
'assets/fonts/roboto/Roboto-Regular.ttf',
|
16
|
+
'assets/fonts/roboto/Roboto-Bold.ttf',
|
14
17
|
'lib/invoice_printer/fonts.rb'
|
15
18
|
]
|
16
19
|
|
@@ -22,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
22
25
|
spec.summary = 'Super simple PDF invoicing in pure Ruby'
|
23
26
|
spec.description = 'Super simple and fast PDF invoicing in pure Ruby (based on Prawn library).'
|
24
27
|
spec.homepage = 'https://github.com/strzibny/invoice_printer'
|
25
|
-
spec.
|
28
|
+
spec.licenses = ['MIT', 'OFL 1.1', 'Apache 2.0']
|
26
29
|
|
27
30
|
# Include only font files
|
28
31
|
spec.files = FONTS_FILES
|
data/lib/invoice_printer.rb
CHANGED
@@ -15,6 +15,7 @@ Prawn::Font::AFM.hide_m17n_warning = true
|
|
15
15
|
# InvoicePrinter.print(
|
16
16
|
# document: invoice,
|
17
17
|
# font: 'path-to-font-file.ttf',
|
18
|
+
# bold_font: 'path-to-font-file.ttf',
|
18
19
|
# stamp: 'stamp.jpg',
|
19
20
|
# logo: 'logo.jpg',
|
20
21
|
# file_name: 'invoice.pdf'
|
@@ -37,6 +38,7 @@ module InvoicePrinter
|
|
37
38
|
# iban: 'IBAN:',
|
38
39
|
# issue_date: 'Issue date:',
|
39
40
|
# due_date: 'Due date:',
|
41
|
+
# variable_symbol: 'Variable symbol:'
|
40
42
|
# item: 'Item',
|
41
43
|
# quantity: 'Quantity',
|
42
44
|
# unit: 'Unit',
|
@@ -64,16 +66,28 @@ module InvoicePrinter
|
|
64
66
|
# document - InvoicePrinter::Document object
|
65
67
|
# labels - labels to override
|
66
68
|
# font - font file to use
|
69
|
+
# bold_font - bold font file to use
|
67
70
|
# stamp - stamp & signature (image)
|
68
71
|
# logo - logotype (image)
|
69
72
|
# background - background (image)
|
70
73
|
# page_size - :letter or :a4
|
71
74
|
# file_name - output file
|
72
|
-
def self.print(
|
75
|
+
def self.print(
|
76
|
+
document:,
|
77
|
+
labels: {},
|
78
|
+
font: nil,
|
79
|
+
bold_font: nil,
|
80
|
+
stamp: nil,
|
81
|
+
logo: nil,
|
82
|
+
background: nil,
|
83
|
+
page_size: :letter,
|
84
|
+
file_name:
|
85
|
+
)
|
73
86
|
PDFDocument.new(
|
74
87
|
document: document,
|
75
88
|
labels: labels,
|
76
89
|
font: font,
|
90
|
+
bold_font: bold_font,
|
77
91
|
stamp: stamp,
|
78
92
|
logo: logo,
|
79
93
|
background: background,
|
@@ -86,15 +100,26 @@ module InvoicePrinter
|
|
86
100
|
# document - InvoicePrinter::Document object
|
87
101
|
# labels - labels to override
|
88
102
|
# font - font file to use
|
103
|
+
# bold_font - bold font file to use
|
89
104
|
# stamp - stamp & signature (image)
|
90
105
|
# logo - logotype (image)
|
91
106
|
# background - background (image)
|
92
107
|
# page_size - :letter or :a4
|
93
|
-
def self.render(
|
108
|
+
def self.render(
|
109
|
+
document:,
|
110
|
+
labels: {},
|
111
|
+
font: nil,
|
112
|
+
bold_font: nil,
|
113
|
+
stamp: nil,
|
114
|
+
logo: nil,
|
115
|
+
background: nil,
|
116
|
+
page_size: :letter
|
117
|
+
)
|
94
118
|
PDFDocument.new(
|
95
119
|
document: document,
|
96
120
|
labels: labels,
|
97
121
|
font: font,
|
122
|
+
bold_font: bold_font,
|
98
123
|
stamp: stamp,
|
99
124
|
logo: logo,
|
100
125
|
background: background,
|
@@ -15,6 +15,7 @@ module InvoicePrinter
|
|
15
15
|
# purchaser_lines: "Ostravska 2\n747 05 Opava",
|
16
16
|
# issue_date: '19/03/3939',
|
17
17
|
# due_date: '19/03/3939',
|
18
|
+
# variable_symbol: '198900000001',
|
18
19
|
# subtotal: '$ 150',
|
19
20
|
# tax: '$ 50',
|
20
21
|
# total: '$ 200',
|
@@ -39,27 +40,14 @@ module InvoicePrinter
|
|
39
40
|
:provider_tax_id,
|
40
41
|
:provider_tax_id2,
|
41
42
|
:provider_lines,
|
42
|
-
# Provider address fields
|
43
|
-
:provider_street,
|
44
|
-
:provider_street_number,
|
45
|
-
:provider_postcode,
|
46
|
-
:provider_city,
|
47
|
-
:provider_city_part,
|
48
|
-
:provider_extra_address_line,
|
49
43
|
# Purchaser fields
|
50
44
|
:purchaser_name,
|
51
45
|
:purchaser_tax_id,
|
52
46
|
:purchaser_tax_id2,
|
53
47
|
:purchaser_lines,
|
54
|
-
# Purchaser address fields
|
55
|
-
:purchaser_street,
|
56
|
-
:purchaser_street_number,
|
57
|
-
:purchaser_postcode,
|
58
|
-
:purchaser_city,
|
59
|
-
:purchaser_city_part,
|
60
|
-
:purchaser_extra_address_line,
|
61
48
|
:issue_date,
|
62
49
|
:due_date,
|
50
|
+
:variable_symbol,
|
63
51
|
# Account details
|
64
52
|
:subtotal,
|
65
53
|
:tax,
|
@@ -76,113 +64,78 @@ module InvoicePrinter
|
|
76
64
|
class << self
|
77
65
|
def from_json(json)
|
78
66
|
new(
|
79
|
-
number:
|
80
|
-
provider_name:
|
81
|
-
provider_tax_id:
|
82
|
-
provider_tax_id2:
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
issue_date: json['issue_date'],
|
101
|
-
due_date: json['due_date'],
|
102
|
-
subtotal: json['subtotal'],
|
103
|
-
tax: json['tax'],
|
104
|
-
tax2: json['tax2'],
|
105
|
-
tax3: json['tax3'],
|
106
|
-
total: json['total'],
|
107
|
-
bank_account_number: json['bank_account_number'],
|
108
|
-
account_iban: json['account_iban'],
|
109
|
-
account_swift: json['account_swift'],
|
110
|
-
note: json['note'],
|
67
|
+
number: json['number'],
|
68
|
+
provider_name: json['provider_name'],
|
69
|
+
provider_tax_id: json['provider_tax_id'],
|
70
|
+
provider_tax_id2: json['provider_tax_id2'],
|
71
|
+
provider_lines: json['provider_lines'],
|
72
|
+
purchaser_name: json['purchaser_name'],
|
73
|
+
purchaser_tax_id: json['purchaser_tax_id'],
|
74
|
+
purchaser_tax_id2: json['purchaser_tax_id2'],
|
75
|
+
purchaser_lines: json['purchaser_lines'],
|
76
|
+
issue_date: json['issue_date'],
|
77
|
+
due_date: json['due_date'],
|
78
|
+
variable_symbol: json['variable_symbol'],
|
79
|
+
subtotal: json['subtotal'],
|
80
|
+
tax: json['tax'],
|
81
|
+
tax2: json['tax2'],
|
82
|
+
tax3: json['tax3'],
|
83
|
+
total: json['total'],
|
84
|
+
bank_account_number: json['bank_account_number'],
|
85
|
+
account_iban: json['account_iban'],
|
86
|
+
account_swift: json['account_swift'],
|
87
|
+
note: json['note'],
|
111
88
|
|
112
|
-
items:
|
89
|
+
items: (json['items'] || []).map { |item_json| Item.from_json(item_json) }
|
113
90
|
)
|
114
91
|
end
|
115
92
|
end
|
116
93
|
|
117
|
-
def initialize(number:
|
118
|
-
provider_name:
|
119
|
-
provider_tax_id:
|
120
|
-
provider_tax_id2:
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
due_date: nil,
|
140
|
-
subtotal: nil,
|
141
|
-
tax: nil,
|
142
|
-
tax2: nil,
|
143
|
-
tax3: nil,
|
144
|
-
total: nil,
|
145
|
-
bank_account_number: nil,
|
146
|
-
account_iban: nil,
|
147
|
-
account_swift: nil,
|
148
|
-
items: nil,
|
149
|
-
note: nil)
|
150
|
-
|
151
|
-
@number = String(number)
|
152
|
-
@provider_name = String(provider_name)
|
153
|
-
@provider_tax_id = String(provider_tax_id)
|
154
|
-
@provider_tax_id2 = String(provider_tax_id2)
|
155
|
-
@provider_street = String(provider_street)
|
156
|
-
@provider_street_number = String(provider_street_number)
|
157
|
-
@provider_postcode = String(provider_postcode)
|
158
|
-
@provider_city = String(provider_city)
|
159
|
-
@provider_city_part = String(provider_city_part)
|
160
|
-
@provider_extra_address_line = String(provider_extra_address_line)
|
161
|
-
@provider_lines = String(provider_lines)
|
162
|
-
@purchaser_name = String(purchaser_name)
|
163
|
-
@purchaser_tax_id = String(purchaser_tax_id)
|
164
|
-
@purchaser_tax_id2 = String(purchaser_tax_id2)
|
165
|
-
@purchaser_street = String(purchaser_street)
|
166
|
-
@purchaser_street_number = String(purchaser_street_number)
|
167
|
-
@purchaser_postcode = String(purchaser_postcode)
|
168
|
-
@purchaser_city = String(purchaser_city)
|
169
|
-
@purchaser_city_part = String(purchaser_city_part)
|
170
|
-
@purchaser_extra_address_line = String(purchaser_extra_address_line)
|
171
|
-
@purchaser_lines = String(purchaser_lines)
|
172
|
-
@issue_date = String(issue_date)
|
173
|
-
@due_date = String(due_date)
|
174
|
-
@subtotal = String(subtotal)
|
175
|
-
@tax = String(tax)
|
176
|
-
@tax2 = String(tax2)
|
177
|
-
@tax3 = String(tax3)
|
178
|
-
@total = String(total)
|
179
|
-
@bank_account_number = String(bank_account_number)
|
180
|
-
@account_iban = String(account_iban)
|
181
|
-
@account_swift = String(account_swift)
|
182
|
-
@items = items
|
183
|
-
@note = String(note)
|
184
|
-
|
94
|
+
def initialize(number: nil,
|
95
|
+
provider_name: nil,
|
96
|
+
provider_tax_id: nil,
|
97
|
+
provider_tax_id2: nil,
|
98
|
+
provider_lines: nil,
|
99
|
+
purchaser_name: nil,
|
100
|
+
purchaser_tax_id: nil,
|
101
|
+
purchaser_tax_id2: nil,
|
102
|
+
purchaser_lines: nil,
|
103
|
+
issue_date: nil,
|
104
|
+
due_date: nil,
|
105
|
+
variable_symbol: nil,
|
106
|
+
subtotal: nil,
|
107
|
+
tax: nil,
|
108
|
+
tax2: nil,
|
109
|
+
tax3: nil,
|
110
|
+
total: nil,
|
111
|
+
bank_account_number: nil,
|
112
|
+
account_iban: nil,
|
113
|
+
account_swift: nil,
|
114
|
+
items: nil,
|
115
|
+
note: nil)
|
185
116
|
|
117
|
+
@number = String(number)
|
118
|
+
@provider_name = String(provider_name)
|
119
|
+
@provider_tax_id = String(provider_tax_id)
|
120
|
+
@provider_tax_id2 = String(provider_tax_id2)
|
121
|
+
@provider_lines = String(provider_lines)
|
122
|
+
@purchaser_name = String(purchaser_name)
|
123
|
+
@purchaser_tax_id = String(purchaser_tax_id)
|
124
|
+
@purchaser_tax_id2 = String(purchaser_tax_id2)
|
125
|
+
@purchaser_lines = String(purchaser_lines)
|
126
|
+
@issue_date = String(issue_date)
|
127
|
+
@due_date = String(due_date)
|
128
|
+
@variable_symbol = String(variable_symbol)
|
129
|
+
@subtotal = String(subtotal)
|
130
|
+
@tax = String(tax)
|
131
|
+
@tax2 = String(tax2)
|
132
|
+
@tax3 = String(tax3)
|
133
|
+
@total = String(total)
|
134
|
+
@bank_account_number = String(bank_account_number)
|
135
|
+
@account_iban = String(account_iban)
|
136
|
+
@account_swift = String(account_swift)
|
137
|
+
@items = items
|
138
|
+
@note = String(note)
|
186
139
|
|
187
140
|
raise InvalidInput, 'items are not only a type of InvoicePrinter::Document::Item' \
|
188
141
|
unless @items.select{ |i| !i.is_a?(InvoicePrinter::Document::Item) }.empty?
|
@@ -190,39 +143,28 @@ module InvoicePrinter
|
|
190
143
|
|
191
144
|
def to_h
|
192
145
|
{
|
193
|
-
'number':
|
194
|
-
'provider_name':
|
195
|
-
'provider_tax_id':
|
196
|
-
'provider_tax_id2':
|
197
|
-
'
|
198
|
-
'
|
199
|
-
'
|
200
|
-
'
|
201
|
-
'
|
202
|
-
'
|
203
|
-
'
|
204
|
-
'
|
205
|
-
'
|
206
|
-
'
|
207
|
-
'
|
208
|
-
'
|
209
|
-
'
|
210
|
-
'
|
211
|
-
'
|
212
|
-
'
|
213
|
-
'
|
214
|
-
'
|
215
|
-
'due_date': @due_date,
|
216
|
-
'subtotal': @subtotal,
|
217
|
-
'tax': @tax,
|
218
|
-
'tax2': @tax2,
|
219
|
-
'tax3': @tax3,
|
220
|
-
'total': @total,
|
221
|
-
'bank_account_number': @bank_account_number,
|
222
|
-
'account_iban': @account_iban,
|
223
|
-
'account_swift': @account_swift,
|
224
|
-
'items': @items.map(&:to_h),
|
225
|
-
'note': @note
|
146
|
+
'number': @number,
|
147
|
+
'provider_name': @provider_name,
|
148
|
+
'provider_tax_id': @provider_tax_id,
|
149
|
+
'provider_tax_id2': @provider_tax_id2,
|
150
|
+
'provider_lines': @provider_lines,
|
151
|
+
'purchaser_name': @purchaser_name,
|
152
|
+
'purchaser_tax_id': @purchaser_tax_id,
|
153
|
+
'purchaser_tax_id2': @purchaser_tax_id2,
|
154
|
+
'purchaser_lines': @purchaser_lines,
|
155
|
+
'issue_date': @issue_date,
|
156
|
+
'due_date': @due_date,
|
157
|
+
'variable_symbol': @variable_symbol,
|
158
|
+
'subtotal': @subtotal,
|
159
|
+
'tax': @tax,
|
160
|
+
'tax2': @tax2,
|
161
|
+
'tax3': @tax3,
|
162
|
+
'total': @total,
|
163
|
+
'bank_account_number': @bank_account_number,
|
164
|
+
'account_iban': @account_iban,
|
165
|
+
'account_swift': @account_swift,
|
166
|
+
'items': @items.map(&:to_h),
|
167
|
+
'note': @note
|
226
168
|
}
|
227
169
|
end
|
228
170
|
|
@@ -6,6 +6,7 @@ module InvoicePrinter
|
|
6
6
|
#
|
7
7
|
# item = InvoicePrinter::Document::Item.new(
|
8
8
|
# name: 'UX consultation',
|
9
|
+
# breakdown: "Monday 3h\nTuesday 1h"
|
9
10
|
# variable: 'June 2008',
|
10
11
|
# quantity: '4',
|
11
12
|
# unit: 'hours',
|
@@ -18,6 +19,7 @@ module InvoicePrinter
|
|
18
19
|
# but this is not enforced.
|
19
20
|
class Item
|
20
21
|
attr_reader :name,
|
22
|
+
:breakdown,
|
21
23
|
:variable, # for anything required
|
22
24
|
:quantity,
|
23
25
|
:unit,
|
@@ -30,51 +32,55 @@ module InvoicePrinter
|
|
30
32
|
class << self
|
31
33
|
def from_json(json)
|
32
34
|
new(
|
33
|
-
name:
|
35
|
+
name: json['name'],
|
36
|
+
breakdown: json['breakdown'],
|
34
37
|
variable: json['variable'],
|
35
38
|
quantity: json['quantity'],
|
36
|
-
unit:
|
37
|
-
price:
|
38
|
-
tax:
|
39
|
-
tax2:
|
40
|
-
tax3:
|
41
|
-
amount:
|
39
|
+
unit: json['unit'],
|
40
|
+
price: json['price'],
|
41
|
+
tax: json['tax'],
|
42
|
+
tax2: json['tax2'],
|
43
|
+
tax3: json['tax3'],
|
44
|
+
amount: json['amount']
|
42
45
|
)
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
46
|
-
def initialize(name:
|
49
|
+
def initialize(name: nil,
|
50
|
+
breakdown: nil,
|
47
51
|
variable: nil,
|
48
52
|
quantity: nil,
|
49
|
-
unit:
|
50
|
-
price:
|
51
|
-
tax:
|
52
|
-
tax2:
|
53
|
-
tax3:
|
54
|
-
amount:
|
53
|
+
unit: nil,
|
54
|
+
price: nil,
|
55
|
+
tax: nil,
|
56
|
+
tax2: nil,
|
57
|
+
tax3: nil,
|
58
|
+
amount: nil)
|
55
59
|
|
56
|
-
@name
|
60
|
+
@name = String(name)
|
61
|
+
@breakdown = String(breakdown)
|
57
62
|
@variable = String(variable)
|
58
63
|
@quantity = String(quantity)
|
59
|
-
@unit
|
60
|
-
@price
|
61
|
-
@tax
|
62
|
-
@tax2
|
63
|
-
@tax3
|
64
|
-
@amount
|
64
|
+
@unit = String(unit)
|
65
|
+
@price = String(price)
|
66
|
+
@tax = String(tax)
|
67
|
+
@tax2 = String(tax2)
|
68
|
+
@tax3 = String(tax3)
|
69
|
+
@amount = String(amount)
|
65
70
|
end
|
66
71
|
|
67
72
|
def to_h
|
68
73
|
{
|
69
|
-
'name':
|
74
|
+
'name': @name,
|
75
|
+
'breakdown': @breakdown,
|
70
76
|
'variable': @variable,
|
71
77
|
'quantity': @quantity,
|
72
|
-
'unit':
|
73
|
-
'price':
|
74
|
-
'tax':
|
75
|
-
'tax2':
|
76
|
-
'tax3':
|
77
|
-
'amount':
|
78
|
+
'unit': @unit,
|
79
|
+
'price': @price,
|
80
|
+
'tax': @tax,
|
81
|
+
'tax2': @tax2,
|
82
|
+
'tax3': @tax3,
|
83
|
+
'amount': @amount,
|
78
84
|
}
|
79
85
|
end
|
80
86
|
|