write_invoice 0.1.81

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,513 @@
1
+ module Sections
2
+ private
3
+
4
+
5
+ def pdf_generate_header( obj, pdf )
6
+
7
+ pdf.font( obj[:style][:font][:name] )
8
+
9
+ h = {
10
+ grid: {
11
+ length: {
12
+ x: 5,
13
+ y: 5
14
+ },
15
+ height: {
16
+ total: nil,
17
+ cell: nil,
18
+ image: nil
19
+ },
20
+ width: {
21
+ total: nil,
22
+ cell: nil,
23
+ image: nil
24
+ }
25
+ },
26
+ box: {
27
+ padding: 5,
28
+ position: {
29
+ x: nil,
30
+ y: nil,
31
+ },
32
+ size: {
33
+ width: nil,
34
+ height: nil
35
+ },
36
+ range: {
37
+ x: {
38
+ min: nil,
39
+ max: nil
40
+ },
41
+ y: {
42
+ min: nil,
43
+ max: nil
44
+ }
45
+ }
46
+ },
47
+ image: {
48
+ image: nil,
49
+ fit: nil,
50
+ colspan: nil,
51
+ rowspan: nil,
52
+ borders: nil,
53
+ border_width: nil
54
+ }
55
+ }
56
+
57
+ h[:grid][:length][:x] = obj[:headline][:grid][:x]
58
+ h[:grid][:length][:y] = obj[:headline][:grid][:y]
59
+
60
+ h[:grid][:height][:total] = obj[:style][:header][:height]
61
+
62
+ h[:box][:position][:x] = obj[:headline][:image][:grid][ 0 ]
63
+ h[:box][:position][:y] = obj[:headline][:image][:grid][ 1 ]
64
+
65
+ h[:box][:size][:width] = obj[:headline][:image][:colspan]
66
+ h[:box][:size][:height] = obj[:headline][:image][:rowspan]
67
+
68
+ h[:grid][:width][:total] = obj[:style][:document][:width]
69
+
70
+ h[:grid][:width][:cell] = h[:grid][:width][:total] / h[:grid][:length][:x]
71
+ h[:grid][:height][:cell] = h[:grid][:height][:total] / h[:grid][:length][:y]
72
+
73
+ h[:grid][:width][:image] = ( h[:grid][:width][:cell] * h[:box][:size][:width] ) - h[:box][:padding] * 2
74
+ h[:grid][:height][:image] = ( h[:grid][:height][:cell] * h[:box][:size][:height] ) - h[:box][:padding] * 2
75
+
76
+ fit = [ h[:grid][:width][:image], h[:grid][:height][:image] ]
77
+ obj[:headline][:image].key?( :fit ) ? fit = obj[:headline][:image][:fit] : ''
78
+
79
+ if obj[:show][:logo]
80
+ if !obj[:headline][:image][:src].to_s.split( '.' ).last.eql?( 'png' )
81
+ h[:image][:image] = StringIO.new( Base64.decode64( obj[:headline][:image][:src] ) )
82
+ else
83
+ h[:image][:image] = obj[:headline][:image][:src]
84
+ end
85
+
86
+ h[:image][:fit] = fit
87
+ h[:image][:colspan] = h[:box][:size][:width]
88
+ h[:image][:rowspan] = h[:box][:size][:height]
89
+ h[:image][:borders] = obj[:headline][:image][:borders]
90
+ h[:image][:border_width] = obj[:headline][:image][:border_width]
91
+ end
92
+
93
+ [ { pos: :x, size: :width }, { pos: :y, size: :height } ].each do | axis |
94
+ h[:box][:range][ axis[:pos ] ][:min] = h[:box][:position][ axis[:pos ] ]
95
+ h[:box][:range][ axis[:pos ] ][:max] = h[:box][:range][ axis[:pos ] ][:min] + h[:box][:size][ axis[:size ] ] -1
96
+ end
97
+
98
+ data = []
99
+ h[:grid][:length][:y].times.each do | y |
100
+ row = []
101
+ h[:grid][:length][:x].times.each do | x |
102
+ if( y == h[:box][:position][:y] and x == h[:box][:position][:x] )
103
+ obj[:show][:logo] ? row.push( h[:image] ) : ''
104
+ end
105
+
106
+ a = y.between?( h[:box][:range][:y][:min], h[:box][:range][:y][:max] )
107
+ b = x.between?( h[:box][:range][:x][:min], h[:box][:range][:x][:max] )
108
+
109
+ if( a and b )
110
+ else
111
+ r = obj[:headline][:texts].find { | item | item[:grid].eql?( [ x, y ] ) }
112
+ if r.nil?
113
+ rr = obj[:headline][:default]
114
+ else
115
+ rr = r
116
+
117
+ [ :content, :text_color].each do | kk |
118
+ keys = rr[ kk ].to_s.split( '__' ).map { | a | a.to_sym }
119
+ rr[ kk ] = self.get_value( keys, obj, false )
120
+ end
121
+ end
122
+
123
+ cell = Prawn::Table::Cell::Text.new(
124
+ pdf,
125
+ [ 0, 0 ],
126
+ content: rr[:content],
127
+ inline_format: true,
128
+ borders: rr[:borders],
129
+ border_width: rr[:border_width],
130
+ text_color: rr[:text_color],
131
+ align: rr[:align]
132
+ )
133
+
134
+ row.push( cell )
135
+ end
136
+ end
137
+ data.push( row )
138
+ end
139
+
140
+ pdf.table(
141
+ data,
142
+ cell_style: {
143
+ size: obj[:style][:font][:small],
144
+ height: h[:grid][:height][:cell]
145
+ },
146
+ width: h[:grid][:width][:total]
147
+ )
148
+ return pdf
149
+ end
150
+
151
+
152
+ def pdf_generate_two( obj, pdf )
153
+ pdf.font obj[:style][:font][:name]
154
+ offset_x = obj[:style][:address_label][:offset_x]
155
+
156
+ pdf.text_box(
157
+ obj[:sections][:two][:small][:content],
158
+ at: [ pdf.bounds.left + offset_x, pdf.cursor],
159
+ width: 400,
160
+ height: 200,
161
+ overflow: :expand,
162
+ inline_format: true,
163
+ size: obj[:style][:font][:small]
164
+ )
165
+
166
+ pdf.move_down obj[:style][:address_label][:move_down_one]
167
+
168
+ pdf.text_box(
169
+ obj[:sections][:two][:to][:content],
170
+ at: [ pdf.bounds.left + offset_x , pdf.cursor],
171
+ width: 400,
172
+ height: 200,
173
+ overflow: :expand,
174
+ inline_format: true,
175
+ size: obj[:style][:font][:default]
176
+ )
177
+
178
+ pdf.move_down obj[:style][:address_label][:move_down_two]
179
+
180
+ return pdf
181
+ end
182
+
183
+
184
+ def pdf_generate_three( obj, pdf )
185
+ pdf.font( obj[:style][:font][:name] )
186
+
187
+ pdf.text(
188
+ obj[:sections][:three][:date][:content],
189
+ inline_format: true,
190
+ size: obj[:style][:font][:default]
191
+ )
192
+ pdf.text(
193
+ obj[:sections][:three][:headline][:content],
194
+ inline_format: true,
195
+ size: obj[:style][:font][:default]
196
+ )
197
+
198
+ cpos = pdf.cursor
199
+
200
+ if obj[:show][:qr_code]
201
+ x = obj[:style][:articles]
202
+ .keys
203
+ .map { | key | obj[:style][:articles][ key ][:width] }
204
+ .sum + 10
205
+
206
+ pdf.print_qr_code(
207
+ obj[:sections][:three][:qr_code][:content],
208
+ pos: [ x - obj[:style][:qr_code][:width] , cpos + obj[:style][:qr_code][:width] ],
209
+ extent: obj[:style][:qr_code][:width],
210
+ stroke: false
211
+ )
212
+ end
213
+
214
+ return pdf
215
+ end
216
+
217
+
218
+ def pdf_generate_four( obj, pdf )
219
+ pdf.font( obj[:style][:font][:name] )
220
+ pdf.text(
221
+ obj[:sections][:four][:snippet][:content],
222
+ inline_format: true,
223
+ size: obj[:style][:font][:default]
224
+ )
225
+
226
+ return pdf
227
+ end
228
+
229
+
230
+ def pdf_generate_five( obj, pdf )
231
+ table_data = []
232
+ row = []
233
+
234
+ cells = obj[:text][:articles].zip( obj[:style][:articles] )
235
+ .map { | text, style | { name: text[ 1 ] }.merge( style[ 1 ] ) }
236
+
237
+ cells.each do | cell |
238
+ c = Prawn::Table::Cell::Text.new(
239
+ pdf,
240
+ [ 0, 0 ],
241
+ content: cell[:name],
242
+ inline_format: true,
243
+ borders: [ :bottom ],
244
+ align: cell[:align],
245
+ width: cell[:width],
246
+ )
247
+ row.push( c )
248
+ end
249
+ table_data.push( row )
250
+
251
+ obj[:items][:articles].each.with_index do | article, index |
252
+ contents = [ index + 1, :id, :name, :pieces, :single, :total ].map do | key |
253
+ if key.class.to_s.eql?( 'Integer' )
254
+ key.to_s
255
+ else
256
+ keys = key.to_s.split( '__' ).map { | a | a.to_sym }
257
+ case keys.length
258
+ when 1
259
+ article[ keys[ 0 ] ].to_s
260
+ when 2
261
+ article[ keys[ 0 ] ][ keys[ 1 ] ].to_s
262
+ end
263
+ end
264
+ end
265
+
266
+ row = []
267
+ contents.each.with_index do | text, i |
268
+ c = Prawn::Table::Cell::Text.new(
269
+ pdf,
270
+ [ 0, 0 ],
271
+ content: text,
272
+ inline_format: true,
273
+ border_width: 0,
274
+ align: cells[ i ][:align],
275
+ width: cells[ i ][:width],
276
+ )
277
+ row.push( c )
278
+ end
279
+
280
+ table_data.push( row )
281
+ end
282
+
283
+ pdf.table(
284
+ table_data,
285
+ cell_style: { size: obj[:style][:font][:default] },
286
+ width: obj[:style][:document][:width],
287
+ row_colors: obj[:style][:colors][:rows].values
288
+ )
289
+
290
+ return pdf
291
+ end
292
+
293
+
294
+ def pdf_generate_six( obj, pdf )
295
+ table_data = []
296
+ orders = obj[:text][:total].keys
297
+ articles = obj[:style][:articles].keys
298
+
299
+ grid = orders.map do | order |
300
+ articles.map do | article |
301
+ {
302
+ text: '',
303
+ width: obj[:style][:articles][ article ][:width],
304
+ align: obj[:style][:articles][ article ][:align],
305
+ borders: [:top],
306
+ border_width: 0
307
+ }
308
+ end
309
+ end
310
+
311
+ items = orders.map.with_index do | key, index |
312
+ item = {}
313
+ item[:show] = obj[:show][ key ]
314
+ item[:y] = index
315
+ item[:text] = obj[:text][:total][ key ]
316
+ item[:value] = obj[:sections][:six][ key ][:content]
317
+ item[:borders] = obj[:style][:total][ key ][:borders]
318
+ item[:border_width] = obj[:style][:total][ key ][:border_width]
319
+ item
320
+ end
321
+
322
+ items.each.with_index do | item, y |
323
+ if item[:show]
324
+ item.keys.each do | key |
325
+ [ 3, 4, 5 ].each do | type |
326
+ grid[ y ][ type ][ key ] = item[ key ]
327
+ case type
328
+ when 3
329
+ grid[ y ][ type ][:insert] = item[:text]
330
+ when 4
331
+ grid[ y ][ type ][:insert] = ''
332
+ when 5
333
+ grid[ y ][ type ][:insert] = item[:value]
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end
339
+
340
+ grid.each do | _row |
341
+ row = []
342
+ _row.each do | cell |
343
+ c = Prawn::Table::Cell::Text.new(
344
+ pdf,
345
+ [ 0, 0 ],
346
+ content: cell[:insert].to_s,
347
+ inline_format: true,
348
+ borders: cell[:borders],
349
+ border_widths: cell[:border_width],
350
+ align: cell[:align],
351
+ width: cell[:width]
352
+ )
353
+ row.push( c )
354
+ end
355
+ table_data.push( row )
356
+ end
357
+
358
+ if table_data.length != 0
359
+ pdf.table(
360
+ table_data,
361
+ cell_style: { size: obj[:style][:font][:default] },
362
+ width: obj[:style][:document][:width]
363
+ )
364
+ end
365
+
366
+ return pdf
367
+ end
368
+
369
+
370
+ def pdf_generate_seven( obj, pdf )
371
+ pdf.font( obj[:style][:font][:name] )
372
+ pdf.text(
373
+ obj[:sections][:seven][:snippet][:content],
374
+ inline_format: true,
375
+ size: obj[:style][:font][:default]
376
+ )
377
+
378
+ return pdf
379
+ end
380
+
381
+
382
+ def pdf_generate_eight( obj, pdf )
383
+ pdf.font( obj[:style][:font][:name] )
384
+ pdf.text(
385
+ obj[:sections][:eight][:snippet][:content],
386
+ inline_format: true,
387
+ size: obj[:style][:font][:default]
388
+ )
389
+
390
+ return pdf
391
+ end
392
+
393
+
394
+ def pdf_generate_nine( obj, pdf, p )
395
+ x = obj[:style][:articles]
396
+ .keys
397
+ .map { | key | obj[:style][:articles][ key ][:width] }
398
+ .sum
399
+
400
+ measure = "#{p[:page]} / #{p[:total]}"
401
+
402
+ offset = pdf
403
+ .font( obj[:style][:font][:name] )
404
+ .compute_width_of( measure, size: obj[:style][:font][:small] )
405
+
406
+ options = {
407
+ at: [ x - offset, pdf.bounds.height + obj[:style][:page_count][:offset_y] ],
408
+ size: obj[:style][:font][:small],
409
+ start_count_at: obj[:style][:page_count][:start_count_at]
410
+ }
411
+
412
+ pdf.go_to_page( p[:index] + 1 )
413
+ pdf.draw_text( measure, options )
414
+
415
+ return pdf
416
+ end
417
+
418
+
419
+ def pdf_generate_footer( obj, pdf )
420
+
421
+ table_data = []
422
+ aligns = obj[:footer].keys
423
+
424
+ headlines = [
425
+ :sections__nine__left_headline__content,
426
+ :sections__nine__center_headline__content,
427
+ :sections__nine__right_headline__content
428
+ ]
429
+ headlines = headlines.map do | a |
430
+ keys = a.to_s.split( '__' ).map { | a | a.to_sym }
431
+ self.get_value( keys, obj, false )
432
+ end
433
+
434
+ row = []
435
+
436
+ for i in 0..headlines.length - 1
437
+ # str = headlines[ i ]
438
+ c = Prawn::Table::Cell::Text.new(
439
+ pdf,
440
+ [ 0, 0 ],
441
+ content: '-',
442
+ inline_format: true,
443
+ borders: obj[:style][:footer][:borders],
444
+ border_width: obj[:style][:footer][:border_width],
445
+ text_color: obj[:style][:colors][:background],
446
+ align: aligns[ i ],
447
+ padding: 0
448
+ )
449
+ row.push( c )
450
+ end
451
+
452
+ table_data.push( row )
453
+ row = []
454
+
455
+ for i in 0..headlines.length - 1
456
+ str = headlines[ i ]
457
+ c = Prawn::Table::Cell::Text.new(
458
+ pdf,
459
+ [ 0, 0 ],
460
+ content: str,
461
+ inline_format: true,
462
+ border_width: 0,
463
+ align: aligns[ i ],
464
+ padding: 0
465
+ )
466
+ row.push( c )
467
+ end
468
+
469
+ table_data.push( row )
470
+ combs = []
471
+
472
+ obj[:footer].keys.each { | h |
473
+ obj[:footer][ h ].keys.each { | v |
474
+ combs.push( [ h, v ] )
475
+ }
476
+ }
477
+
478
+ rows = combs
479
+ .map { | a | a[ 1 ] }.to_set.to_a
480
+ .map { | key | combs.select { | cell | cell[ 1 ] == key } }
481
+
482
+ rows.each do | _row |
483
+ row = []
484
+ _row.each do | _cell |
485
+ keys = obj[:footer][ _cell[ 0 ] ][ _cell[ 1 ] ]
486
+ .to_s.split( '__' )
487
+ .map { | a | a.to_sym }
488
+
489
+ str = get_value( keys, obj, false )
490
+ c = Prawn::Table::Cell::Text.new(
491
+ pdf,
492
+ [ 0, 0 ],
493
+ content: str,
494
+ inline_format: true,
495
+ border_width: 0,
496
+ align: _cell[ 0 ],
497
+ padding: 0
498
+ )
499
+ row.push( c )
500
+ end
501
+ table_data.push( row )
502
+ end
503
+
504
+ pdf.table(
505
+ table_data,
506
+ cell_style: { size: obj[:style][:font][:small] },
507
+ width: obj[:style][:document][:width]
508
+ )
509
+
510
+ return pdf
511
+ end
512
+
513
+ end
@@ -0,0 +1,200 @@
1
+ module Exmple
2
+ private
3
+
4
+
5
+ def examples_generate( invoices_total: nil, articles_total: nil )
6
+ struct = {
7
+ document: {
8
+ metadata: {
9
+ title: '',
10
+ author: '',
11
+ subject: ''
12
+ },
13
+ encrypt: {
14
+ user_password: '',
15
+ owner_password: '',
16
+ permissions: {
17
+ print_document: nil,
18
+ modify_contents: nil,
19
+ copy_contents: nil,
20
+ modify_annotations: nil
21
+ }
22
+ }
23
+ },
24
+ invoices: []
25
+ }
26
+
27
+ results = []
28
+ rand( invoices_total ).times.each.with_index do | t, index |
29
+ payload = example_generate( articles_total: articles_total )
30
+
31
+ if index == 0
32
+ results.push( payload )
33
+ else
34
+ [ :address, :bank, :contact, :tax_id ].each do | key |
35
+ payload[:from][ key ] = results[ 0 ][:from][ key ]
36
+ end
37
+
38
+ results.push( payload )
39
+ end
40
+ end
41
+
42
+ struct[:document][:metadata][:title] = results[ 0 ][:from][:address][:name]
43
+ struct[:document][:metadata][:author] = 'This is a Demo Document.'
44
+ struct[:document][:metadata][:subject] = 'Ecommerce Revenue'
45
+
46
+ alpha = [ ( 'a'..'z' ), ( 'A'..'Z' ), ( '0'..'9' ) ].map( &:to_a ).flatten
47
+ struct[:document][:encrypt][:user_password] = ( 0...42 ).map { alpha[ rand( alpha.length ) ] }.join
48
+ struct[:document][:encrypt][:owner_password] = struct[:document][:encrypt][:user_password]
49
+ struct[:document][:encrypt][:permissions][:print_document] = true
50
+ struct[:document][:encrypt][:permissions][:modify_contents] = false
51
+ struct[:document][:encrypt][:permissions][:copy_contents] = false
52
+ struct[:document][:encrypt][:permissions][:modify_annotations] = false
53
+
54
+ struct[:invoices] = results
55
+ .sort_by { | a | a[:to][:address][:name] }
56
+
57
+ return struct
58
+ end
59
+
60
+
61
+ private
62
+
63
+
64
+ def example_generate( articles_total: nil )
65
+ template = {
66
+ structure: {
67
+ meta: {
68
+ id: '',
69
+ qr_code: '',
70
+ headline: '',
71
+ group: ''
72
+ },
73
+ date: {
74
+ period: {
75
+ from: '',
76
+ to: ''
77
+ },
78
+ invoice: '',
79
+ billing: ''
80
+ },
81
+ from: {
82
+ address: {
83
+ name: '',
84
+ phrase: '',
85
+ street: '',
86
+ city: '',
87
+ country: ''
88
+ },
89
+ bank: {
90
+ name: '',
91
+ iban: '',
92
+ bic: ''
93
+ },
94
+ contact: {
95
+ phone: '',
96
+ mobile: '',
97
+ email: '',
98
+ website: ''
99
+ },
100
+ tax_id: ''
101
+ },
102
+ to: {
103
+ address: {
104
+ name: '',
105
+ street: '',
106
+ city: '',
107
+ country: ''
108
+ },
109
+ tax_id: ''
110
+ },
111
+ items: {
112
+ articles: [],
113
+ sub_total: nil,
114
+ shipping_fee: nil,
115
+ total_net: nil,
116
+ vat: nil,
117
+ total_gross: nil
118
+ }
119
+ }
120
+ }
121
+
122
+ config = {
123
+ domain: 'writeinvoice.com',
124
+ date: {
125
+ from: '1998-01-01',
126
+ to: '1998-01-30'
127
+ },
128
+ days: {
129
+ invoice: 15,
130
+ billing: 30
131
+ }
132
+ }
133
+
134
+ payload = Marshal.load( Marshal.dump( template[:structure] ) )
135
+ payload[:date][:period][:from] =
136
+ Faker::Date.between( from: config[:date][:from], to: config[:date][:to] ).to_time.to_i
137
+
138
+ tmp = Faker::Date.between( from: config[:date][:from], to: config[:date][:to] )
139
+ payload[:date][:period][:to] = tmp.to_time.to_i
140
+ payload[:date][:invoice] = tmp.next_day( config[:days][:invoice] ).to_time.to_i
141
+ payload[:date][:billing] = tmp.next_day( config[:days][:billing] ).to_time.to_i
142
+
143
+ payload[:from][:address][:name] = Faker::Movies::Hobbit.character
144
+ payload[:from][:address][:phrase] = Faker::Company.catch_phrase
145
+ payload[:from][:address][:street] = Faker::Address.street_address
146
+ payload[:from][:address][:city] = "#{Faker::Address.zip} #{Faker::Address.city}"
147
+ payload[:from][:address][:country] = Faker::Address.country
148
+
149
+ payload[:from][:bank][:name] = Faker::Company.name
150
+ payload[:from][:bank][:iban] = Faker::Bank.iban
151
+ payload[:from][:bank][:bic] = Faker::Bank.swift_bic
152
+
153
+ payload[:from][:contact][:phone] = Faker::PhoneNumber.phone_number
154
+ payload[:from][:contact][:mobile] = Faker::PhoneNumber.phone_number
155
+ payload[:from][:contact][:email] = Faker::Internet.email( domain: config[:domain] )
156
+ payload[:from][:contact][:website] = Faker::Internet.domain_name( subdomain: true, domain: config[:domain] )
157
+
158
+ payload[:from][:tax_id] = Faker::IDNumber.valid
159
+
160
+ payload[:to][:address][:name] = Faker::Movies::StarWars.character
161
+ payload[:to][:address][:street] = Faker::Address.street_address
162
+ payload[:to][:address][:city] = "#{Faker::Address.zip} #{Faker::Address.city}"
163
+ payload[:to][:address][:country] = Faker::Movies::StarWars.planet
164
+
165
+ payload[:to][:tax_id] = Faker::IDNumber.valid
166
+
167
+ payload[:meta][:id] = Faker::DrivingLicence.usa_driving_licence
168
+ payload[:meta][:qr_code] = "https://#{payload[:from][:contact][:website]}/api/#{payload[:meta][:id]}"
169
+ payload[:meta][:headline] = "#{payload[:meta][:id]} | #{payload[:to][:address][:name]}"
170
+ payload[:meta][:group] = DateTime.strptime( payload[:date][:billing].to_s, '%s' ).strftime( '%G-W%V' )
171
+
172
+ rand( articles_total ).times.each do | index |
173
+ article = {
174
+ id: '',
175
+ name: '',
176
+ pieces: nil,
177
+ single: nil,
178
+ total: nil
179
+ }
180
+
181
+ article[:id] = Faker::IDNumber.valid
182
+ article[:name] = Faker::Commerce.product_name
183
+ _p = rand( 1..5 )
184
+ article[:pieces] = _p
185
+ _n = Faker::Commerce.price
186
+ article[:single] = _n
187
+ article[:total] = ( _n * _p ).round( 2 )
188
+ payload[:items][:articles].push( article )
189
+ end
190
+
191
+ payload[:items][:sub_total] = payload[:items][:articles].map { | a | a[:total] }.sum
192
+ payload[:items][:shipping_fee] = Faker::Commerce.price( range: 0..10.0 )
193
+ payload[:items][:total_net] = ( payload[:items][:sub_total] + payload[:items][:shipping_fee] ).round( 2 )
194
+ payload[:items][:total_gross] = ( payload[:items][:total_net] * 1.19 ).round( 2 )
195
+ payload[:items][:vat] = ( payload[:items][:total_gross] - payload[:items][:total_net] ).round( 2 )
196
+
197
+ return payload
198
+ end
199
+
200
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WriteInvoice
4
+ VERSION = "0.1.81"
5
+ end