invoice_printer 1.1.0 → 1.2.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7267267a6ecf63b5859b996d9e559f15a47c1c99
4
- data.tar.gz: 0526101ea5a21143caca53fa8e6d6cde1a6a1907
3
+ metadata.gz: 8abb69910f861a930c17f4a59b2f00c5c7530556
4
+ data.tar.gz: b4b108dc6b68db259a24a9fca49db4eb78ab0a9b
5
5
  SHA512:
6
- metadata.gz: cf3f24eb77ac24d9fad50aff96b215289088f4a1d56f5d7aa32d29bbfeaf527301b46275853538da488dfc02eb925b3fc5d8fd4da59cdb0fd06049cdc8cd6ca5
7
- data.tar.gz: 9746c2ce166bbdbe5b81668345fde6ade8897c76872e175849e70be9f69f4a9c630ddf5933bb17cee4412cc14bb6527117f2e8f8a0366a42bd6463bed6ce2a86
6
+ metadata.gz: 126cddc2f3e5cf893cf94f18abdd2b7966399f993f0ff29826adff0d1b77f26ea08c8de3feb6b036c4c5b12027ebbd90b41ef54f3b1b9fecc6e80bc88c9a530c
7
+ data.tar.gz: db9b42fb49fa1c303c0f6a6abeb1408cd2940960efc529107372f9581d21248eb982ce1f3eaf4e4bee23ce6d3bb759972aeabfd3f4611aec42cd295d961968e2
data/Gemfile CHANGED
@@ -6,4 +6,5 @@ gemspec
6
6
  group :test do
7
7
  gem 'pdf-inspector'
8
8
  gem 'minitest'
9
+ gem 'rack-test', require: 'rack/test'
9
10
  end
data/README.md CHANGED
@@ -1,12 +1,22 @@
1
- <a href="http://strzibny.github.io/invoice_printer/">
2
- <img src="./docs/web/logo.png" width="300" />
3
- </a>
1
+ <img src="./assets/logo.png" width="300" />
4
2
 
5
3
  &nbsp;
6
4
 
7
- Super simple PDF invoicing in pure Ruby
5
+ **Super simple PDF invoicing.** InvoicePrinter is a server, command line program and pure Ruby library to generate PDF invoices in no time. You can use Ruby or JSON as the invoice representation to build the final PDF.
8
6
 
9
- InvoicePrinter is a Ruby library and a command line program. You can use Ruby or JSON to build the final PDF.
7
+ ## Philosophy
8
+
9
+ - **Simple**, no styling required, no calculation, no money formatting (bring your own)
10
+ - **Pure Ruby**, no dependency on system libraries or browsers
11
+ - **Fast**, so you can render invoice on the fly during request
12
+
13
+ ## Examples
14
+
15
+ | Simple invoice |
16
+ | -------------- |
17
+ | <a href="https://github.com/strzibny/invoice_printer/raw/master/examples/promo.pdf"><img src="./examples/picture.jpg" width="180" /></a>|
18
+
19
+ See more usecases in the `examples/` directory.
10
20
 
11
21
  ## Features
12
22
 
@@ -26,296 +36,18 @@ InvoicePrinter is a Ruby library and a command line program. You can use Ruby or
26
36
  - Note
27
37
  - JSON format
28
38
  - CLI
39
+ - Server
29
40
  - Well tested
30
41
 
