croatia 0.2.0 → 0.3.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/lib/croatia/fiscalizer/xml_builder.rb +29 -1
- data/lib/croatia/fiscalizer.rb +36 -6
- data/lib/croatia/invoice/fiscalizable.rb +3 -32
- data/lib/croatia/invoice/payable.rb +1 -1
- data/lib/croatia/invoice.rb +4 -8
- data/lib/croatia/pdf417.rb +11 -34
- data/lib/croatia/qr_code.rb +1 -1
- data/lib/croatia/umcn.rb +172 -11
- data/lib/croatia/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 950fcecdaee0439b153f3bccc88c0dcc1bd65707200d6f88b7c08729752d0384
|
4
|
+
data.tar.gz: 56d5d0073b5059d2a70767ff82be379c92183f16a37bfcbb318c576cccc3b797
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6388cb5613f183c1bbea376ab1eb2975b9e6f90c00c98c1e272a94a69ca19819b509aadc86d27fd63f1bf194b9597b5d391598015366294dbf6c1cbebdea306
|
7
|
+
data.tar.gz: 8f27f7baabdbb619e7b3048fc34f204b7279137437e0983de40492b5e5af2c1b23ba80c03e01b3c471a035756bfc7d6cb5106a147534e4a372220b46328a3ca0
|
@@ -5,9 +5,20 @@ require "rexml/document"
|
|
5
5
|
module Croatia::Fiscalizer::XMLBuilder
|
6
6
|
TNS = "http://www.apis-it.hr/fin/2012/types/f73"
|
7
7
|
XSI = "http://www.w3.org/2001/XMLSchema-instance"
|
8
|
+
SEQUENCE_MARK = {
|
9
|
+
register: "N", # N - sequential by register
|
10
|
+
business_location: "P" # P - sequential by business location
|
11
|
+
}.freeze
|
12
|
+
PAYMENT_METHODS = {
|
13
|
+
cash: "G", # G - gotovina
|
14
|
+
card: "K", # K - kartica
|
15
|
+
check: "C", # C - ček
|
16
|
+
transfer: "T", # T - prijenos
|
17
|
+
other: "O" # O - ostalo
|
18
|
+
}.freeze
|
8
19
|
|
9
20
|
class << self
|
10
|
-
def invoice_request(invoice:, message_id:, timezone: Croatia::
|
21
|
+
def invoice_request(invoice:, message_id:, specific_purpose: nil, subsequent_delivery: false, timezone: Croatia::Fiscalizer::TZ)
|
11
22
|
REXML::Document.new.tap do |doc|
|
12
23
|
envelope = doc.add_element("tns:RacunZahtjev", {
|
13
24
|
"xmlns:tns" => TNS,
|
@@ -23,6 +34,23 @@ module Croatia::Fiscalizer::XMLBuilder
|
|
23
34
|
payload.add_element("tns:Oib").text = invoice.seller.pin
|
24
35
|
payload.add_element("tns:USustPdv").text = invoice.seller.pays_vat ? "true" : "false"
|
25
36
|
payload.add_element("tns:DatVrijeme").text = timezone.to_local(invoice.issue_date).strftime("%d.%m.%YT%H:%M:%S")
|
37
|
+
payload.add_element("tns:OznSlijed").text = SEQUENCE_MARK[invoice.sequential_by]
|
38
|
+
|
39
|
+
payload.add_element("tns:BrRac").tap do |invoice_number|
|
40
|
+
invoice_number.add_element("tns:BrOznRac").text = invoice.sequential_number.to_s
|
41
|
+
invoice_number.add_element("tns:OznPosPr").text = invoice.business_location_identifier.to_s
|
42
|
+
invoice_number.add_element("tns:OznNapUr").text = invoice.register_identifier.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
# TODO: Add taxes
|
46
|
+
|
47
|
+
payload.add_element("tns:IznosUkupno").text = invoice.total.to_f.to_s
|
48
|
+
payload.add_element("tns:NacinPlac").text = PAYMENT_METHODS[invoice.payment_method]
|
49
|
+
payload.add_element("tns:OibOper").text = invoice.issuer.pin
|
50
|
+
payload.add_element("tns:ZastKod").text = invoice.issuer_protection_code
|
51
|
+
payload.add_element("tns:NakDost").text = subsequent_delivery ? "true" : "false"
|
52
|
+
payload.add_element("tns:ParagonBrRac").text = invoice.number
|
53
|
+
payload.add_element("tns:SpecNamj").text = specific_purpose if specific_purpose
|
26
54
|
end
|
27
55
|
end
|
28
56
|
end
|
data/lib/croatia/fiscalizer.rb
CHANGED
@@ -4,11 +4,13 @@ require "digest/md5"
|
|
4
4
|
require "openssl"
|
5
5
|
require "securerandom"
|
6
6
|
require "tzinfo"
|
7
|
+
require "uri"
|
7
8
|
|
8
9
|
class Croatia::Fiscalizer
|
9
10
|
autoload :XMLBuilder, "croatia/fiscalizer/xml_builder"
|
10
11
|
|
11
12
|
TZ = TZInfo::Timezone.get("Europe/Zagreb")
|
13
|
+
QR_CODE_BASE_URL = "https://porezna.gov.hr/rn"
|
12
14
|
|
13
15
|
attr_reader :certificate
|
14
16
|
|
@@ -20,11 +22,8 @@ class Croatia::Fiscalizer
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def fiscalize(invoice:, message_id: SecureRandom.uuid)
|
23
|
-
|
24
|
-
|
25
|
-
# TODO: Implement the fiscalization logic here
|
26
|
-
puts "TODO: Fiscalize invoice #{invoice}"
|
27
|
-
puts "GENERATED XML:\n#{document}"
|
25
|
+
_document = XMLBuilder.invoice_request(invoice: invoice, message_id: message_id, timezone: TZ)
|
26
|
+
raise NotImplementedError, "Fiscalization XML generation is not implemented yet"
|
28
27
|
end
|
29
28
|
|
30
29
|
def generate_issuer_protection_code(invoice)
|
@@ -42,6 +41,34 @@ class Croatia::Fiscalizer
|
|
42
41
|
Digest::MD5.hexdigest(signature).downcase
|
43
42
|
end
|
44
43
|
|
44
|
+
def generate_verification_qr_code(invoice)
|
45
|
+
Croatia::QRCode.ensure_supported!
|
46
|
+
|
47
|
+
params = {
|
48
|
+
datv: TZ.to_local(invoice.issue_date).strftime("%Y%m%d_%H%M"),
|
49
|
+
izn: invoice.total_cents.to_s
|
50
|
+
}
|
51
|
+
|
52
|
+
if params[:izn].length > 10
|
53
|
+
raise ArgumentError, "Total amount exceeds 10 digits: #{params[:izn]}"
|
54
|
+
end
|
55
|
+
|
56
|
+
if invoice.unique_invoice_identifier
|
57
|
+
params[:jir] = invoice.unique_invoice_identifier
|
58
|
+
else
|
59
|
+
params[:zki] = generate_issuer_protection_code(invoice)
|
60
|
+
end
|
61
|
+
|
62
|
+
if params[:jir].nil? && params[:zki].nil?
|
63
|
+
raise ArgumentError, "Either unique_invoice_identifier or issuer_protection_code must be provided"
|
64
|
+
end
|
65
|
+
|
66
|
+
query_string = URI.encode_www_form(params)
|
67
|
+
url = "#{QR_CODE_BASE_URL}?#{query_string}"
|
68
|
+
|
69
|
+
Croatia::QRCode.new(url)
|
70
|
+
end
|
71
|
+
|
45
72
|
private
|
46
73
|
|
47
74
|
def load_certificate(cert, password)
|
@@ -50,7 +77,10 @@ class Croatia::Fiscalizer
|
|
50
77
|
elsif cert.is_a?(OpenSSL::PKey::PKey)
|
51
78
|
cert
|
52
79
|
else
|
53
|
-
|
80
|
+
begin
|
81
|
+
cert = File.read(cert) if cert.respond_to?(:to_s) && File.exist?(cert.to_s)
|
82
|
+
rescue ArgumentError
|
83
|
+
end
|
54
84
|
|
55
85
|
begin
|
56
86
|
OpenSSL::PKey.read(cert)
|
@@ -1,10 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "uri"
|
4
|
-
|
5
3
|
module Croatia::Invoice::Fiscalizable
|
6
|
-
QR_CODE_BASE_URL = "https://porezna.gov.hr/rn"
|
7
|
-
|
8
4
|
def self.included(base)
|
9
5
|
base.include InstanceMethods
|
10
6
|
end
|
@@ -26,34 +22,9 @@ module Croatia::Invoice::Fiscalizable
|
|
26
22
|
end
|
27
23
|
|
28
24
|
def fiscalization_qr_code(**options)
|
29
|
-
Croatia::
|
30
|
-
|
31
|
-
|
32
|
-
datv: issue_date.strftime("%Y%m%d_%H%M"),
|
33
|
-
izn: total_cents.to_s
|
34
|
-
}
|
35
|
-
|
36
|
-
if params[:izn].length > 10
|
37
|
-
raise ArgumentError, "Total amount exceeds 10 digits: #{params[:izn]}"
|
38
|
-
end
|
39
|
-
|
40
|
-
uii = options[:unique_invoice_identifier] || unique_invoice_identifier
|
41
|
-
|
42
|
-
if uii
|
43
|
-
params[:jir] = uii
|
44
|
-
elsif !params[:zki]
|
45
|
-
ipc = issuer_protection_code(**options)
|
46
|
-
params[:zki] = ipc
|
47
|
-
end
|
48
|
-
|
49
|
-
if (params[:jir] && params[:zki]) || (params[:jir].nil? && params[:zki].nil?)
|
50
|
-
raise ArgumentError, "Either unique_invoice_identifier or issuer_protection_code must be provided"
|
51
|
-
end
|
52
|
-
|
53
|
-
query_string = URI.encode_www_form(params)
|
54
|
-
url = "#{QR_CODE_BASE_URL}?#{query_string}"
|
55
|
-
|
56
|
-
Croatia::QRCode.new(url)
|
25
|
+
Croatia::Fiscalizer
|
26
|
+
.new(**options)
|
27
|
+
.generate_verification_qr_code(self)
|
57
28
|
end
|
58
29
|
end
|
59
30
|
end
|
data/lib/croatia/invoice.rb
CHANGED
@@ -10,7 +10,6 @@ class Croatia::Invoice
|
|
10
10
|
autoload :Party, "croatia/invoice/party"
|
11
11
|
autoload :Tax, "croatia/invoice/tax"
|
12
12
|
autoload :LineItem, "croatia/invoice/line_item"
|
13
|
-
autoload :Fiscalizer, "croatia/invoice/fiscalizer"
|
14
13
|
|
15
14
|
include Croatia::Enum
|
16
15
|
include Fiscalizable
|
@@ -27,16 +26,13 @@ class Croatia::Invoice
|
|
27
26
|
:sequential_number, # redni broj racuna
|
28
27
|
:unique_invoice_identifier # jir
|
29
28
|
|
30
|
-
enum :payment_method,
|
31
|
-
|
32
|
-
card: "K",
|
33
|
-
check: "C",
|
34
|
-
transfer: "T",
|
35
|
-
other: "O"
|
36
|
-
}.freeze, allow_nil: true, prefix: :payment_method
|
29
|
+
enum :payment_method, %i[ cash card check transfer other ].freeze, allow_nil: true, prefix: :payment_method
|
30
|
+
enum :sequential_by, %i[ register business_location ].freeze, allow_nil: true, prefix: :sequential_by
|
37
31
|
|
38
32
|
def initialize(**options)
|
39
33
|
self.line_items = options.delete(:line_items) { [] }
|
34
|
+
self.payment_method = :card
|
35
|
+
self.sequential_by = :register
|
40
36
|
|
41
37
|
options.each do |key, value|
|
42
38
|
public_send("#{key}=", value)
|
data/lib/croatia/pdf417.rb
CHANGED
@@ -4,11 +4,11 @@ class Croatia::PDF417
|
|
4
4
|
def self.ensure_supported!
|
5
5
|
return if supported?
|
6
6
|
|
7
|
-
raise LoadError, "
|
7
|
+
raise LoadError, "Zint library is not loaded. Please ensure you have the ruby-zint gem installed and required."
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.supported?
|
11
|
-
defined?(
|
11
|
+
defined?(Zint)
|
12
12
|
end
|
13
13
|
|
14
14
|
attr_reader :data, :options
|
@@ -19,36 +19,17 @@ class Croatia::PDF417
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_svg(**options)
|
22
|
-
|
22
|
+
vec = barcode.to_vector
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
options[:x_scale] ||= 1
|
29
|
-
options[:y_scale] ||= 1
|
30
|
-
options[:margin] ||= 10
|
31
|
-
|
32
|
-
full_width = (ary.first.size * options[:x_scale]) + (options[:margin] * 2)
|
33
|
-
full_height = (ary.size * options[:y_scale]) + (options[:margin] * 2)
|
34
|
-
|
35
|
-
dots = ary.map { |l| l.chars.map { |c| c == "1" } }
|
24
|
+
foreground_color = options[:foreground_color] || "black"
|
25
|
+
background_color = options[:background_color] || "white"
|
36
26
|
|
37
27
|
svg = []
|
38
|
-
svg << %Q(
|
39
|
-
svg << %Q(<
|
40
|
-
svg << %Q(<rect width="100%" height="100%" fill="white" />)
|
28
|
+
svg << %Q(<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="#{vec.width.to_i}" height="#{vec.height.to_i}" viewBox="0 0 #{vec.width.to_i} #{vec.height.to_i}">)
|
29
|
+
svg << %Q(<rect width="#{vec.width.to_i}" height="#{vec.height.to_i}" fill="#{background_color}" />)
|
41
30
|
|
42
|
-
|
43
|
-
|
44
|
-
x = options[:margin]
|
45
|
-
line.each do |bar|
|
46
|
-
if bar
|
47
|
-
svg << %Q(<rect x="#{x}" y="#{y}" width="#{options[:x_scale]}" height="#{options[:y_scale]}" fill="black" />)
|
48
|
-
end
|
49
|
-
x += options[:x_scale]
|
50
|
-
end
|
51
|
-
y += options[:y_scale]
|
31
|
+
vec.each_rectangle do |rect|
|
32
|
+
svg << %Q(<rect x="#{rect.x.to_i}" y="#{rect.y.to_i}" width="#{rect.width.to_i}" height="#{rect.height.to_i}" fill="#{foreground_color}" />)
|
52
33
|
end
|
53
34
|
|
54
35
|
svg << "</svg>"
|
@@ -56,16 +37,12 @@ class Croatia::PDF417
|
|
56
37
|
end
|
57
38
|
|
58
39
|
def to_png(**options)
|
59
|
-
barcode.
|
40
|
+
barcode.to_memory_file(extension: ".png")
|
60
41
|
end
|
61
42
|
|
62
43
|
private
|
63
44
|
|
64
45
|
def barcode
|
65
|
-
@barcode ||=
|
66
|
-
end
|
67
|
-
|
68
|
-
def bar
|
69
|
-
barcode.instance_variable_get(:@bar)
|
46
|
+
@barcode ||= Zint::Barcode.new(**options, value: data, symbology: Zint::BARCODE_PDF417)
|
70
47
|
end
|
71
48
|
end
|
data/lib/croatia/qr_code.rb
CHANGED
@@ -4,7 +4,7 @@ class Croatia::QRCode
|
|
4
4
|
def self.ensure_supported!
|
5
5
|
return if supported?
|
6
6
|
|
7
|
-
raise LoadError, "RQRCode library is not loaded. Please ensure you have the rqrcode gem installed."
|
7
|
+
raise LoadError, "RQRCode library is not loaded. Please ensure you have the rqrcode gem installed and required."
|
8
8
|
end
|
9
9
|
|
10
10
|
def self.supported?
|
data/lib/croatia/umcn.rb
CHANGED
@@ -2,29 +2,190 @@
|
|
2
2
|
|
3
3
|
# JMBG - Jedinstveni Matični Broj Građana
|
4
4
|
# UMCN - Unique Master Citizen Number
|
5
|
-
|
5
|
+
class Croatia::UMCN
|
6
|
+
WEIGHTS = [ 7, 6, 5, 4, 3, 2, 7, 6, 5, 4, 3, 2 ]
|
7
|
+
REGION_CODES = {
|
8
|
+
# Special / Foreign
|
9
|
+
0 => "Yugoslavia",
|
10
|
+
1 => "Foreigner in BiH",
|
11
|
+
2 => "Foreigner in Montenegro",
|
12
|
+
3 => "Foreigner in Croatia",
|
13
|
+
4 => "Foreigner in North Macedonia",
|
14
|
+
5 => "Foreigner in Slovenia",
|
15
|
+
6 => "Foreigner in Serbia",
|
16
|
+
7 => "Foreigner in Vojvodina",
|
17
|
+
8 => "Foreigner in Kosovo",
|
18
|
+
9 => "Yugoslavia",
|
19
|
+
|
20
|
+
# Bosnia and Herzegovina (10–19)
|
21
|
+
10 => "Banja Luka",
|
22
|
+
11 => "Bihac",
|
23
|
+
12 => "Doboj",
|
24
|
+
13 => "Gorazde",
|
25
|
+
14 => "Livno",
|
26
|
+
15 => "Mostar",
|
27
|
+
16 => "Prijedor",
|
28
|
+
17 => "Sarajevo",
|
29
|
+
18 => "Tuzla",
|
30
|
+
19 => "Zenica",
|
31
|
+
|
32
|
+
# Montenegro (21–29)
|
33
|
+
21 => "Podgorica",
|
34
|
+
22 => "Bar",
|
35
|
+
23 => "Budva",
|
36
|
+
24 => "Herceg Novi",
|
37
|
+
25 => "Cetinje",
|
38
|
+
26 => "Niksic",
|
39
|
+
27 => "Berane",
|
40
|
+
28 => "Bijelo Polje",
|
41
|
+
29 => "Pljevlja",
|
42
|
+
|
43
|
+
# Croatia (30–39)
|
44
|
+
30 => "Slavonia",
|
45
|
+
31 => "Podravina",
|
46
|
+
32 => "Medimurje",
|
47
|
+
33 => "Zagreb",
|
48
|
+
34 => "Kordun",
|
49
|
+
35 => "Lika",
|
50
|
+
36 => "Istria",
|
51
|
+
37 => "Banovina",
|
52
|
+
38 => "Dalmatia",
|
53
|
+
39 => "Zagorje",
|
54
|
+
|
55
|
+
# North Macedonia (41–49)
|
56
|
+
41 => "Bitola",
|
57
|
+
42 => "Kumanovo",
|
58
|
+
43 => "Ohrid",
|
59
|
+
44 => "Prilep",
|
60
|
+
45 => "Skopje",
|
61
|
+
46 => "Strumica",
|
62
|
+
47 => "Tetovo",
|
63
|
+
48 => "Veles",
|
64
|
+
49 => "Stip",
|
65
|
+
|
66
|
+
# Slovenia (50)
|
67
|
+
50 => "Slovenia",
|
68
|
+
|
69
|
+
# Serbia (70–79)
|
70
|
+
70 => "Serbia Abroad",
|
71
|
+
71 => "Belgrade",
|
72
|
+
72 => "Sumadija",
|
73
|
+
73 => "Nis",
|
74
|
+
74 => "Morava",
|
75
|
+
75 => "Zajecar",
|
76
|
+
76 => "Podunavlje",
|
77
|
+
77 => "Kolubara",
|
78
|
+
78 => "Kraljevo",
|
79
|
+
79 => "Uzice",
|
80
|
+
|
81
|
+
# Vojvodina (80–89)
|
82
|
+
80 => "Novi Sad",
|
83
|
+
81 => "Sombor",
|
84
|
+
82 => "Subotica",
|
85
|
+
83 => "Zrenjanin",
|
86
|
+
84 => "Kikinda",
|
87
|
+
85 => "Pancevo",
|
88
|
+
86 => "Vrbas",
|
89
|
+
87 => "Sremska Mitrovica",
|
90
|
+
88 => "Ruma",
|
91
|
+
89 => "Backa Topola",
|
92
|
+
|
93
|
+
# Kosovo (90–99)
|
94
|
+
90 => "Pristina",
|
95
|
+
91 => "Prizren",
|
96
|
+
92 => "Pec",
|
97
|
+
93 => "Djakovica",
|
98
|
+
94 => "Mitrovica",
|
99
|
+
95 => "Gnjilane",
|
100
|
+
96 => "Ferizaj",
|
101
|
+
97 => "Decan",
|
102
|
+
98 => "Klina",
|
103
|
+
99 => "Malisevo"
|
104
|
+
}.freeze
|
105
|
+
|
106
|
+
|
107
|
+
attr_accessor :birthday, :region_code, :sequence_number, :checkusm
|
108
|
+
|
6
109
|
def self.valid?(umcn)
|
7
|
-
return false
|
110
|
+
return false if umcn.nil?
|
111
|
+
return false unless umcn.match?(/\A\d{13}\Z/)
|
112
|
+
|
113
|
+
parse(umcn).checksum == umcn.strip[-1].to_i
|
114
|
+
rescue Date::Error, ArgumentError
|
115
|
+
false
|
116
|
+
end
|
8
117
|
|
118
|
+
def self.parse(umcn)
|
9
119
|
digits = umcn.chars.map(&:to_i)
|
10
120
|
|
11
121
|
day = digits[0..1].join.to_i
|
12
122
|
month = digits[2..3].join.to_i
|
13
123
|
year = digits[4..6].join.to_i
|
14
|
-
|
124
|
+
millenium = case digits[4]
|
15
125
|
when 0 then 2000
|
16
|
-
|
17
|
-
|
126
|
+
else 1000
|
127
|
+
end
|
128
|
+
full_year = millenium + year
|
129
|
+
|
130
|
+
birthday = Date.new(full_year, month, day)
|
131
|
+
region_code = digits[7..8].join.to_i
|
132
|
+
sequence_number = digits[9..11].join.to_i
|
133
|
+
|
134
|
+
new(birthday: birthday, region_code: region_code, sequence_number: sequence_number)
|
135
|
+
end
|
136
|
+
|
137
|
+
def initialize(birthday:, region_code:, sequence_number:)
|
138
|
+
@birthday = birthday
|
139
|
+
@region_code = region_code
|
140
|
+
@sequence_number = sequence_number
|
141
|
+
end
|
142
|
+
|
143
|
+
def region_code=(value)
|
144
|
+
value = value.to_i
|
145
|
+
|
146
|
+
if REGION_CODES.key?(value)
|
147
|
+
@region_code = value
|
148
|
+
else
|
149
|
+
raise ArgumentError, "Invalid region code: #{value}"
|
18
150
|
end
|
19
|
-
|
151
|
+
end
|
20
152
|
|
21
|
-
|
153
|
+
def sequence_number=(value)
|
154
|
+
value = value.to_i
|
155
|
+
|
156
|
+
if value < 0 || value > 999
|
157
|
+
raise ArgumentError, "Sequence number must be between 0 and 999"
|
158
|
+
end
|
159
|
+
|
160
|
+
@sequence_number = value
|
161
|
+
end
|
22
162
|
|
23
|
-
|
24
|
-
|
163
|
+
def sex
|
164
|
+
sequence_number <= 499 ? :male : :female
|
165
|
+
end
|
166
|
+
|
167
|
+
def region_of_birth
|
168
|
+
REGION_CODES[region_code]
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_s
|
172
|
+
parts = []
|
173
|
+
parts << birthday.strftime("%d%m")
|
174
|
+
parts << format("%03d", birthday.year % 1000)
|
175
|
+
parts << format("%02d", region_code)
|
176
|
+
parts << format("%03d", sequence_number)
|
177
|
+
|
178
|
+
digits = parts.join.chars.map(&:to_i)
|
179
|
+
sum = digits.each_with_index.sum { |digit, i| digit * WEIGHTS[i] }
|
25
180
|
mod = sum % 11
|
26
|
-
checksum = mod == 0 || mod == 1 ? 0 : 11 - mod
|
27
181
|
|
28
|
-
|
182
|
+
checksum = (mod == 0 || mod == 1) ? 0 : (11 - mod)
|
183
|
+
|
184
|
+
parts << checksum.to_s
|
185
|
+
parts.join
|
186
|
+
end
|
187
|
+
|
188
|
+
def checksum
|
189
|
+
to_s[-1].to_i
|
29
190
|
end
|
30
191
|
end
|
data/lib/croatia/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: croatia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stanko K.R.
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-06-
|
10
|
+
date: 2025-06-04 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: openssl
|