mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 14:55:42 +00:00
Refactor[BE] adjustment stock handling: remove stock_log_id, update relations, and enhance transfer logging
This commit is contained in:
+3
@@ -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);
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE adjustment_stocks DROP COLUMN IF EXISTS stock_log_id;
|
||||||
@@ -4,7 +4,6 @@ import "time"
|
|||||||
|
|
||||||
type AdjustmentStock struct {
|
type AdjustmentStock struct {
|
||||||
Id uint `gorm:"primaryKey"`
|
Id uint `gorm:"primaryKey"`
|
||||||
StockLogId uint `gorm:"column:stock_log_id;not null;index"`
|
|
||||||
ProductWarehouseId uint `gorm:"column:product_warehouse_id;not null"`
|
ProductWarehouseId uint `gorm:"column:product_warehouse_id;not null"`
|
||||||
TotalQty float64 `gorm:"column:total_qty;default:0"`
|
TotalQty float64 `gorm:"column:total_qty;default:0"`
|
||||||
TotalUsed float64 `gorm:"column:total_used;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"`
|
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
|
||||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
||||||
|
|
||||||
StockLog *StockLog `gorm:"foreignKey:StockLogId;references:Id"`
|
|
||||||
ProductWarehouse *ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
ProductWarehouse *ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
||||||
|
StockLog *StockLog `gorm:"polymorphic:Loggable;polymorphicType:LoggableType;polymorphicId:LoggableId;polymorphicValue:ADJUSTMENT"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ func ToProductWarehouseDTO(e *entity.ProductWarehouse) *ProductWarehouseDTO {
|
|||||||
func ToAdjustmentRelationDTO(e *entity.AdjustmentStock) AdjustmentRelationDTO {
|
func ToAdjustmentRelationDTO(e *entity.AdjustmentStock) AdjustmentRelationDTO {
|
||||||
return AdjustmentRelationDTO{
|
return AdjustmentRelationDTO{
|
||||||
Id: e.Id,
|
Id: e.Id,
|
||||||
Note: e.StockLog.Notes,
|
Note: "",
|
||||||
Increase: e.TotalQty,
|
Increase: e.TotalQty,
|
||||||
Decrease: e.UsageQty,
|
Decrease: e.UsageQty,
|
||||||
ProductWarehouseId: e.ProductWarehouseId,
|
ProductWarehouseId: e.ProductWarehouseId,
|
||||||
@@ -113,24 +113,17 @@ func ToAdjustmentRelationDTO(e *entity.AdjustmentStock) AdjustmentRelationDTO {
|
|||||||
|
|
||||||
func ToAdjustmentListDTO(e *entity.AdjustmentStock) AdjustmentListDTO {
|
func ToAdjustmentListDTO(e *entity.AdjustmentStock) AdjustmentListDTO {
|
||||||
var createdUser *userDTO.UserRelationDTO
|
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{}
|
// Get created user from StockLog
|
||||||
if e.StockLog != nil {
|
if e.StockLog != nil && e.StockLog.CreatedUser != nil {
|
||||||
createdAt = e.StockLog.CreatedAt
|
mapped := userDTO.ToUserRelationDTO(*e.StockLog.CreatedUser)
|
||||||
|
createdUser = &mapped
|
||||||
}
|
}
|
||||||
|
|
||||||
return AdjustmentListDTO{
|
return AdjustmentListDTO{
|
||||||
AdjustmentRelationDTO: ToAdjustmentRelationDTO(e),
|
AdjustmentRelationDTO: ToAdjustmentRelationDTO(e),
|
||||||
CreatedUser: createdUser,
|
CreatedUser: createdUser,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: e.CreatedAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
type AdjustmentStockRepository interface {
|
type AdjustmentStockRepository interface {
|
||||||
CreateOne(ctx context.Context, data *entity.AdjustmentStock, modifier func(*gorm.DB) *gorm.DB) error
|
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
|
WithTx(tx *gorm.DB) AdjustmentStockRepository
|
||||||
DB() *gorm.DB
|
DB() *gorm.DB
|
||||||
}
|
}
|
||||||
@@ -30,19 +30,13 @@ func (r *adjustmentStockRepositoryImpl) CreateOne(ctx context.Context, data *ent
|
|||||||
return q.Create(data).Error
|
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
|
var record entity.AdjustmentStock
|
||||||
err := r.db.WithContext(ctx).
|
q := r.db.WithContext(ctx)
|
||||||
Preload("StockLog").
|
if modifier != nil {
|
||||||
Preload("StockLog.ProductWarehouse").
|
q = modifier(q)
|
||||||
Preload("StockLog.ProductWarehouse.Product").
|
}
|
||||||
Preload("StockLog.ProductWarehouse.Warehouse").
|
err := q.First(&record, id).Error
|
||||||
Preload("StockLog.CreatedUser").
|
|
||||||
Preload("ProductWarehouse").
|
|
||||||
Preload("ProductWarehouse.Product").
|
|
||||||
Preload("ProductWarehouse.Warehouse").
|
|
||||||
Where("stock_log_id = ?", stockLogID).
|
|
||||||
First(&record).Error
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,11 +70,11 @@ func (s *adjustmentService) withRelations(db *gorm.DB) *gorm.DB {
|
|||||||
Preload("ProductWarehouse").
|
Preload("ProductWarehouse").
|
||||||
Preload("ProductWarehouse.Product").
|
Preload("ProductWarehouse.Product").
|
||||||
Preload("ProductWarehouse.Warehouse").
|
Preload("ProductWarehouse.Warehouse").
|
||||||
Preload("CreatedUser")
|
Preload("StockLog.CreatedUser")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *adjustmentService) GetOne(c *fiber.Ctx, id uint) (*entity.AdjustmentStock, error) {
|
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 err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Adjustment not found")
|
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) {
|
if transactionType == string(utils.StockLogTransactionTypeIncrease) {
|
||||||
afterQuantity += req.Quantity
|
afterQuantity += req.Quantity
|
||||||
newLog.Increase = afterQuantity
|
newLog.Increase = req.Quantity
|
||||||
} else {
|
} else {
|
||||||
if productWarehouse.Quantity < req.Quantity {
|
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))
|
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
|
afterQuantity -= req.Quantity
|
||||||
newLog.Decrease = afterQuantity
|
newLog.Decrease = req.Quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.StockLogsRepository.WithTx(tx).CreateOne(ctx, newLog, nil); err != nil {
|
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{
|
adjustmentStock := &entity.AdjustmentStock{
|
||||||
StockLogId: newLog.Id,
|
|
||||||
ProductWarehouseId: productWarehouse.Id,
|
ProductWarehouseId: productWarehouse.Id,
|
||||||
}
|
}
|
||||||
if err := s.AdjustmentStockRepository.WithTx(tx).CreateOne(ctx, adjustmentStock, nil); err != nil {
|
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")
|
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) {
|
if transactionType == string(utils.StockLogTransactionTypeIncrease) {
|
||||||
|
|
||||||
note := fmt.Sprintf("Stock Adjustment IN #%d", newLog.Id)
|
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
|
productWarehouse.Quantity = afterQuantity
|
||||||
if err := s.ProductWarehouseRepo.WithTx(tx).UpdateOne(ctx, productWarehouse.Id, productWarehouse, nil); err != nil {
|
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)
|
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
|
var total int64
|
||||||
|
|
||||||
q := s.AdjustmentStockRepository.DB().WithContext(c.Context()).Model(&entity.AdjustmentStock{}).
|
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").
|
||||||
Preload("ProductWarehouse.Product").
|
Preload("ProductWarehouse.Product").
|
||||||
Preload("ProductWarehouse.Warehouse")
|
Preload("ProductWarehouse.Warehouse").
|
||||||
|
Preload("StockLog.CreatedUser")
|
||||||
|
|
||||||
if query.ProductID > 0 {
|
if query.ProductID > 0 {
|
||||||
q = q.Joins("JOIN stock_logs ON stock_logs.id = adjustment_stocks.stock_log_id").
|
q = q.Joins("JOIN product_warehouses ON product_warehouses.id = adjustment_stocks.product_warehouse_id").
|
||||||
Joins("JOIN product_warehouses ON product_warehouses.id = stock_logs.product_warehouse_id").
|
|
||||||
Where("product_warehouses.product_id = ?", query.ProductID)
|
Where("product_warehouses.product_id = ?", query.ProductID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.WarehouseID > 0 {
|
if query.WarehouseID > 0 {
|
||||||
q = q.Joins("JOIN stock_logs ON stock_logs.id = adjustment_stocks.stock_log_id").
|
q = q.Joins("JOIN product_warehouses ON product_warehouses.id = adjustment_stocks.product_warehouse_id").
|
||||||
Joins("JOIN product_warehouses ON product_warehouses.id = stock_logs.product_warehouse_id").
|
|
||||||
Where("product_warehouses.warehouse_id = ?", query.WarehouseID)
|
Where("product_warehouses.warehouse_id = ?", query.WarehouseID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.TransactionType != "" {
|
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))
|
Where("stock_logs.transaction_type = ?", strings.ToUpper(query.TransactionType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user