mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 15:25:43 +00:00
Merge branch 'feat/BE/Sprint-7' of https://gitlab.com/mbugroup/lti-api into feat/BE/US-304/permission-middleware-adjustment
This commit is contained in:
+54
@@ -84,3 +84,57 @@ func (u *ProjectFlockKandangController) GetOne(c *fiber.Ctx) error {
|
||||
Data: dto.ToProjectFlockKandangDetailDTOWithAvailableQty(*result, availableQtys, productWarehouses),
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ProjectFlockKandangController) Closing(c *fiber.Ctx) error {
|
||||
id, err := strconv.Atoi(c.Params("id"))
|
||||
if err != nil || id <= 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
}
|
||||
|
||||
req := new(validation.Closing)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
result, err := u.ProjectFlockKandangService.Closing(c, uint(id), req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
detail, availableQtys, productWarehouses, err := u.ProjectFlockKandangService.GetOne(c, result.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
detailDTO := dto.ToProjectFlockKandangDetailDTOWithAvailableQty(*detail, availableQtys, productWarehouses)
|
||||
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.Success{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Status closing kandang diperbarui",
|
||||
Data: fiber.Map{
|
||||
"detail": detailDTO,
|
||||
"approval": detailDTO.Approval,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ProjectFlockKandangController) CheckClosing(c *fiber.Ctx) error {
|
||||
id, err := strconv.Atoi(c.Params("id"))
|
||||
if err != nil || id <= 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||
}
|
||||
|
||||
result, err := u.ProjectFlockKandangService.CheckClosing(c, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(response.Success{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Cek persyaratan closing kandang",
|
||||
Data: result,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ import (
|
||||
|
||||
sProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/services"
|
||||
rProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
|
||||
rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
|
||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
rExpense "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
@@ -28,15 +29,17 @@ func (ProjectFlockKandangModule) RegisterRoutes(router fiber.Router, db *gorm.DB
|
||||
userRepo := rUser.NewUserRepository(db)
|
||||
warehouseRepo := rWarehouse.NewWarehouseRepository(db)
|
||||
productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db)
|
||||
kandangRepo := rKandang.NewKandangRepository(db)
|
||||
|
||||
approvalRepo := commonRepo.NewApprovalRepository(db)
|
||||
approvalService := commonSvc.NewApprovalService(approvalRepo)
|
||||
// register workflow steps for project flock kandang approvals
|
||||
// register workflow steps for chickin approvals
|
||||
if err := approvalService.RegisterWorkflowSteps(utils.ApprovalWorkflowProjectFlockKandang, utils.ProjectFlockKandangApprovalSteps); err != nil {
|
||||
panic(fmt.Sprintf("failed to register project flock kandang approval workflow: %v", err))
|
||||
panic(fmt.Sprintf("failed to register chickin approval workflow: %v", err))
|
||||
}
|
||||
|
||||
projectFlockKandangService := sProjectFlockKandang.NewProjectFlockKandangService(projectFlockKandangRepo, approvalService, warehouseRepo, productWarehouseRepo, projectFlockPopulationRepo, validate)
|
||||
expenseRepo := rExpense.NewExpenseRepository(db)
|
||||
projectFlockKandangService := sProjectFlockKandang.NewProjectFlockKandangService(projectFlockKandangRepo, approvalService, expenseRepo, warehouseRepo, productWarehouseRepo, projectFlockPopulationRepo,kandangRepo, validate)
|
||||
userService := sUser.NewUserService(userRepo, validate)
|
||||
|
||||
ProjectFlockKandangRoutes(router, userService, projectFlockKandangService)
|
||||
|
||||
@@ -16,5 +16,8 @@ func ProjectFlockKandangRoutes(v1 fiber.Router, u user.UserService, s projectFlo
|
||||
route.Use(m.Auth(u))
|
||||
route.Get("/",m.RequirePermissions(m.P_ProjectFlockKandangsGetAll), ctrl.GetAll)
|
||||
route.Get("/:id",m.RequirePermissions(m.P_ProjectFlockKandangsGetOne), ctrl.GetOne)
|
||||
|
||||
// route.Post("/:id/closing", m.RequirePermissions(m.PermissionProjectFlockClosing), ctrl.Closing)
|
||||
// route.Get("/:id/closing/check", m.RequirePermissions(m.PermissionProjectFlockClosing), ctrl.CheckClosing)
|
||||
route.Post("/:id/closing", ctrl.Closing)
|
||||
route.Get("/:id/closing/check", ctrl.CheckClosing)
|
||||
}
|
||||
|
||||
+393
-11
@@ -2,47 +2,84 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/validations"
|
||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||
rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories"
|
||||
kandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories"
|
||||
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project-flock-kandangs/validations"
|
||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ProjectFlockKandangService interface {
|
||||
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandang, int64, error)
|
||||
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, map[uint]float64, []entity.ProductWarehouse, error)
|
||||
CheckClosing(ctx *fiber.Ctx, id uint) (*ClosingCheckResult, error)
|
||||
Closing(ctx *fiber.Ctx, id uint, req *validation.Closing) (*entity.ProjectFlockKandang, error)
|
||||
GetProjectFlockKandangClosingDate(c *fiber.Ctx, id uint) (*time.Time, error)
|
||||
}
|
||||
|
||||
// Note: map[uint]float64 adalah mapping dari ProductWarehouse ID ke calculated available quantity
|
||||
|
||||
type projectFlockKandangService struct {
|
||||
Log *logrus.Logger
|
||||
Validate *validator.Validate
|
||||
Repository repository.ProjectFlockKandangRepository
|
||||
ApprovalSvc commonSvc.ApprovalService
|
||||
ExpenseRepo expenseRepo.ExpenseRepository
|
||||
WarehouseRepo rWarehouse.WarehouseRepository
|
||||
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
|
||||
PopulationRepo repository.ProjectFlockPopulationRepository
|
||||
KandangRepo kandangRepo.KandangRepository
|
||||
}
|
||||
|
||||
func NewProjectFlockKandangService(repo repository.ProjectFlockKandangRepository, approvalSvc commonSvc.ApprovalService, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, populationRepo repository.ProjectFlockPopulationRepository, validate *validator.Validate) ProjectFlockKandangService {
|
||||
type ClosingCheckResult struct {
|
||||
UnfinishedExpenses int64 `json:"unfinished_expenses"`
|
||||
StockRemaining []StockRemainingDetail `json:"stock_remaining"`
|
||||
Expenses []ExpenseSummary `json:"expenses"`
|
||||
}
|
||||
|
||||
type StockRemainingDetail struct {
|
||||
FlagName string `json:"flag_name"`
|
||||
ProductWarehouseId uint `json:"product_warehouse_id"`
|
||||
ProductId uint `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
ProductCategory string `json:"product_category"`
|
||||
Uom string `json:"uom"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
}
|
||||
|
||||
type ExpenseSummary struct {
|
||||
Id uint64 `json:"id"`
|
||||
PoNumber string `json:"po_number"`
|
||||
Category string `json:"category"`
|
||||
Total float64 `json:"total"`
|
||||
Status string `json:"status"`
|
||||
StepName string `json:"step_name"`
|
||||
Step uint16 `json:"step"`
|
||||
Reference string `json:"reference_number"`
|
||||
}
|
||||
|
||||
func NewProjectFlockKandangService(repo repository.ProjectFlockKandangRepository, approvalSvc commonSvc.ApprovalService, expenseRepo expenseRepo.ExpenseRepository, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, populationRepo repository.ProjectFlockPopulationRepository, kandangRepo kandangRepo.KandangRepository, validate *validator.Validate) ProjectFlockKandangService {
|
||||
return &projectFlockKandangService{
|
||||
Log: utils.Log,
|
||||
Validate: validate,
|
||||
Repository: repo,
|
||||
ApprovalSvc: approvalSvc,
|
||||
ExpenseRepo: expenseRepo,
|
||||
WarehouseRepo: warehouseRepo,
|
||||
ProductWarehouseRepo: productWarehouseRepo,
|
||||
PopulationRepo: populationRepo,
|
||||
KandangRepo: kandangRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +203,351 @@ func (s projectFlockKandangService) getAvailableQuantities(c *fiber.Ctx, project
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s projectFlockKandangService) CheckClosing(c *fiber.Ctx, id uint) (*ClosingCheckResult, error) {
|
||||
pfk, err := s.Repository.GetByID(c.Context(), id)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var unfinished int64
|
||||
if s.ExpenseRepo != nil && s.ApprovalSvc != nil {
|
||||
count, err := s.ExpenseRepo.CountUnfinishedByProjectFlockKandang(c.Context(), pfk.Id, pfk.KandangId, func(appr *entity.Approval) bool {
|
||||
return appr != nil && appr.StepNumber == uint16(utils.ExpenseStepSelesai) && appr.Action != nil && *appr.Action == entity.ApprovalActionApproved
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unfinished = count
|
||||
}
|
||||
|
||||
stockRemain := make([]StockRemainingDetail, 0)
|
||||
if s.WarehouseRepo != nil && s.ProductWarehouseRepo != nil {
|
||||
warehouse, werr := s.WarehouseRepo.GetByKandangID(c.Context(), pfk.KandangId)
|
||||
if werr != nil {
|
||||
return nil, werr
|
||||
}
|
||||
|
||||
for _, flagName := range []utils.FlagType{utils.FlagPakan, utils.FlagOVK} {
|
||||
productWarehouses, pwErr := s.ProductWarehouseRepo.GetByFlagAndWarehouseID(c.Context(), string(flagName), warehouse.Id)
|
||||
if pwErr != nil {
|
||||
return nil, pwErr
|
||||
}
|
||||
|
||||
for _, pw := range productWarehouses {
|
||||
if pw.Quantity > 0 {
|
||||
category := ""
|
||||
if pw.Product.ProductCategory.Id != 0 {
|
||||
category = pw.Product.ProductCategory.Name
|
||||
}
|
||||
uomName := ""
|
||||
if pw.Product.Uom.Id != 0 {
|
||||
uomName = pw.Product.Uom.Name
|
||||
}
|
||||
stockRemain = append(stockRemain, StockRemainingDetail{
|
||||
FlagName: string(flagName),
|
||||
ProductWarehouseId: pw.Id,
|
||||
ProductId: pw.ProductId,
|
||||
ProductName: pw.Product.Name,
|
||||
ProductCategory: category,
|
||||
Uom: uomName,
|
||||
Quantity: pw.Quantity,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expenseSummaries := make([]ExpenseSummary, 0)
|
||||
if s.ExpenseRepo != nil {
|
||||
var expenses []entity.Expense
|
||||
if err := s.ExpenseRepo.DB().WithContext(c.Context()).
|
||||
Scopes(s.ExpenseRepo.WithProjectFlockKandangFilter(pfk.Id, pfk.KandangId)).
|
||||
Preload("Nonstocks").
|
||||
Find(&expenses).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(expenses) > 0 && s.ApprovalSvc != nil {
|
||||
ids := make([]uint, 0, len(expenses))
|
||||
for _, e := range expenses {
|
||||
ids = append(ids, uint(e.Id))
|
||||
}
|
||||
latestMap, err := s.ApprovalSvc.LatestByTargets(c.Context(), utils.ApprovalWorkflowExpense, ids, nil)
|
||||
if err == nil {
|
||||
for i := range expenses {
|
||||
if latest, ok := latestMap[uint(expenses[i].Id)]; ok {
|
||||
expenses[i].LatestApproval = latest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, exp := range expenses {
|
||||
total := 0.0
|
||||
for _, ns := range exp.Nonstocks {
|
||||
total += ns.Qty * ns.Price
|
||||
}
|
||||
|
||||
status := "Pending"
|
||||
stepName := ""
|
||||
stepNum := uint16(0)
|
||||
if exp.LatestApproval != nil {
|
||||
stepName = exp.LatestApproval.StepName
|
||||
stepNum = exp.LatestApproval.StepNumber
|
||||
if exp.LatestApproval.Action != nil {
|
||||
status = string(*exp.LatestApproval.Action)
|
||||
} else if stepName != "" {
|
||||
status = stepName
|
||||
}
|
||||
}
|
||||
|
||||
expenseSummaries = append(expenseSummaries, ExpenseSummary{
|
||||
Id: exp.Id,
|
||||
PoNumber: exp.PoNumber,
|
||||
Category: exp.Category,
|
||||
Total: total,
|
||||
Status: status,
|
||||
StepName: stepName,
|
||||
Step: stepNum,
|
||||
Reference: exp.ReferenceNumber,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &ClosingCheckResult{
|
||||
UnfinishedExpenses: unfinished,
|
||||
StockRemaining: stockRemain,
|
||||
Expenses: expenseSummaries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getProjectFlockKandangClosingDate mengembalikan tanggal closing PFK jika sudah di-close.
|
||||
func (s projectFlockKandangService) GetProjectFlockKandangClosingDate(c *fiber.Ctx, id uint) (*time.Time, error) {
|
||||
if id == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
pfk, err := s.Repository.GetByID(c.Context(), id)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return pfk.ClosedAt, nil
|
||||
}
|
||||
|
||||
func (s projectFlockKandangService) Closing(c *fiber.Ctx, id uint, req *validation.Closing) (*entity.ProjectFlockKandang, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actorID, err := m.ActorIDFromContext(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pfk, err := s.Repository.GetByID(c.Context(), id)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.ApprovalSvc != nil {
|
||||
latest, aerr := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlock, pfk.ProjectFlockId, nil)
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
if latest == nil || latest.Action == nil || *latest.Action != entity.ApprovalActionApproved {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Project flock belum berstatus aktif")
|
||||
}
|
||||
if latest.StepNumber != uint16(utils.ProjectFlockStepAktif) && latest.StepNumber != uint16(utils.ProjectFlockStepSelesai) {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Project flock belum berstatus aktif")
|
||||
}
|
||||
}
|
||||
|
||||
action := strings.ToLower(strings.TrimSpace(req.Action))
|
||||
now := time.Now()
|
||||
|
||||
switch action {
|
||||
case "close":
|
||||
if pfk.ClosedAt != nil {
|
||||
return nil, fiber.NewError(fiber.StatusConflict, "Kandang sudah closed")
|
||||
}
|
||||
if s.ExpenseRepo != nil && s.ApprovalSvc != nil {
|
||||
unfinished, err := s.ExpenseRepo.CountUnfinishedByProjectFlockKandang(c.Context(), pfk.Id, pfk.KandangId, func(appr *entity.Approval) bool {
|
||||
return appr != nil && appr.StepNumber == uint16(utils.ExpenseStepSelesai) && appr.Action != nil && *appr.Action == entity.ApprovalActionApproved
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unfinished > 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Masih ada expense belum selesai untuk kandang ini")
|
||||
}
|
||||
}
|
||||
|
||||
if s.WarehouseRepo != nil && s.ProductWarehouseRepo != nil {
|
||||
warehouse, werr := s.WarehouseRepo.GetByKandangID(c.Context(), pfk.KandangId)
|
||||
if werr != nil {
|
||||
return nil, werr
|
||||
}
|
||||
|
||||
for _, flagName := range []utils.FlagType{utils.FlagPakan, utils.FlagOVK} {
|
||||
productWarehouses, pwErr := s.ProductWarehouseRepo.GetByFlagAndWarehouseID(c.Context(), string(flagName), warehouse.Id)
|
||||
if pwErr != nil {
|
||||
return nil, pwErr
|
||||
}
|
||||
|
||||
for _, pw := range productWarehouses {
|
||||
if pw.Quantity > 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Stok %s masih tersedia (product warehouse %d: %.2f)", flagName, pw.Id, pw.Quantity))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeTime := now
|
||||
if req.ClosedDate != nil {
|
||||
parsed, perr := utils.ParseDateString(strings.TrimSpace(*req.ClosedDate))
|
||||
if perr != nil {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "closed_date tidak valid, gunakan format YYYY-MM-DD")
|
||||
}
|
||||
closeTime = parsed
|
||||
}
|
||||
if err := s.Repository.UpdateClosedAt(c.Context(), id, &closeTime); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.KandangRepo != nil {
|
||||
if err := s.KandangRepo.UpdateStatusByIDs(
|
||||
c.Context(),
|
||||
[]uint{pfk.KandangId},
|
||||
utils.KandangStatusNonActive,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if s.ApprovalSvc != nil {
|
||||
closeAction := entity.ApprovalActionApproved
|
||||
// Hindari duplikasi jika approval terakhir sudah Closed + Approved
|
||||
latestPFK, lerr := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, id, nil)
|
||||
if lerr != nil {
|
||||
return nil, lerr
|
||||
}
|
||||
shouldCreate := true
|
||||
if latestPFK != nil &&
|
||||
latestPFK.StepNumber == uint16(utils.ProjectFlockKandangStepClosed) &&
|
||||
latestPFK.Action != nil && *latestPFK.Action == closeAction {
|
||||
shouldCreate = false
|
||||
}
|
||||
|
||||
if shouldCreate {
|
||||
if _, aerr := s.ApprovalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlockKandang,
|
||||
id,
|
||||
utils.ProjectFlockKandangStepClosed,
|
||||
&closeAction,
|
||||
actorID,
|
||||
nil,
|
||||
); aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
}
|
||||
|
||||
// Jika semua kandang dalam project sudah ditutup, set approval project flock ke SELESAI.
|
||||
pfks, ferr := s.Repository.GetByProjectFlockID(c.Context(), pfk.ProjectFlockId)
|
||||
if ferr != nil {
|
||||
return nil, ferr
|
||||
}
|
||||
allClosed := true
|
||||
for _, item := range pfks {
|
||||
if item.ClosedAt == nil {
|
||||
allClosed = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allClosed {
|
||||
latestPF, lerr := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlock, pfk.ProjectFlockId, nil)
|
||||
if lerr != nil {
|
||||
return nil, lerr
|
||||
}
|
||||
if latestPF == nil || latestPF.StepNumber != uint16(utils.ProjectFlockStepSelesai) {
|
||||
if _, aerr := s.ApprovalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlock,
|
||||
pfk.ProjectFlockId,
|
||||
utils.ProjectFlockStepSelesai,
|
||||
&closeAction,
|
||||
actorID,
|
||||
nil,
|
||||
); aerr != nil && !errors.Is(aerr, gorm.ErrDuplicatedKey) {
|
||||
return nil, aerr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case "unclose":
|
||||
if pfk.ClosedAt == nil {
|
||||
return nil, fiber.NewError(fiber.StatusConflict, "Kandang belum closed")
|
||||
}
|
||||
openNewer, err := s.Repository.HasOpenNewerPeriod(c.Context(), pfk.KandangId, pfk.Period, &pfk.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if openNewer {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Tidak dapat un-close: ada periode yang sedang berjalan")
|
||||
}
|
||||
if err := s.Repository.UpdateClosedAt(c.Context(), id, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.KandangRepo != nil {
|
||||
if err := s.KandangRepo.UpdateStatusByIDs(
|
||||
c.Context(),
|
||||
[]uint{pfk.KandangId},
|
||||
utils.KandangStatusActive,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if s.ApprovalSvc != nil {
|
||||
reopenAction := entity.ApprovalActionUpdated
|
||||
// Hindari duplikasi jika approval terakhir sudah Disetujui + Updated
|
||||
latestPFK, lerr := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, id, nil)
|
||||
if lerr != nil {
|
||||
return nil, lerr
|
||||
}
|
||||
shouldCreate := true
|
||||
if latestPFK != nil &&
|
||||
latestPFK.StepNumber == uint16(utils.ProjectFlockKandangStepDisetujui) &&
|
||||
latestPFK.Action != nil && *latestPFK.Action == reopenAction {
|
||||
shouldCreate = false
|
||||
}
|
||||
|
||||
if shouldCreate {
|
||||
if _, aerr := s.ApprovalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlockKandang,
|
||||
id,
|
||||
utils.ProjectFlockKandangStepDisetujui,
|
||||
&reopenAction,
|
||||
actorID,
|
||||
nil,
|
||||
); aerr != nil && !errors.Is(aerr, gorm.ErrDuplicatedKey) {
|
||||
return nil, aerr
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "action harus close atau unclose")
|
||||
}
|
||||
|
||||
return s.Repository.GetByID(c.Context(), id)
|
||||
}
|
||||
|
||||
func (s projectFlockKandangService) calculateAvailableQuantityForProductWarehouse(c *fiber.Ctx, projectFlockKandang *entity.ProjectFlockKandang, productWarehouse *entity.ProductWarehouse) (float64, error) {
|
||||
availableQty := productWarehouse.Quantity
|
||||
|
||||
|
||||
+5
@@ -22,3 +22,8 @@ type Query struct {
|
||||
SortOrder string `query:"sort_order" validate:"omitempty,oneof=ASC DESC"`
|
||||
StepName string `query:"step_name" validate:"omitempty,max=50"`
|
||||
}
|
||||
|
||||
type Closing struct {
|
||||
Action string `json:"action" validate:"required,oneof=close unclose"`
|
||||
ClosedDate *string `json:"closed_date,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user