qrcode_pix_ruby 0.3.2 → 0.5.0
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/.github/workflows/ci.yml +13 -2
- data/.github/workflows/heroku.yml +50 -0
- data/.github/workflows/rubygems.yml +1 -1
- data/.gitignore +2 -1
- data/.rubocop.yml +38 -0
- data/CHANGELOG.md +19 -0
- data/Dockerfile +2 -4
- data/LICENSE.txt +1 -1
- data/README.md +76 -29
- data/Rakefile +3 -1
- data/demo/Gemfile +5 -0
- data/demo/config.ru +171 -0
- data/lib/qrcode_pix_ruby.rb +1 -2
- data/lib/qrcode_pix_ruby/payload.rb +64 -48
- data/lib/qrcode_pix_ruby/version.rb +1 -1
- data/qrcode_pix_ruby.gemspec +14 -12
- metadata +38 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7d931df9ece2ebd9af528f72a1dda1efefda84c10524b3896194d0d34d96c22
|
4
|
+
data.tar.gz: dfb9495a14d4a1607f8451465bb009e8bff5a12816cb79f314e4b7572c60023b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b58df6d23aa1f1c884218da52bacf1c0450e7534eef254522f32d021fda4be283b4d001b5a0b04488f208de62512e1e60ea1baccb54e13f98171f97825eae11
|
7
|
+
data.tar.gz: 7608914b8ef248a0f6705bc4d14483ffbb5a716009de911302fef9822136b5f51f5213999922df89a8053ba1cb32745887243f6c8f11df2ef5c84c9a8b1f1ed0
|
data/.github/workflows/ci.yml
CHANGED
@@ -3,11 +3,22 @@ name: CI
|
|
3
3
|
on: [push, pull_request]
|
4
4
|
|
5
5
|
jobs:
|
6
|
-
|
6
|
+
dockerfile:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
|
11
|
+
- name: Build Dockerfile
|
12
|
+
run: docker build -t qrcode_pix_ruby_specs .
|
13
|
+
|
14
|
+
- name: Run tests inside Docker container
|
15
|
+
run: docker run -v $(pwd):/app/ -i qrcode_pix_ruby_specs
|
16
|
+
|
17
|
+
tests:
|
7
18
|
runs-on: ubuntu-latest
|
8
19
|
strategy:
|
9
20
|
matrix:
|
10
|
-
ruby-version: [2.7, 3.0]
|
21
|
+
ruby-version: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0]
|
11
22
|
env:
|
12
23
|
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
|
13
24
|
steps:
|
@@ -0,0 +1,50 @@
|
|
1
|
+
name: Publish to Heroku
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [master]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
deploy:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
steps:
|
11
|
+
- uses: actions/checkout@v2
|
12
|
+
|
13
|
+
- name: Install Ruby
|
14
|
+
uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: 3.0
|
17
|
+
|
18
|
+
- name: Install dependencies
|
19
|
+
run: |
|
20
|
+
cd demo/
|
21
|
+
bundle install
|
22
|
+
bundle update qrcode_pix_ruby
|
23
|
+
cd ../
|
24
|
+
|
25
|
+
- name: Define Heroku credentials
|
26
|
+
run: |
|
27
|
+
cat > ~/.netrc <<EOF
|
28
|
+
machine api.heroku.com
|
29
|
+
login $HEROKU_EMAIL
|
30
|
+
password $HEROKU_API_KEY
|
31
|
+
machine git.heroku.com
|
32
|
+
login $HEROKU_EMAIL
|
33
|
+
password $HEROKU_API_KEY
|
34
|
+
EOF
|
35
|
+
env:
|
36
|
+
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
|
37
|
+
HEROKU_EMAIL: ${{ secrets.HEROKU_EMAIL }}
|
38
|
+
|
39
|
+
- name: Define Heroku git remote
|
40
|
+
run: heroku git:remote --app $HEROKU_APP_NAME
|
41
|
+
env:
|
42
|
+
HEROKU_APP_NAME: ${{ secrets.HEROKU_APP_NAME }}
|
43
|
+
|
44
|
+
- name: Publish to Heroku
|
45
|
+
run: |
|
46
|
+
git config user.name 'Pedro Furtado'
|
47
|
+
git config user.email 'pedro.felipe.azevedo.furtado@gmail.com'
|
48
|
+
git add --all
|
49
|
+
git commit -m 'Publish to Heroku'
|
50
|
+
git push heroku `git subtree split --prefix demo master`:master --force
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
AllCops:
|
2
|
+
NewCops: enable
|
3
|
+
SuggestExtensions: false
|
4
|
+
Exclude:
|
5
|
+
- spec/*
|
6
|
+
- demo/*
|
7
|
+
|
8
|
+
Style/RegexpLiteral:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Layout/LineLength:
|
12
|
+
Max: 120
|
13
|
+
Exclude:
|
14
|
+
- qrcode_pix_ruby.gemspec
|
15
|
+
|
16
|
+
Metrics/MethodLength:
|
17
|
+
Max: 20
|
18
|
+
|
19
|
+
Gemspec/RequiredRubyVersion:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Metrics/AbcSize:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Metrics/BlockNesting:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/IfUnlessModifier:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Metrics/CyclomaticComplexity:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Metrics/PerceivedComplexity:
|
38
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.5.0] - 2021-07-13
|
4
|
+
|
5
|
+
- Add option to pass Pix informations directly in initializer
|
6
|
+
- CI speedup
|
7
|
+
- Specs reorganization
|
8
|
+
|
9
|
+
## [0.4.0] - 2021-07-10
|
10
|
+
|
11
|
+
- Add URL option for PIX, in order to generate dynamic QR Codes
|
12
|
+
|
13
|
+
## [0.3.4] - 2021-06-28
|
14
|
+
|
15
|
+
- Fix behavior of EMV field 'repeatable' (the logic was inversed)
|
16
|
+
|
17
|
+
## [0.3.3] - 2021-06-25
|
18
|
+
|
19
|
+
- Rubocop setup
|
20
|
+
- Add rubies 2.3, 2.4, 2.5 and 2.6 to support of gem
|
21
|
+
|
3
22
|
## [0.3.2] - 2021-06-24
|
4
23
|
|
5
24
|
- Setup for run tests/specs locally with Docker
|
data/Dockerfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -7,10 +7,11 @@
|
|
7
7
|
[]()
|
8
8
|
[]()
|
9
9
|
[](https://github.com/pedrofurtado/qrcode_pix_ruby)
|
10
|
+
[](https://github.com/rubocop/rubocop)
|
10
11
|
|
11
12
|
Ruby gem for Qrcode generation of Pix (Pagamento Instantâneo Brasileiro - Banco Central do Brasil).
|
12
13
|
|
13
|
-
<img src="https://github.com/pedrofurtado/qrcode_pix_ruby/blob/master/pix_logo.png?raw=true" height="100px" />
|
14
|
+
<img style="max-width: 100%;" src="https://github.com/pedrofurtado/qrcode_pix_ruby/blob/master/pix_logo.png?raw=true" height="100px" />
|
14
15
|
|
15
16
|
## Installation
|
16
17
|
|
@@ -28,33 +29,87 @@ Or install it yourself as:
|
|
28
29
|
|
29
30
|
gem install qrcode_pix_ruby
|
30
31
|
|
31
|
-
## Usage
|
32
|
+
## Usage (examples)
|
33
|
+
|
34
|
+
### Static QR Code
|
32
35
|
|
33
36
|
```ruby
|
34
37
|
require 'qrcode_pix_ruby'
|
35
38
|
|
36
|
-
pix = QrcodePixRuby::Payload.new
|
39
|
+
pix = QrcodePixRuby::Payload.new(
|
40
|
+
pix_key: 'minhachavedopix',
|
41
|
+
description: 'Pagamento do pedido 123456',
|
42
|
+
merchant_name: 'Fulano de Tal',
|
43
|
+
merchant_city: 'SAO PAULO',
|
44
|
+
transaction_id: 'TID12345',
|
45
|
+
amount: '100.00',
|
46
|
+
currency: '986',
|
47
|
+
country_code: 'BR',
|
48
|
+
postal_code: '01131010',
|
49
|
+
repeatable: false
|
50
|
+
)
|
51
|
+
|
52
|
+
# If needed, change the attributes value later
|
53
|
+
pix.pix_key = 'minhaoutrachavepix'
|
54
|
+
pix.merchant_city = 'BRASILIA'
|
55
|
+
|
56
|
+
# QRCode copia-e-cola
|
57
|
+
puts pix.payload
|
58
|
+
|
59
|
+
# QRCode for images
|
60
|
+
puts pix.base64
|
61
|
+
```
|
62
|
+
|
63
|
+
### Dynamic QR Code
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
require 'qrcode_pix_ruby'
|
37
67
|
|
38
|
-
pix
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
68
|
+
pix = QrcodePixRuby::Payload.new(
|
69
|
+
url: 'https://example.com',
|
70
|
+
merchant_name: 'Fulano de Tal',
|
71
|
+
merchant_city: 'SAO PAULO',
|
72
|
+
amount: '100.00',
|
73
|
+
transaction_id: 'TID12345',
|
74
|
+
repeatable: false
|
75
|
+
)
|
76
|
+
|
77
|
+
# If needed, change the attributes value later
|
78
|
+
pix.url = 'https://another-example.com'
|
79
|
+
pix.amount = 1.50
|
48
80
|
|
49
81
|
# QRCode copia-e-cola
|
50
82
|
puts pix.payload
|
51
83
|
|
52
|
-
# QRCode
|
84
|
+
# QRCode para uso em imagens
|
53
85
|
puts pix.base64
|
54
86
|
```
|
55
87
|
|
56
88
|
🚨 Important note: BACEN (Banco Central do Brasil) sets a variety of rules for each field in QRCode Payload (maximum number of characters, invalid values, mandatory and optional fields, and so on). So, pay attention that a QRCode payload+base64 generated by the gem can be valid, theorically, but may not be accepted in banking apps because of these restrictions (that are out of scope of gem).
|
57
89
|
|
90
|
+
## Execute tests/specs
|
91
|
+
|
92
|
+
To execute gem tests locally, use Docker with the commands below:
|
93
|
+
|
94
|
+
```bash
|
95
|
+
git clone https://github.com/pedrofurtado/qrcode_pix_ruby
|
96
|
+
cd qrcode_pix_ruby/
|
97
|
+
docker build -t qrcode_pix_ruby_specs .
|
98
|
+
|
99
|
+
# Then, run this command how many times you want,
|
100
|
+
# after editing local files, and so on, to get
|
101
|
+
# feedback from test suite of gem.
|
102
|
+
docker run -v $(pwd):/app/ -it qrcode_pix_ruby_specs
|
103
|
+
```
|
104
|
+
|
105
|
+
## Demo
|
106
|
+
|
107
|
+
It's provided a simple demo app, in Heroku, that uses the gem always in latest commit. You can check and test your QRCodes here:
|
108
|
+
|
109
|
+
https://qrcode-pix-ruby.herokuapp.com
|
110
|
+
|
111
|
+
🚨 Important note: The first page load can be slow, because of Heroku free tier. But don't worry, the demo works well 🤓
|
112
|
+
|
58
113
|
## Useful links
|
59
114
|
|
60
115
|
* https://github.com/joseviniciusnunes/qrcode-pix
|
@@ -67,27 +122,19 @@ puts pix.base64
|
|
67
122
|
* https://openpix.com.br/qrcode/scanner
|
68
123
|
* https://openpix.com.br/qrcode/debug
|
69
124
|
* https://github.com/william-costa/wdev-qrcode-pix-estatico-php
|
125
|
+
* https://github.com/william-costa/wdev-qrcode-pix-php
|
70
126
|
* https://www.youtube.com/watch?v=eO11iFgrdCA
|
71
127
|
* https://qrcodepix.dinheiro.tech
|
72
128
|
* http://decoder.qrcodepix.dinheiro.tech
|
73
129
|
* https://www.bcb.gov.br/estabilidadefinanceira/pix
|
74
130
|
* https://gerencianet.com.br/blog/qr-code-estatico-qr-code-dinamico-no-pix
|
75
131
|
* https://blog.juno.com.br/pix-qr-code-estatico-x-qr-code-dinamico
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
git clone https://github.com/pedrofurtado/qrcode_pix_ruby
|
83
|
-
cd qrcode_pix_ruby/
|
84
|
-
docker build -t qrcode_pix_ruby_specs .
|
85
|
-
|
86
|
-
# Then, run this command how many times you want,
|
87
|
-
# after editing local files, and so on, to get
|
88
|
-
# feedback from test suite of gem.
|
89
|
-
docker run -v $(pwd):/app/ -it qrcode_pix_ruby_specs
|
90
|
-
```
|
132
|
+
* https://github.com/entria/awesome-pix
|
133
|
+
* https://zxing.org/w/decode.jspx
|
134
|
+
* https://github.com/hiagodotme/gpix
|
135
|
+
* https://github.com/EnssureIT/faz-um-pix
|
136
|
+
* https://github.com/jesobreira/pixkey
|
137
|
+
* https://github.com/pedrinholemes/pix-br
|
91
138
|
|
92
139
|
## Contributing
|
93
140
|
|
data/Rakefile
CHANGED
data/demo/Gemfile
ADDED
data/demo/config.ru
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'qrcode_pix_ruby'
|
4
|
+
|
5
|
+
def generate_html_with(env)
|
6
|
+
qrcode_data = Rack::Request.new(env).params
|
7
|
+
payload = ''
|
8
|
+
data_uri = ''
|
9
|
+
pix = QrcodePixRuby::Payload.new
|
10
|
+
|
11
|
+
unless qrcode_data.empty?
|
12
|
+
pix.pix_key = qrcode_data['pix_key'] if !qrcode_data['pix_key'].nil? && !qrcode_data['pix_key'].empty?
|
13
|
+
pix.url = qrcode_data['url'] if !qrcode_data['url'].nil? && !qrcode_data['url'].empty?
|
14
|
+
pix.description = qrcode_data['description'] if !qrcode_data['description'].nil? && !qrcode_data['description'].empty?
|
15
|
+
pix.merchant_name = qrcode_data['merchant_name'] if !qrcode_data['merchant_name'].nil? && !qrcode_data['merchant_name'].empty?
|
16
|
+
pix.merchant_city = qrcode_data['merchant_city'] if !qrcode_data['merchant_city'].nil? && !qrcode_data['merchant_city'].empty?
|
17
|
+
pix.transaction_id = qrcode_data['transaction_id'] if !qrcode_data['transaction_id'].nil? && !qrcode_data['transaction_id'].empty?
|
18
|
+
pix.amount = qrcode_data['amount'] if !qrcode_data['amount'].nil? && !qrcode_data['amount'].empty?
|
19
|
+
pix.currency = qrcode_data['currency'] if !qrcode_data['currency'].nil? && !qrcode_data['currency'].empty?
|
20
|
+
pix.country_code = qrcode_data['country_code'] if !qrcode_data['country_code'].nil? && !qrcode_data['country_code'].empty?
|
21
|
+
pix.postal_code = qrcode_data['postal_code'] if !qrcode_data['postal_code'].nil? && !qrcode_data['postal_code'].empty?
|
22
|
+
pix.repeatable = qrcode_data['repeatable'] == 't' if !qrcode_data['repeatable'].nil? && !qrcode_data['repeatable'].empty?
|
23
|
+
|
24
|
+
payload = <<-HTML
|
25
|
+
<label for='payload'>Payload</label>
|
26
|
+
<div class='input-group mb-3'>
|
27
|
+
<input class='form-control' id='payload' value='#{pix.payload}'>
|
28
|
+
<button class='btn btn-outline-success btn-clipboard' data-clipboard-target='#payload' data-bs-toggle='tooltip' data-bs-placement='top' title='Copied!' data-bs-trigger='click'>Copy</button>
|
29
|
+
</div>
|
30
|
+
HTML
|
31
|
+
|
32
|
+
data_uri = "<img style='max-width: 100%; display: block; margin: 0 auto;' src='#{pix.base64}'>"
|
33
|
+
end
|
34
|
+
|
35
|
+
StringIO.new <<-HTML
|
36
|
+
<!DOCTYPE html>
|
37
|
+
<html>
|
38
|
+
<head>
|
39
|
+
<meta charset='utf-8'>
|
40
|
+
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
41
|
+
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css' rel='stylesheet'>
|
42
|
+
<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js'></script>
|
43
|
+
<script src='https://cdn.jsdelivr.net/npm/clipboard@2.0.8/dist/clipboard.min.js'></script>
|
44
|
+
<title>QRCode Pix Ruby - Demo App</title>
|
45
|
+
</head>
|
46
|
+
<body>
|
47
|
+
<div class='container' style='margin-top: 50px;'>
|
48
|
+
<div class='row'>
|
49
|
+
<div class='col-md-12'>
|
50
|
+
<h1 class='text-center'>QRCode Pix Ruby - Demo App</h1>
|
51
|
+
<br>
|
52
|
+
<img style='display: block; margin: 0 auto; max-width: 100%;' src="https://github.com/pedrofurtado/qrcode_pix_ruby/blob/master/pix_logo.png?raw=true" height="100px" />
|
53
|
+
<br>
|
54
|
+
<p style='word-break: break-all;' class='text-center'>For more details check the official repo: <a href="https://github.com/pedrofurtado/qrcode_pix_ruby">https://github.com/pedrofurtado/qrcode_pix_ruby</a></p>
|
55
|
+
<br>
|
56
|
+
<br>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
<div class='row' style='padding-bottom: 50px;'>
|
60
|
+
<div class='col-sm-6'>
|
61
|
+
<strong>QRCode informations</strong>
|
62
|
+
<br>
|
63
|
+
<br>
|
64
|
+
<form action='https://qrcode-pix-ruby.herokuapp.com' method='post'>
|
65
|
+
<div class='mb-3'>
|
66
|
+
<div class='form-text'>
|
67
|
+
For static Pix, please fill the 'Pix key' field.<br>
|
68
|
+
For dynamic Pix, fill the 'URL' field.<br>
|
69
|
+
Do not fill both fields.
|
70
|
+
</div>
|
71
|
+
</div>
|
72
|
+
<div class='mb-3'>
|
73
|
+
<label for='pix_key'>* Pix key</label>
|
74
|
+
<input type='text' class='form-control' id='pix_key' value='#{qrcode_data["pix_key"]}' name='pix_key'>
|
75
|
+
<div class='form-text'>
|
76
|
+
Formats of Pix keys:<br>
|
77
|
+
CPF: 12345678910 (only numbers)<br>
|
78
|
+
Phone: +5511912345678 (+55 + DDD + phone, only numbers)<br>
|
79
|
+
Email: example@mail.com<br>
|
80
|
+
Random: a6hf7jdk3nc8iK (generated by bank)
|
81
|
+
</div>
|
82
|
+
</div>
|
83
|
+
<div class='mb-3 text-center'> or</div>
|
84
|
+
<div class='mb-3'>
|
85
|
+
<label for='url'>* URL</label>
|
86
|
+
<input type='url' pattern='https?:\/\/.+' class='form-control' id='url' value='#{qrcode_data["url"]}' name='url'>
|
87
|
+
</div>
|
88
|
+
<hr>
|
89
|
+
<div class='mb-3'>
|
90
|
+
<label for='merchant_name'>* Merchant name</label>
|
91
|
+
<input required maxlength='10' type='text' class='form-control' id='merchant_name' value='#{qrcode_data["merchant_name"]}' name='merchant_name'>
|
92
|
+
</div>
|
93
|
+
<div class='mb-3'>
|
94
|
+
<label for='merchant_city'>* Merchant city</label>
|
95
|
+
<input required maxlength='10' type='text' class='form-control' id='merchant_city' value='#{qrcode_data["merchant_city"]}' name='merchant_city'>
|
96
|
+
</div>
|
97
|
+
<div class='mb-3'>
|
98
|
+
<label for='country_code'>* Country</label>
|
99
|
+
<select required id='country_code' name='country_code' class='form-select'>
|
100
|
+
<option></option>
|
101
|
+
<option value='BR' #{qrcode_data['country_code'] == 'BR' ? 'selected' : ''}>Brazil</option>
|
102
|
+
</select>
|
103
|
+
</div>
|
104
|
+
<div class='mb-3'>
|
105
|
+
<label for='currency'>* Currency</label>
|
106
|
+
<select required id='currency' name='currency' class='form-select'>
|
107
|
+
<option></option>
|
108
|
+
<option value='986' #{qrcode_data['currency'] == '986' ? 'selected' : ''}>Brazilian Real (R$)</option>
|
109
|
+
</select>
|
110
|
+
</div>
|
111
|
+
<div class='mb-3'>
|
112
|
+
<label for='description'>Description</label>
|
113
|
+
<input maxlength='10' type='text' class='form-control' id='description' value='#{qrcode_data["description"]}' name='description'>
|
114
|
+
</div>
|
115
|
+
<div class='mb-3'>
|
116
|
+
<label for='transaction_id'>Transaction ID</label>
|
117
|
+
<input maxlength='10' pattern='[a-zA-z0-9]*' type='text' class='form-control' id='transaction_id' value='#{qrcode_data["transaction_id"]}' name='transaction_id'>
|
118
|
+
<div class='form-text'>Only numbers and simple characters, without whitespaces.</div>
|
119
|
+
</div>
|
120
|
+
<div class='mb-3'>
|
121
|
+
<label for='amount'>Amount</label>
|
122
|
+
<input type='number' step='0.01' pattern='[0-9]{1,}\.[0-9][0-9]' class='form-control' id='amount' value='#{qrcode_data["amount"]}' name='amount'>
|
123
|
+
<div class='form-text'>Only numbers with 2 decimal places.</div>
|
124
|
+
</div>
|
125
|
+
<div class='mb-3'>
|
126
|
+
<label for='postal_code'>Postal code</label>
|
127
|
+
<input maxlength='8' pattern='[0-9]{8}' type='tel' class='form-control' id='postal_code' value='#{qrcode_data["postal_code"]}' name='postal_code'>
|
128
|
+
<div class='form-text'>Only numbers.</div>
|
129
|
+
</div>
|
130
|
+
<div class='mb-3'>
|
131
|
+
<label for='repeatable'>Can be paid multiple times?</label>
|
132
|
+
<select required id='repeatable' name='repeatable' class='form-select'>
|
133
|
+
<option></option>
|
134
|
+
<option value='t' #{qrcode_data['repeatable'] == 't' ? 'selected' : ''}>Yes</option>
|
135
|
+
<option value='f' #{qrcode_data['repeatable'] == 'f' ? 'selected' : ''}>No</option>
|
136
|
+
</select>
|
137
|
+
</div>
|
138
|
+
<div class='d-grid gap-2' style='padding-bottom: 20px;'>
|
139
|
+
<button type='submit' class='btn btn-lg btn-primary'>Generate</button>
|
140
|
+
</div>
|
141
|
+
</form>
|
142
|
+
</div>
|
143
|
+
<div class='col-sm-6'>
|
144
|
+
<strong>Preview</strong>
|
145
|
+
<br>
|
146
|
+
<br>
|
147
|
+
#{payload}
|
148
|
+
#{data_uri}
|
149
|
+
</div>
|
150
|
+
</div>
|
151
|
+
</div>
|
152
|
+
<script>
|
153
|
+
new ClipboardJS('.btn-clipboard');
|
154
|
+
Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')).forEach(function(tooltipTriggerEl) {
|
155
|
+
new bootstrap.Tooltip(tooltipTriggerEl);
|
156
|
+
});
|
157
|
+
</script>
|
158
|
+
</body>
|
159
|
+
</html>
|
160
|
+
HTML
|
161
|
+
end
|
162
|
+
|
163
|
+
run lambda { |env|
|
164
|
+
[
|
165
|
+
200,
|
166
|
+
{
|
167
|
+
'Content-Type' => 'text/html'
|
168
|
+
},
|
169
|
+
generate_html_with(env)
|
170
|
+
]
|
171
|
+
}
|
data/lib/qrcode_pix_ruby.rb
CHANGED
@@ -3,37 +3,41 @@
|
|
3
3
|
require 'rqrcode'
|
4
4
|
|
5
5
|
module QrcodePixRuby
|
6
|
+
class PayloadArgumentError < ArgumentError; end
|
7
|
+
|
6
8
|
class Payload
|
7
|
-
ID_PAYLOAD_FORMAT_INDICATOR = '00'
|
8
|
-
ID_POINT_OF_INITIATION_METHOD = '01'
|
9
|
-
ID_MERCHANT_ACCOUNT_INFORMATION = '26'
|
10
|
-
ID_MERCHANT_ACCOUNT_INFORMATION_GUI = '00'
|
11
|
-
ID_MERCHANT_ACCOUNT_INFORMATION_KEY = '01'
|
12
|
-
ID_MERCHANT_ACCOUNT_INFORMATION_DESCRIPTION = '02'
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
9
|
+
ID_PAYLOAD_FORMAT_INDICATOR = '00'
|
10
|
+
ID_POINT_OF_INITIATION_METHOD = '01'
|
11
|
+
ID_MERCHANT_ACCOUNT_INFORMATION = '26'
|
12
|
+
ID_MERCHANT_ACCOUNT_INFORMATION_GUI = '00'
|
13
|
+
ID_MERCHANT_ACCOUNT_INFORMATION_KEY = '01'
|
14
|
+
ID_MERCHANT_ACCOUNT_INFORMATION_DESCRIPTION = '02'
|
15
|
+
ID_MERCHANT_ACCOUNT_INFORMATION_URL = '25'
|
16
|
+
ID_MERCHANT_CATEGORY_CODE = '52'
|
17
|
+
ID_TRANSACTION_CURRENCY = '53'
|
18
|
+
ID_TRANSACTION_AMOUNT = '54'
|
19
|
+
ID_COUNTRY_CODE = '58'
|
20
|
+
ID_MERCHANT_NAME = '59'
|
21
|
+
ID_MERCHANT_CITY = '60'
|
22
|
+
ID_POSTAL_CODE = '61'
|
23
|
+
ID_ADDITIONAL_DATA_FIELD_TEMPLATE = '62'
|
24
|
+
ID_ADDITIONAL_DATA_FIELD_TEMPLATE_TXID = '05'
|
25
|
+
ID_CRC16 = '63'
|
26
|
+
|
27
|
+
ATTRIBUTES = %i[pix_key url repeatable currency country_code description postal_code
|
28
|
+
merchant_name merchant_city transaction_id amount].freeze
|
29
|
+
|
30
|
+
def initialize(**kwargs)
|
31
|
+
verify_kwargs(kwargs.keys)
|
32
|
+
|
33
|
+
ATTRIBUTES.each do |attribute|
|
34
|
+
singleton_class.class_eval { attr_accessor attribute }
|
35
|
+
instance_variable_set("@#{attribute}", kwargs[attribute])
|
36
|
+
end
|
37
|
+
end
|
34
38
|
|
35
39
|
def payload
|
36
|
-
p
|
40
|
+
p = ''
|
37
41
|
|
38
42
|
p += emv(ID_PAYLOAD_FORMAT_INDICATOR, '01')
|
39
43
|
p += emv_repeatable
|
@@ -51,56 +55,68 @@ module QrcodePixRuby
|
|
51
55
|
end
|
52
56
|
|
53
57
|
def base64
|
54
|
-
::RQRCode::QRCode.new(payload).as_png(
|
58
|
+
::RQRCode::QRCode.new(payload).as_png(
|
59
|
+
bit_depth: 1,
|
60
|
+
border_modules: 0,
|
61
|
+
color_mode: 0,
|
62
|
+
color: 'black',
|
63
|
+
file: nil,
|
64
|
+
fill: 'white',
|
65
|
+
module_px_size: 6,
|
66
|
+
resize_exactly_to: false,
|
67
|
+
resize_gte_to: false
|
68
|
+
).to_data_url
|
55
69
|
end
|
56
70
|
|
57
71
|
private
|
58
72
|
|
73
|
+
def verify_kwargs(keys)
|
74
|
+
unknowns = keys - ATTRIBUTES
|
75
|
+
|
76
|
+
return unless unknowns.any?
|
77
|
+
|
78
|
+
raise QrcodePixRuby::PayloadArgumentError, "Unknown attributes: #{unknowns.join(', ')}"
|
79
|
+
end
|
80
|
+
|
59
81
|
def emv(id, value)
|
60
82
|
size = value.to_s.length.to_s.rjust(2, '0')
|
61
83
|
"#{id}#{size}#{value}"
|
62
84
|
end
|
63
85
|
|
64
86
|
def emv_repeatable
|
65
|
-
emv(ID_POINT_OF_INITIATION_METHOD, repeatable ? '
|
87
|
+
emv(ID_POINT_OF_INITIATION_METHOD, repeatable ? '11' : '12')
|
66
88
|
end
|
67
89
|
|
68
90
|
def emv_merchant
|
69
|
-
merchant_gui = emv
|
70
|
-
merchant_pix_key = emv
|
91
|
+
merchant_gui = emv(ID_MERCHANT_ACCOUNT_INFORMATION_GUI, 'BR.GOV.BCB.PIX')
|
92
|
+
merchant_pix_key = emv(ID_MERCHANT_ACCOUNT_INFORMATION_KEY, pix_key) if pix_key
|
71
93
|
merchant_description = emv(ID_MERCHANT_ACCOUNT_INFORMATION_DESCRIPTION, description) if description
|
72
|
-
|
73
|
-
emv
|
94
|
+
merchant_url = emv(ID_MERCHANT_ACCOUNT_INFORMATION_URL, url.gsub(/https?:\/\//, '')) if url
|
95
|
+
emv(ID_MERCHANT_ACCOUNT_INFORMATION, "#{merchant_gui}#{merchant_pix_key}#{merchant_description}#{merchant_url}")
|
74
96
|
end
|
75
97
|
|
76
98
|
def emv_additional_data
|
77
99
|
txid = emv(ID_ADDITIONAL_DATA_FIELD_TEMPLATE_TXID, transaction_id || '***')
|
78
|
-
emv
|
100
|
+
emv(ID_ADDITIONAL_DATA_FIELD_TEMPLATE, txid)
|
79
101
|
end
|
80
102
|
|
81
|
-
def crc16(
|
82
|
-
extended_payload = "#{
|
103
|
+
def crc16(text)
|
104
|
+
extended_payload = "#{text}#{ID_CRC16}04"
|
83
105
|
extended_payload_length = extended_payload.length
|
84
106
|
polynomial = 0x1021
|
85
107
|
result = 0xFFFF
|
86
108
|
|
87
|
-
if extended_payload_length
|
109
|
+
if extended_payload_length.positive?
|
88
110
|
offset = 0
|
89
111
|
|
90
112
|
while offset < extended_payload_length
|
91
|
-
result
|
92
|
-
|
113
|
+
result ^= extended_payload[offset].bytes[0] << 8
|
93
114
|
bitwise = 0
|
94
115
|
|
95
116
|
while bitwise < 8
|
96
|
-
result
|
97
|
-
|
98
|
-
|
99
|
-
result = result ^ polynomial
|
100
|
-
end
|
101
|
-
|
102
|
-
result = result & 0xFFFF
|
103
|
-
|
117
|
+
result <<= 1
|
118
|
+
result ^= polynomial if result & 0x10000 != 0
|
119
|
+
result &= 0xFFFF
|
104
120
|
bitwise += 1
|
105
121
|
end
|
106
122
|
|
data/qrcode_pix_ruby.gemspec
CHANGED
@@ -5,15 +5,16 @@ require_relative 'lib/qrcode_pix_ruby/version'
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'qrcode_pix_ruby'
|
7
7
|
spec.version = QrcodePixRuby::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
10
|
-
spec.summary =
|
11
|
-
spec.description =
|
12
|
-
spec.homepage =
|
13
|
-
spec.license =
|
14
|
-
spec.metadata[
|
15
|
-
spec.metadata[
|
16
|
-
spec.metadata[
|
8
|
+
spec.authors = ['Pedro Furtado', 'Marcio de Jesus', 'William Radi', 'Leonardo Comar']
|
9
|
+
spec.email = ['pedro.felipe.azevedo.furtado@gmail.com', 'marciodejesusrj@gmail.com', 'williamw@lbv.org.br', 'lfcomar@lbv.org.br']
|
10
|
+
spec.summary = 'Ruby gem for Qrcode generation of Pix (Pagamento Instantâneo Brasileiro - Banco Central do Brasil)'
|
11
|
+
spec.description = 'Ruby gem for Qrcode generation of Pix (Pagamento Instantâneo Brasileiro - Banco Central do Brasil)'
|
12
|
+
spec.homepage = 'https://github.com/pedrofurtado/qrcode_pix_ruby'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
15
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
16
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
|
17
|
+
spec.required_ruby_version = '>= 2.3.0'
|
17
18
|
|
18
19
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
19
20
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
@@ -23,7 +24,8 @@ Gem::Specification.new do |spec|
|
|
23
24
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
24
25
|
spec.require_paths = ['lib']
|
25
26
|
|
26
|
-
spec.add_dependency '
|
27
|
-
spec.
|
28
|
-
spec.
|
27
|
+
spec.add_dependency 'rqrcode'
|
28
|
+
spec.add_development_dependency 'rake'
|
29
|
+
spec.add_development_dependency 'rspec'
|
30
|
+
spec.add_development_dependency 'rubocop'
|
29
31
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qrcode_pix_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Furtado
|
@@ -11,50 +11,64 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2021-
|
14
|
+
date: 2021-07-13 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
17
|
+
name: rqrcode
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - "
|
20
|
+
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - "
|
27
|
+
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
30
44
|
- !ruby/object:Gem::Dependency
|
31
45
|
name: rspec
|
32
46
|
requirement: !ruby/object:Gem::Requirement
|
33
47
|
requirements:
|
34
|
-
- - "
|
48
|
+
- - ">="
|
35
49
|
- !ruby/object:Gem::Version
|
36
|
-
version: '
|
37
|
-
type: :
|
50
|
+
version: '0'
|
51
|
+
type: :development
|
38
52
|
prerelease: false
|
39
53
|
version_requirements: !ruby/object:Gem::Requirement
|
40
54
|
requirements:
|
41
|
-
- - "
|
55
|
+
- - ">="
|
42
56
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
57
|
+
version: '0'
|
44
58
|
- !ruby/object:Gem::Dependency
|
45
|
-
name:
|
59
|
+
name: rubocop
|
46
60
|
requirement: !ruby/object:Gem::Requirement
|
47
61
|
requirements:
|
48
|
-
- - "
|
62
|
+
- - ">="
|
49
63
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
51
|
-
type: :
|
64
|
+
version: '0'
|
65
|
+
type: :development
|
52
66
|
prerelease: false
|
53
67
|
version_requirements: !ruby/object:Gem::Requirement
|
54
68
|
requirements:
|
55
|
-
- - "
|
69
|
+
- - ">="
|
56
70
|
- !ruby/object:Gem::Version
|
57
|
-
version: '
|
71
|
+
version: '0'
|
58
72
|
description: Ruby gem for Qrcode generation of Pix (Pagamento Instantâneo Brasileiro
|
59
73
|
- Banco Central do Brasil)
|
60
74
|
email:
|
@@ -67,9 +81,11 @@ extensions: []
|
|
67
81
|
extra_rdoc_files: []
|
68
82
|
files:
|
69
83
|
- ".github/workflows/ci.yml"
|
84
|
+
- ".github/workflows/heroku.yml"
|
70
85
|
- ".github/workflows/rubygems.yml"
|
71
86
|
- ".gitignore"
|
72
87
|
- ".rspec"
|
88
|
+
- ".rubocop.yml"
|
73
89
|
- CHANGELOG.md
|
74
90
|
- CODE_OF_CONDUCT.md
|
75
91
|
- Dockerfile
|
@@ -79,6 +95,8 @@ files:
|
|
79
95
|
- Rakefile
|
80
96
|
- bin/console
|
81
97
|
- bin/setup
|
98
|
+
- demo/Gemfile
|
99
|
+
- demo/config.ru
|
82
100
|
- lib/qrcode_pix_ruby.rb
|
83
101
|
- lib/qrcode_pix_ruby/payload.rb
|
84
102
|
- lib/qrcode_pix_ruby/version.rb
|
@@ -99,14 +117,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
117
|
requirements:
|
100
118
|
- - ">="
|
101
119
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
120
|
+
version: 2.3.0
|
103
121
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
122
|
requirements:
|
105
123
|
- - ">="
|
106
124
|
- !ruby/object:Gem::Version
|
107
125
|
version: '0'
|
108
126
|
requirements: []
|
109
|
-
rubygems_version: 3.2.
|
127
|
+
rubygems_version: 3.2.22
|
110
128
|
signing_key:
|
111
129
|
specification_version: 4
|
112
130
|
summary: Ruby gem for Qrcode generation of Pix (Pagamento Instantâneo Brasileiro -
|