mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Feat[BE]: add document handling to stock transfer process
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
@@ -27,7 +28,7 @@ import (
|
||||
type TransferService interface {
|
||||
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.StockTransfer, int64, error)
|
||||
GetOne(ctx *fiber.Ctx, id uint) (*entity.StockTransfer, error)
|
||||
CreateOne(ctx *fiber.Ctx, req *validation.TransferRequest) (*entity.StockTransfer, error)
|
||||
CreateOne(ctx *fiber.Ctx, req *validation.TransferRequest, files []*multipart.FileHeader) (*entity.StockTransfer, error)
|
||||
}
|
||||
|
||||
type transferService struct {
|
||||
@@ -42,9 +43,10 @@ type transferService struct {
|
||||
SupplierRepo rSupplier.SupplierRepository
|
||||
WarehouseRepo warehouseRepo.WarehouseRepository
|
||||
ProjectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository
|
||||
DocumentSvc commonSvc.DocumentService
|
||||
}
|
||||
|
||||
func NewTransferService(validate *validator.Validate, stockTransferRepo rStockTransfer.StockTransferRepository, stockTransferDetailRepo rStockTransfer.StockTransferDetailRepository, stockTransferDeliveryRepo rStockTransfer.StockTransferDeliveryRepository, stockTransferDeliveryItemRepo rStockTransfer.StockTransferDeliveryItemRepository, stockLogsRepo rStockLogs.StockLogRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, supplierRepo rSupplier.SupplierRepository, warehouseRepo warehouseRepo.WarehouseRepository, projectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository) TransferService {
|
||||
func NewTransferService(validate *validator.Validate, stockTransferRepo rStockTransfer.StockTransferRepository, stockTransferDetailRepo rStockTransfer.StockTransferDetailRepository, stockTransferDeliveryRepo rStockTransfer.StockTransferDeliveryRepository, stockTransferDeliveryItemRepo rStockTransfer.StockTransferDeliveryItemRepository, stockLogsRepo rStockLogs.StockLogRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, supplierRepo rSupplier.SupplierRepository, warehouseRepo warehouseRepo.WarehouseRepository, projectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository, documentSvc commonSvc.DocumentService) TransferService {
|
||||
return &transferService{
|
||||
Log: utils.Log,
|
||||
Validate: validate,
|
||||
@@ -57,6 +59,7 @@ func NewTransferService(validate *validator.Validate, stockTransferRepo rStockTr
|
||||
SupplierRepo: supplierRepo,
|
||||
WarehouseRepo: warehouseRepo,
|
||||
ProjectFlockKandangRepo: projectFlockKandangRepo,
|
||||
DocumentSvc: documentSvc,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +75,10 @@ func (s transferService) withRelations(db *gorm.DB) *gorm.DB {
|
||||
Preload("Details").
|
||||
Preload("Details.Product").
|
||||
Preload("Deliveries.Items").
|
||||
Preload("Deliveries.Supplier")
|
||||
Preload("Deliveries.Supplier").
|
||||
Preload("Documents", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("documentable_type = ?", "STOCK_TRANSFER")
|
||||
})
|
||||
}
|
||||
|
||||
func (s transferService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.StockTransfer, int64, error) {
|
||||
@@ -94,31 +100,31 @@ func (s transferService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entit
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
s.Log.Infof("Retrieved %d transfers", len(transfers))
|
||||
|
||||
return transfers, total, nil
|
||||
}
|
||||
|
||||
func (s transferService) GetOne(c *fiber.Ctx, id uint) (*entity.StockTransfer, error) {
|
||||
var transfer entity.StockTransfer
|
||||
s.Log.Infof("Attempting to get StockTransfer with ID: %d", id)
|
||||
|
||||
transferPtr, err := s.StockTransferRepo.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB {
|
||||
return s.withRelations(db)
|
||||
})
|
||||
if err != nil {
|
||||
s.Log.Errorf("Error getting StockTransfer ID %d: %+v", id, err)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Transfer not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to get transfer by ID: %+v", err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get transfer")
|
||||
}
|
||||
|
||||
s.Log.Infof("Retrieved transfer: %+v", transfer)
|
||||
if transferPtr != nil {
|
||||
s.Log.Infof("StockTransfer %d has %d documents", transferPtr.Id, len(transferPtr.Documents))
|
||||
}
|
||||
|
||||
return transferPtr, nil
|
||||
}
|
||||
|
||||
func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferRequest) (*entity.StockTransfer, error) {
|
||||
func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferRequest, files []*multipart.FileHeader) (*entity.StockTransfer, error) {
|
||||
|
||||
pwIDs := make([]uint, 0, len(req.Products))
|
||||
|
||||
@@ -180,7 +186,6 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
|
||||
seqNum, err := s.StockTransferRepo.GetNextMovementNumber(c.Context())
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get next movement number: %+v", err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to generate movement number")
|
||||
}
|
||||
movementNumber := fmt.Sprintf("PND-MBU-%05d", seqNum)
|
||||
@@ -198,10 +203,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
err = s.StockTransferRepo.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error {
|
||||
|
||||
if err := s.StockTransferRepo.WithTx(tx).CreateOne(c.Context(), entityTransfer, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create stock transfer: %+v", err)
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("Stock transfer created: %+v", entityTransfer.Id)
|
||||
|
||||
var details []*entity.StockTransferDetail
|
||||
for _, product := range req.Products {
|
||||
@@ -212,10 +215,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
})
|
||||
}
|
||||
if err := s.StockTransferDetailRepo.WithTx(tx).CreateMany(c.Context(), details, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create stock transfer details: %+v", err)
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("Stock transfer details created for transfer ID: %+v", entityTransfer.Id)
|
||||
|
||||
var deliveries []*entity.StockTransferDelivery
|
||||
for _, delivery := range req.Deliveries {
|
||||
@@ -224,13 +225,11 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
SupplierId: uint64(delivery.SupplierID),
|
||||
VehiclePlate: delivery.VehiclePlate,
|
||||
DriverName: delivery.DriverName,
|
||||
DocumentPath: "https://tourism.gov.in/sites/default/files/2019-04/dummy-pdf_2.pdf",
|
||||
ShippingCostItem: delivery.DeliveryCostPerItem,
|
||||
ShippingCostTotal: delivery.DeliveryCost,
|
||||
})
|
||||
}
|
||||
if err := s.StockTransferDeliveryRepo.WithTx(tx).CreateMany(c.Context(), deliveries, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create stock transfer deliveries: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -256,27 +255,46 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
}
|
||||
}
|
||||
if err := s.StockTransferDeliveryItemRepo.WithTx(tx).CreateMany(c.Context(), deliveryItems, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create stock transfer delivery items: %+v", err)
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("Stock transfer delivery items created for transfer ID: %+v", entityTransfer.Id)
|
||||
|
||||
actorIDCopy := actorID
|
||||
if s.DocumentSvc != nil && len(files) > 0 {
|
||||
s.Log.Infof("Starting document upload for %d files", len(files))
|
||||
documentFiles := make([]commonSvc.DocumentFile, 0, len(files))
|
||||
for idx, file := range files {
|
||||
docIndex := idx
|
||||
documentFiles = append(documentFiles, commonSvc.DocumentFile{
|
||||
File: file,
|
||||
Type: "STOCK_TRANSFER_DOCUMENT",
|
||||
Index: &docIndex,
|
||||
})
|
||||
}
|
||||
_, err := s.DocumentSvc.UploadDocuments(c.Context(), commonSvc.DocumentUploadRequest{
|
||||
DocumentableType: "STOCK_TRANSFER",
|
||||
DocumentableID: entityTransfer.Id,
|
||||
CreatedBy: &actorIDCopy,
|
||||
Files: documentFiles,
|
||||
})
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to upload documents for transfer %d: %+v", entityTransfer.Id, err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to upload transfer documents")
|
||||
}
|
||||
s.Log.Infof("Successfully uploaded documents for transfer ID %d", entityTransfer.Id)
|
||||
}
|
||||
|
||||
for _, product := range req.Products {
|
||||
sourcePW, err := s.ProductWarehouseRepo.GetProductWarehouseByProductAndWarehouseID(c.Context(), uint(product.ProductID), uint(req.SourceWarehouseID))
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to get source product warehouse: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get source product warehouse")
|
||||
}
|
||||
if sourcePW.Quantity < product.ProductQty {
|
||||
s.Log.Errorf("Insufficient stock in source warehouse for product ID: %+v", product.ProductID)
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Insufficient stock in source warehouse for product ID: %d", product.ProductID))
|
||||
}
|
||||
sourcePW.Quantity -= product.ProductQty
|
||||
if err := s.ProductWarehouseRepo.WithTx(tx).UpdateOne(c.Context(), sourcePW.Id, sourcePW, nil); err != nil {
|
||||
s.Log.Errorf("Failed to update source product warehouse: %+v", err)
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("Source product warehouse updated: %+v", sourcePW.Id)
|
||||
|
||||
decreaseLog := &entity.StockLog{
|
||||
Decrease: product.ProductQty,
|
||||
@@ -287,7 +305,6 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
CreatedBy: actorID,
|
||||
}
|
||||
if err := s.StockLogsRepository.WithTx(tx).CreateOne(c.Context(), decreaseLog, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create stock log decrease: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -295,7 +312,6 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
c.Context(), uint(product.ProductID), uint(req.DestinationWarehouseID),
|
||||
)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.Log.Errorf("Failed to get destination product warehouse: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get destination product warehouse")
|
||||
}
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -311,18 +327,14 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
ProjectFlockKandangId: &projectFlockKandangID,
|
||||
}
|
||||
if err := s.ProductWarehouseRepo.WithTx(tx).CreateOne(c.Context(), destPW, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create destination product warehouse: %+v", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create destination product warehouse")
|
||||
}
|
||||
s.Log.Infof("Destination product warehouse created: %+v", destPW.Id)
|
||||
}
|
||||
|
||||
destPW.Quantity += product.ProductQty
|
||||
if err := s.ProductWarehouseRepo.WithTx(tx).UpdateOne(c.Context(), destPW.Id, destPW, nil); err != nil {
|
||||
s.Log.Errorf("Failed to update destination product warehouse: %+v", err)
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("Destination product warehouse updated: %+v", destPW.Id)
|
||||
|
||||
increaseLog := &entity.StockLog{
|
||||
Increase: product.ProductQty,
|
||||
@@ -333,7 +345,6 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
CreatedBy: actorID,
|
||||
}
|
||||
if err := s.StockLogsRepository.WithTx(tx).CreateOne(c.Context(), increaseLog, nil); err != nil {
|
||||
s.Log.Errorf("Failed to create stock log increase: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -343,7 +354,7 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
||||
|
||||
if err != nil {
|
||||
s.Log.Errorf("Transaction failed in CreateOne: %+v", err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to process transfer transaction")
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to process transfer transaction: %v", err))
|
||||
}
|
||||
|
||||
result, err := s.GetOne(c, uint(entityTransfer.Id))
|
||||
@@ -359,7 +370,6 @@ func (s *transferService) getActiveProjectFlockKandangID(ctx context.Context, wa
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return 0, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Gudang dengan ID %d tidak ditemukan", warehouseID))
|
||||
}
|
||||
s.Log.Errorf("Failed to get warehouse %d: %+v", warehouseID, err)
|
||||
return 0, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data gudang")
|
||||
}
|
||||
|
||||
@@ -372,7 +382,6 @@ func (s *transferService) getActiveProjectFlockKandangID(ctx context.Context, wa
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return 0, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Kandang %d belum memiliki project flock aktif", *warehouse.KandangId))
|
||||
}
|
||||
s.Log.Errorf("Failed to get active project flock for kandang %d: %+v", *warehouse.KandangId, err)
|
||||
return 0, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil project flock kandang")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user