fiskalhrgo

package module
v0.1.5-alpha.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 20, 2024 License: MIT Imports: 27 Imported by: 0

README

   ___ _     _         _         __     ___        _ 
  / __(_)___| | ____ _| | /\  /\/__\   / _ \___   / \
 / _\ | / __| |/ / _` | |/ /_/ / \//  / /_\/ _ \ /  /
/ /   | \__ \   < (_| | / __  / _  \ / /_\\ (_) /\_/ 
\/    |_|___/_|\_\__,_|_\/ /_/\/ \_/ \____/\___/\/         

Test CodeQL Go Report Card Go version Go Reference

FiskalHR Go

Overview

FiskalHR Go is a Go library designed for Croatian fiscalization (fiskalizacija). The goal of this library is to provide a well-maintained, efficient, and hassle-free solution with embedded certificates for checking signatures, making it easy to use. Based on "Fiskalizacija" specification v2.5

Note: This project is currently a work in progress and alpha stage and not feature complete, not recommended in production but coming soon.

README in Croatian

Why this project?

While there are numerous open-source implementations of Croatian fiscalization libraries available, they tend to focus on other programming languages. However, after some research, it became clear that an open-source solution in Go (Golang) is hard to come by. To fill this gap, we're developing a pure Go open-source Croatian fiscalization library (package). So here we Go! ;)

Features

  • Process and send invoices to CIS (Croatian Tax Administration) for compliance the law.
  • Handle and verify responses from CIS.
  • Non-intrusive to the host application, leaving business logic entirely to the host.
  • Parse and verify embedded certificates.
  • Parse and verify client P12 certificate.
  • Suitable for single tenant and multitenant application
  • Suitable for any type of application (web service, web app, desktop)
  • Extract and return certificate details such as public key, issuer, subject, serial number, and validity period.
  • Helper function to get data for QR code (that can be passed to a QR code generator of your choice)

Go Version Compatibility

  • Minimum tested and supported version: Go 1.22
  • Recommended version: Go 1.23.1+ for best performance

Installation

In your project root get the module

go get github.com/l-d-t/fiskalhrgo

Usage

Minimal simple example of CIS ping using the EchoRequest and get some cert info.

Send a simple minimal invoice, get the JIR

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/l-d-t/fiskalhrgo"
)

func main() {
    // Create a new FiskalEntity
    fiskalEntity, err := NewFiskalEntity(
        "12345678901", // OIB
        true,          // sustavPDV
        "Location1",   // locationID, if not DEMO MODE have to be registered
                      // with ePorezna
        true,          // centralized invoice numbers
        true,          // demoMode, if true expected a valid Fiskal demo
                      // certificate
        true,          // chk_expired
        "cert.p12",    // certPath
        "password",    // certPassword
    )
    if err != nil {
        log.Fatalf("Failed to create FiskalEntity: %v", err)
    }

    errPing := fiskalEntity.PingCIS()
    if errPing != nil {
        log.Fatalf("Failed to make Ping request: %v", err)
    }

    // Get certificate basic info
    if fiskalEntity.IsExpiringSoon() {
        fmt.Println("WARNING: Certificate is expiring soon")
        fmt.Printf("Certificate expires in %d days",
            fiskalEntity.DaysUntilExpire())
    }

    // Display certificate info
    fmt.Println(fiskalEntity.DisplayCertInfoText())

    invoice, zki, err := fiskalEntity.NewCISInvoice(
        time.Now(),
        uint(1236), // invoice number
        uint(1),    // register id number
        [][]interface{}{ // PDV
            {"25.00", "1000.00", "250.00"},
        },
        nil, // PNP
        nil, // Other taxes
        "0.00", // total amount of exemptions on the issued invoice. 
                // Exemptions in cases where goods are delivered or services are
                // provided that are exempt from VAT payment.
        "0.00", // amount subject to the special margin taxation procedure 
                // if exist
        "0.00", // total amount not subject to taxation on the issued invoice. 
                // This information is submitted to the Tax Administration only
                // if there is an amount on the invoice that is not subject to
                // taxation.
        nil,           // naknade
        "1250.00",     // total
        "G",           // payment method G - cash, K - credit card, T -
                       // transfer, O - other, C - check (deprecated)
        "12345678901", // operator OIB
    )

    if err != nil {
        log.Fatalf("Failed to create invoice: %v", err)
    }

    // Display the ZKI
    fmt.Println("ZKI: ", zki)

    // At this point, the application can save the ZKI with the invoice and
    // commit those changes. An invoice is valid with just ZKI and can be
    // issued even if the next step fails and there is no JIR. But in that case,
    // the process has to be repeated with the same identical data within 48h
    // with the flag for late delivery set to true. A valid JIR has to be added
    // within 48h to an invoice with just ZKI. It is recommended to save the
    // serial of the certificate used to generate it for future reference. You
    // can get the cert serial with fiskalEntity.GetCertSERIAL().

    // Display the invoice for test
    fmt.Println(invoice)

    // NOW we should have a saved invoice with a valid ZKI and we are ready to
    // send the invoice to the CIS

    // Send test invoice to CIS with InvoiceRequest
    jir, zkiR, err := invoice.InvoiceRequest()

    if err != nil {
        log.Fatalf("Failed to send invoice: %v", err)
    }

    // Display the JIR and ZKI
    fmt.Println("JIR: ", jir)
    fmt.Println("ZKI: ", zkiR)

    // At this point the application can save the JIR with the invoice and
    // commit those changes,

    // Display/send/print the invoice to the user with all elements required by
    // law
}

Commercial and Professional Support

For commercial support, long-term maintenance contracts, and/or consulting or development services, contact LDT or send an email to info@ldt.hr.

Custom commercial versions for your specific needs in Go or other technologies (C, Zig, Rust, Python, PHP, Mojo, OCaml, Swift, Objective-C) or for specific platforms or embedded devices are also possible. Full custom (or not) business/invoicing/erp commercial solutions either as a product or SaaS are also possible.

Sponsors

LDT Logo

If you are interested in sponsoring the project as a company or individual, contact us at oss@ldt.hr.

Contributors

Contributors are welcome! You can contribute to the development in the following ways:

  • Testing
  • Reporting issues
  • Writing documentation
  • Translating documentation
  • Submitting pull requests for new features or improving existing ones (recommended to contact and consult before doing the work)

Your contribution is invaluable and helps us create a better product for the community.

Note for Running Tests

You can run tests with verbose output with

go test -v

Before running some environment variables must be se

The CIS_P12_BASE64 environment variable must contain a single-line base64 encoded string of the original valid Fiskal certificate in P12 format. This encoded string is essential for the tests to interact with the CIS (Croatian Fiscalization System).

To encode your P12 certificate file (e.g., fiskalDemo1.p12) to a single-line base64 string on a Linux system, use the following command:

base64 -w 0 fiskal1.p12

Then, set the CIS_P12_BASE64 environment variable with the encoded string.

Additionally, ensure that the FISKALHRGO_TEST_CERT_PASSWORD and FISKALHRGO_TEST_CERT_OIB environment variables are set with the appropriate certificate password and OIB (Personal Identification Number) respectively.

This system is used for the tests because these tests will run in CI (Continuous Integration), so secrets, for example on GitHub, are passed as environment variables. This makes it easy and convenient to manage. The certificate, password, and OIB for tests can be easily stored as GitHub Action secrets, for example.

Documentation

Index

Constants

View Source
const (
	DefaultPrefix = "ds"
	Namespace     = "http://www.w3.org/2000/09/xmldsig#"
)
View Source
const (
	SignatureTag              = "Signature"
	SignedInfoTag             = "SignedInfo"
	CanonicalizationMethodTag = "CanonicalizationMethod"
	SignatureMethodTag        = "SignatureMethod"
	ReferenceTag              = "Reference"
	TransformsTag             = "Transforms"
	TransformTag              = "Transform"
	DigestMethodTag           = "DigestMethod"
	DigestValueTag            = "DigestValue"
	SignatureValueTag         = "SignatureValue"
	KeyInfoTag                = "KeyInfo"
	X509DataTag               = "X509Data"
	X509CertificateTag        = "X509Certificate"
	InclusiveNamespacesTag    = "InclusiveNamespaces"
)

Tags

View Source
const (
	AlgorithmAttr  = "Algorithm"
	URIAttr        = "URI"
	DefaultIdAttr  = "Id"
	PrefixListAttr = "PrefixList"
)
View Source
const (
	RSASHA1SignatureMethod     = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
	RSASHA256SignatureMethod   = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
	RSASHA384SignatureMethod   = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
	RSASHA512SignatureMethod   = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
	ECDSASHA1SignatureMethod   = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"
	ECDSASHA256SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"
	ECDSASHA384SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"
	ECDSASHA512SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"
)
View Source
const DefaultNamespace = "http://www.apis-it.hr/fin/2012/types/f73"

Variables

This section is empty.

Functions

func IsFileReadable

func IsFileReadable(filePath string) bool

IsFileReadable checks if the given file exists and is readable. It returns true if the file exists and is readable, otherwise false.

func IsValidCurrencyFormat

func IsValidCurrencyFormat(amount string) bool

Helper function to validate if the string is a valid currency format (with 2 decimal places)

func IsValidTaxRate

func IsValidTaxRate(rate string) bool

IsValidTaxRate checks if the given string is a valid non-negative tax rate with exactly two decimal places. Allows positive values and 0.00, but not negative values.

func ValidateJIR

func ValidateJIR(jir string) bool

ValidateJIR checks if the given JIR is a valid UUID format (e.g., "9d6f5bb6-da48-4fcd-a803-4586a025e0e4"). Returns true if valid, otherwise false.

func ValidateLocationID

func ValidateLocationID(locationID string) bool

ValidateLocationID validates the locationID It can contain only digits (0-9) and letters (a-z, A-Z), with a maximum length of 20.

func ValidateOIB

func ValidateOIB(oib string) bool

ValidateOIB checks if an OIB is valid using the Mod 11, 10 algorithm

func ValidateZKI

func ValidateZKI(zki string) bool

ValidateZKI checks if the given ZKI is a valid MD5 hash in hexadecimal format (32 characters). Returns true if valid, otherwise false.

Types

type AlgorithmID

type AlgorithmID string
const (
	// Supported canonicalization algorithms
	CanonicalXML10ExclusiveAlgorithmId             AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#"
	CanonicalXML10ExclusiveWithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"

	CanonicalXML11AlgorithmId             AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11"
	CanonicalXML11WithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11#WithComments"

	CanonicalXML10RecAlgorithmId          AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
	CanonicalXML10WithCommentsAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"

	EnvelopedSignatureAltorithmId AlgorithmID = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
)

Well-known signature algorithms

func (AlgorithmID) String

func (id AlgorithmID) String() string

type BrojPDType

type BrojPDType struct {
	BrOznPD  int    `xml:"tns:BrOznPD"`
	OznPosPr string `xml:"tns:OznPosPr"`
	OznNapUr int    `xml:"tns:OznNapUr"`
}

BrojPDType ...

type BrojRacunaType

type BrojRacunaType struct {
	BrOznRac uint   `xml:"tns:BrOznRac"`
	OznPosPr string `xml:"tns:OznPosPr"`
	OznNapUr uint   `xml:"tns:OznNapUr"`
}

BrojRacunaType ...

type Canonicalizer

type Canonicalizer interface {
	Canonicalize(el *etree.Element) ([]byte, error)
	Algorithm() AlgorithmID
}

Canonicalizer is an implementation of a canonicalization algorithm.

func MakeC14N10ExclusiveCanonicalizerWithPrefixList

func MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList string) Canonicalizer

MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer from a PrefixList in NMTOKENS format (a white space separated list).

func MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList

func MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList(prefixList string) Canonicalizer

MakeC14N10ExclusiveWithCommentsCanonicalizerWithPrefixList constructs an exclusive Canonicalizer from a PrefixList in NMTOKENS format (a white space separated list).

func MakeC14N10RecCanonicalizer

func MakeC14N10RecCanonicalizer() Canonicalizer

MakeC14N10RecCanonicalizer constructs an inclusive canonicalizer.

func MakeC14N10WithCommentsCanonicalizer

func MakeC14N10WithCommentsCanonicalizer() Canonicalizer

MakeC14N10WithCommentsCanonicalizer constructs an inclusive canonicalizer.

func MakeC14N11Canonicalizer

func MakeC14N11Canonicalizer() Canonicalizer

MakeC14N11Canonicalizer constructs an inclusive canonicalizer.

func MakeC14N11WithCommentsCanonicalizer

func MakeC14N11WithCommentsCanonicalizer() Canonicalizer

MakeC14N11WithCommentsCanonicalizer constructs an inclusive canonicalizer.

func MakeNullCanonicalizer

func MakeNullCanonicalizer() Canonicalizer

type EchoRequest

type EchoRequest struct {
	XMLName xml.Name `xml:"tns:EchoRequest"`
	Xmlns   string   `xml:"xmlns:tns,attr"` // Declare the tns namespace
	Text    string   `xml:",chardata"`
}

EchoRequest represents a simple request with a text body

type EchoResponse

type EchoResponse struct {
	XMLName xml.Name `xml:"EchoResponse"`
	Text    string   `xml:",chardata"`
}

EchoResponse represents a simple response with a text body

type FiskalEntity

type FiskalEntity struct {
	// contains filtered or unexported fields
}

FiskalEntity represents an entity involved in the fiscalization process. It contains essential information and configurations required for generating and verifying fiscal invoices in compliance with Croatian fiscalization laws.

func NewFiskalEntity

func NewFiskalEntity(oib string, sustavPDV bool, locationID string, centralizedInvoiceNumber bool, demoMode bool, chk_expired bool, certPath string, certPassword string) (*FiskalEntity, error)

NewFiskalEntity creates a new FiskalEntity with provided values, validates certificates and input before returning an entity.

Parameters:

  • oib: The taxpayer's OIB, which will be validated against the OIB in the certificate.
  • sustavPDV: If true, the entity is part of the VAT system and will include VAT in the invoices.
  • locationID: The unique identifier of the location where fiscalization is taking place. This identifier must be registered with ePorezna, is case-sensitive, and must be identical to the one registered there. If using in demo mode the location don't have to be registered. And can use any alphanumeric value.
  • centralizedInvoiceNumber: If true, invoice numbers are centralized for the entire location. If not, each register device within the location has its own sequence of invoice numbers.
  • demoMode: If true, the entity is in demo mode and will use the demo CIS certificate and endpoint.
  • chk_expired: If true, the entity creation will fail if the certificate is expired (recommended).
  • certPath, certPassword: These are required if certManager is nil and are used to load the certificate.

Certificate Handling and Expiry:

  • If the certificate is expired and the `chk_expired` flag is set to true, the entity creation will fail. This is recommended as invoices signed with an expired certificate will be rejected by the Croatian CIS, and no JIR (unique invoice identifier) will be returned.
  • The `chk_expired` flag exists for situations where an expired certificate must be loaded, such as when recalculating the ZKI for older invoices. This is sometimes required by law during an inspection to prove that the invoice was not modified after the original fiscalization took place. It is recommended to save for each invoice a pointer or identifier of certificate used to generate the ZKI at the time not only the ZKI itself. And to keep in store old certificates. Normally fiskal certificates are valid for 5 years.

Best Practices:

  • It is advisable to retain old certificates even after they expire, along with the ZKI, JIR, and the certificate's serial number or fingerprint. This ensures traceability and proof of which certificate was used to sign each invoice.
  • While expired certificates may be loaded to handle historical cases, it is mandatory to always use a valid, non-expired certificate when generating and sending new invoices.

Returns:

  • (*FiskalEntity, error): A pointer to a new FiskalEntity instance with the provided values, or an error if the input is invalid.

func (*FiskalEntity) CentralizedInvoiceNumber

func (fe *FiskalEntity) CentralizedInvoiceNumber() bool

CentralizedInvoiceNumber specifies whether invoice numbers are centralized per locationID. Or each register device within the location has its own sequence of invoice numbers.

func (*FiskalEntity) DaysUntilExpire

func (fe *FiskalEntity) DaysUntilExpire() uint16

DaysUntilExpire returns the number of days until the certificate expires. This provides a countdown of days remaining before the certificate becomes invalid.

func (*FiskalEntity) DemoMode

func (fe *FiskalEntity) DemoMode() bool

DemoMode indicates whether the entity is in demo mode (Demo Fiskalizacija).

func (*FiskalEntity) DisplayCertInfoHTML

func (fe *FiskalEntity) DisplayCertInfoHTML() string

func (*FiskalEntity) DisplayCertInfoKeyPoints

func (fe *FiskalEntity) DisplayCertInfoKeyPoints() [][2]string

func (*FiskalEntity) DisplayCertInfoMarkdown

func (fe *FiskalEntity) DisplayCertInfoMarkdown() string

func (*FiskalEntity) DisplayCertInfoText

func (fe *FiskalEntity) DisplayCertInfoText() string

func (*FiskalEntity) EchoRequest

func (fe *FiskalEntity) EchoRequest(text string) (string, error)

EchoRequest sends an echo request to CIS and processes the response.

func (*FiskalEntity) GenerateZKI

func (entity *FiskalEntity) GenerateZKI(issueDateTime time.Time, invoiceNumber uint, deviceID uint, totalAmount string) (string, error)

GenerateZKI generates the ZKI (Zaštitni Kod Izdavatelja) based on the given data. The ZKI is a unique identifier for the invoice, generated by signing the concatenated invoice data with the taxpayer's private key and hashing the signature.

Parameters:

  • ssueDateTime time.Time: The date and time when the invoice was issued.
  • invoiceNumber uint: The unique number of the invoice.
  • deviceID uint: The unique identifier of the device issuing the invoice.
  • totalAmount string: The total amount of the invoice, formatted as a string with 2 decimal places (e.g., "100.00").

Returns:

  • string: The generated ZKI as a hexadecimal string.
  • error: An error if the ZKI generation fails, otherwise nil.

func (*FiskalEntity) GetCertORG

func (fe *FiskalEntity) GetCertORG() string

GetCertORG returns the organization name from the certificate. The organization name is typically included in the certificate's subject field.

func (*FiskalEntity) GetCertSERIAL

func (fe *FiskalEntity) GetCertSERIAL() string

GetCertSERIAL returns the serial number from the certificate. The serial number is a unique identifier assigned by the certificate issuer.

func (*FiskalEntity) GetResponse

func (fe *FiskalEntity) GetResponse(xmlPayload []byte, sign bool) ([]byte, int, error)

GetResponse wraps the XML payload in a SOAP envelope, makes an HTTPS request, and returns the extracted response body. - Input: XML payload - Output: Response body, error, HTTP status code

func (*FiskalEntity) IsExpired

func (fe *FiskalEntity) IsExpired() bool

IsExpired returns whether the certificate is expired. This indicates if the certificate's validity period has ended.

func (*FiskalEntity) IsExpiringSoon

func (fe *FiskalEntity) IsExpiringSoon() bool

IsExpiringSoon returns whether the certificate is expiring soon. This indicates if the certificate is approaching its expiration date.

func (*FiskalEntity) LocationID

func (fe *FiskalEntity) LocationID() string

LocationID returns the unique identifier of the location where the fiscalization is taking place.

func (*FiskalEntity) NewCISInvoice

func (fe *FiskalEntity) NewCISInvoice(
	dateTime time.Time,
	invoiceNumber uint,
	registerDeviceID uint,
	pdvValues [][]interface{},
	pnpValues [][]interface{},
	ostaliPorValues [][]interface{},
	iznosOslobPdv string,
	iznosMarza string,
	iznosNePodlOpor string,
	naknadeValues [][]string,
	iznosUkupno string,
	paymentMethod PaymentMethod,
	oibOper string,
) (*RacunType, string, error)

NewCISInvoice initializes and returns a RacunType instance

This method creates a new instance of RacunType, which represents an invoice with all necessary fields. The instance can be marshaled to XML and sent to the CIS for fiscalization. ALWAYS use the provided methods to set or modify the values of the RacunType instance. Using the provided methods is safe end ensure the correct format of the data and no discrepancies with the ZKI. DO NOT MODIFY the returned RacunType instance directly, as it may lead to invalid XML output or ZKI problems. Unsafe and unexpected results may happen if you modify the data manually and use it to send later. It can result in wrong data sent to CIS or discrepancy between sent data and ZKI, witch can lead to severe consequences.

Parameters:

  • dateTime (time.Time): The date and time of the invoice.
  • centralized (bool): Indicates whether the sequence mark is centralized.
  • invoiceNumber (uint): The unique number of the invoice.
  • locationIdentifier (string): The identifier for the business location where the invoice was issued.
  • registerDeviceID (uint): The identifier for the cash register device used to issue the invoice.
  • pdvValues ([][]interface{}): A 2D array for VAT details (nullable).
  • pnpValues ([][]interface{}): A 2D array for consumption tax details (nullable).
  • ostaliPorValues ([][]interface{}): A 2D array for other tax details (nullable).
  • iznosOslobPdv (string): The amount exempt from VAT.
  • iznosMarza (string): The margin amount.
  • iznosNePodlOpor (string): The amount not subject to taxation.
  • naknadeValues ([][]string): A 2D array for fees details (nullable).
  • iznosUkupno (string): The total amount.
  • paymentMethod (string): The payment method.
  • oibOper (string): The OIB of the operator.
  • attachedDocumentJIRorZKI (string): The JIR or ZKI of the attached document (empty if no attached document).

Returns:

(*RacunType, string, error): A pointer to a new RacunType instance with the provided values, generated zki or an error if the input is invalid.

func (*FiskalEntity) OIB

func (fe *FiskalEntity) OIB() string

OIB returns the taxpayer's identification number.

func (*FiskalEntity) PingCIS

func (fe *FiskalEntity) PingCIS() error

PingCIS checks if connection and message exchange with CIS works using the CISEcho function. It sends a simple text message to CIS and expects the same message back. Returns:

  • nil if the ping was successful
  • error if the ping failed

func (*FiskalEntity) SustPDV

func (fe *FiskalEntity) SustPDV() bool

SustPDV indicates whether the entity is part of the VAT system.

type GreskaType

type GreskaType struct {
	SifraGreske  string `xml:"SifraGreske"`
	PorukaGreske string `xml:"PorukaGreske"`
}

GreskaType ...

type GreskeType

type GreskeType struct {
	Greska []*GreskaType `xml:"Greska"`
}

GreskeType ...

type NaknadaType

type NaknadaType struct {
	NazivN string `xml:"tns:NazivN"`
	IznosN string `xml:"tns:IznosN"`
}

NaknadaType ...

type NaknadeType

type NaknadeType struct {
	Naknada []*NaknadaType `xml:"tns:Naknada"`
}

NaknadeType ...

type NapojnicaOdgovor

type NapojnicaOdgovor struct {
	XMLName        xml.Name              `xml:"NapojnicaOdgovor"`
	IdAttr         string                `xml:"Id,attr,omitempty"`
	Zaglavlje      *ZaglavljeOdgovorType `xml:"Zaglavlje"`
	PorukaOdgovora *PorukaOdgovoraType   `xml:"PorukaOdgovora"`
	Greske         *GreskeType           `xml:"Greske"`
}

NapojnicaOdgovor ...

type NapojnicaType

type NapojnicaType struct {
	IznosNapojnice         string `xml:"tns:iznosNapojnice"`
	NacinPlacanjaNapojnice string `xml:"tns:nacinPlacanjaNapojnice"`
}

NapojnicaType ...

type NapojnicaZahtjev

type NapojnicaZahtjev struct {
	XMLName   xml.Name       `xml:"tns:NapojnicaZahtjev"`
	Xmlns     string         `xml:"xmlns:tns,attr"` // Declare the tns namespace
	IdAttr    string         `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeType `xml:"tns:Zaglavlje"`
	Racun     *RacunType     `xml:"tns:Racun"`
}

