init
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"apskel-pos-be/internal/entities"
|
||||
"apskel-pos-be/internal/mappers"
|
||||
"apskel-pos-be/internal/models"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type InventoryProcessor interface {
|
||||
CreateInventory(ctx context.Context, req *models.CreateInventoryRequest) (*models.InventoryResponse, error)
|
||||
UpdateInventory(ctx context.Context, id uuid.UUID, req *models.UpdateInventoryRequest) (*models.InventoryResponse, error)
|
||||
DeleteInventory(ctx context.Context, id uuid.UUID) error
|
||||
GetInventoryByID(ctx context.Context, id uuid.UUID) (*models.InventoryResponse, error)
|
||||
ListInventory(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.InventoryResponse, int, error)
|
||||
AdjustInventory(ctx context.Context, productID, outletID uuid.UUID, req *models.InventoryAdjustmentRequest) (*models.InventoryResponse, error)
|
||||
GetLowStockItems(ctx context.Context, outletID uuid.UUID) ([]models.InventoryResponse, error)
|
||||
GetZeroStockItems(ctx context.Context, outletID uuid.UUID) ([]models.InventoryResponse, error)
|
||||
}
|
||||
|
||||
type InventoryRepository interface {
|
||||
Create(ctx context.Context, inventory *entities.Inventory) error
|
||||
GetByID(ctx context.Context, id uuid.UUID) (*entities.Inventory, error)
|
||||
GetWithRelations(ctx context.Context, id uuid.UUID) (*entities.Inventory, error)
|
||||
GetByProductAndOutlet(ctx context.Context, productID, outletID uuid.UUID) (*entities.Inventory, error)
|
||||
GetByOutlet(ctx context.Context, outletID uuid.UUID) ([]*entities.Inventory, error)
|
||||
GetByProduct(ctx context.Context, productID uuid.UUID) ([]*entities.Inventory, error)
|
||||
GetLowStock(ctx context.Context, outletID uuid.UUID) ([]*entities.Inventory, error)
|
||||
GetZeroStock(ctx context.Context, outletID uuid.UUID) ([]*entities.Inventory, error)
|
||||
Update(ctx context.Context, inventory *entities.Inventory) error
|
||||
Delete(ctx context.Context, id uuid.UUID) error
|
||||
List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.Inventory, int64, error)
|
||||
Count(ctx context.Context, filters map[string]interface{}) (int64, error)
|
||||
AdjustQuantity(ctx context.Context, productID, outletID uuid.UUID, delta int) (*entities.Inventory, error)
|
||||
SetQuantity(ctx context.Context, productID, outletID uuid.UUID, quantity int) (*entities.Inventory, error)
|
||||
UpdateReorderLevel(ctx context.Context, id uuid.UUID, reorderLevel int) error
|
||||
BulkCreate(ctx context.Context, inventoryItems []*entities.Inventory) error
|
||||
BulkAdjustQuantity(ctx context.Context, adjustments map[uuid.UUID]int, outletID uuid.UUID) error
|
||||
GetTotalValueByOutlet(ctx context.Context, outletID uuid.UUID) (float64, error)
|
||||
}
|
||||
|
||||
type InventoryProcessorImpl struct {
|
||||
inventoryRepo InventoryRepository
|
||||
productRepo ProductRepository
|
||||
outletRepo OutletRepository
|
||||
}
|
||||
|
||||
func NewInventoryProcessorImpl(
|
||||
inventoryRepo InventoryRepository,
|
||||
productRepo ProductRepository,
|
||||
outletRepo OutletRepository,
|
||||
) *InventoryProcessorImpl {
|
||||
return &InventoryProcessorImpl{
|
||||
inventoryRepo: inventoryRepo,
|
||||
productRepo: productRepo,
|
||||
outletRepo: outletRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) CreateInventory(ctx context.Context, req *models.CreateInventoryRequest) (*models.InventoryResponse, error) {
|
||||
_, err := p.productRepo.GetByID(ctx, req.ProductID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid product: %w", err)
|
||||
}
|
||||
|
||||
// Validate outlet exists
|
||||
_, err = p.outletRepo.GetByID(ctx, req.OutletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid outlet: %w", err)
|
||||
}
|
||||
|
||||
// Check if inventory already exists for this product-outlet combination
|
||||
existingInventory, err := p.inventoryRepo.GetByProductAndOutlet(ctx, req.ProductID, req.OutletID)
|
||||
if err == nil && existingInventory != nil {
|
||||
return nil, fmt.Errorf("inventory already exists for product %s in outlet %s", req.ProductID, req.OutletID)
|
||||
}
|
||||
|
||||
// Map request to entity
|
||||
inventoryEntity := mappers.CreateInventoryRequestToEntity(req)
|
||||
|
||||
// Create inventory
|
||||
if err := p.inventoryRepo.Create(ctx, inventoryEntity); err != nil {
|
||||
return nil, fmt.Errorf("failed to create inventory: %w", err)
|
||||
}
|
||||
|
||||
// Get inventory with relations for response
|
||||
inventoryWithRelations, err := p.inventoryRepo.GetWithRelations(ctx, inventoryEntity.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve created inventory: %w", err)
|
||||
}
|
||||
|
||||
// Map entity to response model
|
||||
response := mappers.InventoryEntityToResponse(inventoryWithRelations)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) UpdateInventory(ctx context.Context, id uuid.UUID, req *models.UpdateInventoryRequest) (*models.InventoryResponse, error) {
|
||||
// Get existing inventory
|
||||
existingInventory, err := p.inventoryRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("inventory not found: %w", err)
|
||||
}
|
||||
|
||||
// Apply updates to entity
|
||||
mappers.UpdateInventoryEntityFromRequest(existingInventory, req)
|
||||
|
||||
// Update inventory
|
||||
if err := p.inventoryRepo.Update(ctx, existingInventory); err != nil {
|
||||
return nil, fmt.Errorf("failed to update inventory: %w", err)
|
||||
}
|
||||
|
||||
// Get updated inventory with relations for response
|
||||
inventoryWithRelations, err := p.inventoryRepo.GetWithRelations(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve updated inventory: %w", err)
|
||||
}
|
||||
|
||||
// Map entity to response model
|
||||
response := mappers.InventoryEntityToResponse(inventoryWithRelations)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) DeleteInventory(ctx context.Context, id uuid.UUID) error {
|
||||
// Check if inventory exists
|
||||
_, err := p.inventoryRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("inventory not found: %w", err)
|
||||
}
|
||||
|
||||
// Delete inventory
|
||||
if err := p.inventoryRepo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete inventory: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) GetInventoryByID(ctx context.Context, id uuid.UUID) (*models.InventoryResponse, error) {
|
||||
inventoryEntity, err := p.inventoryRepo.GetWithRelations(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("inventory not found: %w", err)
|
||||
}
|
||||
|
||||
response := mappers.InventoryEntityToResponse(inventoryEntity)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) ListInventory(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.InventoryResponse, int, error) {
|
||||
offset := (page - 1) * limit
|
||||
|
||||
inventoryEntities, total, err := p.inventoryRepo.List(ctx, filters, limit, offset)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list inventory: %w", err)
|
||||
}
|
||||
|
||||
responses := make([]models.InventoryResponse, len(inventoryEntities))
|
||||
for i, entity := range inventoryEntities {
|
||||
response := mappers.InventoryEntityToResponse(entity)
|
||||
if response != nil {
|
||||
responses[i] = *response
|
||||
}
|
||||
}
|
||||
|
||||
return responses, int(total), nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) AdjustInventory(ctx context.Context, productID, outletID uuid.UUID, req *models.InventoryAdjustmentRequest) (*models.InventoryResponse, error) {
|
||||
// Validate product exists
|
||||
_, err := p.productRepo.GetByID(ctx, productID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid product: %w", err)
|
||||
}
|
||||
|
||||
// Validate outlet exists
|
||||
_, err = p.outletRepo.GetByID(ctx, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid outlet: %w", err)
|
||||
}
|
||||
|
||||
// Perform quantity adjustment
|
||||
adjustedInventory, err := p.inventoryRepo.AdjustQuantity(ctx, productID, outletID, req.Delta)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to adjust inventory quantity: %w", err)
|
||||
}
|
||||
|
||||
// Get inventory with relations for response
|
||||
inventoryWithRelations, err := p.inventoryRepo.GetWithRelations(ctx, adjustedInventory.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve adjusted inventory: %w", err)
|
||||
}
|
||||
|
||||
// Map entity to response model
|
||||
response := mappers.InventoryEntityToResponse(inventoryWithRelations)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) GetLowStockItems(ctx context.Context, outletID uuid.UUID) ([]models.InventoryResponse, error) {
|
||||
// Validate outlet exists
|
||||
_, err := p.outletRepo.GetByID(ctx, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid outlet: %w", err)
|
||||
}
|
||||
|
||||
inventoryEntities, err := p.inventoryRepo.GetLowStock(ctx, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get low stock items: %w", err)
|
||||
}
|
||||
|
||||
responses := make([]models.InventoryResponse, len(inventoryEntities))
|
||||
for i, entity := range inventoryEntities {
|
||||
response := mappers.InventoryEntityToResponse(entity)
|
||||
if response != nil {
|
||||
responses[i] = *response
|
||||
}
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func (p *InventoryProcessorImpl) GetZeroStockItems(ctx context.Context, outletID uuid.UUID) ([]models.InventoryResponse, error) {
|
||||
// Validate outlet exists
|
||||
_, err := p.outletRepo.GetByID(ctx, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid outlet: %w", err)
|
||||
}
|
||||
|
||||
inventoryEntities, err := p.inventoryRepo.GetZeroStock(ctx, outletID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get zero stock items: %w", err)
|
||||
}
|
||||
|
||||
responses := make([]models.InventoryResponse, len(inventoryEntities))
|
||||
for i, entity := range inventoryEntities {
|
||||
response := mappers.InventoryEntityToResponse(entity)
|
||||
if response != nil {
|
||||
responses[i] = *response
|
||||
}
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
Reference in New Issue
Block a user