Compare commits

..

No commits in common. "54dc8662d68544e2f6b8f05338e335f9d9f881de" and "670a283c7b69a481e936695385bff47c09df3dc6" have entirely different histories.

15 changed files with 22 additions and 35 deletions

View File

@ -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"`

View File

@ -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"`

View File

@ -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"`

View File

@ -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"`

View File

@ -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")

View File

@ -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
} }
} }

View File

@ -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"`

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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
} }

View File

@ -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,

View File

@ -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,

View File

@ -1,2 +0,0 @@
ALTER TABLE categories
DROP COLUMN "order";

View File

@ -1,3 +0,0 @@
ALTER TABLE categories
ADD COLUMN "order" INT DEFAULT 0;