Skip to content

Commit 930e103

Browse files
authored
Merge pull request #1 from mrsool/feature/generate-qr-codes
2 parents 7cd0ba2 + 4136c72 commit 930e103

22 files changed

+580
-51
lines changed

.github/workflows/main.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Ruby
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Set up Ruby
16+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
17+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
18+
uses: ruby/setup-ruby@v1
19+
with:
20+
ruby-version: 3.0.0
21+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
22+
- name: Lint
23+
run: bundle exec standardrb
24+
25+
- name: Run tests
26+
run: bundle exec rspec

.gitignore

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,10 @@
1-
*.gem
2-
*.rbc
3-
/.config
1+
/.bundle/
2+
/.yardoc
3+
/_yardoc/
44
/coverage/
5-
/InstalledFiles
5+
/doc/
66
/pkg/
77
/spec/reports/
8-
/spec/examples.txt
9-
/test/tmp/
10-
/test/version_tmp/
118
/tmp/
129

13-
# Used by dotenv library to load environment variables.
14-
# .env
15-
16-
# Ignore Byebug command history file.
17-
.byebug_history
18-
19-
## Specific to RubyMotion:
20-
.dat*
21-
.repl_history
22-
build/
23-
*.bridgesupport
24-
build-iPhoneOS/
25-
build-iPhoneSimulator/
26-
27-
## Specific to RubyMotion (use of CocoaPods):
28-
#
29-
# We recommend against adding the Pods directory to your .gitignore. However
30-
# you should judge for yourself, the pros and cons are mentioned at:
31-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32-
#
33-
# vendor/Pods/
34-
35-
## Documentation cache and generated files:
36-
/.yardoc/
37-
/_yardoc/
38-
/doc/
39-
/rdoc/
40-
41-
## Environment normalization:
42-
/.bundle/
43-
/vendor/bundle
44-
/lib/bundler/man/
45-
46-
# for a library or gem, you might want to ignore these files since the code is
47-
# intended to run in multiple environments; otherwise, check them in:
48-
# Gemfile.lock
49-
# .ruby-version
50-
# .ruby-gemset
51-
52-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53-
.rvmrc
54-
55-
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
56-
# .rubocop-https?--*
10+
.byebug_history

.rspec

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--require spec_helper
2+
-I lib/zatca

Gemfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# frozen_string_literal: true
2+
3+
source "https://rubygems.org"
4+
5+
# Specify your gem's dependencies in zatca-qr-code.gemspec
6+
gemspec
7+
8+
gem "rake", "~> 13.0"

