invoice_printer 2.0.0.alpha1 → 2.1.0.rc1

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.
@@ -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.alpha1'
2
+ VERSION = '2.1.0.rc1'
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