fix on stocks on store catalogue

This commit is contained in:
2026-08-31 16:26:06 +05:30
parent d55f101834
commit bc10b589cd
4 changed files with 172 additions and 11 deletions

View File

@@ -42,9 +42,11 @@ type fakeProductRepo struct {
existingByImage *models.Products
linked [][2]any
ensuredRefs []models.ProductLocationRef
syncedRefs []models.ProductLocationRef
categorySet map[int][2]int // productid -> {categoryid, subcategoryid}
ensuredRefs []models.ProductLocationRef
syncedRefs []models.ProductLocationRef
publishedRefs []models.ProductLocationRef
created []models.Products
categorySet map[int][2]int // productid -> {categoryid, subcategoryid}
}
func newFakeRepo() *fakeProductRepo {
@@ -107,6 +109,26 @@ func (f *fakeProductRepo) UpdateProductCategory(productid, categoryid, subcatego
return nil
}
// Publishing what an import brought in priced.
//
// The gate exists to stop an UNPRICED product reaching a till; a spreadsheet
// import carries the price, so demanding a second manual release protected
// nothing — and cost the merchant sight of their own stock, because nothing in
// the backend filters on `publishedat` but the store catalogue screen does.
// A fresh import creates the snapshot; the existing cases all take the
// re-import branch, so this only became reachable when publishing did.
func (f *fakeProductRepo) CreateProductReturningID(product models.Products) (int, error) {
f.calls = append(f.calls, "CreateProductReturningID")
f.created = append(f.created, product)
return 9001, nil
}
func (f *fakeProductRepo) PublishPricedLocations(refs []models.ProductLocationRef) error {
f.calls = append(f.calls, "PublishPricedLocations")
f.publishedRefs = append(f.publishedRefs, refs...)
return nil
}
func (f *fakeProductRepo) CreateProductLocation(input []models.Productlocations) error {
f.calls = append(f.calls, "CreateProductLocation")
return nil
@@ -513,3 +535,74 @@ func TestBrowseStillHidesWhatTheShopDoesNotHave(t *testing.T) {
t.Fatalf("browse should still offer only the stocked product, got %v", names(offered))
}
}
/*
A priced import releases itself.
The publish gate is there to stop an unpriced product reaching a till that would
ring it up at zero. A spreadsheet import carries the price on every row, so the
condition is already met at import time and a second manual release could only
ever answer "yes".
It was not a harmless extra click. Nothing in the backend filters on
`publishedat` — only the merchant's own store-catalogue screen does — so on
2026-08-31 seventeen products at R mart were on sale in the customer app, priced
and stocked, while the shopkeeper's store catalogue showed none of them. The one
person who could not see the stock was the one selling it.
*/
func TestImportPublishesWhatItPriced(t *testing.T) {
repo := newFakeRepo()
service := NewProductService(repo, &fakeCatalogueService{
product: &models.CatalogueProduct{
ID: 1, Brand: "kohinoor", ProductName: "Kohinoor Charminar Rice 5kg",
ImageID: "kohinoor_kohinoor_charminar_rice_5kg",
},
})
if err := service.ImportCatalogueProduct([]models.ImportCatalogueProductRequest{{
Tenantid: 1147, Locationid: 1185, Brand: "kohinoor", Catalogueid: 1,
Categoryid: 2, Retailprice: 395, Quantity: 22, Stocktype: "in",
}}); err != nil {
t.Fatalf("ImportCatalogueProduct: %v", err)
}
if len(repo.publishedRefs) != 1 {
t.Fatalf("want the imported row released, got %d refs (calls: %v)",
len(repo.publishedRefs), repo.calls)
}
got := repo.publishedRefs[0]
// The branch that was imported into, and only that one. Publishing
// tenant-wide would put products in outlets nobody chose.
if got.Tenantid != 1147 || got.Locationid != 1185 {
t.Errorf("released the wrong row: %+v", got)
}
}
// Order matters: publishing addresses (tenantid, locationid, productid), and a
// brand-new snapshot has no productid until its rows are written.
func TestImportPublishesAfterTheRowsExist(t *testing.T) {
repo := newFakeRepo()
service := NewProductService(repo, &fakeCatalogueService{
product: &models.CatalogueProduct{ID: 1, Brand: "colin", ProductName: "Colin Glass Cleaner 500ml"},
})
if err := service.ImportCatalogueProduct([]models.ImportCatalogueProductRequest{{
Tenantid: 1147, Locationid: 1185, Brand: "colin", Catalogueid: 1,
Categoryid: 2, Retailprice: 105, Quantity: 42,
}}); err != nil {
t.Fatalf("ImportCatalogueProduct: %v", err)
}
create, publish := -1, -1
for i, call := range repo.calls {
if call == "CreateProductLocation" {
create = i
}
if call == "PublishPricedLocations" {
publish = i
}
}
if create < 0 || publish < 0 || publish < create {
t.Fatalf("want CreateProductLocation before PublishPricedLocations, got %v", repo.calls)
}
}