mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 23:35:43 +00:00
[FEAT/BE] wiring recording,transfer_stock,transfer_laying,marketing for consumer chick in project flock population
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
sChickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/services"
|
||||
|
||||
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
rTransferLaying "gitlab.com/mbugroup/lti-api.git/internal/modules/production/transfer_layings/repositories"
|
||||
|
||||
rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories"
|
||||
sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||
@@ -36,6 +37,7 @@ func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
|
||||
projectflockkandangrepo := rProjectFlock.NewProjectFlockKandangRepository(db)
|
||||
projectflockpopulationrepo := rProjectFlock.NewProjectFlockPopulationRepository(db)
|
||||
projectFlockRepo := rProjectFlock.NewProjectflockRepository(db)
|
||||
transferLayingRepo := rTransferLaying.NewTransferLayingRepository(db)
|
||||
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
|
||||
productRepo := rProduct.NewProductRepository(db)
|
||||
fifoStockV2Service := commonSvc.NewFifoStockV2Service(db, utils.Log)
|
||||
@@ -57,6 +59,7 @@ func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
|
||||
projectflockkandangrepo,
|
||||
projectflockpopulationrepo,
|
||||
chickinDetailRepo,
|
||||
transferLayingRepo,
|
||||
validate,
|
||||
fifoStockV2Service)
|
||||
userService := sUser.NewUserService(userRepo, validate)
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/validations"
|
||||
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
rTransferLaying "gitlab.com/mbugroup/lti-api.git/internal/modules/production/transfer_layings/repositories"
|
||||
rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
|
||||
@@ -51,11 +52,12 @@ type chickinService struct {
|
||||
ProjectflockKandangRepo rProjectFlock.ProjectFlockKandangRepository
|
||||
ProjectflockPopulationRepo rProjectFlock.ProjectFlockPopulationRepository
|
||||
ProjectChickinDetailRepo repository.ProjectChickinDetailRepository
|
||||
TransferLayingRepo rTransferLaying.TransferLayingRepository
|
||||
FifoStockV2Svc commonSvc.FifoStockV2Service
|
||||
StockLogRepo rStockLogs.StockLogRepository
|
||||
}
|
||||
|
||||
func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo KandangRepo.KandangRepository, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, productRepo rProduct.ProductRepository, projectFlockRepo rProjectFlock.ProjectflockRepository, projectflockkandangRepo rProjectFlock.ProjectFlockKandangRepository, projectflockpopulationRepo rProjectFlock.ProjectFlockPopulationRepository, projectChickinDetailRepo repository.ProjectChickinDetailRepository, validate *validator.Validate, fifoStockV2Svc commonSvc.FifoStockV2Service) ChickinService {
|
||||
func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo KandangRepo.KandangRepository, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, productRepo rProduct.ProductRepository, projectFlockRepo rProjectFlock.ProjectflockRepository, projectflockkandangRepo rProjectFlock.ProjectFlockKandangRepository, projectflockpopulationRepo rProjectFlock.ProjectFlockPopulationRepository, projectChickinDetailRepo repository.ProjectChickinDetailRepository, transferLayingRepo rTransferLaying.TransferLayingRepository, validate *validator.Validate, fifoStockV2Svc commonSvc.FifoStockV2Service) ChickinService {
|
||||
return &chickinService{
|
||||
Log: utils.Log,
|
||||
Validate: validate,
|
||||
@@ -68,6 +70,7 @@ func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo Kan
|
||||
ProjectflockKandangRepo: projectflockkandangRepo,
|
||||
ProjectflockPopulationRepo: projectflockpopulationRepo,
|
||||
ProjectChickinDetailRepo: projectChickinDetailRepo,
|
||||
TransferLayingRepo: transferLayingRepo,
|
||||
FifoStockV2Svc: fifoStockV2Svc,
|
||||
StockLogRepo: rStockLogs.NewStockLogRepository(repo.DB()),
|
||||
}
|
||||
@@ -120,11 +123,36 @@ func (s chickinService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectChickin, e
|
||||
return chickin, nil
|
||||
}
|
||||
|
||||
func (s chickinService) ensureNotTransferred(ctx context.Context, projectFlockKandangID uint) error {
|
||||
if projectFlockKandangID == 0 || s.TransferLayingRepo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
transfer, err := s.TransferLayingRepo.GetLatestApprovedBySourceKandang(ctx, projectFlockKandangID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil
|
||||
}
|
||||
s.Log.Errorf("Failed to resolve transfer laying by source kandang %d: %+v", projectFlockKandangID, err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memvalidasi transfer laying")
|
||||
}
|
||||
|
||||
if transfer != nil && transfer.ExecutedAt != nil && !transfer.ExecutedAt.IsZero() {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Project flock kandang sudah dipindahkan ke laying")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]entity.ProjectChickin, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.ensureNotTransferred(c.Context(), req.ProjectFlockKandangId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectFlockKandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), req.ProjectFlockKandangId)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Project Flock Kandang not found")
|
||||
@@ -334,6 +362,17 @@ func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chickin, err := s.Repository.GetByID(c.Context(), id, nil)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Chickin not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if err := s.ensureNotTransferred(c.Context(), chickin.ProjectFlockKandangId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updateBody := make(map[string]any)
|
||||
|
||||
if req.ChickInDate != "" {
|
||||
@@ -377,6 +416,10 @@ func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.ensureNotTransferred(c.Context(), chickin.ProjectFlockKandangId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actorID, err := m.ActorIDFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -446,6 +489,9 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
if err := commonSvc.EnsureRelations(c.Context(), commonSvc.RelationCheck{Name: "ProjectFlockKandang", ID: &id, Exists: s.ProjectflockKandangRepo.IdExists}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.ensureNotTransferred(c.Context(), id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
latestApproval, err := approvalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowChickin, id, nil)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -98,6 +98,7 @@ func (RecordingModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate
|
||||
projectFlockKandangRepo,
|
||||
projectFlockPopulationRepo,
|
||||
chickinDetailRepo,
|
||||
transferLayingRepo,
|
||||
validate,
|
||||
fifoStockV2Service,
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
fifoV2 "gitlab.com/mbugroup/lti-api.git/internal/common/service/fifo_stock_v2"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
fifo "gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
|
||||
recordingutil "gitlab.com/mbugroup/lti-api.git/internal/utils/recording"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
@@ -416,6 +418,10 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
|
||||
if err := s.reflowApplyRecordingDepletionsIn(ctx, tx, mappedDepletions); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Repository.ResyncProjectFlockPopulationUsage(ctx, tx, createdRecording.ProjectFlockKandangId); err != nil {
|
||||
s.Log.Errorf("Failed to resync project flock population usage: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
mappedEggs := recordingutil.MapEggs(createdRecording.Id, createdRecording.CreatedBy, req.Eggs)
|
||||
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
|
||||
@@ -951,6 +957,13 @@ func (s *recordingService) enforceTransferRecordingRoute(
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal memvalidasi transfer laying")
|
||||
}
|
||||
|
||||
if transfer != nil && transfer.ExecutedAt != nil && !transfer.ExecutedAt.IsZero() {
|
||||
return fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
"Project flock kandang sudah dipindahkan ke laying",
|
||||
)
|
||||
}
|
||||
|
||||
effectiveDate := effectiveTransferDate(transfer)
|
||||
if effectiveDate.IsZero() {
|
||||
return nil
|
||||
@@ -1835,6 +1848,14 @@ func (s *recordingService) reflowApplyRecordingDepletionsOut(
|
||||
}
|
||||
s.logDepletionTrace("reflow_apply:done", *refreshed, fmt.Sprintf("desired=%.3f used=%.3f pending=%.3f", desired, refreshed.UsageQty, refreshed.PendingQty))
|
||||
|
||||
consumeQty := refreshed.UsageQty
|
||||
if refreshed.PendingQty > 0 {
|
||||
consumeQty += refreshed.PendingQty
|
||||
}
|
||||
if err := s.allocatePopulationForDepletion(ctx, tx, *refreshed, consumeQty); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logDecrease := refreshed.UsageQty
|
||||
if refreshed.PendingQty > 0 {
|
||||
logDecrease += refreshed.PendingQty
|
||||
@@ -1894,11 +1915,15 @@ func (s *recordingService) reflowResetRecordingDepletionsOut(
|
||||
return errors.New("stock log repository is not available")
|
||||
}
|
||||
logState := newRecordingStockLogState()
|
||||
stockAllocationRepo := commonRepo.NewStockAllocationRepository(tx)
|
||||
|
||||
for _, depletion := range depletions {
|
||||
if depletion.Id == 0 {
|
||||
continue
|
||||
}
|
||||
if err := stockAllocationRepo.ReleaseByUsable(ctx, fifo.UsableKeyRecordingDepletion.String(), depletion.Id, nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
s.logDepletionTrace("reflow_reset:start", depletion, "")
|
||||
|
||||
sourceWarehouseID := uint(0)
|
||||
@@ -1979,6 +2004,58 @@ func (s *recordingService) reflowResetRecordingDepletionsOut(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *recordingService) allocatePopulationForDepletion(
|
||||
ctx context.Context,
|
||||
tx *gorm.DB,
|
||||
depletion entity.RecordingDepletion,
|
||||
consumeQty float64,
|
||||
) error {
|
||||
if consumeQty <= 0 {
|
||||
return nil
|
||||
}
|
||||
if tx == nil {
|
||||
return errors.New("transaction is required")
|
||||
}
|
||||
|
||||
sourceWarehouseID := uint(0)
|
||||
if depletion.SourceProductWarehouseId != nil {
|
||||
sourceWarehouseID = *depletion.SourceProductWarehouseId
|
||||
}
|
||||
if sourceWarehouseID == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Source product warehouse populasi tidak ditemukan")
|
||||
}
|
||||
|
||||
var projectFlockKandangID uint
|
||||
if err := tx.WithContext(ctx).
|
||||
Table("recordings").
|
||||
Select("project_flock_kandangs_id").
|
||||
Where("id = ?", depletion.RecordingId).
|
||||
Scan(&projectFlockKandangID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if projectFlockKandangID == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Project flock kandang tidak ditemukan untuk depletion")
|
||||
}
|
||||
|
||||
populations, err := s.ProjectFlockPopulationRepo.GetByProjectFlockKandangIDAndProductWarehouseID(ctx, projectFlockKandangID, sourceWarehouseID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(populations) == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Populasi tidak ditemukan untuk depletion")
|
||||
}
|
||||
|
||||
return fifoV2.AllocatePopulationConsumption(
|
||||
ctx,
|
||||
tx,
|
||||
populations,
|
||||
sourceWarehouseID,
|
||||
fifo.UsableKeyRecordingDepletion.String(),
|
||||
depletion.Id,
|
||||
consumeQty,
|
||||
)
|
||||
}
|
||||
|
||||
func (s *recordingService) reflowApplyRecordingDepletionsIn(
|
||||
ctx context.Context,
|
||||
tx *gorm.DB,
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
fifoV2 "gitlab.com/mbugroup/lti-api.git/internal/common/service/fifo_stock_v2"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/config"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||
@@ -1005,6 +1006,9 @@ func (s *transferLayingService) executeApprovedTransferMovement(
|
||||
}
|
||||
|
||||
movedQty := usageDelta
|
||||
if err := s.allocatePopulationForTransfer(ctx, tx, source, movedQty); err != nil {
|
||||
return err
|
||||
}
|
||||
targetShares := distributeProportionalWithRounding(targets, totalTargetQty, movedQty)
|
||||
for i, target := range targets {
|
||||
roundedQty := math.Round(targetShares[i])
|
||||
@@ -1104,6 +1108,45 @@ func (s *transferLayingService) executeApprovedTransferMovement(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *transferLayingService) allocatePopulationForTransfer(
|
||||
ctx context.Context,
|
||||
tx *gorm.DB,
|
||||
source entity.LayingTransferSource,
|
||||
consumeQty float64,
|
||||
) error {
|
||||
if consumeQty <= 0 {
|
||||
return nil
|
||||
}
|
||||
if tx == nil {
|
||||
return errors.New("transaction is required")
|
||||
}
|
||||
if source.SourceProjectFlockKandangId == 0 || source.ProductWarehouseId == nil || *source.ProductWarehouseId == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Project flock kandang sumber atau product warehouse tidak valid")
|
||||
}
|
||||
|
||||
populations, err := s.ProjectFlockPopulationRepo.GetByProjectFlockKandangIDAndProductWarehouseID(
|
||||
ctx,
|
||||
source.SourceProjectFlockKandangId,
|
||||
*source.ProductWarehouseId,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(populations) == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Populasi tidak ditemukan untuk transfer laying")
|
||||
}
|
||||
|
||||
return fifoV2.AllocatePopulationConsumption(
|
||||
ctx,
|
||||
tx,
|
||||
populations,
|
||||
*source.ProductWarehouseId,
|
||||
fifo.UsableKeyTransferToLayingOut.String(),
|
||||
source.Id,
|
||||
consumeQty,
|
||||
)
|
||||
}
|
||||
|
||||
func (s *transferLayingService) calculateEffectiveMoveDate(ctx context.Context, sources []entity.LayingTransferSource) (time.Time, error) {
|
||||
if len(sources) == 0 {
|
||||
return time.Time{}, fiber.NewError(fiber.StatusBadRequest, "Sumber transfer laying tidak ditemukan")
|
||||
|
||||
Reference in New Issue
Block a user