From 3d124bafb001c0238d1c0f3314ce93a2bdab534c Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 13 May 2026 15:42:51 +0700 Subject: [PATCH] feat: add nullable outlet_id to product Co-authored-by: aider (openai/glm-5.1) --- internal/contract/product_contract.go | 4 ++++ internal/entities/product.go | 2 ++ internal/handler/product_handler.go | 6 ++++++ internal/models/product.go | 4 ++++ internal/service/product_service.go | 3 +++ internal/transformer/product_transformer.go | 5 ++++- 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/internal/contract/product_contract.go b/internal/contract/product_contract.go index 084a769..685b6e6 100644 --- a/internal/contract/product_contract.go +++ b/internal/contract/product_contract.go @@ -7,6 +7,7 @@ import ( ) type CreateProductRequest struct { + OutletID *uuid.UUID `json:"outlet_id,omitempty"` CategoryID uuid.UUID `json:"category_id" validate:"required"` SKU *string `json:"sku,omitempty"` Name string `json:"name" validate:"required,min=1,max=255"` @@ -25,6 +26,7 @@ type CreateProductRequest struct { } type UpdateProductRequest struct { + OutletID *uuid.UUID `json:"outlet_id,omitempty"` CategoryID *uuid.UUID `json:"category_id,omitempty"` SKU *string `json:"sku,omitempty"` Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"` @@ -58,6 +60,7 @@ type UpdateProductVariantRequest struct { type ProductResponse struct { ID uuid.UUID `json:"id"` OrganizationID uuid.UUID `json:"organization_id"` + OutletID *uuid.UUID `json:"outlet_id"` CategoryID uuid.UUID `json:"category_id"` CategoryName string `json:"category_name"` SKU *string `json:"sku"` @@ -89,6 +92,7 @@ type ProductVariantResponse struct { type ListProductsRequest struct { OrganizationID *uuid.UUID `json:"organization_id,omitempty"` + OutletID *uuid.UUID `json:"outlet_id,omitempty"` CategoryID *uuid.UUID `json:"category_id,omitempty"` BusinessType string `json:"business_type,omitempty"` IsActive *bool `json:"is_active,omitempty"` diff --git a/internal/entities/product.go b/internal/entities/product.go index b76d5f2..bf6397a 100644 --- a/internal/entities/product.go +++ b/internal/entities/product.go @@ -10,6 +10,7 @@ import ( type Product struct { 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"` + OutletID *uuid.UUID `gorm:"type:uuid;index" json:"outlet_id"` CategoryID uuid.UUID `gorm:"type:uuid;not null;index" json:"category_id" validate:"required"` SKU *string `gorm:"size:100;index" json:"sku"` Name string `gorm:"not null;size:255" json:"name" validate:"required,min=1,max=255"` @@ -27,6 +28,7 @@ type Product struct { UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"` Organization Organization `gorm:"foreignKey:OrganizationID" json:"organization,omitempty"` + Outlet *Outlet `gorm:"foreignKey:OutletID" json:"outlet,omitempty"` Category Category `gorm:"foreignKey:CategoryID" json:"category,omitempty"` Unit *Unit `gorm:"foreignKey:UnitID" json:"unit,omitempty"` ProductVariants []ProductVariant `gorm:"foreignKey:ProductID" json:"variants,omitempty"` diff --git a/internal/handler/product_handler.go b/internal/handler/product_handler.go index bdbe54f..9edb4a3 100644 --- a/internal/handler/product_handler.go +++ b/internal/handler/product_handler.go @@ -172,6 +172,12 @@ func (h *ProductHandler) ListProducts(c *gin.Context) { } } + if outletIDStr := c.Query("outlet_id"); outletIDStr != "" { + if outletID, err := uuid.Parse(outletIDStr); err == nil { + req.OutletID = &outletID + } + } + if categoryIDStr := c.Query("category_id"); categoryIDStr != "" { if categoryID, err := uuid.Parse(categoryIDStr); err == nil { req.CategoryID = &categoryID diff --git a/internal/models/product.go b/internal/models/product.go index 43e47d2..825ae13 100644 --- a/internal/models/product.go +++ b/internal/models/product.go @@ -10,6 +10,7 @@ import ( type Product struct { ID uuid.UUID OrganizationID uuid.UUID + OutletID *uuid.UUID CategoryID uuid.UUID SKU *string Name string @@ -40,6 +41,7 @@ type ProductVariant struct { type CreateProductRequest struct { OrganizationID uuid.UUID `validate:"required"` + OutletID *uuid.UUID `validate:"omitempty"` CategoryID uuid.UUID `validate:"required"` SKU *string `validate:"omitempty,max=100"` Name string `validate:"required,min=1,max=255"` @@ -60,6 +62,7 @@ type CreateProductRequest struct { } type UpdateProductRequest struct { + OutletID *uuid.UUID `validate:"omitempty"` CategoryID *uuid.UUID `validate:"omitempty"` SKU *string `validate:"omitempty,max=100"` Name *string `validate:"omitempty,min=1,max=255"` @@ -94,6 +97,7 @@ type UpdateProductVariantRequest struct { type ProductResponse struct { ID uuid.UUID OrganizationID uuid.UUID + OutletID *uuid.UUID CategoryID uuid.UUID CategoryName string SKU *string diff --git a/internal/service/product_service.go b/internal/service/product_service.go index 61eed11..de05f5e 100644 --- a/internal/service/product_service.go +++ b/internal/service/product_service.go @@ -85,6 +85,9 @@ func (s *ProductServiceImpl) ListProducts(ctx context.Context, req *contract.Lis if req.OrganizationID != nil { filters["organization_id"] = *req.OrganizationID } + if req.OutletID != nil { + filters["outlet_id"] = *req.OutletID + } if req.CategoryID != nil { filters["category_id"] = *req.CategoryID } diff --git a/internal/transformer/product_transformer.go b/internal/transformer/product_transformer.go index 77ec925..e1c57d3 100644 --- a/internal/transformer/product_transformer.go +++ b/internal/transformer/product_transformer.go @@ -39,6 +39,7 @@ func CreateProductRequestToModel(apctx *appcontext.ContextInfo, req *contract.Cr return &models.CreateProductRequest{ OrganizationID: apctx.OrganizationID, + OutletID: req.OutletID, CategoryID: req.CategoryID, SKU: req.SKU, Name: req.Name, @@ -60,7 +61,8 @@ func UpdateProductRequestToModel(req *contract.UpdateProductRequest) *models.Upd } return &models.UpdateProductRequest{ - CategoryID: req.CategoryID, + OutletID: req.OutletID, + CategoryID: req.CategoryID, SKU: req.SKU, Name: req.Name, Description: req.Description, @@ -100,6 +102,7 @@ func ProductModelResponseToResponse(prod *models.ProductResponse) *contract.Prod return &contract.ProductResponse{ ID: prod.ID, OrganizationID: prod.OrganizationID, + OutletID: prod.OutletID, CategoryID: prod.CategoryID, CategoryName: prod.CategoryName, SKU: prod.SKU,