feat/BE/US-278/TASK-288,289-adjust schema database,Create trigger in expense module, add filter in warehouse linked to project flock

This commit is contained in:
ragilap
2025-12-08 01:23:21 +07:00
parent 4638fba318
commit 0a18753dde
10 changed files with 322 additions and 195 deletions
@@ -16,6 +16,7 @@ import (
rProduct "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/repositories"
rSupplier "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/repositories"
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
projectFlockKandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
rPurchase "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/validations"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
@@ -43,16 +44,17 @@ const (
)
type purchaseService struct {
Log *logrus.Logger
Validate *validator.Validate
PurchaseRepo rPurchase.PurchaseRepository
ProductRepo rProduct.ProductRepository
WarehouseRepo rWarehouse.WarehouseRepository
SupplierRepo rSupplier.SupplierRepository
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
ApprovalSvc commonSvc.ApprovalService
ExpenseBridge PurchaseExpenseBridge
approvalWorkflow approvalutils.ApprovalWorkflowKey
Log *logrus.Logger
Validate *validator.Validate
PurchaseRepo rPurchase.PurchaseRepository
ProductRepo rProduct.ProductRepository
WarehouseRepo rWarehouse.WarehouseRepository
SupplierRepo rSupplier.SupplierRepository
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
ProjectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository
ApprovalSvc commonSvc.ApprovalService
ExpenseBridge PurchaseExpenseBridge
approvalWorkflow approvalutils.ApprovalWorkflowKey
}
type staffAdjustmentPayload struct {
@@ -67,20 +69,22 @@ func NewPurchaseService(
warehouseRepo rWarehouse.WarehouseRepository,
supplierRepo rSupplier.SupplierRepository,
productWarehouseRepo rProductWarehouse.ProductWarehouseRepository,
projectFlockKandangRepo projectFlockKandangRepo.ProjectFlockKandangRepository,
approvalSvc commonSvc.ApprovalService,
expenseBridge PurchaseExpenseBridge,
) PurchaseService {
return &purchaseService{
Log: utils.Log,
Validate: validate,
PurchaseRepo: purchaseRepo,
ProductRepo: productRepo,
WarehouseRepo: warehouseRepo,
SupplierRepo: supplierRepo,
ProductWarehouseRepo: productWarehouseRepo,
ApprovalSvc: approvalSvc,
ExpenseBridge: expenseBridge,
approvalWorkflow: utils.ApprovalWorkflowPurchase,
Log: utils.Log,
Validate: validate,
PurchaseRepo: purchaseRepo,
ProductRepo: productRepo,
WarehouseRepo: warehouseRepo,
SupplierRepo: supplierRepo,
ProductWarehouseRepo: productWarehouseRepo,
ProjectFlockKandangRepo: projectFlockKandangRepo,
ApprovalSvc: approvalSvc,
ExpenseBridge: expenseBridge,
approvalWorkflow: utils.ApprovalWorkflowPurchase,
}
}
func (s *purchaseService) withRelations(db *gorm.DB) *gorm.DB {
@@ -221,6 +225,7 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
productId uint
warehouseId uint
subQty float64
pfkID *uint
}
if len(req.Items) == 0 {
@@ -229,9 +234,9 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
warehouseCache := make(map[uint]*entity.Warehouse)
productSupplierCache := make(map[uint]bool)
getWarehouse := func(id uint) (*entity.Warehouse, error) {
getWarehouse := func(id uint) (*entity.Warehouse, *uint, error) {
if warehouse, ok := warehouseCache[id]; ok {
return warehouse, nil
return warehouse, nil, nil
}
warehouse, err := s.WarehouseRepo.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB {
return db.Preload("Area").Preload("Location")
@@ -239,21 +244,37 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Warehouse %d not found", id))
return nil, nil, fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Warehouse %d not found", id))
}
s.Log.Errorf("Failed to get warehouse %d: %+v", id, err)
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get warehouse")
return nil, nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get warehouse")
}
if warehouse.KandangId == nil || *warehouse.KandangId == 0 {
return nil, nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Warehouse %d is not linked to a kandang", id))
}
var pfkID *uint
if s.ProjectFlockKandangRepo != nil {
if pfk, err := s.ProjectFlockKandangRepo.GetActiveByKandangID(c.Context(), uint(*warehouse.KandangId)); err == nil && pfk != nil {
idCopy := uint(pfk.Id)
pfkID = &idCopy
} else if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Warehouse %d has no active project flock", id))
} else if err != nil {
s.Log.Errorf("Failed to validate project flock for warehouse %d: %+v", id, err)
return nil, nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate project flock")
}
}
warehouseCache[id] = warehouse
return warehouse, nil
return warehouse, pfkID, nil
}
aggregated := make([]*aggregatedItem, 0, len(req.Items))
indexMap := make(map[string]int)
for _, item := range req.Items {
if _, err := getWarehouse(item.WarehouseID); err != nil {
_, pfkID, err := getWarehouse(item.WarehouseID)
if err != nil {
return nil, err
}
@@ -282,6 +303,7 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
productId: productId,
warehouseId: warehouseId,
subQty: item.Quantity,
pfkID: pfkID,
}
aggregated = append(aggregated, entry)
indexMap[key] = len(aggregated) - 1
@@ -308,14 +330,15 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
emptyVehicle := ""
for _, item := range aggregated {
items = append(items, &entity.PurchaseItem{
ProductId: item.productId,
WarehouseId: item.warehouseId,
SubQty: item.subQty,
TotalQty: 0,
TotalUsed: 0,
Price: 0,
TotalPrice: 0,
VehicleNumber: &emptyVehicle,
ProductId: item.productId,
WarehouseId: item.warehouseId,
ProjectFlockKandangId: item.pfkID,
SubQty: item.subQty,
TotalQty: 0,
TotalUsed: 0,
Price: 0,
TotalPrice: 0,
VehicleNumber: &emptyVehicle,
})
}
@@ -332,6 +355,10 @@ func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchase
return err
}
if err := purchaseRepoTx.BackfillProjectFlockKandang(c.Context(), purchase.Id); err != nil {
return err
}
actorID := uint(purchase.CreatedBy)
if err := s.createPurchaseApproval(c.Context(), tx, purchase.Id, utils.PurchaseStepPengajuan, entity.ApprovalActionCreated, actorID, nil, false); err != nil {
return err