From 74158138c0309f3cc2e4e543f14455c26018b9bd Mon Sep 17 00:00:00 2001 From: aguhh18 Date: Sat, 24 Jan 2026 10:38:52 +0700 Subject: [PATCH] Fix[BE]: enhance error logging and messages in transfer service --- .../transfers/services/transfer.service.go | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/internal/modules/inventory/transfers/services/transfer.service.go b/internal/modules/inventory/transfers/services/transfer.service.go index eb096257..ea1041ea 100644 --- a/internal/modules/inventory/transfers/services/transfer.service.go +++ b/internal/modules/inventory/transfers/services/transfer.service.go @@ -124,7 +124,8 @@ func (s transferService) GetOne(c *fiber.Ctx, id uint) (*entity.StockTransfer, e if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Transfer dengan ID %d tidak ditemukan", id)) } - return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengambil data transfer dengan ID %d", id)) + s.Log.Errorf("Failed to fetch transfer by ID %d: %+v", id, err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data transfer") } return transferPtr, nil @@ -142,7 +143,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Produk dengan ID %d tidak ditemukan di gudang asal (ID: %d)", product.ProductID, req.SourceWarehouseID)) } - return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengecek stok produk %d di gudang asal", product.ProductID)) + s.Log.Errorf("Failed to fetch product warehouse for product_id=%d, warehouse_id=%d: %+v", product.ProductID, req.SourceWarehouseID, err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengecek stok produk") } if sourcePW.Quantity < product.ProductQty { return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Stok produk %d di gudang asal tidak mencukupi. Tersedia: %.2f, Diminta: %.2f", product.ProductID, sourcePW.Quantity, product.ProductQty)) @@ -166,7 +168,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques if destPfkID > 0 { projectFlockKandang, err := s.ProjectFlockKandangRepo.GetByID(c.Context(), destPfkID) if err != nil { - return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data project flock untuk gudang tujuan") + s.Log.Errorf("Failed to fetch project flock kandang by ID %d: %+v", destPfkID, err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data project flock") } if projectFlockKandang.ClosedAt != nil { return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Project flock untuk gudang tujuan sudah ditutup (closing) pada %s", projectFlockKandang.ClosedAt.Format("2006-01-02"))) @@ -198,7 +201,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Supplier dengan ID %d tidak ditemukan", delivery.SupplierID)) } - return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengambil data supplier dengan ID %d", delivery.SupplierID)) + s.Log.Errorf("Failed to fetch supplier by ID %d: %+v", delivery.SupplierID, err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data supplier") } if supplier.Category != string(utils.SupplierCategoryBOP) { return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Supplier '%s' (ID: %d) bukan kategori BOP. Kategori saat ini: %s", supplier.Name, delivery.SupplierID, supplier.Category)) @@ -207,7 +211,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques movementNumber, err := s.StockTransferRepo.GenerateMovementNumber(c.Context()) if err != nil { - return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat nomor movement transfer") + s.Log.Errorf("Failed to generate movement number: %+v", err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat nomor transfer") } transferDate, _ := utils.ParseDateString(req.TransferDate) @@ -247,14 +252,16 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques if errors.Is(err, gorm.ErrRecordNotFound) { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Produk %d tidak ditemukan di gudang asal (ID: %d)", product.ProductID, req.SourceWarehouseID)) } - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengambil data product warehouse untuk produk %d di gudang asal", product.ProductID)) + s.Log.Errorf("Failed to fetch source product warehouse for product_id=%d, warehouse_id=%d: %+v", product.ProductID, req.SourceWarehouseID, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data stok gudang asal") } destPW, err := productWarehouseRepoTX.GetProductWarehouseByProductAndWarehouseID( c.Context(), uint(product.ProductID), uint(req.DestinationWarehouseID), ) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengambil data product warehouse untuk produk %d di gudang tujuan", product.ProductID)) + s.Log.Errorf("Failed to fetch dest product warehouse for product_id=%d, warehouse_id=%d: %+v", product.ProductID, req.DestinationWarehouseID, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data stok gudang tujuan") } if errors.Is(err, gorm.ErrRecordNotFound) { ctx := c.Context() @@ -275,7 +282,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques ProjectFlockKandangId: pfkID, } if err := productWarehouseRepoTX.CreateOne(c.Context(), destPW, nil); err != nil { - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal membuat product warehouse untuk produk %d di gudang tujuan", product.ProductID)) + s.Log.Errorf("Failed to create product warehouse for product_id=%d, warehouse_id=%d: %+v", product.ProductID, req.DestinationWarehouseID, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat data stok gudang tujuan") } } @@ -365,9 +373,9 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques Files: documentFiles, }) if err != nil { - s.Log.WithError(err).Errorf("Failed to upload document for delivery %d (delivery_id: %d, filename: %s)", - deliveryIdx+1, delivery.Id, file.Filename) - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to upload document for delivery %d: %v", deliveryIdx+1, err)) + s.Log.Errorf("Failed to upload document for delivery %d (delivery_id=%d, filename=%s): %+v", + deliveryIdx+1, delivery.Id, file.Filename, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal mengunggah dokumen") } } } @@ -393,7 +401,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques "usage_qty": consumeResult.UsageQuantity, "pending_qty": consumeResult.PendingQuantity, }).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengupdate tracking usage untuk produk %d", product.ProductID)) + s.Log.Errorf("Failed to update tracking usage for detail_id=%d, product_id=%d: %+v", detail.Id, product.ProductID, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal memperbarui data tracking") } note := fmt.Sprintf("Transfer #%s", entityTransfer.MovementNumber) @@ -406,7 +415,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques Tx: tx, }) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal menambah stok untuk produk %d di gudang tujuan. Error: %v", product.ProductID, err)) + s.Log.Errorf("Failed to replenish stock for product_id=%d, pw_id=%d, qty=%.2f: %+v", product.ProductID, *detail.DestProductWarehouseID, product.ProductQty, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal menambah stok gudang tujuan") } if err := tx.Model(&entity.StockTransferDetail{}). @@ -414,7 +424,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques Updates(map[string]interface{}{ "total_qty": replenishResult.AddedQuantity, }).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengupdate tracking total untuk produk %d", product.ProductID)) + s.Log.Errorf("Failed to update tracking total for detail_id=%d, product_id=%d: %+v", detail.Id, product.ProductID, err) + return fiber.NewError(fiber.StatusInternalServerError, "Gagal memperbarui data tracking") } } @@ -448,7 +459,10 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques }) if err != nil { - return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal memproses transfer. Error: %v", err)) + if fiberErr, ok := err.(*fiber.Error); ok { + return nil, fiberErr + } + return nil, fiber.NewError(fiber.StatusInternalServerError, "Internal server error") } result, err := s.GetOne(c, uint(entityTransfer.Id)) @@ -458,7 +472,8 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques if len(expensePayloads) > 0 { if err := s.notifyExpenseItemsDelivered(c, entityTransfer.Id, expensePayloads); err != nil { - return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal sinkronisasi data expense untuk transfer %s. Silakan cek manual di module expense", entityTransfer.MovementNumber)) + s.Log.Errorf("Failed to sync expense for transfer_id=%d, movement_number=%s: %+v", entityTransfer.Id, entityTransfer.MovementNumber, err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Gagal sinkronisasi data expense. Silakan cek manual di module expense") } } @@ -478,7 +493,8 @@ 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)) } - return 0, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Gagal mengambil data gudang dengan ID %d", warehouseID)) + s.Log.Errorf("Failed to fetch warehouse by ID %d: %+v", warehouseID, err) + return 0, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data gudang") } if warehouse.KandangId == nil || *warehouse.KandangId == 0 { @@ -490,7 +506,8 @@ func (s *transferService) getActiveProjectFlockKandangID(ctx context.Context, wa if errors.Is(err, gorm.ErrRecordNotFound) { return 0, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Tidak ada project flock aktif untuk kandang %d", *warehouse.KandangId)) } - return 0, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data project flock kandang yang aktif") + s.Log.Errorf("Failed to fetch active project flock kandang for kandang_id=%d: %+v", *warehouse.KandangId, err) + return 0, fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil data project flock") } return uint(projectFlockKandang.Id), nil