product price

This commit is contained in:
2026-08-04 10:58:26 +05:30
parent 8aa4d86eb6
commit bddd8fa265
4 changed files with 176 additions and 6 deletions

View File

@@ -465,7 +465,13 @@ func (r *productRepository) GetLocationProducts(tenantID, locationID, subcategor
// into Locationproducts.Quantity, which is what made the console's stock
// column look frozen after an order despite CreateOrder recording the
// "out" ledger entry correctly.
query := `SELECT a.*, b.productlocationid, b.status, b.price,
// COALESCE so `price` means the same thing here as in GetProducts: the
// effective selling price at this outlet, falling back to the master
// retailprice when the store hasn't set its own. Returning a bare b.price
// reported 0 for any product priced only at tenant level, which the store
// catalogue then rendered as "—".
query := `SELECT a.*, b.productlocationid, b.status,
COALESCE(NULLIF(b.price, 0), a.retailprice, 0) AS price,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'IN' THEN c.quantity ELSE 0 END), 0) AS total_in,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' THEN c.quantity ELSE 0 END), 0) AS total_out,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'IN' THEN c.quantity ELSE 0 END) -
@@ -842,7 +848,7 @@ func (r *productRepository) GetProducts(params models.ProductFilter) ([]models.P
var products []models.Products
q := r.db.Table("products a").
Joins("LEFT JOIN productlocations pl ON pl.productid = a.productid").
Joins("LEFT JOIN productlocations pl ON pl.productid = a.productid AND pl.tenantid = a.tenantid").
Joins("LEFT JOIN productdiscounts pd ON pd.productid = a.productid").
Joins("LEFT JOIN productcategories c ON a.categoryid = c.categoryid").
Where("a.categoryid = ?", params.CategoryID)
@@ -875,9 +881,26 @@ func (r *productRepository) GetProducts(params models.ProductFilter) ([]models.P
// never-decremented products.quantity column — same fix as
// GetLocationProducts/GetProductByVariant, otherwise this endpoint would
// keep showing stock that never reduces after an order.
// price is the effective selling price at params.LocationID: the store's own
// productlocations.price, falling back to the master products.retailprice
// when that outlet hasn't set one. It has to be here — this endpoint feeds
// the customer app's browse-by-subcategory view, and `a.*` only carries
// retailprice, which the admin catalogue never writes. So a price the admin
// set per store could never reach the app; every product priced as 0.
//
// Deliberately a correlated subquery rather than a read off the joined `pl`:
// that join isn't outlet-scoped unless params.LocationID is set, so reading
// pl.price directly would pick an arbitrary branch's price (and multiply the
// rows) whenever the caller didn't scope to one. Same shape as the
// productstock subqueries below, for the same reason.
err := q.Select(`
a.*,
COALESCE(pd.discountvalue, 0) AS discountvalue,
COALESCE(NULLIF((
SELECT pl2.price FROM productlocations pl2
WHERE pl2.productid = a.productid AND pl2.tenantid = a.tenantid AND pl2.locationid = ?
LIMIT 1
), 0), a.retailprice, 0) AS price,
COALESCE((
SELECT SUM(CASE WHEN LOWER(ps.stocktype) = 'in' THEN ps.quantity ELSE 0 END) -
SUM(CASE WHEN LOWER(ps.stocktype) = 'out' THEN ps.quantity ELSE 0 END)
@@ -890,7 +913,7 @@ func (r *productRepository) GetProducts(params models.ProductFilter) ([]models.P
FROM productstocks ps
WHERE ps.productid = a.productid AND ps.tenantid = a.tenantid AND ps.locationid = ?
), 0) AS quantity
`, params.LocationID, params.LocationID).Find(&products).Error
`, params.LocationID, params.LocationID, params.LocationID).Find(&products).Error
return products, err
}