changes with app product stock
This commit is contained in:
53
services/productVisibility.go
Normal file
53
services/productVisibility.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package services
|
||||
|
||||
import "nearle/models"
|
||||
|
||||
// InStockOnly drops the products an outlet cannot actually sell.
|
||||
//
|
||||
// Being on a shelf is not the same as being in stock. Suriya Store's Peelamedu
|
||||
// branch listed three products in the customer app of which exactly one had any
|
||||
// stock, so a shopper could add a chocolate bar to their basket and order
|
||||
// something the shop did not have. The rule the business wants is the simple
|
||||
// one: if we have the stock, it can be ordered — otherwise it is not on offer.
|
||||
//
|
||||
// ── Why here and not in the SQL ──────────────────────────────────────────────
|
||||
//
|
||||
// The obvious implementation is another correlated subquery in GetProducts'
|
||||
// WHERE clause. This is better for a reason that outlives the convenience:
|
||||
// `Productstock` is the number the app DISPLAYS, computed by that query as the
|
||||
// live SUM(in)-SUM(out) balance. Filtering on the same value that is shown makes
|
||||
// it impossible for the two to disagree. A second copy of the balance
|
||||
// expression in a WHERE clause is a copy that can drift from the one in the
|
||||
// SELECT, and the failure it produces — a product listed as "3 in stock" that
|
||||
// the filter considers empty, or worse the reverse — is very hard to see.
|
||||
//
|
||||
// It also filters on the ledger rather than productlocations.status. That flag
|
||||
// is derived and admits drift: SyncProductLocationStatus repairs it on the next
|
||||
// ledger entry, so between an order and that entry it can still read
|
||||
// "available" for an empty shelf. The ledger cannot drift from itself.
|
||||
//
|
||||
// ── The locationID guard ─────────────────────────────────────────────────────
|
||||
//
|
||||
// Not defensive padding. GetProducts computes the stock balance scoped to
|
||||
// params.LocationID, and with no outlet the subquery matches nothing, so EVERY
|
||||
// product comes back with Productstock 0. Filtering that would turn an unscoped
|
||||
// browse into an empty catalogue rather than an unfiltered one.
|
||||
//
|
||||
// The console is deliberately unaffected: its inventory screens read
|
||||
// GetLocationProducts, a different query, and they must keep showing the empty
|
||||
// lines — restocking them is the entire point of that screen.
|
||||
func InStockOnly(products []models.Products, locationID int) []models.Products {
|
||||
if locationID <= 0 {
|
||||
return products
|
||||
}
|
||||
|
||||
// Rebuilt rather than filtered in place: the caller's slice is the
|
||||
// repository's own result and nothing here should be writing through it.
|
||||
inStock := make([]models.Products, 0, len(products))
|
||||
for _, p := range products {
|
||||
if p.Productstock > 0 {
|
||||
inStock = append(inStock, p)
|
||||
}
|
||||
}
|
||||
return inStock
|
||||
}
|
||||
Reference in New Issue
Block a user