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 +4 -4
- data/README.rdoc +34 -0
- data/lib/hexapdf/extras/layout/swiss_qr_bill.rb +39 -6
- data/lib/hexapdf/extras/version.rb +1 -1
- data/test/hexapdf/extras/layout/test_swiss_qr_bill.rb +19 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c7f4718bb802b0d1dd228a9fa22fb44ed10dd95402d72c664d937dc8368c5c2
|
4
|
+
data.tar.gz: 7a8111bdb4d323ae5ca910bb215c6aacdbb0799ea05a264a5d4d459a7b21c67c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,
|
70
|
-
#
|
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("#{
|
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("#{
|
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(
|
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 = []
|
@@ -13,7 +13,7 @@ describe HexaPDF::Extras::Layout::SwissQRBill do
|
|
13
13
|
def data
|
14
14
|
@data ||= {
|
15
15
|
creditor: {
|
16
|
-
iban: "
|
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
|
|