invoice_printer 2.0.0.beta1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -94,41 +94,7 @@ module InvoicePrinter
94
94
  end
95
95
 
96
96
  if used? @font
97
- if File.exist?(@font)
98
- set_fonts(@font) if @font
99
- else
100
- raise FontFileNotFound, "Font file not found at #{@font}"
101
- end
102
- end
103
-
104
- # Version 2.1 deprecation warnings
105
- warnings = [
106
- @document.provider_street,
107
- @document.provider_street_number,
108
- @document.provider_postcode,
109
- @document.provider_city,
110
- @document.provider_city_part,
111
- @document.provider_extra_address_line,
112
- @document.purchaser_street,
113
- @document.purchaser_street_number,
114
- @document.purchaser_postcode,
115
- @document.purchaser_city,
116
- @document.purchaser_city_part,
117
- @document.purchaser_extra_address_line
118
- ].delete_if(&:empty?)
119
-
120
- unless warnings.empty?
121
- warning = <<~WARN
122
- WARNING: Following values are used in deprecated fields and
123
- won't be rendered in future versions of InvoicePrinter:
124
-
125
- #{warnings.join(", ")}
126
-
127
- Use new provider_lines and purchaser_lines fields instead of
128
- the old address fields.
129
- WARN
130
-
131
- $stderr.puts warning
97
+ use_font(@font)
132
98
  end
133
99
 
134
100
  build_pdf
@@ -146,8 +112,28 @@ module InvoicePrinter
146
112
 
147
113
  private
148
114
 
115
+ def use_font(font)
116
+ if File.exist?(@font)
117
+ set_font_from_path(@font)
118
+ else
119
+ set_builtin_font(@font)
120
+ end
121
+ end
122
+
123
+ def set_builtin_font(font)
124
+ require 'invoice_printer/fonts'
125
+
126
+ @pdf.font_families.update(
127
+ "#{font}" => InvoicePrinter::Fonts.paths_for(font)
128
+ )
129
+ @pdf.font(font)
130
+
131
+ rescue StandardError
132
+ raise FontFileNotFound, "Font file not found for #{font}"
133
+ end
134
+
149
135
  # Add font family in Prawn for a given +font+ file
150
- def set_fonts(font)
136
+ def set_font_from_path(font)
151
137
  font_name = Pathname.new(font).basename
