facturae

package module
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2024 License: Apache-2.0 Imports: 22 Imported by: 0

README

GOBL to FacturaE Toolkit

Convert GOBL documents into the Spain's FacturaE format.

Copyright Invopop Ltd. 2023. Released publicly under the Apache License Version 2.0. For commercial licenses please contact the dev team at invopop. In order to accept contributions to this library we will require transferring copyrights to Invopop Ltd.

Lint Test Go Go Report Card GoDoc Latest Tag

Usage

Go

There are a couple of entry points to build a new FacturaE document. If you already have a GOBL Envelope available in Go, you could convert and output to a data file like this:

doc, err := facturae.NewInvoice(env)
if err != nil {
    panic(err)
}

data, err := doc.Bytes()
if err != nil {
    panic(err)
}

if err = os.WriteFile("./test.xml", data, 0644); err != nil {
    panic(err)
}

If you're loading from a file, you can use the LoadGOBL convenience method:

doc, err := facturae.LoadGOBL(file)
if err != nil {
    panic(err)
}
// do something with doc

Outputting to a FacturaE XML is most useful when the document is signed. Use a certificate to sign the document as follows:

// import from github.com/invopop/xmldsig
cert, err := xmldsig.LoadCertificate(filename, password)
if err != nil {
    panic(err)
}

doc, err := facturae.NewInvoice(env, facturae.WithCertificate(cert))
if err != nil {
    panic(err)
}
CLI

The command line interface can be useful for situations when you're using a language other than Golang in your application.

# install example

Simply provide the input GOBL JSON file and output to a file or another application:

./gobl.facturae convert input.json output.xml

If you have a digital certificate, run with:

./gobl.facturae convert -c cert.p12 -p password input.json > output.xml

The command also supports pipes:

cat input.json > ./gobl.facturae > output.xml
Testing

This package uses lestrrat-go/libxml2 for testing purporses, which in turn depends on the libxml-2.0 C library. Ensure you have the development dependency installed. In linux this implies:

sudo apt-get install libxml2-dev

To specifically run the examples and update the output in the /test/data/out directory, run:

go test ./examples_test.go --update

For automated testing purposes, we don't attach certificates to the XML output. For manual testing of complete XML documents, digital certificates are available in the /test/certificates path which can be used to generate XML documents in the /test/data/ path:

mage -v convertXML

YAML files are used for base examples. To generate the GOBL JSON, run:

mage -v convertYAML

Notes

  • To validate the XML output and digital certificates, use https://face.gob.es/es/facturas/validar-visualizar-facturas
  • In most cases Go structures have been written using the same naming from the XML style document. This means names are not repeated in tags and generally makes it a bit easier map the XML output to the internal structures.

Current Conversion Limitations

The FacturaE format is quite complex due to the number of local requirements in Spain.

  • Payment Information: FacturaE requires each payment instruction to have a Due Date. The GOBL invoice allows these details to be independent. If you require payment instructions to appear on a FacturaE document, there must be a due date.

Documentation

Index

Constants

View Source
const (
	XAdESSupplier   xmldsig.XAdESSignerRole = "supplier"
	XAdESCustomer   xmldsig.XAdESSignerRole = "customer"
	XAdESThirdParty xmldsig.XAdESSignerRole = "third party"
)

XAdES Signer Roles used for FacturaE

View Source
const (
	ModalityIndividual = "I" // Individual
	ModalityBatch      = "L" // Batch or multiple invoices in on document
)

List of accepted Mobility Types

View Source
const (
	InvoiceIssuerSeller     = "EM"  // Seller
	InvoiceIssuerBuyer      = " RE" // Buyer
	InvoiceIssuerThirdParty = "TE"  // Third party
)

List of accepted Issuer Types

View Source
const ES string = "ESP"

ES is the ISO Alpha-3 code used for Spain

View Source
const (
	NamespaceFacturaE = "http://www.facturae.gob.es/formato/Versiones/Facturaev3_2_2.xml"
)

Namespaces used for FacturaE. DSig stuff is handled in the signatures.

Variables

View Source
var (
	ErrCertificateNotFound = errors.New("certificate-not-found")
)

Standard error messages for the repo

