feat: Add OnComplete functionality to Inventory Receipt

- Implemented OnComplete method in InventoryReceiptController to handle completion of inventory receipts.
- Added success and failure messages in dto for completing inventory receipts.
- Updated routes to include the new OnComplete endpoint.
- Enhanced InventoryReceiptService to manage the completion logic, including updating inventory storage.
- Introduced new methods in InventoryStorageRepository for bulk creation and retrieval of inventory storages.
- Added methods in ProductService to fetch inventory storages and transactions by product and client.
- Updated ProductController to handle new endpoints for inventory storages and transactions.
- Enhanced Product DTO to include inventory storage and transaction responses.
- Refactored ProductRepository to retrieve cross-references and preloaded relationships for inventory storages and transactions.
- Updated core dependency injection to include new repositories and services.
This commit is contained in:
Habib Fatkhul Rohman 2025-11-25 15:57:08 +07:00
parent e22c76abe3
commit 2ef6052a2c
16 changed files with 521 additions and 159 deletions

View File

@ -22,6 +22,7 @@ type InventoryReceiptController interface {
CreateLine(ctx *gin.Context) CreateLine(ctx *gin.Context)
UpdateLine(ctx *gin.Context) UpdateLine(ctx *gin.Context)
DeleteLine(ctx *gin.Context) DeleteLine(ctx *gin.Context)
OnComplete(ctx *gin.Context)
} }
type inventoryReceiptController struct { type inventoryReceiptController struct {
@ -29,6 +30,19 @@ type inventoryReceiptController struct {
db *gorm.DB db *gorm.DB
} }
// OnComplete implements InventoryReceiptController.
func (c *inventoryReceiptController) OnComplete(ctx *gin.Context) {
id := ctx.Param("id")
updated, err := c.receiptService.OnComplete(ctx, id)
if err != nil {
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_COMPLETE_INVENTORY_RECEIPT, err.Error(), nil)
ctx.JSON(http.StatusInternalServerError, res)
return
}
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_COMPLETE_INVENTORY_RECEIPT, updated)
ctx.JSON(http.StatusOK, res)
}
// DeleteLine implements InventoryReceiptController. // DeleteLine implements InventoryReceiptController.
func (c *inventoryReceiptController) DeleteLine(ctx *gin.Context) { func (c *inventoryReceiptController) DeleteLine(ctx *gin.Context) {
id := ctx.Param("id") id := ctx.Param("id")

View File

@ -18,6 +18,8 @@ const (
MESSAGE_SUCCESS_DELETE_INVENTORY_RECEIPT = "success delete inventory receipt" MESSAGE_SUCCESS_DELETE_INVENTORY_RECEIPT = "success delete inventory receipt"
MESSAGE_SUCCESS_DELETE_INVENTORY_RECEIPT_LINE = "success delete inventory receipt line" MESSAGE_SUCCESS_DELETE_INVENTORY_RECEIPT_LINE = "success delete inventory receipt line"
MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body" MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body"
MESSAGE_SUCCESS_COMPLETE_INVENTORY_RECEIPT = "success complete inventory receipt"
MESSAGE_FAILED_COMPLETE_INVENTORY_RECEIPT = "failed complete inventory receipt"
) )
type InventoryReceiptCreateRequest struct { type InventoryReceiptCreateRequest struct {
@ -34,10 +36,10 @@ type InventoryReceiptLineCreateRequest struct {
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
BatchNumber string `json:"batch_number"` BatchNumber string `json:"batch_number"`
RepackingSuggestion string `json:"repacking_suggestion"` RepackingSuggestion string `json:"repacking_suggestion"`
RepackUomID string `json:"repack_uom_id"` RepackUomID string `json:"repack_uom_id"`
RepackUomCode string `json:"repack_uom_code"` RepackUomCode string `json:"repack_uom_code"`
ProductID string `json:"product_id"` ProductID string `json:"product_id"`
ProductCode string `json:"product_code"` ProductCode string `json:"product_code"`
ClientID string `json:"client_id"` ClientID string `json:"client_id"`
} }

View File

@ -23,5 +23,6 @@ func RegisterRoutes(server *gin.Engine, injector *do.Injector) {
receiptRoutes.POST(":id/lines", middlewares.Authenticate(jwtService), receiptController.CreateLine) receiptRoutes.POST(":id/lines", middlewares.Authenticate(jwtService), receiptController.CreateLine)
receiptRoutes.PUT("lines/:id", middlewares.Authenticate(jwtService), receiptController.UpdateLine) receiptRoutes.PUT("lines/:id", middlewares.Authenticate(jwtService), receiptController.UpdateLine)
receiptRoutes.DELETE("lines/:id", middlewares.Authenticate(jwtService), receiptController.DeleteLine) receiptRoutes.DELETE("lines/:id", middlewares.Authenticate(jwtService), receiptController.DeleteLine)
receiptRoutes.POST(":id/complete", middlewares.Authenticate(jwtService), receiptController.OnComplete)
} }
} }

View File

