From 923cbaba6a6458dc4fbeda8886814adea2ab7efb Mon Sep 17 00:00:00 2001 From: Habib Fatkhul Rohman Date: Mon, 8 Dec 2025 15:08:21 +0700 Subject: [PATCH] feat: add current stock tracking to inventory request line responses and implement GetNewestByProductId in inventory storage --- .../dto/inventory_request_dto.go | 21 ++++---- .../service/inventory_request_service.go | 50 ++++++++++++++----- .../inventory_storage_repository.go | 21 ++++++++ .../service/inventory_storage_service.go | 10 ++++ providers/core.go | 8 +-- 5 files changed, 83 insertions(+), 27 deletions(-) diff --git a/modules/inventory_request/dto/inventory_request_dto.go b/modules/inventory_request/dto/inventory_request_dto.go index 314596d..c8e8303 100644 --- a/modules/inventory_request/dto/inventory_request_dto.go +++ b/modules/inventory_request/dto/inventory_request_dto.go @@ -172,7 +172,7 @@ func ToInventoryRequestResponse(e entities.TInventoryRequestEntity) InventoryReq } } -func ToInventoryRequestLineResponse(e entities.TInventoryRequestLineEntity) InventoryRequestLineResponse { +func ToInventoryRequestLineResponse(e entities.TInventoryRequestLineEntity, currentStock float64) InventoryRequestLineResponse { product := InventoryRequestLineProductResponse{} if e.Product.ID != uuid.Nil { product = InventoryRequestLineProductResponse{ @@ -186,11 +186,11 @@ func ToInventoryRequestLineResponse(e entities.TInventoryRequestLineEntity) Inve } } return InventoryRequestLineResponse{ - ID: e.ID.String(), - Quantity: e.Quantity, - // CurrentStock: e.CurrentStock, - Product: product, - ClientID: e.ClientID.String(), + ID: e.ID.String(), + Quantity: e.Quantity, + CurrentStock: currentStock, + Product: product, + ClientID: e.ClientID.String(), } } @@ -210,10 +210,11 @@ func ToInventoryRequestLineResponses(linesEntity []entities.TInventoryRequestLin } } lines = append(lines, InventoryRequestLineResponse{ - ID: line.ID.String(), - Quantity: line.Quantity, - Product: product, - ClientID: line.ClientID.String(), + ID: line.ID.String(), + Quantity: line.Quantity, + Product: product, + CurrentStock: 0, + ClientID: line.ClientID.String(), }) } return lines diff --git a/modules/inventory_request/service/inventory_request_service.go b/modules/inventory_request/service/inventory_request_service.go index 1c6595a..c452402 100644 --- a/modules/inventory_request/service/inventory_request_service.go +++ b/modules/inventory_request/service/inventory_request_service.go @@ -7,6 +7,7 @@ import ( dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/query" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/repository" + invstorageservice "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_storage/service" sequenceservice "github.com/Caknoooo/go-gin-clean-starter/modules/sequence/service" "github.com/Caknoooo/go-gin-clean-starter/pkg/constants" pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" @@ -30,11 +31,12 @@ type InventoryRequestService interface { } type inventoryRequestService struct { - db *gorm.DB - requestRepo repository.InventoryRequestRepository - requestLineRepo repository.InventoryRequestLineRepository - sequenceService sequenceservice.SequenceService - log *logrus.Logger + db *gorm.DB + requestRepo repository.InventoryRequestRepository + requestLineRepo repository.InventoryRequestLineRepository + invStorageService invstorageservice.InventoryStorageService + sequenceService sequenceservice.SequenceService + log *logrus.Logger } // GetLineById implements InventoryRequestService. @@ -43,7 +45,17 @@ func (s *inventoryRequestService) GetLineById(ctx context.Context, lineId string if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } - return dtodomain.ToInventoryRequestLineResponse(line), nil + + var currentStock float64 + if line.ProductID != uuid.Nil { + storage, err := s.invStorageService.GetNewestByProductId(ctx, line.ProductID.String()) + if err != nil { + return dtodomain.InventoryRequestLineResponse{}, err + } + currentStock = storage.AvailableQuantity + } + + return dtodomain.ToInventoryRequestLineResponse(line, currentStock), nil } // GetLinesByRequestId implements InventoryRequestService. @@ -52,7 +64,18 @@ func (s *inventoryRequestService) GetLinesByRequestId(ctx context.Context, reque if err != nil { return nil, err } - return dtodomain.ToInventoryRequestLineResponses(lines), nil + responses := make([]dtodomain.InventoryRequestLineResponse, 0) + for _, line := range lines { + var currentStock float64 + if line.ProductID != uuid.Nil { + storage, err := s.invStorageService.GetNewestByProductId(ctx, line.ProductID.String()) + if err == nil { + currentStock = storage.AvailableQuantity + } + } + responses = append(responses, dtodomain.ToInventoryRequestLineResponse(line, currentStock)) + } + return responses, nil } func (s *inventoryRequestService) DeleteLine(ctx context.Context, lineId string) error { @@ -376,12 +399,13 @@ func (s *inventoryRequestService) CreateLine(ctx context.Context, requestId stri }, nil } -func NewInventoryRequestService(db *gorm.DB, requestRepo repository.InventoryRequestRepository, requestLineRepo repository.InventoryRequestLineRepository, sequenceService sequenceservice.SequenceService, log *logrus.Logger) InventoryRequestService { +func NewInventoryRequestService(db *gorm.DB, requestRepo repository.InventoryRequestRepository, requestLineRepo repository.InventoryRequestLineRepository, invStorageService invstorageservice.InventoryStorageService, sequenceService sequenceservice.SequenceService, log *logrus.Logger) InventoryRequestService { return &inventoryRequestService{ - db: db, - requestRepo: requestRepo, - requestLineRepo: requestLineRepo, - sequenceService: sequenceService, - log: log, + db: db, + requestRepo: requestRepo, + requestLineRepo: requestLineRepo, + invStorageService: invStorageService, + sequenceService: sequenceService, + log: log, } } diff --git a/modules/inventory_storage/repository/inventory_storage_repository.go b/modules/inventory_storage/repository/inventory_storage_repository.go index 80e5c6b..be7ec7d 100644 --- a/modules/inventory_storage/repository/inventory_storage_repository.go +++ b/modules/inventory_storage/repository/inventory_storage_repository.go @@ -18,12 +18,33 @@ type InventoryStorageRepository interface { BulkCreate(ctx context.Context, tx *gorm.DB, inventoryStorages []entities.InventoryStorageEntity) error GetLatestByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId string) (entities.InventoryStorageEntity, error) GetStoragesByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId string) ([]entities.InventoryStorageEntity, error) + GetNewestByProductId(ctx context.Context, tx *gorm.DB, productId string) (entities.InventoryStorageEntity, error) } type inventoryStorageRepository struct { db *gorm.DB } +// GetNewestByProductId implements InventoryStorageRepository. +func (r *inventoryStorageRepository) GetNewestByProductId(ctx context.Context, tx *gorm.DB, productId string) (entities.InventoryStorageEntity, error) { + if tx == nil { + tx = r.db + } + var inventoryStorage entities.InventoryStorageEntity + if err := tx.WithContext(ctx). + Preload("Product"). + Preload("Aisle"). + Preload("Uom"). + Preload("Client"). + // Preload("InvRequest"). + // Preload("InvReceipt"). + Order("created_at DESC"). + First(&inventoryStorage, "product_id = ?", productId).Error; err != nil { + return inventoryStorage, err + } + return inventoryStorage, nil +} + // GetStoragesByProductAndClient implements InventoryStorageRepository. func (r *inventoryStorageRepository) GetStoragesByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId string) ([]entities.InventoryStorageEntity, error) { if tx == nil { diff --git a/modules/inventory_storage/service/inventory_storage_service.go b/modules/inventory_storage/service/inventory_storage_service.go index 57b015e..19afd97 100644 --- a/modules/inventory_storage/service/inventory_storage_service.go +++ b/modules/inventory_storage/service/inventory_storage_service.go @@ -20,6 +20,7 @@ type InventoryStorageService interface { GetAll(ctx context.Context, filter query.InventoryStorageFilter) ([]dtodomain.InventoryStorageResponse, int64, error) Update(ctx context.Context, req dtodomain.InventoryStorageUpdateRequest, inventoryStorageId string) (dtodomain.InventoryStorageResponse, error) Delete(ctx context.Context, inventoryStorageId string) error + GetNewestByProductId(ctx context.Context, productId string) (dtodomain.InventoryStorageResponse, error) } type inventoryStorageService struct { @@ -28,6 +29,15 @@ type inventoryStorageService struct { log *logrus.Logger } +// GetNewestByProductId implements InventoryStorageService. +func (s *inventoryStorageService) GetNewestByProductId(ctx context.Context, productId string) (dtodomain.InventoryStorageResponse, error) { + inventoryStorage, err := s.inventoryStorageRepo.GetNewestByProductId(ctx, nil, productId) + if err != nil { + return dtodomain.InventoryStorageResponse{}, err + } + return dtodomain.ToInventoryStorageResponse(inventoryStorage), nil +} + func (s *inventoryStorageService) Create(ctx context.Context, req dtodomain.InventoryStorageCreateRequest) (dtodomain.InventoryStorageResponse, error) { tx := s.db.Begin() defer func() { diff --git a/providers/core.go b/providers/core.go index 81dd0d4..0d31146 100644 --- a/providers/core.go +++ b/providers/core.go @@ -187,14 +187,14 @@ func RegisterDependencies(injector *do.Injector) { warehouseServ := warehouseService.NewWarehouseService(warehouseRepository, db, log) zonaServ := zonaService.NewZonaService(zonaRepository, db, log) aisleServ := aisleService.NewAisleService(aisleRepository, db, log) + inventoryStorageServ := inventoryStorageService.NewInventoryStorageService(db, inventoryStorageRepository, log) + inventoryTransactionServ := inventoryTransactionService.NewInventoryTransactionService(db, inventoryTransactionRepository, log) inventoryReceiptServ := inventoryReceiptService.NewInventoryReceiptService(db, inventoryReceiptRepository, inventoryReceiptLineRepository, productRepository, uomRepository, inventoryStorageRepository, sequenceServ, log) assignmentServ := assignmentService.NewAssignmentService(db, assignmentRepository, assignmentUserRepository) - inventoryRequestServ := inventoryRequestService.NewInventoryRequestService(db, inventoryRequestRepository, inventoryRequestLineRepository, sequenceServ, log) + inventoryRequestServ := inventoryRequestService.NewInventoryRequestService(db, inventoryRequestRepository, inventoryRequestLineRepository, inventoryStorageServ, sequenceServ, log) inventoryIssueServ := inventoryIssueService.NewInventoryIssueService(db, inventoryIssueRepository, inventoryIssueLineRepository, sequenceServ, log) inventoryReturnServ := inventoryReturnService.NewInventoryReturnService(db, inventoryReturnRepository, inventoryReturnLineRepository, inventoryIssueLineRepository, productRepository, sequenceServ, log) inventoryMovementServ := inventoryMovementService.NewInventoryMovementService(db, inventoryMovementRepository, inventoryMovementLineRepository, sequenceServ, log) - inventoryStorageService := inventoryStorageService.NewInventoryStorageService(db, inventoryStorageRepository, log) - inventoryTransactionServ := inventoryTransactionService.NewInventoryTransactionService(db, inventoryTransactionRepository, log) quarantineServ := quarantineService.NewQuarantineService(db, quarantineRepository, quarantineLineRepository, productRepository, uomRepository, inventoryStorageRepository) // Controller @@ -305,7 +305,7 @@ func RegisterDependencies(injector *do.Injector) { ) do.Provide( injector, func(i *do.Injector) (inventoryStorageController.InventoryStorageController, error) { - return inventoryStorageController.NewInventoryStorageController(i, inventoryStorageService), nil + return inventoryStorageController.NewInventoryStorageController(i, inventoryStorageServ), nil }, ) do.Provide(