Functions

This section is empty.

Types

type AdditionalData

type AdditionalData struct {
	InvoiceAdditionalInformation string `xml:"InvoiceAdditionalInformation,omitempty"`
}

AdditionalData stores notes that the provider of the invoice estimates are needed

type Address

type Address struct {
	Address     string `xml:",omitempty"`
	PostCode    string `xml:",omitempty"`
	Town        string `xml:",omitempty"`
	Province    string `xml:",omitempty"`
	CountryCode string `xml:",omitempty"`
}

Address stores location information FIXME: para direcciones extranjeras hay un campo diferentes PostCodeAndTown

type Amount

type Amount struct {
	TotalAmount       string
	EquivalentInEuros string `xml:",omitempty"` // not used yet!
}

Amount provides a wrapper around our regular amounts so that we can include the `TotalAmount` tag. Eventually this could also handle currency conversion.

type BankAccount

type BankAccount struct {
	IBAN                  string   `xml:",omitempty"`
	AccountNumber         string   `xml:",omitempty"`
	BranchInSpainAddress  *Address `xml:",omitempty"`
	OverseasBranchAddress *Address `xml:",omitempty"`
	BIC                   string   `xml:",omitempty"`
}

BankAccount contains info needed to pay by transfer or direct debit

type Batch

type Batch struct {
	BatchIdentifier        string
	InvoicesCount          int
	TotalInvoicesAmount    Amount
	TotalOutstandingAmount Amount
	TotalExecutableAmount  Amount
	InvoiceCurrencyCode    string
}

Batch would contain info about a group of invoices that are submitted at the same time, but we only allow one invoice at a time

type CertificateRepo

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

CertificateRepo is an implementation of the CertificateRepo that loads the certificate from a local file

func NewCertificateRepo

func NewCertificateRepo(path string) (*CertificateRepo, error)

NewCertificateRepo instantiates a new repository of certificates stored in a local directory. Each certificate found will be parsed and stored in a map of file names without extension to certificate instances.

func (*CertificateRepo) Get

func (repo *CertificateRepo) Get(id string) (*xmldsig.Certificate, error)

Get returns the local pre-loaded certificate

type Charge

type Charge struct {
	Reason string `xml:"ChargeReason"`
	Rate   string `xml:"ChargeRate,omitempty"`
	Amount string `xml:"ChargeAmount"`
}

Charge defines the basic data for a single surcharge.

type Charges

type Charges struct {
	Items []*Charge `xml:"Charge"`
}

Charges contains a list of charge instances. This is used both at a line and document level as per the FacturaE specification. Unfortunately, this implies that taxes will not be applied in the context of a global charge. We recommend avoiding using this in Spanish invoices.

type ContactDetails

type ContactDetails struct {
	Telephone                string `xml:",omitempty"`
	TeleFax                  string `xml:",omitempty"`
	WebAddress               string `xml:",omitempty"`
	ElectronicMail           string `xml:",omitempty"`
	ContactPersons           string `xml:",omitempty"`
	CnoCnae                  string `xml:",omitempty"` // Code of economic activity from INE
	INETownCode              string `xml:",omitempty"` // Code of town allocated by INE
	AdditionalContactDetails string `xml:",omitempty"`
}

ContactDetails store info about how to contact the party

type Corrective

type Corrective struct {
	InvoiceNumber               string `xml:",omitempty"`
	InvoiceSeriesCode           string `xml:",omitempty"`
	ReasonCode                  string
	ReasonDescription           string
	TaxPeriod                   *PeriodDates
	CorrectionMethod            string
	CorrectionMethodDescription string
	AdditionalReasonDescription string `xml:",omitempty"`
	InvoiceIssueDate            string `xml:",omitempty"`
}

Corrective is used to represent the details of a previous invoice that this one serves to modify or replace. Details here are a bit sketchy as in practical usage, most companies don't demand this level of detail.

type Discount

type Discount struct {
	Reason string `xml:"DiscountReason"`
	Rate   string `xml:"DiscountRate,omitempty"`
	Amount string `xml:"DiscountAmount"`
}

Discount is used in general and line discounts. Unlike in GOBL, FacturaE does not differentiate between the two, which could potentially lead to confusion for handling taxes.