Gemfile.lock

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
PATH
2+
remote: .
3+
specs:
4+
zatca-qr-code (0.1.0)
5+
dry-schema (~> 1.5)
6+
rqrcode (~> 2.1.0)
7+
zeitwerk (~> 2.4)
8+
9+
GEM
10+
remote: https://rubygems.org/
11+
specs:
12+
ast (2.4.2)
13+
byebug (9.1.0)
14+
chunky_png (1.4.0)
15+
concurrent-ruby (1.1.9)
16+
diff-lcs (1.4.4)
17+
dry-configurable (0.13.0)
18+
concurrent-ruby (~> 1.0)
19+
dry-core (~> 0.6)
20+
dry-container (0.9.0)
21+
concurrent-ruby (~> 1.0)
22+
dry-configurable (~> 0.13, >= 0.13.0)
23+
dry-core (0.7.1)
24+
concurrent-ruby (~> 1.0)
25+
dry-inflector (0.2.1)
26+
dry-initializer (3.0.4)
27+
dry-logic (1.2.0)
28+
concurrent-ruby (~> 1.0)
29+
dry-core (~> 0.5, >= 0.5)
30+
dry-schema (1.8.0)
31+
concurrent-ruby (~> 1.0)
32+
dry-configurable (~> 0.13, >= 0.13.0)
33+
dry-core (~> 0.5, >= 0.5)
34+
dry-initializer (~> 3.0)
35+
dry-logic (~> 1.0)
36+
dry-types (~> 1.5)
37+
dry-types (1.5.1)
38+
concurrent-ruby (~> 1.0)
39+
dry-container (~> 0.3)
40+
dry-core (~> 0.5, >= 0.5)
41+
dry-inflector (~> 0.1, >= 0.1.2)
42+
dry-logic (~> 1.0, >= 1.0.2)
43+
parallel (1.21.0)
44+
parser (3.0.2.0)
45+
ast (~> 2.4.1)
46+
rainbow (3.0.0)
47+
rake (13.0.6)
48+
regexp_parser (2.1.1)
49+
rexml (3.2.5)
50+
rqrcode (2.1.0)
51+
chunky_png (~> 1.0)
52+
rqrcode_core (~> 1.0)
53+
rqrcode_core (1.2.0)
54+
rspec (3.10.0)
55+
rspec-core (~> 3.10.0)
56+
rspec-expectations (~> 3.10.0)
57+
rspec-mocks (~> 3.10.0)
58+
rspec-core (3.10.1)
59+
rspec-support (~> 3.10.0)
60+
rspec-expectations (3.10.1)
61+
diff-lcs (>= 1.2.0, < 2.0)
62+
rspec-support (~> 3.10.0)
63+
rspec-mocks (3.10.2)
64+
diff-lcs (>= 1.2.0, < 2.0)
65+
rspec-support (~> 3.10.0)
66+
rspec-support (3.10.2)
67+
rubocop (1.20.0)
68+
parallel (~> 1.10)
69+
parser (>= 3.0.0.0)
70+
rainbow (>= 2.2.2, < 4.0)
71+
regexp_parser (>= 1.8, < 3.0)
72+
rexml
73+
rubocop-ast (>= 1.9.1, < 2.0)
74+
ruby-progressbar (~> 1.7)
75+
unicode-display_width (>= 1.4.0, < 3.0)
76+
rubocop-ast (1.12.0)
77+
parser (>= 3.0.1.1)
78+
rubocop-performance (1.11.5)
79+
rubocop (>= 1.7.0, < 2.0)
80+
rubocop-ast (>= 0.4.0)
81+
ruby-progressbar (1.11.0)
82+
standard (1.3.0)
83+
rubocop (= 1.20.0)
84+
rubocop-performance (= 1.11.5)
85+
unicode-display_width (2.1.0)
86+
zeitwerk (2.4.2)
87+
88+
PLATFORMS
89+
x86_64-darwin-20
90+
x86_64-linux
91+
92+
DEPENDENCIES
93+
byebug (~> 9.0)
94+
rake (~> 13.0)
95+
rspec (~> 3.10)
96+
standard (~> 1.3)
97+
zatca-qr-code!
98+
99+
BUNDLED WITH
100+
2.2.27

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,52 @@
11
# zatca-qr-code
2+
3+
[🚧 Still being validated by ZATCA](https://github.com/mrsool/zatca-qr-code/issues/3).
4+
25
A library for generating QR Codes for the e-invoice standard by ZATCA in Saudi Arabia.
6+
7+
# Installation
8+
9+
## Rubygems
10+
```sh
11+
gem install zatca-qr-code
12+
```
13+
14+
## Bundler
15+
```sh
16+
bundle add zatca-qr-code
17+
```
18+
19+
# Usage
20+
21+
```rb
22+
require "zatca-qr-code"
23+
24+
tags = {
25+
seller_name: "Mrsool",
26+
vat_registration_number: "310228833400003",
27+
timestamp: "2021-10-20T19:29:32+03:00",
28+
vat_total: "15",
29+
invoice_total: "115",
30+
}
31+
32+
ZATCA.render_qr_code(tags)
33+
# => data:image/png;base64,...
34+
# Hint (Try pasting the above into your web browser's address bar)
35+
```
36+
37+
If you'd like to customize the size of the QR Code you can manually use the generator like so:
38+
39+
```rb
40+
require "zatca-qr-code"
41+
42+
tags = ZATCA::Tags.new({
43+
seller_name: "Mrsool",
44+
vat_registration_number: "310228833400003",
45+
timestamp: "2021-10-20T19:29:32+03:00",
46+
vat_total: "15",
47+
invoice_total: "115",
48+
})
49+
50+
generator = ZATCA::QRCodeGenerator.new(tags)
51+
generator.render(size: 512)
52+
```

Rakefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# frozen_string_literal: true
2+
3+
require "bundler/gem_tasks"
4+
task default: %i[]

bin/console

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
require "bundler/setup"
5+
require_relative "../lib/zatca.rb"
6+
7+
# You can add fixtures and/or initialization code here to make experimenting
8+
# with your gem easier. You can also use a different console, if you like.
9+
10+
# (If you use this, don't forget to add pry to your Gemfile!)
11+
# require "pry"
12+
# Pry.start
13+
14+
require "irb"
15+
IRB.start(__FILE__)

bin/setup

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
IFS=$'\n\t'
4+
set -vx
5+
6+
bundle install
7+
8+
# Do any other automated setup that you need to do here

lib/zatca.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "zatca/version"
4+
5+
require "zeitwerk"
6+
7+
loader = Zeitwerk::Loader.for_gem
8+
loader.inflector.inflect(
9+
"zatca" => "ZATCA",
10+
"qr_code_generator" => "QRCodeGenerator"
11+
)
12+
loader.setup
13+
14+
module ZATCA
15+
extend self
16+
17+
class Error < StandardError; end
18+
19+
def self.render_qr_code(tags)
20+
QRCodeGenerator.new(ZATCA::Tags.new(tags)).render
21+
end
22+
end
23+
24+
loader.eager_load

lib/zatca/qr_code_generator.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require "rqrcode"
2+
3+
module ZATCA
4+
class QRCodeGenerator
5+
def initialize(tags)
6+
@tags = tags
7+
end
8+
9+
def render(size: 256)
10+
qr_code = generate
11+
12+
qr_code.as_png(size: size, border_modules: 2)&.to_data_url
13+
end
14+
15+
private
16+
17+
def generate
18+
RQRCode::QRCode.new(@tags.to_base64)
19+
end
20+
end
21+
end

lib/zatca/tag.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module ZATCA
2+
class Tag
3+
TAG_IDS = {
4+
seller_name: 1,
5+
vat_registration_number: 2,
6+
timestamp: 3,
7+
invoice_total: 4,
8+
vat_total: 5
9+
}.freeze
10+
11+
attr_accessor :id, :key, :value
12+
13+
def initialize(key:, value:)
14+
@id = TAG_IDS[key]
15+
@key = key
16+
@value = value.to_s
17+
end
18+
19+
def to_h
20+
{id: @id, key: @key, value: @value}
21+
end
22+
23+
def to_tlv
24+
# TLV should be concatenated together without any separator in the following
25+
# format: hex_value_of_id hex_value_of_length value_itself
26+
# where hex_values should be padded with a 0 if containing only a single digit.
27+
28+
sprintf("%02X%02X%s", @id, @value.length, @value)
29+
end
30+
end
31+
end

0 commit comments

Comments
 (0)