LINUS ROUND 1: Delete dead code (rust/c), generic Store[T], tests, slim main.go

- Removed rust-service/, c-runtime/, kafka stubs
- Generic Store[T] pattern with real tests
- Slimmed main.go from 324 to ~50 lines
- Added config, middleware, store, ledger, pdf tests
- Frontend SPA shell with router
- Binary: 15.5MB -> 12MB
This commit is contained in:
Bernt (LandveX AI)
2026-07-14 12:31:55 +00:00
parent 95b581e8c5
commit c2b10347b1
1100 changed files with 1544 additions and 7058 deletions
+207
View File
@@ -0,0 +1,207 @@
// Package pdf provides generic document generation.
// One function, multiple document types. Linus-style.
package pdf
import (
"bytes"
"fmt"
"time"
"github.com/jung-kurt/gofpdf"
)
// DocType represents the type of document
type DocType string
const (
InvoiceDoc DocType = "FAKTURA"
QuoteDoc DocType = "OFFERT"
)
// LineItem represents a single line on a document
type LineItem struct {
Description string
Quantity float64
Unit string
UnitPrice float64
Total float64
}
// DocumentData contains all data needed to generate a document
type DocumentData struct {
DocType DocType
DocNumber string
DocDate time.Time
ValidUntil *time.Time
CustomerName string
CustomerAddress string
CustomerOrgNr string
Items []LineItem
Subtotal float64
VATRate float64
VATAmount float64
Total float64
Currency string
CompanyName string
CompanyAddress string
CompanyOrgNr string
CompanyBankgiro string
Notes string
}
// GenerateDocument creates a professional PDF document
func GenerateDocument(data DocumentData) ([]byte, error) {
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
// Header with document type
pdf.SetFont("Arial", "B", 20)
pdf.SetTextColor(201, 106, 58) // Terracotta
pdf.Cell(0, 12, string(data.DocType))
pdf.Ln(8)
// Company info
pdf.SetFont("Arial", "B", 10)
pdf.SetTextColor(50, 50, 50)
pdf.Cell(0, 5, data.CompanyName)
pdf.Ln(5)
pdf.SetFont("Arial", "", 9)
pdf.Cell(0, 4, data.CompanyAddress)
pdf.Ln(4)
if data.CompanyOrgNr != "" {
pdf.Cell(0, 4, fmt.Sprintf("Org.nr: %s", data.CompanyOrgNr))
pdf.Ln(4)
}
if data.CompanyBankgiro != "" {
pdf.Cell(0, 4, fmt.Sprintf("Bankgiro: %s", data.CompanyBankgiro))
pdf.Ln(4)
}
pdf.Ln(5)
// Document details box
pdf.SetFillColor(250, 248, 245)
pdf.Rect(130, 30, 70, 35, "F")
pdf.SetXY(135, 33)
pdf.SetFont("Arial", "B", 9)
pdf.SetTextColor(201, 106, 58)
pdf.Cell(0, 5, docInfoLabel(data.DocType))
pdf.Ln(6)
pdf.SetFont("Arial", "", 9)
pdf.SetTextColor(50, 50, 50)
pdf.SetX(135)
pdf.Cell(0, 4, fmt.Sprintf("%s: %s", docNumberLabel(data.DocType), data.DocNumber))
pdf.Ln(4)
pdf.SetX(135)
pdf.Cell(0, 4, fmt.Sprintf("Datum: %s", data.DocDate.Format("2006-01-02")))
pdf.Ln(4)
if data.ValidUntil != nil {
pdf.SetX(135)
pdf.Cell(0, 4, fmt.Sprintf("Giltig till: %s", data.ValidUntil.Format("2006-01-02")))
pdf.Ln(4)
}
pdf.SetX(135)
pdf.Cell(0, 4, fmt.Sprintf("Valuta: %s", data.Currency))
pdf.Ln(4)
// Customer info
pdf.SetXY(10, 75)
pdf.SetFont("Arial", "B", 10)
pdf.SetTextColor(201, 106, 58)
pdf.Cell(0, 5, "KUND")
pdf.Ln(6)
pdf.SetFont("Arial", "B", 10)
pdf.SetTextColor(50, 50, 50)
pdf.Cell(0, 5, data.CustomerName)
pdf.Ln(5)
pdf.SetFont("Arial", "", 9)
pdf.Cell(0, 4, data.CustomerAddress)
pdf.Ln(4)
if data.CustomerOrgNr != "" {
pdf.Cell(0, 4, fmt.Sprintf("Org.nr: %s", data.CustomerOrgNr))
pdf.Ln(4)
}
pdf.Ln(10)
// Items table header
pdf.SetFillColor(201, 106, 58)
pdf.SetTextColor(255, 255, 255)
pdf.SetFont("Arial", "B", 9)
pdf.Cell(80, 8, "Beskrivning")
pdf.Cell(25, 8, "Antal")
pdf.Cell(25, 8, "Enhet")
pdf.Cell(30, 8, "Pris")
pdf.Cell(30, 8, "Belopp")
pdf.Ln(8)
// Items
pdf.SetTextColor(50, 50, 50)
pdf.SetFont("Arial", "", 9)
for i, item := range data.Items {
if i%2 == 0 {
pdf.SetFillColor(250, 248, 245)
pdf.Rect(10, pdf.GetY(), 190, 6, "F")
}
pdf.Cell(80, 6, item.Description)
pdf.Cell(25, 6, fmt.Sprintf("%.2f", item.Quantity))
pdf.Cell(25, 6, item.Unit)
pdf.Cell(30, 6, fmt.Sprintf("%.2f", item.UnitPrice))
pdf.Cell(30, 6, fmt.Sprintf("%.2f", item.Total))
pdf.Ln(6)
}
pdf.Ln(5)
// Totals
pdf.SetX(120)
pdf.SetFont("Arial", "", 9)
pdf.Cell(40, 5, "Delsumma:")
pdf.Cell(30, 5, fmt.Sprintf("%.2f %s", data.Subtotal, data.Currency))
pdf.Ln(5)
pdf.SetX(120)
pdf.Cell(40, 5, fmt.Sprintf("Moms (%.0f%%):", data.VATRate*100))
pdf.Cell(30, 5, fmt.Sprintf("%.2f %s", data.VATAmount, data.Currency))
pdf.Ln(5)
pdf.SetX(120)
pdf.SetFont("Arial", "B", 11)
pdf.SetTextColor(201, 106, 58)
totalLabel := "ATT BETALA:"
if data.DocType == QuoteDoc {
totalLabel = "TOTALT:"
}
pdf.Cell(40, 7, totalLabel)
pdf.Cell(30, 7, fmt.Sprintf("%.2f %s", data.Total, data.Currency))
pdf.Ln(10)
// Notes
if data.Notes != "" {
pdf.SetFont("Arial", "I", 8)
pdf.SetTextColor(100, 100, 100)
pdf.MultiCell(0, 4, data.Notes, "", "", false)
}
// Footer
pdf.SetY(-20)
pdf.SetFont("Arial", "", 8)
pdf.SetTextColor(150, 150, 150)
pdf.Cell(0, 4, fmt.Sprintf("%s | %s %s | Sida %d", data.CompanyName, data.DocType, data.DocNumber, pdf.PageNo()))
var buf bytes.Buffer
if err := pdf.Output(&buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func docInfoLabel(dt DocType) string {
if dt == QuoteDoc {
return "OFFERTINFORMATION"
}
return "FAKTURAINFORMATION"
}
func docNumberLabel(dt DocType) string {
if dt == QuoteDoc {
return "Offertnr"
}
return "Fakturanr"
}