categories add outlet id
This commit is contained in:
parent
72f67cb519
commit
91960f0e57
@ -10,7 +10,8 @@ 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"`
|
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||||
|
Order *int `json:"order,omitempty"`
|
||||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,12 +19,14 @@ 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"`
|
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||||
|
Order *int `json:"order,omitempty"`
|
||||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListCategoriesRequest struct {
|
type ListCategoriesRequest struct {
|
||||||
OrganizationID *uuid.UUID `json:"organization_id,omitempty"`
|
OrganizationID *uuid.UUID `json:"organization_id,omitempty"`
|
||||||
|
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||||
BusinessType string `json:"business_type,omitempty"`
|
BusinessType string `json:"business_type,omitempty"`
|
||||||
Search string `json:"search,omitempty"`
|
Search string `json:"search,omitempty"`
|
||||||
Page int `json:"page" validate:"required,min=1"`
|
Page int `json:"page" validate:"required,min=1"`
|
||||||
@ -34,10 +37,11 @@ type ListCategoriesRequest struct {
|
|||||||
type CategoryResponse struct {
|
type CategoryResponse struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
|
OutletID *uuid.UUID `json:"outlet_id"`
|
||||||
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"`
|
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"`
|
||||||
|
|||||||
@ -31,15 +31,16 @@ func (m *Metadata) Scan(value interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Category struct {
|
type Category struct {
|
||||||
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
||||||
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"`
|
OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"`
|
||||||
Description *string `gorm:"type:text" json:"description"`
|
Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"`
|
||||||
Order int `gorm:"default:0" json:"order"`
|
Description *string `gorm:"type:text" json:"description"`
|
||||||
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
|
Order int `gorm:"default:0" json:"order"`
|
||||||
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
BusinessType string `gorm:"size:50;default:'restaurant'" json:"business_type"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
Metadata Metadata `gorm:"type:jsonb;default:'{}'" json:"metadata"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||||
|
|
||||||
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"`
|
||||||
Products []Product `gorm:"foreignKey:CategoryID" json:"products,omitempty"`
|
Products []Product `gorm:"foreignKey:CategoryID" json:"products,omitempty"`
|
||||||
|
|||||||
@ -36,7 +36,7 @@ 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)
|
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())
|
||||||
@ -44,6 +44,11 @@ func (h *CategoryHandler) CreateCategory(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inject outlet_id from context if user has one and request doesn't provide it
|
||||||
|
if req.OutletID == nil && contextInfo.OutletID != uuid.Nil {
|
||||||
|
req.OutletID = &contextInfo.OutletID
|
||||||
|
}
|
||||||
|
|
||||||
validationError, validationErrorCode := h.categoryValidator.ValidateCreateCategoryRequest(&req)
|
validationError, validationErrorCode := h.categoryValidator.ValidateCreateCategoryRequest(&req)
|
||||||
if validationError != nil {
|
if validationError != nil {
|
||||||
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
|
||||||
@ -149,6 +154,11 @@ func (h *CategoryHandler) ListCategories(c *gin.Context) {
|
|||||||
OrganizationID: &contextInfo.OrganizationID,
|
OrganizationID: &contextInfo.OrganizationID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inject outlet_id from context if user has one
|
||||||
|
if contextInfo.OutletID != uuid.Nil {
|
||||||
|
req.OutletID = &contextInfo.OutletID
|
||||||
|
}
|
||||||
|
|
||||||
// Parse query parameters
|
// Parse query parameters
|
||||||
if pageStr := c.Query("page"); pageStr != "" {
|
if pageStr := c.Query("page"); pageStr != "" {
|
||||||
if page, err := strconv.Atoi(pageStr); err == nil {
|
if page, err := strconv.Atoi(pageStr); err == nil {
|
||||||
@ -176,6 +186,12 @@ func (h *CategoryHandler) ListCategories(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if outletIDStr := c.Query("outlet_id"); outletIDStr != "" {
|
||||||
|
if outletID, err := uuid.Parse(outletIDStr); err == nil {
|
||||||
|
req.OutletID = &outletID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validationError, validationErrorCode := h.categoryValidator.ValidateListCategoriesRequest(req)
|
validationError, validationErrorCode := h.categoryValidator.ValidateListCategoriesRequest(req)
|
||||||
if validationError != nil {
|
if validationError != nil {
|
||||||
logger.FromContext(ctx).WithError(validationError).Error("CategoryHandler::ListCategories -> request validation failed")
|
logger.FromContext(ctx).WithError(validationError).Error("CategoryHandler::ListCategories -> request validation failed")
|
||||||
|
|||||||
@ -13,11 +13,12 @@ func CategoryEntityToModel(entity *entities.Category) *models.Category {
|
|||||||
return &models.Category{
|
return &models.Category{
|
||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
OrganizationID: entity.OrganizationID,
|
OrganizationID: entity.OrganizationID,
|
||||||
|
OutletID: entity.OutletID,
|
||||||
Name: entity.Name,
|
Name: entity.Name,
|
||||||
Description: entity.Description,
|
Description: entity.Description,
|
||||||
ImageURL: nil, // Entity doesn't have ImageURL, model does
|
ImageURL: nil,
|
||||||
Order: entity.Order, // Entity doesn't have SortOrder, model does
|
Order: entity.Order,
|
||||||
IsActive: true, // Entity doesn't have IsActive, default to true
|
IsActive: true,
|
||||||
CreatedAt: entity.CreatedAt,
|
CreatedAt: entity.CreatedAt,
|
||||||
UpdatedAt: entity.UpdatedAt,
|
UpdatedAt: entity.UpdatedAt,
|
||||||
}
|
}
|
||||||
@ -32,14 +33,14 @@ 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
|
|
||||||
|
|
||||||
return &entities.Category{
|
return &entities.Category{
|
||||||
ID: model.ID,
|
ID: model.ID,
|
||||||
OrganizationID: model.OrganizationID,
|
OrganizationID: model.OrganizationID,
|
||||||
|
OutletID: model.OutletID,
|
||||||
Name: model.Name,
|
Name: model.Name,
|
||||||
Description: model.Description,
|
Description: model.Description,
|
||||||
BusinessType: "restaurant", // Default business type
|
BusinessType: "restaurant",
|
||||||
Order: model.Order,
|
Order: model.Order,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
CreatedAt: model.CreatedAt,
|
CreatedAt: model.CreatedAt,
|
||||||
@ -56,14 +57,14 @@ 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
|
|
||||||
|
|
||||||
return &entities.Category{
|
return &entities.Category{
|
||||||
OrganizationID: req.OrganizationID,
|
OrganizationID: req.OrganizationID,
|
||||||
|
OutletID: req.OutletID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
Order: req.Order,
|
Order: req.Order,
|
||||||
BusinessType: "restaurant", // Default business type
|
BusinessType: "restaurant",
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,11 +88,12 @@ func CategoryEntityToResponse(entity *entities.Category) *models.CategoryRespons
|
|||||||
return &models.CategoryResponse{
|
return &models.CategoryResponse{
|
||||||
ID: entity.ID,
|
ID: entity.ID,
|
||||||
OrganizationID: entity.OrganizationID,
|
OrganizationID: entity.OrganizationID,
|
||||||
|
OutletID: entity.OutletID,
|
||||||
Name: entity.Name,
|
Name: entity.Name,
|
||||||
Description: entity.Description,
|
Description: entity.Description,
|
||||||
ImageURL: imageURL,
|
ImageURL: imageURL,
|
||||||
Order: entity.Order,
|
Order: entity.Order,
|
||||||
IsActive: true, // Default to true since entity doesn't have this field
|
IsActive: true,
|
||||||
CreatedAt: entity.CreatedAt,
|
CreatedAt: entity.CreatedAt,
|
||||||
UpdatedAt: entity.UpdatedAt,
|
UpdatedAt: entity.UpdatedAt,
|
||||||
}
|
}
|
||||||
@ -121,6 +123,10 @@ func UpdateCategoryEntityFromRequest(entity *entities.Category, req *models.Upda
|
|||||||
if req.Order != nil {
|
if req.Order != nil {
|
||||||
entity.Order = *req.Order
|
entity.Order = *req.Order
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.OutletID != nil {
|
||||||
|
entity.OutletID = req.OutletID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CategoryEntitiesToModels(entities []*entities.Category) []*models.Category {
|
func CategoryEntitiesToModels(entities []*entities.Category) []*models.Category {
|
||||||
|
|||||||
@ -9,10 +9,11 @@ import (
|
|||||||
type Category struct {
|
type Category struct {
|
||||||
ID uuid.UUID
|
ID uuid.UUID
|
||||||
OrganizationID uuid.UUID
|
OrganizationID uuid.UUID
|
||||||
|
OutletID *uuid.UUID
|
||||||
Name string
|
Name string
|
||||||
Description *string
|
Description *string
|
||||||
ImageURL *string
|
ImageURL *string
|
||||||
Order int
|
Order int
|
||||||
IsActive bool
|
IsActive bool
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
@ -20,27 +21,30 @@ type Category struct {
|
|||||||
|
|
||||||
type CreateCategoryRequest struct {
|
type CreateCategoryRequest struct {
|
||||||
OrganizationID uuid.UUID `validate:"required"`
|
OrganizationID uuid.UUID `validate:"required"`
|
||||||
Name string `validate:"required,min=1,max=255"`
|
OutletID *uuid.UUID
|
||||||
Description *string `validate:"omitempty,max=1000"`
|
Name string `validate:"required,min=1,max=255"`
|
||||||
ImageURL *string `validate:"omitempty,url"`
|
Description *string `validate:"omitempty,max=1000"`
|
||||||
Order int `validate:"min=0"`
|
ImageURL *string `validate:"omitempty,url"`
|
||||||
|
Order 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"`
|
OutletID *uuid.UUID
|
||||||
|
Order *int `validate:"omitempty,min=0"`
|
||||||
IsActive *bool
|
IsActive *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CategoryResponse struct {
|
type CategoryResponse struct {
|
||||||
ID uuid.UUID
|
ID uuid.UUID
|
||||||
OrganizationID uuid.UUID
|
OrganizationID uuid.UUID
|
||||||
|
OutletID *uuid.UUID
|
||||||
Name string
|
Name string
|
||||||
Description *string
|
Description *string
|
||||||
ImageURL *string
|
ImageURL *string
|
||||||
Order int
|
Order int
|
||||||
IsActive bool
|
IsActive bool
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
|
|||||||
@ -85,6 +85,9 @@ func (s *CategoryServiceImpl) ListCategories(ctx context.Context, req *contract.
|
|||||||
if req.OrganizationID != nil {
|
if req.OrganizationID != nil {
|
||||||
filters["organization_id"] = *req.OrganizationID
|
filters["organization_id"] = *req.OrganizationID
|
||||||
}
|
}
|
||||||
|
if req.OutletID != nil {
|
||||||
|
filters["outlet_id"] = *req.OutletID
|
||||||
|
}
|
||||||
if req.BusinessType != "" {
|
if req.BusinessType != "" {
|
||||||
filters["business_type"] = req.BusinessType
|
filters["business_type"] = req.BusinessType
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,12 +7,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CreateCategoryRequestToModel(apctx *appcontext.ContextInfo, req *contract.CreateCategoryRequest) *models.CreateCategoryRequest {
|
func CreateCategoryRequestToModel(apctx *appcontext.ContextInfo, req *contract.CreateCategoryRequest) *models.CreateCategoryRequest {
|
||||||
|
order := 0
|
||||||
|
if req.Order != nil {
|
||||||
|
order = *req.Order
|
||||||
|
}
|
||||||
return &models.CreateCategoryRequest{
|
return &models.CreateCategoryRequest{
|
||||||
OrganizationID: apctx.OrganizationID,
|
OrganizationID: apctx.OrganizationID,
|
||||||
|
OutletID: req.OutletID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
ImageURL: nil,
|
ImageURL: nil,
|
||||||
Order: *req.Order,
|
Order: order,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,7 +26,8 @@ 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,
|
OutletID: req.OutletID,
|
||||||
|
Order: req.Order,
|
||||||
IsActive: nil,
|
IsActive: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,9 +40,10 @@ func CategoryModelResponseToResponse(cat *models.CategoryResponse) *contract.Cat
|
|||||||
return &contract.CategoryResponse{
|
return &contract.CategoryResponse{
|
||||||
ID: cat.ID,
|
ID: cat.ID,
|
||||||
OrganizationID: cat.OrganizationID,
|
OrganizationID: cat.OrganizationID,
|
||||||
|
OutletID: cat.OutletID,
|
||||||
Name: cat.Name,
|
Name: cat.Name,
|
||||||
Description: cat.Description,
|
Description: cat.Description,
|
||||||
BusinessType: "restaurant", // Default business type
|
BusinessType: "restaurant",
|
||||||
Order: cat.Order,
|
Order: cat.Order,
|
||||||
Metadata: map[string]interface{}{},
|
Metadata: map[string]interface{}{},
|
||||||
CreatedAt: cat.CreatedAt,
|
CreatedAt: cat.CreatedAt,
|
||||||
|
|||||||
5
migrations/000069_add_outlet_id_to_categories.down.sql
Normal file
5
migrations/000069_add_outlet_id_to_categories.down.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
-- Remove outlet_id column from categories table
|
||||||
|
DROP INDEX IF EXISTS idx_categories_outlet_id;
|
||||||
|
|
||||||
|
ALTER TABLE categories
|
||||||
|
DROP COLUMN IF EXISTS outlet_id;
|
||||||
6
migrations/000069_add_outlet_id_to_categories.up.sql
Normal file
6
migrations/000069_add_outlet_id_to_categories.up.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
-- Add outlet_id column to categories table (nullable)
|
||||||
|
ALTER TABLE categories
|
||||||
|
ADD COLUMN outlet_id UUID REFERENCES outlets(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
-- Index for outlet_id filter
|
||||||
|
CREATE INDEX idx_categories_outlet_id ON categories(outlet_id);
|
||||||
Loading…
x
Reference in New Issue
Block a user