prawn-swiss_qr_bill 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Swiss QR-bill Example, PDF](./images/sqb_example_01.png)
|
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
|