mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat/BE/US-76/US-78/US-79/TASK-112,120,133,121-Recording growing/TASK-187,189,202,190-Recording Laying/TASK-191,192,194,197,203-Grading Telur
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -41,21 +40,14 @@ func Run(db *gorm.DB) error {
|
||||
return err
|
||||
}
|
||||
|
||||
flocks, err := seedFlocks(tx, adminID)
|
||||
if err != nil {
|
||||
if _, err := seedFlocks(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fcrs, err := seedFcr(tx, adminID)
|
||||
if err != nil {
|
||||
if _, err := seedFcr(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
if err := seedProjectFlocks(tx, adminID, flocks, areas, fcrs, locations); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
kandangs, err := seedKandangs(tx, adminID, locations, users)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -93,10 +85,6 @@ func Run(db *gorm.DB) error {
|
||||
if err := seedTransferStock(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := seedChickin(tx, adminID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("✅ Master data seeding completed")
|
||||
return nil
|
||||
})
|
||||
@@ -243,158 +231,12 @@ func seedFlocks(tx *gorm.DB, createdBy uint) (map[string]uint, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func seedProjectFlocks(
|
||||
tx *gorm.DB,
|
||||
createdBy uint,
|
||||
flocks, areas, fcrs, locations map[string]uint,
|
||||
) error {
|
||||
seeds := []struct {
|
||||
Key string
|
||||
Flock string
|
||||
Area string
|
||||
Category utils.ProjectFlockCategory
|
||||
Fcr string
|
||||
Location string
|
||||
Period int
|
||||
}{
|
||||
{
|
||||
Key: "Singaparna Period 1",
|
||||
Flock: "Flock Priangan",
|
||||
Area: "Priangan",
|
||||
Category: utils.ProjectFlockCategoryGrowing,
|
||||
Fcr: "FCR Layer",
|
||||
Location: "Singaparna",
|
||||
Period: 1,
|
||||
},
|
||||
{
|
||||
Key: "Cikaum Period 1",
|
||||
Flock: "Flock Banten",
|
||||
Area: "Banten",
|
||||
Category: utils.ProjectFlockCategoryGrowing,
|
||||
Fcr: "FCR Layer",
|
||||
Location: "Cikaum",
|
||||
Period: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, seed := range seeds {
|
||||
flockID, ok := flocks[seed.Flock]
|
||||
if !ok {
|
||||
return fmt.Errorf("floc %s not seeded", seed.Flock)
|
||||
}
|
||||
areaID, ok := areas[seed.Area]
|
||||
if !ok {
|
||||
return fmt.Errorf("area %s not seeded", seed.Area)
|
||||
}
|
||||
fcrID, ok := fcrs[seed.Fcr]
|
||||
if !ok {
|
||||
return fmt.Errorf("fcr %s not seeded", seed.Fcr)
|
||||
}
|
||||
locationID, ok := locations[seed.Location]
|
||||
if !ok {
|
||||
return fmt.Errorf("location %s not seeded", seed.Location)
|
||||
}
|
||||
|
||||
var projectFlock entity.ProjectFlock
|
||||
err := tx.Where(
|
||||
"flock_id = ? AND area_id = ? AND category = ? AND fcr_id = ? AND location_id = ? AND period = ?",
|
||||
flockID, areaID, seed.Category, fcrID, locationID, seed.Period,
|
||||
).First(&projectFlock).Error
|
||||
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
projectFlock = entity.ProjectFlock{
|
||||
FlockId: flockID,
|
||||
AreaId: areaID,
|
||||
Category: string(seed.Category),
|
||||
FcrId: fcrID,
|
||||
LocationId: locationID,
|
||||
Period: seed.Period,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if err := tx.Create(&projectFlock).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := tx.Model(&entity.ProjectFlock{}).Where("id = ?", projectFlock.Id).Updates(map[string]any{
|
||||
"flock_id": flockID,
|
||||
"area_id": areaID,
|
||||
"category": string(seed.Category),
|
||||
"fcr_id": fcrID,
|
||||
"location_id": locationID,
|
||||
"period": seed.Period,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := ensureProjectFlockApprovals(tx, projectFlock.Id, createdBy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureProjectFlockApprovals(tx *gorm.DB, projectFlockID uint, actorID uint) error {
|
||||
if projectFlockID == 0 || actorID == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
workflow := utils.ApprovalWorkflowProjectFlock.String()
|
||||
|
||||
steps := []struct {
|
||||
step approvalutils.ApprovalStep
|
||||
action entity.ApprovalAction
|
||||
}{
|
||||
{step: utils.ProjectFlockStepPengajuan, action: entity.ApprovalActionCreated},
|
||||
{step: utils.ProjectFlockStepAktif, action: entity.ApprovalActionApproved},
|
||||
}
|
||||
|
||||
for _, cfg := range steps {
|
||||
var count int64
|
||||
if err := tx.Model(&entity.Approval{}).
|
||||
Where("approvable_type = ? AND approvable_id = ? AND step_number = ?", workflow, projectFlockID, uint16(cfg.step)).
|
||||
Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
stepName, ok := utils.ProjectFlockApprovalSteps[cfg.step]
|
||||
if !ok || strings.TrimSpace(stepName) == "" {
|
||||
stepName = fmt.Sprintf("Step %d", cfg.step)
|
||||
}
|
||||
|
||||
var actionPtr *entity.ApprovalAction
|
||||
action := cfg.action
|
||||
actionPtr = &action
|
||||
|
||||
record := entity.Approval{
|
||||
ApprovableType: workflow,
|
||||
ApprovableId: projectFlockID,
|
||||
StepNumber: uint16(cfg.step),
|
||||
StepName: stepName,
|
||||
Action: actionPtr,
|
||||
ActionBy: uintPtr(actorID),
|
||||
}
|
||||
|
||||
if err := tx.Create(&record).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users map[string]uint) (map[string]uint, error) {
|
||||
seeds := []struct {
|
||||
Name string
|
||||
Status utils.KandangStatus
|
||||
Location string
|
||||
PicKey string
|
||||
Name string
|
||||
Status utils.KandangStatus
|
||||
Location string
|
||||
PicKey string
|
||||
}{
|
||||
{Name: "Singaparna 1", Status: utils.KandangStatusNonActive, Location: "Singaparna", PicKey: "admin"},
|
||||
{Name: "Singaparna 2", Status: utils.KandangStatusNonActive, Location: "Singaparna", PicKey: "admin"},
|
||||
@@ -414,16 +256,15 @@ func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users
|
||||
return nil, fmt.Errorf("user %s not seeded", seed.PicKey)
|
||||
}
|
||||
|
||||
|
||||
var kandang entity.Kandang
|
||||
err := tx.Where("name = ?", seed.Name).First(&kandang).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
kandang = entity.Kandang{
|
||||
Name: seed.Name,
|
||||
Status: string(seed.Status),
|
||||
LocationId: locID,
|
||||
PicId: picID,
|
||||
CreatedBy: createdBy,
|
||||
Name: seed.Name,
|
||||
Status: string(seed.Status),
|
||||
LocationId: locID,
|
||||
PicId: picID,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if err := tx.Create(&kandang).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -446,7 +287,6 @@ func seedKandangs(tx *gorm.DB, createdBy uint, locations map[string]uint, users
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
||||
func seedWarehouses(tx *gorm.DB, createdBy uint, areas map[string]uint, locations map[string]uint, kandangs map[string]uint) error {
|
||||
seeds := []struct {
|
||||
Name string
|
||||
@@ -525,6 +365,7 @@ func seedProductCategories(tx *gorm.DB, createdBy uint) (map[string]uint, error)
|
||||
}{
|
||||
{"Bahan Baku", "RAW"},
|
||||
{"Day Old Chick", "DOC"},
|
||||
{"Telur", "EGG"},
|
||||
}
|
||||
|
||||
result := make(map[string]uint, len(seeds))
|
||||
@@ -739,6 +580,22 @@ func seedProducts(tx *gorm.DB, createdBy uint, uoms map[string]uint, categories
|
||||
Suppliers: []string{"PT CHAROEN POKPHAND INDONESIA Tbk"},
|
||||
Flags: []utils.FlagType{utils.FlagPakan, utils.FlagStarter},
|
||||
},
|
||||
{
|
||||
Name: "Telur Konsumsi Baik",
|
||||
Brand: "Layer Farm",
|
||||
Sku: "EGG-GOOD",
|
||||
Uom: "Unit",
|
||||
Category: "Telur",
|
||||
Price: 1800,
|
||||
},
|
||||
{
|
||||
Name: "Telur Pecah",
|
||||
Brand: "Layer Farm",
|
||||
Sku: "EGG-CRACK",
|
||||
Uom: "Unit",
|
||||
Category: "Telur",
|
||||
Price: 900,
|
||||
},
|
||||
}
|
||||
|
||||
for _, seed := range seeds {
|
||||
@@ -978,25 +835,44 @@ func seedBanks(tx *gorm.DB, createdBy uint) error {
|
||||
}
|
||||
|
||||
func seedProductWarehouse(tx *gorm.DB, createdBy uint) error {
|
||||
|
||||
seeds := []struct {
|
||||
ProductID uint
|
||||
WarehouseID uint
|
||||
Quantity float64
|
||||
ProductName string
|
||||
WarehouseName string
|
||||
Quantity float64
|
||||
}{
|
||||
{ProductID: 1, WarehouseID: 1, Quantity: 100},
|
||||
{ProductID: 2, WarehouseID: 2, Quantity: 200},
|
||||
{ProductID: 2, WarehouseID: 1, Quantity: 300},
|
||||
{ProductID: 1, WarehouseID: 3, Quantity: 5000},
|
||||
{ProductName: "DOC Broiler", WarehouseName: "Gudang Priangan", Quantity: 100},
|
||||
{ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Singaparna", Quantity: 200},
|
||||
{ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Banten", Quantity: 300},
|
||||
{ProductName: "DOC Broiler", WarehouseName: "Gudang Singaparna 1", Quantity: 5000},
|
||||
{ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Singaparna 1", Quantity: 600},
|
||||
{ProductName: "Telur Pecah", WarehouseName: "Gudang Singaparna 1", Quantity: 80},
|
||||
{ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Cikaum 1", Quantity: 450},
|
||||
{ProductName: "Telur Pecah", WarehouseName: "Gudang Cikaum 1", Quantity: 60},
|
||||
}
|
||||
|
||||
for _, seed := range seeds {
|
||||
var product entity.Product
|
||||
if err := tx.Where("name = ?", seed.ProductName).First(&product).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("product %q not found for product warehouse seeding", seed.ProductName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var warehouse entity.Warehouse
|
||||
if err := tx.Where("name = ?", seed.WarehouseName).First(&warehouse).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("warehouse %q not found for product warehouse seeding", seed.WarehouseName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var productWarehouse entity.ProductWarehouse
|
||||
err := tx.Where("product_id = ? AND warehouse_id = ?", seed.ProductID, seed.WarehouseID).First(&productWarehouse).Error
|
||||
err := tx.Where("product_id = ? AND warehouse_id = ?", product.Id, warehouse.Id).First(&productWarehouse).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
productWarehouse = entity.ProductWarehouse{
|
||||
ProductId: seed.ProductID,
|
||||
WarehouseId: seed.WarehouseID,
|
||||
ProductId: product.Id,
|
||||
WarehouseId: warehouse.Id,
|
||||
Quantity: seed.Quantity,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
@@ -1005,6 +881,12 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error {
|
||||
}
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := tx.Model(&productWarehouse).Updates(map[string]any{
|
||||
"quantity": seed.Quantity,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,71 +967,6 @@ func seedTransferStock(tx *gorm.DB, createdBy uint) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
func seedChickin(tx *gorm.DB, createdBy uint) error {
|
||||
// gunakan identitas yang stabil, bukan ID pivot
|
||||
seeds := []struct {
|
||||
KandangName string
|
||||
LocationName string
|
||||
Period int
|
||||
ChickInDate string
|
||||
Quantity float64
|
||||
Note string
|
||||
}{
|
||||
{"Singaparna 1", "Singaparna", 1, "2025-10-20", 100, "Seeder chickin 1"},
|
||||
{"Cikaum 1", "Cikaum", 1, "2025-10-21", 200, "Seeder chickin 2"},
|
||||
}
|
||||
|
||||
for _, s := range seeds {
|
||||
pfkID, err := ensurePFK(tx, s.KandangName, s.LocationName, s.Period)
|
||||
if err != nil { return err }
|
||||
|
||||
date, err := time.Parse("2006-01-02", s.ChickInDate)
|
||||
if err != nil { return err }
|
||||
|
||||
// upsert project_chickin (idempotent)
|
||||
var chickin entity.ProjectChickin
|
||||
err = tx.Where("project_flock_kandang_id = ? AND chick_in_date = ?", pfkID, date).First(&chickin).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
chickin = entity.ProjectChickin{
|
||||
ProjectFlockKandangId: pfkID,
|
||||
ChickInDate: date,
|
||||
Quantity: s.Quantity,
|
||||
Note: s.Note,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if err := tx.Create(&chickin).Error; err != nil { return err }
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// upsert population
|
||||
var pop entity.ProjectFlockPopulation
|
||||
err = tx.Where("project_flock_kandang_id = ?", pfkID).First(&pop).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
pop = entity.ProjectFlockPopulation{
|
||||
ProjectFlockKandangId: pfkID,
|
||||
InitialQuantity: s.Quantity,
|
||||
CurrentQuantity: s.Quantity,
|
||||
ReservedQuantity: 0,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
if err := tx.Create(&pop).Error; err != nil { return err }
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := tx.Model(&entity.ProjectFlockPopulation{}).
|
||||
Where("id = ?", pop.Id).
|
||||
Updates(map[string]any{
|
||||
"initial_quantity": pop.InitialQuantity + s.Quantity,
|
||||
"current_quantity": pop.CurrentQuantity + s.Quantity,
|
||||
"reserved_quantity": 0,
|
||||
}).Error; err != nil { return err }
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
@@ -1165,30 +982,3 @@ func intPtr(v int) *int {
|
||||
func uintPtr(v uint) *uint {
|
||||
return &v
|
||||
}
|
||||
|
||||
func ensurePFK(tx *gorm.DB, kandangName, locationName string, period int) (uint, error) {
|
||||
var kandang entity.Kandang
|
||||
if err := tx.Where("name = ?", kandangName).First(&kandang).Error; err != nil {
|
||||
return 0, fmt.Errorf("kandang %q not found: %w", kandangName, err)
|
||||
}
|
||||
var loc entity.Location
|
||||
if err := tx.Where("name = ?", locationName).First(&loc).Error; err != nil {
|
||||
return 0, fmt.Errorf("location %q not found: %w", locationName, err)
|
||||
}
|
||||
var pf entity.ProjectFlock
|
||||
if err := tx.Where("location_id = ? AND period = ?", loc.Id, period).First(&pf).Error; err != nil {
|
||||
return 0, fmt.Errorf("project_flock for %s period %d not found: %w", locationName, period, err)
|
||||
}
|
||||
var pfk entity.ProjectFlockKandang
|
||||
if err := tx.Where("project_flock_id = ? AND kandang_id = ?", pf.Id, kandang.Id).First(&pfk).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
pfk = entity.ProjectFlockKandang{ ProjectFlockId: pf.Id, KandangId: kandang.Id }
|
||||
if err := tx.Create(&pfk).Error; err != nil {
|
||||
return 0, fmt.Errorf("create pivot pfk(%d,%d) failed: %w", pf.Id, kandang.Id, err)
|
||||
}
|
||||
} else {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return pfk.Id, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user