prawn-swiss_qr_bill 0.4.1
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 +7 -0
- data/Gemfile +5 -0
- data/README.md +124 -0
- data/config/locales/de.yml +15 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/fr.yml +15 -0
- data/config/locales/it.yml +15 -0
- data/lib/prawn/swiss_qr_bill/bill.rb +20 -0
- data/lib/prawn/swiss_qr_bill/corner_box.rb +79 -0
- data/lib/prawn/swiss_qr_bill/cutting_lines.rb +74 -0
- data/lib/prawn/swiss_qr_bill/debug_section.rb +140 -0
- data/lib/prawn/swiss_qr_bill/extension.rb +18 -0
- data/lib/prawn/swiss_qr_bill/helpers/box_helper.rb +14 -0
- data/lib/prawn/swiss_qr_bill/helpers/number_helper.rb +16 -0
- data/lib/prawn/swiss_qr_bill/iban.rb +84 -0
- data/lib/prawn/swiss_qr_bill/images/scissor.png +0 -0
- data/lib/prawn/swiss_qr_bill/images/swiss_cross.png +0 -0
- data/lib/prawn/swiss_qr_bill/padded_box.rb +52 -0
- data/lib/prawn/swiss_qr_bill/qr/data.rb +105 -0
- data/lib/prawn/swiss_qr_bill/sections/payment_amount.rb +88 -0
- data/lib/prawn/swiss_qr_bill/sections/payment_further_information.rb +14 -0
- data/lib/prawn/swiss_qr_bill/sections/payment_information.rb +59 -0
- data/lib/prawn/swiss_qr_bill/sections/payment_title.rb +18 -0
- data/lib/prawn/swiss_qr_bill/sections/qr_code.rb +102 -0
- data/lib/prawn/swiss_qr_bill/sections/receipt_acceptance.rb +18 -0
- data/lib/prawn/swiss_qr_bill/sections/receipt_amount.rb +86 -0
- data/lib/prawn/swiss_qr_bill/sections/receipt_information.rb +51 -0
- data/lib/prawn/swiss_qr_bill/sections/receipt_title.rb +18 -0
- data/lib/prawn/swiss_qr_bill/sections/section.rb +88 -0
- data/lib/prawn/swiss_qr_bill/sections.rb +29 -0
- data/lib/prawn/swiss_qr_bill/specifications.rb +78 -0
- data/lib/prawn/swiss_qr_bill/specs.yml +106 -0
- data/lib/prawn/swiss_qr_bill/version.rb +7 -0
- data/lib/prawn/swiss_qr_bill.rb +43 -0
- data/prawn-swiss_qr_bill.gemspec +40 -0
- metadata +218 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: faa2f8fb8c38ea2681890f7573bb42ab424cadb413d57699e0e64145088c8911
|
4
|
+
data.tar.gz: 2fa0db096bc0d9fb4060858dd0fe88ba187c20a54ae36babcb66848c6a102a33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e1d30550f53e1ed3dc74a0256d826a25fa2290f06a9b4e282e8529dabeaf334907b87613e6babd52667ee3cf248098464dd9381743e4883014a7a85c8783c97d
|
7
|
+
data.tar.gz: 536068e41ad5d54e70dcebe9deeeb19a1984eb52b4bee5e020e5644bbdcf4e7c66453b449ae3e811b523f37dc2b3fc1a2dcaacd51c072562a1628b0b3ef509ea
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# Prawn::SwissQRBill
|
2
|
+
|
3
|
+
A Ruby library for creating Swiss QR-bill payment slips inside a PDF. It is
|
4
|
+
built as a [Prawn](https://github.com/prawnpdf/prawn) extension.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add the following line to your `Gemfile`:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'prawn-swiss_qr_bill'
|
12
|
+
```
|
13
|
+
|
14
|
+
or install it manually:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
gem install prawn-swiss_qr_bill
|
18
|
+
```
|
19
|
+
|
20
|
+
## Basic Usage
|
21
|
+
|
22
|
+
Define the relevant information for the Swiss QR-bill and render it inside the Prawn block:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
require 'prawn'
|
26
|
+
require 'prawn/swiss_qr_bill'
|
27
|
+
|
28
|
+
@qr_data = {
|
29
|
+
creditor: {
|
30
|
+
iban: 'CH08 3080 8004 1110 4136 9',
|
31
|
+
address: {
|
32
|
+
name: 'Mischa Schindowski',
|
33
|
+
line1: 'Schybenächerweg 553',
|
34
|
+
line2: '5324 Full-Reuenthal',
|
35
|
+
country: 'CH'
|
36
|
+
}
|
37
|
+
},
|
38
|
+
amount: 9.90,
|
39
|
+
currency: 'CHF',
|
40
|
+
reference: '00 00000 00000 02202 20202 99991',
|
41
|
+
reference_type: 'QRR'
|
42
|
+
}
|
43
|
+
|
44
|
+
Prawn::Document.generate('output.pdf', page_size: 'A4') do
|
45
|
+
text 'A Swiss QR bill'
|
46
|
+
|
47
|
+
swiss_qr_bill(@qr_data)
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
This will render the Swiss QR-bill at the bottom of the page:
|
52
|
+
|
53
|
+

|
54
|
+
|
55
|
+
### Options
|
56
|
+
|
57
|
+
The following options are available:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# *: mandatory
|
61
|
+
@qr_data = {
|
62
|
+
creditor: {
|
63
|
+
iban: '<iban>', # *
|
64
|
+
address: { # *
|
65
|
+
type: '<K|S>', # default: K
|
66
|
+
name: '<name>', # *
|
67
|
+
line1: '<street> <nr>', # *
|
68
|
+
line2: '<line 2>',
|
69
|
+
postal_code: '<postal code>',
|
70
|
+
city: '<city>',
|
71
|
+
country: '<country>' # *
|
72
|
+
}
|
73
|
+
},
|
74
|
+
debtor: {
|
75
|
+
address: {
|
76
|
+
type: '<K|S>', # default: nil
|
77
|
+
name: '<name>',
|
78
|
+
line1: '<street> <nr>',
|
79
|
+
line2: '<line 2>',
|
80
|
+
postal_code: '<postal_code>',
|
81
|
+
city: '<city>',
|
82
|
+
country: '<country>'
|
83
|
+
}
|
84
|
+
},
|
85
|
+
amount: 9.90,
|
86
|
+
currency: '<CHF|EUR>', # *
|
87
|
+
reference: '<ref nr>',
|
88
|
+
reference_type: '<QRR|SCOR|NON>' # default: NON
|
89
|
+
}
|
90
|
+
```
|
91
|
+
|
92
|
+
If `debtor` or `amount` amount is not given, a box will be printed.
|
93
|
+
|
94
|
+
## Important
|
95
|
+
|
96
|
+
This library does not validate (yet) IBAN, reference or the given QR data.
|
97
|
+
Please refer to the implementation guidelines and the Swiss QR-bill validaton
|
98
|
+
portal by SIX below.
|
99
|
+
|
100
|
+
## Contributing
|
101
|
+
|
102
|
+
If you miss a feature or you've found a bug, please [open a GitHub issue](https://github.com/mitosch/prawn-swiss_qr_bill/issues).
|
103
|
+
|
104
|
+
Pull requests are highly welcome:
|
105
|
+
|
106
|
+
* Fork the project
|
107
|
+
* Make your changes
|
108
|
+
* Send the pull request
|
109
|
+
|
110
|
+
## Authors
|
111
|
+
|
112
|
+
Original author: Mischa Schindowski
|
113
|
+
|
114
|
+
## Resources
|
115
|
+
|
116
|
+
* [Prawn](https://github.com/prawnpdf/prawn): Fast, Nimble PDF Generation For Ruby
|
117
|
+
* [Swiss QR-bill Validation Portal](https://validation.iso-payments.ch/qrrechnung)
|
118
|
+
* [Swiss Payment Standards](https://www.paymentstandards.ch):
|
119
|
+
* [Style Guide QR-bill](https://www.paymentstandards.ch/dam/downloads/style-guide-en.pdf)
|
120
|
+
* [Implementation Guidelines QR-bill](https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-en.pdf)
|
121
|
+
|
122
|
+
## Copyright
|
123
|
+
|
124
|
+
MIT License (http://www.opensource.org/licenses/mit-license.html)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
de:
|
2
|
+
swiss_qr_bill:
|
3
|
+
payment: Zahlteil
|
4
|
+
creditor: Konto / Zahlbar an
|
5
|
+
reference: Referenz
|
6
|
+
additional_info: Zusätzliche Informationen
|
7
|
+
further_info: Weitere Informationen
|
8
|
+
currency: Währung
|
9
|
+
amount: Betrag
|
10
|
+
receipt: Empfangsschein
|
11
|
+
acceptance: Annahmestelle
|
12
|
+
separate: Vor der Einzahlung abzutrennen
|
13
|
+
debtor: Zahlbar durch
|
14
|
+
debtor_blank: Zahlbar durch (Name/Adresse)
|
15
|
+
debtor_favour: Zugunsten
|
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
swiss_qr_bill:
|
3
|
+
payment: Payment part
|
4
|
+
creditor: Account / Payable to
|
5
|
+
reference: Reference
|
6
|
+
additional_info: Additional information
|
7
|
+
further_info: Further information
|
8
|
+
currency: Currency
|
9
|
+
amount: Amount
|
10
|
+
receipt: Receipt
|
11
|
+
acceptance: Acceptance point
|
12
|
+
separate: Separate before paying in
|
13
|
+
debtor: Payable by
|
14
|
+
debtor_blank: Payable by (name/address)
|
15
|
+
debtor_favour: In favour of
|
@@ -0,0 +1,15 @@
|
|
1
|
+
fr:
|
2
|
+
swiss_qr_bill:
|
3
|
+
payment: Section paiement
|
4
|
+
creditor: Compte / Payable à
|
5
|
+
reference: Référence
|
6
|
+
additional_info: Informations supplémentaires
|
7
|
+
further_info: Informations additionnelles
|
8
|
+
currency: Monnaie
|
9
|
+
amount: Montant
|
10
|
+
receipt: Récépissé
|
11
|
+
acceptance: Point de dépôt
|
12
|
+
separate: A détacher avant le versement
|
13
|
+
debtor: Payable par
|
14
|
+
debtor_blank: Payable par (nom/adresse)
|
15
|
+
debtor_favour: En faveur de
|
@@ -0,0 +1,15 @@
|
|
1
|
+
it:
|
2
|
+
swiss_qr_bill:
|
3
|
+
payment: Sezione pagamento
|
4
|
+
creditor: Conto / Pagabile a
|
5
|
+
reference: Riferimento
|
6
|
+
additional_info: Informazioni supplementari
|
7
|
+
further_info: Informazioni aggiuntive
|
8
|
+
currency: Valuta
|
9
|
+
amount: Importo
|
10
|
+
receipt: Ricevuta
|
11
|
+
acceptance: Punto di accettazione
|
12
|
+
separate: Da staccare prima del versamento
|
13
|
+
debtor: Pagabile da
|
14
|
+
debtor_blank: Pagabile da (nome/indirizzo)
|
15
|
+
debtor_favour: A favore di
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
# Bill renders the Swiss QR-bill at the bottom of a page
|
6
|
+
class Bill
|
7
|
+
def initialize(document, data)
|
8
|
+
@doc = document
|
9
|
+
@data = data
|
10
|
+
end
|
11
|
+
|
12
|
+
def draw
|
13
|
+
@doc.canvas do
|
14
|
+
Sections.draw_all(@doc, @data)
|
15
|
+
CuttingLines.new(@doc).draw
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
# Draws a box with corner ticks
|
6
|
+
class CornerBox
|
7
|
+
TICK_SIZE = 3.mm
|
8
|
+
|
9
|
+
LINE_WIDTH = 0.75
|
10
|
+
|
11
|
+
def initialize(document, point, options)
|
12
|
+
unless options.key?(:width) && options.key?(:height)
|
13
|
+
raise ArgumentError,
|
14
|
+
'corner_box needs the :width and :height option to be set'
|
15
|
+
end
|
16
|
+
|
17
|
+
@document = document
|
18
|
+
@point = point
|
19
|
+
@width = options[:width]
|
20
|
+
@height = options[:height]
|
21
|
+
|
22
|
+
@brain = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def draw
|
26
|
+
set_styles
|
27
|
+
draw_lines
|
28
|
+
reset_styles
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def set_styles
|
34
|
+
@brain[:line_width] = @document.line_width
|
35
|
+
@document.line_width = LINE_WIDTH
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset_styles
|
39
|
+
@document.line_width = @brain[:line_width]
|
40
|
+
end
|
41
|
+
|
42
|
+
def draw_lines
|
43
|
+
point_x, point_y = @point
|
44
|
+
|
45
|
+
@document.stroke do
|
46
|
+
draw_horizontal_lines(point_x, point_y)
|
47
|
+
draw_vertical_lines(point_x, point_y)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def draw_horizontal_lines(point_x, point_y)
|
52
|
+
# upper lines
|
53
|
+
@document.horizontal_line point_x, point_x + TICK_SIZE,
|
54
|
+
at: point_y
|
55
|
+
@document.horizontal_line point_x + @width, point_x + @width - TICK_SIZE,
|
56
|
+
at: point_y
|
57
|
+
# lower lines
|
58
|
+
@document.horizontal_line point_x, point_x + TICK_SIZE,
|
59
|
+
at: point_y - @height
|
60
|
+
@document.horizontal_line point_x + @width, point_x + @width - TICK_SIZE,
|
61
|
+
at: point_y - @height
|
62
|
+
end
|
63
|
+
|
64
|
+
def draw_vertical_lines(point_x, point_y)
|
65
|
+
# upper lines
|
66
|
+
@document.vertical_line point_y, point_y - TICK_SIZE,
|
67
|
+
at: point_x
|
68
|
+
@document.vertical_line point_y, point_y - TICK_SIZE,
|
69
|
+
at: point_x + @width
|
70
|
+
|
71
|
+
# lower lines
|
72
|
+
@document.vertical_line point_y - @height, point_y - @height + TICK_SIZE,
|
73
|
+
at: point_x
|
74
|
+
@document.vertical_line point_y - @height, point_y - @height + TICK_SIZE,
|
75
|
+
at: point_x + @width
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
# Horizontal and vertical cutting lines with a scissor symbol
|
6
|
+
class CuttingLines
|
7
|
+
SCISSOR_FILE = File.expand_path("#{__dir__}/images/scissor.png")
|
8
|
+
|
9
|
+
SCISSOR_WIDTH = 5.mm
|
10
|
+
SCISSOR_HEIGHT = 3.mm
|
11
|
+
|
12
|
+
PAD_LEFT = 5.mm
|
13
|
+
PAD_TOP = 1.mm
|
14
|
+
|
15
|
+
attr_reader :doc, :receipt_width, :receipt_height
|
16
|
+
|
17
|
+
def initialize(document)
|
18
|
+
@doc = document
|
19
|
+
|
20
|
+
@brain = {}
|
21
|
+
|
22
|
+
load_specs
|
23
|
+
end
|
24
|
+
|
25
|
+
def draw
|
26
|
+
set_styles
|
27
|
+
|
28
|
+
draw_strokes
|
29
|
+
draw_scissors
|
30
|
+
|
31
|
+
reset_styles
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def load_specs
|
37
|
+
specs = Specifications.new
|
38
|
+
@receipt_height = specs.get('receipt.height').mm
|
39
|
+
@receipt_width = specs.get('receipt.width').mm
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_styles
|
43
|
+
@brain[:line_width] = doc.line_width
|
44
|
+
|
45
|
+
doc.line_width 0.5
|
46
|
+
doc.dash 2, space: 2
|
47
|
+
end
|
48
|
+
|
49
|
+
def draw_strokes
|
50
|
+
doc.stroke { doc.line [0, receipt_height], [doc.bounds.right, receipt_height] }
|
51
|
+
doc.stroke { doc.line [receipt_width, receipt_height], [receipt_width, doc.bounds.bottom] }
|
52
|
+
end
|
53
|
+
|
54
|
+
def draw_scissors
|
55
|
+
doc.bounding_box([doc.bounds.left + PAD_LEFT, receipt_height + (SCISSOR_HEIGHT / 2)],
|
56
|
+
width: SCISSOR_WIDTH, height: SCISSOR_HEIGHT) do
|
57
|
+
doc.image SCISSOR_FILE, width: SCISSOR_WIDTH
|
58
|
+
end
|
59
|
+
|
60
|
+
doc.bounding_box([receipt_width - (SCISSOR_HEIGHT / 2), receipt_height - PAD_TOP],
|
61
|
+
width: SCISSOR_WIDTH, height: SCISSOR_HEIGHT) do
|
62
|
+
doc.rotate(270, origin: [0, 0]) do
|
63
|
+
doc.image SCISSOR_FILE, width: SCISSOR_WIDTH
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def reset_styles
|
69
|
+
doc.line_width = @brain[:line_width]
|
70
|
+
doc.undash
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
# Draws a blue debug section.
|
6
|
+
#
|
7
|
+
# Reference:
|
8
|
+
# https://www.paymentstandards.ch/dam/downloads/style-guide-en.pdf
|
9
|
+
#
|
10
|
+
# OPTIMIZE: move several general styling functions to helpers (bb-helper)
|
11
|
+
class DebugSection
|
12
|
+
SECTIONS = [
|
13
|
+
'receipt',
|
14
|
+
'receipt.title',
|
15
|
+
'receipt.information',
|
16
|
+
'receipt.amount',
|
17
|
+
'receipt.acceptance',
|
18
|
+
'payment',
|
19
|
+
'payment.title',
|
20
|
+
'payment.information',
|
21
|
+
'payment.qr_code',
|
22
|
+
'payment.qr_cross',
|
23
|
+
'payment.amount',
|
24
|
+
'payment.further_information'
|
25
|
+
].freeze
|
26
|
+
|
27
|
+
attr_reader :doc, :properties
|
28
|
+
|
29
|
+
def initialize(document)
|
30
|
+
@doc = document
|
31
|
+
|
32
|
+
@brain = { font: {}, border: { color: nil, width: nil } }
|
33
|
+
|
34
|
+
@spec = Prawn::SwissQRBill::Specifications.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw
|
38
|
+
SECTIONS.each do |section|
|
39
|
+
name = @spec.get(section)['name']
|
40
|
+
specs = @spec.get_specs(section)
|
41
|
+
point = specs.point
|
42
|
+
options = { width: specs.width, height: specs.height }.merge(
|
43
|
+
text: name,
|
44
|
+
background: false, border: true, font_size: 10
|
45
|
+
)
|
46
|
+
|
47
|
+
draw_debug_box(point, options)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Draws a box like in the style guide.
|
54
|
+
#
|
55
|
+
# NOTE: Background removed for simplicity, color was: D4EDFC
|
56
|
+
def draw_debug_box(*args)
|
57
|
+
position = args[0]
|
58
|
+
text = args[1].delete(:text)
|
59
|
+
border_style = { color: '71C4E9', width: 0.75 } if args[1][:border]
|
60
|
+
debug_box_opts = args[1].merge(padding: 1.mm,
|
61
|
+
border: border_style,
|
62
|
+
font: { size: args[1][:font_size] })
|
63
|
+
|
64
|
+
draw_padded_box(position, debug_box_opts) do
|
65
|
+
doc.text text, color: '71C4E9'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def draw_padded_box(*args, &block)
|
70
|
+
padding = args[1].delete(:padding) || 0
|
71
|
+
|
72
|
+
doc.bounding_box(*args) do
|
73
|
+
height = doc.bounds.height
|
74
|
+
width = doc.bounds.width
|
75
|
+
|
76
|
+
ensure_styles(args[1])
|
77
|
+
|
78
|
+
doc.bounding_box([padding, height - padding],
|
79
|
+
width: width - (2 * padding),
|
80
|
+
height: height - (2 * padding)) { yield block }
|
81
|
+
end
|
82
|
+
|
83
|
+
reset_styles
|
84
|
+
end
|
85
|
+
|
86
|
+
# ensures setting the styles by meaningful options:
|
87
|
+
#
|
88
|
+
# {
|
89
|
+
# border: { color: '123456', width: 2 },
|
90
|
+
# font: { size: 10 }
|
91
|
+
# }
|
92
|
+
def ensure_styles(opts)
|
93
|
+
stroke_style(opts[:border])
|
94
|
+
font_style(opts[:font])
|
95
|
+
end
|
96
|
+
|
97
|
+
def stroke_style(opts)
|
98
|
+
return unless opts
|
99
|
+
|
100
|
+
remember_style(:border)
|
101
|
+
|
102
|
+
doc.line_width opts[:width]
|
103
|
+
doc.stroke_color opts[:color]
|
104
|
+
doc.stroke_bounds
|
105
|
+
end
|
106
|
+
|
107
|
+
def font_style(opts)
|
108
|
+
return unless opts
|
109
|
+
|
110
|
+
remember_style(:font)
|
111
|
+
doc.font_size opts[:size]
|
112
|
+
end
|
113
|
+
|
114
|
+
def remember_style(style_type)
|
115
|
+
case style_type
|
116
|
+
when :font
|
117
|
+
@brain[:font][:size] = doc.font_size
|
118
|
+
when :border
|
119
|
+
@brain[:border][:color] = doc.line_width
|
120
|
+
@brain[:border][:width] = doc.stroke_color
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def reset_styles
|
125
|
+
reset_style(:font)
|
126
|
+
reset_style(:border)
|
127
|
+
end
|
128
|
+
|
129
|
+
def reset_style(style_type)
|
130
|
+
case style_type
|
131
|
+
when :font
|
132
|
+
doc.font_size @brain[:font][:size]
|
133
|
+
when :border
|
134
|
+
doc.line_width @brain[:border][:color]
|
135
|
+
doc.stroke_color @brain[:border][:width]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
# Extend prawn with *swiss_qr_bill* methods
|
6
|
+
module Extension
|
7
|
+
def swiss_qr_bill(data)
|
8
|
+
Prawn::SwissQRBill::Bill.new(self, data).draw
|
9
|
+
end
|
10
|
+
|
11
|
+
def swiss_qr_bill_sections
|
12
|
+
canvas do
|
13
|
+
Prawn::SwissQRBill::DebugSection.new(self).draw
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
module Helpers
|
6
|
+
# Helpers for drawing boxes
|
7
|
+
module BoxHelper
|
8
|
+
def corner_box(doc, point, options)
|
9
|
+
Prawn::SwissQRBill::CornerBox.new(doc, point, options).draw
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
module Helpers
|
6
|
+
# Helpers to format numbers
|
7
|
+
module NumberHelper
|
8
|
+
def format_with_delimiter(number)
|
9
|
+
left, right = format('%.2f', number).split('.')
|
10
|
+
left.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/) { |d| "#{d} " }
|
11
|
+
[left, right].compact.join('.')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prawn
|
4
|
+
module SwissQRBill
|
5
|
+
# Check validity of IBAN.
|
6
|
+
#
|
7
|
+
# NOTE: *For Switzerland only*
|
8
|
+
#
|
9
|
+
# Simple implementation according to
|
10
|
+
# https://en.wikipedia.org/wiki/International_Bank_Account_Number#Algorithms
|
11
|
+
#
|
12
|
+
# TODO: validate QR-iban
|
13
|
+
class IBAN
|
14
|
+
attr_reader :code
|
15
|
+
|
16
|
+
def initialize(code)
|
17
|
+
@code = standardize(code)
|
18
|
+
end
|
19
|
+
|
20
|
+
def country_code
|
21
|
+
@code[0..1]
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_digits
|
25
|
+
@code[2..3]
|
26
|
+
end
|
27
|
+
|
28
|
+
def bban
|
29
|
+
@code[4..-1]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Convert Alpha-Numeric IBAN to numeric values (incl. rearrangement)
|
33
|
+
#
|
34
|
+
# Reference:
|
35
|
+
# https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN
|
36
|
+
def to_i
|
37
|
+
"#{bban}#{country_code}#{check_digits}".gsub(/[A-Z]/) { |c| c.ord - 55 }.to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
def prettify
|
41
|
+
@code.gsub(/(.{4})/, '\1 ').strip
|
42
|
+
end
|
43
|
+
|
44
|
+
# valid IBAN:
|
45
|
+
# CH77 8080 8004 1110 4136 9
|
46
|
+
#
|
47
|
+
# valid QR-IBAN:
|
48
|
+
# CH08 3080 8004 1110 4136 9
|
49
|
+
def valid?
|
50
|
+
valid_check_digits? && valid_swiss_length? && valid_country?
|
51
|
+
end
|
52
|
+
|
53
|
+
def valid_check_digits?
|
54
|
+
to_i % 97 == 1
|
55
|
+
end
|
56
|
+
|
57
|
+
# NOTE: Only the length for Switzerland is implemented because it is Swiss QR-bill specific
|
58
|
+
def valid_length?
|
59
|
+
valid_swiss_length?
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid_swiss_length?
|
63
|
+
@code.length == 21
|
64
|
+
end
|
65
|
+
|
66
|
+
def valid_country?
|
67
|
+
country_code == 'CH'
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
# Make the given string standard:
|
73
|
+
#
|
74
|
+
# CH21 2345 2123 5543 5554
|
75
|
+
# ch21 2345 2123 5543 5554
|
76
|
+
# " ch21 2345 2123 5543 5554 "
|
77
|
+
#
|
78
|
+
# => CH212345212355435554
|
79
|
+
def standardize(code)
|
80
|
+
code.to_s.strip.gsub(/\s+/, '').upcase
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
Binary file
|
Binary file
|