@ -2,13 +2,16 @@ package service
import ( import (
"context" "context"
"errors"
"github.com/Caknoooo/go-gin-clean-starter/database/entities" "github.com/Caknoooo/go-gin-clean-starter/database/entities"
dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/dto" dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/dto"
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/query" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/query"
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/repository" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/repository"
invstoragerepository "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_storage/repository"
productrepository "github.com/Caknoooo/go-gin-clean-starter/modules/product/repository" productrepository "github.com/Caknoooo/go-gin-clean-starter/modules/product/repository"
uomrepository "github.com/Caknoooo/go-gin-clean-starter/modules/uom/repository" uomrepository "github.com/Caknoooo/go-gin-clean-starter/modules/uom/repository"
"github.com/Caknoooo/go-gin-clean-starter/pkg/constants"
pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto"
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils" "github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
"github.com/google/uuid" "github.com/google/uuid"
@ -24,14 +27,75 @@ type InventoryReceiptService interface {
CreateLine(ctx context.Context, receiptId string, req dtodomain.InventoryReceiptLineCreateRequest) (dtodomain.InventoryReceiptLineResponse, error) CreateLine(ctx context.Context, receiptId string, req dtodomain.InventoryReceiptLineCreateRequest) (dtodomain.InventoryReceiptLineResponse, error)
UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryReceiptLineUpdateRequest) (dtodomain.InventoryReceiptLineResponse, error) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryReceiptLineUpdateRequest) (dtodomain.InventoryReceiptLineResponse, error)
DeleteLine(ctx context.Context, lineId string) error DeleteLine(ctx context.Context, lineId string) error
OnComplete(ctx context.Context, id string) (dtodomain.InventoryReceiptResponse, error)
} }
type inventoryReceiptService struct { type inventoryReceiptService struct {
db *gorm.DB db *gorm.DB
receiptRepo repository.InventoryReceiptRepository receiptRepo repository.InventoryReceiptRepository
receiptLineRepo repository.InventoryReceiptLineRepository receiptLineRepo repository.InventoryReceiptLineRepository
productRepo productrepository.ProductRepository productRepo productrepository.ProductRepository
uomRepo uomrepository.UomRepository uomRepo uomrepository.UomRepository
invStorageRepository invstoragerepository.InventoryStorageRepository
}
func (s *inventoryReceiptService) OnComplete(ctx context.Context, id string) (dtodomain.InventoryReceiptResponse, error) {
tx := s.db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
receipt, err := s.receiptRepo.GetById(ctx, tx, id)
if err != nil {
tx.Rollback()
return dtodomain.InventoryReceiptResponse{}, err
}
receipt.Status = constants.COMPLETED
for _, line := range receipt.ReceiptLines {
product, err := s.productRepo.GetById(ctx, tx, line.ProductID.String())
if err != nil {
tx.Rollback()
return dtodomain.InventoryReceiptResponse{}, err
}
existing, err := s.invStorageRepository.GetByProductAndClient(ctx, tx, product.ID.String(), receipt.ClientID.String())
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
tx.Rollback()
return dtodomain.InventoryReceiptResponse{}, err
}
if existing.ID != uuid.Nil {
existing.OnHandQuantity += line.Quantity
existing.AvailableQuantity += line.Quantity
_, err = s.invStorageRepository.Update(ctx, tx, existing)
if err != nil {
tx.Rollback()
return dtodomain.InventoryReceiptResponse{}, err
}
} else {
newStorage := entities.InventoryStorageEntity{
ProductID: line.ProductID,
UomID: *product.UomID,
OnHandQuantity: line.Quantity,
AvailableQuantity: line.Quantity,
InvReceiptID: receipt.ID,
ClientID: receipt.ClientID,
}
_, err = s.invStorageRepository.Create(ctx, tx, newStorage)
if err != nil {
tx.Rollback()
return dtodomain.InventoryReceiptResponse{}, err
}
}
}
if _, err := s.receiptRepo.Update(ctx, tx, receipt); err != nil {
tx.Rollback()
return dtodomain.InventoryReceiptResponse{}, err
}
tx.Commit()
return toInventoryReceiptResponse(receipt), nil
} }
// DeleteLine implements InventoryReceiptService. // DeleteLine implements InventoryReceiptService.
@ -235,6 +299,7 @@ func (s *inventoryReceiptService) Create(ctx context.Context, req dtodomain.Inve
} }
// Bulk create lines // Bulk create lines
var lines []entities.TInventoryReceiptLineEntity var lines []entities.TInventoryReceiptLineEntity
// var invStorages []entities.InventoryStorageEntity
for _, lineReq := range req.ReceiptLines { for _, lineReq := range req.ReceiptLines {
var productUUID uuid.UUID var productUUID uuid.UUID
if lineReq.ProductID != "" { if lineReq.ProductID != "" {
@ -285,6 +350,21 @@ func (s *inventoryReceiptService) Create(ctx context.Context, req dtodomain.Inve
ProductID: productUUID, ProductID: productUUID,
ClientID: clientLineUUID, ClientID: clientLineUUID,
}) })
// // Prepare inventory storage entity
// product, err := s.productRepo.GetById(ctx, tx, productUUID.String())
// if err != nil {
// tx.Rollback()
// return dtodomain.InventoryReceiptResponse{}, err
// }
// invStorages = append(invStorages, entities.InventoryStorageEntity{
// ProductID: productUUID,
// UomID: *product.UomID,
// OnHandQuantity: 0,
// AvailableQuantity: 0,
// InvReceiptID: created.ID,
// ClientID: clientUUID,
// })
} }
if len(lines) > 0 { if len(lines) > 0 {
err = s.receiptLineRepo.BulkCreate(ctx, tx, lines) err = s.receiptLineRepo.BulkCreate(ctx, tx, lines)
@ -293,6 +373,13 @@ func (s *inventoryReceiptService) Create(ctx context.Context, req dtodomain.Inve
return dtodomain.InventoryReceiptResponse{}, err return dtodomain.InventoryReceiptResponse{}, err
} }
} }
// if len(invStorages) > 0 {
// err = s.invStorageRepository.BulkCreate(ctx, tx, invStorages)
// if err != nil {
// tx.Rollback()
// return dtodomain.InventoryReceiptResponse{}, err
// }
// }
tx.Commit() tx.Commit()
result, err := s.receiptRepo.GetById(ctx, nil, created.ID.String()) result, err := s.receiptRepo.GetById(ctx, nil, created.ID.String())
if err != nil { if err != nil {
@ -453,12 +540,14 @@ func NewInventoryReceiptService(db *gorm.DB,
receiptRepo repository.InventoryReceiptRepository, receiptRepo repository.InventoryReceiptRepository,
receiptLineRepo repository.InventoryReceiptLineRepository, receiptLineRepo repository.InventoryReceiptLineRepository,
productRepo productrepository.ProductRepository, productRepo productrepository.ProductRepository,
uomRepo uomrepository.UomRepository) InventoryReceiptService { uomRepo uomrepository.UomRepository,
invStorageRepository invstoragerepository.InventoryStorageRepository) InventoryReceiptService {
return &inventoryReceiptService{ return &inventoryReceiptService{
db: db, db: db,
receiptRepo: receiptRepo, receiptRepo: receiptRepo,
receiptLineRepo: receiptLineRepo, receiptLineRepo: receiptLineRepo,
productRepo: productRepo, productRepo: productRepo,
uomRepo: uomRepo, uomRepo: uomRepo,
invStorageRepository: invStorageRepository,
} }
} }

View File

@ -75,10 +75,11 @@ type AssignmentUserResponse struct {
} }
type InventoryRequestLineResponse struct { type InventoryRequestLineResponse struct {
ID string `json:"id"` ID string `json:"id"`
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
Product InventoryRequestLineProductResponse `json:"product"` CurrentStock float64 `json:"current_stock"`
ClientID string `json:"client_id"` Product InventoryRequestLineProductResponse `json:"product"`
ClientID string `json:"client_id"`
} }
type InventoryRequestLineProductResponse struct { type InventoryRequestLineProductResponse struct {

View File

@ -121,6 +121,7 @@ func toInventoryRequestResponse(e entities.TInventoryRequestEntity) dtodomain.In
lines = append(lines, dtodomain.InventoryRequestLineResponse{ lines = append(lines, dtodomain.InventoryRequestLineResponse{
ID: line.ID.String(), ID: line.ID.String(),
Quantity: line.Quantity, Quantity: line.Quantity,
// CurrentStock: line.Product.CurrentStock,
Product: product, Product: product,
ClientID: line.ClientID.String(), ClientID: line.ClientID.String(),
}) })

View File

@ -33,8 +33,8 @@ type InventoryStorageCreateRequest struct {
ClientID string `json:"client_id" binding:"required"` ClientID string `json:"client_id" binding:"required"`
OnHandQuantity float64 `json:"on_hand_quantity"` OnHandQuantity float64 `json:"on_hand_quantity"`
AvailableQuantity float64 `json:"available_quantity"` AvailableQuantity float64 `json:"available_quantity"`
InvRequestID string `json:"inv_request_id"` InvRequestID *string `json:"inv_request_id"`
InvReceiptID string `json:"inv_receipt_id"` InvReceiptID *string `json:"inv_receipt_id"`
} }
type InventoryStorageUpdateRequest struct { type InventoryStorageUpdateRequest struct {

View File

@ -6,6 +6,7 @@ import (
"github.com/Caknoooo/go-gin-clean-starter/database/entities" "github.com/Caknoooo/go-gin-clean-starter/database/entities"
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_storage/query" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_storage/query"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause"
) )
type InventoryStorageRepository interface { type InventoryStorageRepository interface {
@ -14,12 +15,66 @@ type InventoryStorageRepository interface {
GetAll(ctx context.Context, filter query.InventoryStorageFilter) ([]entities.InventoryStorageEntity, int64, error) GetAll(ctx context.Context, filter query.InventoryStorageFilter) ([]entities.InventoryStorageEntity, int64, error)
Update(ctx context.Context, tx *gorm.DB, inventoryStorage entities.InventoryStorageEntity) (entities.InventoryStorageEntity, error) Update(ctx context.Context, tx *gorm.DB, inventoryStorage entities.InventoryStorageEntity) (entities.InventoryStorageEntity, error)
Delete(ctx context.Context, tx *gorm.DB, inventoryStorageId string) error Delete(ctx context.Context, tx *gorm.DB, inventoryStorageId string) error
BulkCreate(ctx context.Context, tx *gorm.DB, inventoryStorages []entities.InventoryStorageEntity) error
GetByProductAndClient(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)
} }
type inventoryStorageRepository struct { type inventoryStorageRepository struct {
db *gorm.DB db *gorm.DB
} }
// GetStoragesByProductAndClient implements InventoryStorageRepository.
func (r *inventoryStorageRepository) GetStoragesByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId string) ([]entities.InventoryStorageEntity, error) {
if tx == nil {
tx = r.db
}
var inventoryStorages []entities.InventoryStorageEntity
if err := tx.WithContext(ctx).
Preload("Product").
Preload("Aisle").
Preload("Uom").
Preload("Client").
Preload("InvRequest").
Preload("InvReceipt").
Where("product_id = ? AND client_id = ?", productId, clientId).
Find(&inventoryStorages).Error; err != nil {
return nil, err
}
return inventoryStorages, nil
}
// GetByProductAndClient implements InventoryStorageRepository.
func (r *inventoryStorageRepository) GetByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId 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 = ? AND client_id = ?", productId, clientId).Error; err != nil {
return inventoryStorage, err
}
return inventoryStorage, nil
}
// BulkCreate implements InventoryStorageRepository.
func (r *inventoryStorageRepository) BulkCreate(ctx context.Context, tx *gorm.DB, inventoryStorages []entities.InventoryStorageEntity) error {
if tx == nil {
tx = r.db
}
if err := tx.WithContext(ctx).Clauses(clause.OnConflict{DoNothing: true}).Create(&inventoryStorages).Error; err != nil {
return err
}
return nil
}
func NewInventoryStorageRepository(db *gorm.DB) InventoryStorageRepository { func NewInventoryStorageRepository(db *gorm.DB) InventoryStorageRepository {
return &inventoryStorageRepository{db: db} return &inventoryStorageRepository{db: db}
} }