type Discounts

type Discounts struct {
	Items []*Discount `xml:"Discount"`
}

Discounts list discounts applied on a line or document level.

type Document

type Document struct {
	XMLName     xml.Name `xml:"fe:Facturae"`
	FeNamespace string   `xml:"xmlns:fe,attr"`

	FileHeader *FileHeader
	Parties    *Parties
	Invoices   *Invoices
	Signature  *xmldsig.Signature `xml:"ds:Signature,omitempty"`
	// contains filtered or unexported fields
}

Document is a pseudo-model for containing the XML document being created.

func LoadGOBL

func LoadGOBL(src io.Reader, opts ...Option) (*Document, error)

LoadGOBL will build a FacturaE Document from the source buffer

func NewInvoice

func NewInvoice(env *gobl.Envelope, opts ...Option) (*Document, error)

NewInvoice expects the base envelope and provides a new Document containing the XML version.

func (*Document) Buffer

func (d *Document) Buffer() (*bytes.Buffer, error)

Buffer returns a byte buffer representation of the complete XML document.

func (*Document) Bytes

func (d *Document) Bytes() ([]byte, error)

Bytes returns the XML document bytes

func (*Document) Canonical

func (d *Document) Canonical() ([]byte, error)

Canonical converts a struct representation of facturae to its canonical representation as defined in https://www.w3.org/TR/2001/REC-xml-c14n-20010315 (for a simpler explanation look at https://www.di-mgt.com.au/xmldsig-c14n.html) This is used when we need to create a hash for signing, timestamping, ...

func (*Document) String

func (d *Document) String() (string, error)

String converts a struct representation to its string representation

type ExchangeRateDetails

type ExchangeRateDetails struct {
	ExchangeRate     string
	ExchangeRateDate string
}

ExchangeRateDetails describes how to exchange from the invoices currency to euros.

type Facturae

type Facturae struct {
}

Facturae represent the root node of an invoice

type FileHeader

type FileHeader struct {
	SchemaVersion     string
	Modality          string
	InvoiceIssuerType string      // Who is signing the invoice?
	ThirdParty        *ThirdParty `xml:",omitempty"`
	Batch             *Batch
}

FileHeader contains the FileHeader element of a facturae invoice

type Individual

type Individual struct {
	Name            string
	FirstSurname    string          `xml:",omitempty"`
	SecondSurname   string          `xml:",omitempty"`
	AddressInSpain  *Address        `xml:",omitempty"`
	OverseasAddress *Address        `xml:",omitempty"`
	ContactDetails  *ContactDetails `xml:",omitempty"`
}

Individual stores party info for people

func NewIndividual

func NewIndividual(party *org.Party) *Individual

NewIndividual creates info for people

type Installment

type Installment struct {
	InstallmentDueDate              string
	InstallmentAmount               string
	PaymentMeans                    string       `xml:",omitempty"`
	AccountToBeCredited             *BankAccount `xml:",omitempty"`
	DebitReconciliationReference    string       `xml:",omitempty"`
	AccountToBeDebited              *BankAccount `xml:",omitempty"`
	CollectionAdditionalInformation string       `xml:",omitempty"`
}

Installment contains info about each of the payment terms

type Invoice

type Invoice struct {
	InvoiceHeader    *InvoiceHeader
	InvoiceIssueData *InvoiceIssueData
	TaxesOutputs     *TaxSummary `xml:",omitempty"`
	TaxesWithheld    *TaxSummary `xml:",omitempty"`
	InvoiceTotals    *InvoiceTotals
	Items            *Items
	PaymentDetails   *PaymentDetails `xml:",omitempty"`
	LegalLiterals    *LegalLiterals  `xml:",omitempty"`
	AdditionalData   *AdditionalData `xml:",omitempty"`
}

Invoice contains info about a single invoice

type InvoiceHeader

type InvoiceHeader struct {
	InvoiceNumber       string
	InvoiceSeriesCode   string `xml:",omitempty"`
	InvoiceDocumentType string
	InvoiceClass        string
	Corrective          *Corrective `xml:",omitempty"`
}

InvoiceHeader contains general information of a single invoice

type InvoiceIssueData

type InvoiceIssueData struct {
	IssueDate                    string
	OperationDate                string       `xml:",omitempty"`
	PlaceOfIssue                 string       `xml:",omitempty"`
	InvoiceingPeriod             *PeriodDates `xml:",omitempty"`
	InvoiceCurrencyCode          string
	ExchangeRateDetails          *ExchangeRateDetails `xml:",omitempty"` // TODO!
	TaxCurrencyCode              string
	LanguageName                 string // FIXME: [JUANJO] are we going to support multiple languages?
	InvoiceDescription           string `xml:",omitempty"` // TODO
	ReceiverTransactionReference string `xml:",omitempty"` // TODO
	FileReference                string `xml:",omitempty"` // TODO
	ReceiverContractReference    string `xml:",omitempty"` // TODO
}

InvoiceIssueData contains information about dates, lang and currencies

type InvoiceLine

type InvoiceLine struct {
	ItemDescription               string
	Quantity                      string
	UnitOfMeasure                 string `xml:",omitempty"`
	UnitPriceWithoutTax           string
	TotalCost                     string               // Unit Price * quantity
	DiscountsAndRebates           *Discounts           `xml:",omitempty"`
	Charges                       *Charges             `xml:",omitempty"`
	GrossAmount                   string               // total cost - discount + charges
	TaxesWithheld                 *TaxSummary          `xml:",omitempty"`
	TaxesOutputs                  *TaxSummary          `xml:",omitempty"`
	AdditionalLineItemInformation string               `xml:",omitempty"`
	SpecialTaxableEvent           *SpecialTaxableEvent `xml:",omitempty"`
}

InvoiceLine contains info about a specific line

type InvoiceTotals

type InvoiceTotals struct {
	TotalGrossAmount            string     // Without included taxes
	GeneralDiscounts            *Discounts `xml:",omitempty"`
	GeneralSurcharges           *Charges   `xml:",omitempty"`
	TotalGeneralDiscounts       string     `xml:",omitempty"`
	TotalGeneralSurcharges      string     `xml:",omitempty"`
	TotalGrossAmountBeforeTaxes string
	TotalTaxOutputs             string
	TotalTaxesWithheld          string
	InvoiceTotal                string
	Subsidies                   *Subsidies            `xml:",omitempty"`
	PaymentsOnAccount           *PaymentsOnAccount    `xml:",omitempty"`
	ReimbursableExpenses        *ReimbursableExpenses `xml:",omitempty"`
	TotalOutstandingAmount      string                // InvoiceTotal - (Total subvenciones + TotalPaymentsOnAccount)
	TotalPaymentsOnAccount      string                `xml:",omitempty"`
	TotalExecutableAmount       string
	TotalReimbursableExpenses   string `xml:",omitempty"`
}

InvoiceTotals contains the summary of the amounts in an invoice

type Invoices

type Invoices struct {
	List []*Invoice `xml:"Invoice"`
}

Invoices contains info about a batch of invoices. In our case there will only be one invoice per batch

type Items

type Items struct {
	InvoiceLine []*InvoiceLine
}

Items contains info about all the lines in an invoice

type LegalEntity

type LegalEntity struct {
	CorporateName   string
	AddressInSpain  *Address        `xml:",omitempty"`
	OverseasAddress *Address        `xml:",omitempty"`
	ContactDetails  *ContactDetails `xml:",omitempty"`
}

LegalEntity stores party info for companies, associations, ...

func NewLegalEntity

func NewLegalEntity(party *org.Party) *LegalEntity

NewLegalEntity creates info for companies, associations, ...

type LegalLiterals

type LegalLiterals struct {
	LegalReference []string
}

LegalLiterals contains an array of legal texts to add to the Invoice in certain situations.

type Option

type Option func(*options)

Option defines a callback configuration option used to customize the conversion to XML process

func WithCertificate

func WithCertificate(cert *xmldsig.Certificate) Option

WithCertificate will use the provided certificate to sign the XML document.

func WithThirdParty

func WithThirdParty(tp *ThirdParty) Option

WithThirdParty adds optional information about who is manipulating and signing the document.

func WithTimestamp

