package handlers import ( "net/http" "strconv" "strings" "git.mchus.pro/mchus/quoteforge/internal/localdb" "git.mchus.pro/mchus/quoteforge/internal/repository" "github.com/gin-gonic/gin" ) // PartnumberBooksHandler provides read-only access to local partnumber book snapshots. type PartnumberBooksHandler struct { localDB *localdb.LocalDB } func NewPartnumberBooksHandler(localDB *localdb.LocalDB) *PartnumberBooksHandler { return &PartnumberBooksHandler{localDB: localDB} } // List returns all local partnumber book snapshots. // GET /api/partnumber-books func (h *PartnumberBooksHandler) List(c *gin.Context) { bookRepo := repository.NewPartnumberBookRepository(h.localDB.DB()) books, err := bookRepo.ListBooks() if err != nil { RespondError(c, http.StatusInternalServerError, "internal server error", err) return } type bookSummary struct { ID uint `json:"id"` ServerID int `json:"server_id"` Version string `json:"version"` CreatedAt string `json:"created_at"` IsActive bool `json:"is_active"` ItemCount int64 `json:"item_count"` } summaries := make([]bookSummary, 0, len(books)) for _, b := range books { summaries = append(summaries, bookSummary{ ID: b.ID, ServerID: b.ServerID, Version: b.Version, CreatedAt: b.CreatedAt.Format("2006-01-02"), IsActive: b.IsActive, ItemCount: bookRepo.CountBookItems(b.ID), }) } c.JSON(http.StatusOK, gin.H{ "books": summaries, "total": len(summaries), }) } // GetItems returns items for a partnumber book by server ID. // GET /api/partnumber-books/:id func (h *PartnumberBooksHandler) GetItems(c *gin.Context) { idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid book ID"}) return } bookRepo := repository.NewPartnumberBookRepository(h.localDB.DB()) page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) perPage, _ := strconv.Atoi(c.DefaultQuery("per_page", "100")) search := strings.TrimSpace(c.Query("search")) if page < 1 { page = 1 } if perPage < 1 || perPage > 500 { perPage = 100 } // Find local book by server_id var book localdb.LocalPartnumberBook if err := h.localDB.DB().Where("server_id = ?", id).First(&book).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "partnumber book not found"}) return } items, total, err := bookRepo.GetBookItemsPage(book.ID, search, page, perPage) if err != nil { RespondError(c, http.StatusInternalServerError, "internal server error", err) return } c.JSON(http.StatusOK, gin.H{ "book_id": book.ServerID, "version": book.Version, "is_active": book.IsActive, "partnumbers": book.PartnumbersJSON, "items": items, "total": total, "page": page, "per_page": perPage, "search": search, "book_total": bookRepo.CountBookItems(book.ID), "lot_count": bookRepo.CountDistinctLots(book.ID), }) }