31
- ## Example
32
-
33
- | Simple invoice |
34
- | -------------- |
35
- | <a href="https://github.com/strzibny/invoice_printer/raw/master/examples/promo.pdf"><img src="./examples/picture.jpg" width="180" /></a>|
36
-
37
- See more usecases in the `examples/` directory.
38
-
39
- ## Installation
40
-
41
- Add this line to your application's Gemfile:
42
-
43
- ```ruby
44
- gem 'invoice_printer'
45
- ```
46
-
47
- And then execute:
48
-
49
- $ bundle
50
-
51
- Or install it yourself as:
52
-
53
- $ gem install invoice_printer
54
-
55
- ## Usage
56
-
57
- The simplest way how to create your invoice PDF is to create an invoice object
58
- and pass it to printer:
59
-
60
- ```ruby
61
- item = InvoicePrinter::Document::Item.new(
62
- ...
63
- )
64
-
65
- invoice = InvoicePrinter::Document.new(
66
- ...
67
- items: [item, ...]
68
- )
69
-
70
- InvoicePrinter.print(
71
- document: invoice,
72
- file_name: 'invoice.pdf'
73
- )
74
-
75
- # Or render PDF directly
76
- InvoicePrinter.render(
77
- document: invoice
78
- )
79
- ```
80
-
81
- Here is an full example for creating the document object:
82
-
83
- ```ruby
84
- item = InvoicePrinter::Document::Item.new(
85
- name: 'Web consultation',
86
- quantity: nil,
87
- unit: 'hours',
88
- price: '$ 25',
89
- tax: '$ 1',
90
- amount: '$ 100'
91
- )
92
-
93
- invoice = InvoicePrinter::Document.new(
94
- number: '201604030001',
95
- provider_name: 'Business s.r.o.',
96
- provider_tax_id: '56565656',
97
- provider_tax_id2: '465454',
98
- provider_street: 'Rolnicka',
99
- provider_street_number: '1',
100
- provider_postcode: '747 05',
101
- provider_city: 'Opava',
102
- provider_city_part: 'Katerinky',
103
- provider_extra_address_line: 'Czech Republic',
104
- purchaser_name: 'Adam',
105
- purchaser_tax_id: '',
106
- purchaser_tax_id2: '',
107
- purchaser_street: 'Ostravska',
108
- purchaser_street_number: '1',
109
- purchaser_postcode: '747 70',
110
- purchaser_city: 'Opava',
111
- purchaser_city_part: '',
112
- purchaser_extra_address_line: '',
113
- issue_date: '19/03/3939',
114
- due_date: '19/03/3939',
115
- subtotal: '175',
116
- tax: '5',
117
- tax2: '10',
118
- tax3: '20',
119
- total: '$ 200',
120
- bank_account_number: '156546546465',
121
- account_iban: 'IBAN464545645',
122
- account_swift: 'SWIFT5456',
123
- items: [item],
124
- note: 'A note...'
125
- )
126
- ```
127
-
128
- ### Ruby on Rails
129
-
130
- If you want to use InvoicePrinter for printing PDF documents directly from Rails
131
- actions, you can:
132
-
133
- ```ruby
134
- # GET /invoices/1
135
- def show
136
- invoice = InvoicePrinter::Document.new(...)
137
-
138
- respond_to do |format|
139
- format.pdf {
140
- @pdf = InvoicePrinter.render(
141
- document: invoice
142
- )
143
- send_data @pdf, type: 'application/pdf', disposition: 'inline'
144
- }
145
- end
146
- end
147
- ```
148
-
149
- ### JSON format
150
-
151
- JSON format is supported via `from_json` method. JSON itself mimicks the original Ruby objects:
152
-
153
- ```ruby
154
- json = InvoicePrinter::Document.new(...).to_json
155
- document = InvoicePrinter::Document.from_json(json)
156
-
157
-
158
- InvoicePrinter.print(
159
- document: document,
160
- ...
161
- )
162
-
163
- ```
164
-
165
- ## CLI
166
-
167
- InvoicePrinter ships with a command line executable called `invoice_printer`.
168
-
169
- It supports all features except it only accepts JSON as an input.
170
-
171
- ```
172
- $ invoice_printer --help
173
- Usage: invoice_printer [options]
174
-
175
- Options:
176
-
177
- -l, --labels labels as JSON
178
- -d, --document document as JSON
179
- -s, --stamp path to stamp
180
- --logo path to logotype
181
- --font path to font
182
- --page_size letter or a4 (letter is the default)
183
- -f, --filename output path
184
- -r, --render directly render PDF stream (filename option will be ignored)
185
- ```
186
-
187
-
188
- ## Customization
189
-
190
- ### Page size
191
-
192
- Both A4 and US letter is supported. Just pass `page_size` as an argument to `print` or `render` methods:
193
-
194
- ```ruby
195
- InvoicePrinter.print(
196
- document: invoice,
197
- labels: labels,
198
- page_size: :a4,
199
- file_name: 'invoice.pdf'
200
- )
201
- ```
202
-
203
- `:letter` is the default.
204
-
205
-
206
- ### Localization
207
-
208
- To localize your documents you can set both global defaults or instance
209
- overrides:
210
-
211
- ```ruby
212
- InvoicePrinter.labels = {
213
- provider: 'Dodavatel'
214
- }
215
-
216
- labels = {
217
- purchaser: 'Customer'
218
- }
219
-
220
- InvoicePrinter.print(
221
- document: invoice,
222
- labels: labels,
223
- file_name: 'invoice.pdf'
224
- )
225
- ```
226
-
227
- Here is the full list of labels to configure. You can paste and edit this block
228
- to `initializers/invoice_printer.rb` if you are using Rails.
229
-
230
- ```ruby
231
- InvoicePrinter.labels = {
232
- name: 'Invoice',
233
- provider: 'Provider',
234
- purchaser: 'Purchaser',
235
- tax_id: 'Identification number',
236
- tax_id2: 'Identification number',
237
- payment: 'Payment',
238
- payment_by_transfer: 'Payment by bank transfer on the account below:',
239
- payment_in_cash: 'Payment in cash',
240
- account_number: 'Account NO',
241
- swift: 'SWIFT',
242
- iban: 'IBAN',
243
- issue_date: 'Issue date',
244
- due_date: 'Due date',
245
- item: 'Item',
246
- quantity: 'Quantity',
247
- unit: 'Unit',
248
- price_per_item: 'Price per item',
249
- amount: 'Amount',
250
- tax: 'Tax',
251
- tax2: 'Tax 2',
252
- tax3: 'Tax 3',
253
- subtotal: 'Subtotal',
254
- total: 'Total'
255
- }
256
- ```
257
-
258
- You can also use sublabels feature to provide the document in two languages:
259
-
260
- ```ruby
261
- labels = {
262
- ...
263
- }
264
-
265
- sublabels = {
266
- name: 'Faktura',
267
- provider: 'Prodejce',
268
- purchaser: 'Kupující',
269
- tax_id: 'IČ',
270
- tax_id2: 'DIČ',
271
- payment: 'Forma úhrady',
272
- payment_by_transfer: 'Platba na následující účet:',
273
- account_number: 'Číslo účtu',
274
- issue_date: 'Datum vydání',
275
- due_date: 'Datum splatnosti',
276
- item: 'Položka',
277
- quantity: 'Počet',
278
- unit: 'MJ',
279
- price_per_item: 'Cena za položku',
280
- amount: 'Celkem bez daně',
281
- subtotal: 'Cena bez daně',
282
- tax: 'DPH 21 %',
283
- total: 'Celkem'
284
- }
285
-
286
- labels.merge!({ sublabels: sublabels })
287
-
288
- ...
289
- ```
290
-
291
- Now the document will have a little sublabels next to the original labels in Czech.
292
-
293
- ### Font
294
-
295
- To support specific characters you might need to specify a TTF font to be used:
296
-
297
- ``` ruby
298
- InvoicePrinter.print(
299
- ...
300
- font: File.expand_path('../Overpass-Regular.ttf', __FILE__)
301
- )
302
- ```
303
-
304
- We recommend you DejaVuSans and Overpass fonts.
305
-
306
- ### Background
307
-
308
- To include a background image you might need to create the file according to the size and resolution to be used (see: [examples/background.png](https://github.com/strzibny/invoice_printer/blob/master/examples/background.png)):
42
+ ## Documentation
309
43
 
310
- ``` ruby
311
- InvoicePrinter.print(
312
- ...
313
- background: File.expand_path('../background.png', __FILE__)
314
- )
315
- ```
44
+ - [Installation](./docs/INSTALLATION.md)
45
+ - [Ruby library](./docs/LIBRARY.md)
46
+ - [Server](./docs/SERVER.md)
47
+ - [Command line](./docs/COMMAND_LINE.md)
316
48
 
317
49
  ## Copyright
318
50
 
319
- Copyright 2015-2017 &copy; [Josef Strzibny](http://strzibny.name/). MIT licensed.
51
+ Copyright 2015-2018 &copy; [Josef Strzibny](http://strzibny.name/). MIT licensed.
320
52
 
321
53
  Originally extracted from and created for an open source single-entry invoicing app [InvoiceBar](https://github.com/strzibny/invoicebar).
Binary file
@@ -2,7 +2,6 @@
2
2
  $LOAD_PATH << File.expand_path('lib')
3
3
 
4
4
  require 'optparse'
5
- require 'json'
6
5
  require 'invoice_printer'
7
6
 
8
7
  def show_version
@@ -34,8 +33,6 @@ end
34
33
  options = {}
35
34
 
36
35
  parser = OptionParser.new do|opts|
37
- opts.banner = "Usage: invoice_printer [options]"
38
-
39
36
  opts.on('-l', '--labels JSON') do |json|
40
37
  options[:labels] = json
41
38
  end
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.expand_path('lib')
3
+
4
+ require 'optparse'
5
+ require 'rack/handler/puma'
6
+ require 'invoice_printer/server'
7
+
8
+ def show_version
9
+ puts "InvoicePrinter v#{InvoicePrinter::VERSION}"
10
+
11
+ exit 0
12
+ end
13
+
14
+ def show_help
15
+ puts <<~HELP
16
+ Usage: invoice_printer_server [options]
17
+
18
+ Options:
19
+
20
+ -h, --host hostname to listen on (default is 0.0.0.0)
21
+ -p, --port port to listen on (default is 9393)
22
+ -w, --workers number of Puma workers (default is 2)
23
+
24
+ HELP
25
+
26
+ exit 0
27
+ end
28
+
29
+ options = {}
30
+
31
+ parser = OptionParser.new do|opts|
32
+ opts.on('-h', '--hostname ADDRESS') do |address|
33
+ options[:Host] = address
34
+ end
35
+
36
+ opts.on('-p', '--port NUMBER') do |number|
37
+ options[:Port] = number
38
+ end
39
+
40
+ opts.on('-w', '--workers NUMBER') do |number|
41
+ options[:workers] = number.to_i
42
+ end
43
+
44
+ opts.on('--debug') do
45
+ options[:debug] = true
46
+ end
47
+
48
+ opts.on('-h', '--help') do
49
+ show_help
50
+ end
51
+ end
52
+
53
+ parser.parse!
54
+
55
+ puma_options = { :Host => '0.0.0.0', :Port => 9393, :workers => 2 }.merge(options)
56
+
57
+ begin
58
+ puts 'Starting InvoicePrinter Server...'
59
+ Rack::Handler::Puma.run(InvoicePrinter::Server.freeze.app, puma_options)
60
+ rescue => e
61
+ STDERR.puts "ERROR: #{e.message}"
62
+
63
+ if options[:debug]
64
+ STDERR.puts
65
+ STDERR.puts e.backtrace
66
+ end
67
+
68
+ exit 1
69
+ end
@@ -0,0 +1,21 @@
1
+ # InvoicePrinter CLI
2
+
3
+ InvoicePrinter ships with a command line executable called `invoice_printer`.
4
+
5
+ It supports all features except it only accepts JSON as an input.
6
+
7
+ ```
8
+ $ invoice_printer --help
9
+ Usage: invoice_printer [options]
10
+
11
+ Options:
12
+
13
+ -l, --labels labels as JSON
14
+ -d, --document document as JSON
15
+ -s, --stamp path to stamp
16
+ --logo path to logotype
17
+ --font path to font
18
+ --page_size letter or a4 (letter is the default)
19
+ -f, --filename output path
20
+ -r, --render directly render PDF stream (filename option will be ignored)
21
+ ```
@@ -0,0 +1,22 @@
1
+ # Installation
2
+
3
+ ## Via RubyGems
4
+
5
+ This requires Ruby to be installed.
6
+
7
+ Then install the gem as:
8
+
9
+ $ gem install invoice_printer
10
+
11
+
12
+ ### With Bundler
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'invoice_printer'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
@@ -0,0 +1,242 @@
1
+ # InvoicePrinter Library
2
+
3
+ ## Usage
4
+
5
+ The simplest way how to create your invoice PDF is to create an invoice object
6
+ and pass it to printer:
7
+
8
+ ```ruby
9
+ item = InvoicePrinter::Document::Item.new(
10
+ ...
11
+ )
12
+
13
+ invoice = InvoicePrinter::Document.new(
14
+ ...
15
+ items: [item, ...]
16
+ )
17
+
18
+ InvoicePrinter.print(
19
+ document: invoice,
20
+ file_name: 'invoice.pdf'
21
+ )
22
+
23
+ # Or render PDF directly
24
+ InvoicePrinter.render(
25
+ document: invoice
26
+ )
27
+ ```
28
+
29
+ Here is an full example for creating the document object:
30
+
31
+ ```ruby
32
+ item = InvoicePrinter::Document::Item.new(
33
+ name: 'Web consultation',
34
+ quantity: nil,
35
+ unit: 'hours',
36
+ price: '$ 25',
37
+ tax: '$ 1',
38
+ amount: '$ 100'
39
+ )
40
+
41
+ invoice = InvoicePrinter::Document.new(
42
+ number: '201604030001',
43
+ provider_name: 'Business s.r.o.',
44
+ provider_tax_id: '56565656',
45
+ provider_tax_id2: '465454',
46
+ provider_street: 'Rolnicka',
47
+ provider_street_number: '1',
48
+ provider_postcode: '747 05',
49
+ provider_city: 'Opava',
50
+ provider_city_part: 'Katerinky',
51
+ provider_extra_address_line: 'Czech Republic',
52
+ purchaser_name: 'Adam',
53
+ purchaser_tax_id: '',
54
+ purchaser_tax_id2: '',
55
+ purchaser_street: 'Ostravska',
56
+ purchaser_street_number: '1',
57
+ purchaser_postcode: '747 70',
58
+ purchaser_city: 'Opava',
59
+ purchaser_city_part: '',
60
+ purchaser_extra_address_line: '',
61
+ issue_date: '19/03/3939',
62
+ due_date: '19/03/3939',
63
+ subtotal: '175',
64
+ tax: '5',
65
+ tax2: '10',
66
+ tax3: '20',
67
+ total: '$ 200',
68
+ bank_account_number: '156546546465',
69
+ account_iban: 'IBAN464545645',
70
+ account_swift: 'SWIFT5456',
71
+ items: [item],
72
+ note: 'A note...'
73
+ )
74
+ ```
75
+
76
+ ### Ruby on Rails
77
+
78
+ If you want to use InvoicePrinter for printing PDF documents directly from Rails
79
+ actions, you can:
80
+
81
+ ```ruby
82
+ # GET /invoices/1
83
+ def show
84
+ invoice = InvoicePrinter::Document.new(...)
85
+
86
+ respond_to do |format|
87
+ format.pdf {
88
+ @pdf = InvoicePrinter.render(
89
+ document: invoice
90
+ )
91
+ send_data @pdf, type: 'application/pdf', disposition: 'inline'
92
+ }
93
+ end
94
+ end
95
+ ```
96
+
97
+ ### JSON format
98
+
99
+ JSON format is supported via `from_json` method. JSON itself mimicks the original Ruby objects:
100
+
101
+ ```ruby
102
+ json = InvoicePrinter::Document.new(...).to_json
103
+ document = InvoicePrinter::Document.from_json(json)
104
+
105
+
106
+ InvoicePrinter.print(
107
+ document: document,
108
+ ...
109
+ )
110
+
111
+ ```
112
+
113
+
114
+
115
+ ## Customization
116
+
117
+ ### Page size
118
+
119
+ Both A4 and US letter is supported. Just pass `page_size` as an argument to `print` or `render` methods:
120
+
121
+ ```ruby
122
+ InvoicePrinter.print(
123
+ document: invoice,
124
+ labels: labels,
125
+ page_size: :a4,
126
+ file_name: 'invoice.pdf'
127
+ )
128
+ ```
129
+
130
+ `:letter` is the default.
131
+
132
+
133
+ ### Localization
134
+
135
+ To localize your documents you can set both global defaults or instance
136
+ overrides:
137
+
138
+ ```ruby
139
+ InvoicePrinter.labels = {
140
+ provider: 'Dodavatel'
141
+ }
142
+
143
+ labels = {
144
+ purchaser: 'Customer'
145
+ }
146
+
147
+ InvoicePrinter.print(
148
+ document: invoice,
149
+ labels: labels,
150
+ file_name: 'invoice.pdf'
151
+ )
152
+ ```
153
+
154
+ Here is the full list of labels to configure. You can paste and edit this block
155
+ to `initializers/invoice_printer.rb` if you are using Rails.
156
+
157
+ ```ruby
158
+ InvoicePrinter.labels = {
159
+ name: 'Invoice',
160
+ provider: 'Provider',
161
+ purchaser: 'Purchaser',
162
+ tax_id: 'Identification number',
163
+ tax_id2: 'Identification number',
164
+ payment: 'Payment',
165
+ payment_by_transfer: 'Payment by bank transfer on the account below:',
166
+ payment_in_cash: 'Payment in cash',
167
+ account_number: 'Account NO',
168
+ swift: 'SWIFT',
169
+ iban: 'IBAN',
170
+ issue_date: 'Issue date',
171
+ due_date: 'Due date',
172
+ item: 'Item',
173
+ quantity: 'Quantity',
174
+ unit: 'Unit',
175
+ price_per_item: 'Price per item',
176
+ amount: 'Amount',
177
+ tax: 'Tax',
178
+ tax2: 'Tax 2',
179
+ tax3: 'Tax 3',
180
+ subtotal: 'Subtotal',
181
+ total: 'Total'
182
+ }
183
+ ```
184
+
185
+ You can also use sublabels feature to provide the document in two languages:
186
+
187
+ ```ruby
188
+ labels = {
189
+ ...
190
+ }
191
+
192
+ sublabels = {
193
+ name: 'Faktura',
194
+ provider: 'Prodejce',
195
+ purchaser: 'Kupující',
196
+ tax_id: 'IČ',
197
+ tax_id2: 'DIČ',
198
+ payment: 'Forma úhrady',
199
+ payment_by_transfer: 'Platba na následující účet:',
200
+ account_number: 'Číslo účtu',
201
+ issue_date: 'Datum vydání',
202
+ due_date: 'Datum splatnosti',
203
+ item: 'Položka',
204
+ quantity: 'Počet',
205
+ unit: 'MJ',
206
+ price_per_item: 'Cena za položku',
207
+ amount: 'Celkem bez daně',
208
+ subtotal: 'Cena bez daně',
209
+ tax: 'DPH 21 %',
210
+ total: 'Celkem'
211
+ }
212
+
213
+ labels.merge!({ sublabels: sublabels })
214
+
215
+ ...
216
+ ```
217
+
218
+ Now the document will have a little sublabels next to the original labels in Czech.
219
+
220
+ ### Font
221
+
222
+ To support specific characters you might need to specify a TTF font to be used:
223
+
224
+ ``` ruby
225
+ InvoicePrinter.print(
226
+ ...
227
+ font: File.expand_path('../Overpass-Regular.ttf', __FILE__)
228
+ )
229
+ ```
230
+
231
+ We recommend you DejaVuSans and Overpass fonts.
232
+
233
+ ### Background
234
+
235
+ To include a background image you might need to create the file according to the size and resolution to be used (see: [examples/background.png](https://github.com/strzibny/invoice_printer/blob/master/examples/background.png)):
236
+
237
+ ``` ruby
238
+ InvoicePrinter.print(
239
+ ...
240
+ background: File.expand_path('../background.png', __FILE__)
241
+ )
242
+ ```
@@ -0,0 +1,96 @@
1
+ # InvoicePrinter Server
2
+
3
+ InvoicePrinter contains a built in server that can be run from a command line with `invoice_printer_server`.
4
+
5
+ Apart from this you can also manually mount the server inside of your Rack application.
6
+
7
+ ## Running the server
8
+
9
+ ### From command line
10
+
11
+ Once installed, InvoicePrinter provides `invoice_printer_server` executable that starts the Puma server:
12
+
13
+ ```bash
14
+ invoice_printer_server -h 0.0.0.0 -p 5000
15
+ ```
16
+
17
+ `-h` defines a host and `-p` defines a port. For help you can run `--help`.
18
+
19
+ By default server binds to `0.0.0.0:9393`.
20
+
21
+ ### As mountable Rack app
22
+
23
+ If you want you can always run the server from your custom program or mount it directly from a Rack app.
24
+
25
+ `InvoicePrinter::Server` is a Rack app as any other. Example:
26
+
27
+ ```ruby
28
+ require 'rack/handler/puma'
29
+ require 'invoice_printer/server'
30
+
31
+ Rack::Handler::Puma.run InvoicePrinter::Server.freeze.app
32
+ ```
33
+
34
+ ## Available API
35
+
36
+ Endpoints accept similar arguments as the corresponding methods to `InvoicePrinter`. `render` is used for directly getting the PDF output whereas `print` would accept `filename` option and save the document to that
37
+ file.
38
+
39
+ A content type is always `application/json` both for requests and responses.
40
+
41
+ ### `POST /render`
42
+
43
+ Directly render PDF data.
44
+
45
+ Options:
46
+
47
+ - `document` - JSON representation of the document
48
+ - `labels` - JSON for labels
49
+ - `stamp` - path to stamp file
50
+ - `logo` - path to logotype file
51
+ - `font` - path to font file
52
+
53
+ On success a `200` response is returned:
54
+
55
+ ```json
56
+ { "result": "ok", "data": "base64 encoded PDF document" }
57
+ ```
58
+
59
+ On error a `400` response is returned:
60
+
61
+ ```json
62
+ { "result": "error", "error": "error description" }
63
+ ```
64
+
65
+ #### Example
66
+
67
+ Example of calling the API to render a document using `curl`:
68
+
69
+ ```
70
+ $ curl -X POST http://0.0.0.0:9393/render -H "Content-Type: application/json" --data '{"document":{"number":"c. 198900000001","provider_name":"Petr Novy","provider_tax_id":"56565656","provider_tax_id2":"","provider_street":"Rolnicka","provider_street_number":"1","provider_postcode":"747 05","provider_city":"Opava","provider_city_part":"Katerinky","provider_extra_address_line":"","purchaser_name":"Adam Cerny","purchaser_tax_id":"","purchaser_tax_id2":"","purchaser_street":"Ostravska","purchaser_street_number":"1","purchaser_postcode":"747 70","purchaser_city":"Opava","purchaser_city_part":"","purchaser_extra_address_line":"","issue_date":"05/03/2016","due_date":"19/03/2016","subtotal":"Kc 10.000","tax":"Kc 2.100","tax2":"","tax3":"","total":"Kc 12.100,-","bank_account_number":"156546546465","account_iban":"IBAN464545645","account_swift":"SWIFT5456","items":[{"name":"Konzultace","quantity":"2","unit":"hod","price":"Kc 500","tax":"","tax2":"","tax3":"","amount":"Kc 1.000"},{"name":"Programovani","quantity":"10","unit":"hod","price":"Kc 900","tax":"","tax2":"","tax3":"","amount":"Kc 9.000"}],"note":"Osoba je zapsána v zivnostenském rejstríku."}}'
71
+ ```
72
+
73
+ ### `POST /print`
74
+
75
+ Print resulting document to a file.
76
+
77
+ Options:
78
+
79
+ - `document` - JSON representation of the document
80
+ - `labels` - JSON for labels
81
+ - `stamp` - path to stamp file
82
+ - `logo` - path to logotype file
83
+ - `font` - path to font file
84
+ - `filename` - path for saving the generated output PDF
85
+
86
+ On success a `200` response is returned:
87
+
88
+ ```json
89
+ { "result": "ok", "path": "/path/basically/what/was/sent/as/filepath" }
90
+ ```
91
+
92
+ On error a `400` response is returned:
93
+
94
+ ```json
95
+ { "result": "error", "error": "error description" }
96
+ ```
@@ -15,7 +15,6 @@ Gem::Specification.new do |spec|
15
15
  # Remove .pdf files as they take a lot of space
16
16
  package_files = `git ls-files -z`.split("\x0")
17
17
  .reject{ |file| file.match /.*\.pdf/ }
18
- .reject{ |file| file.match /docs\/.*/ }
19
18
 
20
19
  spec.files = package_files
21
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -24,6 +23,8 @@ Gem::Specification.new do |spec|
24
23
  spec.bindir = 'bin'
25
24
 
26
25
  spec.add_dependency 'json', '~> 2.1'
26
+ spec.add_dependency 'roda', '3.5.0'
27
+ spec.add_dependency 'puma', '~> 3.9'
27
28
  spec.add_dependency 'prawn', '2.1.0'
28
29
  spec.add_dependency 'prawn-layout', '0.8.4'
29
30
 
@@ -1,7 +1,12 @@
1
+ require 'json'
1
2
  require 'invoice_printer/version'
3
+ require 'invoice_printer/document'
2
4
  require 'invoice_printer/document/item'
3
5
  require 'invoice_printer/pdf_document'
4
6
 
7
+ # Skip warning for not specifying TTF font
8
+ Prawn::Font::AFM.hide_m17n_warning = true
9
+
5
10
  # Create PDF versions of invoices or receipts using Prawn
6
11
  #
7
12
  # Example:
@@ -1,5 +1,3 @@
1
- require 'json'
2
-
3
1
  module InvoicePrinter
4
2
  # Invoice and receipt representation
5
3
  #
@@ -1,5 +1,3 @@
1
- require 'invoice_printer/document'
2
-
3
1
  module InvoicePrinter
4
2
  class Document
5
3
  # Line items for InvoicePrinter::Document
@@ -0,0 +1,82 @@
1
+ require 'base64'
2
+ require 'roda'
3
+ require 'invoice_printer'
4
+
5
+ class InvoicePrinter::Server < Roda
6
+ route do |r|
7
+ response['Content-Type'] = 'application/json'
8
+
9
+ # Assign params
10
+ if r.content_type == 'application/json'
11
+ begin
12
+ params = JSON.parse(r.body.read, symbolize_names: true)
13
+ rescue => e
14
+ response.status = 400
15
+ response.write({ result: 'error', error: 'Invalid JSON.' }.to_json)
16
+ r.halt
17
+ end
18
+
19
+ labels = params[:labels]
20
+ document = params[:document]
21
+ stamp = params[:stamp]
22
+ logo = params[:logo]
23
+ font = params[:font]
24
+ else
25
+ response.status = 400
26
+ response.write({ result: 'error', error: 'No JSON. Did you set Content-Type to application/json?' }.to_json)
27
+ r.halt
28
+ end
29
+
30
+ # Initialize InvoicePrinter::Document from given JSON
31
+ begin
32
+ document[:items] ||= []
33
+ items = document[:items].map { |item| InvoicePrinter::Document::Item.new(**item) }
34
+ document[:items] = items
35
+
36
+ document = InvoicePrinter::Document.new(**document)
37
+ rescue => e
38
+ response.status = 400
39
+ response.write({ result: 'error', error: 'Invalid JSON document.' }.to_json)
40
+ r.halt
41
+ end
42
+
43
+ # POST /print
44
+ r.post 'print' do
45
+ filename = params[:filename] || 'document.pdf'
46
+
47
+ begin
48
+ InvoicePrinter.print(
49
+ document: document,
50
+ font: font,
51
+ stamp: stamp,
52
+ logo: logo,
53
+ file_name: filename
54
+ )
55
+
56
+ { result: 'ok', path: filename }.to_json
57
+ rescue => e
58
+ response.status = 400
59
+ response.write({ result: 'error', error: e.message }.to_json)
60
+ r.halt
61
+ end
62
+ end
63
+
64
+ # POST /render
65
+ r.post 'render' do
66
+ begin
67
+ stream = InvoicePrinter.render(
68
+ document: document,
69
+ font: font,
70
+ stamp: stamp,
71
+ logo: logo
72
+ )
73
+
74
+ { result: 'ok', data: Base64.encode64(stream) }.to_json
75
+ rescue => e
76
+ response.status = 400
77
+ response.write({ result: 'error', error: e.message }.to_json)
78
+ r.halt
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,3 +1,3 @@
1
1
  module InvoicePrinter
2
- VERSION = '1.1.0'
2
+ VERSION = '1.2.0.alpha1'
3
3
  end
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+ require 'invoice_printer/server'
3
+
4
+ class ApiTest < Minitest::Test
5
+ include Rack::Test::Methods
6
+ include InvoicePrinterHelpers
7
+
8
+ def app
9
+ InvoicePrinter::Server.freeze.app
10
+ end
11
+
12
+ def setup
13
+ @test_dir = File.absolute_path('./tmp/invoice_printer_api')
14
+ FileUtils.mkdir_p @test_dir
15
+ end
16
+
17
+ def teardown
18
+ FileUtils.rm_rf @test_dir if File.exists?(@test_dir)
19
+ end
20
+
21
+ # Test POST /print
22
+
23
+ def test_print_with_invalid_json
24
+ header 'Content-Type', 'application/json'
25
+ post '/print', nil
26
+
27
+ body = JSON.parse last_response.body
28
+
29
+ assert !last_response.ok?
30
+ assert_equal body, { 'result' => 'error', 'error' => 'Invalid JSON.' }
31
+ end
32
+
33
+ def test_print_with_valid_document
34
+ invoice = InvoicePrinter::Document.new(default_document_params)
35
+
36
+ json = {
37
+ 'document' => invoice.to_h,
38
+ 'filename' => "#{@test_dir}/test"
39
+ }.to_json
40
+
41
+ header 'Content-Type', 'application/json'
42
+ post '/print', json
43
+
44
+ body = JSON.parse last_response.body
45
+
46
+ assert last_response.ok?
47
+ assert_equal body, { 'result' => 'ok', 'path' => "#{@test_dir}/test" }
48
+ end
49
+
50
+ # Test POST /render
51
+
52
+ def test_render_with_invalid_json
53
+ header 'Content-Type', 'application/json'
54
+ post '/render', nil
55
+
56
+ body = JSON.parse last_response.body
57
+
58
+ assert !last_response.ok?
59
+ assert_equal body, { 'result' => 'error', 'error' => 'Invalid JSON.' }
60
+ end
61
+
62
+ def test_render_with_valid_document
63
+ invoice = InvoicePrinter::Document.new(default_document_params)
64
+ output = InvoicePrinter.render(document: invoice)
65
+
66
+ json = {
67
+ 'document' => invoice.to_h
68
+ }.to_json
69
+
70
+ header 'Content-Type', 'application/json'
71
+ post '/render', json
72
+
73
+ body = JSON.parse last_response.body
74
+
75
+ assert last_response.ok?
76
+ assert_equal body, { 'result' => 'ok', 'data' => Base64.encode64(output) }
77
+ end
78
+ end
@@ -1,4 +1,6 @@
1
+ require 'json'
1
2
  require 'pdf/inspector'
3
+ require 'rack/test'
2
4
 
3
5
  lib = File.expand_path('../../lib', __FILE__)
4
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: invoice_printer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0.alpha1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josef Strzibny
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-31 00:00:00.000000000 Z
11
+ date: 2018-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: roda
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.5.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.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: puma
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: prawn
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -85,6 +113,7 @@ email:
85
113
  - strzibny@strzibny.name
86
114
  executables:
87
115
  - invoice_printer
116
+ - invoice_printer_server
88
117
  extensions: []
89
118
  extra_rdoc_files: []
90
119
  files:
@@ -93,7 +122,13 @@ files:
93
122
  - LICENSE.txt
94
123
  - README.md
95
124
  - Rakefile
125
+ - assets/logo.png
96
126
  - bin/invoice_printer
127
+ - bin/invoice_printer_server
128
+ - docs/COMMAND_LINE.md
129
+ - docs/INSTALLATION.md
130
+ - docs/LIBRARY.md
131
+ - docs/SERVER.md
97
132
  - examples/background.png
98
133
  - examples/complex_invoice.rb
99
134
  - examples/czech_invoice.rb
@@ -110,7 +145,9 @@ files:
110
145
  - lib/invoice_printer/document.rb
111
146
  - lib/invoice_printer/document/item.rb
112
147
  - lib/invoice_printer/pdf_document.rb
148
+ - lib/invoice_printer/server.rb
113
149
  - lib/invoice_printer/version.rb
150
+ - test/api_test.rb
114
151
  - test/background_test.rb
115
152
  - test/cli_test.rb
116
153
  - test/dates_box_test.rb
@@ -139,16 +176,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
139
176
  version: '0'
140
177
  required_rubygems_version: !ruby/object:Gem::Requirement
141
178
  requirements:
142
- - - ">="
179
+ - - ">"
143
180
  - !ruby/object:Gem::Version
144
- version: '0'
181
+ version: 1.3.1
145
182
  requirements: []
146
183
  rubyforge_project:
147
- rubygems_version: 2.6.13
184
+ rubygems_version: 2.6.14
148
185
  signing_key:
149
186
  specification_version: 4
150
187
  summary: Super simple PDF invoicing in pure Ruby
151
188
  test_files:
189
+ - test/api_test.rb
152
190
  - test/background_test.rb
153
191
  - test/cli_test.rb
154
192
  - test/dates_box_test.rb