Полноценно редактируются черновики

Добавляются фасовки как в черновике, так и в обучении
Исправил внешний вид
This commit is contained in:
2025-12-17 22:00:21 +03:00
parent e2df2350f7
commit c8aab42e8e
24 changed files with 1313 additions and 433 deletions

View File

@@ -149,3 +149,129 @@ func (h *DraftsHandler) CommitDraft(c *gin.Context) {
"document_number": docNum,
})
}
// AddContainerRequestDTO - запрос на создание фасовки
type AddContainerRequestDTO struct {
ProductID string `json:"product_id" binding:"required"`
Name string `json:"name" binding:"required"`
Count float64 `json:"count" binding:"required,gt=0"`
}
// AddContainer создает новую фасовку для товара
func (h *DraftsHandler) AddContainer(c *gin.Context) {
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
}
// Конвертация float64 -> decimal
countDec := decimal.NewFromFloat(req.Count)
// Вызов сервиса
newID, err := h.service.CreateProductContainer(pID, req.Name, countDec)
if err != nil {
logger.Log.Error("Failed to create container", zap.Error(err))
// Можно возвращать 502, если ошибка от RMS
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "created",
"container_id": newID.String(),
})
}
// DraftListItemDTO - структура элемента списка
type DraftListItemDTO struct {
ID string `json:"id"`
DocumentNumber string `json:"document_number"`
DateIncoming string `json:"date_incoming"` // YYYY-MM-DD
Status string `json:"status"`
ItemsCount int `json:"items_count"`
TotalSum float64 `json:"total_sum"`
StoreName string `json:"store_name"`
CreatedAt string `json:"created_at"`
}
// GetDrafts возвращает список активных черновиков
func (h *DraftsHandler) GetDrafts(c *gin.Context) {
list, err := h.service.GetActiveDrafts()
if err != nil {
logger.Log.Error("Failed to fetch drafts", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
response := make([]DraftListItemDTO, 0, len(list))
for _, d := range list {
// Расчет суммы
var totalSum decimal.Decimal
for _, item := range d.Items {
// Если item.Sum посчитана - берем её, иначе (qty * price)
if !item.Sum.IsZero() {
totalSum = totalSum.Add(item.Sum)
} else {
totalSum = totalSum.Add(item.Quantity.Mul(item.Price))
}
}
sumFloat, _ := totalSum.Float64()
// Форматирование даты
dateStr := ""
if d.DateIncoming != nil {
dateStr = d.DateIncoming.Format("2006-01-02")
}
// Имя склада
storeName := ""
if d.Store != nil {
storeName = d.Store.Name
}
response = append(response, DraftListItemDTO{
ID: d.ID.String(),
DocumentNumber: d.DocumentNumber,
DateIncoming: dateStr,
Status: d.Status,
ItemsCount: len(d.Items),
TotalSum: sumFloat,
StoreName: storeName,
CreatedAt: d.CreatedAt.Format(time.RFC3339),
})
}
c.JSON(http.StatusOK, response)
}
// DeleteDraft обрабатывает запрос на удаление/отмену
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 {
logger.Log.Error("Failed to delete draft", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Возвращаем новый статус, чтобы фронтенд знал, удалился он совсем или стал CANCELED
c.JSON(http.StatusOK, gin.H{
"status": newStatus,
"id": id.String(),
})
}