fix[BE]: fix logic pengambilan quatity untuk chick in dan penggunaan helper common

This commit is contained in:
aguhh18
2025-10-21 10:20:34 +07:00
parent 542e503360
commit 1afbdea4ff
8 changed files with 39 additions and 76 deletions
@@ -1 +0,0 @@
DROP TABLE IF EXISTS stock_availabilities;
@@ -1,15 +0,0 @@
CREATE TABLE stock_availabilities (
id BIGSERIAL PRIMARY KEY,
entity_type VARCHAR(50) NOT NULL,
entity_id BIGINT NOT NULL,
product_id BIGINT,
quantity NUMERIC(15, 3) NOT NULL DEFAULT 0,
reserved_quantity NUMERIC(15, 3) NOT NULL DEFAULT 0,
unit VARCHAR(20),
last_updated TIMESTAMPTZ DEFAULT now(),
created_at TIMESTAMPTZ DEFAULT now(),
deleted_at TIMESTAMPTZ
);
ALTER TABLE stock_availabilities
ADD CONSTRAINT fk_product_id FOREIGN KEY (product_id) REFERENCES products (id);
@@ -1 +0,0 @@
DROP TABLE IF EXISTS audit_logs;
@@ -1,13 +0,0 @@
CREATE TABLE audit_logs (
id BIGSERIAL PRIMARY KEY,
table_name VARCHAR(100) NOT NULL,
record_id BIGINT NOT NULL,
action VARCHAR(30) NOT NULL,
before_data JSONB,
after_data JSONB,
changed_by BIGINT,
created_at TIMESTAMPTZ DEFAULT now()
);
ALTER TABLE audit_logs
ADD CONSTRAINT fk_changed_by FOREIGN KEY (changed_by) REFERENCES users (id);
@@ -49,8 +49,8 @@ func (u *AdjustmentController) AdjustmentHistory(c *fiber.Ctx) error {
query := &validation.Query{ query := &validation.Query{
Page: c.QueryInt("page", 1), Page: c.QueryInt("page", 1),
Limit: c.QueryInt("limit", 10), Limit: c.QueryInt("limit", 10),
ProductID: c.QueryInt("product_id", 0), ProductID: uint(c.QueryInt("product_id", 0)),
WarehouseID: c.QueryInt("warehouse_id", 0), WarehouseID: uint(c.QueryInt("warehouse_id", 0)),
TransactionType: c.Query("transaction_type", ""), TransactionType: c.Query("transaction_type", ""),
} }
@@ -4,6 +4,8 @@ import (
"errors" "errors"
"strings" "strings"
common "gitlab.com/mbugroup/lti-api.git/internal/common/service"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities" entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments/validations" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments/validations"
ProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" ProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
@@ -77,22 +79,11 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
} }
ctx := c.Context() ctx := c.Context()
isProductExist, err := s.ProductRepo.IdExists(c.Context(), uint(req.ProductID)) if err := common.EnsureRelations(c.Context(),
if err != nil { common.RelationCheck{Name: "Product", ID: &req.ProductID, Exists: s.ProductRepo.IdExists},
s.Log.Errorf("Failed to check product existence: %+v", err) common.RelationCheck{Name: "Warehouse", ID: &req.WarehouseID, Exists: s.WarehouseRepo.IdExists},
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product") ); err != nil {
} return nil, err
if !isProductExist {
return nil, fiber.NewError(fiber.StatusNotFound, "Product not found")
}
isWarehouseExist, err := s.WarehouseRepo.IdExists(c.Context(), uint(req.WarehouseID))
if err != nil {
s.Log.Errorf("Failed to check warehouse existence: %+v", err)
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate warehouse")
}
if !isWarehouseExist {
return nil, fiber.NewError(fiber.StatusNotFound, "Warehouse not found")
} }
if req.Quantity <= 0 { if req.Quantity <= 0 {
@@ -118,6 +109,7 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
Quantity: 0, Quantity: 0,
CreatedBy: 1, // TODO: should Get from auth middleware CreatedBy: 1, // TODO: should Get from auth middleware
} }
if err := s.ProductWarehouseRepo.CreateOne(ctx, newPW, nil); err != nil { if err := s.ProductWarehouseRepo.CreateOne(ctx, newPW, nil); err != nil {
s.Log.Errorf("Failed to create product warehouse: %+v", err) s.Log.Errorf("Failed to create product warehouse: %+v", err)
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create product warehouse") return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create product warehouse")
@@ -126,7 +118,6 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
} }
err = s.StockLogsRepository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { 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.GetProductWarehouseByProductAndWarehouseID(ctx, uint(req.ProductID), uint(req.WarehouseID))
if err != nil { if err != nil {
s.Log.Errorf("Failed to get product warehouse: %+v", err) s.Log.Errorf("Failed to get product warehouse: %+v", err)
@@ -159,14 +150,12 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e
s.Log.Errorf("Failed to create stock log: %+v", err) s.Log.Errorf("Failed to create stock log: %+v", err)
return err return err
} }
s.Log.Infof("Stock log created: %+v", newLog.Id)
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)
return err return err
} }
s.Log.Infof("Product warehouse quantity updated: %+v", productWarehouse.Id)
createdLogId = newLog.Id createdLogId = newLog.Id
return nil return nil
@@ -184,7 +173,6 @@ func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Qu
if err := s.Validate.Struct(query); err != nil { if err := s.Validate.Struct(query); err != nil {
return nil, 0, err return nil, 0, err
} }
offset := (query.Page - 1) * query.Limit offset := (query.Page - 1) * query.Limit
isWarehousesExist, err := s.WarehouseRepo.IdExists(c.Context(), uint(query.WarehouseID)) isWarehousesExist, err := s.WarehouseRepo.IdExists(c.Context(), uint(query.WarehouseID))
@@ -11,7 +11,7 @@ type Create struct {
type Query struct { type Query struct {
Page int `query:"page" validate:"omitempty,min=1"` Page int `query:"page" validate:"omitempty,min=1"`
Limit int `query:"limit" validate:"omitempty,min=1,max=100"` Limit int `query:"limit" validate:"omitempty,min=1,max=100"`
ProductID int `query:"product_id" validate:"omitempty,min=0"` ProductID uint `query:"product_id" validate:"omitempty,min=0"`
WarehouseID int `query:"warehouse_id" validate:"omitempty,min=0"` WarehouseID uint `query:"warehouse_id" validate:"omitempty,min=0"`
TransactionType string `query:"transaction_type" validate:"omitempty,oneof=increase decrease"` TransactionType string `query:"transaction_type" validate:"omitempty,oneof=increase decrease"`
} }
@@ -132,27 +132,33 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
s.Log.Errorf("Failed to get project flock: %+v", err) s.Log.Errorf("Failed to get project flock: %+v", err)
return nil, fiber.NewError(fiber.StatusNotFound, "Project Flock not found") return nil, fiber.NewError(fiber.StatusNotFound, "Project Flock not found")
} }
var productWarehouses []entity.ProductWarehouse
var productWarehouse entity.ProductWarehouse
err = s.ProductWarehouseRepo.DB(). err = s.ProductWarehouseRepo.DB().
WithContext(c.Context()). WithContext(c.Context()).
Joins("JOIN products ON products.id = product_warehouses.product_id"). Joins("JOIN products ON products.id = product_warehouses.product_id").
Joins("JOIN product_categories ON product_categories.id = products.product_category_id"). Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", projectFlock.ProductCategory.Code, warehouse.Id). Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", projectFlock.ProductCategory.Code, warehouse.Id).
Order("created_at DESC"). Order("created_at DESC").
First(&productWarehouse).Error Find(&productWarehouses).Error
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { s.Log.Errorf("Failed to get product warehouses: %+v", err)
return nil, fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse")
}
s.Log.Errorf("Failed to get product warehouse: %+v", err)
return nil, err return nil, err
} }
if len(productWarehouses) == 0 {
if productWarehouse.Quantity < 1 { return nil, fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse")
return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient product quantity in warehouse")
} }
// Jumlahkan semua quantity DOC
totalQuantity := 0.0
for _, pw := range productWarehouses {
totalQuantity += pw.Quantity
}
if totalQuantity < 1 {
return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient quantity in Product Warehouses")
}
// Buat satu chickin dengan total quantity
chickinDate, err := utils.ParseDateString(req.ChickInDate) chickinDate, err := utils.ParseDateString(req.ChickInDate)
if err != nil { if err != nil {
s.Log.Errorf("Failed to parse chickin date: %+v", err) s.Log.Errorf("Failed to parse chickin date: %+v", err)
@@ -161,9 +167,9 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
newChickin := &entity.ProjectChickin{ newChickin := &entity.ProjectChickin{
ProjectFlockKandangId: projectflockkandang.ProjectFlockId, ProjectFlockKandangId: projectflockkandang.ProjectFlockId,
ChickInDate: chickinDate, ChickInDate: chickinDate,
Quantity: productWarehouse.Quantity, Quantity: totalQuantity,
Note: "", Note: "",
CreatedBy: 1, //todo: ganti dengan CreatedBy: 1, //todo: ganti dengan user login
} }
err = s.Repository.CreateOne(c.Context(), newChickin, nil) err = s.Repository.CreateOne(c.Context(), newChickin, nil)
if err != nil { if err != nil {
@@ -171,16 +177,15 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
return nil, err return nil, err
} }
updatedQuantity := productWarehouse.Quantity - newChickin.Quantity // Update semua product warehouse: set quantity jadi 0
if updatedQuantity < 0 { for _, pw := range productWarehouses {
updatedQuantity = 0 err = s.ProductWarehouseRepo.PatchOne(c.Context(), pw.Id, map[string]any{
} "quantity": 0,
err = s.ProductWarehouseRepo.PatchOne(c.Context(), productWarehouse.Id, map[string]any{ }, nil)
"quantity": updatedQuantity, if err != nil {
}, nil) s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
if err != nil { return nil, err
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err) }
return nil, err
} }
existingPopulation, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangID(c.Context(), req.ProjectFlockKandangId) existingPopulation, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangID(c.Context(), req.ProjectFlockKandangId)