feat(boc): v1.0 - Complete Business Operations Center

- Go backend API with full CRUD for all modules
- Rust analytics service with parallel processing
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables
- Redis cache, Kafka event streaming
- WebSocket hub, automation engine
- PDF generation, Resend email integration
- JWT auth, multi-tenant
- Docker Compose deployment
- Nginx reverse proxy

Refs: BOC-001
This commit is contained in:
Bernt (LandveX AI)
2026-07-12 13:21:10 +00:00
commit 67a69ab073
1130 changed files with 18263 additions and 0 deletions
+286
View File
@@ -0,0 +1,286 @@
package handlers
import (
"database/sql"
"encoding/json"
"net/http"
"time"
)
type SupplierHandler struct {
DB *sql.DB
}
func NewSupplierHandler(db *sql.DB) *SupplierHandler {
return &SupplierHandler{DB: db}
}
type Supplier struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Phone string `json:"phone"`
OrgNumber string `json:"org_number"`
Address map[string]interface{} `json:"address"`
PaymentTerms string `json:"payment_terms"`
BankAccount string `json:"bank_account"`
Bankgiro string `json:"bankgiro"`
Postgiro string `json:"postgiro"`
Currency string `json:"currency"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
type PurchaseOrder struct {
ID string `json:"id"`
SupplierID string `json:"supplier_id"`
PONumber string `json:"po_number"`
Status string `json:"status"`
Amount float64 `json:"amount"`
TaxAmount float64 `json:"tax_amount"`
Currency string `json:"currency"`
ExpectedDelivery *time.Time `json:"expected_delivery"`
ReceivedAt *time.Time `json:"received_at"`
Notes string `json:"notes"`
CreatedAt time.Time `json:"created_at"`
}
type SupplierInvoice struct {
ID string `json:"id"`
SupplierID string `json:"supplier_id"`
POID *string `json:"po_id"`
InvoiceNumber string `json:"invoice_number"`
Amount float64 `json:"amount"`
TaxAmount float64 `json:"tax_amount"`
Currency string `json:"currency"`
Status string `json:"status"`
DueDate *time.Time `json:"due_date"`
PaidAt *time.Time `json:"paid_at"`
OCRNumber string `json:"ocr_number"`
Notes string `json:"notes"`
CreatedAt time.Time `json:"created_at"`
}
func (h *SupplierHandler) ListSuppliers(w http.ResponseWriter, r *http.Request) {
rows, err := h.DB.Query(`
SELECT id, name, email, phone, org_number, address, payment_terms, bank_account, bankgiro, postgiro, currency, status, created_at
FROM boc_suppliers WHERE status = 'active' ORDER BY name
`)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
suppliers := []Supplier{}
for rows.Next() {
var s Supplier
var addr []byte
if err := rows.Scan(&s.ID, &s.Name, &s.Email, &s.Phone, &s.OrgNumber, &addr, &s.PaymentTerms, &s.BankAccount, &s.Bankgiro, &s.Postgiro, &s.Currency, &s.Status, &s.CreatedAt); err != nil {
continue
}
json.Unmarshal(addr, &s.Address)
suppliers = append(suppliers, s)
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"suppliers": suppliers,
"total": len(suppliers),
})
}
func (h *SupplierHandler) CreateSupplier(w http.ResponseWriter, r *http.Request) {
var req Supplier
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid request")
return
}
addr, _ := json.Marshal(req.Address)
var id string
err := h.DB.QueryRow(`
INSERT INTO boc_suppliers (name, email, phone, org_number, address, payment_terms, bank_account, bankgiro, postgiro, currency)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id
`, req.Name, req.Email, req.Phone, req.OrgNumber, addr, req.PaymentTerms, req.BankAccount, req.Bankgiro, req.Postgiro, req.Currency).Scan(&id)
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to create supplier")
return
}
writeJSON(w, http.StatusCreated, map[string]interface{}{
"id": id,
"message": "Supplier created",
})
}
func (h *SupplierHandler) ListPurchaseOrders(w http.ResponseWriter, r *http.Request) {
status := r.URL.Query().Get("status")
if status == "" {
status = "all"
}
var query string
var args []interface{}
if status == "all" {
query = `SELECT id, supplier_id, po_number, status, amount, currency, expected_delivery, received_at, created_at FROM boc_purchase_orders ORDER BY created_at DESC LIMIT 100`
} else {
query = `SELECT id, supplier_id, po_number, status, amount, currency, expected_delivery, received_at, created_at FROM boc_purchase_orders WHERE status = $1 ORDER BY created_at DESC LIMIT 100`
args = append(args, status)
}
rows, err := h.DB.Query(query, args...)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
pos := []PurchaseOrder{}
for rows.Next() {
var p PurchaseOrder
if err := rows.Scan(&p.ID, &p.SupplierID, &p.PONumber, &p.Status, &p.Amount, &p.Currency, &p.ExpectedDelivery, &p.ReceivedAt, &p.CreatedAt); err != nil {
continue
}
pos = append(pos, p)
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"purchase_orders": pos,
"total": len(pos),
})
}
func (h *SupplierHandler) CreatePurchaseOrder(w http.ResponseWriter, r *http.Request) {
var req struct {
SupplierID string `json:"supplier_id"`
ExpectedDelivery *time.Time `json:"expected_delivery"`
Notes string `json:"notes"`
Items []struct {
ProductID string `json:"product_id"`
Description string `json:"description"`
Quantity float64 `json:"quantity"`
UnitPrice float64 `json:"unit_price"`
TaxRate float64 `json:"tax_rate"`
} `json:"items"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid request")
return
}
poNumber := "PO-" + time.Now().Format("20060102-150405")
var totalAmount, totalTax float64
for _, item := range req.Items {
itemTotal := item.Quantity * item.UnitPrice
itemTax := itemTotal * (item.TaxRate / 100)
totalAmount += itemTotal
totalTax += itemTax
}
tx, err := h.DB.Begin()
if err != nil {
writeError(w, http.StatusInternalServerError, "transaction error")
return
}
defer tx.Rollback()
var id string
err = tx.QueryRow(`
INSERT INTO boc_purchase_orders (supplier_id, po_number, amount, tax_amount, currency, expected_delivery, notes)
VALUES ($1, $2, $3, $4, 'USD', $5, $6)
RETURNING id
`, req.SupplierID, poNumber, totalAmount, totalTax, req.ExpectedDelivery, req.Notes).Scan(&id)
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to create PO")
return
}
for _, item := range req.Items {
itemTotal := item.Quantity * item.UnitPrice
_, err = tx.Exec(`
INSERT INTO boc_purchase_order_items (po_id, product_id, description, quantity, unit_price, tax_rate, total)
VALUES ($1, $2, $3, $4, $5, $6, $7)
`, id, item.ProductID, item.Description, item.Quantity, item.UnitPrice, item.TaxRate, itemTotal)
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to create PO items")
return
}
}
if err := tx.Commit(); err != nil {
writeError(w, http.StatusInternalServerError, "commit failed")
return
}
writeJSON(w, http.StatusCreated, map[string]interface{}{
"id": id,
"number": poNumber,
"message": "Purchase order created",
})
}
func (h *SupplierHandler) ListSupplierInvoices(w http.ResponseWriter, r *http.Request) {
status := r.URL.Query().Get("status")
if status == "" {
status = "all"
}
var query string
var args []interface{}
if status == "all" {
query = `SELECT id, supplier_id, po_id, invoice_number, amount, currency, status, due_date, paid_at, ocr_number, created_at FROM boc_supplier_invoices ORDER BY created_at DESC LIMIT 100`
} else {
query = `SELECT id, supplier_id, po_id, invoice_number, amount, currency, status, due_date, paid_at, ocr_number, created_at FROM boc_supplier_invoices WHERE status = $1 ORDER BY created_at DESC LIMIT 100`
args = append(args, status)
}
rows, err := h.DB.Query(query, args...)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
invoices := []SupplierInvoice{}
for rows.Next() {
var i SupplierInvoice
if err := rows.Scan(&i.ID, &i.SupplierID, &i.POID, &i.InvoiceNumber, &i.Amount, &i.Currency, &i.Status, &i.DueDate, &i.PaidAt, &i.OCRNumber, &i.CreatedAt); err != nil {
continue
}
invoices = append(invoices, i)
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"invoices": invoices,
"total": len(invoices),
})
}
func (h *SupplierHandler) CreateSupplierInvoice(w http.ResponseWriter, r *http.Request) {
var req SupplierInvoice
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid request")
return
}
var id string
err := h.DB.QueryRow(`
INSERT INTO boc_supplier_invoices (supplier_id, po_id, invoice_number, amount, tax_amount, currency, due_date, ocr_number, notes)
VALUES ($1, $2, $3, $4, $5, 'USD', $6, $7, $8)
RETURNING id
`, req.SupplierID, req.POID, req.InvoiceNumber, req.Amount, req.TaxAmount, req.DueDate, req.OCRNumber, req.Notes).Scan(&id)
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to create supplier invoice")
return
}
writeJSON(w, http.StatusCreated, map[string]interface{}{
"id": id,
"message": "Supplier invoice created",
})
}