console categories
This commit is contained in:
@@ -18,6 +18,7 @@ type ProductRepository interface {
|
||||
GetProductCount(tenantID, categoryID, subcategoryID int, approve string) ([]models.Productcount, error)
|
||||
GetProductCategory() ([]models.ProductCategory, error)
|
||||
EnsureTenantCategories(tenantID int, names []string) (map[string]int, error)
|
||||
RecategoriseProducts(tenantID int, updates []models.ProductCategoryUpdate) (int64, error)
|
||||
GetProductVariants(tenantID, subcategoryID int) ([]models.Productvariant, error)
|
||||
GetCatalougeProducts(tenantID, locationID, subcategoryID, pageno, pagesize int, keyword string) ([]models.Products, error)
|
||||
GetProductStocks(tenantID, locationID string) ([]models.Productstocks, error)
|
||||
@@ -1404,6 +1405,56 @@ func (r *productRepository) GetImportedCatalogueRefs(tenantid int, brand string)
|
||||
// row despite being in real use). This is deliberately not the global
|
||||
// productcategories list: that list can omit categoryids tenants actually
|
||||
// have products in, which would make the import category picker unusable.
|
||||
// RecategoriseProducts moves products into different categories, in bulk.
|
||||
//
|
||||
// Written for the backfill that re-files everything imported before categories
|
||||
// existed: those rows all carry whichever single category the tenant had, while
|
||||
// the catalogue has known all along what each product actually is.
|
||||
//
|
||||
// ── Two things this deliberately does not do ────────────────────────────────
|
||||
//
|
||||
// It does not touch any column but categoryid. UpdateProduct next door runs
|
||||
// GORM's Updates over a whole struct, which is why it can only be trusted with
|
||||
// a hand-built partial — a bulk caller sending full rows would write back every
|
||||
// field it happened to have read, including a price it never meant to change.
|
||||
// One column, named explicitly, cannot do that.
|
||||
//
|
||||
// It is scoped by tenantid in the WHERE clause, not just trusted from the
|
||||
// caller. A productid is global, so a mistyped id in a list would otherwise
|
||||
// re-file another merchant's product into a category that does not exist for
|
||||
// them — invisible to both shops and to the app.
|
||||
func (r *productRepository) RecategoriseProducts(tenantID int, updates []models.ProductCategoryUpdate) (int64, error) {
|
||||
if tenantID == 0 || len(updates) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
placeholders := make([]string, 0, len(updates))
|
||||
args := make([]any, 0, len(updates)*2)
|
||||
for _, u := range updates {
|
||||
if u.Productid == 0 || u.Categoryid == 0 {
|
||||
// categoryid 0 is the value the customer app rejects outright.
|
||||
// Refusing it here means a bad row is skipped rather than hiding a
|
||||
// product from every shopper.
|
||||
continue
|
||||
}
|
||||
placeholders = append(placeholders, "(?::bigint, ?::bigint)")
|
||||
args = append(args, u.Productid, u.Categoryid)
|
||||
}
|
||||
if len(placeholders) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
args = append(args, tenantID)
|
||||
tx := r.db.Exec(`
|
||||
UPDATE products p
|
||||
SET categoryid = v.categoryid
|
||||
FROM (VALUES `+strings.Join(placeholders, ",")+`) AS v(productid, categoryid)
|
||||
WHERE p.productid = v.productid
|
||||
AND p.tenantid = ?
|
||||
`, args...)
|
||||
return tx.RowsAffected, tx.Error
|
||||
}
|
||||
|
||||
// EnsureTenantCategories maps category NAMES to this tenant's category ids,
|
||||
// creating any that do not exist yet, and is safe to call repeatedly.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user