mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Feat[BE]: add multilpple type of chickin growing and laying, make convertion product when chickin approved, add projectflockkandangid on projectflock api
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/dto"
|
||||
@@ -22,30 +21,84 @@ func NewChickinController(chickinService service.ChickinService) *ChickinControl
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ChickinController) GetAll(c *fiber.Ctx) error {
|
||||
query := &validation.Query{
|
||||
Page: c.QueryInt("page", 1),
|
||||
Limit: c.QueryInt("limit", 10),
|
||||
ProjectFlockKandangId: uint(c.QueryInt("project_flock_kandang_id", 0)),
|
||||
// func (u *ChickinController) GetAll(c *fiber.Ctx) error {
|
||||
// query := &validation.Query{
|
||||
// Page: c.QueryInt("page", 1),
|
||||
// Limit: c.QueryInt("limit", 10),
|
||||
// ProjectFlockKandangId: uint(c.QueryInt("project_flock_kandang_id", 0)),
|
||||
// }
|
||||
|
||||
// result, totalResults, err := u.ChickinService.GetAll(c, query)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// return c.Status(fiber.StatusOK).
|
||||
// JSON(response.SuccessWithPaginate[dto.ChickinListDTO]{
|
||||
// Code: fiber.StatusOK,
|
||||
// Status: "success",
|
||||
// Message: "Get all chickins successfully",
|
||||
// Meta: response.Meta{
|
||||
// Page: query.Page,
|
||||
// Limit: query.Limit,
|
||||
// TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||
// TotalResults: totalResults,
|
||||
// },
|
||||
// Data: dto.ToChickinListDTOs(result),
|
||||
// })
|
||||
// }
|
||||
|
||||
// func (u *ChickinController) GetOne(c *fiber.Ctx) error {
|
||||
// param := c.Params("id")
|
||||
|
||||
// id, err := strconv.Atoi(param)
|
||||
// if err != nil {
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
// }
|
||||
|
||||
// result, err := u.ChickinService.GetOne(c, uint(id))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// return c.Status(fiber.StatusOK).
|
||||
// JSON(response.Success{
|
||||
// Code: fiber.StatusOK,
|
||||
// Status: "success",
|
||||
// Message: "Get chickin successfully",
|
||||
// Data: dto.ToChickinListDTO(*result),
|
||||
// })
|
||||
// }
|
||||
|
||||
func (u *ChickinController) CreateOne(c *fiber.Ctx) error {
|
||||
req := new(validation.Create)
|
||||
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
result, totalResults, err := u.ChickinService.GetAll(c, query)
|
||||
results, err := u.ChickinService.CreateOne(c, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.SuccessWithPaginate[dto.ChickinListDTO]{
|
||||
Code: fiber.StatusOK,
|
||||
var (
|
||||
data interface{}
|
||||
message = "Create chickin successfully"
|
||||
)
|
||||
if len(results) == 1 {
|
||||
data = dto.ToChickinListDTO(results[0])
|
||||
} else {
|
||||
message = "Create chickins successfully"
|
||||
data = dto.ToChickinListDTOs(results)
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).
|
||||
JSON(response.Success{
|
||||
Code: fiber.StatusCreated,
|
||||
Status: "success",
|
||||
Message: "Get all chickins successfully",
|
||||
Meta: response.Meta{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||
TotalResults: totalResults,
|
||||
},
|
||||
Data: dto.ToChickinListDTOs(result),
|
||||
Message: message,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -67,80 +120,60 @@ func (u *ChickinController) GetOne(c *fiber.Ctx) error {
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Get chickin successfully",
|
||||
Data: dto.ToChickinListDTO(*result),
|
||||
Data: dto.ToChickinDetailDTO(*result),
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ChickinController) CreateOne(c *fiber.Ctx) error {
|
||||
req := new(validation.Create)
|
||||
// func (u *ChickinController) UpdateOne(c *fiber.Ctx) error {
|
||||
// req := new(validation.Update)
|
||||
// param := c.Params("id")
|
||||
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
// id, err := strconv.Atoi(param)
|
||||
// if err != nil {
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
// }
|
||||
|
||||
result, err := u.ChickinService.CreateOne(c, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := c.BodyParser(req); err != nil {
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
// }
|
||||
|
||||
return c.Status(fiber.StatusCreated).
|
||||
JSON(response.Success{
|
||||
Code: fiber.StatusCreated,
|
||||
Status: "success",
|
||||
Message: "Create chickin successfully",
|
||||
Data: dto.ToChickinListDTO(*result),
|
||||
})
|
||||
}
|
||||
// result, err := u.ChickinService.UpdateOne(c, req, uint(id))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
func (u *ChickinController) UpdateOne(c *fiber.Ctx) error {
|
||||
req := new(validation.Update)
|
||||
param := c.Params("id")
|
||||
// return c.Status(fiber.StatusOK).
|
||||
// JSON(response.Success{
|
||||
// Code: fiber.StatusOK,
|
||||
// Status: "success",
|
||||
// Message: "Update chickin successfully",
|
||||
// Data: dto.ToChickinListDTO(*result),
|
||||
// })
|
||||
// }
|
||||
|
||||
id, err := strconv.Atoi(param)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
}
|
||||
// func (u *ChickinController) DeleteOne(c *fiber.Ctx) error {
|
||||
// param := c.Params("id")
|
||||
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
// id, err := strconv.Atoi(param)
|
||||
// if err != nil {
|
||||
// return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
// }
|
||||
|
||||
result, err := u.ChickinService.UpdateOne(c, req, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := u.ChickinService.DeleteOne(c, uint(id)); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.Success{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Update chickin successfully",
|
||||
Data: dto.ToChickinListDTO(*result),
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ChickinController) DeleteOne(c *fiber.Ctx) error {
|
||||
param := c.Params("id")
|
||||
|
||||
id, err := strconv.Atoi(param)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
}
|
||||
|
||||
if err := u.ChickinService.DeleteOne(c, uint(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.Common{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Delete chickin successfully",
|
||||
})
|
||||
}
|
||||
// return c.Status(fiber.StatusOK).
|
||||
// JSON(response.Common{
|
||||
// Code: fiber.StatusOK,
|
||||
// Status: "success",
|
||||
// Message: "Delete chickin successfully",
|
||||
// })
|
||||
// }
|
||||
|
||||
func (u *ChickinController) Approval(c *fiber.Ctx) error {
|
||||
req := new(validation.Approve)
|
||||
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ import (
|
||||
// === DTO Structs (ordered) ===
|
||||
|
||||
type ChickinBaseDTO struct {
|
||||
Id uint `json:"id"`
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||
ChickInDate time.Time `json:"chick_in_date"`
|
||||
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||
UsageQty float64 `json:"usage_qty"`
|
||||
PendingUsageQty float64 `json:"pending_usage_qty"`
|
||||
Notes string `json:"notes"`
|
||||
Id uint `json:"id"`
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||
ChickInDate time.Time `json:"chick_in_date"`
|
||||
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||
UsageQty float64 `json:"usage_qty"`
|
||||
PendingUsageQty float64 `json:"pending_usage_qty"`
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
type ProjectFlockDTO struct {
|
||||
@@ -61,7 +61,17 @@ type ChickinListDTO struct {
|
||||
}
|
||||
|
||||
type ChickinDetailDTO struct {
|
||||
ChickinListDTO
|
||||
Id uint `json:"id"`
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||
ChickInDate time.Time `json:"chick_in_date"`
|
||||
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||
UsageQty float64 `json:"usage_qty"`
|
||||
PendingUsageQty float64 `json:"pending_usage_qty"`
|
||||
Notes string `json:"notes"`
|
||||
CreatedBy uint `json:"created_by"`
|
||||
CreatedUser *userBaseDTO.UserBaseDTO `json:"created_user"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// === Mapper Functions (ordered) ===
|
||||
@@ -149,13 +159,13 @@ func ToChickinBaseDTO(e entity.ProjectChickin) ChickinBaseDTO {
|
||||
projectFlockKandangId = e.ProjectFlockKandangId
|
||||
}
|
||||
return ChickinBaseDTO{
|
||||
Id: e.Id,
|
||||
Id: e.Id,
|
||||
ProjectFlockKandangId: projectFlockKandangId,
|
||||
ChickInDate: e.ChickInDate,
|
||||
ProductWarehouseId: e.ProductWarehouseId,
|
||||
UsageQty: e.UsageQty,
|
||||
PendingUsageQty: e.PendingUsageQty,
|
||||
Notes: e.Notes,
|
||||
ChickInDate: e.ChickInDate,
|
||||
ProductWarehouseId: e.ProductWarehouseId,
|
||||
UsageQty: e.UsageQty,
|
||||
PendingUsageQty: e.PendingUsageQty,
|
||||
Notes: e.Notes,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +213,31 @@ func ToChickinSimpleDTOs(e []entity.ProjectChickin) []ChickinSimpleDTO {
|
||||
}
|
||||
|
||||
func ToChickinDetailDTO(e entity.ProjectChickin) ChickinDetailDTO {
|
||||
var createdUser *userBaseDTO.UserBaseDTO
|
||||
if e.CreatedUser != nil && e.CreatedUser.Id != 0 {
|
||||
mapped := userBaseDTO.ToUserBaseDTO(*e.CreatedUser)
|
||||
createdUser = &mapped
|
||||
}
|
||||
|
||||
return ChickinDetailDTO{
|
||||
ChickinListDTO: ToChickinListDTO(e),
|
||||
Id: e.Id,
|
||||
ProjectFlockKandangId: e.ProjectFlockKandangId,
|
||||
ChickInDate: e.ChickInDate,
|
||||
ProductWarehouseId: e.ProductWarehouseId,
|
||||
UsageQty: e.UsageQty,
|
||||
PendingUsageQty: e.PendingUsageQty,
|
||||
Notes: e.Notes,
|
||||
CreatedBy: e.CreatedBy,
|
||||
CreatedUser: createdUser,
|
||||
CreatedAt: e.CreatedAt,
|
||||
UpdatedAt: e.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func ToChickinDetailDTOs(e []entity.ProjectChickin) []ChickinDetailDTO {
|
||||
result := make([]ChickinDetailDTO, len(e))
|
||||
for i, r := range e {
|
||||
result[i] = ToChickinDetailDTO(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ func ChickinRoutes(v1 fiber.Router, u user.UserService, s chickin.ChickinService
|
||||
// route.Patch("/:id", m.Auth(u), ctrl.UpdateOne)
|
||||
// route.Delete("/:id", m.Auth(u), ctrl.DeleteOne)
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
// route.Get("/", ctrl.GetAll)
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
route.Get("/:id", ctrl.GetOne)
|
||||
route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
// route.Patch("/:id", ctrl.UpdateOne)
|
||||
// route.Delete("/:id", ctrl.DeleteOne)
|
||||
route.Post("/approvals", ctrl.Approval)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
type ChickinService interface {
|
||||
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectChickin, int64, error)
|
||||
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectChickin, error)
|
||||
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectChickin, error)
|
||||
CreateOne(ctx *fiber.Ctx, req *validation.Create) ([]entity.ProjectChickin, error)
|
||||
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectChickin, error)
|
||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectChickin, error)
|
||||
@@ -109,7 +109,7 @@ func (s chickinService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectChickin, e
|
||||
return chickin, nil
|
||||
}
|
||||
|
||||
func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entity.ProjectChickin, error) {
|
||||
func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) ([]entity.ProjectChickin, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -150,6 +150,11 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
||||
actorID := uint(1) // todo nanti ambil dari auth context
|
||||
newChikins := make([]*entity.ProjectChickin, 0)
|
||||
for _, productWarehouse := range productWarehouses {
|
||||
|
||||
if productWarehouse.Quantity <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
newChickin := &entity.ProjectChickin{
|
||||
ProjectFlockKandangId: req.ProjectFlockKandangId,
|
||||
ChickInDate: chickinDate,
|
||||
@@ -167,6 +172,12 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "No chickins to create")
|
||||
}
|
||||
|
||||
existingChikins, err := s.Repository.GetByProjectFlockKandangID(c.Context(), req.ProjectFlockKandangId)
|
||||
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 {
|
||||
|
||||
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
||||
@@ -187,16 +198,27 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
||||
|
||||
if err := productWarehouseTx.PatchOne(c.Context(), chickin.ProductWarehouseId, updates, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("failed to update product warehouse quantity for id %d", chickin.ProductWarehouseId)
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Product warehouse %d not found", chickin.ProductWarehouseId))
|
||||
}
|
||||
return err
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update product warehouse quantity")
|
||||
}
|
||||
}
|
||||
var approvalAction entity.ApprovalAction
|
||||
if isFirstTime {
|
||||
approvalAction = entity.ApprovalActionCreated
|
||||
} else {
|
||||
approvalAction = entity.ApprovalActionUpdated
|
||||
}
|
||||
|
||||
if latest == nil {
|
||||
|
||||
action := entity.ApprovalActionCreated
|
||||
if _, err := approvalSvcTx.CreateApproval(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, utils.ProjectFlockKandangStepPengajuan, &action, actorID, nil); err != nil {
|
||||
if _, err := approvalSvcTx.CreateApproval(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, utils.ProjectFlockKandangStepPengajuan, &approvalAction, actorID, nil); err != nil {
|
||||
lower := strings.ToLower(err.Error())
|
||||
if !(strings.Contains(lower, "duplicate") || strings.Contains(lower, "unique constraint") || strings.Contains(lower, "23505")) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if latest.StepNumber != uint16(utils.ProjectFlockKandangStepPengajuan) {
|
||||
if _, err := approvalSvcTx.CreateApproval(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, utils.ProjectFlockKandangStepPengajuan, &approvalAction, actorID, nil); err != nil {
|
||||
lower := strings.ToLower(err.Error())
|
||||
if !(strings.Contains(lower, "duplicate") || strings.Contains(lower, "unique constraint") || strings.Contains(lower, "23505")) {
|
||||
return err
|
||||
@@ -210,7 +232,19 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return newChikins[0], nil
|
||||
result := make([]entity.ProjectChickin, 0, len(newChikins))
|
||||
for _, chickin := range newChikins {
|
||||
loaded, err := s.GetOne(c, chickin.Id)
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to reload chickin %d with relations: %v", chickin.Id, err))
|
||||
}
|
||||
result = append(result, *loaded)
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to load created chickins")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectChickin, error) {
|
||||
@@ -257,7 +291,8 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actorID := uint(1) // todo nanti ambil dari auth context
|
||||
|
||||
approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(s.Repository.DB()))
|
||||
|
||||
var action entity.ApprovalAction
|
||||
switch strings.ToUpper(strings.TrimSpace(req.Action)) {
|
||||
@@ -269,21 +304,19 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "action must be APPROVED or REJECTED")
|
||||
}
|
||||
|
||||
approvableIDs := uniqueUintSlice(req.ApprovableIds)
|
||||
approvableIDs := utils.UniqueUintSlice(req.ApprovableIds)
|
||||
if len(approvableIDs) == 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "approvable_ids must contain at least one id")
|
||||
}
|
||||
|
||||
// Validate all ProjectFlockKandang IDs exist and have valid approval status
|
||||
approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(s.Repository.DB()))
|
||||
for _, id := range approvableIDs {
|
||||
idCopy := id
|
||||
if err := commonSvc.EnsureRelations(c.Context(), commonSvc.RelationCheck{Name: "ProjectFlockKandang", ID: &idCopy, Exists: s.ProjectflockKandangRepo.IdExists}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check latest approval status - must be PENGAJUAN to be approvable
|
||||
latestApproval, err := approvalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, id, nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to check approval status")
|
||||
}
|
||||
@@ -308,6 +341,7 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
|
||||
for _, approvableID := range approvableIDs {
|
||||
|
||||
actorID := uint(1) // todo nanti ambil dari auth context
|
||||
if _, err := approvalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlockKandang,
|
||||
@@ -348,21 +382,34 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
return err
|
||||
}
|
||||
|
||||
pulletPW, err := s.getOrCreatePulletProductWarehouse(c, warehouse.Id, dbTransaction, actorID)
|
||||
if err != nil {
|
||||
category := strings.ToUpper(strings.TrimSpace(kandangForApproval.ProjectFlock.Category))
|
||||
var conversionCategoryCode string
|
||||
|
||||
continue
|
||||
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 err := s.convertChickinsToPullet(c, chickins, pulletPW, dbTransaction, actorID); err != nil {
|
||||
targetPW, err := s.getOrCreateProductWarehouse(c, warehouse.Id, conversionCategoryCode, dbTransaction, actorID)
|
||||
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 {
|
||||
s.Log.Warnf("failed to get chickins for rejection %d: %v", approvableID, err)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("failed to get chickins for rejection %d: %w", approvableID, err)
|
||||
}
|
||||
|
||||
if len(chickins) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -371,12 +418,21 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
updates := map[string]any{"quantity": chickin.PendingUsageQty}
|
||||
|
||||
if err := productWarehouseTx.PatchOne(c.Context(), chickin.ProductWarehouseId, updates, nil); err != nil {
|
||||
s.Log.Warnf("failed to restore product warehouse quantity for rejection: %v", err)
|
||||
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)
|
||||
}
|
||||
|
||||
if err := chickinRepoTx.DeleteOne(c.Context(), chickin.Id); err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("failed to delete rejected chickin %d: %w", chickin.Id, err)
|
||||
}
|
||||
s.Log.Infof("chickin %d already deleted during rejection", chickin.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -387,7 +443,6 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Chickin not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to record approval for chickins %+v: %+v", approvableIDs, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to record approval")
|
||||
}
|
||||
|
||||
@@ -403,39 +458,39 @@ func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entit
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s *chickinService) getOrCreatePulletProductWarehouse(ctx *fiber.Ctx, warehouseId uint, dbTransaction *gorm.DB, actorID uint) (*entity.ProductWarehouse, error) {
|
||||
func (s *chickinService) getOrCreateProductWarehouse(ctx *fiber.Ctx, warehouseId uint, categoryCode string, dbTransaction *gorm.DB, actorID uint) (*entity.ProductWarehouse, error) {
|
||||
|
||||
pulletProducts, err := s.ProductWarehouseRepo.GetByCategoryCodeAndWarehouseID(ctx.Context(), "PULLET", warehouseId)
|
||||
if err == nil && len(pulletProducts) > 0 {
|
||||
return &pulletProducts[0], nil
|
||||
products, err := s.ProductWarehouseRepo.GetByCategoryCodeAndWarehouseID(ctx.Context(), categoryCode, warehouseId)
|
||||
if err == nil && len(products) > 0 {
|
||||
return &products[0], nil
|
||||
}
|
||||
|
||||
pulletProduct, err := s.ProductWarehouseRepo.GetFirstProductByCategoryCode(ctx.Context(), "PULLET")
|
||||
product, err := s.ProductWarehouseRepo.GetFirstProductByCategoryCode(ctx.Context(), categoryCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get PULLET product: %w", err)
|
||||
return nil, fmt.Errorf("failed to get %s product: %w", categoryCode, err)
|
||||
}
|
||||
if pulletProduct == nil {
|
||||
return nil, fmt.Errorf("no PULLET product found in system")
|
||||
if product == nil {
|
||||
return nil, fmt.Errorf("no %s product found in system", categoryCode)
|
||||
}
|
||||
|
||||
newPulletPW := &entity.ProductWarehouse{
|
||||
ProductId: pulletProduct.Id,
|
||||
newPW := &entity.ProductWarehouse{
|
||||
ProductId: product.Id,
|
||||
WarehouseId: warehouseId,
|
||||
Quantity: 0,
|
||||
CreatedBy: actorID,
|
||||
}
|
||||
|
||||
if err := s.ProductWarehouseRepo.WithTx(dbTransaction).CreateOne(ctx.Context(), newPulletPW, nil); err != nil {
|
||||
return nil, fmt.Errorf("failed to create PULLET product warehouse: %w", err)
|
||||
if err := s.ProductWarehouseRepo.WithTx(dbTransaction).CreateOne(ctx.Context(), newPW, nil); err != nil {
|
||||
return nil, fmt.Errorf("failed to create %s product warehouse: %w", categoryCode, err)
|
||||
}
|
||||
|
||||
return newPulletPW, nil
|
||||
return newPW, nil
|
||||
}
|
||||
|
||||
func (s *chickinService) convertChickinsToPullet(ctx *fiber.Ctx, chickins []entity.ProjectChickin, pulletPW *entity.ProductWarehouse, dbTransaction *gorm.DB, actorID uint) error {
|
||||
func (s *chickinService) convertChickinsToTarget(ctx *fiber.Ctx, chickins []entity.ProjectChickin, targetPW *entity.ProductWarehouse, dbTransaction *gorm.DB, actorID uint) error {
|
||||
|
||||
if pulletPW == nil || pulletPW.Id == 0 {
|
||||
return fmt.Errorf("invalid PULLET product warehouse")
|
||||
if targetPW == nil || targetPW.Id == 0 {
|
||||
return fmt.Errorf("invalid target product warehouse")
|
||||
}
|
||||
|
||||
chickinRepoTx := repository.NewChickinRepository(dbTransaction)
|
||||
@@ -444,6 +499,16 @@ func (s *chickinService) convertChickinsToPullet(ctx *fiber.Ctx, chickins []enti
|
||||
|
||||
for _, chickin := range chickins {
|
||||
|
||||
populationExists, err := ProjectFlockPopulationRepotx.ExistsByProjectChickinID(ctx.Context(), chickin.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check population existence for chickin %d: %w", chickin.Id, err)
|
||||
}
|
||||
|
||||
if populationExists {
|
||||
s.Log.Infof("population already exists for chickin %d, skipping", chickin.Id)
|
||||
continue
|
||||
}
|
||||
|
||||
quantityToConvert := chickin.PendingUsageQty
|
||||
|
||||
if err := chickinRepoTx.PatchOne(ctx.Context(), chickin.Id, map[string]any{
|
||||
@@ -453,52 +518,31 @@ func (s *chickinService) convertChickinsToPullet(ctx *fiber.Ctx, chickins []enti
|
||||
return fmt.Errorf("failed to update chickin %d qty: %w", chickin.Id, err)
|
||||
}
|
||||
|
||||
// Update quantity di PULLET product warehouse dengan quantity dari chickin
|
||||
if err := productWarehouseTx.PatchOne(ctx.Context(), pulletPW.Id, map[string]any{
|
||||
if err := productWarehouseTx.PatchOne(ctx.Context(), targetPW.Id, map[string]any{
|
||||
"quantity": gorm.Expr("quantity + ?", quantityToConvert),
|
||||
}, nil); err != nil {
|
||||
s.Log.Warnf("failed to update PULLET warehouse quantity: %v", err)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Target product warehouse %d not found", targetPW.Id))
|
||||
}
|
||||
return fmt.Errorf("failed to update target warehouse quantity: %w", err)
|
||||
}
|
||||
|
||||
populationExists, err := ProjectFlockPopulationRepotx.ExistsByProjectChickinID(ctx.Context(), chickin.Id)
|
||||
if err != nil {
|
||||
s.Log.Warnf("failed to check population existence for chickin %d: %v", chickin.Id, err)
|
||||
continue
|
||||
population := &entity.ProjectFlockPopulation{
|
||||
ProjectChickinId: chickin.Id,
|
||||
ProductWarehouseId: targetPW.Id,
|
||||
TotalQty: quantityToConvert,
|
||||
TotalUsedQty: 0,
|
||||
Notes: chickin.Notes,
|
||||
CreatedBy: actorID,
|
||||
}
|
||||
|
||||
if !populationExists {
|
||||
population := &entity.ProjectFlockPopulation{
|
||||
ProjectChickinId: chickin.Id,
|
||||
ProductWarehouseId: pulletPW.Id,
|
||||
TotalQty: quantityToConvert,
|
||||
TotalUsedQty: 0,
|
||||
Notes: chickin.Notes,
|
||||
CreatedBy: actorID,
|
||||
if err := ProjectFlockPopulationRepotx.CreateOne(ctx.Context(), population, nil); err != nil {
|
||||
lower := strings.ToLower(err.Error())
|
||||
if !(strings.Contains(lower, "duplicate") || strings.Contains(lower, "unique constraint") || strings.Contains(lower, "23505")) {
|
||||
return err
|
||||
}
|
||||
if err := ProjectFlockPopulationRepotx.CreateOne(ctx.Context(), population, nil); err != nil {
|
||||
lower := strings.ToLower(err.Error())
|
||||
if !(strings.Contains(lower, "duplicate") || strings.Contains(lower, "unique constraint") || strings.Contains(lower, "23505")) {
|
||||
return err
|
||||
}
|
||||
s.Log.Infof("ignored duplicate population for chickin %d: %v", chickin.Id, err)
|
||||
}
|
||||
} else {
|
||||
s.Log.Infof("population already exists for chickin %d", chickin.Id)
|
||||
s.Log.Infof("ignored duplicate population for chickin %d: %v", chickin.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func uniqueUintSlice(values []uint) []uint {
|
||||
seen := make(map[uint]struct{}, len(values))
|
||||
result := make([]uint, 0, len(values))
|
||||
for _, v := range values {
|
||||
if _, ok := seen[v]; ok {
|
||||
continue
|
||||
}
|
||||
seen[v] = struct{}{}
|
||||
result = append(result, v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
+153
-160
@@ -8,8 +8,9 @@ import (
|
||||
areaDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
|
||||
fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto"
|
||||
flockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/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"
|
||||
productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto"
|
||||
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||
chickinDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/dto"
|
||||
projectFlockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/dto"
|
||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||
@@ -27,7 +28,7 @@ type ProjectFlockCustomDTO struct {
|
||||
Category string `json:"category"`
|
||||
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"`
|
||||
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"`
|
||||
Kandangs []kandangDTO.KandangBaseDTO `json:"kandangs,omitempty"`
|
||||
Kandangs []KandangCustomDTO `json:"kandangs,omitempty"`
|
||||
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
@@ -39,22 +40,11 @@ type KandangCustomDTO struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type ProductBaseDTO struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type WarehouseBaseDTO struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type ProductWarehouseDTO struct {
|
||||
Id uint `json:"id"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
Product *ProductBaseDTO `json:"product,omitempty"`
|
||||
Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"`
|
||||
Id uint `json:"id"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
Product *productDTO.ProductBaseDTO `json:"product,omitempty"`
|
||||
Warehouse *warehouseDTO.WarehouseBaseDTO `json:"warehouse,omitempty"`
|
||||
}
|
||||
|
||||
type AvailableQtyDTO struct {
|
||||
@@ -95,74 +85,38 @@ func toProjectFlockCustomDTO(pf *projectFlockDTO.ProjectFlockListDTO) *ProjectFl
|
||||
Category: pf.Category,
|
||||
Fcr: pf.Fcr,
|
||||
Location: pf.Location,
|
||||
Kandangs: pf.Kandangs,
|
||||
Kandangs: buildKandangCustomDTOs(pf.Kandangs),
|
||||
CreatedUser: pf.CreatedUser,
|
||||
CreatedAt: pf.CreatedAt,
|
||||
UpdatedAt: pf.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func buildAvailableQtys(chickins []entity.ProjectChickin) []AvailableQtyDTO {
|
||||
if len(chickins) == 0 {
|
||||
return nil
|
||||
func ToProjectFlockKandangListDTOWithAvailableQty(e entity.ProjectFlockKandang, availableQtysRaw []map[string]interface{}) ProjectFlockKandangListDTO {
|
||||
var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO
|
||||
if e.ProjectFlock.Id != 0 {
|
||||
mapped := projectFlockDTO.ToProjectFlockListDTO(e.ProjectFlock)
|
||||
projectFlockSummary = &mapped
|
||||
}
|
||||
|
||||
availableQtyMap := make(map[uint]AvailableQtyDTO)
|
||||
for _, ch := range chickins {
|
||||
if ch.ProductWarehouse == nil || ch.ProductWarehouse.Quantity <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := availableQtyMap[ch.ProductWarehouseId]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
pwDTO := &ProductWarehouseDTO{
|
||||
Id: ch.ProductWarehouse.Id,
|
||||
Quantity: ch.ProductWarehouse.Quantity,
|
||||
}
|
||||
|
||||
if ch.ProductWarehouse.Product.Id != 0 {
|
||||
pwDTO.Product = &ProductBaseDTO{
|
||||
Id: ch.ProductWarehouse.Product.Id,
|
||||
Name: ch.ProductWarehouse.Product.Name,
|
||||
}
|
||||
}
|
||||
|
||||
if ch.ProductWarehouse.Warehouse.Id != 0 {
|
||||
pwDTO.Warehouse = &WarehouseBaseDTO{
|
||||
Id: ch.ProductWarehouse.Warehouse.Id,
|
||||
Name: ch.ProductWarehouse.Warehouse.Name,
|
||||
Type: ch.ProductWarehouse.Warehouse.Type,
|
||||
}
|
||||
}
|
||||
|
||||
availableQtyMap[ch.ProductWarehouseId] = AvailableQtyDTO{
|
||||
ProductWarehouse: pwDTO,
|
||||
}
|
||||
return ProjectFlockKandangListDTO{
|
||||
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e),
|
||||
ProjectFlock: toProjectFlockCustomDTO(projectFlockSummary),
|
||||
Kandang: buildKandangFromEntity(e.Kandang),
|
||||
Chickins: buildChickins(e.Chickins),
|
||||
AvailableQtys: buildAvailableQtysFromRaw(availableQtysRaw),
|
||||
CreatedAt: e.CreatedAt,
|
||||
CreatedUser: buildCreatedUser(e.ProjectFlock),
|
||||
Approval: defaultProjectFlockKandangLatestApproval(e),
|
||||
}
|
||||
|
||||
if len(availableQtyMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]AvailableQtyDTO, 0, len(availableQtyMap))
|
||||
for _, v := range availableQtyMap {
|
||||
result = append(result, v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildChickins(chickins []entity.ProjectChickin) []chickinDTO.ChickinBaseDTO {
|
||||
if len(chickins) == 0 {
|
||||
return nil
|
||||
func toKandangCustomDTO(k projectFlockDTO.KandangWithProjectFlockIdDTO) KandangCustomDTO {
|
||||
return KandangCustomDTO{
|
||||
Id: k.Id,
|
||||
Name: k.Name,
|
||||
Status: k.Status,
|
||||
}
|
||||
|
||||
result := make([]chickinDTO.ChickinBaseDTO, len(chickins))
|
||||
for i, ch := range chickins {
|
||||
result[i] = chickinDTO.ToChickinBaseDTO(ch)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func defaultProjectFlockKandangLatestApproval(e entity.ProjectFlockKandang) *approvalDTO.ApprovalBaseDTO {
|
||||
@@ -180,32 +134,14 @@ func ToProjectFlockKandangListDTO(e entity.ProjectFlockKandang) ProjectFlockKand
|
||||
projectFlockSummary = &mapped
|
||||
}
|
||||
|
||||
var kandangSummary *KandangCustomDTO
|
||||
if e.Kandang.Id != 0 {
|
||||
kandangSummary = &KandangCustomDTO{
|
||||
Id: e.Kandang.Id,
|
||||
Name: e.Kandang.Name,
|
||||
Status: e.Kandang.Status,
|
||||
}
|
||||
}
|
||||
|
||||
var createdUser *userDTO.UserBaseDTO
|
||||
if e.ProjectFlock.CreatedUser.Id != 0 {
|
||||
mapped := userDTO.ToUserBaseDTO(e.ProjectFlock.CreatedUser)
|
||||
createdUser = &mapped
|
||||
} else if e.ProjectFlock.CreatedBy != 0 {
|
||||
mapped := userDTO.UserBaseDTO{Id: e.ProjectFlock.CreatedBy, IdUser: int64(e.ProjectFlock.CreatedBy)}
|
||||
createdUser = &mapped
|
||||
}
|
||||
|
||||
return ProjectFlockKandangListDTO{
|
||||
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e),
|
||||
ProjectFlock: toProjectFlockCustomDTO(projectFlockSummary),
|
||||
Kandang: kandangSummary,
|
||||
Kandang: buildKandangFromEntity(e.Kandang),
|
||||
Chickins: buildChickins(e.Chickins),
|
||||
AvailableQtys: buildAvailableQtys(e.Chickins),
|
||||
CreatedAt: e.CreatedAt,
|
||||
CreatedUser: createdUser,
|
||||
CreatedUser: buildCreatedUser(e.ProjectFlock),
|
||||
Approval: defaultProjectFlockKandangLatestApproval(e),
|
||||
}
|
||||
}
|
||||
@@ -224,69 +160,6 @@ func ToProjectFlockKandangDetailDTO(e entity.ProjectFlockKandang) ProjectFlockKa
|
||||
}
|
||||
}
|
||||
|
||||
func ToProjectFlockKandangListDTOWithAvailableQty(e entity.ProjectFlockKandang, availableQtysRaw []map[string]interface{}) ProjectFlockKandangListDTO {
|
||||
var projectFlockSummary *projectFlockDTO.ProjectFlockListDTO
|
||||
if e.ProjectFlock.Id != 0 {
|
||||
mapped := projectFlockDTO.ToProjectFlockListDTO(e.ProjectFlock)
|
||||
projectFlockSummary = &mapped
|
||||
}
|
||||
|
||||
var kandangSummary *KandangCustomDTO
|
||||
if e.Kandang.Id != 0 {
|
||||
kandangSummary = &KandangCustomDTO{
|
||||
Id: e.Kandang.Id,
|
||||
Name: e.Kandang.Name,
|
||||
Status: e.Kandang.Status,
|
||||
}
|
||||
}
|
||||
|
||||
var createdUser *userDTO.UserBaseDTO
|
||||
if e.ProjectFlock.CreatedUser.Id != 0 {
|
||||
mapped := userDTO.ToUserBaseDTO(e.ProjectFlock.CreatedUser)
|
||||
createdUser = &mapped
|
||||
} else if e.ProjectFlock.CreatedBy != 0 {
|
||||
mapped := userDTO.UserBaseDTO{Id: e.ProjectFlock.CreatedBy, IdUser: int64(e.ProjectFlock.CreatedBy)}
|
||||
createdUser = &mapped
|
||||
}
|
||||
|
||||
// convert available qtys from raw map data
|
||||
var availableQtys []AvailableQtyDTO
|
||||
if len(availableQtysRaw) > 0 {
|
||||
availableQtys = buildAvailableQtysFromRaw(availableQtysRaw)
|
||||
}
|
||||
|
||||
return ProjectFlockKandangListDTO{
|
||||
ProjectFlockKandangBaseDTO: ToProjectFlockKandangBaseDTO(e),
|
||||
ProjectFlock: toProjectFlockCustomDTO(projectFlockSummary),
|
||||
Kandang: kandangSummary,
|
||||
Chickins: buildChickins(e.Chickins),
|
||||
AvailableQtys: availableQtys,
|
||||
CreatedAt: e.CreatedAt,
|
||||
CreatedUser: createdUser,
|
||||
Approval: defaultProjectFlockKandangLatestApproval(e),
|
||||
}
|
||||
}
|
||||
|
||||
func buildAvailableQtysFromRaw(availableQtysRaw []map[string]interface{}) []AvailableQtyDTO {
|
||||
if len(availableQtysRaw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]AvailableQtyDTO, len(availableQtysRaw))
|
||||
for i, v := range availableQtysRaw {
|
||||
pwData, ok := v["product_warehouse"].(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
pwDTO := buildProductWarehouseFromMap(pwData)
|
||||
result[i] = AvailableQtyDTO{
|
||||
ProductWarehouse: pwDTO,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildProductWarehouseFromMap(pwData map[string]interface{}) *ProductWarehouseDTO {
|
||||
if pwData == nil {
|
||||
return nil
|
||||
@@ -315,12 +188,12 @@ func buildProductWarehouseFromMap(pwData map[string]interface{}) *ProductWarehou
|
||||
return dto
|
||||
}
|
||||
|
||||
func buildProductFromMap(pData map[string]interface{}) *ProductBaseDTO {
|
||||
func buildProductFromMap(pData map[string]interface{}) *productDTO.ProductBaseDTO {
|
||||
if pData == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
product := &ProductBaseDTO{}
|
||||
product := &productDTO.ProductBaseDTO{}
|
||||
if id, ok := pData["id"].(float64); ok {
|
||||
product.Id = uint(id)
|
||||
} else if id, ok := pData["id"].(uint); ok {
|
||||
@@ -332,12 +205,12 @@ func buildProductFromMap(pData map[string]interface{}) *ProductBaseDTO {
|
||||
return product
|
||||
}
|
||||
|
||||
func buildWarehouseFromMap(wData map[string]interface{}) *WarehouseBaseDTO {
|
||||
func buildWarehouseFromMap(wData map[string]interface{}) *warehouseDTO.WarehouseBaseDTO {
|
||||
if wData == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
warehouse := &WarehouseBaseDTO{}
|
||||
warehouse := &warehouseDTO.WarehouseBaseDTO{}
|
||||
if id, ok := wData["id"].(float64); ok {
|
||||
warehouse.Id = uint(id)
|
||||
} else if id, ok := wData["id"].(uint); ok {
|
||||
@@ -351,3 +224,123 @@ func buildWarehouseFromMap(wData map[string]interface{}) *WarehouseBaseDTO {
|
||||
}
|
||||
return warehouse
|
||||
}
|
||||
|
||||
func buildCreatedUser(pf entity.ProjectFlock) *userDTO.UserBaseDTO {
|
||||
if pf.CreatedUser.Id != 0 {
|
||||
mapped := userDTO.ToUserBaseDTO(pf.CreatedUser)
|
||||
return &mapped
|
||||
} else if pf.CreatedBy != 0 {
|
||||
return &userDTO.UserBaseDTO{
|
||||
Id: pf.CreatedBy,
|
||||
IdUser: int64(pf.CreatedBy),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildKandangCustomDTOs(kandangs []projectFlockDTO.KandangWithProjectFlockIdDTO) []KandangCustomDTO {
|
||||
if len(kandangs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]KandangCustomDTO, len(kandangs))
|
||||
for i, k := range kandangs {
|
||||
result[i] = toKandangCustomDTO(k)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildKandangFromEntity(kandang entity.Kandang) *KandangCustomDTO {
|
||||
if kandang.Id == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &KandangCustomDTO{
|
||||
Id: kandang.Id,
|
||||
Name: kandang.Name,
|
||||
Status: kandang.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func buildChickins(chickins []entity.ProjectChickin) []chickinDTO.ChickinBaseDTO {
|
||||
if len(chickins) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]chickinDTO.ChickinBaseDTO, len(chickins))
|
||||
for i, ch := range chickins {
|
||||
result[i] = chickinDTO.ToChickinBaseDTO(ch)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildAvailableQtys(chickins []entity.ProjectChickin) []AvailableQtyDTO {
|
||||
if len(chickins) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
availableQtyMap := make(map[uint]AvailableQtyDTO)
|
||||
for _, ch := range chickins {
|
||||
if ch.ProductWarehouse == nil || ch.ProductWarehouse.Quantity <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := availableQtyMap[ch.ProductWarehouseId]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
pwDTO := &ProductWarehouseDTO{
|
||||
Id: ch.ProductWarehouse.Id,
|
||||
Quantity: ch.ProductWarehouse.Quantity,
|
||||
}
|
||||
|
||||
if ch.ProductWarehouse.Product.Id != 0 {
|
||||
pwDTO.Product = &productDTO.ProductBaseDTO{
|
||||
Id: ch.ProductWarehouse.Product.Id,
|
||||
Name: ch.ProductWarehouse.Product.Name,
|
||||
}
|
||||
}
|
||||
|
||||
if ch.ProductWarehouse.Warehouse.Id != 0 {
|
||||
pwDTO.Warehouse = &warehouseDTO.WarehouseBaseDTO{
|
||||
Id: ch.ProductWarehouse.Warehouse.Id,
|
||||
Name: ch.ProductWarehouse.Warehouse.Name,
|
||||
Type: ch.ProductWarehouse.Warehouse.Type,
|
||||
}
|
||||
}
|
||||
|
||||
availableQtyMap[ch.ProductWarehouseId] = AvailableQtyDTO{
|
||||
ProductWarehouse: pwDTO,
|
||||
}
|
||||
}
|
||||
|
||||
if len(availableQtyMap) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]AvailableQtyDTO, 0, len(availableQtyMap))
|
||||
for _, v := range availableQtyMap {
|
||||
result = append(result, v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func buildAvailableQtysFromRaw(availableQtysRaw []map[string]interface{}) []AvailableQtyDTO {
|
||||
if len(availableQtysRaw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]AvailableQtyDTO, len(availableQtysRaw))
|
||||
for i, v := range availableQtysRaw {
|
||||
pwData, ok := v["product_warehouse"].(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
pwDTO := buildProductWarehouseFromMap(pwData)
|
||||
result[i] = AvailableQtyDTO{
|
||||
ProductWarehouse: pwDTO,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -20,18 +20,25 @@ type ProjectFlockBaseDTO struct {
|
||||
Period int `json:"period"`
|
||||
}
|
||||
|
||||
type KandangWithProjectFlockIdDTO struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||
}
|
||||
|
||||
type ProjectFlockListDTO struct {
|
||||
ProjectFlockBaseDTO
|
||||
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"`
|
||||
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"`
|
||||
Category string `json:"category"`
|
||||
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"`
|
||||
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"`
|
||||
Kandangs []kandangDTO.KandangBaseDTO `json:"kandangs,omitempty"`
|
||||
CreatedUser *userDTO.UserBaseDTO `json:"created_user"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Approval approvalDTO.ApprovalBaseDTO `json:"approval"`
|
||||
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"`
|
||||
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"`
|
||||
Category string `json:"category"`
|
||||
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"`
|
||||
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"`
|
||||
Kandangs []KandangWithProjectFlockIdDTO `json:"kandangs,omitempty"`
|
||||
CreatedUser *userDTO.UserBaseDTO `json:"created_user"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Approval approvalDTO.ApprovalBaseDTO `json:"approval"`
|
||||
}
|
||||
|
||||
type ProjectFlockDetailDTO struct {
|
||||
@@ -50,11 +57,24 @@ func ToProjectFlockListDTO(e entity.ProjectFlock) ProjectFlockListDTO {
|
||||
createdUser = &mapped
|
||||
}
|
||||
|
||||
var kandangSummaries []kandangDTO.KandangBaseDTO
|
||||
var kandangSummaries []KandangWithProjectFlockIdDTO
|
||||
if len(e.Kandangs) > 0 {
|
||||
kandangSummaries = make([]kandangDTO.KandangBaseDTO, len(e.Kandangs))
|
||||
kandangSummaries = make([]KandangWithProjectFlockIdDTO, len(e.Kandangs))
|
||||
|
||||
// Create a map of KandangId -> ProjectFlockKandangId from KandangHistory
|
||||
kandangIdToProjectFlockKandangId := make(map[uint]uint)
|
||||
for _, kh := range e.KandangHistory {
|
||||
kandangIdToProjectFlockKandangId[kh.KandangId] = kh.Id
|
||||
}
|
||||
|
||||
for i, kandang := range e.Kandangs {
|
||||
kandangSummaries[i] = kandangDTO.ToKandangBaseDTO(kandang)
|
||||
baseDTO := kandangDTO.ToKandangBaseDTO(kandang)
|
||||
kandangSummaries[i] = KandangWithProjectFlockIdDTO{
|
||||
Id: baseDTO.Id,
|
||||
Name: baseDTO.Name,
|
||||
Status: baseDTO.Status,
|
||||
ProjectFlockKandangId: kandangIdToProjectFlockKandangId[kandang.Id],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,9 @@ func (s projectflockService) withRelations(db *gorm.DB) *gorm.DB {
|
||||
Preload("Area").
|
||||
Preload("Fcr").
|
||||
Preload("Location").
|
||||
Preload("Kandangs")
|
||||
Preload("Kandangs").
|
||||
Preload("KandangHistory").
|
||||
Preload("KandangHistory.Kandang")
|
||||
}
|
||||
|
||||
func (s projectflockService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlock, int64, error) {
|
||||
|
||||
Reference in New Issue
Block a user