FIX[BE]: fixing wrong index data on adjustment. change get from stocklogs to adjustment table

This commit is contained in:
aguhh18
2026-01-21 15:16:30 +07:00
parent e8a89f0f17
commit a73b44808f
5 changed files with 99 additions and 74 deletions
@@ -100,38 +100,42 @@ func ToProductWarehouseDTO(e *entity.ProductWarehouse) *ProductWarehouseDTO {
}
}
func ToAdjustmentRelationDTO(e *entity.StockLog) AdjustmentRelationDTO {
func ToAdjustmentRelationDTO(e *entity.AdjustmentStock) AdjustmentRelationDTO {
return AdjustmentRelationDTO{
Id: e.Id,
Note: e.Notes,
Increase: e.Increase,
Decrease: e.Decrease,
Note: e.StockLog.Notes,
Increase: e.TotalQty,
Decrease: e.UsageQty,
ProductWarehouseId: e.ProductWarehouseId,
ProductWarehouse: ToProductWarehouseDTO(e.ProductWarehouse),
}
}
func ToAdjustmentListDTO(e *entity.StockLog) AdjustmentListDTO {
func ToAdjustmentListDTO(e *entity.AdjustmentStock) AdjustmentListDTO {
var createdUser *userDTO.UserRelationDTO
if e.CreatedUser != nil {
if e.StockLog != nil && e.StockLog.CreatedUser != nil {
createdUser = &userDTO.UserRelationDTO{
Id: e.CreatedUser.Id,
IdUser: e.CreatedUser.IdUser,
Email: e.CreatedUser.Email,
Name: e.CreatedUser.Name,
Id: e.StockLog.CreatedUser.Id,
IdUser: e.StockLog.CreatedUser.IdUser,
Email: e.StockLog.CreatedUser.Email,
Name: e.StockLog.CreatedUser.Name,
}
}
createdAt := time.Time{}
if e.StockLog != nil {
createdAt = e.StockLog.CreatedAt
}
return AdjustmentListDTO{
AdjustmentRelationDTO: ToAdjustmentRelationDTO(e),
CreatedUser: createdUser,
CreatedAt: e.CreatedAt,
CreatedAt: createdAt,
}
}
func ToAdjustmentDetailDTO(e *entity.StockLog) AdjustmentDetailDTO {
func ToAdjustmentDetailDTO(e *entity.AdjustmentStock) AdjustmentDetailDTO {
return AdjustmentDetailDTO{
AdjustmentListDTO: ToAdjustmentListDTO(e),
// UpdatedAt: e.UpdatedAt,
}
}
@@ -33,6 +33,14 @@ func (r *adjustmentStockRepositoryImpl) CreateOne(ctx context.Context, data *ent
func (r *adjustmentStockRepositoryImpl) GetByStockLogID(ctx context.Context, stockLogID uint) (*entity.AdjustmentStock, error) {
var record entity.AdjustmentStock
err := r.db.WithContext(ctx).
Preload("StockLog").
Preload("StockLog.ProductWarehouse").
Preload("StockLog.ProductWarehouse.Product").
Preload("StockLog.ProductWarehouse.Warehouse").
Preload("StockLog.CreatedUser").
Preload("ProductWarehouse").
Preload("ProductWarehouse.Product").
Preload("ProductWarehouse.Warehouse").
Where("stock_log_id = ?", stockLogID).
First(&record).Error
if err != nil {
@@ -25,9 +25,9 @@ import (
)
type AdjustmentService interface {
Adjustment(ctx *fiber.Ctx, req *validation.Create) (*entity.StockLog, error)
GetOne(ctx *fiber.Ctx, id uint) (*entity.StockLog, error)
AdjustmentHistory(ctx *fiber.Ctx, query *validation.Query) ([]*entity.StockLog, int64, error)
Adjustment(ctx *fiber.Ctx, req *validation.Create) (*entity.AdjustmentStock, error)
GetOne(ctx *fiber.Ctx, id uint) (*entity.AdjustmentStock, error)
AdjustmentHistory(ctx *fiber.Ctx, query *validation.Query) ([]*entity.AdjustmentStock, int64, error)
}
type adjustmentService struct {
@@ -73,10 +73,8 @@ func (s *adjustmentService) withRelations(db *gorm.DB) *gorm.DB {
Preload("CreatedUser")
}
func (s *adjustmentService) GetOne(c *fiber.Ctx, id uint) (*entity.StockLog, error) {
stockLog, err := s.StockLogsRepository.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB {
return s.withRelations(db).Preload("ProductWarehouse.Product.ProductCategory")
})
func (s *adjustmentService) GetOne(c *fiber.Ctx, id uint) (*entity.AdjustmentStock, error) {
adjustmentStock, err := s.AdjustmentStockRepository.GetByStockLogID(c.Context(), id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fiber.NewError(fiber.StatusNotFound, "Adjustment not found")
@@ -85,14 +83,10 @@ func (s *adjustmentService) GetOne(c *fiber.Ctx, id uint) (*entity.StockLog, err
return nil, err
}
if stockLog.LoggableType != string(utils.StockLogTypeAdjustment) {
return nil, fiber.NewError(fiber.StatusNotFound, "Adjustment not found")
}
return stockLog, nil
return adjustmentStock, nil
}
func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*entity.StockLog, error) {
func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*entity.AdjustmentStock, error) {
if err := s.Validate.Struct(req); err != nil {
return nil, err
}
@@ -111,12 +105,13 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
if req.Quantity <= 0 {
return nil, fiber.NewError(fiber.StatusBadRequest, "Quantity must be greater than zero")
}
transactionType := strings.ToUpper(req.TransactionType)
if transactionType != string(utils.StockLogTransactionTypeIncrease) && transactionType != string(utils.StockLogTransactionTypeDecrease) {
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid transaction type")
}
var createdLogId uint
var createdAdjustmentStockId uint
var projectFlockKandangID *uint
pfkID, err := s.getActiveProjectFlockKandangID(ctx, uint(req.WarehouseID))
@@ -151,7 +146,8 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
return nil, err
}
err = s.StockLogsRepository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
productWarehouse, err := s.ProductWarehouseRepo.GetProductWarehouseByProductAndWarehouseID(ctx, uint(req.ProductID), uint(req.WarehouseID))
productWarehouse, err := s.ProductWarehouseRepo.FindByProductWarehouseAndPfk(ctx, uint(req.ProductID), uint(req.WarehouseID), projectFlockKandangID)
if err != nil {
s.Log.Errorf("Failed to get product warehouse: %+v", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get product warehouse")
@@ -171,14 +167,14 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
newLog.Increase = afterQuantity
} else {
if productWarehouse.Quantity < req.Quantity {
return fiber.NewError(fiber.StatusBadRequest, "Insufficient stock for adjustment")
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Insufficient stock. Current: %.2f, Requested: %.2f", productWarehouse.Quantity, req.Quantity))
}
afterQuantity -= req.Quantity
newLog.Decrease = afterQuantity
}
if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil {
s.Log.Errorf("Failed to create stock log: %+v", err)
return err
}
@@ -187,7 +183,7 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
ProductWarehouseId: productWarehouse.Id,
}
if err := s.AdjustmentStockRepository.WithTx(tx).CreateOne(ctx, adjustmentStock, nil); err != nil {
s.Log.Errorf("Failed to create adjustment stock: %+v", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create adjustment stock record")
}
@@ -212,7 +208,7 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
UsableID: adjustmentStock.Id,
ProductWarehouseID: uint(productWarehouse.Id),
Quantity: req.Quantity,
AllowPending: false, // Don't allow pending for adjustment
AllowPending: false,
Tx: tx,
})
if err != nil {
@@ -220,24 +216,27 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
}
}
// Update ProductWarehouse quantity (for backward compatibility/reporting)
// LEGACY: Update ProductWarehouse quantity (for backward compatibility/reporting)
productWarehouse.Quantity = afterQuantity
if err := s.ProductWarehouseRepo.WithTx(tx).UpdateOne(ctx, productWarehouse.Id, productWarehouse, nil); err != nil {
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
return err
}
createdLogId = newLog.Id
createdAdjustmentStockId = adjustmentStock.Id
return nil
})
if err != nil {
s.Log.Errorf("Transaction failed in CreateOne: %+v", err)
var fiberErr *fiber.Error
if errors.As(err, &fiberErr) {
return nil, err
}
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to process adjustment transaction")
}
return s.GetOne(c, createdLogId)
return s.GetOne(c, createdAdjustmentStockId)
}
func (s *adjustmentService) getActiveProjectFlockKandangID(ctx context.Context, warehouseID uint) (uint, error) {
@@ -266,13 +265,15 @@ func (s *adjustmentService) getActiveProjectFlockKandangID(ctx context.Context,
return uint(projectFlockKandang.Id), nil
}
func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Query) ([]*entity.StockLog, int64, error) {
func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Query) ([]*entity.AdjustmentStock, int64, error) {
if err := s.Validate.Struct(query); err != nil {
return nil, 0, err
}
offset := (query.Page - 1) * query.Limit
var isProductsExist bool
isWarehousesExist, err := s.WarehouseRepo.IdExists(c.Context(), uint(query.WarehouseID))
if err != nil {
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate warehouse")
}
@@ -280,7 +281,8 @@ func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Qu
return nil, 0, fiber.NewError(fiber.StatusNotFound, "Warehouse not found")
}
isProductsExist, err := s.ProductRepo.IdExists(c.Context(), uint(query.ProductID))
isProductsExist, err = s.ProductRepo.IdExists(c.Context(), uint(query.ProductID))
if err != nil {
s.Log.Errorf("Failed to check product existence: %+v", err)
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product")
@@ -289,28 +291,51 @@ func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Qu
return nil, 0, fiber.NewError(fiber.StatusNotFound, "Product not found")
}
stockLogs, total, err := s.StockLogsRepository.GetAll(c.Context(), offset, query.Limit, func(db *gorm.DB) *gorm.DB {
var adjustmentStocks []entity.AdjustmentStock
var total int64
db = s.withRelations(db)
q := s.AdjustmentStockRepository.DB().WithContext(c.Context()).Model(&entity.AdjustmentStock{}).
Preload("StockLog").
Preload("StockLog.ProductWarehouse").
Preload("StockLog.ProductWarehouse.Product").
Preload("StockLog.ProductWarehouse.Warehouse").
Preload("StockLog.CreatedUser").
Preload("ProductWarehouse").
Preload("ProductWarehouse.Product").
Preload("ProductWarehouse.Warehouse")
db = db.Where("loggable_type = ?", string(utils.StockLogTypeAdjustment))
if query.ProductID > 0 {
q = q.Joins("JOIN stock_logs ON stock_logs.id = adjustment_stocks.stock_log_id").
Joins("JOIN product_warehouses ON product_warehouses.id = stock_logs.product_warehouse_id").
Where("product_warehouses.product_id = ?", query.ProductID)
}
if query.TransactionType != "" {
db = db.Where("transaction_type = ?", strings.ToUpper(query.TransactionType))
}
db = s.StockLogsRepository.ApplyProductWarehouseFilters(db, uint(query.ProductID), uint(query.WarehouseID))
if query.WarehouseID > 0 {
q = q.Joins("JOIN stock_logs ON stock_logs.id = adjustment_stocks.stock_log_id").
Joins("JOIN product_warehouses ON product_warehouses.id = stock_logs.product_warehouse_id").
Where("product_warehouses.warehouse_id = ?", query.WarehouseID)
}
return db.Order("created_at DESC")
})
if query.TransactionType != "" {
q = q.Joins("JOIN stock_logs ON stock_logs.id = adjustment_stocks.stock_log_id").
Where("stock_logs.transaction_type = ?", strings.ToUpper(query.TransactionType))
}
if err = q.Count(&total).Error; err != nil {
s.Log.Errorf("Failed to get adjustments: %+v", err)
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to get adjustment history")
}
err = q.Offset(offset).Limit(query.Limit).Order("created_at DESC").Find(&adjustmentStocks).Error
if err != nil {
s.Log.Errorf("Failed to get adjustments: %+v", err)
return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to get adjustment history")
}
result := make([]*entity.StockLog, len(stockLogs))
for i, v := range stockLogs {
result[i] = &v
result := make([]*entity.AdjustmentStock, len(adjustmentStocks))
for i := range adjustmentStocks {
result[i] = &adjustmentStocks[i]
}
return result, total, nil
@@ -3,15 +3,14 @@ package service
import (
"errors"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"github.com/sirupsen/logrus"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/validations"
kandangrepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)