mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-25 15:55:44 +00:00
feat/BE/US-76/US-78/US-79/TASK-112,120,133,121-Recording growing/TASK-187,189,202,190-Recording Laying/TASK-191,192,194,197,203-Grading Telur
This commit is contained in:
@@ -208,7 +208,6 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
createBody := &entity.ProjectFlock{
|
createBody := &entity.ProjectFlock{
|
||||||
FlockName: "",
|
|
||||||
AreaId: req.AreaId,
|
AreaId: req.AreaId,
|
||||||
Category: cat,
|
Category: cat,
|
||||||
FcrId: req.FcrId,
|
FcrId: req.FcrId,
|
||||||
|
|||||||
@@ -170,104 +170,90 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := s.Repository.DB().WithContext(ctx).Begin()
|
var createdRecording entity.Recording
|
||||||
if tx.Error != nil {
|
transactionErr := s.Repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
s.Log.Errorf("Failed to start recording transaction: %+v", tx.Error)
|
|
||||||
return nil, tx.Error
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
_ = tx.Rollback()
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
nextDay, err := s.Repository.GenerateNextDay(tx, req.ProjectFlockKandangId)
|
nextDay, err := s.Repository.GenerateNextDay(tx, req.ProjectFlockKandangId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to determine recording day: %+v", err)
|
s.Log.Errorf("Failed to determine recording day: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
recordTime := time.Now().UTC()
|
recordTime := time.Now().UTC()
|
||||||
|
|
||||||
existsToday, err := s.Repository.ExistsOnDate(ctx, req.ProjectFlockKandangId, recordTime)
|
existsToday, err := s.Repository.ExistsOnDate(ctx, req.ProjectFlockKandangId, recordTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to verify existing recording on date: %+v", err)
|
s.Log.Errorf("Failed to verify existing recording on date: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
if existsToday {
|
if existsToday {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(fiber.StatusBadRequest, "Recording for this project flock today already exists")
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Recording for this project flock today already exists")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recording := &entity.Recording{
|
day := nextDay
|
||||||
|
createdRecording = entity.Recording{
|
||||||
ProjectFlockKandangId: req.ProjectFlockKandangId,
|
ProjectFlockKandangId: req.ProjectFlockKandangId,
|
||||||
RecordDatetime: recordTime,
|
RecordDatetime: recordTime,
|
||||||
Day: &nextDay,
|
Day: &day,
|
||||||
CreatedBy: 1, // TODO: replace with authenticated user
|
CreatedBy: 1, // TODO: replace with authenticated user
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Repository.CreateOne(ctx, recording, func(*gorm.DB) *gorm.DB { return tx }); err != nil {
|
if err := s.Repository.CreateOne(ctx, &createdRecording, func(*gorm.DB) *gorm.DB { return tx }); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Recording for project flock kandang %d already exists", req.ProjectFlockKandangId))
|
return fiber.NewError(
|
||||||
|
fiber.StatusBadRequest,
|
||||||
|
fmt.Sprintf("Recording for project flock kandang %d already exists", req.ProjectFlockKandangId),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
s.Log.Errorf("Failed to create recording: %+v", err)
|
s.Log.Errorf("Failed to create recording: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedBodyWeights := recordingutil.MapBodyWeights(recording.Id, req.BodyWeights)
|
mappedBodyWeights := recordingutil.MapBodyWeights(createdRecording.Id, req.BodyWeights)
|
||||||
if err := s.Repository.CreateBodyWeights(tx, mappedBodyWeights); err != nil {
|
if err := s.Repository.CreateBodyWeights(tx, mappedBodyWeights); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to persist body weights: %+v", err)
|
s.Log.Errorf("Failed to persist body weights: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
mappedStocks := recordingutil.MapStocks(recording.Id, req.Stocks)
|
|
||||||
|
mappedStocks := recordingutil.MapStocks(createdRecording.Id, req.Stocks)
|
||||||
if err := s.Repository.CreateStocks(tx, mappedStocks); err != nil {
|
if err := s.Repository.CreateStocks(tx, mappedStocks); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to persist stocks: %+v", err)
|
s.Log.Errorf("Failed to persist stocks: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
mappedDepletions := recordingutil.MapDepletions(recording.Id, req.Depletions)
|
|
||||||
|
mappedDepletions := recordingutil.MapDepletions(createdRecording.Id, req.Depletions)
|
||||||
if err := s.Repository.CreateDepletions(tx, mappedDepletions); err != nil {
|
if err := s.Repository.CreateDepletions(tx, mappedDepletions); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to persist depletions: %+v", err)
|
s.Log.Errorf("Failed to persist depletions: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
mappedEggs := recordingutil.MapEggs(recording.Id, recording.CreatedBy, req.Eggs)
|
|
||||||
|
mappedEggs := recordingutil.MapEggs(createdRecording.Id, createdRecording.CreatedBy, req.Eggs)
|
||||||
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
|
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to persist eggs: %+v", err)
|
s.Log.Errorf("Failed to persist eggs: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, mappedStocks, nil, mappedEggs)); err != nil {
|
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, mappedStocks, nil, mappedEggs)); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to adjust product warehouses: %+v", err)
|
s.Log.Errorf("Failed to adjust product warehouses: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.computeAndUpdateMetrics(ctx, tx, recording); err != nil {
|
if err := s.computeAndUpdateMetrics(ctx, tx, &createdRecording); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to compute recording metrics: %+v", err)
|
s.Log.Errorf("Failed to compute recording metrics: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
action := entity.ApprovalActionCreated
|
action := entity.ApprovalActionCreated
|
||||||
if err := s.createRecordingApproval(ctx, tx, recording.Id, utils.RecordingStepGradingTelur, action, recording.CreatedBy, nil); err != nil {
|
if err := s.createRecordingApproval(ctx, tx, createdRecording.Id, utils.RecordingStepGradingTelur, action, createdRecording.CreatedBy, nil); err != nil {
|
||||||
_ = tx.Rollback()
|
s.Log.Errorf("Failed to create recording approval for %d: %+v", createdRecording.Id, err)
|
||||||
s.Log.Errorf("Failed to create recording approval for %d: %+v", recording.Id, err)
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit().Error; err != nil {
|
return nil
|
||||||
s.Log.Errorf("Failed to commit recording transaction: %+v", err)
|
})
|
||||||
return nil, err
|
if transactionErr != nil {
|
||||||
|
return nil, transactionErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.GetOne(c, recording.Id)
|
return s.GetOne(c, createdRecording.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.Recording, error) {
|
func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.Recording, error) {
|
||||||
@@ -277,30 +263,19 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
|
|
||||||
ctx := c.Context()
|
ctx := c.Context()
|
||||||
|
|
||||||
tx := s.Repository.DB().WithContext(ctx).Begin()
|
var recordingEntity *entity.Recording
|
||||||
if tx.Error != nil {
|
transactionErr := s.Repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
s.Log.Errorf("Failed to start recording transaction: %+v", tx.Error)
|
|
||||||
return nil, tx.Error
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
_ = tx.Rollback()
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
recording, err := s.Repository.GetByID(ctx, id, func(db *gorm.DB) *gorm.DB {
|
recording, err := s.Repository.GetByID(ctx, id, func(db *gorm.DB) *gorm.DB {
|
||||||
return s.Repository.WithRelations(tx)
|
return s.Repository.WithRelations(tx)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Recording not found")
|
return fiber.NewError(fiber.StatusNotFound, "Recording not found")
|
||||||
}
|
}
|
||||||
s.Log.Errorf("Failed to find recording: %+v", err)
|
s.Log.Errorf("Failed to find recording: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
recordingEntity := recording
|
recordingEntity = recording
|
||||||
|
|
||||||
var category string
|
var category string
|
||||||
if recordingEntity.ProjectFlockKandang != nil && recordingEntity.ProjectFlockKandang.ProjectFlock.Id != 0 {
|
if recordingEntity.ProjectFlockKandang != nil && recordingEntity.ProjectFlockKandang.ProjectFlock.Id != 0 {
|
||||||
@@ -309,133 +284,125 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
isLaying := category == strings.ToUpper(string(utils.ProjectFlockCategoryLaying))
|
isLaying := category == strings.ToUpper(string(utils.ProjectFlockCategoryLaying))
|
||||||
if req.Eggs != nil {
|
if req.Eggs != nil {
|
||||||
if !isLaying && len(req.Eggs) > 0 {
|
if !isLaying && len(req.Eggs) > 0 {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(fiber.StatusBadRequest, "Egg details permitted only for laying project flocks")
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Egg details permitted only for laying project flocks")
|
|
||||||
}
|
}
|
||||||
if isLaying && len(req.Eggs) == 0 {
|
if isLaying && len(req.Eggs) == 0 {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(fiber.StatusBadRequest, "Egg details are required for laying project flocks")
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Egg details are required for laying project flocks")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.BodyWeights != nil {
|
if req.BodyWeights != nil {
|
||||||
if err := s.Repository.DeleteBodyWeights(tx, recordingEntity.Id); err != nil {
|
if err := s.Repository.DeleteBodyWeights(tx, recordingEntity.Id); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to clear body weights: %+v", err)
|
s.Log.Errorf("Failed to clear body weights: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.Repository.CreateBodyWeights(tx, recordingutil.MapBodyWeights(recordingEntity.Id, req.BodyWeights)); err != nil {
|
if err := s.Repository.CreateBodyWeights(tx, recordingutil.MapBodyWeights(recordingEntity.Id, req.BodyWeights)); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to update body weights: %+v", err)
|
s.Log.Errorf("Failed to update body weights: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Stocks != nil {
|
if req.Stocks != nil {
|
||||||
if err := s.ensureProductWarehousesExist(c, req.Stocks, nil, nil); err != nil {
|
if err := s.ensureProductWarehousesExist(c, req.Stocks, nil, nil); err != nil {
|
||||||
_ = tx.Rollback()
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
existingStocks, err := s.Repository.ListStocks(tx, recordingEntity.Id)
|
existingStocks, err := s.Repository.ListStocks(tx, recordingEntity.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to list existing stocks: %+v", err)
|
s.Log.Errorf("Failed to list existing stocks: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Repository.DeleteStocks(tx, recordingEntity.Id); err != nil {
|
if err := s.Repository.DeleteStocks(tx, recordingEntity.Id); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to clear stocks: %+v", err)
|
s.Log.Errorf("Failed to clear stocks: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedStocks := recordingutil.MapStocks(recordingEntity.Id, req.Stocks)
|
mappedStocks := recordingutil.MapStocks(recordingEntity.Id, req.Stocks)
|
||||||
if err := s.Repository.CreateStocks(tx, mappedStocks); err != nil {
|
if err := s.Repository.CreateStocks(tx, mappedStocks); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to update stocks: %+v", err)
|
s.Log.Errorf("Failed to update stocks: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingStocks, mappedStocks, nil, nil)); err != nil {
|
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingStocks, mappedStocks, nil, nil)); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to adjust product warehouses for stocks: %+v", err)
|
s.Log.Errorf("Failed to adjust product warehouses for stocks: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Eggs != nil && req.Depletions == nil {
|
if req.Eggs != nil && req.Depletions == nil {
|
||||||
if err := s.ensureProductWarehousesExist(c, nil, nil, req.Eggs); err != nil {
|
if err := s.ensureProductWarehousesExist(c, nil, nil, req.Eggs); err != nil {
|
||||||
_ = tx.Rollback()
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var existingDepletions []entity.RecordingDepletion
|
|
||||||
if req.Depletions != nil {
|
if req.Depletions != nil {
|
||||||
if err := s.ensureProductWarehousesExist(c, nil, req.Depletions, req.Eggs); err != nil {
|
if err := s.ensureProductWarehousesExist(c, nil, req.Depletions, req.Eggs); err != nil {
|
||||||
_ = tx.Rollback()
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
var err error
|
|
||||||
existingDepletions, err = s.Repository.ListDepletions(tx, recordingEntity.Id)
|
existingDepletions, err := s.Repository.ListDepletions(tx, recordingEntity.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to list existing depletions: %+v", err)
|
s.Log.Errorf("Failed to list existing depletions: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Repository.DeleteDepletions(tx, recordingEntity.Id); err != nil {
|
if err := s.Repository.DeleteDepletions(tx, recordingEntity.Id); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to clear depletions: %+v", err)
|
s.Log.Errorf("Failed to clear depletions: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedDepletions := recordingutil.MapDepletions(recordingEntity.Id, req.Depletions)
|
mappedDepletions := recordingutil.MapDepletions(recordingEntity.Id, req.Depletions)
|
||||||
if err := s.Repository.CreateDepletions(tx, mappedDepletions); err != nil {
|
if err := s.Repository.CreateDepletions(tx, mappedDepletions); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to update depletions: %+v", err)
|
s.Log.Errorf("Failed to update depletions: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(existingDepletions, mappedDepletions, nil, nil, nil, nil)); err != nil {
|
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(existingDepletions, mappedDepletions, nil, nil, nil, nil)); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to adjust product warehouses for depletions: %+v", err)
|
s.Log.Errorf("Failed to adjust product warehouses for depletions: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Eggs != nil {
|
if req.Eggs != nil {
|
||||||
existingEggs, err := s.Repository.ListEggs(tx, recordingEntity.Id)
|
existingEggs, err := s.Repository.ListEggs(tx, recordingEntity.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to list existing eggs: %+v", err)
|
s.Log.Errorf("Failed to list existing eggs: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Repository.DeleteEggs(tx, recordingEntity.Id); err != nil {
|
if err := s.Repository.DeleteEggs(tx, recordingEntity.Id); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to clear eggs: %+v", err)
|
s.Log.Errorf("Failed to clear eggs: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedEggs := recordingutil.MapEggs(recordingEntity.Id, recordingEntity.CreatedBy, req.Eggs)
|
mappedEggs := recordingutil.MapEggs(recordingEntity.Id, recordingEntity.CreatedBy, req.Eggs)
|
||||||
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
|
if err := s.Repository.CreateEggs(tx, mappedEggs); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to update eggs: %+v", err)
|
s.Log.Errorf("Failed to update eggs: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, nil, nil, existingEggs, mappedEggs)); err != nil {
|
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, nil, nil, existingEggs, mappedEggs)); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err)
|
s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.computeAndUpdateMetrics(ctx, tx, recordingEntity); err != nil {
|
if err := s.computeAndUpdateMetrics(ctx, tx, recordingEntity); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to recompute recording metrics: %+v", err)
|
s.Log.Errorf("Failed to recompute recording metrics: %+v", err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
action := entity.ApprovalActionUpdated
|
action := entity.ApprovalActionUpdated
|
||||||
if err := s.createRecordingApproval(ctx, tx, recordingEntity.Id, utils.RecordingStepPengajuan, action, recordingEntity.CreatedBy, nil); err != nil {
|
if err := s.createRecordingApproval(ctx, tx, recordingEntity.Id, utils.RecordingStepPengajuan, action, recordingEntity.CreatedBy, nil); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to create approval after recording update %d: %+v", recordingEntity.Id, err)
|
s.Log.Errorf("Failed to create approval after recording update %d: %+v", recordingEntity.Id, err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit().Error; err != nil {
|
return nil
|
||||||
s.Log.Errorf("Failed to commit recording transaction: %+v", err)
|
})
|
||||||
return nil, err
|
if transactionErr != nil {
|
||||||
|
return nil, transactionErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.GetOne(c, id)
|
return s.GetOne(c, id)
|
||||||
@@ -446,30 +413,29 @@ func (s *recordingService) SubmitGrading(c *fiber.Ctx, req *validation.SubmitGra
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := c.Context()
|
if len(req.EggsGrading) == 0 {
|
||||||
tx := s.Repository.DB().WithContext(ctx).Begin()
|
return nil, fiber.NewError(fiber.StatusBadRequest, "eggs_grading must contain at least one item")
|
||||||
if tx.Error != nil {
|
|
||||||
s.Log.Errorf("Failed to start grading transaction: %+v", tx.Error)
|
|
||||||
return nil, tx.Error
|
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
_ = tx.Rollback()
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
recordingEgg, err := s.Repository.GetRecordingEggByID(ctx, req.RecordingEggId, func(db *gorm.DB) *gorm.DB {
|
recordingEggID := req.EggsGrading[0].RecordingEggId
|
||||||
|
for _, grading := range req.EggsGrading[1:] {
|
||||||
|
if grading.RecordingEggId != recordingEggID {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "semua grading harus untuk recording egg yang sama")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := c.Context()
|
||||||
|
var recordingID uint
|
||||||
|
transactionErr := s.Repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
|
recordingEgg, err := s.Repository.GetRecordingEggByID(ctx, recordingEggID, func(db *gorm.DB) *gorm.DB {
|
||||||
return tx
|
return tx
|
||||||
})
|
})
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(fiber.StatusNotFound, "Recording egg not found")
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Recording egg not found")
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
s.Log.Errorf("Failed to get recording egg %d: %+v", recordingEggID, err)
|
||||||
s.Log.Errorf("Failed to get recording egg %d: %+v", req.RecordingEggId, err)
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var category string
|
var category string
|
||||||
@@ -477,8 +443,7 @@ func (s *recordingService) SubmitGrading(c *fiber.Ctx, req *validation.SubmitGra
|
|||||||
category = strings.ToUpper(recordingEgg.Recording.ProjectFlockKandang.ProjectFlock.Category)
|
category = strings.ToUpper(recordingEgg.Recording.ProjectFlockKandang.ProjectFlock.Category)
|
||||||
}
|
}
|
||||||
if category != strings.ToUpper(string(utils.ProjectFlockCategoryLaying)) {
|
if category != strings.ToUpper(string(utils.ProjectFlockCategoryLaying)) {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(fiber.StatusBadRequest, "Grading eggs hanya diperbolehkan pada project flock dengan kategori laying")
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Grading eggs hanya diperbolehkan pada project flock dengan kategori laying")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
totalGradingQty := 0.0
|
totalGradingQty := 0.0
|
||||||
@@ -488,8 +453,7 @@ func (s *recordingService) SubmitGrading(c *fiber.Ctx, req *validation.SubmitGra
|
|||||||
|
|
||||||
availableRecorded := float64(recordingEgg.Qty)
|
availableRecorded := float64(recordingEgg.Qty)
|
||||||
if totalGradingQty > availableRecorded {
|
if totalGradingQty > availableRecorded {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(
|
||||||
return nil, fiber.NewError(
|
|
||||||
fiber.StatusBadRequest,
|
fiber.StatusBadRequest,
|
||||||
fmt.Sprintf("Total grading (%.2f) melebihi jumlah telur tercatat (%.2f)", totalGradingQty, availableRecorded),
|
fmt.Sprintf("Total grading (%.2f) melebihi jumlah telur tercatat (%.2f)", totalGradingQty, availableRecorded),
|
||||||
)
|
)
|
||||||
@@ -498,8 +462,7 @@ func (s *recordingService) SubmitGrading(c *fiber.Ctx, req *validation.SubmitGra
|
|||||||
if recordingEgg.ProductWarehouse.Id != 0 {
|
if recordingEgg.ProductWarehouse.Id != 0 {
|
||||||
availableWarehouse := recordingEgg.ProductWarehouse.Quantity
|
availableWarehouse := recordingEgg.ProductWarehouse.Quantity
|
||||||
if totalGradingQty > availableWarehouse {
|
if totalGradingQty > availableWarehouse {
|
||||||
_ = tx.Rollback()
|
return fiber.NewError(
|
||||||
return nil, fiber.NewError(
|
|
||||||
fiber.StatusBadRequest,
|
fiber.StatusBadRequest,
|
||||||
fmt.Sprintf("Total grading (%.2f) melebihi stok telur baik (%.2f)", totalGradingQty, availableWarehouse),
|
fmt.Sprintf("Total grading (%.2f) melebihi stok telur baik (%.2f)", totalGradingQty, availableWarehouse),
|
||||||
)
|
)
|
||||||
@@ -507,9 +470,8 @@ func (s *recordingService) SubmitGrading(c *fiber.Ctx, req *validation.SubmitGra
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Repository.DeleteGradingEggs(tx, recordingEgg.Id); err != nil {
|
if err := s.Repository.DeleteGradingEggs(tx, recordingEgg.Id); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to clear grading eggs for recording egg %d: %+v", recordingEgg.Id, err)
|
s.Log.Errorf("Failed to clear grading eggs for recording egg %d: %+v", recordingEgg.Id, err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gradings := make([]entity.GradingEgg, 0, len(req.EggsGrading))
|
gradings := make([]entity.GradingEgg, 0, len(req.EggsGrading))
|
||||||
@@ -528,25 +490,25 @@ func (s *recordingService) SubmitGrading(c *fiber.Ctx, req *validation.SubmitGra
|
|||||||
|
|
||||||
if len(gradings) > 0 {
|
if len(gradings) > 0 {
|
||||||
if err := s.Repository.CreateGradingEggs(tx, gradings); err != nil {
|
if err := s.Repository.CreateGradingEggs(tx, gradings); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to persist grading eggs for recording egg %d: %+v", recordingEgg.Id, err)
|
s.Log.Errorf("Failed to persist grading eggs for recording egg %d: %+v", recordingEgg.Id, err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action := entity.ApprovalActionUpdated
|
action := entity.ApprovalActionUpdated
|
||||||
if err := s.createRecordingApproval(ctx, tx, recordingEgg.RecordingId, utils.RecordingStepPengajuan, action, createdBy, nil); err != nil {
|
if err := s.createRecordingApproval(ctx, tx, recordingEgg.RecordingId, utils.RecordingStepPengajuan, action, createdBy, nil); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to create approval after grading for recording %d: %+v", recordingEgg.RecordingId, err)
|
s.Log.Errorf("Failed to create approval after grading for recording %d: %+v", recordingEgg.RecordingId, err)
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit().Error; err != nil {
|
recordingID = recordingEgg.RecordingId
|
||||||
s.Log.Errorf("Failed to commit grading transaction: %+v", err)
|
return nil
|
||||||
return nil, err
|
})
|
||||||
|
if transactionErr != nil {
|
||||||
|
return nil, transactionErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.GetOne(c, recordingEgg.RecordingId)
|
return s.GetOne(c, recordingID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s recordingService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.Recording, error) {
|
func (s recordingService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.Recording, error) {
|
||||||
@@ -629,37 +591,30 @@ func (s recordingService) Approval(c *fiber.Ctx, req *validation.Approve) ([]ent
|
|||||||
func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error {
|
func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||||
ctx := c.Context()
|
ctx := c.Context()
|
||||||
|
|
||||||
tx := s.Repository.DB().WithContext(ctx).Begin()
|
return s.Repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
if tx.Error != nil {
|
|
||||||
return tx.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
oldDepletions, err := s.Repository.ListDepletions(tx, id)
|
oldDepletions, err := s.Repository.ListDepletions(tx, id)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to list depletions before delete: %+v", err)
|
s.Log.Errorf("Failed to list depletions before delete: %+v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldEggs, err := s.Repository.ListEggs(tx, id)
|
oldEggs, err := s.Repository.ListEggs(tx, id)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to list eggs before delete: %+v", err)
|
s.Log.Errorf("Failed to list eggs before delete: %+v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
oldStocks, err := s.Repository.ListStocks(tx, id)
|
oldStocks, err := s.Repository.ListStocks(tx, id)
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
_ = tx.Rollback()
|
|
||||||
s.Log.Errorf("Failed to list stocks before delete: %+v", err)
|
s.Log.Errorf("Failed to list stocks before delete: %+v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(oldDepletions, nil, oldStocks, nil, oldEggs, nil)); err != nil {
|
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(oldDepletions, nil, oldStocks, nil, oldEggs, nil)); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.Repository.WithTx(tx).DeleteOne(ctx, id); err != nil {
|
if err := s.Repository.WithTx(tx).DeleteOne(ctx, id); err != nil {
|
||||||
_ = tx.Rollback()
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return fiber.NewError(fiber.StatusNotFound, "Recording not found")
|
return fiber.NewError(fiber.StatusNotFound, "Recording not found")
|
||||||
}
|
}
|
||||||
@@ -667,11 +622,8 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit().Error; err != nil {
|
|
||||||
s.Log.Errorf("Failed to commit delete recording transaction: %+v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Persistence Helpers ===
|
// === Persistence Helpers ===
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type (
|
|||||||
|
|
||||||
Stock struct {
|
Stock struct {
|
||||||
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"`
|
ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,number,min=1"`
|
||||||
UsageAmount *float64 `json:"usage_amount,omitempty" validate:"omitempty,gte=0"`
|
Qty *float64 `json:"qty,omitempty" validate:"required_without=UsageAmount,gte=0"`
|
||||||
PendingQty *float64 `json:"pending_qty,omitempty" validate:"omitempty,gte=0"`
|
PendingQty *float64 `json:"pending_qty,omitempty" validate:"omitempty,gte=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +46,12 @@ type Query struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EggGrading struct {
|
type EggGrading struct {
|
||||||
|
RecordingEggId uint `json:"recording_egg_id" validate:"required,number,min=1"`
|
||||||
Grade string `json:"grade" validate:"required"`
|
Grade string `json:"grade" validate:"required"`
|
||||||
Qty float64 `json:"qty" validate:"required,gte=0"`
|
Qty float64 `json:"qty" validate:"required,gte=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubmitGrading struct {
|
type SubmitGrading struct {
|
||||||
RecordingEggId uint `json:"recording_egg_id" validate:"required,number,min=1"`
|
|
||||||
EggsGrading []EggGrading `json:"eggs_grading" validate:"required,dive"`
|
EggsGrading []EggGrading `json:"eggs_grading" validate:"required,dive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,11 +35,21 @@ func MapStocks(recordingID uint, items []validation.Stock) []entity.RecordingSto
|
|||||||
|
|
||||||
result := make([]entity.RecordingStock, 0, len(items))
|
result := make([]entity.RecordingStock, 0, len(items))
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
|
var usageAmount float64
|
||||||
|
if item.Qty != nil {
|
||||||
|
usageAmount = *item.Qty
|
||||||
|
}
|
||||||
|
usagePtr := new(float64)
|
||||||
|
*usagePtr = usageAmount
|
||||||
|
pending := item.PendingQty
|
||||||
|
if pending == nil {
|
||||||
|
pending = new(float64)
|
||||||
|
}
|
||||||
result = append(result, entity.RecordingStock{
|
result = append(result, entity.RecordingStock{
|
||||||
RecordingId: recordingID,
|
RecordingId: recordingID,
|
||||||
ProductWarehouseId: item.ProductWarehouseId,
|
ProductWarehouseId: item.ProductWarehouseId,
|
||||||
UsageQty: item.UsageAmount,
|
UsageQty: usagePtr,
|
||||||
PendingQty: item.PendingQty,
|
PendingQty: pending,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|||||||
Reference in New Issue
Block a user