new api for offline sales
This commit is contained in:
@@ -29,6 +29,7 @@ type ProductRepository interface {
|
||||
GetStockStatement(tenantID, locationID, subcategoryID, pageno, pagesize int, keyword string) ([]models.Productstockstatement, error)
|
||||
GetLocationProducts(tenantID, locationID, subcategoryID, pageno, pagesize int, keyword string) ([]models.Locationproducts, error)
|
||||
GetLocationProductSummary(tenantID, locationID int) ([]models.ProductSummary, error)
|
||||
GetSaleTemplate(tenantID, locationID int) (*models.SaleTemplate, error)
|
||||
FetchFilteredProducts(categoryID, subcategoryID, productID, applocationID, tenantID, locationID int, keyword, productStatus, approve string, pageno, pagesize int) ([]models.Tenantproducts, error)
|
||||
GetProductByVariant(tenantid, variantid, locationid int) ([]models.Products, error)
|
||||
GetSubcategories(categoryID int) ([]models.Subcategory, error)
|
||||
@@ -502,6 +503,71 @@ func (r *productRepository) GetLocationProducts(tenantID, locationID, subcategor
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// GetSaleTemplate lists every product stocked at one outlet, with its live
|
||||
// ledger balance, so the web app can generate a pre-filled offline-sales
|
||||
// spreadsheet. It deliberately returns the whole catalogue for the outlet
|
||||
// unpaged — a spreadsheet the user is meant to fill in and hand back is only
|
||||
// useful if it contains every product they could have sold.
|
||||
//
|
||||
// The balance is the same SUM(in) - SUM(out) expression CreateOrder validates
|
||||
// against, so the "currentstock" the user reads in the sheet is exactly the
|
||||
// number the import will later check their quantity against. LOWER() covers
|
||||
// the mixed-case stocktype values in production ('out', 'IN', 'in').
|
||||
//
|
||||
// A location that does not belong to the tenant yields no template rather than
|
||||
// another tenant's catalogue: the caller treats that as "not your outlet".
|
||||
func (r *productRepository) GetSaleTemplate(tenantID, locationID int) (*models.SaleTemplate, error) {
|
||||
if tenantID <= 0 || locationID <= 0 {
|
||||
return nil, errors.New("tenantid and locationid are required")
|
||||
}
|
||||
|
||||
var loc struct {
|
||||
Locationname string
|
||||
}
|
||||
err := r.db.Raw(
|
||||
`SELECT locationname FROM tenantlocations WHERE tenantid = ? AND locationid = ?`,
|
||||
tenantID, locationID,
|
||||
).Scan(&loc).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if strings.TrimSpace(loc.Locationname) == "" {
|
||||
return nil, fmt.Errorf("location %d does not belong to tenant %d", locationID, tenantID)
|
||||
}
|
||||
|
||||
rows := make([]models.SaleTemplateRow, 0)
|
||||
query := `
|
||||
SELECT a.productid,
|
||||
a.productname,
|
||||
COALESCE(a.productunit, '') AS productunit,
|
||||
COALESCE(a.unitvalue, '') AS unitvalue,
|
||||
COALESCE(d.categoryname, '') AS categoryname,
|
||||
COALESCE(SUM(CASE WHEN LOWER(c.stocktype) = 'in' THEN c.quantity ELSE 0 END) -
|
||||
SUM(CASE WHEN LOWER(c.stocktype) = 'out' THEN c.quantity ELSE 0 END), 0) AS currentstock,
|
||||
CASE WHEN COALESCE(b.price, 0) > 0 THEN b.price ELSE COALESCE(a.retailprice, 0) END AS price,
|
||||
COALESCE(a.taxpercent, 0) AS taxpercent
|
||||
FROM products a
|
||||
INNER JOIN productlocations b ON a.productid = b.productid AND a.tenantid = b.tenantid
|
||||
LEFT JOIN productstocks c
|
||||
ON a.productid = c.productid AND b.locationid = c.locationid AND a.tenantid = c.tenantid
|
||||
LEFT JOIN productcategories d ON a.categoryid = d.categoryid
|
||||
WHERE a.approve = 1 AND a.tenantid = ? AND b.locationid = ?
|
||||
GROUP BY a.productid, a.productname, a.productunit, a.unitvalue, d.categoryname,
|
||||
b.price, a.retailprice, a.taxpercent
|
||||
ORDER BY a.productname ASC`
|
||||
|
||||
if err := r.db.Raw(query, tenantID, locationID).Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.SaleTemplate{
|
||||
Tenantid: tenantID,
|
||||
Locationid: locationID,
|
||||
Locationname: strings.TrimSpace(loc.Locationname),
|
||||
Products: rows,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *productRepository) GetLocationProductSummary(tenantID, locationID int) ([]models.ProductSummary, error) {
|
||||
data := make([]models.ProductSummary, 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user