From 219a6a39edee3e6195cbc56a16c51f405bdd0f81 Mon Sep 17 00:00:00 2001 From: aguhh18 Date: Fri, 31 Oct 2025 15:33:31 +0700 Subject: [PATCH] Feat[BE]: refactored Chickin createone and implement approvals and add more needed constant --- internal/database/seed/seeder.go | 272 ++++++------ internal/entities/project_chickin.go | 11 +- internal/entities/project_flock_population.go | 24 +- internal/entities/projectflock.go | 1 + internal/entities/projectflock_kandang.go | 14 +- .../repositories/constant.repository.go | 4 + .../controllers/chickin.controller.go | 28 +- .../production/chickins/dto/chickin.dto.go | 36 +- .../modules/production/chickins/module.go | 13 + internal/modules/production/chickins/route.go | 2 +- .../chickins/services/chickin.service.go | 414 +++++++++--------- .../validations/chickin.validation.go | 8 +- .../repositories/projectflock.repository.go | 5 + .../projectflock_kandang.repository.go | 5 + .../recordings/services/recording.service.go | 25 +- .../production/transfer_layings/module.go | 6 +- internal/utils/constant.go | 32 ++ 17 files changed, 485 insertions(+), 415 deletions(-) diff --git a/internal/database/seed/seeder.go b/internal/database/seed/seeder.go index 791cfddb..ca8e8cf3 100644 --- a/internal/database/seed/seeder.go +++ b/internal/database/seed/seeder.go @@ -93,9 +93,9 @@ func Run(db *gorm.DB) error { if err := seedTransferStock(tx, adminID); err != nil { return err } - if err := seedChickin(tx, adminID); err != nil { - return err - } + // if err := seedChickin(tx, adminID); err != nil { + // return err + // } fmt.Println("✅ Master data seeding completed") return nil @@ -1134,151 +1134,151 @@ func seedTransferStock(tx *gorm.DB, createdBy uint) error { return nil } -func seedChickin(tx *gorm.DB, createdBy uint) error { - seeds := []struct { - ProjectFlockKandangId uint - ChickInDate string - Quantity float64 - Note string - }{ - {ProjectFlockKandangId: 1, ChickInDate: "2025-10-20", Quantity: 100, Note: "Seeder chickin 1"}, - {ProjectFlockKandangId: 2, ChickInDate: "2025-10-21", Quantity: 200, Note: "Seeder chickin 2"}, - } +// func seedChickin(tx *gorm.DB, createdBy uint) error { +// seeds := []struct { +// ProjectFlockKandangId uint +// ChickInDate string +// Quantity float64 +// Note string +// }{ +// {ProjectFlockKandangId: 1, ChickInDate: "2025-10-20", Quantity: 100, Note: "Seeder chickin 1"}, +// {ProjectFlockKandangId: 2, ChickInDate: "2025-10-21", Quantity: 200, Note: "Seeder chickin 2"}, +// } - for _, seed := range seeds { - chickinDate, err := time.Parse("2006-01-02", seed.ChickInDate) - if err != nil { - return err - } +// for _, seed := range seeds { +// chickinDate, err := time.Parse("2006-01-02", seed.ChickInDate) +// if err != nil { +// return err +// } - // Insert ProjectChickin jika belum ada - var chickin entity.ProjectChickin - err = tx.Where("project_flock_kandang_id = ? AND chick_in_date = ?", seed.ProjectFlockKandangId, chickinDate). - First(&chickin).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - chickin = entity.ProjectChickin{ - ProjectFlockKandangId: seed.ProjectFlockKandangId, - ChickInDate: chickinDate, - Quantity: seed.Quantity, - Note: seed.Note, - CreatedBy: createdBy, - } - if err := tx.Create(&chickin).Error; err != nil { - return err - } - } else if err != nil { - return err - } +// // Insert ProjectChickin jika belum ada +// var chickin entity.ProjectChickin +// err = tx.Where("project_flock_kandang_id = ? AND chick_in_date = ?", seed.ProjectFlockKandangId, chickinDate). +// First(&chickin).Error +// if errors.Is(err, gorm.ErrRecordNotFound) { +// chickin = entity.ProjectChickin{ +// ProjectFlockKandangId: seed.ProjectFlockKandangId, +// ChickInDate: chickinDate, +// Quantity: seed.Quantity, +// Note: seed.Note, +// CreatedBy: createdBy, +// } +// if err := tx.Create(&chickin).Error; err != nil { +// return err +// } +// } else if err != nil { +// return err +// } - var population entity.ProjectFlockPopulation - err = tx.Where("project_flock_kandang_id = ?", seed.ProjectFlockKandangId).First(&population).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - population = entity.ProjectFlockPopulation{ - ProjectFlockKandangId: seed.ProjectFlockKandangId, - InitialQuantity: seed.Quantity, - CurrentQuantity: seed.Quantity, - ReservedQuantity: 0, - CreatedBy: createdBy, - } - if err := tx.Create(&population).Error; err != nil { - return err - } - } else if err != nil { - return err - } else { - // Update population quantities - if err := tx.Model(&entity.ProjectFlockPopulation{}). - Where("id = ?", population.Id). - Updates(map[string]any{ - "initial_quantity": population.InitialQuantity + seed.Quantity, - "current_quantity": population.CurrentQuantity + seed.Quantity, - "reserved_quantity": 0, - }).Error; err != nil { - return err - } - } +// var population entity.ProjectFlockPopulation +// err = tx.Where("project_flock_kandang_id = ?", seed.ProjectFlockKandangId).First(&population).Error +// if errors.Is(err, gorm.ErrRecordNotFound) { +// population = entity.ProjectFlockPopulation{ +// ProjectFlockKandangId: seed.ProjectFlockKandangId, +// InitialQuantity: seed.Quantity, +// CurrentQuantity: seed.Quantity, +// ReservedQuantity: 0, +// CreatedBy: createdBy, +// } +// if err := tx.Create(&population).Error; err != nil { +// return err +// } +// } else if err != nil { +// return err +// } else { +// // Update population quantities +// if err := tx.Model(&entity.ProjectFlockPopulation{}). +// Where("id = ?", population.Id). +// Updates(map[string]any{ +// "initial_quantity": population.InitialQuantity + seed.Quantity, +// "current_quantity": population.CurrentQuantity + seed.Quantity, +// "reserved_quantity": 0, +// }).Error; err != nil { +// return err +// } +// } - var pfk entity.ProjectFlockKandang - if err := tx.Where("id = ?", seed.ProjectFlockKandangId).First(&pfk).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - // no pivot found; skip creating details - continue - } - return err - } +// var pfk entity.ProjectFlockKandang +// if err := tx.Where("id = ?", seed.ProjectFlockKandangId).First(&pfk).Error; err != nil { +// if errors.Is(err, gorm.ErrRecordNotFound) { +// // no pivot found; skip creating details +// continue +// } +// return err +// } - var warehouse entity.Warehouse - if err := tx.Where("kandang_id = ?", pfk.KandangId).First(&warehouse).Error; err != nil { - // if warehouse not found, cannot create details - if errors.Is(err, gorm.ErrRecordNotFound) { - continue - } - return err - } +// var warehouse entity.Warehouse +// if err := tx.Where("kandang_id = ?", pfk.KandangId).First(&warehouse).Error; err != nil { +// // if warehouse not found, cannot create details +// if errors.Is(err, gorm.ErrRecordNotFound) { +// continue +// } +// return err +// } - var productWarehouses []entity.ProductWarehouse - err = tx.Table("product_warehouses"). - Select("product_warehouses.*"). - Joins("JOIN products ON products.id = product_warehouses.product_id"). - Joins("JOIN product_categories ON product_categories.id = products.product_category_id"). - Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", "DOC", warehouse.Id). - Order("product_warehouses.created_at DESC"). - Find(&productWarehouses).Error - if err != nil { - return err - } +// var productWarehouses []entity.ProductWarehouse +// err = tx.Table("product_warehouses"). +// Select("product_warehouses.*"). +// Joins("JOIN products ON products.id = product_warehouses.product_id"). +// Joins("JOIN product_categories ON product_categories.id = products.product_category_id"). +// Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", "DOC", warehouse.Id). +// Order("product_warehouses.created_at DESC"). +// Find(&productWarehouses).Error +// if err != nil { +// return err +// } - // If no product warehouses found, keep existing chickin.Quantity and skip details - if len(productWarehouses) == 0 { - continue - } +// // If no product warehouses found, keep existing chickin.Quantity and skip details +// if len(productWarehouses) == 0 { +// continue +// } - // sum all pw quantities and set chickin.Quantity to that total (mimic CreateOne) - totalQty := 0.0 - for _, pw := range productWarehouses { - totalQty += pw.Quantity - } +// // sum all pw quantities and set chickin.Quantity to that total (mimic CreateOne) +// totalQty := 0.0 +// for _, pw := range productWarehouses { +// totalQty += pw.Quantity +// } - if chickin.Quantity != totalQty { - if err := tx.Model(&entity.ProjectChickin{}).Where("id = ?", chickin.Id).Update("quantity", totalQty).Error; err != nil { - return err - } - chickin.Quantity = totalQty - } +// if chickin.Quantity != totalQty { +// if err := tx.Model(&entity.ProjectChickin{}).Where("id = ?", chickin.Id).Update("quantity", totalQty).Error; err != nil { +// return err +// } +// chickin.Quantity = totalQty +// } - for _, pw := range productWarehouses { - // ensure detail exists or create it with full pw.Quantity - var detail entity.ProjectChickinDetail - err = tx.Where("project_chickin_id = ? AND product_warehouse_id = ?", chickin.Id, pw.Id).First(&detail).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - detail = entity.ProjectChickinDetail{ - ProjectChickinId: chickin.Id, - ProductWarehouseId: pw.Id, - Quantity: pw.Quantity, - CreatedBy: createdBy, - } - if err := tx.Create(&detail).Error; err != nil { - return err - } - } else if err != nil { - return err - } else { - if detail.Quantity != pw.Quantity { - if err := tx.Model(&entity.ProjectChickinDetail{}).Where("id = ?", detail.Id).Update("quantity", pw.Quantity).Error; err != nil { - return err - } - } - } +// for _, pw := range productWarehouses { +// // ensure detail exists or create it with full pw.Quantity +// var detail entity.ProjectChickinDetail +// err = tx.Where("project_chickin_id = ? AND product_warehouse_id = ?", chickin.Id, pw.Id).First(&detail).Error +// if errors.Is(err, gorm.ErrRecordNotFound) { +// detail = entity.ProjectChickinDetail{ +// ProjectChickinId: chickin.Id, +// ProductWarehouseId: pw.Id, +// Quantity: pw.Quantity, +// CreatedBy: createdBy, +// } +// if err := tx.Create(&detail).Error; err != nil { +// return err +// } +// } else if err != nil { +// return err +// } else { +// if detail.Quantity != pw.Quantity { +// if err := tx.Model(&entity.ProjectChickinDetail{}).Where("id = ?", detail.Id).Update("quantity", pw.Quantity).Error; err != nil { +// return err +// } +// } +// } - // zero out pw quantity - if err := tx.Model(&entity.ProductWarehouse{}).Where("id = ?", pw.Id).Update("quantity", 0).Error; err != nil { - return err - } - } - } +// // zero out pw quantity +// if err := tx.Model(&entity.ProductWarehouse{}).Where("id = ?", pw.Id).Update("quantity", 0).Error; err != nil { +// return err +// } +// } +// } - return nil -} +// return nil +// } func ptr[T any](v T) *T { return &v diff --git a/internal/entities/project_chickin.go b/internal/entities/project_chickin.go index 95a658c8..c3ca2671 100644 --- a/internal/entities/project_chickin.go +++ b/internal/entities/project_chickin.go @@ -12,13 +12,16 @@ type ProjectChickin struct { Id uint `gorm:"primaryKey"` ProjectFlockKandangId uint `gorm:"not null"` ChickInDate time.Time `gorm:"not null"` - Quantity float64 `gorm:"not null"` - Note string `gorm:"type:text"` + ProductWarehouseId uint `gorm:"not null"` + UsageQty float64 `gorm:"type:numeric(15,3);not null"` + PendingUsageQty float64 `gorm:"type:numeric(15,3);default:0"` + Notes string `gorm:"type:text"` CreatedBy uint `gorm:"not null"` CreatedAt time.Time `gorm:"autoCreateTime"` UpdatedAt time.Time `gorm:"autoUpdateTime"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` - ProjectFlockKandang ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` - CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` + ProjectFlockKandang *ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` + ProductWarehouse *ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"` + CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"` } diff --git a/internal/entities/project_flock_population.go b/internal/entities/project_flock_population.go index 184ace65..e5b3216c 100644 --- a/internal/entities/project_flock_population.go +++ b/internal/entities/project_flock_population.go @@ -7,16 +7,18 @@ import ( ) type ProjectFlockPopulation struct { - Id uint `gorm:"primaryKey"` - ProjectFlockKandangId uint `gorm:"not null"` - InitialQuantity float64 `gorm:"type:numeric(15,3);not null"` - CurrentQuantity float64 `gorm:"type:numeric(15,3);not null"` - ReservedQuantity float64 `gorm:"type:numeric(15,3)"` - CreatedBy uint `gorm:"not null"` - CreatedAt time.Time `gorm:"autoCreateTime"` - UpdatedAt time.Time `gorm:"autoUpdateTime"` - DeletedAt gorm.DeletedAt `gorm:"index"` + Id uint `gorm:"primaryKey"` + ProjectChickinId uint `gorm:"not null"` + ProductWarehouseId uint `gorm:"not null"` + TotalQty float64 `gorm:"type:numeric(15,3);not null"` + TotalUsedQty float64 `gorm:"type:numeric(15,3);not null"` + Notes string `gorm:"type:text"` + CreatedBy uint `gorm:"not null"` + CreatedAt time.Time `gorm:"autoCreateTime"` + UpdatedAt time.Time `gorm:"autoUpdateTime"` + DeletedAt gorm.DeletedAt `gorm:"index"` - ProjectFlockKandang *ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` - CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"` + ProjectChickin *ProjectChickin `gorm:"foreignKey:ProjectChickinId;references:Id"` + ProductWarehouse *ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"` + CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"` } diff --git a/internal/entities/projectflock.go b/internal/entities/projectflock.go index c840892f..4c05298f 100644 --- a/internal/entities/projectflock.go +++ b/internal/entities/projectflock.go @@ -28,3 +28,4 @@ type ProjectFlock struct { KandangHistory []ProjectFlockKandang `gorm:"foreignKey:ProjectFlockId;references:Id"` LatestApproval *Approval `gorm:"-" json:"-"` } + diff --git a/internal/entities/projectflock_kandang.go b/internal/entities/projectflock_kandang.go index 1c29c22e..f10dbd17 100644 --- a/internal/entities/projectflock_kandang.go +++ b/internal/entities/projectflock_kandang.go @@ -3,10 +3,12 @@ package entities import "time" type ProjectFlockKandang struct { - Id uint `gorm:"primaryKey"` - ProjectFlockId uint `gorm:"not null;index:idx_project_flock_kandangs_project;uniqueIndex:idx_project_flock_kandangs_unique"` - KandangId uint `gorm:"not null;index:idx_project_flock_kandangs_kandang;uniqueIndex:idx_project_flock_kandangs_unique"` - CreatedAt time.Time `gorm:"autoCreateTime"` - ProjectFlock ProjectFlock `gorm:"foreignKey:ProjectFlockId;references:Id"` - Kandang Kandang `gorm:"foreignKey:KandangId;references:Id"` + Id uint `gorm:"primaryKey"` + ProjectFlockId uint `gorm:"not null;index:idx_project_flock_kandangs_project;uniqueIndex:idx_project_flock_kandangs_unique"` + KandangId uint `gorm:"not null;index:idx_project_flock_kandangs_kandang;uniqueIndex:idx_project_flock_kandangs_unique"` + CreatedAt time.Time `gorm:"autoCreateTime"` + + ProjectFlock ProjectFlock `gorm:"foreignKey:ProjectFlockId;references:Id"` + Kandang Kandang `gorm:"foreignKey:KandangId;references:Id"` + Chickins []ProjectChickin `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` } diff --git a/internal/modules/constants/repositories/constant.repository.go b/internal/modules/constants/repositories/constant.repository.go index 4b44d553..493f4cb9 100644 --- a/internal/modules/constants/repositories/constant.repository.go +++ b/internal/modules/constants/repositories/constant.repository.go @@ -82,6 +82,10 @@ func (r *ConstantRepositoryImpl) GetConstants() map[string]interface{} { "LOKASI", "KANDANG", }, + "stock_log": map[string][]string{ + "log_types": []string{"TRANSFER", "ADJUSTMENT"}, + "transaction_types": []string{"INCREASE", "DECREASE"}, + }, "supplier_categories": []string{ "BOP", "SAPRONAK", diff --git a/internal/modules/production/chickins/controllers/chickin.controller.go b/internal/modules/production/chickins/controllers/chickin.controller.go index fadcbc3e..c132b279 100644 --- a/internal/modules/production/chickins/controllers/chickin.controller.go +++ b/internal/modules/production/chickins/controllers/chickin.controller.go @@ -139,23 +139,33 @@ func (u *ChickinController) DeleteOne(c *fiber.Ctx) error { }) } -func (u *ChickinController) Approve(c *fiber.Ctx) error { - param := c.Params("id") - - id, err := strconv.Atoi(param) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") +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") } - if err := u.ChickinService.Approve(c, uint(id)); err != nil { + results, err := u.ChickinService.Approval(c, req) + if err != nil { return err } + var ( + data interface{} + message = "Submit chickin approval successfully" + ) + if len(results) == 1 { + data = dto.ToChickinListDTO(results[0]) + } else { + message = "Submit chickin approvals successfully" + data = dto.ToChickinListDTOs(results) + } + return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", - Message: "Approve chickin successfully", - Data: nil, + Message: message, + Data: data, }) } diff --git a/internal/modules/production/chickins/dto/chickin.dto.go b/internal/modules/production/chickins/dto/chickin.dto.go index 193257b6..823cbfa5 100644 --- a/internal/modules/production/chickins/dto/chickin.dto.go +++ b/internal/modules/production/chickins/dto/chickin.dto.go @@ -18,8 +18,10 @@ type ChickinBaseDTO struct { Id uint `json:"id"` ProjectFlockKandang *ProjectFlockKandangDTO `json:"project_flock_kandang"` ChickInDate time.Time `json:"chick_in_date"` - Quantity float64 `json:"quantity"` - Note string `json:"note"` + ProductWarehouseId uint `json:"product_warehouse_id"` + UsageQty float64 `json:"usage_qty"` + PendingUsageQty float64 `json:"pending_usage_qty"` + Notes string `json:"notes"` } type ProjectFlockDTO struct { @@ -44,8 +46,10 @@ type ChickinSimpleDTO struct { Id uint `json:"id"` ProjectFlockKandangId uint `json:"project_flock_kandang_id"` ChickInDate time.Time `json:"chick_in_date"` - Quantity float64 `json:"quantity"` - Note string `json:"note"` + 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"` } @@ -138,16 +142,18 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD func ToChickinBaseDTO(e entity.ProjectChickin) ChickinBaseDTO { var pfk *ProjectFlockKandangDTO - if e.ProjectFlockKandang.Id != 0 { - mapped := ToProjectFlockKandangDTO(e.ProjectFlockKandang) + if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.Id != 0 { + mapped := ToProjectFlockKandangDTO(*e.ProjectFlockKandang) pfk = &mapped } return ChickinBaseDTO{ Id: e.Id, ProjectFlockKandang: pfk, ChickInDate: e.ChickInDate, - Quantity: e.Quantity, - Note: e.Note, + ProductWarehouseId: e.ProductWarehouseId, + UsageQty: e.UsageQty, + PendingUsageQty: e.PendingUsageQty, + Notes: e.Notes, } } @@ -156,21 +162,23 @@ func ToChickinSimpleDTO(e entity.ProjectChickin) ChickinSimpleDTO { Id: e.Id, ProjectFlockKandangId: e.ProjectFlockKandangId, ChickInDate: e.ChickInDate, - Quantity: e.Quantity, - Note: e.Note, + ProductWarehouseId: e.ProductWarehouseId, + UsageQty: e.UsageQty, + PendingUsageQty: e.PendingUsageQty, + Notes: e.Notes, CreatedBy: e.CreatedBy, } } func ToChickinListDTO(e entity.ProjectChickin) ChickinListDTO { var createdUser *userBaseDTO.UserBaseDTO - if e.CreatedUser.Id != 0 { - mapped := userBaseDTO.ToUserBaseDTO(e.CreatedUser) + if e.CreatedUser != nil && e.CreatedUser.Id != 0 { + mapped := userBaseDTO.ToUserBaseDTO(*e.CreatedUser) createdUser = &mapped } var pfk *ProjectFlockKandangDTO - if e.ProjectFlockKandang.Id != 0 { - mapped := ToProjectFlockKandangDTO(e.ProjectFlockKandang) + if e.ProjectFlockKandang != nil && e.ProjectFlockKandang.Id != 0 { + mapped := ToProjectFlockKandangDTO(*e.ProjectFlockKandang) pfk = &mapped } return ChickinListDTO{ diff --git a/internal/modules/production/chickins/module.go b/internal/modules/production/chickins/module.go index f1e0baea..f6dd554b 100644 --- a/internal/modules/production/chickins/module.go +++ b/internal/modules/production/chickins/module.go @@ -1,10 +1,15 @@ package chickins import ( + "fmt" + "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "gorm.io/gorm" + commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" + rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/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" @@ -15,6 +20,8 @@ import ( rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" + + utils "gitlab.com/mbugroup/lti-api.git/internal/utils" ) type ChickinModule struct{} @@ -32,6 +39,12 @@ func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate * userRepo := rUser.NewUserRepository(db) + approvalRepo := commonRepo.NewApprovalRepository(db) + approvalService := commonSvc.NewApprovalService(approvalRepo) + if err := approvalService.RegisterWorkflowSteps(utils.ApprovalWorkflowProjectFlockKandang, utils.ProjectFlockKandangApprovalSteps); err != nil { + panic(fmt.Sprintf("failed to register project flock kandang approval workflow: %v", err)) + } + chickinService := sChickin.NewChickinService(chickinRepo, kandangRepo, warehouseRepo, productWarehouseRepo, projectFlockRepo, projectflockkandangrepo, projectflockpopulationrepo, chickinDetailRepo, validate) userService := sUser.NewUserService(userRepo, validate) diff --git a/internal/modules/production/chickins/route.go b/internal/modules/production/chickins/route.go index 5fa5237a..0bb5e93d 100644 --- a/internal/modules/production/chickins/route.go +++ b/internal/modules/production/chickins/route.go @@ -25,5 +25,5 @@ func ChickinRoutes(v1 fiber.Router, u user.UserService, s chickin.ChickinService route.Get("/:id", ctrl.GetOne) route.Patch("/:id", ctrl.UpdateOne) route.Delete("/:id", ctrl.DeleteOne) - route.Post("/:id/approve", ctrl.Approve) + route.Post("/approvals", ctrl.Approval) } diff --git a/internal/modules/production/chickins/services/chickin.service.go b/internal/modules/production/chickins/services/chickin.service.go index 83d94ba5..2b44c242 100644 --- a/internal/modules/production/chickins/services/chickin.service.go +++ b/internal/modules/production/chickins/services/chickin.service.go @@ -2,7 +2,11 @@ package service import ( "errors" + "fmt" + "strings" + commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + 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" KandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" @@ -24,7 +28,7 @@ type ChickinService interface { 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 - Approve(ctx *fiber.Ctx, id uint) error + Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectChickin, error) } type chickinService struct { @@ -110,107 +114,98 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit return nil, err } - projectflockkandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), req.ProjectFlockKandangId) + projectFlockKandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), req.ProjectFlockKandangId) if err != nil { - s.Log.Errorf("Failed to get projectflock kandang: %+v", err) - return nil, err + return nil, fiber.NewError(fiber.StatusNotFound, "Project Flock Kandang not found") } - warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectflockkandang.KandangId) + warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectFlockKandang.KandangId) if err != nil { - s.Log.Errorf("Failed to get warehouse: %+v", err) - return nil, err + return nil, fiber.NewError(fiber.StatusNotFound, "Warehouse for Kandang not found") } - // move complex DB query into repository for cleaner service - productWarehouses, err := s.ProductWarehouseRepo.GetByCategoryCodeAndWarehouseID(c.Context(), "DOC", warehouse.Id) - if err != nil { - s.Log.Errorf("Failed to get product warehouses: %+v", err) - return nil, err - } - if len(productWarehouses) == 0 { - return nil, fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse") - } - totalQuantity := 0.0 - for _, pw := range productWarehouses { - totalQuantity += pw.Quantity - } + var productWarehouses []entity.ProductWarehouse - if totalQuantity < 1 { - return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient quantity in Product Warehouses") + if strings.ToUpper(strings.TrimSpace(projectFlockKandang.ProjectFlock.Category)) == string(utils.ProjectFlockCategoryGrowing) { + + productWarehouses, err = s.ProductWarehouseRepo.GetByCategoryCodeAndWarehouseID(c.Context(), "DOC", warehouse.Id) + if err != nil || len(productWarehouses) == 0 { + return nil, fiber.NewError(fiber.StatusNotFound, "Product for growing category in the Kandang's warehouse not found") + } } chickinDate, err := utils.ParseDateString(req.ChickInDate) if err != nil { - s.Log.Errorf("Failed to parse chickin date: %+v", err) return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid ChickInDate format") } - newChickin := &entity.ProjectChickin{ - ProjectFlockKandangId: projectflockkandang.Id, - ChickInDate: chickinDate, - Quantity: totalQuantity, - Note: req.Note, - CreatedBy: 1, //todo: ganti dengan user login + + actorID := uint(1) // todo nanti ambil dari auth context + newChikins := make([]*entity.ProjectChickin, 0) + for _, productWarehouse := range productWarehouses { + + if productWarehouse.Quantity > 0 { + newChickin := &entity.ProjectChickin{ + ProjectFlockKandangId: req.ProjectFlockKandangId, + ChickInDate: chickinDate, + UsageQty: 0, + PendingUsageQty: productWarehouse.Quantity, + ProductWarehouseId: productWarehouse.Id, + Notes: req.Note, + CreatedBy: actorID, + } + + newChikins = append(newChikins, newChickin) + } } - err = s.Repository.CreateOne(c.Context(), newChickin, nil) + + if len(newChikins) == 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "No chickins to create") + } + + err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error { + + approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction)) + productWarehouseTx := s.ProductWarehouseRepo.WithTx(dbTransaction) + + if err := s.Repository.WithTx(dbTransaction).CreateMany(c.Context(), newChikins, nil); err != nil { + return err + } + + latest, err := approvalSvcTx.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, nil) + if err != nil { + return err + } + + for _, chickin := range newChikins { + + updates := map[string]any{"quantity": 0} + + 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 err + } + } + + if latest == nil { + + action := entity.ApprovalActionCreated + if _, err := approvalSvcTx.CreateApproval(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, utils.ProjectFlockKandangStepPengajuan, &action, 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 + } + } + } + + return nil + }) if err != nil { - s.Log.Errorf("Failed to create chickin: %+v", err) - return nil, err + return nil, fiber.NewError(fiber.StatusBadRequest, err.Error()) } - // Update semua product warehouse: set quantity jadi 0 - for _, pw := range productWarehouses { - err = s.ProductWarehouseRepo.PatchOne(c.Context(), pw.Id, map[string]any{ - "quantity": 0, - }, nil) - if err != nil { - s.Log.Errorf("Failed to update product warehouse quantity: %+v", err) - return nil, err - } - - newChickinDetail := &entity.ProjectChickinDetail{ - ProjectChickinId: newChickin.Id, - ProductWarehouseId: pw.Id, - Quantity: pw.Quantity, - CreatedBy: 1, // todo: ganti dengan user login - } - err = s.ProjectChickinDetailRepo.CreateOne(c.Context(), newChickinDetail, nil) - if err != nil { - s.Log.Errorf("Failed to create chickin detail: %+v", err) - return nil, err - } - } - - existingPopulation, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangID(c.Context(), req.ProjectFlockKandangId) - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - s.Log.Errorf("Failed to get project flock population: %+v", err) - return nil, err - } - if existingPopulation != nil { - - err = s.ProjectflockPopulationRepo.PatchOne(c.Context(), existingPopulation.Id, map[string]any{ - "reserved_quantity": newChickin.Quantity + existingPopulation.ReservedQuantity, - }, nil) - if err != nil { - s.Log.Errorf("Failed to update project flock population: %+v", err) - return nil, err - } - } else { - newPopulation := &entity.ProjectFlockPopulation{ - ProjectFlockKandangId: req.ProjectFlockKandangId, - InitialQuantity: 0, - CurrentQuantity: 0, - ReservedQuantity: newChickin.Quantity, - CreatedBy: 1, // todo: ganti dengan user login - } - err = s.ProjectflockPopulationRepo.CreateOne(c.Context(), newPopulation, nil) - if err != nil { - s.Log.Errorf("Failed to create project flock population: %+v", err) - return nil, err - } - } - - return s.GetOne(c, newChickin.Id) + return newChikins[0], nil } func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectChickin, error) { @@ -224,7 +219,8 @@ func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) updateBody["chick_in_date"] = req.ChickInDate } if req.Note != "" { - updateBody["note"] = req.Note + // entity uses `Notes` => column `notes` + updateBody["notes"] = req.Note } if len(updateBody) == 0 { return s.GetOne(c, id) @@ -243,160 +239,140 @@ func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error { + // Simplified delete: directly call repository delete. Complex restore logic removed for now. + if err := s.Repository.DeleteOne(c.Context(), id); err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return fiber.NewError(fiber.StatusNotFound, "Chickin not found") + } + return err + } + + return nil +} + +func (s chickinService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.ProjectChickin, error) { + if err := s.Validate.Struct(req); err != nil { + return nil, err + } + + actorID := uint(1) // todo nanti ambil dari auth context + + var action entity.ApprovalAction + switch strings.ToUpper(strings.TrimSpace(req.Action)) { + case string(entity.ApprovalActionRejected): + action = entity.ApprovalActionRejected + case string(entity.ApprovalActionApproved): + action = entity.ApprovalActionApproved + default: + return nil, fiber.NewError(fiber.StatusBadRequest, "action must be APPROVED or REJECTED") + } + + approvableIDs := uniqueUintSlice(req.ApprovableIds) + if len(approvableIDs) == 0 { + return nil, fiber.NewError(fiber.StatusBadRequest, "approvable_ids must contain at least one id") + } + + step := utils.ProjectFlockKandangStepPengajuan + if action == entity.ApprovalActionApproved { + step = utils.ProjectFlockKandangStepDisetujui + } + err := s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error { + approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction)) + ProjectFlockPopulationRepotx := s.ProjectflockPopulationRepo.WithTx(dbTransaction) + chickinRepoTx := s.Repository.WithTx(dbTransaction) - chickinRepo := repository.NewChickinRepository(dbTransaction) - projectFlockKandangRepo := s.ProjectflockKandangRepo.WithTx(dbTransaction) - productWarehouseRepo := s.ProductWarehouseRepo.WithTxRepo(dbTransaction) - projectFlockPopulationRepo := s.ProjectflockPopulationRepo.WithTx(dbTransaction) - projectChickinDetailRepo := s.ProjectChickinDetailRepo.WithTxRepo(dbTransaction) - warehouseRepoTx := rWarehouse.NewWarehouseRepository(dbTransaction) + for _, approvableID := range approvableIDs { - chickin, err := chickinRepo.GetByID(c.Context(), id, nil) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Chickin not found") - } - return err - } - - population, err := projectFlockPopulationRepo.GetByProjectFlockKandangID(c.Context(), chickin.ProjectFlockKandangId) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Project flock population not found") - } - return err - } - - newReserved := population.ReservedQuantity - chickin.Quantity - if newReserved < 0 { - newReserved = 0 - } - - err = projectFlockPopulationRepo.PatchOne(c.Context(), population.Id, map[string]any{ - "reserved_quantity": newReserved, - }, nil) - if err != nil { - return err - } - - restoreFromDetails := func() (bool, error) { - - details, err := projectChickinDetailRepo.GetByProjectChickinID(c.Context(), chickin.Id) + exists, err := s.ProjectflockKandangRepo.WithTx(dbTransaction).IdExists(c.Context(), approvableID) if err != nil { - return false, err + return err + } + if !exists { + return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("ProjectFlockKandang %d not found", approvableID)) } - for _, d := range details { - productWarehouse, err := productWarehouseRepo.GetByID(c.Context(), d.ProductWarehouseId, nil) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - continue + if _, err := approvalSvc.CreateApproval( + c.Context(), + utils.ApprovalWorkflowProjectFlockKandang, + approvableID, + step, + &action, + actorID, + req.Notes, + ); 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 approval for kandang %d: %v", approvableID, err) + } + + if action == entity.ApprovalActionApproved { + + var chickins []entity.ProjectChickin + if err := chickinRepoTx.DB().WithContext(c.Context()).Where("project_flock_kandang_id = ?", approvableID).Find(&chickins).Error; err != nil { + return err + } + + for _, chickin := range chickins { + population := &entity.ProjectFlockPopulation{ + ProjectChickinId: chickin.Id, + ProductWarehouseId: chickin.ProductWarehouseId, + TotalQty: chickin.PendingUsageQty, + TotalUsedQty: 0, + Notes: chickin.Notes, + CreatedBy: actorID, + } + if err := ProjectFlockPopulationRepotx.CreateOne(c.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) } - return false, err } - updatedQuantity := productWarehouse.Quantity + d.Quantity - if err := productWarehouseRepo.PatchOne(c.Context(), productWarehouse.Id, map[string]any{"quantity": updatedQuantity}, nil); err != nil { - return false, err - } } - if err := projectChickinDetailRepo.DeleteMany(c.Context(), func(db *gorm.DB) *gorm.DB { - return db.Where("project_chickin_id = ?", chickin.Id) - }); err != nil { - return false, err - } - - return true, nil - } - - restored, err := restoreFromDetails() - if err != nil { - return err - } - - if !restored { - projectflockkandang, err := projectFlockKandangRepo.GetByID(c.Context(), population.ProjectFlockKandangId) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Project flock kandang not found") - } - return err - } - - warehouse, err := warehouseRepoTx.GetByKandangID(c.Context(), projectflockkandang.KandangId) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Warehouse not found for kandang") - } - return err - } - - productWarehouse, err := productWarehouseRepo.GetLatestByCategoryCodeAndWarehouseID(c.Context(), "DOC", warehouse.Id) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse") - } - return err - } - - updatedQuantity := productWarehouse.Quantity + chickin.Quantity - - if err := productWarehouseRepo.PatchOne(c.Context(), productWarehouse.Id, map[string]any{"quantity": updatedQuantity}, nil); err != nil { - return err - } - } - - if err := chickinRepo.DeleteOne(c.Context(), id); err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Chickin not found") - } - return err } return nil }) if err != nil { - if ferr, ok := err.(*fiber.Error); ok { - return ferr + if fiberErr, ok := err.(*fiber.Error); ok { + return nil, fiberErr } - return err + 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") } - return nil + updated := make([]entity.ProjectChickin, 0) + for _, kandangID := range approvableIDs { + var chickins []entity.ProjectChickin + if err := s.Repository.DB().WithContext(c.Context()).Where("project_flock_kandang_id = ?", kandangID).Find(&chickins).Error; err != nil { + return nil, err + } + updated = append(updated, chickins...) + } + + return updated, nil } -func (s *chickinService) Approve(c *fiber.Ctx, id uint) error { - - // todo: ini contoh akhir jika sudah approved - - chickin, err := s.Repository.GetByID(c.Context(), id, nil) - - if errors.Is(err, gorm.ErrRecordNotFound) { - return fiber.NewError(fiber.StatusNotFound, "Chickin not found") +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) } - if err != nil { - s.Log.Errorf("Failed get chickin by id: %+v", err) - return err - } - - population, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangID(c.Context(), chickin.ProjectFlockKandangId) - if err != nil { - s.Log.Errorf("Failed to get project flock population: %+v", err) - return err - } - - err = s.ProjectflockPopulationRepo.PatchOne(c.Context(), population.Id, map[string]any{ - "reserved_quantity": population.ReservedQuantity - chickin.Quantity, - "initial_quantity": population.InitialQuantity + chickin.Quantity, - "current_quantity": population.CurrentQuantity + chickin.Quantity, - }, nil) - if err != nil { - s.Log.Errorf("Failed to update project flock population: %+v", err) - return err - } - - return nil + return result } diff --git a/internal/modules/production/chickins/validations/chickin.validation.go b/internal/modules/production/chickins/validations/chickin.validation.go index 9747ee07..c2676130 100644 --- a/internal/modules/production/chickins/validations/chickin.validation.go +++ b/internal/modules/production/chickins/validations/chickin.validation.go @@ -3,7 +3,7 @@ package validation type Create struct { ProjectFlockKandangId uint `json:"project_flock_kandang_id" validate:"required,number,min=1"` ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"` - Note string `json:"note" validate:"omitempty` + Note string `json:"note" validate:"omitempty"` } type Update struct { @@ -16,3 +16,9 @@ type Query struct { Limit int `query:"limit" validate:"omitempty,number,min=1,max=100"` ProjectFlockKandangId uint `query:"project_flock_kandang_id" validate:"omitempty,number,min=1"` } + +type Approve struct { + Action string `json:"action" validate:"required_strict"` + ApprovableIds []uint `json:"approvable_ids" validate:"required_strict,min=1,dive,gt=0"` + Notes *string `json:"notes,omitempty" validate:"omitempty,max=500"` +} diff --git a/internal/modules/production/project_flocks/repositories/projectflock.repository.go b/internal/modules/production/project_flocks/repositories/projectflock.repository.go index 476b061b..bc5a0c6b 100644 --- a/internal/modules/production/project_flocks/repositories/projectflock.repository.go +++ b/internal/modules/production/project_flocks/repositories/projectflock.repository.go @@ -16,6 +16,7 @@ type ProjectflockRepository interface { GetActiveByFlock(ctx context.Context, flockID uint) (*entity.ProjectFlock, error) GetMaxPeriodByFlock(ctx context.Context, flockID uint) (int, error) GetNextPeriodForFlock(ctx context.Context, flockID uint) (int, error) + IdExists(ctx context.Context, id uint) (bool, error) } type ProjectflockRepositoryImpl struct { @@ -28,6 +29,10 @@ func NewProjectflockRepository(db *gorm.DB) ProjectflockRepository { } } +func (r *ProjectflockRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) { + return repository.Exists[entity.ProjectFlock](ctx, r.DB(), id) +} + func (r *ProjectflockRepositoryImpl) GetAllByFlock(ctx context.Context, flockID uint) ([]entity.ProjectFlock, error) { var records []entity.ProjectFlock if err := r.DB().WithContext(ctx). diff --git a/internal/modules/production/project_flocks/repositories/projectflock_kandang.repository.go b/internal/modules/production/project_flocks/repositories/projectflock_kandang.repository.go index 5c78f830..7205b72a 100644 --- a/internal/modules/production/project_flocks/repositories/projectflock_kandang.repository.go +++ b/internal/modules/production/project_flocks/repositories/projectflock_kandang.repository.go @@ -3,6 +3,7 @@ package repository import ( "context" + "gitlab.com/mbugroup/lti-api.git/internal/common/repository" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" "gorm.io/gorm" ) @@ -14,6 +15,7 @@ type ProjectFlockKandangRepository interface { DeleteMany(ctx context.Context, projectFlockID uint, kandangIDs []uint) error GetAll(ctx context.Context) ([]entity.ProjectFlockKandang, error) WithTx(tx *gorm.DB) ProjectFlockKandangRepository + IdExists(ctx context.Context, id uint) (bool, error) DB() *gorm.DB } @@ -67,6 +69,9 @@ func (r *projectFlockKandangRepositoryImpl) WithTx(tx *gorm.DB) ProjectFlockKand func (r *projectFlockKandangRepositoryImpl) DB() *gorm.DB { return r.db } +func (r *projectFlockKandangRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) { + return repository.Exists[entity.ProjectFlockKandang](ctx, r.db, id) +} func (r *projectFlockKandangRepositoryImpl) GetByID(ctx context.Context, id uint) (*entity.ProjectFlockKandang, error) { record := new(entity.ProjectFlockKandang) diff --git a/internal/modules/production/recordings/services/recording.service.go b/internal/modules/production/recordings/services/recording.service.go index 46ba36cc..b3bdaeaf 100644 --- a/internal/modules/production/recordings/services/recording.service.go +++ b/internal/modules/production/recordings/services/recording.service.go @@ -670,18 +670,19 @@ func (s *recordingService) getPreviousRecording(tx *gorm.DB, projectFlockKandang } func (s *recordingService) getTotalChick(tx *gorm.DB, projectFlockKandangId uint) (int64, error) { - var population entity.ProjectFlockPopulation - err := tx. - Where("project_flock_kandang_id = ?", projectFlockKandangId). - Order("created_at DESC"). - First(&population).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return 0, nil - } - if err != nil { - return 0, err - } - return int64(math.Round(population.InitialQuantity)), nil + // var population entity.ProjectFlockPopulation + // err := tx. + // Where("project_flock_kandang_id = ?", projectFlockKandangId). + // Order("created_at DESC"). + // First(&population).Error + // if errors.Is(err, gorm.ErrRecordNotFound) { + // return 0, nil + // } + // if err != nil { + // return 0, err + // } + //todo : nanti ganti lagi mas saya hardcode dulu + return int64(math.Round(1000)), nil } func (s *recordingService) getAverageBodyWeight(tx *gorm.DB, recordingID uint) (float64, error) { diff --git a/internal/modules/production/transfer_layings/module.go b/internal/modules/production/transfer_layings/module.go index d3c6279c..b309f19e 100644 --- a/internal/modules/production/transfer_layings/module.go +++ b/internal/modules/production/transfer_layings/module.go @@ -5,6 +5,7 @@ import ( "github.com/gofiber/fiber/v2" "gorm.io/gorm" + rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" rTransferLaying "gitlab.com/mbugroup/lti-api.git/internal/modules/production/transfer_layings/repositories" sTransferLaying "gitlab.com/mbugroup/lti-api.git/internal/modules/production/transfer_layings/services" @@ -17,10 +18,11 @@ type TransferLayingModule struct{} func (TransferLayingModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) { transferLayingRepo := rTransferLaying.NewTransferLayingRepository(db) userRepo := rUser.NewUserRepository(db) + projectFlockRepo := rProjectFlock.NewProjectflockRepository(db) + projectFlockKandangRepo := rProjectFlock.NewProjectFlockKandangRepository(db) - transferLayingService := sTransferLaying.NewTransferLayingService(transferLayingRepo, validate) + transferLayingService := sTransferLaying.NewTransferLayingService(transferLayingRepo, projectFlockRepo, projectFlockKandangRepo, validate) userService := sUser.NewUserService(userRepo, validate) TransferLayingRoutes(router, userService, transferLayingService) } - diff --git a/internal/utils/constant.go b/internal/utils/constant.go index bdbc53b6..8328f4d7 100644 --- a/internal/utils/constant.go +++ b/internal/utils/constant.go @@ -79,6 +79,24 @@ const ( WarehouseTypeKandang WarehouseType = "KANDANG" ) +// ------------------------------------------------------------------- +// Stock log +// ------------------------------------------------------------------- + +type StockLogTransactionType string + +const ( + StockLogTransactionTypeIncrease StockLogTransactionType = "INCREASE" + StockLogTransactionTypeDecrease StockLogTransactionType = "DECREASE" +) + +type StockLogType string + +const ( + StockLogTypeAdjustment StockLogType = "ADJUSTMENT" + StockLogTypeTransfer StockLogType = "TRANSFER" +) + // ------------------------------------------------------------------- // WarehouseType // ------------------------------------------------------------------- @@ -140,6 +158,20 @@ var ProjectFlockApprovalSteps = map[approvalutils.ApprovalStep]string{ ProjectFlockStepAktif: "Aktif", } +// ------------------------------------------------------------------- +// Project Flock Kandang Approval +// ------------------------------------------------------------------- +const ( + ApprovalWorkflowProjectFlockKandang approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("PROJECT_FLOCK_KANDANGS") + ProjectFlockKandangStepPengajuan approvalutils.ApprovalStep = 1 + ProjectFlockKandangStepDisetujui approvalutils.ApprovalStep = 2 +) + +var ProjectFlockKandangApprovalSteps = map[approvalutils.ApprovalStep]string{ + ProjectFlockKandangStepPengajuan: "Pengajuan", + ProjectFlockKandangStepDisetujui: "Disetujui", +} + // ------------------------------------------------------------------- // Validators // -------------------------------------------------------------------