View File

@ -51,16 +51,26 @@ func (s *inventoryStorageService) Create(ctx context.Context, req dtodomain.Inve
tx.Rollback() tx.Rollback()
return dtodomain.InventoryStorageResponse{}, err return dtodomain.InventoryStorageResponse{}, err
} }
InvRequestID, err := uuid.Parse(req.InvRequestID) var InvRequestID, InvReceiptID uuid.UUID
if err != nil { if req.InvRequestID != nil && *req.InvRequestID != "" {
tx.Rollback() InvRequestID, err = uuid.Parse(*req.InvRequestID)
return dtodomain.InventoryStorageResponse{}, err if err != nil {
tx.Rollback()
return dtodomain.InventoryStorageResponse{}, err
}
} else {
InvRequestID = uuid.Nil
} }
InvReceiptID, err := uuid.Parse(req.InvReceiptID) if req.InvReceiptID != nil && *req.InvReceiptID != "" {
if err != nil { InvReceiptID, err = uuid.Parse(*req.InvReceiptID)
tx.Rollback() if err != nil {
return dtodomain.InventoryStorageResponse{}, err tx.Rollback()
return dtodomain.InventoryStorageResponse{}, err
}
} else {
InvReceiptID = uuid.Nil
} }
inventoryStorage := entities.InventoryStorageEntity{ inventoryStorage := entities.InventoryStorageEntity{
ProductID: productID, ProductID: productID,
AisleID: aisleID, AisleID: aisleID,

View File

@ -14,12 +14,33 @@ type InventoryTransactionRepository interface {
GetAll(ctx context.Context, filter query.InventoryTransactionFilter) ([]entities.InventoryTransactionEntity, int64, error) GetAll(ctx context.Context, filter query.InventoryTransactionFilter) ([]entities.InventoryTransactionEntity, int64, error)
Update(ctx context.Context, tx *gorm.DB, inventoryTransaction entities.InventoryTransactionEntity) (entities.InventoryTransactionEntity, error) Update(ctx context.Context, tx *gorm.DB, inventoryTransaction entities.InventoryTransactionEntity) (entities.InventoryTransactionEntity, error)
Delete(ctx context.Context, tx *gorm.DB, inventoryTransactionId string) error Delete(ctx context.Context, tx *gorm.DB, inventoryTransactionId string) error
GetByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId string) ([]entities.InventoryTransactionEntity, error)
} }
type inventoryTransactionRepository struct { type inventoryTransactionRepository struct {
db *gorm.DB db *gorm.DB
} }
// GetByProductAndClient implements InventoryTransactionRepository.
func (r *inventoryTransactionRepository) GetByProductAndClient(ctx context.Context, tx *gorm.DB, productId string, clientId string) ([]entities.InventoryTransactionEntity, error) {
if tx == nil {
tx = r.db
}
var inventoryTransactions []entities.InventoryTransactionEntity
if err := tx.WithContext(ctx).
Preload("Client").
Preload("Product").
Preload("Aisle").
Preload("InvReceipt").
Preload("InvIssue").
Preload("InvMove").
Where("product_id = ? AND client_id = ?", productId, clientId).
Find(&inventoryTransactions).Error; err != nil {
return nil, err
}
return inventoryTransactions, nil
}
func NewInventoryTransactionRepository(db *gorm.DB) InventoryTransactionRepository { func NewInventoryTransactionRepository(db *gorm.DB) InventoryTransactionRepository {
return &inventoryTransactionRepository{db: db} return &inventoryTransactionRepository{db: db}
} }

