hexapdf-extras 1.1.1 → 1.1.2

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
  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