152
138
  @pdf.font_families.update(
153
139
  "#{font_name}" => {
@@ -165,6 +151,7 @@ module InvoicePrinter
165
151
  @push_down = 0
166
152
  @push_items_table = 0
167
153
  @pdf.fill_color '000000'
154
+ @pdf.stroke_color 'aaaaaa'
168
155
  build_header
169
156
  build_provider_box
170
157
  build_purchaser_box
@@ -447,7 +434,6 @@ module InvoicePrinter
447
434
  end
448
435
 
449
436
  # Match the height of next box if needed
450
- # TODO: it's smaller without sublabels
451
437
  min_height = 60
452
438
  if used?(@document.issue_date) || used?(@document.due_date)
453
439
  min_height = (used?(@document.issue_date) && used?(@document.due_date)) ? 75 : 60
@@ -467,7 +453,8 @@ module InvoicePrinter
467
453
  at: [10, y(483) - @push_down],
468
454
  width: x(234)
469
455
  )
470
- @pdf.stroke_rounded_rectangle([0, 508 - @push_down], 270, 45, 6)
456
+
457
+ @pdf.stroke_rounded_rectangle([0, y(508) - @push_down], x(266), @payment_box_height, 6)
471
458
  else
472
459
  @payment_box_height = 60
473
460
  @push_iban = 0
@@ -654,6 +641,7 @@ module InvoicePrinter
654
641
  height = @payment_box_height if @payment_box_height > height
655
642
 
656
643
  @pdf.stroke_rounded_rectangle([x(274), y(508) - @push_down], x(266), height, 6)
644
+ @push_items_table += 12 if @push_items_table <= 18
657
645
  end
658
646
  end
659
647
 
@@ -683,26 +671,28 @@ module InvoicePrinter
683
671
  items_params = determine_items_structure
684
672
  items = build_items_data(items_params)
685
673
  headers = build_items_header(items_params)
674
+ data = items.prepend(headers)
686
675
 
687
- styles = {
688
- headers: headers,
689
- row_colors: ['F5F5F5', nil],
676
+ options = {
677
+ header: true,
678
+ row_colors: [nil, 'ededed'],
690
679
  width: x(540, 2),
691
- align: {
692
- 0 => :left,
693
- 1 => :right,
694
- 2 => :right,
695
- 3 => :right,
696
- 4 => :right,
697
- 5 => :right,
698
- 6 => :right,
699
- 7 => :right,
700
- 8 => :right
701
- },
702
- font_size: 10
680
+ cell_style: {
681
+ borders: []
682
+ }
703
683
  }
704
684
 
705
- @pdf.table(items, styles) unless items.empty?
685
+ unless items.empty?
686
+ @pdf.font_size(10) do
687
+ @pdf.table(data, options) do
688
+ row(0).background_color = 'e3e3e3'
689
+ row(0).border_color = 'aaaaaa'
690
+ row(0).borders = [:bottom]
691
+ row(items.size - 1).borders = [:bottom]
692
+ row(items.size - 1).border_color = 'd9d9d9'
693
+ end
694
+ end
695
+ end
706
696
  end
707
697
 
708
698
  # Determine sections of the items table to show based on provided data
@@ -726,15 +716,15 @@ module InvoicePrinter
726
716
  def build_items_data(items_params)
727
717
  @document.items.map do |item|
728
718
  line = []
729
- line << item.name if items_params[:names]
730
- line << item.variable if items_params[:variables]
731
- line << item.quantity if items_params[:quantities]
732
- line << item.unit if items_params[:units]
733
- line << item.price if items_params[:prices]
734
- line << item.tax if items_params[:taxes]
735
- line << item.tax2 if items_params[:taxes2]
736
- line << item.tax3 if items_params[:taxes3]
737
- line << item.amount if items_params[:amounts]
719
+ line << { content: item.name, borders: [:bottom], align: :left } if items_params[:names]
720
+ line << { content: item.variable, align: :right } if items_params[:variables]
721
+ line << { content: item.quantity, align: :right } if items_params[:quantities]
722
+ line << { content: item.unit, align: :right } if items_params[:units]
723
+ line << { content: item.price, align: :right } if items_params[:prices]
724
+ line << { content: item.tax, align: :right } if items_params[:taxes]
725
+ line << { content: item.tax2, align: :right } if items_params[:taxes2]
726
+ line << { content: item.tax3, align: :right } if items_params[:taxes3]
727
+ line << { content: item.amount, align: :right } if items_params[:amounts]
738
728
  line
739
729
  end
740
730
  end
@@ -742,15 +732,15 @@ module InvoicePrinter
742
732
  # Include only relevant headers
743
733
  def build_items_header(items_params)
744
734
  headers = []
745
- headers << { text: label_with_sublabel(:item) } if items_params[:names]
746
- headers << { text: label_with_sublabel(:variable) } if items_params[:variables]
747
- headers << { text: label_with_sublabel(:quantity) } if items_params[:quantities]
748
- headers << { text: label_with_sublabel(:unit) } if items_params[:units]
749
- headers << { text: label_with_sublabel(:price_per_item) } if items_params[:prices]
750
- headers << { text: label_with_sublabel(:tax) } if items_params[:taxes]
751
- headers << { text: label_with_sublabel(:tax2) } if items_params[:taxes2]
752
- headers << { text: label_with_sublabel(:tax3) } if items_params[:taxes3]
753
- headers << { text: label_with_sublabel(:amount) } if items_params[:amounts]
735
+ headers << { content: label_with_sublabel(:item), align: :left } if items_params[:names]
736
+ headers << { content: label_with_sublabel(:variable), align: :right } if items_params[:variables]
737
+ headers << { content: label_with_sublabel(:quantity), align: :right } if items_params[:quantities]
738
+ headers << { content: label_with_sublabel(:unit), align: :right } if items_params[:units]
739
+ headers << { content: label_with_sublabel(:price_per_item), align: :right } if items_params[:prices]
740
+ headers << { content: label_with_sublabel(:tax), align: :right } if items_params[:taxes]
741
+ headers << { content: label_with_sublabel(:tax2), align: :right } if items_params[:taxes2]
742
+ headers << { content: label_with_sublabel(:tax3), align: :right } if items_params[:taxes3]
743
+ headers << { content: label_with_sublabel(:amount), align: :right } if items_params[:amounts]
754
744
  headers
755
745
  end
756
746
 
@@ -777,13 +767,13 @@ module InvoicePrinter
777
767
  @pdf.move_down(25)
778
768
 
779
769
  items = []
780
- items << ["#{@labels[:subtotal]}:#{build_sublabel_for_total_table(:subtotal)}", @document.subtotal] \
770
+ items << [{ content: "#{@labels[:subtotal]}:#{build_sublabel_for_total_table(:subtotal)}", align: :right }, @document.subtotal] \
781
771
  unless @document.subtotal.empty?
782
- items << ["#{@labels[:tax]}:#{build_sublabel_for_total_table(:tax)}", @document.tax] \
772
+ items << [{ content: "#{@labels[:tax]}:#{build_sublabel_for_total_table(:tax)}", align: :right }, @document.tax] \
783
773
  unless @document.tax.empty?
784
- items << ["#{@labels[:tax2]}:#{build_sublabel_for_total_table(:tax2)}", @document.tax2] \
774
+ items << [{ content: "#{@labels[:tax2]}:#{build_sublabel_for_total_table(:tax2)}", align: :right }, @document.tax2] \
785
775
  unless @document.tax2.empty?
786
- items << ["#{@labels[:tax3]}:#{build_sublabel_for_total_table(:tax3)}", @document.tax3] \
776
+ items << [{ content: "#{@labels[:tax3]}:#{build_sublabel_for_total_table(:tax3)}", align: :right }, @document.tax3] \
787
777
  unless @document.tax3.empty?
788
778
 
789
779
  width = [
@@ -793,16 +783,14 @@ module InvoicePrinter
793
783
  "#{@labels[:tax3]}#{@document.tax3}".size
794
784
  ].max * 8
795
785
 
796
- styles = {
797
- border_width: 0,
798
- align: {
799
- 0 => :right,
800
- 1 => :left
786
+ options = {
787
+ cell_style: {
788
+ borders: []
801
789
  }
802
790
  }
803
791
 
804
792
  @pdf.span(x(width), position: :right) do
805
- @pdf.table(items, styles) unless items.empty?
793
+ @pdf.table(items, options) unless items.empty?
806
794
  end
807
795
 
808
796
  @pdf.move_down(15)
@@ -841,7 +829,7 @@ module InvoicePrinter
841
829
  # If a note is present, position it on top of it.
842
830
  def build_logo
843
831
  if @logo && !@logo.empty?
844
- bottom = @document.note.empty? ? 75 : 85
832
+ bottom = @document.note.empty? ? 75 : (75 + note_height)
845
833
  @pdf.image(@logo, at: [0, bottom], fit: [200, 50])
846
834
  end
847
835
  end
@@ -859,12 +847,19 @@ module InvoicePrinter
859
847
  @pdf.text_box(
860
848
  "#{@document.note}",
861
849
  size: 10,
862
- at: [0, 10],
850
+ at: [0, note_height],
863
851
  width: x(450),
864
852
  align: :left
865
853
  )
866
854
  end
867
855
 
856
+ def note_height
857
+ @note_height ||= begin
858
+ num_of_lines = @document.note.lines.count
859
+ (num_of_lines * 11)
860
+ end
861
+ end
862
+
868
863
  # Include page numbers if we got more than one page
869
864
  def build_footer
870
865
  @pdf.number_pages(
@@ -1,3 +1,3 @@
1
1
  module InvoicePrinter
2
- VERSION = '2.0.0.beta1'
2
+ VERSION = '2.1.0'
3
3
  end
data/test/api_test.rb CHANGED
@@ -31,7 +31,7 @@ class ApiTest < Minitest::Test
31
31
  end
32
32
 
33
33
  def test_print_with_valid_document
34
- invoice = InvoicePrinter::Document.new(default_document_params)
34
+ invoice = InvoicePrinter::Document.new(**default_document_params)
35
35
 
36
36
  json = {
37
37
  'document' => invoice.to_h,
@@ -60,7 +60,7 @@ class ApiTest < Minitest::Test
60
60
  end
61
61
 
62
62
  def test_render_with_valid_document
63
- invoice = InvoicePrinter::Document.new(default_document_params)
63
+ invoice = InvoicePrinter::Document.new(**default_document_params)
64
64
  output = InvoicePrinter.render(document: invoice)
65
65
 
66
66
  json = {
@@ -73,6 +73,6 @@ class ApiTest < Minitest::Test
73
73
  body = JSON.parse last_response.body
74
74
 
75
75
  assert last_response.ok?
76
- assert_equal body, { 'result' => 'ok', 'data' => Base64.encode64(output) }
76
+ assert_equal body, { 'result' => 'ok', 'data' => Base64.strict_encode64(output) }
77
77
  end
78
78
  end
@@ -4,7 +4,7 @@ class BackgroundTest < Minitest::Test
4
4
  include InvoicePrinterHelpers
5
5
 
6
6
  def setup
7
- @invoice = InvoicePrinter::Document.new(default_document_params)
7
+ @invoice = InvoicePrinter::Document.new(**default_document_params)
8
8
  end
9
9
 
10
10
  def test_background_render
data/test/cli_test.rb CHANGED
@@ -8,7 +8,7 @@ class CLITest < Minitest::Test
8
8
  t = Time.now.strftime("%Y%m%d")
9
9
  tmpname = "/tmp/invoice-#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-fd"
10
10
 
11
- @invoice = InvoicePrinter::Document.new(default_document_params)
11
+ @invoice = InvoicePrinter::Document.new(**default_document_params)
12
12
  @invoice_as_json = @invoice.to_json
13
13
  @output_path = tmpname
14
14
  end
@@ -8,7 +8,7 @@ class DatesBoxTest < Minitest::Test
8
8
  issue_date: '05/03/2016',
9
9
  due_date: '14/03/2016'
10
10
  )
11
- invoice = InvoicePrinter::Document.new(params)
11
+ invoice = InvoicePrinter::Document.new(**params)
12
12
  rendered_pdf = InvoicePrinter.render(document: invoice)
13
13
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
14
14
 
@@ -21,7 +21,7 @@ class DatesBoxTest < Minitest::Test
21
21
  issue_date: '05/03/2016',
22
22
  due_date: ''
23
23
  )
24
- invoice = InvoicePrinter::Document.new(params)
24
+ invoice = InvoicePrinter::Document.new(**params)
25
25
  rendered_pdf = InvoicePrinter.render(document: invoice)
26
26
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
27
27
 
@@ -34,7 +34,7 @@ class DatesBoxTest < Minitest::Test
34
34
  issue_date: nil,
35
35
  due_date: '05/03/2016'
36
36
  )
37
- invoice = InvoicePrinter::Document.new(params)
37
+ invoice = InvoicePrinter::Document.new(**params)
38
38
  rendered_pdf = InvoicePrinter.render(document: invoice)
39
39
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
40
40
 
@@ -47,7 +47,7 @@ class DatesBoxTest < Minitest::Test
47
47
  issue_date: '',
48
48
  due_date: nil
49
49
  )
50
- invoice = InvoicePrinter::Document.new(params)
50
+ invoice = InvoicePrinter::Document.new(**params)
51
51
  rendered_pdf = InvoicePrinter.render(document: invoice)
52
52
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
53
53
 
@@ -11,7 +11,7 @@ class ExamplesTest < Minitest::Test
11
11
  end
12
12
 
13
13
  def teardown
14
- FileUtils.rm_rf @test_dir if File.exists?(@test_dir)
14
+ FileUtils.rm_rf @test_dir if File.exist?(@test_dir)
15
15
  end
16
16
 
17
17
  # 1, copy example to the test directory
data/test/inputs_test.rb CHANGED
@@ -28,12 +28,12 @@ class InputsTest < Minitest::Test
28
28
  )
29
29
 
30
30
  # No exceptions should be raised
31
- invoice = InvoicePrinter::Document.new(params)
31
+ invoice = InvoicePrinter::Document.new(**params)
32
32
  InvoicePrinter.render(document: invoice)
33
33
  end
34
34
 
35
35
  def test_missing_font_raises_an_exception
36
- invoice = InvoicePrinter::Document.new(default_document_params)
36
+ invoice = InvoicePrinter::Document.new(**default_document_params)
37
37
 
38
38
  assert_raises(InvoicePrinter::PDFDocument::FontFileNotFound) do
39
39
  InvoicePrinter.render(document: invoice, font: 'missing.font')
@@ -41,7 +41,7 @@ class InputsTest < Minitest::Test
41
41
  end
42
42
 
43
43
  def test_missing_logo_raises_an_exception
44
- invoice = InvoicePrinter::Document.new(default_document_params)
44
+ invoice = InvoicePrinter::Document.new(**default_document_params)
45
45
 
46
46
  assert_raises(InvoicePrinter::PDFDocument::LogoFileNotFound) do
47
47
  InvoicePrinter.render(document: invoice, logo: 'missing.png')
@@ -49,7 +49,7 @@ class InputsTest < Minitest::Test
49
49
  end
50
50
 
51
51
  def test_missing_stamp_raises_an_exception
52
- invoice = InvoicePrinter::Document.new(default_document_params)
52
+ invoice = InvoicePrinter::Document.new(**default_document_params)
53
53
 
54
54
  assert_raises(InvoicePrinter::PDFDocument::StampFileNotFound) do
55
55
  InvoicePrinter.render(document: invoice, stamp: 'missing.png')
@@ -4,7 +4,7 @@ class InvoicePrinterTest < Minitest::Test
4
4
  include InvoicePrinterHelpers
5
5
 
6
6
  def test_render_document
7
- invoice = InvoicePrinter::Document.new(default_document_params)
7
+ invoice = InvoicePrinter::Document.new(**default_document_params)
8
8
  rendered_pdf = InvoicePrinter.render(document: invoice)
9
9
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
10
10
  strings = InvoicePrinter::PDFDocument.new(document: invoice).to_a
@@ -13,7 +13,7 @@ class InvoicePrinterTest < Minitest::Test
13
13
  end
14
14
 
15
15
  def test_render_document_from_json
16
- invoice = InvoicePrinter::Document.new(default_document_params)
16
+ invoice = InvoicePrinter::Document.new(**default_document_params)
17
17
  invoice_json = JSON.parse(invoice.to_json)
18
18
  invoice_from_json = InvoicePrinter::Document.from_json(invoice_json)
19
19
  rendered_pdf = InvoicePrinter.render(document: invoice_from_json)
@@ -41,10 +41,10 @@ class ItemsTableTest < Minitest::Test
41
41
 
42
42
  def invoice_without_item_column(column)
43
43
  InvoicePrinter::Document.new(
44
- default_document_params.merge(
44
+ **default_document_params.merge(
45
45
  items: [
46
46
  InvoicePrinter::Document::Item.new(
47
- default_document_item_params.merge("#{column}": nil)
47
+ **default_document_item_params.merge("#{column}": nil)
48
48
  )
49
49
  ]
50
50
  )
data/test/labels_test.rb CHANGED
@@ -6,7 +6,7 @@ class LabelsTest < Minitest::Test
6
6
  def test_setting_global_labels
7
7
  labels = { provider: 'Default Provider', purchaser: 'Default Purchaser' }
8
8
  InvoicePrinter.labels = labels
9
- invoice = InvoicePrinter::Document.new(default_document_params)
9
+ invoice = InvoicePrinter::Document.new(**default_document_params)
10
10
  rendered_pdf = InvoicePrinter.render(document: invoice)
11
11
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
12
12
 
@@ -16,7 +16,7 @@ class LabelsTest < Minitest::Test
16
16
 
17
17
  def test_setting_instant_labels
18
18
  labels = { provider: 'Current Provider', purchaser: 'Current Purchaser' }
19
- invoice = InvoicePrinter::Document.new(default_document_params)
19
+ invoice = InvoicePrinter::Document.new(**default_document_params)
20
20
  rendered_pdf = InvoicePrinter.render(document: invoice, labels: labels)
21
21
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
22
22
 
data/test/notes_test.rb CHANGED
@@ -7,7 +7,7 @@ class NotesTest < Minitest::Test
7
7
  params = default_document_params.merge(
8
8
  note: 'ABC is a registered trademark.'
9
9
  )
10
- invoice = InvoicePrinter::Document.new(params)
10
+ invoice = InvoicePrinter::Document.new(**params)
11
11
  rendered_pdf = InvoicePrinter.render(document: invoice)
12
12
  pdf_analysis = PDF::Inspector::Text.analyze(rendered_pdf)
13
13