Compare commits
No commits in common. "54dc8662d68544e2f6b8f05338e335f9d9f881de" and "670a283c7b69a481e936695385bff47c09df3dc6" have entirely different histories.
54dc8662d6
...
670a283c7b
@ -107,7 +107,6 @@ type ProductAnalyticsData struct {
|
|||||||
ProductName string `json:"product_name"`
|
ProductName string `json:"product_name"`
|
||||||
CategoryID uuid.UUID `json:"category_id"`
|
CategoryID uuid.UUID `json:"category_id"`
|
||||||
CategoryName string `json:"category_name"`
|
CategoryName string `json:"category_name"`
|
||||||
CategoryOrder int `json:"category_order"`
|
|
||||||
QuantitySold int64 `json:"quantity_sold"`
|
QuantitySold int64 `json:"quantity_sold"`
|
||||||
Revenue float64 `json:"revenue"`
|
Revenue float64 `json:"revenue"`
|
||||||
AveragePrice float64 `json:"average_price"`
|
AveragePrice float64 `json:"average_price"`
|
||||||
|
|||||||
@ -10,7 +10,6 @@ type CreateCategoryRequest struct {
|
|||||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
BusinessType *string `json:"business_type,omitempty"`
|
BusinessType *string `json:"business_type,omitempty"`
|
||||||
Order *int `json:"order,omitempty"`
|
|
||||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,7 +17,6 @@ type UpdateCategoryRequest struct {
|
|||||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
|
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
BusinessType *string `json:"business_type,omitempty"`
|
BusinessType *string `json:"business_type,omitempty"`
|
||||||
Order *int `json:"order,omitempty"`
|
|
||||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +35,6 @@ type CategoryResponse struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
BusinessType string `json:"business_type"`
|
BusinessType string `json:"business_type"`
|
||||||
Order int `json:"order"`
|
|
||||||
Metadata map[string]interface{} `json:"metadata"`
|
Metadata map[string]interface{} `json:"metadata"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
|||||||
@ -33,7 +33,6 @@ type ProductAnalytics struct {
|
|||||||
ProductName string `json:"product_name"`
|
ProductName string `json:"product_name"`
|
||||||
CategoryID uuid.UUID `json:"category_id"`
|
CategoryID uuid.UUID `json:"category_id"`
|
||||||
CategoryName string `json:"category_name"`
|
CategoryName string `json:"category_name"`
|
||||||
CategoryOrder int `json:"category_order"`
|
|
||||||
QuantitySold int64 `json:"quantity_sold"`
|
QuantitySold int64 `json:"quantity_sold"`
|
||||||
Revenue float64 `json:"revenue"`
|
Revenue float64 `json:"revenue"`
|
||||||
AveragePrice float64 `json:"average_price"`
|
AveragePrice float64 `json:"average_price"`
|
||||||
|
|||||||
@ -35,7 +35,6 @@ type Category struct {
|
|||||||
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
OrganizationID uuid.UUID `gorm:"type:uuid;not null;index" json:"organization_id" validate:"required"`
|
||||||
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
||||||
Description *string `gorm:"type:text" json:"description"`
|
Description *string `gorm:"type:text" json:"description"`
|
||||||
Order int `gorm:"default:0" json:"order"`
|
|
||||||
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
|
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
|
||||||
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"apskel-pos-be/internal/appcontext"
|
"apskel-pos-be/internal/appcontext"
|
||||||
@ -36,7 +35,6 @@ func (h *CategoryHandler) CreateCategory(c *gin.Context) {
|
|||||||
contextInfo := appcontext.FromGinContext(ctx)
|
contextInfo := appcontext.FromGinContext(ctx)
|
||||||
|
|
||||||
var req contract.CreateCategoryRequest
|
var req contract.CreateCategoryRequest
|
||||||
fmt.Printf("CategoryHandler::CreateCategory -> Request: %+v\n", req)
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
logger.FromContext(c.Request.Context()).WithError(err).Error("CategoryHandler::CreateCategory -> request binding failed")
|
logger.FromContext(c.Request.Context()).WithError(err).Error("CategoryHandler::CreateCategory -> request binding failed")
|
||||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
|
||||||
@ -73,7 +71,6 @@ func (h *CategoryHandler) UpdateCategory(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var req contract.UpdateCategoryRequest
|
var req contract.UpdateCategoryRequest
|
||||||
fmt.Printf("CategoryHandler::UpdateCategory -> Request: %+v\n", req)
|
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::UpdateCategory -> request binding failed")
|
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::UpdateCategory -> request binding failed")
|
||||||
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
|
||||||
|
|||||||
@ -16,7 +16,7 @@ func CategoryEntityToModel(entity *entities.Category) *models.Category {
|
|||||||
Name: entity.Name,
|
Name: entity.Name,
|
||||||
Description: entity.Description,
|
Description: entity.Description,
|
||||||
ImageURL: nil, // Entity doesn't have ImageURL, model does
|
ImageURL: nil, // Entity doesn't have ImageURL, model does
|
||||||
Order: entity.Order, // Entity doesn't have SortOrder, model does
|
SortOrder: 0, // Entity doesn't have SortOrder, model does
|
||||||
IsActive: true, // Entity doesn't have IsActive, default to true
|
IsActive: true, // Entity doesn't have IsActive, default to true
|
||||||
CreatedAt: entity.CreatedAt,
|
CreatedAt: entity.CreatedAt,
|
||||||
UpdatedAt: entity.UpdatedAt,
|
UpdatedAt: entity.UpdatedAt,
|
||||||
@ -32,7 +32,7 @@ func CategoryModelToEntity(model *models.Category) *entities.Category {
|
|||||||
if model.ImageURL != nil {
|
if model.ImageURL != nil {
|
||||||
metadata["image_url"] = *model.ImageURL
|
metadata["image_url"] = *model.ImageURL
|
||||||
}
|
}
|
||||||
// metadata["sort_order"] = model.SortOrder
|
metadata["sort_order"] = model.SortOrder
|
||||||
|
|
||||||
return &entities.Category{
|
return &entities.Category{
|
||||||
ID: model.ID,
|
ID: model.ID,
|
||||||
@ -40,7 +40,6 @@ func CategoryModelToEntity(model *models.Category) *entities.Category {
|
|||||||
Name: model.Name,
|
Name: model.Name,
|
||||||
Description: model.Description,
|
Description: model.Description,
|
||||||
BusinessType: "restaurant", // Default business type
|
BusinessType: "restaurant", // Default business type
|
||||||
Order: model.Order,
|
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
CreatedAt: model.CreatedAt,
|
CreatedAt: model.CreatedAt,
|
||||||
UpdatedAt: model.UpdatedAt,
|
UpdatedAt: model.UpdatedAt,
|
||||||
@ -56,13 +55,12 @@ func CreateCategoryRequestToEntity(req *models.CreateCategoryRequest) *entities.
|
|||||||
if req.ImageURL != nil {
|
if req.ImageURL != nil {
|
||||||
metadata["image_url"] = *req.ImageURL
|
metadata["image_url"] = *req.ImageURL
|
||||||
}
|
}
|
||||||
// metadata["sort_order"] = req.SortOrder
|
metadata["sort_order"] = req.SortOrder
|
||||||
|
|
||||||
return &entities.Category{
|
return &entities.Category{
|
||||||
OrganizationID: req.OrganizationID,
|
OrganizationID: req.OrganizationID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Order: req.Order,
|
|
||||||
BusinessType: "restaurant", // Default business type
|
BusinessType: "restaurant", // Default business type
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
}
|
}
|
||||||
@ -75,6 +73,7 @@ func CategoryEntityToResponse(entity *entities.Category) *models.CategoryRespons
|
|||||||
|
|
||||||
// Extract image URL and sort order from metadata
|
// Extract image URL and sort order from metadata
|
||||||
var imageURL *string
|
var imageURL *string
|
||||||
|
var sortOrder int
|
||||||
|
|
||||||
if entity.Metadata != nil {
|
if entity.Metadata != nil {
|
||||||
if imgURL, exists := entity.Metadata["image_url"]; exists {
|
if imgURL, exists := entity.Metadata["image_url"]; exists {
|
||||||
@ -82,6 +81,13 @@ func CategoryEntityToResponse(entity *entities.Category) *models.CategoryRespons
|
|||||||
imageURL = &imgURLStr
|
imageURL = &imgURLStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if sort, exists := entity.Metadata["sort_order"]; exists {
|
||||||
|
if sortInt, ok := sort.(int); ok {
|
||||||
|
sortOrder = sortInt
|
||||||
|
} else if sortFloat, ok := sort.(float64); ok {
|
||||||
|
sortOrder = int(sortFloat)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.CategoryResponse{
|
return &models.CategoryResponse{
|
||||||
@ -90,7 +96,7 @@ func CategoryEntityToResponse(entity *entities.Category) *models.CategoryRespons
|
|||||||
Name: entity.Name,
|
Name: entity.Name,
|
||||||
Description: entity.Description,
|
Description: entity.Description,
|
||||||
ImageURL: imageURL,
|
ImageURL: imageURL,
|
||||||
Order: entity.Order,
|
SortOrder: sortOrder,
|
||||||
IsActive: true, // Default to true since entity doesn't have this field
|
IsActive: true, // Default to true since entity doesn't have this field
|
||||||
CreatedAt: entity.CreatedAt,
|
CreatedAt: entity.CreatedAt,
|
||||||
UpdatedAt: entity.UpdatedAt,
|
UpdatedAt: entity.UpdatedAt,
|
||||||
@ -118,8 +124,8 @@ func UpdateCategoryEntityFromRequest(entity *entities.Category, req *models.Upda
|
|||||||
entity.Metadata["image_url"] = *req.ImageURL
|
entity.Metadata["image_url"] = *req.ImageURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Order != nil {
|
if req.SortOrder != nil {
|
||||||
entity.Order = *req.Order
|
entity.Metadata["sort_order"] = *req.SortOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -111,7 +111,6 @@ type ProductAnalyticsData struct {
|
|||||||
ProductName string `json:"product_name"`
|
ProductName string `json:"product_name"`
|
||||||
CategoryID uuid.UUID `json:"category_id"`
|
CategoryID uuid.UUID `json:"category_id"`
|
||||||
CategoryName string `json:"category_name"`
|
CategoryName string `json:"category_name"`
|
||||||
CategoryOrder int `json:"category_order"`
|
|
||||||
QuantitySold int64 `json:"quantity_sold"`
|
QuantitySold int64 `json:"quantity_sold"`
|
||||||
Revenue float64 `json:"revenue"`
|
Revenue float64 `json:"revenue"`
|
||||||
AveragePrice float64 `json:"average_price"`
|
AveragePrice float64 `json:"average_price"`
|
||||||
|
|||||||
@ -12,7 +12,7 @@ type Category struct {
|
|||||||
Name string
|
Name string
|
||||||
Description *string
|
Description *string
|
||||||
ImageURL *string
|
ImageURL *string
|
||||||
Order int
|
SortOrder int
|
||||||
IsActive bool
|
IsActive bool
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
@ -23,14 +23,14 @@ type CreateCategoryRequest struct {
|
|||||||
Name string `validate:"required,min=1,max=255"`
|
Name string `validate:"required,min=1,max=255"`
|
||||||
Description *string `validate:"omitempty,max=1000"`
|
Description *string `validate:"omitempty,max=1000"`
|
||||||
ImageURL *string `validate:"omitempty,url"`
|
ImageURL *string `validate:"omitempty,url"`
|
||||||
Order int `validate:"min=0"`
|
SortOrder int `validate:"min=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateCategoryRequest struct {
|
type UpdateCategoryRequest struct {
|
||||||
Name *string `validate:"omitempty,min=1,max=255"`
|
Name *string `validate:"omitempty,min=1,max=255"`
|
||||||
Description *string `validate:"omitempty,max=1000"`
|
Description *string `validate:"omitempty,max=1000"`
|
||||||
ImageURL *string `validate:"omitempty,url"`
|
ImageURL *string `validate:"omitempty,url"`
|
||||||
Order *int `validate:"omitempty,min=0"`
|
SortOrder *int `validate:"omitempty,min=0"`
|
||||||
IsActive *bool
|
IsActive *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ type CategoryResponse struct {
|
|||||||
Name string
|
Name string
|
||||||
Description *string
|
Description *string
|
||||||
ImageURL *string
|
ImageURL *string
|
||||||
Order int
|
SortOrder int
|
||||||
IsActive bool
|
IsActive bool
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
|
|||||||
@ -189,7 +189,6 @@ func (p *AnalyticsProcessorImpl) GetProductAnalytics(ctx context.Context, req *m
|
|||||||
ProductName: data.ProductName,
|
ProductName: data.ProductName,
|
||||||
CategoryID: data.CategoryID,
|
CategoryID: data.CategoryID,
|
||||||
CategoryName: data.CategoryName,
|
CategoryName: data.CategoryName,
|
||||||
CategoryOrder: data.CategoryOrder,
|
|
||||||
QuantitySold: data.QuantitySold,
|
QuantitySold: data.QuantitySold,
|
||||||
Revenue: data.Revenue,
|
Revenue: data.Revenue,
|
||||||
AveragePrice: data.AveragePrice,
|
AveragePrice: data.AveragePrice,
|
||||||
|
|||||||
@ -117,7 +117,6 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalytics(ctx context.Context, organ
|
|||||||
p.name as product_name,
|
p.name as product_name,
|
||||||
c.id as category_id,
|
c.id as category_id,
|
||||||
c.name as category_name,
|
c.name as category_name,
|
||||||
c.order as category_order,
|
|
||||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.quantity - COALESCE(oi.refund_quantity, 0) ELSE 0 END), 0) as quantity_sold,
|
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.quantity - COALESCE(oi.refund_quantity, 0) ELSE 0 END), 0) as quantity_sold,
|
||||||
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END), 0) as revenue,
|
COALESCE(SUM(CASE WHEN oi.is_fully_refunded = false THEN oi.total_price - COALESCE(oi.refund_amount, 0) ELSE 0 END), 0) as revenue,
|
||||||
CASE
|
CASE
|
||||||
@ -143,7 +142,7 @@ func (r *AnalyticsRepositoryImpl) GetProductAnalytics(ctx context.Context, organ
|
|||||||
|
|
||||||
err := query.
|
err := query.
|
||||||
Group("p.id, p.name, c.id, c.name").
|
Group("p.id, p.name, c.id, c.name").
|
||||||
Order("revenue DESC").
|
Order("p.name ASC").
|
||||||
Limit(limit).
|
Limit(limit).
|
||||||
Scan(&results).Error
|
Scan(&results).Error
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,7 @@ func (r *CategoryRepositoryImpl) List(ctx context.Context, filters map[string]in
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err := query.Order("\"order\" ASC").Limit(limit).Offset(offset).Find(&categories).Error
|
err := query.Limit(limit).Offset(offset).Find(&categories).Error
|
||||||
return categories, total, err
|
return categories, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -159,7 +159,6 @@ func ProductAnalyticsModelToContract(resp *models.ProductAnalyticsResponse) *con
|
|||||||
ProductName: item.ProductName,
|
ProductName: item.ProductName,
|
||||||
CategoryID: item.CategoryID,
|
CategoryID: item.CategoryID,
|
||||||
CategoryName: item.CategoryName,
|
CategoryName: item.CategoryName,
|
||||||
CategoryOrder: item.CategoryOrder,
|
|
||||||
QuantitySold: item.QuantitySold,
|
QuantitySold: item.QuantitySold,
|
||||||
Revenue: item.Revenue,
|
Revenue: item.Revenue,
|
||||||
AveragePrice: item.AveragePrice,
|
AveragePrice: item.AveragePrice,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ func CreateCategoryRequestToModel(apctx *appcontext.ContextInfo, req *contract.C
|
|||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
ImageURL: nil,
|
ImageURL: nil,
|
||||||
Order: *req.Order,
|
SortOrder: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ func UpdateCategoryRequestToModel(req *contract.UpdateCategoryRequest) *models.U
|
|||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
ImageURL: nil,
|
ImageURL: nil,
|
||||||
Order: req.Order,
|
SortOrder: nil,
|
||||||
IsActive: nil,
|
IsActive: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,7 +37,6 @@ func CategoryModelResponseToResponse(cat *models.CategoryResponse) *contract.Cat
|
|||||||
Name: cat.Name,
|
Name: cat.Name,
|
||||||
Description: cat.Description,
|
Description: cat.Description,
|
||||||
BusinessType: "restaurant", // Default business type
|
BusinessType: "restaurant", // Default business type
|
||||||
Order: cat.Order,
|
|
||||||
Metadata: map[string]interface{}{},
|
Metadata: map[string]interface{}{},
|
||||||
CreatedAt: cat.CreatedAt,
|
CreatedAt: cat.CreatedAt,
|
||||||
UpdatedAt: cat.UpdatedAt,
|
UpdatedAt: cat.UpdatedAt,
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE categories
|
|
||||||
DROP COLUMN "order";
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
ALTER TABLE categories
|
|
||||||
ADD COLUMN "order" INT DEFAULT 0;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user