diff --git a/internal/app/app.go b/internal/app/app.go index 9948da4..3f57cd5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -347,7 +347,7 @@ func (a *App) initProcessors(cfg *config.Config, repos *repositories) *processor outletProcessor: processor.NewOutletProcessorImpl(repos.outletRepo), outletSettingProcessor: processor.NewOutletSettingProcessorImpl(repos.outletSettingRepo, repos.outletRepo), categoryProcessor: processor.NewCategoryProcessorImpl(repos.categoryRepo), - productProcessor: processor.NewProductProcessorImpl(repos.productRepo, repos.categoryRepo, repos.productVariantRepo, repos.inventoryRepo, repos.outletRepo), + productProcessor: processor.NewProductProcessorImpl(repos.productRepo, repos.categoryRepo, repos.productVariantRepo, repos.inventoryRepo, repos.outletRepo, repos.productOutletPriceRepo), productVariantProcessor: processor.NewProductVariantProcessorImpl(repos.productVariantRepo, repos.productRepo), inventoryProcessor: processor.NewInventoryProcessorImpl(repos.inventoryRepo, repos.productRepo, repos.outletRepo, repos.ingredientRepo, repos.inventoryMovementRepo), orderProcessor: processor.NewOrderProcessorImpl(repos.orderRepo, repos.orderItemRepo, repos.paymentRepo, repos.paymentOrderItemRepo, repos.productRepo, repos.paymentMethodRepo, repos.inventoryRepo, repos.inventoryMovementRepo, repos.productVariantRepo, repos.outletRepo, repos.customerRepo, repos.txManager, repos.productRecipeRepo, repos.ingredientRepo, inventoryMovementService, repos.productOutletPriceRepo), @@ -382,7 +382,7 @@ func (a *App) initProcessors(cfg *config.Config, repos *repositories) *processor inventoryMovementService: inventoryMovementService, userDeviceProcessor: processor.NewUserDeviceProcessorImpl(repos.userDeviceRepo), notificationProcessor: buildNotificationProcessor(cfg, repos), - productOutletPriceProcessor: processor.NewProductOutletPriceProcessorImpl(repos.productOutletPriceRepo), + productOutletPriceProcessor: processor.NewProductOutletPriceProcessorImpl(repos.productOutletPriceRepo, repos.productRepo, repos.outletRepo), } } diff --git a/internal/contract/product_contract.go b/internal/contract/product_contract.go index 084a769..979400f 100644 --- a/internal/contract/product_contract.go +++ b/internal/contract/product_contract.go @@ -89,6 +89,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/handler/product_handler.go b/internal/handler/product_handler.go index bdbe54f..b4957d0 100644 --- a/internal/handler/product_handler.go +++ b/internal/handler/product_handler.go @@ -184,6 +184,14 @@ 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 + } + } else if contextInfo.OutletID != uuid.Nil { + req.OutletID = &contextInfo.OutletID + } + if minPriceStr := c.Query("min_price"); minPriceStr != "" { if minPrice, err := strconv.ParseFloat(minPriceStr, 64); err == nil { req.MinPrice = &minPrice diff --git a/internal/processor/product_processor.go b/internal/processor/product_processor.go index ef522d4..846e74b 100644 --- a/internal/processor/product_processor.go +++ b/internal/processor/product_processor.go @@ -47,15 +47,17 @@ type ProductProcessorImpl struct { productVariantRepo repository.ProductVariantRepository inventoryRepo repository.InventoryRepository outletRepo OutletRepository + outletPriceRepo repository.ProductOutletPriceRepository } -func NewProductProcessorImpl(productRepo ProductRepository, categoryRepo CategoryRepository, productVariantRepo repository.ProductVariantRepository, inventoryRepo repository.InventoryRepository, outletRepo OutletRepository) *ProductProcessorImpl { +func NewProductProcessorImpl(productRepo ProductRepository, categoryRepo CategoryRepository, productVariantRepo repository.ProductVariantRepository, inventoryRepo repository.InventoryRepository, outletRepo OutletRepository, outletPriceRepo repository.ProductOutletPriceRepository) *ProductProcessorImpl { return &ProductProcessorImpl{ productRepo: productRepo, categoryRepo: categoryRepo, productVariantRepo: productVariantRepo, inventoryRepo: inventoryRepo, outletRepo: outletRepo, + outletPriceRepo: outletPriceRepo, } } @@ -227,11 +229,36 @@ func (p *ProductProcessorImpl) GetProductByID(ctx context.Context, id uuid.UUID) func (p *ProductProcessorImpl) ListProducts(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.ProductResponse, int, error) { offset := (page - 1) * limit + var outletID uuid.UUID + if oid, ok := filters["outlet_id"]; ok { + outletID = oid.(uuid.UUID) + delete(filters, "outlet_id") + } + productEntities, total, err := p.productRepo.List(ctx, filters, limit, offset) if err != nil { return nil, 0, fmt.Errorf("failed to list products: %w", err) } + if outletID != uuid.Nil && len(productEntities) > 0 { + productIDs := make([]uuid.UUID, len(productEntities)) + for i, pe := range productEntities { + productIDs[i] = pe.ID + } + outletPrices, err := p.outletPriceRepo.GetByProductsAndOutlet(ctx, productIDs, outletID) + if err == nil { + priceMap := make(map[uuid.UUID]float64, len(outletPrices)) + for _, op := range outletPrices { + priceMap[op.ProductID] = op.Price + } + for _, pe := range productEntities { + if price, ok := priceMap[pe.ID]; ok { + pe.Price = price + } + } + } + } + responses := make([]models.ProductResponse, len(productEntities)) for i, entity := range productEntities { response := mappers.ProductEntityToResponse(entity) diff --git a/internal/repository/product_outlet_price_repository.go b/internal/repository/product_outlet_price_repository.go index 86c5035..6c90a17 100644 --- a/internal/repository/product_outlet_price_repository.go +++ b/internal/repository/product_outlet_price_repository.go @@ -14,6 +14,7 @@ type ProductOutletPriceRepository interface { GetByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID) (*entities.ProductOutletPrice, error) GetByProduct(ctx context.Context, productID uuid.UUID) ([]*entities.ProductOutletPrice, error) GetByOutlet(ctx context.Context, outletID uuid.UUID) ([]*entities.ProductOutletPrice, error) + GetByProductsAndOutlet(ctx context.Context, productIDs []uuid.UUID, outletID uuid.UUID) ([]*entities.ProductOutletPrice, error) Upsert(ctx context.Context, price *entities.ProductOutletPrice) error Delete(ctx context.Context, id uuid.UUID) error GetByID(ctx context.Context, id uuid.UUID) (*entities.ProductOutletPrice, error) @@ -69,3 +70,9 @@ func (r *ProductOutletPriceRepositoryImpl) GetByID(ctx context.Context, id uuid. } return &price, nil } + +func (r *ProductOutletPriceRepositoryImpl) GetByProductsAndOutlet(ctx context.Context, productIDs []uuid.UUID, outletID uuid.UUID) ([]*entities.ProductOutletPrice, error) { + var prices []*entities.ProductOutletPrice + err := r.db.WithContext(ctx).Where("product_id IN ? AND outlet_id = ?", productIDs, outletID).Find(&prices).Error + return prices, err +} 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 }