NapojnicaZahtjev ...

type NullCanonicalizer

type NullCanonicalizer struct {
}

func (*NullCanonicalizer) Algorithm

func (c *NullCanonicalizer) Algorithm() AlgorithmID

func (*NullCanonicalizer) Canonicalize

func (c *NullCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error)

type OstaliPoreziType

type OstaliPoreziType struct {
	Porez []*PorezOstaloType `xml:"tns:Porez"`
}

OstaliPoreziType ...

type PaymentMethod

type PaymentMethod string

PaymentMethod defines a custom type for means of payment

const (
	CISCash         PaymentMethod = "G" // Cash
	CISCard         PaymentMethod = "K" // Card
	CISMixOther     PaymentMethod = "O" // Mix/Other
	CISBankTransfer PaymentMethod = "T" // Bank Transfer (usually not sent to CIS, not mandatory)
	CISCheck        PaymentMethod = "C" // Check [deprecated]
)

Constants representing allowed values for PaymentMethod

func (PaymentMethod) IsValid

func (p PaymentMethod) IsValid() error

IsValid checks if PaymentMethod is one of the allowed values

type PdvType

type PdvType struct {
	Porez []*PorezType `xml:"tns:Porez"`
}

PdvType ...

type PorezNaPotrosnjuType

type PorezNaPotrosnjuType struct {
	Porez []*PorezType `xml:"tns:Porez"`
}

PorezNaPotrosnjuType ...

type PorezOstaloType

type PorezOstaloType struct {
	Naziv    string `xml:"tns:Naziv"`
	Stopa    string `xml:"tns:Stopa"`
	Osnovica string `xml:"tns:Osnovica"`
	Iznos    string `xml:"tns:Iznos"`
}

PorezOstaloType ...

type PorezType

type PorezType struct {
	Stopa    string `xml:"tns:Stopa"`
	Osnovica string `xml:"tns:Osnovica"`
	Iznos    string `xml:"tns:Iznos"`
}

PorezType ...

type PorukaOdgovoraType

type PorukaOdgovoraType struct {
	SifraPoruke string `xml:"SifraPoruke"`
	Poruka      string `xml:"Poruka"`
}

PorukaOdgovoraType ...

type PrateciDokument

type PrateciDokument struct {
	JirPD     string `xml:"tns:JirPD"`
	ZastKodPD string `xml:"tns:ZastKodPD"`
}

PrateciDokument ...

type PrateciDokumentType

type PrateciDokumentType struct {
	Oib                 string      `xml:"tns:Oib"`
	DatVrijeme          string      `xml:"tns:DatVrijeme"`
	BrPratecegDokumenta *BrojPDType `xml:"tns:BrPratecegDokumenta"`
	IznosUkupno         string      `xml:"tns:IznosUkupno"`
	ZastKodPD           string      `xml:"tns:ZastKodPD"`
	NakDost             bool        `xml:"tns:NakDost"`
}

PrateciDokumentType ...

type PrateciDokumentiOdgovor

type PrateciDokumentiOdgovor struct {
	XMLName   xml.Name              `xml:"PrateciDokumentiOdgovor"`
	IdAttr    string                `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeOdgovorType `xml:"Zaglavlje"`
	Jir       string                `xml:"Jir"`
	Greske    *GreskeType           `xml:"Greske"`
}

PrateciDokumentiOdgovor ...

type PrateciDokumentiZahtjev

type PrateciDokumentiZahtjev struct {
	XMLName         xml.Name             `xml:"tns:PrateciDokumentiZahtjev"`
	Xmlns           string               `xml:"xmlns:tns,attr"` // Declare the tns namespace
	IdAttr          string               `xml:"Id,attr,omitempty"`
	Zaglavlje       *ZaglavljeType       `xml:"tns:Zaglavlje"`
	PrateciDokument *PrateciDokumentType `xml:"tns:PrateciDokument"`
}

PrateciDokumentiZahtjev ...

type PromijeniNacPlacOdgovor

type PromijeniNacPlacOdgovor struct {
	XMLName        xml.Name              `xml:"PromijeniNacPlacOdgovor"`
	IdAttr         string                `xml:"Id,attr,omitempty"`
	Zaglavlje      *ZaglavljeOdgovorType `xml:"Zaglavlje"`
	PorukaOdgovora *PorukaOdgovoraType   `xml:"PorukaOdgovora"`
	Greske         *GreskeType           `xml:"Greske"`
}

PromijeniNacPlacOdgovor ...

type PromijeniNacPlacZahtjev

type PromijeniNacPlacZahtjev struct {
	XMLName   xml.Name       `xml:"tns:PromijeniNacPlacZahtjev"`
	Xmlns     string         `xml:"xmlns:tns,attr"` // Declare the tns namespace
	IdAttr    string         `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeType `xml:"tns:Zaglavlje"`
	Racun     *RacunType     `xml:"tns:Racun"`
}

PromijeniNacPlacZahtjev ...

type RacunOdgovor

type RacunOdgovor struct {
	XMLName   xml.Name              `xml:"RacunOdgovor"`
	IdAttr    string                `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeOdgovorType `xml:"Zaglavlje"`
	Jir       string                `xml:"Jir"`
	Greske    *GreskeType           `xml:"Greske"`
}

RacunOdgovor ...

type RacunPDOdgovor

type RacunPDOdgovor struct {
	XMLName   xml.Name              `xml:"RacunPDOdgovor"`
	IdAttr    string                `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeOdgovorType `xml:"Zaglavlje"`
	Jir       string                `xml:"Jir"`
	Greske    *GreskeType           `xml:"Greske"`
}

RacunPDOdgovor ...

type RacunPDZahtjev

type RacunPDZahtjev struct {
	XMLName   xml.Name       `xml:"tns:RacunPDZahtjev"`
	Xmlns     string         `xml:"xmlns:tns,attr"` // Declare the tns namespace
	IdAttr    string         `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeType `xml:"tns:Zaglavlje"`
	Racun     *RacunType     `xml:"tns:Racun"`
}

RacunPDZahtjev ...

type RacunType

type RacunType struct {
	XMLName               xml.Name              `xml:"tns:Racun"`
	Oib                   string                `xml:"tns:Oib"`
	USustPdv              bool                  `xml:"tns:USustPdv"`
	DatVrijeme            string                `xml:"tns:DatVrijeme"`
	OznSlijed             string                `xml:"tns:OznSlijed"`
	BrRac                 *BrojRacunaType       `xml:"tns:BrRac"`
	Pdv                   *PdvType              `xml:"tns:Pdv,omitempty"`
	Pnp                   *PorezNaPotrosnjuType `xml:"tns:Pnp,omitempty"`
	OstaliPor             *OstaliPoreziType     `xml:"tns:OstaliPor,omitempty"`
	IznosOslobPdv         string                `xml:"tns:IznosOslobPdv,omitempty"`
	IznosMarza            string                `xml:"tns:IznosMarza,omitempty"`
	IznosNePodlOpor       string                `xml:"tns:IznosNePodlOpor,omitempty"`
	Naknade               *NaknadeType          `xml:"tns:Naknade,omitempty"`
	IznosUkupno           string                `xml:"tns:IznosUkupno"`
	NacinPlac             string                `xml:"tns:NacinPlac"`
	OibOper               string                `xml:"tns:OibOper"`
	ZastKod               string                `xml:"tns:ZastKod"`
	NakDost               bool                  `xml:"tns:NakDost"`
	ParagonBrRac          string                `xml:"tns:ParagonBrRac,omitempty"`
	SpecNamj              string                `xml:"tns:SpecNamj,omitempty"`
	PrateciDokument       *PrateciDokument      `xml:"tns:PrateciDokument,omitempty"`
	PromijenjeniNacinPlac string                `xml:"tns:PromijenjeniNacinPlac,omitempty"`
	Napojnica             *NapojnicaType        `xml:"tns:Napojnica,omitempty"`
	// contains filtered or unexported fields
}

RacunType represents the invoice type with various details required for fiscalization.

func (*RacunType) GetOib

func (invoice *RacunType) GetOib() string

func (*RacunType) GetZKI

func (invoice *RacunType) GetZKI() string

func (*RacunType) IhaveZKIwithExpiredCertificateEdgeCase

func (invoice *RacunType) IhaveZKIwithExpiredCertificateEdgeCase(oldZKI string, oldCertPath string, oldCertPassword string) error

IhaveZKIwithExpiredCertificateEdgeCase sets the old FiskalEntity instance for the old ZKI verification This is used in the edge case that the ZKI was generated with one certificate and the fiscalization failed But the certificate expired or had to be changed and now fiscalization have to be repeated with new certificate If we replace the original ZKI its a problem we already gave the invoice with old ZKI out So we have to keep the old ZKI and validate it with the old certificate before signing and sending with new one

func (*RacunType) InvoiceRequest

func (invoice *RacunType) InvoiceRequest() (string, string, error)

InvoiceRequest sends an invoice request to the CIS (Croatian Fiscalization System) and processes the response.

This function performs the following steps:

  1. Minimally validates the provided invoice for required fields (any business logic and math is the responsibility of the invoicing application using the library) PLEASE NOTE: the CIS also don't do any extensive validation of the invoice, only basic checks. so you could get a JIR back even if the invoice is not correct. But if you do that you can have problems later with inspections or periodic CIS checks of the data. The library will send the data as is to the CIS. So please validate and chek the invoice data according to you business logic before sending it to the CIS.
  2. Sends the XML request to the CIS and receives the response.
  3. Unmarshals the response XML to extract the response data.
  4. Checks for errors in the response and aggregates them if any are found.
  5. Returns the JIR (Unique Invoice Identifier) if the request was successful.

Parameters: - invoice: A pointer to a RacunType struct representing the invoice to be sent.

Returns: - A string representing the JIR (Unique Invoice Identifier) if the request was successful. - A string representing the ZKI (Protection Code of the Issuer) from the invoice. - An error if any issues occurred during the process.

Possible errors: - If the invoice is nil or something is invalid (only basic checks). - If the SpecNamj field of the invoice is not empty. - If the ZastKod field of the invoice is empty. - If there is an error marshalling the request to XML. - If there is an error making the request to the CIS. - If there is an error unmarshalling the response XML. - If the IdPoruke in the response does not match the request. - If the response status is not 200 and there are errors in the response. - If the JIR in the response is empty. - If an unexpected error occurs.

func (*RacunType) SetLateDelivery

func (invoice *RacunType) SetLateDelivery(ZKI string) error

Set late delivery to true, and set the ZKI you pass from saved data when you issued the invoice to customer Don't worry the ZKI you set will be validated with the current certificate before sending unless to set IhaveZKIwithExpiredCertificateEdgeCase method then the old certificate provided will be used to validate the ZKI

So just set the ZKI you got from the invoice you issued to the customer, and the system will validate it with the current certificate

type RacunZahtjev

type RacunZahtjev struct {
	XMLName   xml.Name       `xml:"tns:RacunZahtjev"`
	Xmlns     string         `xml:"xmlns:tns,attr"` // Declare the tns namespace
	IdAttr    string         `xml:"Id,attr,omitempty"`
	Zaglavlje *ZaglavljeType `xml:"tns:Zaglavlje"`
	Racun     *RacunType     `xml:"tns:Racun"`
}

RacunZahtjev ...

type ZaglavljeOdgovorType

type ZaglavljeOdgovorType struct {
	IdPoruke     string `xml:"IdPoruke"`
	DatumVrijeme string `xml:"DatumVrijeme"`
}

ZaglavljeOdgovorType ...

type ZaglavljeType

type ZaglavljeType struct {
	IdPoruke     string `xml:"tns:IdPoruke"`
	DatumVrijeme string `xml:"tns:DatumVrijeme"`
}

ZaglavljeType is Datum i vrijeme slanja poruke.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL