hexapdf-extras 1.1.1 → 1.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e7fe626cf7fd851cd203b739c69bdd193b5debffcd129c656d59b51c2d326ad
4
- data.tar.gz: 588a1a744477c437035ca66fd187f4c3563b135946efb8a21d5f73e77f15d238
3
+ metadata.gz: 9c7f4718bb802b0d1dd228a9fa22fb44ed10dd95402d72c664d937dc8368c5c2
4
+ data.tar.gz: 7a8111bdb4d323ae5ca910bb215c6aacdbb0799ea05a264a5d4d459a7b21c67c
5
5
  SHA512:
6
- metadata.gz: fb195eef642905d2797b96c545f63eaee7edff117982e16e8c3965d05c9abdf537331d35cfa09df6d9aebac3d03e4a28dbb921714bc3a4968984789f2f4548ea
7
- data.tar.gz: 8682207937162bef5c86ca5f0f061dbb25469b989e65fa51dc4fbe7f3bc75739cc382911efee4c954e30a14650322bd870aa308e56436a1e18a665e0f4174a9d
6
+ metadata.gz: bdf857f06fc000adb0a716bcb4d039b314a0acd3f424a2e39f370bf61851741467f4b3e6319b02d7d0f86d95179ab399ad88cdf0ba95f2202efbae9e422c3ef1
7
+ data.tar.gz: a9ba5813153564d05eff9c10e538a1793c3c6f469025969d50e17ffeb2755e64c7b2c57d88f4a0acb18ef1dfdc853f22d8238fb559e665261134bae5c44ff850
data/README.rdoc CHANGED
@@ -36,3 +36,37 @@ for details.
36
36
 
