diff --git a/internal/database/migrations/20260126075643_remove_stock_log_id_from_adjustment_stocks.down.sql b/internal/database/migrations/20260126075643_remove_stock_log_id_from_adjustment_stocks.down.sql new file mode 100644 index 00000000..e8f203a8 --- /dev/null +++ b/internal/database/migrations/20260126075643_remove_stock_log_id_from_adjustment_stocks.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE adjustment_stocks ADD COLUMN stock_log_id INTEGER; + +CREATE INDEX idx_adjustment_stocks_stock_log_id ON adjustment_stocks (stock_log_id); \ No newline at end of file diff --git a/internal/database/migrations/20260126075643_remove_stock_log_id_from_adjustment_stocks.up.sql b/internal/database/migrations/20260126075643_remove_stock_log_id_from_adjustment_stocks.up.sql new file mode 100644 index 00000000..32f27161 --- /dev/null +++ b/internal/database/migrations/20260126075643_remove_stock_log_id_from_adjustment_stocks.up.sql @@ -0,0 +1 @@ +ALTER TABLE adjustment_stocks DROP COLUMN IF EXISTS stock_log_id; \ No newline at end of file diff --git a/internal/entities/adjustment_stock.go b/internal/entities/adjustment_stock.go index ef27d0c2..841e4820 100644 --- a/internal/entities/adjustment_stock.go +++ b/internal/entities/adjustment_stock.go @@ -4,7 +4,6 @@ import "time" type AdjustmentStock struct { Id uint `gorm:"primaryKey"` - StockLogId uint `gorm:"column:stock_log_id;not null;index"` ProductWarehouseId uint `gorm:"column:product_warehouse_id;not null"` TotalQty float64 `gorm:"column:total_qty;default:0"` TotalUsed float64 `gorm:"column:total_used;default:0"` @@ -13,6 +12,6 @@ type AdjustmentStock struct { CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` - StockLog *StockLog `gorm:"foreignKey:StockLogId;references:Id"` ProductWarehouse *ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"` + StockLog *StockLog `gorm:"polymorphic:Loggable;polymorphicType:LoggableType;polymorphicId:LoggableId;polymorphicValue:ADJUSTMENT"` } diff --git a/internal/modules/inventory/adjustments/dto/adjustment.dto.go b/internal/modules/inventory/adjustments/dto/adjustment.dto.go index 1ce3da1b..c07f84f9 100644 --- a/internal/modules/inventory/adjustments/dto/adjustment.dto.go +++ b/internal/modules/inventory/adjustments/dto/adjustment.dto.go @@ -103,7 +103,7 @@ func ToProductWarehouseDTO(e *entity.ProductWarehouse) *ProductWarehouseDTO { func ToAdjustmentRelationDTO(e *entity.AdjustmentStock) AdjustmentRelationDTO { return AdjustmentRelationDTO{ Id: e.Id, - Note: e.StockLog.Notes, + Note: "", Increase: e.TotalQty, Decrease: e.UsageQty, ProductWarehouseId: e.ProductWarehouseId, @@ -113,24 +113,17 @@ func ToAdjustmentRelationDTO(e *entity.AdjustmentStock) AdjustmentRelationDTO { func ToAdjustmentListDTO(e *entity.AdjustmentStock) AdjustmentListDTO { var createdUser *userDTO.UserRelationDTO - if e.StockLog != nil && e.StockLog.CreatedUser != nil { - createdUser = &userDTO.UserRelationDTO{ - 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 + // Get created user from StockLog + if e.StockLog != nil && e.StockLog.CreatedUser != nil { + mapped := userDTO.ToUserRelationDTO(*e.StockLog.CreatedUser) + createdUser = &mapped } return AdjustmentListDTO{ AdjustmentRelationDTO: ToAdjustmentRelationDTO(e), CreatedUser: createdUser, - CreatedAt: createdAt, + CreatedAt: e.CreatedAt, } } diff --git a/internal/modules/inventory/adjustments/repositories/adjustment_stock.repository.go b/internal/modules/inventory/adjustments/repositories/adjustment_stock.repository.go index fa2685e7..f62738a3 100644 --- a/internal/modules/inventory/adjustments/repositories/adjustment_stock.repository.go +++ b/internal/modules/inventory/adjustments/repositories/adjustment_stock.repository.go @@ -9,7 +9,7 @@ import ( type AdjustmentStockRepository interface { CreateOne(ctx context.Context, data *entity.AdjustmentStock, modifier func(*gorm.DB) *gorm.DB) error - GetByStockLogID(ctx context.Context, stockLogID uint) (*entity.AdjustmentStock, error) + GetByID(ctx context.Context, id uint, modifier func(*gorm.DB) *gorm.DB) (*entity.AdjustmentStock, error) WithTx(tx *gorm.DB) AdjustmentStockRepository DB() *gorm.DB } @@ -30,19 +30,13 @@ func (r *adjustmentStockRepositoryImpl) CreateOne(ctx context.Context, data *ent return q.Create(data).Error } -func (r *adjustmentStockRepositoryImpl) GetByStockLogID(ctx context.Context, stockLogID uint) (*entity.AdjustmentStock, error) { +func (r *adjustmentStockRepositoryImpl) GetByID(ctx context.Context, id uint, modifier func(*gorm.DB) *gorm.DB) (*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 + q := r.db.WithContext(ctx) + if modifier != nil { + q = modifier(q) + } + err := q.First(&record, id).Error if err != nil { return nil, err } diff --git a/internal/modules/inventory/adjustments/services/adjustment.service.go b/internal/modules/inventory/adjustments/services/adjustment.service.go index bec0ef74..16bcf70a 100644 --- a/internal/modules/inventory/adjustments/services/adjustment.service.go +++ b/internal/modules/inventory/adjustments/services/adjustment.service.go @@ -70,11 +70,11 @@ func (s *adjustmentService) withRelations(db *gorm.DB) *gorm.DB { Preload("ProductWarehouse"). Preload("ProductWarehouse.Product"). Preload("ProductWarehouse.Warehouse"). - Preload("CreatedUser") + Preload("StockLog.CreatedUser") } func (s *adjustmentService) GetOne(c *fiber.Ctx, id uint) (*entity.AdjustmentStock, error) { - adjustmentStock, err := s.AdjustmentStockRepository.GetByStockLogID(c.Context(), id) + adjustmentStock, err := s.AdjustmentStockRepository.GetByID(c.Context(), id, s.withRelations) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fiber.NewError(fiber.StatusNotFound, "Adjustment not found") @@ -164,13 +164,13 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e if transactionType == string(utils.StockLogTransactionTypeIncrease) { afterQuantity += req.Quantity - newLog.Increase = afterQuantity + newLog.Increase = req.Quantity } else { if productWarehouse.Quantity < req.Quantity { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Stok tidak mencukupi untuk pengurangan. Stok saat ini: %.2f, Jumlah yang akan dikurangi: %.2f", productWarehouse.Quantity, req.Quantity)) } afterQuantity -= req.Quantity - newLog.Decrease = afterQuantity + newLog.Decrease = req.Quantity } if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil { @@ -179,7 +179,6 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e } adjustmentStock := &entity.AdjustmentStock{ - StockLogId: newLog.Id, ProductWarehouseId: productWarehouse.Id, } if err := s.AdjustmentStockRepository.WithTx(tx).CreateOne(ctx, adjustmentStock, nil); err != nil { @@ -187,6 +186,12 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e return fiber.NewError(fiber.StatusInternalServerError, "Failed to create adjustment stock record") } + newLog.LoggableType = string(utils.StockLogTypeAdjustment) + newLog.LoggableId = adjustmentStock.Id + if err := s.StockLogsRepository.WithTx(tx).UpdateOne(ctx, newLog.Id, newLog, nil); err != nil { + return fiber.NewError(fiber.StatusInternalServerError, "Failed to link stock log") + } + if transactionType == string(utils.StockLogTransactionTypeIncrease) { note := fmt.Sprintf("Stock Adjustment IN #%d", newLog.Id) @@ -216,7 +221,6 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e } } - // 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) @@ -295,29 +299,23 @@ func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Qu var total int64 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") + Preload("ProductWarehouse.Warehouse"). + Preload("StockLog.CreatedUser") 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"). + q = q.Joins("JOIN product_warehouses ON product_warehouses.id = adjustment_stocks.product_warehouse_id"). Where("product_warehouses.product_id = ?", query.ProductID) } 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"). + q = q.Joins("JOIN product_warehouses ON product_warehouses.id = adjustment_stocks.product_warehouse_id"). Where("product_warehouses.warehouse_id = ?", query.WarehouseID) } if query.TransactionType != "" { - q = q.Joins("JOIN stock_logs ON stock_logs.id = adjustment_stocks.stock_log_id"). + q = q.Joins("JOIN stock_logs ON stock_logs.loggable_type = ? AND stock_logs.loggable_id = adjustment_stocks.id", "ADJUSTMENT"). Where("stock_logs.transaction_type = ?", strings.ToUpper(query.TransactionType)) }