Project

croatia

0.0
The project is in a healthy, maintained state
Croatia is a gem that contains various utilities for performing Croatia-specific actions like: - PIN/OIB validation
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

>= 0
>= 0
 Project Readme

Croatia

Croatia is a gem that contains various utilities for performing Croatia-specific actions:

  • PIN (OIB)
    • Validation
  • UMCN (JMBG)
    • Validation
    • Parsing
    • Generation
  • Invoices
    • Discounts
      • Percentage
      • Total
    • Taxes
      • Types
      • Categories
    • Surcharges (Naknade)
    • Margins (Marza)
  • Payment barcodes
    • HUB3 standard 2D barcode generation
  • Fiscalization v2.3 (Fiskalizacija) [NOT YET VERIFIED]
    • Issuer protection code generation (ZKI)
    • Reverse (storno)
    • Invoices (racuni)
    • Supporting documents (prateci dokumenti - otpremnice, radni nalozi, ponude, ugovori, ...)
    • Payment method change
    • Echo
    • Verification QR code generation
  • E-Invoice (e-Racun)

Installation

You can install the gem into your app using the bundle command

bundle add croatia

or you can add it manually to your Gemfile

gem "croatia"

Usage

Configuration

Croatia.configure do |config|
  # Default tax rates
  config.tax_rates = {
    value_added_tax: {
      standard: 0.25,
      lower_rate: 0.13,
      exempt: 0.0,
      zero_rated: 0.0,
      outside_scope: 0.0,
      reverse_charge: 0.0
    },
    consumption_tax: Hash.new(0.0),
    other: Hash.new(0.0)
  }

  # Fiscalization defaults
  config.fiscalization.merge!(
    credential: "path/to/your/credential.p12", # or File.read("path/to/your/credential.p12")
    password: ENV["FISCALIZATION_CREDENTIAL_PASSWORD"],
  )
  # You can also use separate private key and certificate files instead of a full credential (.p12)
  # config.fiscalization.merge!(
  #   credential: {
  #     private_key: "path/to/your/private_key.key", # or ENV["FISCALIZATION_PRIVATE_KEY"]
  #     certificate: "path/to/your/certificate.crt", # or ENV["FISCALIZATION_CERTIFICATE"]
  #     ca_chain: ENV["FISCALIZATION_CA_CHAIN"] # optional, or "path/to/your/ca_cert.crt"
  #   },
  #   password: "credential_password" # only needed for encrypted private keys
  # )
  #
  # Additional fiscalization options
  # config.fiscalization.merge!(
  #   endpoint: :production, # Where to send fiscalization requests; can also be :test, or a custom endpoint URL like "https://fiskalizacija.example.com:1234/fiskalizacija"
  #   pool_size: 5, # Number of threads to use for fiscalization requests; with Rails you'd want to set this to ENV.fetch("RAILS_MAX_THREADS", 5).to_i
  #   pool_timeout: 5, # Timeout for each fiscalization request in seconds
  #   keep_alive_timeout: 60, # For how long to keep a connection open before closing it - speeds up consecutive requests
  # )
end

PINs

Croatia::PIN.valid?("12345678903") # => true
Croatia::PIN.valid?("12345678900") # => false

UMCNs

# Validation
Croatia::UMCN.valid?("0101990123455") # => true
Croatia::UMCN.valid?("3201990123456") # => false

# Parsing
num = Croatia::UMCN.parse("1407933312355") # => <Croatia::UMCN ...>
num.birthday # => <Date: 1933-07-14>
num.region_of_birth # => "Podravina"
num.sequence_number # => 235
num.sex # => :male
num.checksum # => 5
num.to_s # => "1407933312355"

# Generation
# Full list of region codes is available on Wikipedia:
# https://en.wikipedia.org/wiki/Unique_Master_Citizen_Number
num = Croatia::UMCN.new(
  birthday: Date.new(1988, 3, 14),
  region_code: 33, # Zagreb
  sequence_number: 123
)
num.to_s # => "1403988331237"

Invoices

# Values can be set during initialization
invoice = Croatia::Invoice.new(
  sequential_number: 64,
  register_identifier: "123",
  business_location_identifier: "HQ1",
  sequential_by: :business_location,
  payment_method: :card
)

# Or via accessors
invoice.issue_date = Time.now
invoice.due_date = invoice.issue_date + 15 * 24 * 60 * 60 # 15 days later

# Some values accept builders so you don't have to deal with initializing objects
invoice.issuer do |issuer|
  issuer.pin = "12345678903"
end
# If you don't want to use the builder you can also 
# do `invoice.issuer = Croatia::Invoice::Party.new(pin: "12345678903")`
# or set it during initialization

invoice.issuer # => <Croatia::Invoice::Party ...>

invoice.seller do |seller|
  seller.pin = "12345678903"
  seller.name = "Example Company Ltd."
  seller.address = "Example Street 1, Zagreb, Croatia"
  seller.pays_vat = true
end

invoice.buyer do |buyer|
  buyer.pin = "12345678903"
  buyer.name = "Example Client Ltd."
  buyer.address = "Client Street 2, Split, Croatia"
