go-efatura
GİB e-Fatura / e-Arşiv belgeleri (UBL-TR 1.2) için Go kütüphanesi. Belge
modeli, parse ve deterministik XML üretimi, GİB iş kuralı doğrulaması,
XAdES imza ve SBDH zarf katmanı; entegratör taşıması yolda.

Geliştirme sürüyor. v0.1 belge katmanı (builder + parse), v0.2 doğrulama,
v0.3 XAdES imza, v0.4 zarf + durum kodları. Entegratör/GİB taşıması
sonraki sürümde.
Neden
Türkiye e-belge ekosisteminde ciddi kütüphaneler C# ve PHP tarafında;
Go'da UBL-TR üreten, GİB kurallarını bilen bir kütüphane yok. Backend'i Go
olan herkes ya entegratörün hazır paketine kilitleniyor ya da XML'i elle
kuruyor. Bu kütüphane o boşluk için: hangi entegratörü kullanırsanız
kullanın, doğru UBL-TR belgesini üretmek ve gelen belgeyi parse etmek
ortak ihtiyaç.
Kurulum
go get github.com/YusufDrymz/go-efatura
Kullanım
Fatura kurma — satır tutarı, KDV dağılımı ve belge toplamları otomatik
hesaplanır, VKN/TCKN checksum'ları
go-trvalidate ile doğrulanır:
import "github.com/YusufDrymz/go-efatura/ubltr"
b := ubltr.NewInvoice(
ubltr.WithProfile(ubltr.ProfileTemelFatura),
ubltr.WithType(ubltr.TypeSatis),
ubltr.WithID("ABC2026000000001"),
ubltr.WithIssueDate(time.Now()),
ubltr.WithSupplier(ubltr.PartyInfo{VKN: "9990000005", Name: "Örnek A.Ş.", TaxOffice: "Beşiktaş",
Address: ubltr.Address{CitySubdivisionName: "Beşiktaş", CityName: "İstanbul",
Country: ubltr.Country{Name: "Türkiye"}}}),
ubltr.WithCustomer(ubltr.PartyInfo{TCKN: "99900000074", FirstName: "Ali", FamilyName: "Yılmaz",
Address: ubltr.Address{CitySubdivisionName: "Çankaya", CityName: "Ankara",
Country: ubltr.Country{Name: "Türkiye"}}}),
)
b.AddLine(ubltr.Line{Name: "Danışmanlık", Qty: ubltr.D("2"), Unit: "C62",
UnitPrice: ubltr.D("1500"), VATRate: ubltr.D("20")})
inv, err := b.Build() // hesap + dogrulama burada
if err != nil {
return err // birden fazla hata errors.Join ile birlikte doner
}
out, err := inv.XML()
Build eksik/geçersiz her alanı ayrı raporlar (profil, fatura no biçimi,
checksum, adres, kur, istisna gerekçesi...) ve hepsini tek seferde döner —
tek tek düzeltip yeniden denemek gerekmez. Üretilen XML, testlerde GİB'in
resmi XSD'sine karşı xmllint ile doğrulanır (ubltr/testdata/xsd/).
Gelen faturayı parse etme:
inv, err := ubltr.ParseInvoice(data)
fmt.Println(inv.ProfileID, inv.InvoiceTypeCode) // TEMELFATURA SATIS
fmt.Println(inv.LegalMonetaryTotal.PayableAmount.Value) // 17.88
Göndermeden (veya gelen belgeyi işlemeden) önce GİB iş kurallarıyla doğrulama:
import "github.com/YusufDrymz/go-efatura/validate"
issues := validate.Invoice(inv)
for _, is := range issues {
fmt.Println(is) // [hata] InvoicedQuantityCheck: unitCode niteliği zorunludur (InvoiceLine[1]/InvoicedQuantity)
}
if len(validate.Errors(issues)) == 0 {
// kurallardan geçti
}
// opsiyonel XSD katmanı: xmllint gerektirir, şema seti pakete gömülü
if err := validate.XSD(xmlBytes); err != nil { ... }
XAdES-BES ile imzalama (entegratör kullanıyorsanız gerek yok — imzayı
entegratör atar):
import "github.com/YusufDrymz/go-efatura/sign"
// Kamu SM test sertifikaları PFX dağıtılır (şifre: dosya adının son 6 hanesi)
s, err := sign.NewFromPKCS12(pfxBytes, "123456") // veya sign.NewFromPEM / sign.New(cert, cryptoSigner)
signed, err := s.Sign(ctx, xmlBytes) // placeholder gerçek imzayla değişir
res, err := sign.Verify(gelenFatura) // digest'ler + RSA; zincir kararı sizde
fmt.Println(res.Certificate.Subject.CommonName, res.SigningTime)
Zarflama ve gelen sistem yanıtını okuma:
import "github.com/YusufDrymz/go-efatura/envelope"
env, err := envelope.Build(envelope.Envelope{
Sender: envelope.Party{Alias: "urn:mail:defaultgb@ornek.com.tr", VKN: "9990000005", Title: "Örnek A.Ş."},
Receiver: envelope.Party{Alias: "urn:mail:defaultpk@alici.com.tr", VKN: "9990000013"},
Documents: [][]byte{signed}, // imzali fatura baytlari — bayt bayt korunur
})
zipped, err := envelope.Zip(env, zarfID) // GIB'e giden paket: tek xml, adi zarf ID
opened, err := envelope.Open(gelenZarf) // belgeler ham dilimlenir, imza bozulmaz
r, err := envelope.ParseResponse(opened.Documents[0]) // sistem yanıtı
fmt.Println(r.Code, envelope.StatusText(r.Code), envelope.StatusSucceeded(r.Code))
Durum kodları (1000–1300) ve anlamları Ek-2 kılavuzundan gelir;
StatusSucceeded/Failed/Pending sınıflandırması kılavuzdaki akışa göredir.
Zarf açmada belgeler yeniden serialize edilmez, orijinal baytlarıyla
dilimlenir — testlerdeki uçtan uca zincir (kur → imzala → zarfla → aç →
imza doğrula) bunu garanti eder.
İmza yapısı GİB'in resmi imzalı örnekleriyle birebir aynı iskelettedir
(rsa-sha256, tek enveloped transform, SignedProperties referansı) ve
testlerde gerçek bir GİB test mührü imzasının SignedInfo/SignedProperties
kısımları bizim kanonikalizasyonla doğrulanır. Yine de bu katman GİB'in
imza doğrulayıcısına karşı test edilmemiştir — canlıya çıkmadan kendi
mührünüzle uçtan uca deneyin. crypto.Signer kabul edildiği için HSM/
PKCS#11 implementasyonu dışarıdan takılabilir.
Kuralların kaynağı GİB'in resmi schematron dosyalarıdır; her bulgu,
schematron'daki kural ID'siyle gelir (UBLVersionIDCheck, decimalCheck,
WithholdingTaxTotalCheck...). GOEF- önekli kurallar go-efatura'nın ek
kurallarıdır: GİB schematron'u aritmetik tutarlılığı ve VKN/TCKN
checksum'ını hiç denetlemez — toplam formülleri ve checksum'lar burada
doğrulanır. Kapsam kritik fatura alt kümesidir; zarf ve e-İrsaliye kuralları
sonraki fazlarda.
Çalışan örnek: examples/. Yuvarlama tercihi: satır ve
vergi tutarları 2 haneye half-up yuvarlanır, toplamlar yuvarlanmış
değerlerden türetilir — GİB hiçbir kılavuzda yöntem tanımlamadığı için bu
bilinçli ve dokümante bir tercihtir; resmi örneklerdeki değerlerle uyumludur.
Model, UBL-TR kılavuzlarındaki eleman sırasını birebir taşır (XSD sequence
tabanlı olduğu için alan sırası sözleşmenin parçası). Tutarlar
shopspring/decimal üzerine kurulu Dec tipiyle taşınır ve parse edilen
ölçek korunur: 18.0 geri yazarken 18 olmaz, 18.0 kalır.
Yol haritası
| Sürüm |
Katman |
İçerik |
| v0.1 ✓ |
ubltr/ |
belge modeli, builder, otomatik toplam/KDV hesabı, golden testler |
| v0.2 ✓ |
validate/ |
GİB schematron kurallarının kritik alt kümesi (kural ID referanslı) + XSD katmanı |
| v0.3 ✓ |
sign/ |
XAdES-BES imza + doğrulama, pluggable Signer |
| v0.4 ✓ |
envelope/ |
SBDH zarf + zip paketleme + sistem yanıtı / durum kodları |
| v0.5+ |
transport/, earsiv/ |
entegratör adaptörleri, GİB doğrudan entegrasyon, e-Arşiv raporu |
Kapsam ve duruş
- Yalnız resmi yollar hedeflenir: UBL-TR belge + özel entegratör veya GİB
doğrudan entegrasyon. e-Arşiv portalının resmi olmayan JSON API'si
(earsivportal) kapsam dışıdır: dokümante değil, sık kırılıyor.
- Test verileri GİB'in kamuya açık paketlerindeki resmi örneklerden gelir
(
ubltr/testdata/gib/). Gerçek mükellef verisi yoktur; sentetik
fixture'larda VKN/TCKN değerleri uydurma ama checksum-geçerlidir.
- İmza katmanı çekirdeğe bulaşmaz: entegratör kullanan çoğunluk belgeyi
imzasız üretir, imzayı entegratör atar. GİB XSD'si
UBLExtensions'ı
zorunlu kıldığı için imzasız belgede şema-geçerli bir placeholder yazılır;
imzacı bunu XAdES içeriğiyle değiştirir.
English
Go library for Turkish electronic invoices (GİB e-Fatura / e-Arşiv,
UBL-TR 1.2 — a national customization of OASIS UBL 2.1). Ships the
document layer (build invoices with automatic VAT distribution and totals,
parse official documents, re-emit deterministic prefix-correct XML) and a
validation layer implementing the critical subset of GİB's official
schematron rules — every finding carries the schematron rule ID — plus an
optional XSD check backed by the embedded official schema set (requires
xmllint), and an XAdES-BES signing/verification layer mirroring the exact
structure of GİB's official signed samples (tests verify a real GİB test
seal signature with our canonicalization), and an SBDH envelope layer with
status codes — documents travel through envelopes byte-intact, so
signatures survive the round trip. Roadmap: integrator transports (v0.5+).
Docs are in Turkish on purpose — the domain, its terminology and its
regulator are Turkish.
License
MIT — see LICENSE.