func WithTimestamp(val bool) Option

WithTimestamp will ensure the XML document is timestamped

type Parties

type Parties struct {
	Seller *Party `xml:"SellerParty"`
	Buyer  *Party `xml:"BuyerParty"`
}

Parties stores emitter and receiver of the invoice

type Party

type Party struct {
	TaxID       *TaxID       `xml:"TaxIdentification,omitempty"`
	LegalEntity *LegalEntity `xml:"LegalEntity,omitempty"`
	Individual  *Individual  `xml:"Individual,omitempty"`
}

Party stores the info for one of the participants of the invoice

type PaymentDetails

type PaymentDetails struct {
	Installments []*Installment `xml:"Installment"`
}

PaymentDetails contains info about how the invoice should be paid

type PaymentOnAccount

type PaymentOnAccount struct {
	PaymentOnAccountDate   cal.Date
	PaymentOnAccountAmount string
}

PaymentOnAccount is a single advance payment.

type PaymentsOnAccount

type PaymentsOnAccount struct {
	PaymentOnAccount []*PaymentOnAccount
}

PaymentsOnAccount stores payments made in advance.

type PeriodDates

type PeriodDates struct {
	StartDate string
	EndDate   string
}

PeriodDates is used in corrective tax periods to define a date range.

type ReimbursableExpense

type ReimbursableExpense struct {
	ReimbursableExpensesSellerParty *TaxID    `xml:",omitempty"`
	ReimbursableExpensesBuyerParty  *TaxID    `xml:",omitempty"` // never used!
	IssueDate                       *cal.Date `xml:",omitempty"`
	InvoiceNumber                   string    `xml:",omitempty"`
	InvoiceSeriesCode               string    `xml:",omitempty"`
	ReimbursableExpensesAmount      string
}

ReimbursableExpense stores info about a single reimbursable expense.

type ReimbursableExpenses

type ReimbursableExpenses struct {
	ReimbursableExpenses []*ReimbursableExpense
}

ReimbursableExpenses is a group of reimbursable expenses.

type SpecialTaxableEvent

type SpecialTaxableEvent struct {
	SpecialTaxableEventCode   SpecialTaxableEventCode
	SpecialTaxableEventReason string
}

SpecialTaxableEvent stores details as to way the invoice line does not need taxes to be applied.

type SpecialTaxableEventCode

type SpecialTaxableEventCode string

SpecialTaxableEventCode used for special invoice lines that do not need taxes to be applied.

const (
	TaxableAndExemptCode SpecialTaxableEventCode = "01"
	NonTaxableCode       SpecialTaxableEventCode = "02"
)

Special taxable event codes

type Subsidies

type Subsidies struct {
	Subsidy []*Subsidy
}

Subsidies is currently a placeholder, as we don't use it yet.

type Subsidy

type Subsidy struct {
	SubsidyDescription string
	SubsidyRate        string `xml:",omitempty"`
	SubsidyAmount      string
}

Subsidy is a single subsidy entry

type Tax

type Tax struct {
	Code            string  `xml:"TaxTypeCode"`
	Rate            string  `xml:"TaxRate"`
	Base            Amount  `xml:"TaxableBase"`
	Amount          Amount  `xml:"TaxAmount"`
	Surcharge       string  `xml:"EquivalenceSurcharge,omitempty"` // must be with two decimal places
	SurchargeAmount *Amount `xml:"EquivalenceSurchargeAmount,omitempty"`
}

Tax contains the info of a particular tax type

type TaxID

type TaxID struct {
	PersonTypeCode          string
	ResidenceTypeCode       string
	TaxIdentificationNumber string
}

TaxID stores fiscal id

func NewTaxID

func NewTaxID(taxNumber cbc.Code, countryCode l10n.TaxCountryCode) *TaxID

NewTaxID builds the tax identification information of a party

type TaxSummary

type TaxSummary struct {
	List []*Tax `xml:"Tax"`
}

TaxSummary contains a list with the info of each tax type

type ThirdParty

type ThirdParty struct {
	TaxIdentification *TaxID
	LegalEntity       *LegalEntity
}

ThirdParty is used to identify an intermediary building and issuing the invoice.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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