package controllers import ( "errors" "nearle/models" "nearle/services" "net/http" "github.com/gofiber/fiber/v2" ) // ScanController is the scan-to-order surface for the customer app: // // POST /v1/mob/scan/lookup a label → the product, and which of my stores has it // POST /v1/mob/scan/confirm I picked a store and a size → still there? else where? // GET /v1/mob/scan/stores my stores, nearest first // // Business outcomes ("out of stock", "not registered with that store") are // 200s with a reason in the body: the app renders them, it does not retry // them. HTTP errors are reserved for a request that cannot be served at all. type ScanController struct { scanService services.ScanService } func NewScanController(scanService services.ScanService) *ScanController { return &ScanController{scanService: scanService} } func (ctl *ScanController) Lookup(c *fiber.Ctx) error { var req models.ScanLookupRequest if err := c.BodyParser(&req); err != nil { return scanBadRequest(c, "Invalid request body") } resp, err := ctl.scanService.Lookup(c.Context(), req) if err != nil { return scanError(c, err, "Could not look up that product") } return c.Status(http.StatusOK).JSON(fiber.Map{ "code": http.StatusOK, "status": true, "message": resp.Message, "details": resp, }) } func (ctl *ScanController) Confirm(c *fiber.Ctx) error { var req models.ScanConfirmRequest if err := c.BodyParser(&req); err != nil { return scanBadRequest(c, "Invalid request body") } resp, err := ctl.scanService.Confirm(c.Context(), req) if err != nil { return scanError(c, err, "Could not check that store") } return c.Status(http.StatusOK).JSON(fiber.Map{ "code": http.StatusOK, "status": true, "message": resp.Message, "details": resp, }) } func (ctl *ScanController) Stores(c *fiber.Ctx) error { customerid, _ := c.QueryInt("customerid"), 0 stores, err := ctl.scanService.Stores(c.Context(), customerid, models.FlexibleString(c.Query("latitude")), models.FlexibleString(c.Query("longitude"))) if err != nil { return scanError(c, err, "Could not list your stores") } return c.Status(http.StatusOK).JSON(fiber.Map{ "code": http.StatusOK, "status": true, "message": "Success", "details": stores, }) } func scanBadRequest(c *fiber.Ctx, msg string) error { return c.Status(http.StatusBadRequest).JSON(fiber.Map{ "code": http.StatusBadRequest, "status": false, "message": msg, }) } func scanError(c *fiber.Ctx, err error, fallback string) error { code, msg := http.StatusInternalServerError, fallback switch { case errors.Is(err, services.ErrScanBadRequest): code, msg = http.StatusBadRequest, err.Error() case errors.Is(err, services.ErrScanCustomerNotFound): code, msg = http.StatusNotFound, "Customer not found" case errors.Is(err, services.ErrScanCatalogueDown): code, msg = http.StatusServiceUnavailable, "Product search is temporarily unavailable" } return c.Status(code).JSON(fiber.Map{ "code": code, "status": false, "message": msg, }) }