create or update product assign to product outlet
This commit is contained in:
parent
35c4cf2f2f
commit
72f67cb519
@ -8,6 +8,7 @@ import (
|
||||
|
||||
type CreateProductRequest struct {
|
||||
CategoryID uuid.UUID `json:"category_id" validate:"required"`
|
||||
OutletID *uuid.UUID `json:"outlet_id,omitempty"`
|
||||
SKU *string `json:"sku,omitempty"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
@ -19,12 +20,13 @@ type CreateProductRequest struct {
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
Variants []CreateProductVariantRequest `json:"variants,omitempty"`
|
||||
InitialStock *int `json:"initial_stock,omitempty" validate:"omitempty,min=0"` // Initial stock quantity for all outlets
|
||||
ReorderLevel *int `json:"reorder_level,omitempty" validate:"omitempty,min=0"` // Reorder level for all outlets
|
||||
CreateInventory bool `json:"create_inventory,omitempty"` // Whether to create inventory records for all outlets
|
||||
InitialStock *int `json:"initial_stock,omitempty" validate:"omitempty,min=0"`
|
||||
ReorderLevel *int `json:"reorder_level,omitempty" validate:"omitempty,min=0"`
|
||||
CreateInventory bool `json:"create_inventory,omitempty"`
|
||||
}
|
||||
|
||||
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"`
|
||||
@ -36,8 +38,7 @@ type UpdateProductRequest struct {
|
||||
PrinterType *string `json:"printer_type,omitempty" validate:"omitempty,max=50"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
// Stock management fields
|
||||
ReorderLevel *int `json:"reorder_level,omitempty" validate:"omitempty,min=0"` // Update reorder level for all existing inventory records
|
||||
ReorderLevel *int `json:"reorder_level,omitempty" validate:"omitempty,min=0"`
|
||||
}
|
||||
|
||||
type CreateProductVariantRequest struct {
|
||||
|
||||
@ -60,6 +60,7 @@ func (h *ProductHandler) CreateProduct(c *gin.Context) {
|
||||
|
||||
func (h *ProductHandler) UpdateProduct(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
contextInfo := appcontext.FromGinContext(ctx)
|
||||
|
||||
productIDStr := c.Param("id")
|
||||
productID, err := uuid.Parse(productIDStr)
|
||||
@ -85,7 +86,7 @@ func (h *ProductHandler) UpdateProduct(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
productResponse := h.productService.UpdateProduct(ctx, productID, &req)
|
||||
productResponse := h.productService.UpdateProduct(ctx, contextInfo, productID, &req)
|
||||
if productResponse.HasErrors() {
|
||||
errorResp := productResponse.GetErrors()[0]
|
||||
logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::UpdateProduct -> Failed to update product from service")
|
||||
|
||||
@ -40,6 +40,7 @@ type ProductVariant struct {
|
||||
|
||||
type CreateProductRequest struct {
|
||||
OrganizationID uuid.UUID `validate:"required"`
|
||||
OutletID uuid.UUID `validate:"omitempty"` // If set, upsert product_outlet_prices on create
|
||||
CategoryID uuid.UUID `validate:"required"`
|
||||
SKU *string `validate:"omitempty,max=100"`
|
||||
Name string `validate:"required,min=1,max=255"`
|
||||
@ -60,6 +61,7 @@ type CreateProductRequest struct {
|
||||
}
|
||||
|
||||
type UpdateProductRequest struct {
|
||||
OutletID uuid.UUID `validate:"omitempty"` // If set, upsert product_outlet_prices on update
|
||||
CategoryID *uuid.UUID `validate:"omitempty"`
|
||||
SKU *string `validate:"omitempty,max=100"`
|
||||
Name *string `validate:"omitempty,min=1,max=255"`
|
||||
|
||||
@ -122,6 +122,18 @@ func (p *ProductProcessorImpl) CreateProduct(ctx context.Context, req *models.Cr
|
||||
}
|
||||
}
|
||||
|
||||
// Upsert outlet-specific price if outlet context is present
|
||||
if req.OutletID != uuid.Nil {
|
||||
outletPriceEntity := &entities.ProductOutletPrice{
|
||||
ProductID: productEntity.ID,
|
||||
OutletID: req.OutletID,
|
||||
Price: req.Price,
|
||||
}
|
||||
if err := p.outletPriceRepo.Upsert(ctx, outletPriceEntity); err != nil {
|
||||
return nil, fmt.Errorf("failed to assign outlet price: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
productWithCategory, err := p.productRepo.GetWithCategory(ctx, productEntity.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve created product: %w", err)
|
||||
@ -183,6 +195,18 @@ func (p *ProductProcessorImpl) UpdateProduct(ctx context.Context, id uuid.UUID,
|
||||
}
|
||||
}
|
||||
|
||||
// Upsert outlet-specific price if outlet context is present
|
||||
if req.OutletID != uuid.Nil && req.Price != nil {
|
||||
outletPriceEntity := &entities.ProductOutletPrice{
|
||||
ProductID: id,
|
||||
OutletID: req.OutletID,
|
||||
Price: *req.Price,
|
||||
}
|
||||
if err := p.outletPriceRepo.Upsert(ctx, outletPriceEntity); err != nil {
|
||||
return nil, fmt.Errorf("failed to assign outlet price: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
productWithCategory, err := p.productRepo.GetWithCategory(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve updated product: %w", err)
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
|
||||
type ProductService interface {
|
||||
CreateProduct(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateProductRequest) *contract.Response
|
||||
UpdateProduct(ctx context.Context, id uuid.UUID, req *contract.UpdateProductRequest) *contract.Response
|
||||
UpdateProduct(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateProductRequest) *contract.Response
|
||||
DeleteProduct(ctx context.Context, id uuid.UUID) *contract.Response
|
||||
GetProductByID(ctx context.Context, id uuid.UUID, outletID uuid.UUID) *contract.Response
|
||||
ListProducts(ctx context.Context, req *contract.ListProductsRequest) *contract.Response
|
||||
@ -44,8 +44,8 @@ func (s *ProductServiceImpl) CreateProduct(ctx context.Context, apctx *appcontex
|
||||
return contract.BuildSuccessResponse(contractResponse)
|
||||
}
|
||||
|
||||
func (s *ProductServiceImpl) UpdateProduct(ctx context.Context, id uuid.UUID, req *contract.UpdateProductRequest) *contract.Response {
|
||||
modelReq := transformer.UpdateProductRequestToModel(req)
|
||||
func (s *ProductServiceImpl) UpdateProduct(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateProductRequest) *contract.Response {
|
||||
modelReq := transformer.UpdateProductRequestToModel(apctx, req)
|
||||
|
||||
productResponse, err := s.productProcessor.UpdateProduct(ctx, id, modelReq)
|
||||
if err != nil {
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
"apskel-pos-be/internal/models"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func CreateProductRequestToModel(apctx *appcontext.ContextInfo, req *contract.CreateProductRequest) *models.CreateProductRequest {
|
||||
@ -37,8 +39,15 @@ func CreateProductRequestToModel(apctx *appcontext.ContextInfo, req *contract.Cr
|
||||
metadata = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// Prioritize outlet_id from context, fallback to request body
|
||||
outletID := apctx.OutletID
|
||||
if outletID == uuid.Nil && req.OutletID != nil {
|
||||
outletID = *req.OutletID
|
||||
}
|
||||
|
||||
return &models.CreateProductRequest{
|
||||
OrganizationID: apctx.OrganizationID,
|
||||
OutletID: outletID,
|
||||
CategoryID: req.CategoryID,
|
||||
SKU: req.SKU,
|
||||
Name: req.Name,
|
||||
@ -53,13 +62,20 @@ func CreateProductRequestToModel(apctx *appcontext.ContextInfo, req *contract.Cr
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateProductRequestToModel(req *contract.UpdateProductRequest) *models.UpdateProductRequest {
|
||||
func UpdateProductRequestToModel(apctx *appcontext.ContextInfo, req *contract.UpdateProductRequest) *models.UpdateProductRequest {
|
||||
metadata := req.Metadata
|
||||
if metadata == nil {
|
||||
metadata = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// Prioritize outlet_id from context, fallback to request body
|
||||
outletID := apctx.OutletID
|
||||
if outletID == uuid.Nil && req.OutletID != nil {
|
||||
outletID = *req.OutletID
|
||||
}
|
||||
|
||||
return &models.UpdateProductRequest{
|
||||
OutletID: outletID,
|
||||
CategoryID: req.CategoryID,
|
||||
SKU: req.SKU,
|
||||
Name: req.Name,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user