View File

@ -22,6 +22,9 @@ type (
GetAll(ctx *gin.Context) GetAll(ctx *gin.Context)
AssignCrossReference(ctx *gin.Context) AssignCrossReference(ctx *gin.Context)
RemoveCrossReference(ctx *gin.Context) RemoveCrossReference(ctx *gin.Context)
GetInvStoragesByProductAndClient(ctx *gin.Context)
GetInvTransactionsByProductAndClient(ctx *gin.Context)
GetCrossReferencesByProductAndClient(ctx *gin.Context)
} }
productController struct { productController struct {
@ -30,6 +33,49 @@ type (
} }
) )
// GetCrossReferencesByProductAndClient implements ProductController.
func (c *productController) GetCrossReferencesByProductAndClient(ctx *gin.Context) {
id := ctx.Param("id")
crossReferences, err := c.productService.GetCrossReferencesByProduct(ctx, id)
if err != nil {
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_CROSS_REFERENCES, err.Error(), nil)
ctx.JSON(http.StatusInternalServerError, res)
return
}
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_CROSS_REFERENCES, crossReferences)
ctx.JSON(http.StatusOK, res)
}
// GetInvStoragesByProductAndClient implements ProductController.
func (c *productController) GetInvStoragesByProductAndClient(ctx *gin.Context) {
id := ctx.Param("id")
clientId := ctx.MustGet("client_id").(string)
invStorages, err := c.productService.GetInvStoragesByProductAndClient(ctx, id, clientId)
if err != nil {
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_INV_STORAGES, err.Error(), nil)
ctx.JSON(http.StatusInternalServerError, res)
return
}
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_INV_STORAGES, invStorages)
ctx.JSON(http.StatusOK, res)
}
// GetInvTransactionsByProductAndClient implements ProductController.
func (c *productController) GetInvTransactionsByProductAndClient(ctx *gin.Context) {
id := ctx.Param("id")
clientId := ctx.MustGet("client_id").(string)
invTransactions, err := c.productService.GetInvTransactionsByProductAndClient(ctx, id, clientId)
if err != nil {
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_INV_TRANSACTIONS, err.Error(), nil)
ctx.JSON(http.StatusInternalServerError, res)
return
}
res := utils.BuildResponseSuccess(dto.MESSAGE_SUCCESS_GET_INV_TRANSACTIONS, invTransactions)
ctx.JSON(http.StatusOK, res)
}
func NewProductController(i *do.Injector, productService service.ProductService) ProductController { func NewProductController(i *do.Injector, productService service.ProductService) ProductController {
db := do.MustInvokeNamed[*gorm.DB](i, constants.DB) db := do.MustInvokeNamed[*gorm.DB](i, constants.DB)
return &productController{ return &productController{

View File

@ -11,19 +11,25 @@ import (
) )
const ( const (
MESSAGE_FAILED_CREATE_PRODUCT = "failed create product" MESSAGE_FAILED_CREATE_PRODUCT = "failed create product"
MESSAGE_SUCCESS_CREATE_PRODUCT = "success create product" MESSAGE_SUCCESS_CREATE_PRODUCT = "success create product"
MESSAGE_FAILED_GET_PRODUCT = "failed get product" MESSAGE_FAILED_GET_PRODUCT = "failed get product"
MESSAGE_SUCCESS_GET_PRODUCT = "success get product" MESSAGE_SUCCESS_GET_PRODUCT = "success get product"
MESSAGE_FAILED_UPDATE_PRODUCT = "failed update product" MESSAGE_FAILED_UPDATE_PRODUCT = "failed update product"
MESSAGE_SUCCESS_UPDATE_PRODUCT = "success update product" MESSAGE_SUCCESS_UPDATE_PRODUCT = "success update product"
MESSAGE_FAILED_DELETE_PRODUCT = "failed delete product" MESSAGE_FAILED_DELETE_PRODUCT = "failed delete product"
MESSAGE_SUCCESS_DELETE_PRODUCT = "success delete product" MESSAGE_SUCCESS_DELETE_PRODUCT = "success delete product"
MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body" MESSAGE_FAILED_GET_DATA_FROM_BODY = "failed get data from body"
MESSAGE_FAILED_ASSIGN_CROSS_REF = "failed assign cross reference" MESSAGE_FAILED_ASSIGN_CROSS_REF = "failed assign cross reference"
MESSAGE_SUCCESS_ASSIGN_CROSS_REF = "success assign cross reference" MESSAGE_SUCCESS_ASSIGN_CROSS_REF = "success assign cross reference"
MESSAGE_FAILED_REMOVE_CROSS_REF = "failed remove cross reference" MESSAGE_FAILED_REMOVE_CROSS_REF = "failed remove cross reference"
MESSAGE_SUCCESS_REMOVE_CROSS_REF = "success remove cross reference" MESSAGE_SUCCESS_REMOVE_CROSS_REF = "success remove cross reference"
MESSAGE_FAILED_GET_INV_STORAGES = "failed get inventory storages by product and client"
MESSAGE_SUCCESS_GET_INV_STORAGES = "success get inventory storages by product and client"
MESSAGE_FAILED_GET_INV_TRANSACTIONS = "failed get inventory transactions by product and client"
MESSAGE_SUCCESS_GET_INV_TRANSACTIONS = "success get inventory transactions by product and client"
MESSAGE_SUCCESS_GET_CROSS_REFERENCES = "success get cross references by product and client"
MESSAGE_FAILED_GET_CROSS_REFERENCES = "failed get cross references by product and client"
) )
var ( var (
@ -107,41 +113,42 @@ type (
} }
ProductResponse struct { ProductResponse struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
RefNumber string `json:"ref_number"` RefNumber string `json:"ref_number"`
SKU string `json:"sku"` SKU string `json:"sku"`
Description string `json:"description"` Description string `json:"description"`
Status string `json:"status"` Status string `json:"status"`
IsReturnable bool `json:"is_returnable"` IsReturnable bool `json:"is_returnable"`
DimLength float64 `json:"dim_length"` DimLength float64 `json:"dim_length"`
DimWidth float64 `json:"dim_width"` DimWidth float64 `json:"dim_width"`
DimHeight float64 `json:"dim_height"` DimHeight float64 `json:"dim_height"`
Weight float64 `json:"weight"` Weight float64 `json:"weight"`
Volume float64 `json:"volume"` Volume float64 `json:"volume"`
MaxStackHeight int `json:"max_stack_height"` MaxStackHeight int `json:"max_stack_height"`
Temperature string `json:"temperature"` Temperature string `json:"temperature"`
IsHazardous bool `json:"is_hazardous"` IsHazardous bool `json:"is_hazardous"`
MinStock int `json:"min_stock"` MinStock int `json:"min_stock"`
MaxStock int `json:"max_stock"` MaxStock int `json:"max_stock"`
ReplenishType string `json:"replenish_type"` ReplenishType string `json:"replenish_type"`
CycleCount string `json:"cycle_count"` CycleCount string `json:"cycle_count"`
LotRules string `json:"lot_rules"` LotRules string `json:"lot_rules"`
LeadTime int `json:"lead_time"` LeadTime int `json:"lead_time"`
MultiplyRate string `json:"multiply_rate"` MultiplyRate string `json:"multiply_rate"`
DivideRate float64 `json:"divide_rate"` DivideRate float64 `json:"divide_rate"`
Client pkgdto.IdNameResponse `json:"client"` Client pkgdto.IdNameResponse `json:"client"`
Category pkgdto.IdNameResponse `json:"category"` Category pkgdto.IdNameResponse `json:"category"`
Uom pkgdto.IdNameResponse `json:"uom"` Uom pkgdto.IdNameResponse `json:"uom"`
DimUom pkgdto.IdNameResponse `json:"dim_uom"` DimUom pkgdto.IdNameResponse `json:"dim_uom"`
WeightUom pkgdto.IdNameResponse `json:"weight_uom"` WeightUom pkgdto.IdNameResponse `json:"weight_uom"`
VolumeUom pkgdto.IdNameResponse `json:"volume_uom"` VolumeUom pkgdto.IdNameResponse `json:"volume_uom"`
MinStockUom pkgdto.IdNameResponse `json:"min_stock_uom"` MinStockUom pkgdto.IdNameResponse `json:"min_stock_uom"`
MaxStockUom pkgdto.IdNameResponse `json:"max_stock_uom"` MaxStockUom pkgdto.IdNameResponse `json:"max_stock_uom"`
LeadTimeUom pkgdto.IdNameResponse `json:"lead_time_uom"` LeadTimeUom pkgdto.IdNameResponse `json:"lead_time_uom"`
UomToUom pkgdto.IdNameResponse `json:"uom_to_uom"` UomToUom pkgdto.IdNameResponse `json:"uom_to_uom"`
CrossReferences []ProductVendorResponse `json:"cross_references"` // CrossReferences []ProductVendorResponse `json:"cross_references"`
InvTransactions []ProductInventoryTransactionResponse `json:"inv_transactions"` // InvTransactions []ProductInventoryTransactionResponse `json:"inv_transactions"`
// InvStorages []ProductInventoryStorageResponse `json:"inv_storages"`
} }
CrossReferenceRequest struct { CrossReferenceRequest struct {
@ -167,82 +174,21 @@ type (
InvIssueRef string `json:"inv_issue_ref,omitempty"` InvIssueRef string `json:"inv_issue_ref,omitempty"`
InvMoveRef string `json:"inv_move_ref,omitempty"` InvMoveRef string `json:"inv_move_ref,omitempty"`
} }
ProductInventoryStorageResponse struct {
ID string `json:"id"`
Locater string `json:"locater"`
Lot string `json:"lot"`
OnHandQuantity float64 `json:"on_hand_quantity"`
AvailableQuantity float64 `json:"available_quantity"`
AisleID pkgdto.IdNameResponse `json:"aisle_id"`
Uom pkgdto.IdNameResponse `json:"uom"`
InvReceipt pkgdto.IdNameResponse `json:"inv_receipt"`
InvRequest pkgdto.IdNameResponse `json:"inv_request"`
}
) )
func MapProductToResponse(product entities.MProductEntity) ProductResponse { func MapProductToResponse(product entities.MProductEntity) ProductResponse {
crossRefs := make([]ProductVendorResponse, 0, len(product.CrossReferences))
for _, v := range product.CrossReferences {
crossRefs = append(crossRefs, ProductVendorResponse{
ID: v.Vendor.ID.String(),
Name: v.Vendor.Name,
Address: v.Vendor.Address,
ContactPerson: v.Vendor.ContactPerson,
SearchKey: v.Vendor.SearchKey,
})
}
invTransactions := make([]ProductInventoryTransactionResponse, 0, len(product.InventoryTransactions))
for _, it := range product.InventoryTransactions {
var transactionQuantity float64
var lot, locater, invReceiptRef, invIssueRef, invMoveRef string
var transactionDate string
valid := false
// Receipt
if it.InvReceipt.ID != uuid.Nil && it.InvReceipt.Status == constants.COMPLETED {
invReceiptRef = it.InvReceipt.ReferenceNumber
transactionDate = utils.DateTimeToString(it.TransactionDate)
for _, line := range it.InvReceipt.ReceiptLines {
if line.ProductID == it.ProductID {
transactionQuantity = line.Quantity
lot = line.BatchNumber
valid = true
break
}
}
}
// Issue
if it.InvIssue.ID != uuid.Nil && it.InvIssue.Status == constants.COMPLETED {
invIssueRef = it.InvIssue.DocumentNumber
transactionDate = utils.DateTimeToString(it.TransactionDate)
for _, line := range it.InvIssue.IssueLines {
if line.ProductID == it.ProductID {
transactionQuantity = line.IssuedQuantity
valid = true
break
}
}
}
// Move
if it.InvMove.ID != uuid.Nil && it.InvMove.Status == constants.COMPLETED {
invMoveRef = it.InvMove.MovementNumber
transactionDate = utils.DateTimeToString(it.TransactionDate)
for _, line := range it.InvMove.MovementLines {
if line.ProductID == it.ProductID {
transactionQuantity = line.MovedQuantity
valid = true
break
}
}
}
if valid {
invTransactions = append(invTransactions, ProductInventoryTransactionResponse{
ID: it.ID.String(),
TransactionDate: transactionDate,
TransactionType: it.TransactionType,
TransactionQuantity: transactionQuantity,
Lot: lot,
Locater: locater,
InvReceiptRef: invReceiptRef,
InvIssueRef: invIssueRef,
InvMoveRef: invMoveRef,
})
}
}
return ProductResponse{ return ProductResponse{
ID: product.ID.String(), ID: product.ID.String(),
Name: product.Name, Name: product.Name,
@ -307,7 +253,111 @@ func MapProductToResponse(product entities.MProductEntity) ProductResponse {
ID: product.UomToUom.ID.String(), ID: product.UomToUom.ID.String(),
Name: product.UomToUom.Name, Name: product.UomToUom.Name,
}, },
CrossReferences: crossRefs,
InvTransactions: invTransactions,
} }
} }
func MapInventoryTransactionsToResponses(transactions []entities.InventoryTransactionEntity) []ProductInventoryTransactionResponse {
responses := make([]ProductInventoryTransactionResponse, 0, len(transactions))
for _, t := range transactions {
resp := MapInventoryTransactionToProductInventoryTransactionResponse(t)
if resp.ID != "" { // hanya tambahkan jika mapping valid
responses = append(responses, resp)
}
}
return responses
}
func MapInventoryTransactionToProductInventoryTransactionResponse(transaction entities.InventoryTransactionEntity) ProductInventoryTransactionResponse {
var transactionQuantity float64
var lot, locater, invReceiptRef, invIssueRef, invMoveRef string
var transactionDate string
valid := false
if transaction.InvReceipt.ID != uuid.Nil && transaction.InvReceipt.Status == constants.COMPLETED {
invReceiptRef = transaction.InvReceipt.ReferenceNumber
transactionDate = utils.DateTimeToString(transaction.TransactionDate)
for _, line := range transaction.InvReceipt.ReceiptLines {
if line.ProductID == transaction.ProductID {
transactionQuantity = line.Quantity
lot = line.BatchNumber
valid = true
break
}
}
}
if transaction.InvIssue.ID != uuid.Nil && transaction.InvIssue.Status == constants.COMPLETED {
invIssueRef = transaction.InvIssue.DocumentNumber
transactionDate = utils.DateTimeToString(transaction.TransactionDate)
for _, line := range transaction.InvIssue.IssueLines {
if line.ProductID == transaction.ProductID {
transactionQuantity = line.IssuedQuantity
valid = true
break
}
}
}
if transaction.InvMove.ID != uuid.Nil && transaction.InvMove.Status == constants.COMPLETED {
invMoveRef = transaction.InvMove.MovementNumber
transactionDate = utils.DateTimeToString(transaction.TransactionDate)
for _, line := range transaction.InvMove.MovementLines {
if line.ProductID == transaction.ProductID {
transactionQuantity = line.MovedQuantity
valid = true
break
}
}
}
if !valid {
return ProductInventoryTransactionResponse{}
}
return ProductInventoryTransactionResponse{
ID: transaction.ID.String(),
TransactionDate: transactionDate,
TransactionType: transaction.TransactionType,
TransactionQuantity: transactionQuantity,
Lot: lot,
Locater: locater,
InvReceiptRef: invReceiptRef,
InvIssueRef: invIssueRef,
InvMoveRef: invMoveRef,
}
}
func MapInventoryStorageToProductInventoryStorageResponse(storage entities.InventoryStorageEntity) ProductInventoryStorageResponse {
return ProductInventoryStorageResponse{
ID: storage.ID.String(),
// Locater: storage.Locater,
// Lot: storage.BatchNumber,
OnHandQuantity: storage.OnHandQuantity,
AvailableQuantity: storage.AvailableQuantity,
AisleID: pkgdto.IdNameResponse{
ID: storage.Aisle.ID.String(),
Name: storage.Aisle.Name,
},
Uom: pkgdto.IdNameResponse{
ID: storage.Uom.ID.String(),
Name: storage.Uom.Name,
},
InvReceipt: pkgdto.IdNameResponse{
ID: storage.InvReceipt.ID.String(),
Name: storage.InvReceipt.ReferenceNumber,
},
InvRequest: pkgdto.IdNameResponse{
ID: storage.InvRequest.ID.String(),
Name: storage.InvRequest.ReferenceNumber,
},
}
}
func MapCrossReferenceToProductVendorResponse(crossRef entities.MCrossReferenceEntity) ProductVendorResponse {
return ProductVendorResponse{
ID: crossRef.Vendor.ID.String(),
Name: crossRef.Vendor.Name,
ContactPerson: crossRef.Vendor.ContactPerson,
SearchKey: crossRef.Vendor.SearchKey,
Address: crossRef.Vendor.Address}
}

View File

@ -19,12 +19,27 @@ type ProductRepository interface {
Delete(ctx context.Context, tx *gorm.DB, productId string) error Delete(ctx context.Context, tx *gorm.DB, productId string) error
AssignCrossReference(ctx context.Context, tx *gorm.DB, productId string, vendorIds []string) error AssignCrossReference(ctx context.Context, tx *gorm.DB, productId string, vendorIds []string) error
RemoveCrossReference(ctx context.Context, tx *gorm.DB, productId string, vendorIds []string) error RemoveCrossReference(ctx context.Context, tx *gorm.DB, productId string, vendorIds []string) error
GetCrossReferencesByProduct(ctx context.Context, tx *gorm.DB, productId string) ([]entities.MCrossReferenceEntity, error)
} }
type productRepository struct { type productRepository struct {
db *gorm.DB db *gorm.DB
} }
// GetCrossReferencesByProduct implements ProductRepository.
func (r *productRepository) GetCrossReferencesByProduct(ctx context.Context, tx *gorm.DB, productId string) ([]entities.MCrossReferenceEntity, error) {
if tx == nil {
tx = r.db
}
var crossReferences []entities.MCrossReferenceEntity
if err := tx.WithContext(ctx).
Where("product_id = ?", productId).
Find(&crossReferences).Error; err != nil {
return nil, err
}
return crossReferences, nil
}
// GetByCode implements ProductRepository. // GetByCode implements ProductRepository.
func (r *productRepository) GetByCode(ctx context.Context, tx *gorm.DB, productCode string, clientId string) (entities.MProductEntity, error) { func (r *productRepository) GetByCode(ctx context.Context, tx *gorm.DB, productCode string, clientId string) (entities.MProductEntity, error) {
if tx == nil { if tx == nil {
@ -156,6 +171,12 @@ func (r *productRepository) GetById(ctx context.Context, tx *gorm.DB, productId
Preload("CrossReferences"). Preload("CrossReferences").
Preload("CrossReferences.Vendor"). Preload("CrossReferences.Vendor").
Preload("InventoryStorages"). Preload("InventoryStorages").
Preload("InventoryStorages.Client").
Preload("InventoryStorages.Product").
Preload("InventoryStorages.Aisle").
Preload("InventoryStorages.Uom").
Preload("InventoryStorages.InvReceipt").
Preload("InventoryStorages.InvRequest").
Preload("InventoryTransactions"). Preload("InventoryTransactions").
Preload("InventoryTransactions.Client"). Preload("InventoryTransactions.Client").
Preload("InventoryTransactions.Aisle"). Preload("InventoryTransactions.Aisle").

View File

@ -22,5 +22,8 @@ func RegisterRoutes(server *gin.Engine, injector *do.Injector) {
productRoutes.GET("", middlewares.Authenticate(jwtService), productController.GetAll) productRoutes.GET("", middlewares.Authenticate(jwtService), productController.GetAll)
productRoutes.POST("/:id/assign-cross-reference", middlewares.Authenticate(jwtService), productController.AssignCrossReference) productRoutes.POST("/:id/assign-cross-reference", middlewares.Authenticate(jwtService), productController.AssignCrossReference)
productRoutes.POST("/:id/remove-cross-reference", middlewares.Authenticate(jwtService), productController.RemoveCrossReference) productRoutes.POST("/:id/remove-cross-reference", middlewares.Authenticate(jwtService), productController.RemoveCrossReference)
productRoutes.GET("/:id/inv-storages", middlewares.Authenticate(jwtService), productController.GetInvStoragesByProductAndClient)
productRoutes.GET("/:id/inv-transactions", middlewares.Authenticate(jwtService), productController.GetInvTransactionsByProductAndClient)
productRoutes.GET("/:id/cross-references", middlewares.Authenticate(jwtService), productController.GetCrossReferencesByProductAndClient)
} }
} }

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"github.com/Caknoooo/go-gin-clean-starter/database/entities" "github.com/Caknoooo/go-gin-clean-starter/database/entities"
invstoragerepo "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_storage/repository"
invtransactionrepo "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_transaction/repository"
"github.com/Caknoooo/go-gin-clean-starter/modules/product/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/product/dto"
"github.com/Caknoooo/go-gin-clean-starter/modules/product/query" "github.com/Caknoooo/go-gin-clean-starter/modules/product/query"
"github.com/Caknoooo/go-gin-clean-starter/modules/product/repository" "github.com/Caknoooo/go-gin-clean-starter/modules/product/repository"
@ -19,11 +21,55 @@ type ProductService interface {
Delete(ctx context.Context, productId string) error Delete(ctx context.Context, productId string) error
AssignCrossReference(ctx context.Context, productId string, vendorIds []string) error AssignCrossReference(ctx context.Context, productId string, vendorIds []string) error
RemoveCrossReference(ctx context.Context, productId string, vendorIds []string) error RemoveCrossReference(ctx context.Context, productId string, vendorIds []string) error
GetInvTransactionsByProductAndClient(ctx context.Context, productId string, clientId string) ([]dto.ProductInventoryTransactionResponse, error)
GetInvStoragesByProductAndClient(ctx context.Context, productId string, clientId string) ([]dto.ProductInventoryStorageResponse, error)
GetCrossReferencesByProduct(ctx context.Context, productId string) ([]dto.ProductVendorResponse, error)
} }
type productService struct { type productService struct {
db *gorm.DB db *gorm.DB
productRepo repository.ProductRepository productRepo repository.ProductRepository
inventoryTransactionRepo invtransactionrepo.InventoryTransactionRepository
inventoryStorageRepo invstoragerepo.InventoryStorageRepository
}
// GetCrossReferencesByProductAndClient implements ProductService.
func (s *productService) GetCrossReferencesByProduct(ctx context.Context, productId string) ([]dto.ProductVendorResponse, error) {
crossReferences, err := s.productRepo.GetCrossReferencesByProduct(ctx, nil, productId)
if err != nil {
return nil, err
}
var responses []dto.ProductVendorResponse
for _, cr := range crossReferences {
responses = append(responses, dto.MapCrossReferenceToProductVendorResponse(cr))
}
if len(responses) == 0 {
responses = []dto.ProductVendorResponse{} // pastikan slice kosong, bukan nil
}
return responses, nil
}
// GetInvStoragesByProductAndClient implements ProductService.
func (s *productService) GetInvStoragesByProductAndClient(ctx context.Context, productId string, clientId string) ([]dto.ProductInventoryStorageResponse, error) {
invStorages, err := s.inventoryStorageRepo.GetStoragesByProductAndClient(ctx, nil, productId, clientId)
if err != nil {
return nil, err
}
var responses []dto.ProductInventoryStorageResponse
for _, invStorage := range invStorages {
responses = append(responses, dto.MapInventoryStorageToProductInventoryStorageResponse(invStorage))
}
return responses, nil
}
// GetInvTransactionsByProductAndClient implements ProductService.
func (s *productService) GetInvTransactionsByProductAndClient(ctx context.Context, productId string, clientId string) ([]dto.ProductInventoryTransactionResponse, error) {
invTransactions, err := s.inventoryTransactionRepo.GetByProductAndClient(ctx, nil, productId, clientId)
if err != nil {
return nil, err
}
responses := dto.MapInventoryTransactionsToResponses(invTransactions)
return responses, nil
} }
// AssignCrossReference implements ProductService. // AssignCrossReference implements ProductService.
@ -66,10 +112,12 @@ func (s *productService) RemoveCrossReference(ctx context.Context, productId str
return nil return nil
} }
func NewProductService(productRepo repository.ProductRepository, db *gorm.DB) ProductService { func NewProductService(productRepo repository.ProductRepository, db *gorm.DB, inventoryTransactionRepo invtransactionrepo.InventoryTransactionRepository, inventoryStorageRepo invstoragerepo.InventoryStorageRepository) ProductService {
return &productService{ return &productService{
productRepo: productRepo, productRepo: productRepo,
db: db, db: db,
inventoryTransactionRepo: inventoryTransactionRepo,
inventoryStorageRepo: inventoryStorageRepo,
} }
} }

