The offline-sales import required one workbook per outlet and a store picked in the UI. A merchant running several branches had to download, fill and upload a file per branch, and the picker defaulted to the tenant's first outlet — so an admin who never touched it silently credited the wrong store, which no validation could catch because the file and the selection agreed with each other. One workbook now covers every branch. getsaletemplate takes locationid=0 (the default) to span the tenant, stamping tenantid, locationid and the store name onto every row, and that row's locationid is what decides which branch a sale is deducted from. The INNER JOIN on tenantlocations confines it to outlets the tenant owns, so a template can never disclose another merchant's catalogue. uploadofflinesales accordingly takes locationid on each bill. The locationid on the request itself becomes a scope constraint rather than a destination: left at 0 the bills go where their rows say, and set to a branch it pins the upload there and refuses anything else. That is what holds a store user to their own store — the pin comes from their session, so editing the locationid column in the spreadsheet changes nothing. Every branch referenced is checked against the tenant regardless. Branch context and catalogue are resolved once per branch and reused; a workbook covering six outlets would otherwise re-run both queries for every bill in it. Duplicate detection is now per branch. Bill numbers only have to be unique within a store, since counter books at different outlets routinely restart numbering at 1, and treating a shared number as a repeat would have silently dropped a real sale. Verified against tenant 1087, whose two branches both stock product 6998 at 100 units: a single upload of two bills moved 1097 to 97 and 1135 to 95 independently; the same bill number at both branches imported as two separate orders; an upload pinned to 1097 imported its own bill and refused the 1135 one; a row naming another tenant's outlet was refused; and re-uploading the file deducted nothing. All five test orders were cancelled afterwards and both branches confirmed back at 100. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
694 lines
18 KiB
Go
694 lines
18 KiB
Go
package controllers
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"nearle/models"
|
|
"nearle/services"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type ProductController struct {
|
|
productService services.ProductService
|
|
}
|
|
|
|
func NewProductController(productService services.ProductService) *ProductController {
|
|
return &ProductController{productService: productService}
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductSubCategory(c *fiber.Ctx) error {
|
|
categoryID, _ := strconv.Atoi(c.Query("categoryid", "0"))
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid", "0"))
|
|
|
|
data, err := ctl.productService.GetProductSubCategory(categoryID, tenantID)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": 200,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": data,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductCount(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
categoryID, _ := strconv.Atoi(c.Query("categoryid"))
|
|
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
|
|
// locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
approve := c.Query("approve", "")
|
|
|
|
data, err := ctl.productService.GetProductCount(tenantID, categoryID, subcategoryID, approve)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusConflict,
|
|
"message": "failed",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": data,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductCategory(c *fiber.Ctx) error {
|
|
data, err := ctl.productService.GetProductCategory()
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": 500,
|
|
"message": "Failed to fetch categories",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": data,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductVariants(c *fiber.Ctx) error {
|
|
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
|
|
|
|
data, err := ctl.productService.GetProductVariants(tenantID, subcategoryID)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": 500,
|
|
"message": "Failed to fetch Product varients",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": data,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetCatalougeProducts(c *fiber.Ctx) error {
|
|
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
|
|
keyword := c.Query("keyword")
|
|
pageno, _ := strconv.Atoi(c.Query("pageno"))
|
|
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
|
|
|
|
data, err := ctl.productService.GetCatalougeProducts(tenantID, locationID, subcategoryID, pageno, pagesize, keyword)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": 500,
|
|
"message": "Failed to fetch Catalouge Product",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": data,
|
|
})
|
|
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductStocks(c *fiber.Ctx) error {
|
|
tenantID := c.Query("tenantid")
|
|
locationID := c.Query("locationid")
|
|
|
|
stocks, err := ctl.productService.GetProductStocks(tenantID, locationID)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": 500,
|
|
"message": "Failed to fetch product stocks",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": 200,
|
|
"message": "Product stocks fetched successfully",
|
|
"status": true,
|
|
"data": stocks,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) CreateProductStock(c *fiber.Ctx) error {
|
|
var stocks []models.Productstock
|
|
|
|
if err := c.BodyParser(&stocks); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"code": 400,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.CreateProductStock(stocks); err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": 500,
|
|
"message": "Failed to create product stocks",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": 201,
|
|
"message": "Product stocks created successfully",
|
|
"status": true,
|
|
"details": stocks,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) CreateProduct(c *fiber.Ctx) error {
|
|
var product models.Products
|
|
|
|
if err := c.BodyParser(&product); err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.CreateProduct(product); err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusInternalServerError,
|
|
"message": "Failed to create product",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusCreated,
|
|
"message": "Product created successfully",
|
|
"status": true,
|
|
"data": product,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) UpdateProduct(c *fiber.Ctx) error {
|
|
var product models.Products
|
|
|
|
if err := c.BodyParser(&product); err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.UpdateProduct(product); err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusAccepted,
|
|
"message": "Product updated successfully",
|
|
"status": true,
|
|
"data": product,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) DeleteProduct(c *fiber.Ctx) error {
|
|
|
|
pidStr := c.Query("productid")
|
|
pid, err := strconv.Atoi(pidStr)
|
|
if err != nil || pid <= 0 {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid product ID",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.DeleteProduct(pid); err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Product deleted successfully",
|
|
"status": true,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetStockStatement(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
|
|
pageno, _ := strconv.Atoi(c.Query("pageno"))
|
|
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
|
|
keyword := c.Query("keyword")
|
|
|
|
data, err := ctl.productService.GetStockStatement(tenantID, locationID, subcategoryID, pageno, pagesize, keyword)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": data,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetLocationProducts(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
|
|
keyword := c.Query("keyword")
|
|
pageno, _ := strconv.Atoi(c.Query("pageno"))
|
|
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
|
|
|
|
result, err := ctl.productService.GetLocationProducts(tenantID, locationID, subcategoryID, pageno, pagesize, keyword)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"details": result,
|
|
})
|
|
}
|
|
|
|
// GetSaleTemplate serves the data the web app turns into the offline-sales
|
|
// spreadsheet.
|
|
//
|
|
// locationid is optional and defaults to 0, meaning every branch the tenant
|
|
// runs — one workbook for the whole business, with each row carrying the branch
|
|
// its stock belongs to. A store user passes their own locationid to get just
|
|
// theirs. tenantid is required: without it there is no scope at all.
|
|
func (ctl *ProductController) GetSaleTemplate(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid", "0"))
|
|
|
|
if tenantID <= 0 {
|
|
return c.JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusBadRequest,
|
|
"message": "tenantid is required",
|
|
})
|
|
}
|
|
|
|
result, err := ctl.productService.GetSaleTemplate(tenantID, locationID)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"details": result,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetLocationProductSummary(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
|
|
result, err := ctl.productService.GetLocationProductSummary(tenantID, locationID)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"details": result,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetAllProducts(c *fiber.Ctx) error {
|
|
categoryID, _ := strconv.Atoi(c.Query("categoryid"))
|
|
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
|
|
productID, _ := strconv.Atoi(c.Query("productid"))
|
|
applocationID, _ := strconv.Atoi(c.Query("applocationid"))
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
keyword := c.Query("keyword", "")
|
|
productStatus := c.Query("productstatus", "")
|
|
approve := c.Query("approve", "")
|
|
pageno, _ := strconv.Atoi(c.Query("pageno"))
|
|
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
|
|
|
|
details, err := ctl.productService.FetchFilteredProducts(
|
|
categoryID, subcategoryID, productID, applocationID, tenantID,
|
|
locationID, keyword, productStatus, approve, pageno, pagesize,
|
|
)
|
|
if err != nil {
|
|
return c.JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"data": details,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductByVariant(c *fiber.Ctx) error {
|
|
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
variantid, _ := strconv.Atoi(c.Query("variantid"))
|
|
locationID, _ := strconv.Atoi(c.Query("locationid"))
|
|
|
|
result, err := ctl.productService.GetProductByVariant(tenantID, variantid, locationID)
|
|
|
|
if err != nil {
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusConflict,
|
|
"message": "failed",
|
|
"status": false,
|
|
})
|
|
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": result,
|
|
})
|
|
|
|
}
|
|
|
|
func (ctl *ProductController) GetProductsBySubcategory(c *fiber.Ctx) error {
|
|
categoryID, err := strconv.Atoi(c.Query("categoryid"))
|
|
if err != nil || categoryID == 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"code": 400,
|
|
"status": false,
|
|
"message": "Valid categoryid is required",
|
|
"data": fiber.Map{},
|
|
})
|
|
}
|
|
|
|
params := models.ProductFilter{
|
|
CategoryID: categoryID,
|
|
TenantID: parseInt(c.Query("tenantid")),
|
|
AppLocationID: parseInt(c.Query("applocationid")),
|
|
ProductID: parseInt(c.Query("productid")),
|
|
Keyword: c.Query("keyword"),
|
|
LocationID: parseInt(c.Query("locationid")),
|
|
}
|
|
|
|
result, err := ctl.productService.GetProductsBySubcategory(params)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
|
|
"code": 500,
|
|
"status": false,
|
|
"message": err.Error(),
|
|
"data": fiber.Map{},
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": 200,
|
|
"status": true,
|
|
"message": "Success",
|
|
"data": result,
|
|
})
|
|
}
|
|
|
|
func parseInt(s string) int {
|
|
if s == "" {
|
|
return 0
|
|
}
|
|
val, _ := strconv.Atoi(s)
|
|
return val
|
|
}
|
|
|
|
func (ctl *ProductController) UpdateProductLocation(c *fiber.Ctx) error {
|
|
var data models.Productlocations
|
|
|
|
if err := c.BodyParser(&data); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.UpdateProductLocation(data); err != nil {
|
|
return c.Status(http.StatusConflict).JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(http.StatusAccepted).JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusAccepted,
|
|
"message": "Product update successful",
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) CreateProductLocation(c *fiber.Ctx) error {
|
|
var data []models.Productlocations
|
|
|
|
if err := c.BodyParser(&data); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.CreateProductLocation(data); err != nil {
|
|
return c.Status(http.StatusConflict).JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(http.StatusCreated).JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusCreated,
|
|
"message": "Success",
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) CreateProductVariant(c *fiber.Ctx) error {
|
|
var input models.Productvariant
|
|
|
|
// Parse request body
|
|
if err := c.BodyParser(&input); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
// Call service layer
|
|
if err := ctl.productService.CreateProductVariant(input); err != nil {
|
|
return c.Status(http.StatusConflict).JSON(fiber.Map{
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.Status(http.StatusOK).JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) ImportCatalogueProduct(c *fiber.Ctx) error {
|
|
var data []models.ImportCatalogueProductRequest
|
|
|
|
if err := c.BodyParser(&data); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if len(data) == 0 {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Request body must contain at least one product",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
for _, req := range data {
|
|
if req.Tenantid == 0 || req.Locationid == 0 || req.Brand == "" || req.Catalogueid == 0 || req.Categoryid == 0 {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "tenantid, locationid, brand, catalogueid, and categoryid are required",
|
|
"status": false,
|
|
})
|
|
}
|
|
}
|
|
|
|
if err := ctl.productService.ImportCatalogueProduct(data); err != nil {
|
|
return c.Status(http.StatusConflict).JSON(fiber.Map{
|
|
"status": false,
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(http.StatusCreated).JSON(fiber.Map{
|
|
"status": true,
|
|
"code": http.StatusCreated,
|
|
"message": "Success",
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetImportedCatalogueProducts(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
// brand is optional: omit it to check imported status across every
|
|
// brand at once, matching the all-brands catalogue browse view.
|
|
brand := c.Query("brand")
|
|
|
|
if tenantID == 0 {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "tenantid is required",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
refs, err := ctl.productService.GetImportedCatalogueRefs(tenantID, brand)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": refs,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) GetTenantCategories(c *fiber.Ctx) error {
|
|
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
|
|
if tenantID == 0 {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "tenantid is required",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
categories, err := ctl.productService.GetTenantCategories(tenantID)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
|
|
"code": http.StatusInternalServerError,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Success",
|
|
"status": true,
|
|
"details": categories,
|
|
})
|
|
}
|
|
|
|
func (ctl *ProductController) DeleteProductLocation(c *fiber.Ctx) error {
|
|
var input struct {
|
|
Tenantid int `json:"tenantid"`
|
|
Locationid int `json:"locationid"`
|
|
Productid int `json:"productid"`
|
|
}
|
|
|
|
if err := c.BodyParser(&input); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "Invalid request body",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if input.Tenantid == 0 || input.Locationid == 0 || input.Productid == 0 {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
|
"code": http.StatusBadRequest,
|
|
"message": "tenantid, locationid, and productid are required",
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
if err := ctl.productService.DeleteProductLocation(input.Tenantid, input.Locationid, input.Productid); err != nil {
|
|
return c.Status(http.StatusConflict).JSON(fiber.Map{
|
|
"code": http.StatusConflict,
|
|
"message": err.Error(),
|
|
"status": false,
|
|
})
|
|
}
|
|
|
|
return c.Status(http.StatusOK).JSON(fiber.Map{
|
|
"code": http.StatusOK,
|
|
"message": "Product location deleted successfully",
|
|
"status": true,
|
|
})
|
|
}
|