package handlers import ( "fmt" "net/http" "strconv" "time" "erp_system/internal/models" ) func (h *Handler) OrderList(w http.ResponseWriter, r *http.Request) { status := r.URL.Query().Get("status") orders, err := models.OrderGetAll(h.DB, status) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } data := map[string]interface{}{ "Title": "Orders", "Username": h.getUsername(r), "ActivePage": "orders", "Orders": orders, "FilterStatus": status, } if r.Header.Get("HX-Request") == "true" && r.URL.Query().Get("partial") == "true" { h.renderPartial(w, "orders/list.html", "order-table", data) return } h.render(w, []string{"layout.html", "orders/list.html"}, data) } func (h *Handler) OrderNew(w http.ResponseWriter, r *http.Request) { customers, _ := models.CustomerGetAll(h.DB, "") data := map[string]interface{}{ "Title": "New Order", "Username": h.getUsername(r), "ActivePage": "orders", "Order": &models.Order{OrderDate: time.Now().Format("2006-01-02"), Status: "draft"}, "Customers": customers, "IsNew": true, } h.render(w, []string{"layout.html", "orders/form.html"}, data) } func (h *Handler) OrderCreate(w http.ResponseWriter, r *http.Request) { customerID, _ := strconv.Atoi(r.FormValue("customer_id")) o := &models.Order{ CustomerID: customerID, Status: "draft", OrderDate: r.FormValue("order_date"), Notes: r.FormValue("notes"), } if o.CustomerID == 0 { customers, _ := models.CustomerGetAll(h.DB, "") data := map[string]interface{}{ "Title": "New Order", "Username": h.getUsername(r), "ActivePage": "orders", "Order": o, "Customers": customers, "IsNew": true, "Error": "Customer is required", } h.render(w, []string{"layout.html", "orders/form.html"}, data) return } if o.OrderDate == "" { o.OrderDate = time.Now().Format("2006-01-02") } if err := models.OrderInsert(h.DB, o); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", fmt.Sprintf("/orders/%d", o.ID)) return } http.Redirect(w, r, fmt.Sprintf("/orders/%d", o.ID), http.StatusSeeOther) } func (h *Handler) OrderDetail(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) order, err := models.OrderGetByID(h.DB, id) if err != nil { http.Error(w, "Order not found", http.StatusNotFound) return } data := map[string]interface{}{ "Title": fmt.Sprintf("Order #%d", order.ID), "Username": h.getUsername(r), "ActivePage": "orders", "Order": order, } h.render(w, []string{"layout.html", "orders/detail.html"}, data) } func (h *Handler) OrderEdit(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) order, err := models.OrderGetByID(h.DB, id) if err != nil { http.Error(w, "Order not found", http.StatusNotFound) return } if order.Status != "draft" { http.Error(w, "Only draft orders can be edited", http.StatusBadRequest) return } customers, _ := models.CustomerGetAll(h.DB, "") data := map[string]interface{}{ "Title": fmt.Sprintf("Edit Order #%d", order.ID), "Username": h.getUsername(r), "ActivePage": "orders", "Order": order, "Customers": customers, "IsNew": false, } h.render(w, []string{"layout.html", "orders/form.html"}, data) } func (h *Handler) OrderUpdate(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) customerID, _ := strconv.Atoi(r.FormValue("customer_id")) o := &models.Order{ ID: id, CustomerID: customerID, OrderDate: r.FormValue("order_date"), Notes: r.FormValue("notes"), } if err := models.OrderUpdate(h.DB, o); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", fmt.Sprintf("/orders/%d", id)) return } http.Redirect(w, r, fmt.Sprintf("/orders/%d", id), http.StatusSeeOther) } func (h *Handler) OrderConfirm(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) if err := models.OrderUpdateStatus(h.DB, id, "confirmed"); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", fmt.Sprintf("/orders/%d", id)) return } http.Redirect(w, r, fmt.Sprintf("/orders/%d", id), http.StatusSeeOther) } func (h *Handler) OrderFulfill(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) // Update status if err := models.OrderUpdateStatus(h.DB, id, "fulfilled"); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Generate invoice and GL entries if err := models.GenerateInvoiceFromOrder(h.DB, id); err != nil { http.Error(w, fmt.Sprintf("Order fulfilled but invoice generation failed: %v", err), http.StatusInternalServerError) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", fmt.Sprintf("/orders/%d", id)) return } http.Redirect(w, r, fmt.Sprintf("/orders/%d", id), http.StatusSeeOther) } func (h *Handler) OrderCancel(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) if err := models.OrderUpdateStatus(h.DB, id, "cancelled"); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", fmt.Sprintf("/orders/%d", id)) return } http.Redirect(w, r, fmt.Sprintf("/orders/%d", id), http.StatusSeeOther) } func (h *Handler) OrderDelete(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(r.PathValue("id")) if err := models.OrderDelete(h.DB, id); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.Header.Get("HX-Request") == "true" { w.Header().Set("HX-Redirect", "/orders") return } http.Redirect(w, r, "/orders", http.StatusSeeOther) } // Order line handlers (HTMX partials) func (h *Handler) OrderLineAdd(w http.ResponseWriter, r *http.Request) { orderID, _ := strconv.Atoi(r.PathValue("id")) qty, _ := strconv.ParseFloat(r.FormValue("quantity"), 64) price, _ := strconv.ParseFloat(r.FormValue("unit_price"), 64) line := &models.OrderLine{ OrderID: orderID, Description: r.FormValue("description"), Quantity: qty, UnitPrice: price, } if line.Description == "" || line.Quantity <= 0 { http.Error(w, "Description and quantity are required", http.StatusBadRequest) return } if err := models.OrderLineInsert(h.DB, line); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Return updated order detail order, err := models.OrderGetByID(h.DB, orderID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } h.renderPartial(w, "orders/detail.html", "order-lines", order) } func (h *Handler) OrderLineDelete(w http.ResponseWriter, r *http.Request) { orderID, _ := strconv.Atoi(r.PathValue("id")) lineID, _ := strconv.Atoi(r.PathValue("lineID")) if err := models.OrderLineDelete(h.DB, lineID, orderID); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Return updated order detail order, err := models.OrderGetByID(h.DB, orderID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } h.renderPartial(w, "orders/detail.html", "order-lines", order) }