codex: initiated changes

This commit is contained in:
Adnan Zahir
2026-03-30 13:40:29 +07:00
parent d76f72050e
commit be00837148
22 changed files with 1762 additions and 328 deletions
@@ -2,9 +2,10 @@ package repository
import (
"context"
"sort"
"strings"
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
@@ -12,7 +13,7 @@ import (
)
type MarketingDeliveryProductRepository interface {
repository.BaseRepository[entity.MarketingDeliveryProduct]
commonRepo.BaseRepository[entity.MarketingDeliveryProduct]
GetDeliveryProductsByProjectFlockID(ctx context.Context, projectFlockID uint, callback func(*gorm.DB) *gorm.DB) ([]entity.MarketingDeliveryProduct, error)
GetClosingPenjualan(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error)
GetClosingPenjualanByCategory(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint, category string) ([]entity.MarketingDeliveryProduct, error)
@@ -23,26 +24,27 @@ type MarketingDeliveryProductRepository interface {
GetUsageQty(ctx context.Context, id uint) (float64, error)
ResetFifoFields(ctx context.Context, id uint) error
GetClosingPenjualanForAgeChickDataProduction(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error)
GetAttributionRowsByDeliveryProductIDs(ctx context.Context, deliveryProductIDs []uint) ([]commonRepo.MarketingDeliveryAttributionRow, error)
}
type MarketingDeliveryProductRepositoryImpl struct {
*repository.BaseRepositoryImpl[entity.MarketingDeliveryProduct]
*commonRepo.BaseRepositoryImpl[entity.MarketingDeliveryProduct]
}
func NewMarketingDeliveryProductRepository(db *gorm.DB) MarketingDeliveryProductRepository {
return &MarketingDeliveryProductRepositoryImpl{
BaseRepositoryImpl: repository.NewBaseRepository[entity.MarketingDeliveryProduct](db),
BaseRepositoryImpl: commonRepo.NewBaseRepository[entity.MarketingDeliveryProduct](db),
}
}
func (r *MarketingDeliveryProductRepositoryImpl) GetDeliveryProductsByProjectFlockID(ctx context.Context, projectFlockID uint, callback func(*gorm.DB) *gorm.DB) ([]entity.MarketingDeliveryProduct, error) {
var deliveryProducts []entity.MarketingDeliveryProduct
attributionQuery := commonRepo.MarketingDeliveryAttributionRowsQuery(r.DB().WithContext(ctx))
db := r.DB().WithContext(ctx).
Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id").
Joins("JOIN product_warehouses ON product_warehouses.id = marketing_products.product_warehouse_id").
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id").
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
Joins("JOIN (?) AS mda ON mda.marketing_delivery_product_id = marketing_delivery_products.id", attributionQuery).
Where("mda.project_flock_id = ?", projectFlockID).
Distinct("marketing_delivery_products.*")
if callback != nil {
@@ -57,139 +59,50 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetDeliveryProductsByProjectFlo
}
func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualan(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error) {
var deliveryProducts []entity.MarketingDeliveryProduct
db := r.DB().WithContext(ctx).
Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id").
Joins("JOIN product_warehouses ON product_warehouses.id = marketing_products.product_warehouse_id").
Joins("JOIN products ON products.id = product_warehouses.product_id").
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id").
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
Where("marketing_delivery_products.delivery_date IS NOT NULL").
Distinct("marketing_delivery_products.*")
if projectFlockKandangID != nil {
db = db.Where("product_warehouses.project_flock_kandang_id = ?", *projectFlockKandangID)
}
db = db.
Preload("MarketingProduct").
Preload("MarketingProduct.ProductWarehouse").
Preload("MarketingProduct.ProductWarehouse.Product").
Preload("MarketingProduct.ProductWarehouse.Product.ProductCategory").
Preload("MarketingProduct.ProductWarehouse.Product.Uom").
Preload("MarketingProduct.ProductWarehouse.Product.Flags").
Preload("MarketingProduct.ProductWarehouse.Warehouse").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Kandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins").
Preload("MarketingProduct.Marketing").
Preload("MarketingProduct.Marketing.Customer").
Order("marketing_delivery_products.delivery_date DESC")
if err := db.Find(&deliveryProducts).Error; err != nil {
attributionRows, err := r.getClosingAttributionRows(ctx, projectFlockID, projectFlockKandangID, nil)
if err != nil {
return nil, err
}
return deliveryProducts, nil
return r.fetchClosingDeliveryProducts(ctx, attributionRows, projectFlockKandangID)
}
func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualanForAgeChickDataProduction(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error) {
var deliveryProducts []entity.MarketingDeliveryProduct
db := r.DB().WithContext(ctx).
Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id").
Joins("JOIN product_warehouses ON product_warehouses.id = marketing_products.product_warehouse_id").
Joins("JOIN products ON products.id = product_warehouses.product_id").
Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = 'products'").
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id").
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
Where("flags.name IN (?)", []string{
string(utils.FlagAyamAfkir),
string(utils.FlagAyamCulling),
string(utils.FlagPullet),
string(utils.FlagLayer),
}).
Where("marketing_delivery_products.delivery_date IS NOT NULL").
Distinct("marketing_delivery_products.*")
if projectFlockKandangID != nil {
db = db.Where("product_warehouses.project_flock_kandang_id = ?", *projectFlockKandangID)
}
db = db.
Preload("MarketingProduct").
Preload("MarketingProduct.ProductWarehouse").
Preload("MarketingProduct.ProductWarehouse.Product").
Preload("MarketingProduct.ProductWarehouse.Product.ProductCategory").
Preload("MarketingProduct.ProductWarehouse.Product.Flags").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins").
Order("marketing_delivery_products.delivery_date DESC")
if err := db.Find(&deliveryProducts).Error; err != nil {
attributionRows, err := r.getClosingAttributionRows(ctx, projectFlockID, projectFlockKandangID, []string{
string(utils.FlagAyamAfkir),
string(utils.FlagAyamCulling),
string(utils.FlagPullet),
string(utils.FlagLayer),
})
if err != nil {
return nil, err
}
return deliveryProducts, nil
return r.fetchClosingDeliveryProducts(ctx, attributionRows, projectFlockKandangID)
}
func (r *MarketingDeliveryProductRepositoryImpl) GetClosingPenjualanByCategory(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint, category string) ([]entity.MarketingDeliveryProduct, error) {
var deliveryProducts []entity.MarketingDeliveryProduct
db := r.DB().WithContext(ctx).
Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id").
Joins("JOIN product_warehouses ON product_warehouses.id = marketing_products.product_warehouse_id").
Joins("JOIN products ON products.id = product_warehouses.product_id").
Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = 'products'").
Joins("JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id").
Where("project_flock_kandangs.project_flock_id = ?", projectFlockID).
Where("marketing_delivery_products.delivery_date IS NOT NULL").
Distinct("marketing_delivery_products.*")
if projectFlockKandangID != nil {
db = db.Where("product_warehouses.project_flock_kandang_id = ?", *projectFlockKandangID)
flagNames := []string{
string(utils.FlagDOC),
string(utils.FlagPullet),
string(utils.FlagLayer),
string(utils.FlagAyamAfkir),
string(utils.FlagAyamCulling),
string(utils.FlagAyamMati),
}
if category == string(utils.ProjectFlockCategoryLaying) {
db = db.Where("flags.name IN (?)", []string{
flagNames = []string{
string(utils.FlagTelur),
string(utils.FlagTelurUtuh),
string(utils.FlagTelurPecah),
string(utils.FlagTelurPutih),
string(utils.FlagTelurRetak),
})
} else {
db = db.Where("flags.name IN (?)", []string{
string(utils.FlagDOC),
string(utils.FlagPullet),
string(utils.FlagLayer),
string(utils.FlagAyamAfkir),
string(utils.FlagAyamCulling),
string(utils.FlagAyamMati),
})
}
}
db = db.
Preload("MarketingProduct").
Preload("MarketingProduct.ProductWarehouse").
Preload("MarketingProduct.ProductWarehouse.Product").
Preload("MarketingProduct.ProductWarehouse.Product.ProductCategory").
Preload("MarketingProduct.ProductWarehouse.Product.Uom").
Preload("MarketingProduct.ProductWarehouse.Product.Flags").
Preload("MarketingProduct.ProductWarehouse.Warehouse").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Kandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins").
Preload("MarketingProduct.Marketing").
Preload("MarketingProduct.Marketing.Customer").
Order("marketing_delivery_products.delivery_date DESC")
if err := db.Find(&deliveryProducts).Error; err != nil {
attributionRows, err := r.getClosingAttributionRows(ctx, projectFlockID, projectFlockKandangID, flagNames)
if err != nil {
return nil, err
}
return deliveryProducts, nil
return r.fetchClosingDeliveryProducts(ctx, attributionRows, projectFlockKandangID)
}
func (r *MarketingDeliveryProductRepositoryImpl) GetByMarketingId(ctx context.Context, marketingId uint) ([]entity.MarketingDeliveryProduct, error) {
@@ -219,12 +132,199 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetByMarketingProductID(ctx con
return &deliveryProduct, nil
}
func (r *MarketingDeliveryProductRepositoryImpl) GetAttributionRowsByDeliveryProductIDs(ctx context.Context, deliveryProductIDs []uint) ([]commonRepo.MarketingDeliveryAttributionRow, error) {
if len(deliveryProductIDs) == 0 {
return []commonRepo.MarketingDeliveryAttributionRow{}, nil
}
var rows []commonRepo.MarketingDeliveryAttributionRow
query := r.DB().WithContext(ctx).
Table("(?) AS mda", commonRepo.MarketingDeliveryAttributionRowsQuery(r.DB().WithContext(ctx))).
Where("mda.marketing_delivery_product_id IN ?", deliveryProductIDs).
Order("mda.marketing_delivery_product_id ASC, mda.project_flock_kandang_id ASC")
if err := query.Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *MarketingDeliveryProductRepositoryImpl) getClosingAttributionRows(
ctx context.Context,
projectFlockID uint,
projectFlockKandangID *uint,
flagNames []string,
) ([]commonRepo.MarketingDeliveryAttributionRow, error) {
var rows []commonRepo.MarketingDeliveryAttributionRow
attributionQuery := commonRepo.MarketingDeliveryAttributionRowsQuery(r.DB().WithContext(ctx))
query := r.DB().WithContext(ctx).
Table("(?) AS mda", attributionQuery).
Joins("JOIN marketing_delivery_products mdp ON mdp.id = mda.marketing_delivery_product_id").
Joins("JOIN marketing_products mp ON mp.id = mdp.marketing_product_id").
Joins("JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id").
Joins("JOIN products prod ON prod.id = pw.product_id").
Where("mda.project_flock_id = ?", projectFlockID).
Where("mdp.delivery_date IS NOT NULL")
if projectFlockKandangID != nil {
query = query.Where("mda.project_flock_kandang_id = ?", *projectFlockKandangID)
}
if len(flagNames) > 0 {
query = query.
Joins("JOIN flags f ON f.flagable_id = prod.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
Where("f.name IN ?", flagNames)
}
query = query.
Select(`
mda.marketing_delivery_product_id,
mda.project_flock_kandang_id,
mda.project_flock_id,
mda.project_flock_category,
SUM(mda.allocated_qty) AS allocated_qty
`).
Group(`
mda.marketing_delivery_product_id,
mda.project_flock_kandang_id,
mda.project_flock_id,
mda.project_flock_category
`).
Order("mda.marketing_delivery_product_id ASC, mda.project_flock_kandang_id ASC")
if err := query.Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *MarketingDeliveryProductRepositoryImpl) fetchClosingDeliveryProducts(
ctx context.Context,
attributionRows []commonRepo.MarketingDeliveryAttributionRow,
projectFlockKandangID *uint,
) ([]entity.MarketingDeliveryProduct, error) {
deliveryIDs := orderedDeliveryProductIDs(attributionRows)
if len(deliveryIDs) == 0 {
return []entity.MarketingDeliveryProduct{}, nil
}
query := r.closingDeliveryProductsQuery(ctx).
Where("marketing_delivery_products.id IN ?", deliveryIDs).
Order("marketing_delivery_products.delivery_date DESC")
if projectFlockKandangID == nil {
query = query.Joins(
"LEFT JOIN (?) AS mda_single ON mda_single.marketing_delivery_product_id = marketing_delivery_products.id",
commonRepo.MarketingDeliverySingleAttributionQuery(r.DB().WithContext(ctx)),
).Select("marketing_delivery_products.*, mda_single.attributed_project_flock_kandang_id")
}
var deliveryProducts []entity.MarketingDeliveryProduct
if err := query.Find(&deliveryProducts).Error; err != nil {
return nil, err
}
if projectFlockKandangID == nil {
return deliveryProducts, nil
}
return scaleDeliveryProductsByAttribution(deliveryProducts, attributionRows, *projectFlockKandangID), nil
}
func (r *MarketingDeliveryProductRepositoryImpl) closingDeliveryProductsQuery(ctx context.Context) *gorm.DB {
return r.DB().WithContext(ctx).
Model(&entity.MarketingDeliveryProduct{}).
Preload("MarketingProduct").
Preload("MarketingProduct.ProductWarehouse").
Preload("MarketingProduct.ProductWarehouse.Product").
Preload("MarketingProduct.ProductWarehouse.Product.ProductCategory").
Preload("MarketingProduct.ProductWarehouse.Product.Uom").
Preload("MarketingProduct.ProductWarehouse.Product.Flags").
Preload("MarketingProduct.ProductWarehouse.Warehouse").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.ProjectFlock").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Kandang").
Preload("MarketingProduct.ProductWarehouse.ProjectFlockKandang.Chickins").
Preload("MarketingProduct.Marketing").
Preload("MarketingProduct.Marketing.Customer").
Preload("AttributedProjectFlockKandang").
Preload("AttributedProjectFlockKandang.ProjectFlock").
Preload("AttributedProjectFlockKandang.Kandang").
Preload("AttributedProjectFlockKandang.Chickins")
}
func orderedDeliveryProductIDs(rows []commonRepo.MarketingDeliveryAttributionRow) []uint {
seen := make(map[uint]struct{}, len(rows))
ids := make([]uint, 0, len(rows))
for _, row := range rows {
if row.MarketingDeliveryProductID == 0 {
continue
}
if _, ok := seen[row.MarketingDeliveryProductID]; ok {
continue
}
seen[row.MarketingDeliveryProductID] = struct{}{}
ids = append(ids, row.MarketingDeliveryProductID)
}
sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
return ids
}
func scaleDeliveryProductsByAttribution(
deliveryProducts []entity.MarketingDeliveryProduct,
rows []commonRepo.MarketingDeliveryAttributionRow,
projectFlockKandangID uint,
) []entity.MarketingDeliveryProduct {
if len(deliveryProducts) == 0 || projectFlockKandangID == 0 {
return deliveryProducts
}
totalByDelivery := make(map[uint]float64, len(rows))
selectedByDelivery := make(map[uint]float64, len(rows))
for _, row := range rows {
totalByDelivery[row.MarketingDeliveryProductID] += row.AllocatedQty
if row.ProjectFlockKandangID == projectFlockKandangID {
selectedByDelivery[row.MarketingDeliveryProductID] += row.AllocatedQty
}
}
filtered := make([]entity.MarketingDeliveryProduct, 0, len(deliveryProducts))
for _, delivery := range deliveryProducts {
selectedQty := selectedByDelivery[delivery.Id]
totalQty := totalByDelivery[delivery.Id]
if selectedQty <= 0 {
continue
}
share := 1.0
if totalQty > 0 {
share = selectedQty / totalQty
}
cloned := delivery
cloned.AttributedProjectFlockKandangId = &projectFlockKandangID
cloned.UsageQty = selectedQty
cloned.PendingQty = 0
cloned.TotalWeight = delivery.TotalWeight * share
cloned.TotalPrice = delivery.TotalPrice * share
filtered = append(filtered, cloned)
}
return filtered
}
func (r *MarketingDeliveryProductRepositoryImpl) GetAllWithFilters(ctx context.Context, offset, limit int, filters *validation.MarketingQuery) ([]entity.MarketingDeliveryProduct, int64, error) {
var deliveryProducts []entity.MarketingDeliveryProduct
var total int64
baseDB := r.DB().WithContext(ctx)
singleAttributionQuery := commonRepo.MarketingDeliverySingleAttributionQuery(baseDB)
db := r.DB().WithContext(ctx).
Model(&entity.MarketingDeliveryProduct{}).
Select("marketing_delivery_products.*, mda_single.attributed_project_flock_kandang_id").
Joins("LEFT JOIN (?) AS mda_single ON mda_single.marketing_delivery_product_id = marketing_delivery_products.id", singleAttributionQuery).
Preload("MarketingProduct", func(db *gorm.DB) *gorm.DB {
return db.
Preload("Marketing").
@@ -237,6 +337,9 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetAllWithFilters(ctx context.C
Preload("ProductWarehouse.ProjectFlockKandang").
Preload("ProductWarehouse.ProjectFlockKandang.ProjectFlock")
}).
Preload("AttributedProjectFlockKandang").
Preload("AttributedProjectFlockKandang.ProjectFlock").
Preload("AttributedProjectFlockKandang.Kandang").
Joins("JOIN marketing_products ON marketing_products.id = marketing_delivery_products.marketing_product_id").
Joins("JOIN marketings ON marketings.id = marketing_products.marketing_id").
Where("marketing_delivery_products.delivery_date IS NOT NULL")
@@ -292,22 +395,27 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetAllWithFilters(ctx context.C
}
if filters.AreaId > 0 || filters.LocationId > 0 || filters.AllowedAreaIDs != nil || filters.AllowedLocationIDs != nil {
db = db.Joins("LEFT JOIN project_flock_kandangs ON project_flock_kandangs.id = product_warehouses.project_flock_kandang_id").
Joins("LEFT JOIN project_flocks ON project_flocks.id = project_flock_kandangs.project_flock_id")
buildAttrFilter := func() *gorm.DB {
return r.DB().WithContext(ctx).
Table("(?) AS mda", commonRepo.MarketingDeliveryAttributionRowsQuery(r.DB().WithContext(ctx))).
Select("1").
Joins("JOIN project_flock_kandangs pfk ON pfk.id = mda.project_flock_kandang_id").
Joins("JOIN project_flocks pf ON pf.id = pfk.project_flock_id").
Where("mda.marketing_delivery_product_id = marketing_delivery_products.id")
}
if filters.AreaId > 0 {
db = db.Where("project_flocks.area_id = ?", filters.AreaId)
db = db.Where("EXISTS (?)", buildAttrFilter().Where("pf.area_id = ?", filters.AreaId))
}
if filters.LocationId > 0 {
db = db.Where("project_flocks.location_id = ?", filters.LocationId)
db = db.Where("EXISTS (?)", buildAttrFilter().Where("pf.location_id = ?", filters.LocationId))
}
if filters.AllowedAreaIDs != nil {
if len(filters.AllowedAreaIDs) == 0 {
db = db.Where("1 = 0")
} else {
db = db.Where("project_flocks.area_id IN ?", filters.AllowedAreaIDs)
db = db.Where("EXISTS (?)", buildAttrFilter().Where("pf.area_id IN ?", filters.AllowedAreaIDs))
}
}
@@ -315,7 +423,7 @@ func (r *MarketingDeliveryProductRepositoryImpl) GetAllWithFilters(ctx context.C
if len(filters.AllowedLocationIDs) == 0 {
db = db.Where("1 = 0")
} else {
db = db.Where("project_flocks.location_id IN ?", filters.AllowedLocationIDs)
db = db.Where("EXISTS (?)", buildAttrFilter().Where("pf.location_id IN ?", filters.AllowedLocationIDs))
}
}
}
@@ -0,0 +1,42 @@
package repository
import (
"testing"
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
)
func TestScaleDeliveryProductsByAttribution(t *testing.T) {
projectFlockKandangID := uint(101)
deliveryProducts := []entity.MarketingDeliveryProduct{
{
Id: 55,
UsageQty: 100,
TotalWeight: 180,
TotalPrice: 3600,
},
}
attributionRows := []commonRepo.MarketingDeliveryAttributionRow{
{MarketingDeliveryProductID: 55, ProjectFlockKandangID: 101, AllocatedQty: 60},
{MarketingDeliveryProductID: 55, ProjectFlockKandangID: 102, AllocatedQty: 40},
}
got := scaleDeliveryProductsByAttribution(deliveryProducts, attributionRows, projectFlockKandangID)
if len(got) != 1 {
t.Fatalf("expected 1 scaled delivery, got %d", len(got))
}
if got[0].UsageQty != 60 {
t.Fatalf("expected usage qty 60, got %.2f", got[0].UsageQty)
}
if got[0].TotalWeight != 108 {
t.Fatalf("expected total weight 108, got %.2f", got[0].TotalWeight)
}
if got[0].TotalPrice != 2160 {
t.Fatalf("expected total price 2160, got %.2f", got[0].TotalPrice)
}
if got[0].AttributedProjectFlockKandangId == nil || *got[0].AttributedProjectFlockKandangId != projectFlockKandangID {
t.Fatalf("expected attributed kandang id %d, got %+v", projectFlockKandangID, got[0].AttributedProjectFlockKandangId)
}
}