37
37
  Note: There was a {bug in poppler}[https://gitlab.freedesktop.org/poppler/poppler/-/issues/1281]
38
38
  (already fixed) which leads to invalid rendering in Okular (as of 2022-08-06).
39
+
40
+
41
+ === Swiss QR-bill generator
42
+
43
+ This extension provides a box class for the document layouting facilities of HexaPDF to easily
44
+ create a {Swiss QR-bill}[https://www.six-group.com/en/products-services/banking-services/payment-standardization/standards/qr-bill.html]:
45
+
46
+ HexaPDF::Composer.create("sample-qr-bill.pdf", margin: 0) do |composer|
47
+ data = {
48
+ lang: :de,
49
+ creditor: {
50
+ iban: "CH44 3199 9123 0008 8901 2",
51
+ name: "Max Muster & Söhne",
52
+ address_line1: "Musterstrasse",
53
+ address_line2: "123",
54
+ postal_code: "8000",
55
+ town: "Seldwyla",
56
+ country: "CH",
57
+ },
58
+ debtor: {
59
+ address_type: :combined,
60
+ name: "Simon Muster",
61
+ address_line1: "Musterstrasse 1",
62
+ address_line2: "8000 Seldwyla",
63
+ country: "CH"
64
+ },
65
+ amount: 2500.25,
66
+ currency: 'CHF',
67
+ }
68
+ composer.swiss_qr_bill(data: data, style: {valign: :bottom})
69
+ end
70
+
71
+ See {HexaPDF::Extras::Layout::SwissQRBill}[https://hexapdf-extras.gettalong.org/api/HexaPDF/Extras/Layout/SwissQRBill.html]
72
+ for details.
@@ -66,8 +66,8 @@ module HexaPDF
66
66
  # following elements:
67
67
  #
68
68
  # :iban::
69
- # (required) The IBAN of the creditor (21 characters, no spaces, only IBANs for CH or
70
- # LI). Note that the IBAN is not checked for validity.
69
+ # (required) The IBAN of the creditor (21 characters, only IBANs for CH or LI). The
70
+ # IBAN is only validated with respect to its check digits.
71
71
  #
72
72
  # :name::
73
73
  # (required) The name of the creditor (maximum 70 characters).
@@ -158,7 +158,7 @@ module HexaPDF
158
158
  # amount: 2500.25,
159
159
  # currency: 'CHF',
160
160
  # }
161
- # composer.swiss_qr_bill(data: data, valign: :bottom)
161
+ # composer.swiss_qr_bill(data: data, style: {valign: :bottom})
162
162
  # end
163
163
  #
164
164
  # == References
@@ -262,6 +262,25 @@ module HexaPDF
262
262
  raise Error, "Data field :amount must be between 0.01 and 999_999_999.99"
263
263
  end
264
264
 
265
+ if !@data[:creditor]
266
+ raise Error, "Data field :creditor is missing"
267
+ end
268
+
269
+ value = @data[:creditor][:iban]
270
+ if !value
271
+ raise Error, "Data field :iban of :creditor is missing"
272
+ end
273
+ value.gsub!(/\s+/, '')
274
+ value.upcase!
275
+ if value.size != 21
276
+ raise Error, "Data field :iban of :creditor must contain exactly 21 characters"
277
+ end
278
+ # https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
279
+ result = "#{value[4..-1]}#{value[0, 4]}".gsub(/[A-Z]/) {|c| c.ord - 55 }.to_i % 97
280
+ unless result == 1
281
+ raise Error, "Data field :iban of :creditor has invalid check digits"
282
+ end
283
+
265
284
  validate_address = lambda do |hash|
266
285
  hash[:address_type] ||= :structured
267
286
  if hash[:address_type] != :structured && hash[:address_type] != :combined
@@ -452,7 +471,7 @@ module HexaPDF
452
471
  col.text(text('Receipt'), height: 7.mm, style: styles[:section_heading])
453
472
  col.container(height: 56.mm) do |info|
454
473
  info.text(text('Account / Payable to'), style: styles[:receipt_heading])
455
- info.text("#{@data[:creditor][:iban]}\n#{address(@data[:creditor])}", style: styles[:receipt_value])
474
+ info.text("#{formatted_iban}\n#{address(@data[:creditor])}", style: styles[:receipt_value])
456
475
 
457
476
  if @data[:reference_type] != 'NON'
458
477
  info.text(text('Reference'), style: styles[:receipt_heading])
@@ -506,11 +525,11 @@ module HexaPDF
506
525
  end
507
526
  col.container(height: 85.mm) do |info|
508
527
  info.text(text('Account / Payable to'), style: styles[:payment_heading])
509
- info.text("#{@data[:creditor][:iban]}\n#{address(@data[:creditor])}", style: styles[:payment_value])
528
+ info.text("#{formatted_iban}\n#{address(@data[:creditor])}", style: styles[:payment_value])
510
529
 
511
530
  if @data[:reference_type] != 'NON'
512
531
  info.text(text('Reference'), style: styles[:payment_heading])
513
- info.text(@data[:reference], style: styles[:payment_value])
532
+ info.text(formatted_reference, style: styles[:payment_value])
514
533
  end
515
534
 
516
535
  if @data[:message] || @data[:billing_information]
@@ -563,6 +582,11 @@ module HexaPDF
563
582
  TEXT_LITERALS.dig(@data[:lang], str) || str
564
583
  end
565
584
 
585
+ # Returns the formatted IBAN.
586
+ def formatted_iban
587
+ @data[:creditor][:iban].gsub(/(.{4})/, '\1 ')
588
+ end
589
+
566
590
  # Returns a string containing the formatted address for output using the provided data.
567
591
  def address(data)
568
592
  result = +''
@@ -584,6 +608,15 @@ module HexaPDF
584
608
  a.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1 ") << '.' << b
585
609
  end
586
610
 
611
+ # Returns the reference field correctly formatted.
612
+ def formatted_reference
613
+ if @data[:reference_type] == 'QRR'
614
+ "#{@data[:reference][0, 2]} #{@data[:reference][2..-1].gsub(/(.{5})/, '\1 ').strip}"
615
+ else
616
+ @data[:reference].gsub(/(.{4})/, '\1 ').strip
617
+ end
618
+ end
619
+
587
620
  # Creates the content of the QR code using the information provided in #data.
588
621
  def qr_code_data
589
622
  qr_code_data = []
@@ -2,6 +2,6 @@
2
2
 
3
3
  module HexaPDF
4
4
  module Extras
5
- VERSION = '1.1.1'
5
+ VERSION = '1.1.2'
6
6
  end
7
7
  end
@@ -13,7 +13,7 @@ describe HexaPDF::Extras::Layout::SwissQRBill do
13
13
  def data
14
14
  @data ||= {
15
15
  creditor: {
16
- iban: "CH44 3199 9123 0008 8901 2",
16
+ iban: "CH4431999123000889012",
17
17
  name: "Max Muster & Söhne",
18
18
  address_line1: "Musterstrasse",
19
19
  address_line2: "123",
@@ -64,6 +64,22 @@ describe HexaPDF::Extras::Layout::SwissQRBill do
64
64
  assert_equal('NICHT ZUR ZAHLUNG VERWENDEN', create_box(data).data[:message])
65
65
  end
66
66
 
67
+ it "ensures the creditor value exists" do
68
+ data.delete(:creditor)
69
+ assert_invalid_data(/:creditor is missing/)
70
+ end
71
+
72
+ it "ensures a correct iban value in the creditor field" do
73
+ data[:creditor].delete(:iban)
74
+ assert_invalid_data(/:iban of :creditor is missing/)
75
+ data[:creditor][:iban] = 'CH44 319 39912300088901 2'
76
+ assert_invalid_data(/:iban of :creditor.*21/)
77
+ data[:creditor][:iban] = 'CH4431999123000889013'
78
+ assert_invalid_data(/:iban of :creditor.*invalid check digits/)
79
+ data[:creditor][:iban] = 'CH4431999123000889012'
80
+ assert(create_box(data))
81
+ end
82
+
67
83
  it "sets the address type to structured by default" do
68
84
  assert_equal(:structured, create_box(data, width: 10, height: 15).data[:creditor][:address_type])
69
85
  end
@@ -220,6 +236,8 @@ describe HexaPDF::Extras::Layout::SwissQRBill do
220
236
  it "works with no amount and no debtor" do
221
237
  data.delete(:debtor)
222
238
  data.delete(:amount)
239
+ data[:reference_type] = 'SCOR'
240
+ data[:reference] = 'RF48 5000056789012345'
223
241
  assert(@composer.box(:swiss_qr_bill, data: data))
224
242
  end
225
243
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf-extras
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner