mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
FIX[BE]: fix logic on Chickin Laying not convert to layer but still Pullet, and inisiate laying transfer migration and base basic API
This commit is contained in:
@@ -150,8 +150,12 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
|
||||
actorID := uint(1) // todo nanti ambil dari auth context
|
||||
newChikins := make([]*entity.ProjectChickin, 0)
|
||||
for _, productWarehouse := range productWarehouses {
|
||||
availableQty, err := s.calculateAvailableQuantity(c, req.ProjectFlockKandangId, &productWarehouse, category)
|
||||
if err != nil {
|
||||
s.Log.Warnf("Failed to calculate available quantity for product warehouse %d: %v", productWarehouse.Id, err)
|
||||
}
|
||||
|
||||
if productWarehouse.Quantity <= 0 {
|
||||
if availableQty <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -159,7 +163,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
|
||||
ProjectFlockKandangId: req.ProjectFlockKandangId,
|
||||
ChickInDate: chickinDate,
|
||||
UsageQty: 0,
|
||||
PendingUsageQty: productWarehouse.Quantity,
|
||||
PendingUsageQty: availableQty,
|
||||
ProductWarehouseId: productWarehouse.Id,
|
||||
Notes: req.Note,
|
||||
CreatedBy: actorID,
|
||||
@@ -176,6 +180,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to check existing chickins")
|
||||
}
|
||||
|
||||
isFirstTime := len(existingChikins) == 0
|
||||
|
||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||
@@ -192,17 +197,19 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]enti
|
||||
return err
|
||||
}
|
||||
|
||||
for _, chickin := range newChikins {
|
||||
if category == string(utils.ProjectFlockCategoryLaying) {
|
||||
for _, chickin := range newChikins {
|
||||
updates := map[string]any{"quantity": gorm.Expr("quantity - ?", chickin.PendingUsageQty)}
|
||||
|
||||
updates := map[string]any{"quantity": 0}
|
||||
|
||||
if err := productWarehouseTx.PatchOne(c.Context(), chickin.ProductWarehouseId, updates, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Product warehouse %d not found", chickin.ProductWarehouseId))
|
||||
if err := productWarehouseTx.PatchOne(c.Context(), chickin.ProductWarehouseId, updates, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Product warehouse %d not found", chickin.ProductWarehouseId))
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update product warehouse quantity")
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update product warehouse quantity")
|
||||
}
|
||||
}
|
||||
|
||||
var approvalAction entity.ApprovalAction
|
||||
if isFirstTime {
|
||||
approvalAction = entity.ApprovalActionCreated
|
||||
@@ -287,6 +294,56 @@ func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s chickinService) calculateAvailableQuantity(ctx *fiber.Ctx, projectFlockKandangID uint, productWarehouse *entity.ProductWarehouse, category string) (float64, error) {
|
||||
availableQty := productWarehouse.Quantity
|
||||
|
||||
if category == string(utils.ProjectFlockCategoryGrowing) {
|
||||
var totalPendingQty float64
|
||||
|
||||
chickins, err := s.Repository.GetByProjectFlockKandangID(ctx.Context(), projectFlockKandangID)
|
||||
if err == nil {
|
||||
for _, chickin := range chickins {
|
||||
|
||||
if chickin.ProductWarehouseId == productWarehouse.Id && chickin.DeletedAt.Time.IsZero() && chickin.PendingUsageQty > 0 {
|
||||
totalPendingQty += chickin.PendingUsageQty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
availableQty = productWarehouse.Quantity - totalPendingQty
|
||||
if availableQty < 0 {
|
||||
availableQty = 0
|
||||
}
|
||||
} else if category == string(utils.ProjectFlockCategoryLaying) {
|
||||
var totalPopulation float64
|
||||
var totalPendingQty float64
|
||||
|
||||
populations, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangIDAndProductWarehouseID(ctx.Context(), projectFlockKandangID, productWarehouse.Id)
|
||||
if err == nil {
|
||||
for _, pop := range populations {
|
||||
totalPopulation += pop.TotalQty
|
||||
}
|
||||
}
|
||||
|
||||
chickins, err := s.Repository.GetByProjectFlockKandangID(ctx.Context(), projectFlockKandangID)
|
||||
if err == nil {
|
||||
for _, chickin := range chickins {
|
||||
|
||||
if chickin.ProductWarehouseId == productWarehouse.Id && chickin.DeletedAt.Time.IsZero() && chickin.PendingUsageQty > 0 {
|
||||
totalPendingQty += chickin.PendingUsageQty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
availableQty = productWarehouse.Quantity - totalPopulation - totalPendingQty
|
||||
if availableQty < 0 {
|
||||
availableQty = 0
|
||||
}
|
||||
}
|
||||
|
||||
return availableQty, nil
|
||||
}
|
||||
|
||||
func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.ProjectChickin, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
@@ -356,7 +413,7 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
if !(strings.Contains(lower, "duplicate") || strings.Contains(lower, "unique constraint") || strings.Contains(lower, "23505")) {
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("ignored duplicate approval for kandang %d: %v", approvableID, err)
|
||||
|
||||
}
|
||||
|
||||
if action == entity.ApprovalActionApproved {
|
||||
@@ -374,54 +431,76 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
return err
|
||||
}
|
||||
|
||||
warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), kandangForApproval.KandangId)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Warehouse for kandang %d not found", kandangForApproval.KandangId))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
category := strings.ToUpper(strings.TrimSpace(kandangForApproval.ProjectFlock.Category))
|
||||
var conversionCategoryCode string
|
||||
|
||||
switch category {
|
||||
case string(utils.ProjectFlockCategoryGrowing):
|
||||
conversionCategoryCode = "PULLET"
|
||||
case string(utils.ProjectFlockCategoryLaying):
|
||||
conversionCategoryCode = "LAYER"
|
||||
default:
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Unknown category for conversion: %s", category))
|
||||
if category == string(utils.ProjectFlockCategoryGrowing) {
|
||||
warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), kandangForApproval.KandangId)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Warehouse for kandang %d not found", kandangForApproval.KandangId))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
targetPW, err := s.getOrCreateProductWarehouse(c, warehouse.Id, "PULLET", dbTransaction, actorID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get/create PULLET product warehouse: %w", err)
|
||||
}
|
||||
if err := s.convertChickinsToTarget(c, chickins, targetPW, dbTransaction, actorID); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if category == string(utils.ProjectFlockCategoryLaying) {
|
||||
|
||||
warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), kandangForApproval.KandangId)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Warehouse for kandang %d not found", kandangForApproval.KandangId))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
targetPW, err := s.getOrCreateProductWarehouse(c, warehouse.Id, "PULLET", dbTransaction, actorID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get/create PULLET product warehouse: %w", err)
|
||||
}
|
||||
if err := s.convertChickinsToTarget(c, chickins, targetPW, dbTransaction, actorID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
targetPW, err := s.getOrCreateProductWarehouse(c, warehouse.Id, conversionCategoryCode, dbTransaction, actorID)
|
||||
if action == entity.ApprovalActionRejected {
|
||||
|
||||
chickins, err := chickinRepoTx.GetPendingByProjectFlockKandangID(c.Context(), approvableID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get/create %s product warehouse: %w", conversionCategoryCode, err)
|
||||
}
|
||||
if err := s.convertChickinsToTarget(c, chickins, targetPW, dbTransaction, actorID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else if action == entity.ApprovalActionRejected {
|
||||
|
||||
chickins, err := chickinRepoTx.GetByProjectFlockKandangID(c.Context(), approvableID)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("failed to get chickins for rejection %d: %w", approvableID, err)
|
||||
return fmt.Errorf("failed to get pending chickins for rejection %d: %w", approvableID, err)
|
||||
}
|
||||
|
||||
if len(chickins) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
kandangForRejection, err := s.ProjectflockKandangRepo.GetByID(c.Context(), approvableID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("ProjectFlockKandang %d not found", approvableID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
categoryForRejection := strings.ToUpper(strings.TrimSpace(kandangForRejection.ProjectFlock.Category))
|
||||
|
||||
for _, chickin := range chickins {
|
||||
|
||||
updates := map[string]any{"quantity": chickin.PendingUsageQty}
|
||||
if categoryForRejection == string(utils.ProjectFlockCategoryGrowing) {
|
||||
updates := map[string]any{"quantity": gorm.Expr("quantity + ?", chickin.PendingUsageQty)}
|
||||
|
||||
if err := productWarehouseTx.PatchOne(c.Context(), chickin.ProductWarehouseId, updates, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Product warehouse %d not found during rejection", chickin.ProductWarehouseId))
|
||||
if err := productWarehouseTx.PatchOne(c.Context(), chickin.ProductWarehouseId, updates, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Product warehouse %d not found during rejection", chickin.ProductWarehouseId))
|
||||
}
|
||||
return fmt.Errorf("failed to restore product warehouse quantity for chickin %d: %w", chickin.Id, err)
|
||||
}
|
||||
return fmt.Errorf("failed to restore product warehouse quantity for chickin %d: %w", chickin.Id, err)
|
||||
}
|
||||
|
||||
if err := chickinRepoTx.DeleteOne(c.Context(), chickin.Id); err != nil {
|
||||
@@ -518,6 +597,18 @@ func (s *chickinService) convertChickinsToTarget(ctx *fiber.Ctx, chickins []enti
|
||||
return fmt.Errorf("failed to update chickin %d qty: %w", chickin.Id, err)
|
||||
}
|
||||
|
||||
if chickin.ProductWarehouseId != targetPW.Id {
|
||||
if err := productWarehouseTx.PatchOne(ctx.Context(), chickin.ProductWarehouseId, map[string]any{
|
||||
"quantity": gorm.Expr("quantity - ?", quantityToConvert),
|
||||
}, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Source product warehouse %d not found", chickin.ProductWarehouseId))
|
||||
}
|
||||
return fmt.Errorf("failed to deduct source warehouse quantity for chickin %d: %w", chickin.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add to target product warehouse
|
||||
if err := productWarehouseTx.PatchOne(ctx.Context(), targetPW.Id, map[string]any{
|
||||
"quantity": gorm.Expr("quantity + ?", quantityToConvert),
|
||||
}, nil); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user