VerifactuMidAPI/internal/formats/dolibarr/format.go

152 lines
3.4 KiB
Go
Raw Normal View History

package dolibarr
import (
"encoding/json"
"fmt"
"math"
"time"
"VerifactuMidAPI/internal/formats"
)
func init() {
formats.Register(&Transformer{})
}
type Transformer struct{}
func (t *Transformer) Name() string { return "dolibarr" }
type Input struct {
Invoice InvoiceInput `json:"invoice"`
Client *ClientInput `json:"client,omitempty"`
Emisor EmisorInput `json:"emisor"`
Sistema SistemaInput `json:"sistema"`
}
type InvoiceInput struct {
Number string `json:"number"`
Date string `json:"date"`
TotalHt float64 `json:"totalHt"`
TotalTax float64 `json:"totalTax"`
Total float64 `json:"total"`
NotePublic string `json:"notePublic,omitempty"`
Lines []LineInput `json:"lines"`
}
type LineInput struct {
Description string `json:"description"`
Quantity float64 `json:"quantity"`
UnitPrice float64 `json:"unitPrice"`
TaxRate float64 `json:"taxRate"`
Total float64 `json:"total"`
}
type ClientInput struct {
Name string `json:"name"`
VatNumber string `json:"vatNumber"`
}
type EmisorInput struct {
NIF string `json:"nif"`
Nombre string `json:"nombre"`
}
type SistemaInput struct {
Nombre string `json:"nombre"`
NIFProveedor string `json:"nif_proveedor"`
Version string `json:"version"`
}
func (t *Transformer) Transform(raw json.RawMessage) (*formats.TransformResult, error) {
var in Input
if err := json.Unmarshal(raw, &in); err != nil {
return nil, fmt.Errorf("invalid dolibarr format: %w", err)
}
date, err := parseDate(in.Invoice.Date)
if err != nil {
return nil, fmt.Errorf("invalid invoice date: %w", err)
}
ivaMap := make(map[float64]*formats.IVAData)
for _, line := range in.Invoice.Lines {
rate := line.TaxRate
base := line.Total / (1 + rate/100)
cuota := line.Total - base
if existing, ok := ivaMap[rate]; ok {
existing.Base += base
existing.Cuota += cuota
} else {
ivaMap[rate] = &formats.IVAData{
Base: base,
Cuota: cuota,
Tipo: rate,
}
}
}
iva := make([]formats.IVAData, 0, len(ivaMap))
for _, v := range ivaMap {
v.Base = round2(v.Base)
v.Cuota = round2(v.Cuota)
iva = append(iva, *v)
}
var dest *formats.DestinatarioData
if in.Client != nil && in.Client.VatNumber != "" {
dest = &formats.DestinatarioData{
Nombre: in.Client.Name,
NIF: in.Client.VatNumber,
}
}
desc := in.Invoice.NotePublic
if desc == "" {
desc = "Factura"
}
importeTotal := in.Invoice.Total
if importeTotal == 0 {
importeTotal = in.Invoice.TotalHt + in.Invoice.TotalTax
}
return &formats.TransformResult{
EmisorNIF: in.Emisor.NIF,
EmisorNombre: in.Emisor.Nombre,
NumSerie: in.Invoice.Number,
FechaExpedicion: date,
TipoFactura: "F1",
Descripcion: desc,
Destinatario: dest,
IVA: iva,
ImporteTotal: round2(importeTotal),
Sistema: formats.SistemaData{
Nombre: in.Sistema.Nombre,
NIFProveedor: in.Sistema.NIFProveedor,
Version: in.Sistema.Version,
},
}, nil
}
func parseDate(s string) (string, error) {
formats := []string{
"2006-01-02T15:04:05Z07:00",
"2006-01-02T15:04:05Z",
"2006-01-02T15:04:05",
"2006-01-02",
}
for _, f := range formats {
t, err := time.Parse(f, s)
if err == nil {
return t.Format("02-01-2006"), nil
}
}
return "", fmt.Errorf("cannot parse date %q", s)
}
func round2(v float64) float64 {
return math.Round(v*100) / 100
}