View File

@ -162,7 +162,7 @@ func RegisterDependencies(injector *do.Injector) {
// Service // Service
userServ := userService.NewUserService(userRepository, roleRepository, warehouseRepository, clientRepository, refreshTokenRepository, jwtService, db) userServ := userService.NewUserService(userRepository, roleRepository, warehouseRepository, clientRepository, refreshTokenRepository, jwtService, db)
productService := productService.NewProductService(productRepository, db) productService := productService.NewProductService(productRepository, db, inventoryTransactionRepository, inventoryStorageRepository)
roleServ := roleService.NewRoleService(roleRepository, refreshTokenRepository, jwtService, userServ, db) roleServ := roleService.NewRoleService(roleRepository, refreshTokenRepository, jwtService, userServ, db)
menuSvc := menuService.NewMenuService(menuRepository, jwtService, db) menuSvc := menuService.NewMenuService(menuRepository, jwtService, db)
maintenanceGroupServ := maintGroupService.NewMaintenanceGroupService(maintenanceGroupRepository, maintenanceGroupRoleRepository, maintenanceGroupRoleUserRepository, db) maintenanceGroupServ := maintGroupService.NewMaintenanceGroupService(maintenanceGroupRepository, maintenanceGroupRoleRepository, maintenanceGroupRoleUserRepository, db)
@ -174,7 +174,7 @@ func RegisterDependencies(injector *do.Injector) {
warehouseServ := warehouseService.NewWarehouseService(warehouseRepository, db) warehouseServ := warehouseService.NewWarehouseService(warehouseRepository, db)
zonaServ := zonaService.NewZonaService(zonaRepository, db) zonaServ := zonaService.NewZonaService(zonaRepository, db)
aisleServ := aisleService.NewAisleService(aisleRepository, db) aisleServ := aisleService.NewAisleService(aisleRepository, db)
inventoryReceiptServ := inventoryReceiptService.NewInventoryReceiptService(db, inventoryReceiptRepository, inventoryReceiptLineRepository, productRepository, uomRepository) inventoryReceiptServ := inventoryReceiptService.NewInventoryReceiptService(db, inventoryReceiptRepository, inventoryReceiptLineRepository, productRepository, uomRepository, inventoryStorageRepository)
assignmentServ := assignmentService.NewAssignmentService(db, assignmentRepository, assignmentUserRepository) assignmentServ := assignmentService.NewAssignmentService(db, assignmentRepository, assignmentUserRepository)
inventoryRequestServ := inventoryRequestService.NewInventoryRequestService(db, inventoryRequestRepository, inventoryRequestLineRepository) inventoryRequestServ := inventoryRequestService.NewInventoryRequestService(db, inventoryRequestRepository, inventoryRequestLineRepository)
inventoryIssueServ := inventoryIssueService.NewInventoryIssueService(db, inventoryIssueRepository, inventoryIssueLineRepository) inventoryIssueServ := inventoryIssueService.NewInventoryIssueService(db, inventoryIssueRepository, inventoryIssueLineRepository)