Files
backend_fiesta/controllers/stockrequestController.go
2026-09-02 16:50:37 +05:30

159 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package controllers
import (
"net/http"
"strconv"
"nearle/models"
"nearle/services"
"github.com/gofiber/fiber/v2"
)
type StockRequestController struct {
stockRequestService services.StockRequestService
}
func NewStockRequestController(stockRequestService services.StockRequestService) *StockRequestController {
return &StockRequestController{stockRequestService: stockRequestService}
}
// CreateStockRequest accepts one request or a list of them.
//
// A shop restocking after a delivery is asking for twenty things at once, and
// sending twenty HTTP requests to say so is slow, gives no single answer, and
// leaves a half-sent batch behind when the connection drops. The single-object
// form is unchanged, so every existing caller keeps working.
//
// Each row is reported individually rather than the batch failing whole: a
// request for a product that no longer exists should not discard the other
// nineteen, and the requester needs to know WHICH one it was.
func (ctl *StockRequestController) CreateStockRequest(c *fiber.Ctx) error {
inputs, err := parseStockRequests(c)
if err != nil {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "message": "Invalid input", "status": false})
}
if len(inputs) == 0 {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "message": "send at least one request", "status": false})
}
created := make([]models.StockRequest, 0, len(inputs))
failed := make([]fiber.Map, 0)
for i := range inputs {
if inputs[i].Status == "" {
inputs[i].Status = "Pending"
}
if err := ctl.stockRequestService.CreateStockRequest(&inputs[i]); err != nil {
failed = append(failed, fiber.Map{
"productid": inputs[i].Productid,
"reason": err.Error(),
})
continue
}
created = append(created, inputs[i])
}
// A single-object caller gets the object back, exactly as before.
if len(inputs) == 1 && len(failed) == 0 {
return c.JSON(fiber.Map{"code": 200, "message": "Stock request created", "status": true, "details": created[0]})
}
if len(created) == 0 {
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError, "status": false,
"message": "no requests could be created", "details": fiber.Map{"failed": failed},
})
}
return c.JSON(fiber.Map{
"code": 200, "status": true,
"message": stockBatchMessage(len(created), len(failed), "created"),
"details": fiber.Map{"created": created, "failed": failed},
})
}
func (ctl *StockRequestController) GetStockRequests(c *fiber.Ctx) error {
tenantID, _ := strconv.Atoi(c.Query("tenantid", "0"))
locationID, _ := strconv.Atoi(c.Query("locationid", "0"))
status := c.Query("status", "")
date := c.Query("date", "")
pageNo, _ := strconv.Atoi(c.Query("pageno", "1"))
pageSize, _ := strconv.Atoi(c.Query("pagesize", "50"))
data, err := ctl.stockRequestService.GetStockRequests(tenantID, locationID, status, date, pageNo, pageSize)
if err != nil {
return c.JSON(fiber.Map{"code": http.StatusInternalServerError, "message": err.Error(), "status": false})
}
return c.JSON(fiber.Map{"code": 200, "message": "Success", "status": true, "details": data})
}
// UpdateStockRequest decides one request or a batch of them.
//
// `requestid` for one, `requestids` for many, one status for the batch. That
// shape rather than a list of {id,status} pairs because the action a merchant
// takes is "approve these" or "reject these" — a mixed batch is two actions,
// and letting one call do both makes an accidental mass-approve possible.
//
// Approving is not a status write: the service adds the requested quantity to
// the branch’s stock. So each id is applied on its own and reported on its own.
// If the fourth of ten fails, the first three have really been received and the
// merchant has to know that, rather than being told the batch failed and
// approving it a second time.
func (ctl *StockRequestController) UpdateStockRequest(c *fiber.Ctx) error {
var input struct {
RequestID int `json:"requestid"`
RequestIDs []int `json:"requestids"`
Status string `json:"status"`
}
if err := c.BodyParser(&input); err != nil {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "message": "Invalid input", "status": false})
}
if input.Status == "" {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "status": false,
"message": "status is required"})
}
ids := input.RequestIDs
if input.RequestID != 0 {
ids = append([]int{input.RequestID}, ids...)
}
ids = dedupeIDs(ids)
if len(ids) == 0 {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "status": false,
"message": "send requestid, or requestids for several"})
}
updated := make([]int, 0, len(ids))
failed := make([]fiber.Map, 0)
for _, id := range ids {
if err := ctl.stockRequestService.UpdateStockRequest(id, input.Status); err != nil {
failed = append(failed, fiber.Map{"requestid": id, "reason": err.Error()})
continue
}
updated = append(updated, id)
}
// The single-id caller keeps the answer it has always had.
if len(ids) == 1 {
if len(failed) > 0 {
return c.JSON(fiber.Map{"code": http.StatusInternalServerError, "status": false,
"message": failed[0]["reason"]})
}
return c.JSON(fiber.Map{"code": 200, "message": "Stock request updated", "status": true})
}
if len(updated) == 0 {
return c.JSON(fiber.Map{"code": http.StatusInternalServerError, "status": false,
"message": "no requests could be updated", "details": fiber.Map{"failed": failed}})
}
return c.JSON(fiber.Map{
"code": 200, "status": true,
"message": stockBatchMessage(len(updated), len(failed), "updated"),
"details": fiber.Map{"updated": updated, "failed": failed},
})
}