package httpapi import ( "net/http" "strconv" "strings" "time" "github.com/descrybe/descrybe-v2/apps/api/internal/woocommerce" ) func (s *Server) handleSyncWooOrders(w http.ResponseWriter, r *http.Request) { if !s.requireFeatures(w, r, "stores.woocommerce") { return } cid, _ := CompanyIDFromContext(r.Context()) result, err := s.Woo.EnqueueOrdersSync(r.Context(), cid) if msg, ok := woocommerce.ClientError(err); ok { Error(w, http.StatusBadRequest, msg) return } if err != nil { LogAndError(w, http.StatusInternalServerError, "orders sync enqueue failed", err) return } JSON(w, http.StatusAccepted, result) } func (s *Server) handleSyncWooReviews(w http.ResponseWriter, r *http.Request) { if !s.requireFeatures(w, r, "stores.woocommerce") { return } cid, _ := CompanyIDFromContext(r.Context()) result, err := s.Woo.EnqueueReviewsSync(r.Context(), cid) if msg, ok := woocommerce.ClientError(err); ok { Error(w, http.StatusBadRequest, msg) return } if err != nil { LogAndError(w, http.StatusInternalServerError, "reviews sync enqueue failed", err) return } JSON(w, http.StatusAccepted, result) } func (s *Server) handleListWooOrders(w http.ResponseWriter, r *http.Request) { if s.Woo == nil { JSON(w, http.StatusOK, map[string]any{"orders": []any{}, "total": 0, "limit": 50, "offset": 0}) return } cid, _ := CompanyIDFromContext(r.Context()) limit, offset := ParseLimitOffset(r) f := woocommerce.OrderListFilter{ Status: strings.TrimSpace(r.URL.Query().Get("status")), Email: strings.TrimSpace(r.URL.Query().Get("email")), Limit: limit, Offset: offset, } if since := strings.TrimSpace(r.URL.Query().Get("since")); since != "" { if t, err := time.Parse(time.RFC3339, since); err == nil { f.Since = &t } else { Error(w, http.StatusBadRequest, "invalid since (use RFC3339)") return } } items, total, err := s.Woo.ListOrders(r.Context(), cid, f) if err != nil { // Missing table / first-run: return empty list so UI empty-states work. JSON(w, http.StatusOK, map[string]any{ "orders": []any{}, "total": 0, "limit": limit, "offset": offset, }) return } if items == nil { items = []woocommerce.OrderRow{} } JSON(w, http.StatusOK, map[string]any{ "orders": items, "total": total, "limit": limit, "offset": offset, }) } func (s *Server) handleListWooReviews(w http.ResponseWriter, r *http.Request) { if s.Woo == nil { JSON(w, http.StatusOK, map[string]any{"reviews": []any{}, "total": 0, "limit": 50, "offset": 0}) return } cid, _ := CompanyIDFromContext(r.Context()) limit, offset := ParseLimitOffset(r) f := woocommerce.ReviewListFilter{ Status: strings.TrimSpace(r.URL.Query().Get("status")), Limit: limit, Offset: offset, } if pid := strings.TrimSpace(r.URL.Query().Get("product_id")); pid != "" { n, err := strconv.ParseInt(pid, 10, 64) if err != nil || n <= 0 { Error(w, http.StatusBadRequest, "invalid product_id") return } f.ProductID = n } if mr := strings.TrimSpace(r.URL.Query().Get("min_rating")); mr != "" { n, err := strconv.Atoi(mr) if err != nil || n < 1 || n > 5 { Error(w, http.StatusBadRequest, "invalid min_rating") return } f.MinRating = n } items, total, err := s.Woo.ListReviews(r.Context(), cid, f) if err != nil { JSON(w, http.StatusOK, map[string]any{ "reviews": []any{}, "total": 0, "limit": limit, "offset": offset, }) return } if items == nil { items = []woocommerce.ReviewRow{} } JSON(w, http.StatusOK, map[string]any{ "reviews": items, "total": total, "limit": limit, "offset": offset, }) } func (s *Server) handleWooAudience(w http.ResponseWriter, r *http.Request) { if !s.requireFeatures(w, r, "stores.woocommerce") { return } cid, _ := CompanyIDFromContext(r.Context()) var body struct { BoughtCategory string `json:"bought_category"` NotBoughtCategory string `json:"not_bought_category"` Limit int `json:"limit"` } if err := DecodeJSON(r, &body); err != nil { Error(w, http.StatusBadRequest, "invalid json") return } if strings.TrimSpace(body.BoughtCategory) == "" { Error(w, http.StatusBadRequest, "bought_category is required") return } result, err := s.Woo.AudienceBoughtCategories(r.Context(), cid, body.BoughtCategory, body.NotBoughtCategory, body.Limit) if err != nil { LogAndError(w, http.StatusInternalServerError, "audience query failed", err) return } JSON(w, http.StatusOK, result) }