orders
This commit is contained in:
26
controllers/appRequest.go
Normal file
26
controllers/appRequest.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// isAppRequest reports whether a request arrived on the customer app's base.
|
||||
//
|
||||
// Several handlers are registered on both `/v1/web/...` and `/v1/mob/...`, and
|
||||
// a few of them owe the two callers different answers. The clearest case is
|
||||
// stock: the console lists a product with an empty shelf so a merchant can
|
||||
// refill it, and the app must not list the same product at all, because a
|
||||
// shopper can only choose it and be refused at checkout.
|
||||
//
|
||||
// The base is read from the path rather than passed down through the service,
|
||||
// so the difference stays where it belongs — at the edge, in the one place that
|
||||
// knows which audience asked. Services keep answering the same question the
|
||||
// same way for everyone.
|
||||
//
|
||||
// Matched with the surrounding slashes so a tenant, product or keyword
|
||||
// containing "mob" cannot make a console request look like an app one.
|
||||
func isAppRequest(c *fiber.Ctx) bool {
|
||||
return strings.Contains(c.Path(), "/v1/mob/")
|
||||
}
|
||||
50
controllers/appRequest_test.go
Normal file
50
controllers/appRequest_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
/*
|
||||
The console and the customer app share handlers, and a few of those handlers owe
|
||||
the two callers different answers. This is the switch that tells them apart, so
|
||||
it is worth a test of its own: get it wrong in the permissive direction and
|
||||
shoppers are offered empty shelves again; get it wrong in the strict direction
|
||||
and a merchant's restocking screen goes blank, hiding the work they came to do.
|
||||
*/
|
||||
|
||||
func pathSays(t *testing.T, path string, want bool) {
|
||||
t.Helper()
|
||||
app := fiber.New()
|
||||
got := false
|
||||
app.Get("/*", func(c *fiber.Ctx) error {
|
||||
got = isAppRequest(c)
|
||||
return nil
|
||||
})
|
||||
if _, err := app.Test(httptest.NewRequest("GET", path, nil)); err != nil {
|
||||
t.Fatalf("Test(%q): %v", path, err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("isAppRequest(%q) = %v, want %v", path, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTheAppBaseIsRecognised(t *testing.T) {
|
||||
pathSays(t, "/live/api/v1/mob/products/getallproducts", true)
|
||||
}
|
||||
|
||||
func TestTheConsoleBaseIsNotTreatedAsTheApp(t *testing.T) {
|
||||
// The console must keep seeing empty shelves — restocking them is the whole
|
||||
// point of that screen.
|
||||
pathSays(t, "/live/api/v1/web/products/getallproducts", false)
|
||||
}
|
||||
|
||||
func TestAKeywordContainingMobDoesNotImpersonateTheApp(t *testing.T) {
|
||||
// Matched with its slashes, so a search for "mobil" or a shop called
|
||||
// "Mobius" cannot flip a console request into an app one and empty the
|
||||
// merchant's screen.
|
||||
pathSays(t, "/live/api/v1/web/products/getallproducts?keyword=mobile", false)
|
||||
pathSays(t, "/live/api/v1/web/tenants/search?keyword=mob", false)
|
||||
}
|
||||
@@ -385,6 +385,23 @@ func (ctl *ProductController) GetAllProducts(c *fiber.Ctx) error {
|
||||
categoryID, subcategoryID, productID, applocationID, tenantID,
|
||||
locationID, keyword, productStatus, approve, pageno, pagesize,
|
||||
)
|
||||
|
||||
// The customer app is not shown what the shop cannot sell.
|
||||
//
|
||||
// Scoped to the /v1/mob base rather than applied in the service, because
|
||||
// this one handler answers on BOTH bases and the two callers want opposite
|
||||
// things. The console reads it to restock — an empty line is exactly what a
|
||||
// merchant needs to see and act on, so filtering there would hide the work.
|
||||
// A shopper reading the same list can only be misled by it: measured
|
||||
// 2026-09-02 on R mart, four products were on offer in the app with a zero
|
||||
// balance, including Cadbury Bournvita 500g and two Amul packs. Ordering one
|
||||
// gets a 409 at checkout, after the shopper has chosen it.
|
||||
//
|
||||
// It filters on Productstock, the same number the response carries, so the
|
||||
// list and the figure beside it cannot disagree.
|
||||
if err == nil && isAppRequest(c) {
|
||||
details = services.InStockOnlyGrouped(details)
|
||||
}
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"status": false,
|
||||
|
||||
Reference in New Issue
Block a user