159 lines
5.5 KiB
Go
159 lines
5.5 KiB
Go
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},
|
||
})
|
||
}
|