end

invoice.add_line_item do |line_item|
  line_item.description = "Product 1"
  line_item.quantity = 2
  line_item.unit_price = 100.0

  # Looks up the tax rate from the config
  line_item.add_tax(type: :value_added_tax, category: :standard) # PDV 25%
  # line_item.add_tax(type: :value_added_tax, category: :lower_rate) # PDV 13%
  # line_item.add_tax(type: :value_added_tax, category: :exempt) # PDV 0% - e.g. for invoices to the USA
  # line_item.add_tax(type: :value_added_tax, category: :reverse_charge) # PDV 0% - for invoices to the EU
  # line_item.add_tax(type: :value_added_tax, category: :lower_rate, rate: 0.01) # You can override the default rate

  # Set a custom tax rate
  line_item.add_tax do |tax|
    tax.type = :other
    tax.category = :lower_rate
    tax.rate = 0.05
    tax.name = "Porez na luksuz"
  end

  # Remove a tax
  # line_item.remove_tax(:other)

  # Clear all taxes
  # line_item.clear_taxes

  # Add discounts
  line_item.discount_rate = 0.1  # 10% discount
  # line_item.discount = 15.0    # Fixed discount amount (takes priority over discount_rate)

  # Add surcharges (naknade)
  line_item.add_surcharge(name: "Refundable deposit", amount: 2.50)
  line_item.add_surcharge do |surcharge|
    surcharge.name = "Handling fee"
    surcharge.amount = 1.25
  end

  # Remove a surcharge
  # line_item.remove_surcharge("Refundable deposit")

  # Clear all surcharges
  # line_item.clear_surcharges

  # Add margin (affects tax calculation base)
  line_item.margin = 15.0  # Tax will be calculated on margin instead of subtotal
end

invoice.subtotal # => BigDecimal("180.00") # 200.00 - 20.00 discount (10%)
invoice.tax # => BigDecimal("4.50") # Tax calculated on margin: 15.00 * 0.25 + 15.00 * 0.05
invoice.surcharge # => BigDecimal("3.75")
invoice.margin # => BigDecimal("15.00")
invoice.total # => BigDecimal("188.25")
invoice.total_cents # => 18825

invoice.number # => "64/HQ1/123"

Payment barcodes

# IMPORTANT: To be able to generate payment barcodes you have to add
# the "ruby-zint" gem to you Gemfile, or have it installed and required!
require "ruby-zint"

# Generate a 2D barcode which can be scanned by Croatian banking apps
# and initiate a payment
barcode = invoice.payment_barcode # => <Croatia::PaymentBarcode ...>

# You can also set the description, model and reference number
barcode = invoice.payment_barcode(
  description: "Dog walking",
  model: "HR00",
  reference_number: "202506030001"
) # => <Croatia::PaymentBarcode ...>

# Or you can create a payment barcode without an invoice
barcode = Croatia::PaymentBarcode.new(
  description: "Dog walking",

  total_cents: 15_00,
  currency: "EUR",
  model: "HR00",
  reference_number: "202506030001",
  payment_purpose_code: "OTHR",

  buyer_name: "Hrvoje Horvat",
  buyer_address: "Ilica 141",
  buyer_postal_code: 10000,
  buyer_city: "Zagreb",

  seller_name: "Example Company Ltd.",
  seller_address: "Example Street 1",
  seller_postal_code: 2100,
  seller_city: "Split",
) # => <Croatia::PaymentBarcode ...>

barcode.to_svg # => "<svg>...</svg>"
barcode.to_png # => "\b..."

Fiscalization

# Issuer protection code (ZKI) is generated automatically
invoice.issuer_protection_code # => "abcd1234efgh5678ijkl9012mnop3456"

# Fiscalize an invoice using the credential from the config
invoice.fiscalize!
# Fiscalize an invoice using a custom credential and password
invoice.fiscalize!(credential: "path/to/your/credential.p12", password: "your_password")

# In case you want to "undo" a fiscalized invoice, you can reverse the invoice
invoice.reverse!

# IMPORTANT: For QR code generation you need to have the "rqrcode" gem in yuor Gemfile
# or installed and required!
require "rqrcode"

# Generate a QR code to check the fiscalization status of the invoice
qr_code = invoice.fiscalization_qr_code # => <Croatia::QRCode ...>
qr_code.to_svg # => "<svg>...</svg>"
barcode.to_png # => "\b..."

Development

Make sure you have at least Ruby 3.1 installed. You can check your Ruby version by running ruby -v.

After checking out the repo, run bin/setup to install dependencies.

You can start an interactive shell with the gem loaded into it using bin/console.

To run the test suite use bin/test.

To lint the code, run bin/lint. The linter can also automatically fix some issues, you can run bin/lint -A to do so.

To install this gem onto your local machine, run bundle exec rake install.

To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Official documentation

Some features of this gem are based on official documentation, which can be found here

UMCN (JMBG):

Banking/payments:

Fiscalization:

E-Invoice:

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/monorkin/croatia.

License

The gem is available as open source under the terms of the MIT License.