Feat[BE#280]:add project budgets to body create API and get one API

This commit is contained in:
aguhh18
2025-12-02 09:32:42 +07:00
parent 29f0fd6edb
commit 1d0ef8fb93
7 changed files with 108 additions and 23 deletions
+6 -4
View File
@@ -5,10 +5,12 @@ import (
) )
type ProjectBudget struct { type ProjectBudget struct {
Id uint `gorm:"primaryKey"` Id uint `gorm:"primaryKey"`
Qty float64 `gorm:"type:numeric(15,3);not null"` ProjectFlockId uint `gorm:"not null"`
Price float64 `gorm:"type:numeric(15,3);not null"` NonstockId uint `gorm:"not null"`
CreatedAt time.Time `gorm:"autoCreateTime"` Qty float64 `gorm:"type:numeric(15,3);not null"`
Price float64 `gorm:"type:numeric(15,3);not null"`
CreatedAt time.Time `gorm:"autoCreateTime"`
Nonstock *Nonstock `gorm:"foreignKey:Id;references:Id"` Nonstock *Nonstock `gorm:"foreignKey:Id;references:Id"`
ProjectFlock *ProjectFlock `gorm:"foreignKey:Id;references:Id"` ProjectFlock *ProjectFlock `gorm:"foreignKey:Id;references:Id"`
+1
View File
@@ -24,6 +24,7 @@ type ProjectFlock struct {
CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"`
Kandangs []Kandang `gorm:"many2many:project_flock_kandangs;joinTableForeignKey:project_flock_id;joinTableReferences:kandang_id" json:"kandangs,omitempty"` Kandangs []Kandang `gorm:"many2many:project_flock_kandangs;joinTableForeignKey:project_flock_id;joinTableReferences:kandang_id" json:"kandangs,omitempty"`
KandangHistory []ProjectFlockKandang `gorm:"foreignKey:ProjectFlockId;references:Id" json:"-"` KandangHistory []ProjectFlockKandang `gorm:"foreignKey:ProjectFlockId;references:Id" json:"-"`
Budgets []ProjectBudget `gorm:"foreignKey:ProjectFlockId;references:Id" json:"-"`
LatestApproval *Approval `gorm:"-" json:"-"` LatestApproval *Approval `gorm:"-" json:"-"`
} }
@@ -9,6 +9,7 @@ import (
fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto" fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto"
kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto" kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto" locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
nonstockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/nonstocks/dto"
// pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils" // pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
@@ -24,15 +25,16 @@ type ProjectFlockRelationDTO struct {
type ProjectFlockListDTO struct { type ProjectFlockListDTO struct {
ProjectFlockRelationDTO ProjectFlockRelationDTO
Area *areaDTO.AreaRelationDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
Category string `json:"category"` Category string `json:"category"`
Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
Location *locationDTO.LocationRelationDTO `json:"location,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
Kandangs []KandangWithProjectFlockIdDTO `json:"kandangs,omitempty"` Kandangs []KandangWithProjectFlockIdDTO `json:"kandangs,omitempty"`
CreatedUser *userDTO.UserRelationDTO `json:"created_user"` ProjectBudgets []ProjectBudgetDTO `json:"project_budgets,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedUser *userDTO.UserRelationDTO `json:"created_user"`
UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"`
Approval approvalDTO.ApprovalRelationDTO `json:"approval"` UpdatedAt time.Time `json:"updated_at"`
Approval approvalDTO.ApprovalRelationDTO `json:"approval"`
} }
type KandangWithProjectFlockIdDTO struct { type KandangWithProjectFlockIdDTO struct {
@@ -51,6 +53,13 @@ type KandangPeriodSummaryDTO struct {
Period int `json:"period"` Period int `json:"period"`
} }
type ProjectBudgetDTO struct {
Id uint `json:"id"`
Qty float64 `json:"qty"`
Price float64 `json:"price"`
Nonstock *nonstockDTO.NonstockRelationDTO `json:"nonstock,omitempty"`
}
func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectFlockListDTO { func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectFlockListDTO {
var createdUser *userDTO.UserRelationDTO var createdUser *userDTO.UserRelationDTO
if e.CreatedUser.Id != 0 { if e.CreatedUser.Id != 0 {
@@ -110,6 +119,7 @@ func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectF
ProjectFlockRelationDTO: createProjectFlockRelationDTO(e, period), ProjectFlockRelationDTO: createProjectFlockRelationDTO(e, period),
Area: areaSummary, Area: areaSummary,
Kandangs: kandangSummaries, Kandangs: kandangSummaries,
ProjectBudgets: ToProjectBudgetDTOs(e.Budgets),
Category: e.Category, Category: e.Category,
Fcr: fcrSummary, Fcr: fcrSummary,
Location: locationSummary, Location: locationSummary,
@@ -184,3 +194,26 @@ func createProjectFlockRelationDTO(e entity.ProjectFlock, period int) ProjectFlo
FlockName: e.FlockName, FlockName: e.FlockName,
} }
} }
func ToProjectBudgetDTO(e entity.ProjectBudget) ProjectBudgetDTO {
var nonstockRef *nonstockDTO.NonstockRelationDTO
if e.Nonstock != nil && e.Nonstock.Id != 0 {
mapped := nonstockDTO.ToNonstockRelationDTO(*e.Nonstock)
nonstockRef = &mapped
}
return ProjectBudgetDTO{
Id: e.Id,
Qty: e.Qty,
Price: e.Price,
Nonstock: nonstockRef,
}
}
func ToProjectBudgetDTOs(e []entity.ProjectBudget) []ProjectBudgetDTO {
result := make([]ProjectBudgetDTO, len(e))
for i, r := range e {
result[i] = ToProjectBudgetDTO(r)
}
return result
}
@@ -13,6 +13,7 @@ import (
rFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories" rFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories"
rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories" 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" rProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
sProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services" sProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services"
@@ -31,6 +32,7 @@ func (ProjectflockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, valid
projectflockKandangRepo := rProjectflock.NewProjectFlockKandangRepository(db) projectflockKandangRepo := rProjectflock.NewProjectFlockKandangRepository(db)
warehouseRepo := rWarehouse.NewWarehouseRepository(db) warehouseRepo := rWarehouse.NewWarehouseRepository(db)
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db) productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
projectBudgetRepo := rProjectBudget.NewProjectBudgetRepository(db)
userRepo := rUser.NewUserRepository(db) userRepo := rUser.NewUserRepository(db)
approvalRepo := commonRepo.NewApprovalRepository(db) approvalRepo := commonRepo.NewApprovalRepository(db)
@@ -39,7 +41,7 @@ func (ProjectflockModule) RegisterRoutes(router fiber.Router, db *gorm.DB, valid
panic(fmt.Sprintf("failed to register project flock approval workflow: %v", err)) panic(fmt.Sprintf("failed to register project flock approval workflow: %v", err))
} }
projectflockService := sProjectflock.NewProjectflockService(projectflockRepo, flockRepo, kandangRepo, projectflockKandangRepo, warehouseRepo, productWarehouseRepo, approvalService, validate) projectflockService := sProjectflock.NewProjectflockService(projectflockRepo, flockRepo, kandangRepo, projectflockKandangRepo, warehouseRepo, productWarehouseRepo, projectBudgetRepo, approvalService, validate)
userService := sUser.NewUserService(userRepo, validate) userService := sUser.NewUserService(userRepo, validate)
ProjectflockRoutes(router, userService, projectflockService) ProjectflockRoutes(router, userService, projectflockService)
@@ -54,7 +54,9 @@ func (r *ProjectflockRepositoryImpl) WithDefaultRelations() func(*gorm.DB) *gorm
Preload("Location"). Preload("Location").
Preload("Kandangs"). Preload("Kandangs").
Preload("KandangHistory"). Preload("KandangHistory").
Preload("KandangHistory.Kandang") Preload("KandangHistory.Kandang").
Preload("Budgets").
Preload("Budgets.Nonstock")
} }
} }
@@ -16,6 +16,7 @@ import (
flockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories" flockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories"
kandangRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" kandangRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
warehouseRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories" warehouseRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
projectBudgetRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" 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" 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" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
@@ -49,6 +50,7 @@ type projectflockService struct {
KandangRepo kandangRepository.KandangRepository KandangRepo kandangRepository.KandangRepository
WarehouseRepo warehouseRepository.WarehouseRepository WarehouseRepo warehouseRepository.WarehouseRepository
ProductWarehouseRepo productWarehouseRepository.ProductWarehouseRepository ProductWarehouseRepo productWarehouseRepository.ProductWarehouseRepository
ProjectBudgetRepo projectBudgetRepository.ProjectBudgetRepository
PivotRepo repository.ProjectFlockKandangRepository PivotRepo repository.ProjectFlockKandangRepository
ApprovalSvc commonSvc.ApprovalService ApprovalSvc commonSvc.ApprovalService
approvalWorkflow approvalutils.ApprovalWorkflowKey approvalWorkflow approvalutils.ApprovalWorkflowKey
@@ -67,8 +69,10 @@ func NewProjectflockService(
pivotRepo repository.ProjectFlockKandangRepository, pivotRepo repository.ProjectFlockKandangRepository,
warehouseRepo warehouseRepository.WarehouseRepository, warehouseRepo warehouseRepository.WarehouseRepository,
productWarehouseRepo productWarehouseRepository.ProductWarehouseRepository, productWarehouseRepo productWarehouseRepository.ProductWarehouseRepository,
projectBudgetRepo projectBudgetRepository.ProjectBudgetRepository,
approvalSvc commonSvc.ApprovalService, approvalSvc commonSvc.ApprovalService,
validate *validator.Validate, validate *validator.Validate,
) ProjectflockService { ) ProjectflockService {
return &projectflockService{ return &projectflockService{
Log: utils.Log, Log: utils.Log,
@@ -289,7 +293,6 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error { err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
projectRepo := repository.NewProjectflockRepository(dbTransaction) projectRepo := repository.NewProjectflockRepository(dbTransaction)
// Generate unique flock name (sequential per base name, starting from 1)
generatedName, _, err := s.generateSequentialFlockName(c.Context(), projectRepo, canonicalBase, 1, nil) generatedName, _, err := s.generateSequentialFlockName(c.Context(), projectRepo, canonicalBase, 1, nil)
if err != nil { if err != nil {
return err return err
@@ -300,7 +303,6 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
return err return err
} }
// Compute period per kandang so every kandang maintains its own cycle history.
periods, err := projectRepo.GetNextPeriodsForKandangs(c.Context(), kandangIDs) periods, err := projectRepo.GetNextPeriodsForKandangs(c.Context(), kandangIDs)
if err != nil { if err != nil {
return err return err
@@ -309,6 +311,10 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
return err return err
} }
if err := s.UpsertProjectBudget(c.Context(), dbTransaction, createBody.Id, req.ProjectBudgets); err != nil {
return err
}
action := entity.ApprovalActionCreated action := entity.ApprovalActionCreated
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction)) approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
_, err = approvalSvcTx.CreateApproval( _, err = approvalSvcTx.CreateApproval(
@@ -1044,3 +1050,35 @@ func (s projectflockService) kandangRepoWithTx(tx *gorm.DB) kandangRepository.Ka
} }
return kandangRepository.NewKandangRepository(s.Repository.DB()) return kandangRepository.NewKandangRepository(s.Repository.DB())
} }
func (s projectflockService) UpsertProjectBudget(ctx context.Context, dbTransaction *gorm.DB, projectFlockID uint, budgets []validation.ProjectBudget) error {
if len(budgets) == 0 {
return nil
}
budgetRepo := projectBudgetRepository.NewProjectBudgetRepository(dbTransaction)
if err := budgetRepo.DeleteMany(ctx, func(q *gorm.DB) *gorm.DB {
return q.Where("project_flock_id = ?", projectFlockID)
}); err != nil && err != gorm.ErrRecordNotFound {
return err
}
records := make([]*entity.ProjectBudget, 0, len(budgets))
for _, b := range budgets {
records = append(records, &entity.ProjectBudget{
ProjectFlockId: projectFlockID,
NonstockId: b.NonstockId,
Price: b.Price,
Qty: b.Qty,
})
}
if err := budgetRepo.CreateMany(ctx, records, nil); err != nil {
return err
}
return nil
}
@@ -1,12 +1,13 @@
package validation package validation
type Create struct { type Create struct {
FlockName string `json:"flock_name" validate:"required_strict"` FlockName string `json:"flock_name" validate:"required_strict"`
AreaId uint `json:"area_id" validate:"required_strict,number,gt=0"` AreaId uint `json:"area_id" validate:"required_strict,number,gt=0"`
Category string `json:"category" validate:"required_strict"` Category string `json:"category" validate:"required_strict"`
FcrId uint `json:"fcr_id" validate:"required_strict,number,gt=0"` FcrId uint `json:"fcr_id" validate:"required_strict,number,gt=0"`
LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"`
KandangIds []uint `json:"kandang_ids" validate:"required,min=1,dive,gt=0"` KandangIds []uint `json:"kandang_ids" validate:"required,min=1,dive,gt=0"`
ProjectBudgets []ProjectBudget `json:"project_budgets" validate:"required,min=1,dive"`
} }
type Update struct { type Update struct {
@@ -36,3 +37,9 @@ type Approve struct {
ApprovableIds []uint `json:"approvable_ids" validate:"required_strict,min=1,dive,gt=0"` ApprovableIds []uint `json:"approvable_ids" validate:"required_strict,min=1,dive,gt=0"`
Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"` Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"`
} }
type ProjectBudget struct {
NonstockId uint `json:"nonstock_id" validate:"required_strict,number,gt=0"`
Price float64 `json:"price" validate:"required_strict,number,gt=0"`
Qty float64 `json:"qty" validate:"required_strict,number,gt=0"`
}