mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
333 lines
8.8 KiB
Go
333 lines
8.8 KiB
Go
package handlers
|
||
|
||
import (
|
||
"net/http"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/google/uuid"
|
||
"github.com/shopspring/decimal"
|
||
"go.uber.org/zap"
|
||
|
||
"rmser/internal/services/drafts"
|
||
"rmser/pkg/logger"
|
||
)
|
||
|
||
type DraftsHandler struct {
|
||
service *drafts.Service
|
||
}
|
||
|
||
func NewDraftsHandler(service *drafts.Service) *DraftsHandler {
|
||
return &DraftsHandler{service: service}
|
||
}
|
||
|
||
func (h *DraftsHandler) GetDraft(c *gin.Context) {
|
||
userID := c.MustGet("userID").(uuid.UUID)
|
||
idStr := c.Param("id")
|
||
id, err := uuid.Parse(idStr)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||
return
|
||
}
|
||
|
||
draft, err := h.service.GetDraft(id, userID)
|
||
if err != nil {
|
||
c.JSON(http.StatusNotFound, gin.H{"error": "draft not found"})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, draft)
|
||
}
|
||
|
||
func (h *DraftsHandler) GetDictionaries(c *gin.Context) {
|
||
userID := c.MustGet("userID").(uuid.UUID)
|
||
|
||
data, err := h.service.GetDictionaries(userID)
|
||
if err != nil {
|
||
logger.Log.Error("GetDictionaries error", zap.Error(err))
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, data)
|
||
}
|
||
|
||
func (h *DraftsHandler) GetStores(c *gin.Context) {
|
||
userID := c.MustGet("userID").(uuid.UUID)
|
||
|
||
dict, err := h.service.GetDictionaries(userID)
|
||
if err != nil {
|
||
logger.Log.Error("GetStores error", zap.Error(err))
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, dict["stores"])
|
||
}
|
||
|
||
// UpdateItemDTO обновлен: float64 -> *float64, добавлен edited_field
|
||
type UpdateItemDTO struct {
|
||
ProductID *string `json:"product_id"`
|
||
ContainerID *string `json:"container_id"`
|
||
Quantity *float64 `json:"quantity"`
|
||
Price *float64 `json:"price"`
|
||
Sum *float64 `json:"sum"`
|
||
EditedField string `json:"edited_field"` // "quantity", "price", "sum"
|
||
}
|
||
|
||
func (h *DraftsHandler) AddDraftItem(c *gin.Context) {
|
||
draftID, err := uuid.Parse(c.Param("id"))
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid draft id"})
|
||
return
|
||
}
|
||
|
||
item, err := h.service.AddItem(draftID)
|
||
if err != nil {
|
||
logger.Log.Error("Failed to add item", zap.Error(err))
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, item)
|
||
}
|
||
|
||
func (h *DraftsHandler) DeleteDraftItem(c *gin.Context) {
|
||
draftID, err := uuid.Parse(c.Param("id"))
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid draft id"})
|
||
return
|
||
}
|
||
itemID, err := uuid.Parse(c.Param("itemId"))
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid item id"})
|
||
return
|
||
}
|
||
|
||
newTotal, err := h.service.DeleteItem(draftID, itemID)
|
||
if err != nil {
|
||
logger.Log.Error("Failed to delete item", zap.Error(err))
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"status": "deleted",
|
||
"id": itemID.String(),
|
||
"total_sum": newTotal,
|
||
})
|
||
}
|
||
|
||
// UpdateItem обновлен
|
||
func (h *DraftsHandler) UpdateItem(c *gin.Context) {
|
||
draftID, _ := uuid.Parse(c.Param("id"))
|
||
itemID, _ := uuid.Parse(c.Param("itemId"))
|
||
|
||
var req UpdateItemDTO
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
var pID *uuid.UUID
|
||
if req.ProductID != nil && *req.ProductID != "" {
|
||
if uid, err := uuid.Parse(*req.ProductID); err == nil {
|
||
pID = &uid
|
||
}
|
||
}
|
||
|
||
var cID *uuid.UUID
|
||
if req.ContainerID != nil {
|
||
if *req.ContainerID == "" {
|
||
// Сброс фасовки
|
||
empty := uuid.Nil
|
||
cID = &empty
|
||
} else if uid, err := uuid.Parse(*req.ContainerID); err == nil {
|
||
cID = &uid
|
||
}
|
||
}
|
||
|
||
qty := decimal.Zero
|
||
if req.Quantity != nil {
|
||
qty = decimal.NewFromFloat(*req.Quantity)
|
||
}
|
||
|
||
price := decimal.Zero
|
||
if req.Price != nil {
|
||
price = decimal.NewFromFloat(*req.Price)
|
||
}
|
||
|
||
sum := decimal.Zero
|
||
if req.Sum != nil {
|
||
sum = decimal.NewFromFloat(*req.Sum)
|
||
}
|
||
|
||
// Дефолт, если фронт не прислал (для совместимости)
|
||
editedField := req.EditedField
|
||
if editedField == "" {
|
||
if req.Sum != nil {
|
||
editedField = "sum"
|
||
} else if req.Price != nil {
|
||
editedField = "price"
|
||
} else {
|
||
editedField = "quantity"
|
||
}
|
||
}
|
||
|
||
if err := h.service.UpdateItem(draftID, itemID, pID, cID, qty, price, sum, editedField); err != nil {
|
||
logger.Log.Error("Failed to update item", zap.Error(err))
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"status": "updated"})
|
||
}
|
||
|
||
type CommitRequestDTO struct {
|
||
DateIncoming string `json:"date_incoming"` // YYYY-MM-DD
|
||
StoreID string `json:"store_id"`
|
||
SupplierID string `json:"supplier_id"`
|
||
Comment string `json:"comment"`
|
||
IncomingDocNum string `json:"incoming_doc_num"`
|
||
}
|
||
|
||
func (h *DraftsHandler) CommitDraft(c *gin.Context) {
|
||
userID := c.MustGet("userID").(uuid.UUID)
|
||
draftID, err := uuid.Parse(c.Param("id"))
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid draft id"})
|
||
return
|
||
}
|
||
|
||
var req CommitRequestDTO
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
date, err := time.Parse("2006-01-02", req.DateIncoming)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid date format"})
|
||
return
|
||
}
|
||
storeID, err := uuid.Parse(req.StoreID)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid store id"})
|
||
return
|
||
}
|
||
supplierID, err := uuid.Parse(req.SupplierID)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid supplier id"})
|
||
return
|
||
}
|
||
|
||
if err := h.service.UpdateDraftHeader(draftID, &storeID, &supplierID, date, req.Comment, req.IncomingDocNum); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update header: " + err.Error()})
|
||
return
|
||
}
|
||
|
||
docNum, err := h.service.CommitDraft(draftID, userID)
|
||
if err != nil {
|
||
logger.Log.Error("Commit failed", zap.Error(err))
|
||
c.JSON(http.StatusBadGateway, gin.H{"error": "RMS error: " + err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"status": "completed", "document_number": docNum})
|
||
}
|
||
|
||
type AddContainerRequestDTO struct {
|
||
ProductID string `json:"product_id" binding:"required"`
|
||
Name string `json:"name" binding:"required"`
|
||
Count float64 `json:"count" binding:"required,gt=0"`
|
||
}
|
||
|
||
func (h *DraftsHandler) AddContainer(c *gin.Context) {
|
||
userID := c.MustGet("userID").(uuid.UUID)
|
||
|
||
var req AddContainerRequestDTO
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
pID, err := uuid.Parse(req.ProductID)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product_id"})
|
||
return
|
||
}
|
||
|
||
countDec := decimal.NewFromFloat(req.Count)
|
||
|
||
newID, err := h.service.CreateProductContainer(userID, pID, req.Name, countDec)
|
||
if err != nil {
|
||
logger.Log.Error("Failed to create container", zap.Error(err))
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"status": "created", "container_id": newID.String()})
|
||
}
|
||
|
||
func (h *DraftsHandler) GetDrafts(c *gin.Context) {
|
||
userID := c.MustGet("userID").(uuid.UUID)
|
||
|
||
fromStr := c.DefaultQuery("from", time.Now().AddDate(0, 0, -30).Format("2006-01-02"))
|
||
toStr := c.DefaultQuery("to", time.Now().Format("2006-01-02"))
|
||
|
||
from, _ := time.Parse("2006-01-02", fromStr)
|
||
to, _ := time.Parse("2006-01-02", toStr)
|
||
to = to.Add(23*time.Hour + 59*time.Minute + 59*time.Second)
|
||
|
||
list, err := h.service.GetUnifiedList(userID, from, to)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, list)
|
||
}
|
||
|
||
func (h *DraftsHandler) DeleteDraft(c *gin.Context) {
|
||
idStr := c.Param("id")
|
||
id, err := uuid.Parse(idStr)
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||
return
|
||
}
|
||
|
||
newStatus, err := h.service.DeleteDraft(id)
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"status": newStatus, "id": id.String()})
|
||
}
|
||
|
||
// ReorderItems изменяет порядок позиции в черновике
|
||
func (h *DraftsHandler) ReorderItems(c *gin.Context) {
|
||
type ReorderRequest struct {
|
||
ItemID uuid.UUID `json:"item_id" binding:"required"`
|
||
NewOrder int `json:"new_order" binding:"required"`
|
||
}
|
||
|
||
var req ReorderRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
// Получаем draftID из параметров пути
|
||
draftID, err := uuid.Parse(c.Param("id"))
|
||
if err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid draft id"})
|
||
return
|
||
}
|
||
|
||
if err := h.service.ReorderItem(draftID, req.ItemID, req.NewOrder); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"success": true})
|
||
}
|