mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE-281): unfinished uniformity and create project flock triger productwarehouse and add new filtering lookup
This commit is contained in:
@@ -268,6 +268,7 @@ func (u *ProjectflockController) GetPeriodSummary(c *fiber.Ctx) error {
|
||||
func (u *ProjectflockController) LookupProjectFlockKandang(c *fiber.Ctx) error {
|
||||
projectFlockId := c.QueryInt("project_flock_id", 0)
|
||||
kandangId := c.QueryInt("kandang_id", 0)
|
||||
withPopulation := c.QueryBool("withpopulation", false)
|
||||
|
||||
if projectFlockId == 0 || kandangId == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid project_flock_id or kandang_id")
|
||||
@@ -280,6 +281,13 @@ func (u *ProjectflockController) LookupProjectFlockKandang(c *fiber.Ctx) error {
|
||||
|
||||
dtoResult := dto.ToProjectFlockKandangDTO(*result)
|
||||
dtoResult.AvailableQuantity = float64(availableStock)
|
||||
if withPopulation {
|
||||
population, err := u.ProjectflockService.GetProjectFlockKandangPopulation(c, result.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dtoResult.Population = &population
|
||||
}
|
||||
|
||||
if dtoResult.ProjectFlock != nil {
|
||||
for i := range dtoResult.ProjectFlock.Kandangs {
|
||||
|
||||
@@ -32,6 +32,7 @@ type ProjectFlockKandangDTO struct {
|
||||
Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
|
||||
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
|
||||
AvailableQuantity float64 `json:"available_quantity"`
|
||||
Population *float64 `json:"population,omitempty"`
|
||||
}
|
||||
|
||||
func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||
rProjectBudget "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
rProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
rRecording "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||
|
||||
sProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services"
|
||||
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
@@ -32,6 +33,8 @@ func (ProjectflockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, valid
|
||||
nonstockRepo := rNonstock.NewNonstockRepository(db)
|
||||
projectflockRepo := rProjectflock.NewProjectflockRepository(db)
|
||||
projectflockKandangRepo := rProjectflock.NewProjectFlockKandangRepository(db)
|
||||
projectFlockPopulationRepo := rProjectflock.NewProjectFlockPopulationRepository(db)
|
||||
recordingRepo := rRecording.NewRecordingRepository(db)
|
||||
warehouseRepo := rWarehouse.NewWarehouseRepository(db)
|
||||
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
|
||||
projectBudgetRepo := rProjectBudget.NewProjectBudgetRepository(db)
|
||||
@@ -43,7 +46,7 @@ func (ProjectflockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, valid
|
||||
panic(fmt.Sprintf("failed to register project flock approval workflow: %v", err))
|
||||
}
|
||||
|
||||
projectflockService := sProjectflock.NewProjectflockService(projectflockRepo, flockRepo, kandangRepo, projectflockKandangRepo, warehouseRepo, productWarehouseRepo, projectBudgetRepo, nonstockRepo, approvalService, validate)
|
||||
projectflockService := sProjectflock.NewProjectflockService(projectflockRepo, flockRepo, kandangRepo, projectflockKandangRepo, warehouseRepo, productWarehouseRepo, projectBudgetRepo, nonstockRepo, projectFlockPopulationRepo, recordingRepo, approvalService, validate)
|
||||
userService := sUser.NewUserService(userRepo, validate)
|
||||
|
||||
ProjectflockRoutes(router, userService, projectflockService)
|
||||
|
||||
+18
@@ -15,6 +15,7 @@ type ProjectFlockPopulationRepository interface {
|
||||
GetByProjectChickinIDAndProductWarehouseID(ctx context.Context, projectChickinID uint, productWarehouseID uint) ([]entity.ProjectFlockPopulation, error)
|
||||
GetByProjectFlockKandangIDAndProductWarehouseID(ctx context.Context, projectFlockKandangID uint, productWarehouseID uint) ([]entity.ProjectFlockPopulation, error)
|
||||
GetTotalQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
|
||||
GetAvailableQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error)
|
||||
|
||||
// subset of base repository methods used by services
|
||||
CreateOne(ctx context.Context, entity *entity.ProjectFlockPopulation, modifier func(*gorm.DB) *gorm.DB) error
|
||||
@@ -106,3 +107,20 @@ func (r *projectFlockPopulationRepositoryImpl) GetTotalQtyByProjectFlockKandangI
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (r *projectFlockPopulationRepositoryImpl) GetAvailableQtyByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (float64, error) {
|
||||
var total float64
|
||||
err := r.DB().WithContext(ctx).
|
||||
Table("project_flock_populations").
|
||||
Select("COALESCE(SUM(total_qty - total_used_qty), 0) AS total_qty").
|
||||
Joins("JOIN project_chickins ON project_chickins.id = project_flock_populations.project_chickin_id").
|
||||
Where("project_chickins.project_flock_kandang_id = ?", projectFlockKandangID).
|
||||
Scan(&total).Error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if total < 0 {
|
||||
total = 0
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
+15
@@ -27,6 +27,7 @@ type ProjectFlockKandangRepository interface {
|
||||
MaxPeriodByBaseName(ctx context.Context, baseName string) (int, error)
|
||||
ProjectPeriodsByProjectIDs(ctx context.Context, projectIDs []uint) (map[uint]int, error)
|
||||
HasOpenNewerPeriod(ctx context.Context, kandangID uint, currentPeriod int, excludeID *uint) (bool, error)
|
||||
ListIDsByProjectAndKandang(ctx context.Context, projectFlockID uint, kandangIDs []uint) ([]uint, error)
|
||||
WithTx(tx *gorm.DB) ProjectFlockKandangRepository
|
||||
DB() *gorm.DB
|
||||
IdExists(ctx context.Context, id uint) (bool, error)
|
||||
@@ -89,6 +90,20 @@ func (r *projectFlockKandangRepositoryImpl) GetByProjectFlockID(ctx context.Cont
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (r *projectFlockKandangRepositoryImpl) ListIDsByProjectAndKandang(ctx context.Context, projectFlockID uint, kandangIDs []uint) ([]uint, error) {
|
||||
if len(kandangIDs) == 0 {
|
||||
return []uint{}, nil
|
||||
}
|
||||
var ids []uint
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entity.ProjectFlockKandang{}).
|
||||
Where("project_flock_id = ? AND kandang_id IN ?", projectFlockID, kandangIDs).
|
||||
Pluck("id", &ids).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (r *projectFlockKandangRepositoryImpl) GetAllWithFilters(ctx context.Context, offset int, limit int, params interface{}) ([]entity.ProjectFlockKandang, int64, error) {
|
||||
var records []entity.ProjectFlockKandang
|
||||
var total int64
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
|
||||
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
|
||||
@@ -37,6 +38,7 @@ type ProjectflockService interface {
|
||||
GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error)
|
||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||
GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, float64, error)
|
||||
GetProjectFlockKandangPopulation(ctx *fiber.Ctx, projectFlockKandangID uint) (float64, error)
|
||||
GetPeriodSummary(ctx *fiber.Ctx, locationID uint) ([]KandangPeriodSummary, error)
|
||||
GetProjectPeriods(ctx *fiber.Ctx, projectIDs []uint) (map[uint]int, error)
|
||||
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error)
|
||||
@@ -54,6 +56,8 @@ type projectflockService struct {
|
||||
ProductWarehouseRepo productWarehouseRepository.ProductWarehouseRepository
|
||||
ProjectBudgetRepo projectBudgetRepository.ProjectBudgetRepository
|
||||
PivotRepo repository.ProjectFlockKandangRepository
|
||||
PopulationRepo repository.ProjectFlockPopulationRepository
|
||||
RecordingRepo recordingRepo.RecordingRepository
|
||||
ApprovalSvc commonSvc.ApprovalService
|
||||
approvalWorkflow approvalutils.ApprovalWorkflowKey
|
||||
}
|
||||
@@ -73,6 +77,8 @@ func NewProjectflockService(
|
||||
productWarehouseRepo productWarehouseRepository.ProductWarehouseRepository,
|
||||
projectBudgetRepo projectBudgetRepository.ProjectBudgetRepository,
|
||||
nonstockRepo nonstockRepository.NonstockRepository,
|
||||
populationRepo repository.ProjectFlockPopulationRepository,
|
||||
recordingRepo recordingRepo.RecordingRepository,
|
||||
approvalSvc commonSvc.ApprovalService,
|
||||
validate *validator.Validate,
|
||||
|
||||
@@ -86,7 +92,10 @@ func NewProjectflockService(
|
||||
NonstockRepo: nonstockRepo,
|
||||
WarehouseRepo: warehouseRepo,
|
||||
ProductWarehouseRepo: productWarehouseRepo,
|
||||
ProjectBudgetRepo: projectBudgetRepo,
|
||||
PivotRepo: pivotRepo,
|
||||
PopulationRepo: populationRepo,
|
||||
RecordingRepo: recordingRepo,
|
||||
ApprovalSvc: approvalSvc,
|
||||
approvalWorkflow: utils.ApprovalWorkflowProjectFlock,
|
||||
}
|
||||
@@ -417,6 +426,34 @@ func (s projectflockService) GetProjectFlockKandangByProjectAndKandang(ctx *fibe
|
||||
return pfk, availableQuantity, nil
|
||||
}
|
||||
|
||||
func (s projectflockService) GetProjectFlockKandangPopulation(ctx *fiber.Ctx, projectFlockKandangID uint) (float64, error) {
|
||||
if s.PopulationRepo == nil {
|
||||
return 0, fiber.NewError(fiber.StatusInternalServerError, "Project flock population repository is not configured")
|
||||
}
|
||||
if projectFlockKandangID == 0 {
|
||||
return 0, fiber.NewError(fiber.StatusBadRequest, "project_flock_kandang_id is required")
|
||||
}
|
||||
|
||||
if s.RecordingRepo != nil {
|
||||
latest, err := s.RecordingRepo.GetLatestByProjectFlockKandangID(ctx.Context(), projectFlockKandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch latest recording for project flock kandang %d: %+v", projectFlockKandangID, err)
|
||||
return 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock kandang population")
|
||||
}
|
||||
if latest != nil && latest.TotalChickQty != nil && *latest.TotalChickQty > 0 {
|
||||
return *latest.TotalChickQty, nil
|
||||
}
|
||||
}
|
||||
|
||||
total, err := s.PopulationRepo.GetAvailableQtyByProjectFlockKandangID(ctx.Context(), projectFlockKandangID)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch project flock kandang population %d: %+v", projectFlockKandangID, err)
|
||||
return 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock kandang population")
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (s projectflockService) GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, float64, error) {
|
||||
idStr = strings.TrimSpace(idStr)
|
||||
projectFlockIdStr = strings.TrimSpace(projectFlockIdStr)
|
||||
@@ -793,6 +830,9 @@ func (s projectflockService) attachKandangs(ctx context.Context, dbTransaction *
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to persist project flock history")
|
||||
}
|
||||
if err := s.ensureProjectFlockKandangProductWarehouses(ctx, dbTransaction, records); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -818,6 +858,23 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Tidak dapat melepas kandang karena sudah memiliki recording: %s", strings.Join(names, ", ")))
|
||||
}
|
||||
|
||||
pfkIDs, err := s.pivotRepoWithTx(dbTransaction).ListIDsByProjectAndKandang(ctx, projectFlockID, kandangIDs)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to load project flock kandang ids")
|
||||
}
|
||||
|
||||
if len(pfkIDs) > 0 {
|
||||
pwRepo := s.ProductWarehouseRepo
|
||||
if dbTransaction != nil {
|
||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
||||
} else if pwRepo == nil {
|
||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(s.Repository.DB())
|
||||
}
|
||||
if err := pwRepo.DeleteByProjectFlockKandangIDs(ctx, pfkIDs); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove product warehouses for project flock kandang")
|
||||
}
|
||||
}
|
||||
|
||||
if resetStatus {
|
||||
if err := s.kandangRepoWithTx(dbTransaction).UpdateStatusByIDs(ctx, kandangIDs, utils.KandangStatusNonActive); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update kandangs status")
|
||||
@@ -854,6 +911,78 @@ func (s projectflockService) kandangRepoWithTx(tx *gorm.DB) kandangRepository.Ka
|
||||
return kandangRepository.NewKandangRepository(s.Repository.DB())
|
||||
}
|
||||
|
||||
func (s projectflockService) ensureProjectFlockKandangProductWarehouses(ctx context.Context, dbTransaction *gorm.DB, records []*entity.ProjectFlockKandang) error {
|
||||
if len(records) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
pwRepo := s.ProductWarehouseRepo
|
||||
if dbTransaction != nil {
|
||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
||||
} else if pwRepo == nil {
|
||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(s.Repository.DB())
|
||||
}
|
||||
|
||||
warehouseRepo := s.WarehouseRepo
|
||||
if dbTransaction != nil {
|
||||
warehouseRepo = warehouseRepository.NewWarehouseRepository(dbTransaction)
|
||||
} else if warehouseRepo == nil {
|
||||
warehouseRepo = warehouseRepository.NewWarehouseRepository(s.Repository.DB())
|
||||
}
|
||||
|
||||
flags := []utils.FlagType{
|
||||
utils.FlagAyamAfkir,
|
||||
utils.FlagAyamCulling,
|
||||
utils.FlagAyamMati,
|
||||
utils.FlagTelurPecah,
|
||||
utils.FlagTelurUtuh,
|
||||
}
|
||||
|
||||
productIDs := make(map[utils.FlagType]uint, len(flags))
|
||||
for _, flag := range flags {
|
||||
product, err := pwRepo.GetFirstProductByFlag(ctx, string(flag))
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Product untuk flag %s tidak ditemukan", flag))
|
||||
}
|
||||
return err
|
||||
}
|
||||
productIDs[flag] = product.Id
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
if record == nil || record.Id == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
warehouse, err := warehouseRepo.GetByKandangID(ctx, record.KandangId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, flag := range flags {
|
||||
productID := productIDs[flag]
|
||||
if _, err := pwRepo.GetByProductWarehouseAndProjectFlockKandang(ctx, productID, warehouse.Id, record.Id); err == nil {
|
||||
continue
|
||||
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
|
||||
newPW := entity.ProductWarehouse{
|
||||
ProductId: productID,
|
||||
WarehouseId: warehouse.Id,
|
||||
ProjectFlockKandangId: &record.Id,
|
||||
Quantity: 0,
|
||||
}
|
||||
if err := pwRepo.CreateOne(ctx, &newPW, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s projectflockService) Resubmit(c *fiber.Ctx, req *validation.Resubmit, id uint) (*entity.ProjectFlock, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user