242 lines
7.4 KiB
Go
242 lines
7.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.mchus.pro/mchus/priceforge/internal/models"
|
|
"git.mchus.pro/mchus/priceforge/internal/services/pricelist"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type PricelistHandler struct {
|
|
service *pricelist.Service
|
|
dbUser string
|
|
}
|
|
|
|
func NewPricelistHandler(service *pricelist.Service, dbUser string) *PricelistHandler {
|
|
return &PricelistHandler{service: service, dbUser: dbUser}
|
|
}
|
|
|
|
func (h *PricelistHandler) List(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
perPage, _ := strconv.Atoi(c.DefaultQuery("per_page", "20"))
|
|
source := c.Query("source")
|
|
activeOnly := c.DefaultQuery("active_only", "false") == "true"
|
|
|
|
var (
|
|
list []models.PricelistSummary
|
|
total int64
|
|
err error
|
|
)
|
|
if activeOnly {
|
|
list, total, err = h.service.ListActiveBySource(page, perPage, source)
|
|
} else {
|
|
list, total, err = h.service.ListBySource(page, perPage, source)
|
|
}
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"pricelists": list, "total": total, "page": page, "per_page": perPage})
|
|
}
|
|
|
|
func (h *PricelistHandler) Get(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid pricelist ID"})
|
|
return
|
|
}
|
|
pl, err := h.service.GetByID(uint(id))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "pricelist not found"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, pl)
|
|
}
|
|
|
|
func (h *PricelistHandler) Create(c *gin.Context) {
|
|
canWrite, debugInfo := h.service.CanWriteDebug()
|
|
if !canWrite {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "pricelist write is not allowed", "debug": debugInfo})
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Source string `json:"source"`
|
|
Items []struct {
|
|
LotName string `json:"lot_name"`
|
|
Price float64 `json:"price"`
|
|
} `json:"items"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
source := string(models.NormalizePricelistSource(req.Source))
|
|
createdBy := h.dbUser
|
|
if strings.TrimSpace(createdBy) == "" {
|
|
createdBy = "unknown"
|
|
}
|
|
items := make([]pricelist.CreateItemInput, 0, len(req.Items))
|
|
for _, item := range req.Items {
|
|
items = append(items, pricelist.CreateItemInput{LotName: item.LotName, Price: item.Price})
|
|
}
|
|
|
|
pl, err := h.service.CreateForSourceWithProgress(createdBy, source, items, nil)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, pl)
|
|
}
|
|
|
|
func (h *PricelistHandler) CreateWithProgress(c *gin.Context) {
|
|
canWrite, debugInfo := h.service.CanWriteDebug()
|
|
if !canWrite {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "pricelist write is not allowed", "debug": debugInfo})
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Source string `json:"source"`
|
|
Items []struct {
|
|
LotName string `json:"lot_name"`
|
|
Price float64 `json:"price"`
|
|
} `json:"items"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
source := string(models.NormalizePricelistSource(req.Source))
|
|
createdBy := h.dbUser
|
|
if strings.TrimSpace(createdBy) == "" {
|
|
createdBy = "unknown"
|
|
}
|
|
items := make([]pricelist.CreateItemInput, 0, len(req.Items))
|
|
for _, item := range req.Items {
|
|
items = append(items, pricelist.CreateItemInput{LotName: item.LotName, Price: item.Price})
|
|
}
|
|
|
|
c.Header("Content-Type", "text/event-stream")
|
|
c.Header("Cache-Control", "no-cache")
|
|
c.Header("Connection", "keep-alive")
|
|
|
|
flusher, ok := c.Writer.(http.Flusher)
|
|
if !ok {
|
|
pl, err := h.service.CreateForSourceWithProgress(createdBy, source, items, nil)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, pl)
|
|
return
|
|
}
|
|
|
|
send := func(payload gin.H) { c.SSEvent("progress", payload); flusher.Flush() }
|
|
send(gin.H{"current": 0, "total": 100, "status": "starting", "message": "Запуск..."})
|
|
pl, err := h.service.CreateForSourceWithProgress(createdBy, source, items, func(p pricelist.CreateProgress) {
|
|
send(gin.H{"current": p.Current, "total": p.Total, "status": p.Status, "message": p.Message, "updated": p.Updated, "errors": p.Errors, "lot_name": p.LotName})
|
|
})
|
|
if err != nil {
|
|
send(gin.H{"status": "error", "message": err.Error()})
|
|
return
|
|
}
|
|
send(gin.H{"current": 100, "total": 100, "status": "completed", "message": "Готово", "pricelist": pl})
|
|
}
|
|
|
|
func (h *PricelistHandler) Delete(c *gin.Context) {
|
|
canWrite, debugInfo := h.service.CanWriteDebug()
|
|
if !canWrite {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "pricelist write is not allowed", "debug": debugInfo})
|
|
return
|
|
}
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid pricelist ID"})
|
|
return
|
|
}
|
|
if err := h.service.Delete(uint(id)); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "pricelist deleted"})
|
|
}
|
|
|
|
func (h *PricelistHandler) SetActive(c *gin.Context) {
|
|
canWrite, debugInfo := h.service.CanWriteDebug()
|
|
if !canWrite {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "pricelist write is not allowed", "debug": debugInfo})
|
|
return
|
|
}
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid pricelist ID"})
|
|
return
|
|
}
|
|
var req struct {
|
|
IsActive bool `json:"is_active"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
if err := h.service.SetActive(uint(id), req.IsActive); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "updated", "is_active": req.IsActive})
|
|
}
|
|
|
|
func (h *PricelistHandler) GetItems(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid pricelist ID"})
|
|
return
|
|
}
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
perPage, _ := strconv.Atoi(c.DefaultQuery("per_page", "50"))
|
|
search := c.Query("search")
|
|
items, total, err := h.service.GetItems(uint(id), page, perPage, search)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"items": items, "total": total, "page": page, "per_page": perPage})
|
|
}
|
|
|
|
func (h *PricelistHandler) GetLotNames(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid pricelist ID"})
|
|
return
|
|
}
|
|
lotNames, err := h.service.GetLotNames(uint(id))
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"lot_names": lotNames, "total": len(lotNames)})
|
|
}
|
|
|
|
func (h *PricelistHandler) CanWrite(c *gin.Context) {
|
|
canWrite, debugInfo := h.service.CanWriteDebug()
|
|
c.JSON(http.StatusOK, gin.H{"can_write": canWrite, "debug": debugInfo})
|
|
}
|
|
|
|
func (h *PricelistHandler) GetLatest(c *gin.Context) {
|
|
source := string(models.NormalizePricelistSource(c.DefaultQuery("source", string(models.PricelistSourceEstimate))))
|
|
pl, err := h.service.GetLatestActiveBySource(source)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "no pricelists available"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, pl)
|
|
}
|