package handlers import ( "database/sql" "encoding/json" "net/http" "time" "github.com/go-chi/chi/v5" ) type OrderHandler struct { DB *sql.DB } func NewOrderHandler(db *sql.DB) *OrderHandler { return &OrderHandler{DB: db} } type Order struct { ID string `json:"id"` CustomerID string `json:"customer_id"` QuoteID *string `json:"quote_id"` OrderNumber string `json:"order_number"` Title string `json:"title"` Status string `json:"status"` Amount float64 `json:"amount"` TaxAmount float64 `json:"tax_amount"` Currency string `json:"currency"` DeliveryDate *time.Time `json:"delivery_date"` ShippedAt *time.Time `json:"shipped_at"` DeliveredAt *time.Time `json:"delivered_at"` TrackingNumber string `json:"tracking_number"` Notes string `json:"notes"` CreatedAt time.Time `json:"created_at"` } func (h *OrderHandler) ListOrders(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, customer_id, quote_id, order_number, title, status, amount, currency, delivery_date, shipped_at, delivered_at, tracking_number, created_at FROM boc_orders ORDER BY created_at DESC LIMIT 100` } else { query = `SELECT id, customer_id, quote_id, order_number, title, status, amount, currency, delivery_date, shipped_at, delivered_at, tracking_number, created_at FROM boc_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() orders := []Order{} for rows.Next() { var o Order if err := rows.Scan(&o.ID, &o.CustomerID, &o.QuoteID, &o.OrderNumber, &o.Title, &o.Status, &o.Amount, &o.Currency, &o.DeliveryDate, &o.ShippedAt, &o.DeliveredAt, &o.TrackingNumber, &o.CreatedAt); err != nil { continue } orders = append(orders, o) } writeJSON(w, http.StatusOK, map[string]interface{}{ "orders": orders, "total": len(orders), }) } func (h *OrderHandler) CreateOrder(w http.ResponseWriter, r *http.Request) { var req struct { CustomerID string `json:"customer_id"` Title string `json:"title"` DeliveryDate *time.Time `json:"delivery_date"` 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 } orderNumber := "O-" + 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_orders (customer_id, order_number, title, amount, tax_amount, currency, delivery_date, notes) VALUES ($1, $2, $3, $4, $5, 'USD', $6, $7) RETURNING id `, req.CustomerID, orderNumber, req.Title, totalAmount, totalTax, req.DeliveryDate, req.Notes).Scan(&id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to create order") return } for _, item := range req.Items { itemTotal := item.Quantity * item.UnitPrice _, err = tx.Exec(` INSERT INTO boc_order_items (order_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 order 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": orderNumber, "message": "Order created", }) } func (h *OrderHandler) GetOrder(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") var o Order err := h.DB.QueryRow(` SELECT id, customer_id, quote_id, order_number, title, status, amount, tax_amount, currency, delivery_date, shipped_at, delivered_at, tracking_number, notes, created_at FROM boc_orders WHERE id = $1 `, id).Scan(&o.ID, &o.CustomerID, &o.QuoteID, &o.OrderNumber, &o.Title, &o.Status, &o.Amount, &o.TaxAmount, &o.Currency, &o.DeliveryDate, &o.ShippedAt, &o.DeliveredAt, &o.TrackingNumber, &o.Notes, &o.CreatedAt) if err == sql.ErrNoRows { writeError(w, http.StatusNotFound, "order not found") return } if err != nil { writeError(w, http.StatusInternalServerError, "database error") return } writeJSON(w, http.StatusOK, o) } func (h *OrderHandler) UpdateOrder(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") var req Order if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request") return } _, err := h.DB.Exec(` UPDATE boc_orders SET status = $1, delivery_date = $2, tracking_number = $3, notes = $4 WHERE id = $5 `, req.Status, req.DeliveryDate, req.TrackingNumber, req.Notes, id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to update order") return } writeJSON(w, http.StatusOK, map[string]interface{}{ "message": "Order updated", }) } func (h *OrderHandler) ShipOrder(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") var req struct { TrackingNumber string `json:"tracking_number"` } json.NewDecoder(r.Body).Decode(&req) _, err := h.DB.Exec(` UPDATE boc_orders SET status = 'shipped', shipped_at = NOW(), tracking_number = $1 WHERE id = $2 `, req.TrackingNumber, id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to ship order") return } writeJSON(w, http.StatusOK, map[string]interface{}{ "message": "Order shipped", }) } func (h *OrderHandler) DeliverOrder(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") _, err := h.DB.Exec(` UPDATE boc_orders SET status = 'delivered', delivered_at = NOW() WHERE id = $1 `, id) if err != nil { writeError(w, http.StatusInternalServerError, "failed to deliver order") return } writeJSON(w, http.StatusOK, map[string]interface{}{ "message": "Order delivered", }) }