mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 23:05:44 +00:00
Merge branch 'feat/BE/US-75/chick-in-doc' into 'development-before-sso'
[FIX/BE][US#75/TASK#119] Align chickin seeder and DeleteOne with CreateOne behavior, create project lookup API See merge request mbugroup/lti-api!38
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE IF EXISTS project_chickin_details;
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS project_chickin_details (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
project_chickin_id BIGINT NOT NULL,
|
||||||
|
product_warehouse_id BIGINT NOT NULL,
|
||||||
|
quantity NUMERIC(15, 3) NOT NULL,
|
||||||
|
created_by BIGINT NOT NULL,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT now(),
|
||||||
|
deleted_at TIMESTAMPTZ
|
||||||
|
);
|
||||||
|
|
||||||
|
-- FOREIGN KEYS (dijalankan setelah semua tabel parent ada)
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'project_chickins') THEN
|
||||||
|
ALTER TABLE project_chickin_details
|
||||||
|
ADD CONSTRAINT fk_project_chickin_id
|
||||||
|
FOREIGN KEY (project_chickin_id)
|
||||||
|
REFERENCES project_chickins(id)
|
||||||
|
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'product_warehouses') THEN
|
||||||
|
ALTER TABLE project_chickin_details
|
||||||
|
ADD CONSTRAINT fk_product_warehouse_id
|
||||||
|
FOREIGN KEY (product_warehouse_id)
|
||||||
|
REFERENCES product_warehouses(id)
|
||||||
|
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'users') THEN
|
||||||
|
ALTER TABLE project_chickin_details
|
||||||
|
ADD CONSTRAINT fk_created_by
|
||||||
|
FOREIGN KEY (created_by)
|
||||||
|
REFERENCES users(id)
|
||||||
|
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- INDEXES
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_project_chickin_details_project_chickin_id ON project_chickin_details (project_chickin_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_project_chickin_details_product_warehouse_id ON project_chickin_details (product_warehouse_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_project_chickin_details_created_by ON project_chickin_details (created_by);
|
||||||
@@ -1170,7 +1170,6 @@ func seedChickin(tx *gorm.DB, createdBy uint) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update/Insert ProjectFlockPopulation
|
|
||||||
var population entity.ProjectFlockPopulation
|
var population entity.ProjectFlockPopulation
|
||||||
err = tx.Where("project_flock_kandang_id = ?", seed.ProjectFlockKandangId).First(&population).Error
|
err = tx.Where("project_flock_kandang_id = ?", seed.ProjectFlockKandangId).First(&population).Error
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
@@ -1198,6 +1197,84 @@ func seedChickin(tx *gorm.DB, createdBy uint) error {
|
|||||||
return err
|
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectChickinDetail struct {
|
||||||
|
Id uint `gorm:"primaryKey"`
|
||||||
|
ProjectChickinId uint `gorm:"column:project_chickin_id;not null"`
|
||||||
|
ProductWarehouseId uint `gorm:"column:product_warehouse_id;not null"`
|
||||||
|
Quantity float64 `gorm:"type:numeric(15,3);not null"`
|
||||||
|
CreatedBy uint `gorm:"column:created_by;not null"`
|
||||||
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
|
||||||
|
ProjectChickin *ProjectChickin `gorm:"foreignKey:ProjectChickinId;references:Id"`
|
||||||
|
ProductWarehouse *ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"`
|
||||||
|
CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"`
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package entities
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AuditLog struct {
|
|
||||||
Id uint `gorm:"primaryKey"`
|
|
||||||
TableName string `gorm:"size:100;not null"`
|
|
||||||
RecordId uint `gorm:"not null"`
|
|
||||||
Action string `gorm:"size:30;not null"`
|
|
||||||
BeforeData string `gorm:"type:jsonb"`
|
|
||||||
AfterData string `gorm:"type:jsonb"`
|
|
||||||
ChangedBy uint `gorm:"not null"`
|
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
|
||||||
|
|
||||||
User *User `gorm:"foreignKey:ChangedBy;references:Id"`
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package entities
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
EntityTypeProjectFlockKandang = "PROJECT_FLOCK_KANDANG"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StockAvailability struct {
|
|
||||||
Id uint `gorm:"primaryKey"`
|
|
||||||
EntityType string `gorm:"size:50;not null"`
|
|
||||||
EntityId uint `gorm:"not null"`
|
|
||||||
ProductId uint `gorm:"not null"`
|
|
||||||
Quantity float64 `gorm:"not null;default:0"`
|
|
||||||
ReservedQuantity float64 `gorm:"not null;default:0"`
|
|
||||||
Unit string `gorm:"size:20"`
|
|
||||||
LastUpdated time.Time `gorm:"autoUpdateTime"`
|
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
||||||
|
|
||||||
Product *Product `gorm:"foreignKey:ProductId;references:Id"`
|
|
||||||
}
|
|
||||||
@@ -266,6 +266,24 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
}
|
}
|
||||||
s.Log.Infof("Source product warehouse updated: %+v", sourcePW.Id)
|
s.Log.Infof("Source product warehouse updated: %+v", sourcePW.Id)
|
||||||
|
|
||||||
|
// create stock log for decrease (source)
|
||||||
|
beforeQty := sourcePW.Quantity + product.ProductQty // sourcePW already decreased
|
||||||
|
decreaseLog := &entity.StockLog{
|
||||||
|
TransactionType: entity.TransactionTypeDecrease,
|
||||||
|
Quantity: product.ProductQty,
|
||||||
|
BeforeQuantity: beforeQty,
|
||||||
|
AfterQuantity: sourcePW.Quantity,
|
||||||
|
LogType: entity.LogTypeTransfer,
|
||||||
|
LogId: uint(entityTransfer.Id),
|
||||||
|
Note: "",
|
||||||
|
ProductWarehouseId: sourcePW.Id,
|
||||||
|
CreatedBy: 1,
|
||||||
|
}
|
||||||
|
if err := s.StockLogsRepository.WithTx(tx).CreateOne(c.Context(), decreaseLog, nil); err != nil {
|
||||||
|
s.Log.Errorf("Failed to create stock log decrease: %+v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Tambah stok di gudang tujuan
|
// Tambah stok di gudang tujuan
|
||||||
destPW, err := s.ProductWarehouseRepo.GetProductWarehouseByProductAndWarehouseID(
|
destPW, err := s.ProductWarehouseRepo.GetProductWarehouseByProductAndWarehouseID(
|
||||||
c.Context(), uint(product.ProductID), uint(req.DestinationWarehouseID),
|
c.Context(), uint(product.ProductID), uint(req.DestinationWarehouseID),
|
||||||
@@ -296,6 +314,24 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
}
|
}
|
||||||
s.Log.Infof("Destination product warehouse updated: %+v", destPW.Id)
|
s.Log.Infof("Destination product warehouse updated: %+v", destPW.Id)
|
||||||
|
|
||||||
|
// create stock log for increase (destination)
|
||||||
|
beforeDestQty := destPW.Quantity - product.ProductQty
|
||||||
|
increaseLog := &entity.StockLog{
|
||||||
|
TransactionType: entity.TransactionTypeIncrease,
|
||||||
|
Quantity: product.ProductQty,
|
||||||
|
BeforeQuantity: beforeDestQty,
|
||||||
|
AfterQuantity: destPW.Quantity,
|
||||||
|
LogType: entity.LogTypeTransfer,
|
||||||
|
LogId: uint(entityTransfer.Id),
|
||||||
|
Note: "",
|
||||||
|
ProductWarehouseId: destPW.Id,
|
||||||
|
CreatedBy: 1,
|
||||||
|
}
|
||||||
|
if err := s.StockLogsRepository.WithTx(tx).CreateOne(c.Context(), increaseLog, nil); err != nil {
|
||||||
|
s.Log.Errorf("Failed to create stock log increase: %+v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||||
rChickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
rChickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||||
sChickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/services"
|
sChickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/services"
|
||||||
rAuditLog "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories"
|
|
||||||
|
|
||||||
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||||
|
|
||||||
@@ -22,8 +21,9 @@ type ChickinModule struct{}
|
|||||||
|
|
||||||
func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||||
chickinRepo := rChickin.NewChickinRepository(db)
|
chickinRepo := rChickin.NewChickinRepository(db)
|
||||||
|
chickinDetailRepo := rChickin.NewChickinDetailRepository(db)
|
||||||
kandangRepo := rKandang.NewKandangRepository(db)
|
kandangRepo := rKandang.NewKandangRepository(db)
|
||||||
auditlogrepo := rAuditLog.NewAuditLogRepository(db)
|
|
||||||
warehouseRepo := rWarehouse.NewWarehouseRepository(db)
|
warehouseRepo := rWarehouse.NewWarehouseRepository(db)
|
||||||
projectflockkandangrepo := rProjectFlock.NewProjectFlockKandangRepository(db)
|
projectflockkandangrepo := rProjectFlock.NewProjectFlockKandangRepository(db)
|
||||||
projectflockpopulationrepo := rProjectFlock.NewProjectFlockPopulationRepository(db)
|
projectflockpopulationrepo := rProjectFlock.NewProjectFlockPopulationRepository(db)
|
||||||
@@ -32,7 +32,7 @@ func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
|
|||||||
|
|
||||||
userRepo := rUser.NewUserRepository(db)
|
userRepo := rUser.NewUserRepository(db)
|
||||||
|
|
||||||
chickinService := sChickin.NewChickinService(chickinRepo, kandangRepo, warehouseRepo, productWarehouseRepo, projectFlockRepo, auditlogrepo, projectflockkandangrepo, projectflockpopulationrepo, validate)
|
chickinService := sChickin.NewChickinService(chickinRepo, kandangRepo, warehouseRepo, productWarehouseRepo, projectFlockRepo, projectflockkandangrepo, projectflockpopulationrepo, chickinDetailRepo, validate)
|
||||||
userService := sUser.NewUserService(userRepo, validate)
|
userService := sUser.NewUserService(userRepo, validate)
|
||||||
|
|
||||||
ChickinRoutes(router, userService, chickinService)
|
ChickinRoutes(router, userService, chickinService)
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProjectChickinDetailRepository interface {
|
||||||
|
repository.BaseRepository[entity.ProjectChickinDetail]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChickinDetailRepositoryImpl struct {
|
||||||
|
*repository.BaseRepositoryImpl[entity.ProjectChickinDetail]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChickinDetailRepository(db *gorm.DB) ProjectChickinDetailRepository {
|
||||||
|
return &ChickinDetailRepositoryImpl{
|
||||||
|
BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectChickinDetail](db),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,11 +8,8 @@ import (
|
|||||||
KandangRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/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"
|
rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories"
|
||||||
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||||
rProjectFlockKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
|
||||||
|
|
||||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/validations"
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/validations"
|
||||||
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
|
||||||
AuditLogRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories"
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
@@ -38,12 +35,12 @@ type chickinService struct {
|
|||||||
WarehouseRepo rWarehouse.WarehouseRepository
|
WarehouseRepo rWarehouse.WarehouseRepository
|
||||||
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
|
ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository
|
||||||
ProjectFlockRepo rProjectFlock.ProjectflockRepository
|
ProjectFlockRepo rProjectFlock.ProjectflockRepository
|
||||||
AuditLogRepo AuditLogRepo.AuditLogRepository
|
ProjectflockKandangRepo rProjectFlock.ProjectFlockKandangRepository
|
||||||
ProjectflockKandangRepo rProjectFlockKandang.ProjectFlockKandangRepository
|
|
||||||
ProjectflockPopulationRepo rProjectFlock.ProjectFlockPopulationRepository
|
ProjectflockPopulationRepo rProjectFlock.ProjectFlockPopulationRepository
|
||||||
|
ProjectChickinDetailRepo repository.ProjectChickinDetailRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo KandangRepo.KandangRepository, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, projectFlockRepo rProjectFlock.ProjectflockRepository, auditLogRepo AuditLogRepo.AuditLogRepository, projectflockkandangRepo rProjectFlockKandang.ProjectFlockKandangRepository, projectflockpopulationRepo rProjectFlock.ProjectFlockPopulationRepository, validate *validator.Validate) ChickinService {
|
func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo KandangRepo.KandangRepository, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, projectFlockRepo rProjectFlock.ProjectflockRepository, projectflockkandangRepo rProjectFlock.ProjectFlockKandangRepository, projectflockpopulationRepo rProjectFlock.ProjectFlockPopulationRepository, projectChickinDetailRepo repository.ProjectChickinDetailRepository, validate *validator.Validate) ChickinService {
|
||||||
return &chickinService{
|
return &chickinService{
|
||||||
Log: utils.Log,
|
Log: utils.Log,
|
||||||
Validate: validate,
|
Validate: validate,
|
||||||
@@ -52,9 +49,9 @@ func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo Kan
|
|||||||
WarehouseRepo: warehouseRepo,
|
WarehouseRepo: warehouseRepo,
|
||||||
ProductWarehouseRepo: productWarehouseRepo,
|
ProductWarehouseRepo: productWarehouseRepo,
|
||||||
ProjectFlockRepo: projectFlockRepo,
|
ProjectFlockRepo: projectFlockRepo,
|
||||||
AuditLogRepo: auditLogRepo,
|
|
||||||
ProjectflockKandangRepo: projectflockkandangRepo,
|
ProjectflockKandangRepo: projectflockkandangRepo,
|
||||||
ProjectflockPopulationRepo: projectflockpopulationRepo,
|
ProjectflockPopulationRepo: projectflockpopulationRepo,
|
||||||
|
ProjectChickinDetailRepo: projectChickinDetailRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +109,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
projectflockkandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), 1)
|
projectflockkandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), req.ProjectFlockKandangId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Log.Errorf("Failed to get projectflock kandang: %+v", err)
|
s.Log.Errorf("Failed to get projectflock kandang: %+v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -124,23 +121,12 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
projectFlock, err := s.ProjectFlockRepo.GetByID(
|
|
||||||
c.Context(),
|
|
||||||
projectflockkandang.ProjectFlockId,
|
|
||||||
func(db *gorm.DB) *gorm.DB {
|
|
||||||
return db
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
s.Log.Errorf("Failed to get project flock: %+v", err)
|
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Project Flock not found")
|
|
||||||
}
|
|
||||||
var productWarehouses []entity.ProductWarehouse
|
var productWarehouses []entity.ProductWarehouse
|
||||||
err = s.ProductWarehouseRepo.DB().
|
err = s.ProductWarehouseRepo.DB().
|
||||||
WithContext(c.Context()).
|
WithContext(c.Context()).
|
||||||
Joins("JOIN products ON products.id = product_warehouses.product_id").
|
Joins("JOIN products ON products.id = product_warehouses.product_id").
|
||||||
Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
|
Joins("JOIN product_categories ON product_categories.id = products.product_category_id").
|
||||||
Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", projectFlock.Category, warehouse.Id).
|
Where("product_categories.code = ? AND product_warehouses.warehouse_id = ?", "DOC", warehouse.Id).
|
||||||
Order("created_at DESC").
|
Order("created_at DESC").
|
||||||
Find(&productWarehouses).Error
|
Find(&productWarehouses).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -168,7 +154,7 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid ChickInDate format")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid ChickInDate format")
|
||||||
}
|
}
|
||||||
newChickin := &entity.ProjectChickin{
|
newChickin := &entity.ProjectChickin{
|
||||||
ProjectFlockKandangId: projectflockkandang.ProjectFlockId,
|
ProjectFlockKandangId: projectflockkandang.Id,
|
||||||
ChickInDate: chickinDate,
|
ChickInDate: chickinDate,
|
||||||
Quantity: totalQuantity,
|
Quantity: totalQuantity,
|
||||||
Note: "",
|
Note: "",
|
||||||
@@ -189,6 +175,19 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit
|
|||||||
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
|
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add ke detail chickin
|
||||||
|
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)
|
existingPopulation, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangID(c.Context(), req.ProjectFlockKandangId)
|
||||||
@@ -249,85 +248,142 @@ func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error {
|
func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||||
// todo: cek apakah chickin sudah di approve atau belum
|
db := s.Repository.DB()
|
||||||
|
|
||||||
chickin, err := s.Repository.GetByID(c.Context(), id, nil)
|
tx := db.WithContext(c.Context()).Begin()
|
||||||
|
if tx.Error != nil {
|
||||||
|
s.Log.Errorf("Failed to begin transaction: %+v", tx.Error)
|
||||||
|
return tx.Error
|
||||||
|
}
|
||||||
|
rollback := func(err error) error {
|
||||||
|
if rerr := tx.Rollback().Error; rerr != nil {
|
||||||
|
s.Log.Errorf("Rollback failed: %+v", rerr)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
chickinRepoTx := s.Repository.WithTx(tx)
|
||||||
|
pfkRepoTx := s.ProjectflockKandangRepo.WithTx(tx)
|
||||||
|
productWarehouseRepoTx := s.ProductWarehouseRepo.WithTx(tx)
|
||||||
|
|
||||||
|
chickin, err := chickinRepoTx.GetByID(c.Context(), id, nil)
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return fiber.NewError(fiber.StatusNotFound, "Chickin not found")
|
return rollback(fiber.NewError(fiber.StatusNotFound, "Chickin not found"))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Log.Errorf("Failed get chickin by id: %+v", err)
|
s.Log.Errorf("Failed get chickin by id: %+v", err)
|
||||||
return err
|
return rollback(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
population, err := s.ProjectflockPopulationRepo.GetByProjectFlockKandangID(c.Context(), chickin.ProjectFlockKandangId)
|
var population entity.ProjectFlockPopulation
|
||||||
if err != nil {
|
if err := tx.WithContext(c.Context()).Where("project_flock_kandang_id = ?", chickin.ProjectFlockKandangId).First(&population).Error; 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,
|
|
||||||
}, nil)
|
|
||||||
if err != nil {
|
|
||||||
s.Log.Errorf("Failed to update project flock population: %+v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.Repository.DeleteOne(c.Context(), id); err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return fiber.NewError(fiber.StatusNotFound, "Chickin not found")
|
return rollback(fiber.NewError(fiber.StatusNotFound, "Project flock population not found"))
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed to get project flock population: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newReserved := population.ReservedQuantity - chickin.Quantity
|
||||||
|
if newReserved < 0 {
|
||||||
|
newReserved = 0
|
||||||
|
}
|
||||||
|
if err := tx.WithContext(c.Context()).Model(&entity.ProjectFlockPopulation{}).Where("id = ?", population.Id).Updates(map[string]any{"reserved_quantity": newReserved}).Error; err != nil {
|
||||||
|
s.Log.Errorf("Failed to update project flock population: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper: restore quantities from details; returns (restored bool, error)
|
||||||
|
restoreFromDetails := func() (bool, error) {
|
||||||
|
var details []entity.ProjectChickinDetail
|
||||||
|
if err := tx.WithContext(c.Context()).Where("project_chickin_id = ?", chickin.Id).Find(&details).Error; err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if len(details) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range details {
|
||||||
|
var pw entity.ProductWarehouse
|
||||||
|
if err := tx.WithContext(c.Context()).Where("id = ?", d.ProductWarehouseId).First(&pw).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedQuantity := pw.Quantity + d.Quantity
|
||||||
|
if err := productWarehouseRepoTx.PatchOne(c.Context(), pw.Id, map[string]any{"quantity": updatedQuantity}, nil); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.WithContext(c.Context()).Where("project_chickin_id = ?", chickin.Id).Delete(&entity.ProjectChickinDetail{}).Error; err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
restored, err := restoreFromDetails()
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to restore from chickin details: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !restored {
|
||||||
|
|
||||||
|
projectflockkandang, err := pfkRepoTx.GetByID(c.Context(), population.ProjectFlockKandangId)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to get projectflock kandang: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var warehouse entity.Warehouse
|
||||||
|
if err := tx.WithContext(c.Context()).Where("kandang_id = ?", projectflockkandang.KandangId).First(&warehouse).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return rollback(fiber.NewError(fiber.StatusNotFound, "Warehouse not found for kandang"))
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed to get warehouse: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var productWarehouse entity.ProductWarehouse
|
||||||
|
err = tx.WithContext(c.Context()).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").
|
||||||
|
First(&productWarehouse).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return rollback(fiber.NewError(fiber.StatusNotFound, "Product Warehouse not found for the given Project Flock and Warehouse"))
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed to get product warehouse: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedQuantity := productWarehouse.Quantity + chickin.Quantity
|
||||||
|
if err := productWarehouseRepoTx.PatchOne(c.Context(), productWarehouse.Id, map[string]any{"quantity": updatedQuantity}, nil); err != nil {
|
||||||
|
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
|
||||||
|
return rollback(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete chickin (single place)
|
||||||
|
if err := chickinRepoTx.DeleteOne(c.Context(), id); err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return rollback(fiber.NewError(fiber.StatusNotFound, "Chickin not found"))
|
||||||
}
|
}
|
||||||
s.Log.Errorf("Failed to delete chickin: %+v", err)
|
s.Log.Errorf("Failed to delete chickin: %+v", err)
|
||||||
return err
|
return rollback(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
projectflockkandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), population.ProjectFlockKandangId)
|
if err := tx.Commit().Error; err != nil {
|
||||||
if err != nil {
|
s.Log.Errorf("Failed to commit transaction: %+v", err)
|
||||||
s.Log.Errorf("Failed to get projectflock kandang: %+v", err)
|
return rollback(err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectflockkandang.KandangId)
|
|
||||||
if err != nil {
|
|
||||||
s.Log.Errorf("Failed to get warehouse: %+v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
projectFlock, err := s.ProjectFlockRepo.GetByID(
|
|
||||||
c.Context(),
|
|
||||||
projectflockkandang.ProjectFlockId,
|
|
||||||
func(db *gorm.DB) *gorm.DB {
|
|
||||||
return db
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.Log.Errorf("Failed to get project flock: %+v", err)
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, "Project Flock not found")
|
|
||||||
}
|
|
||||||
var productWarehouse entity.ProductWarehouse
|
|
||||||
err = s.ProductWarehouseRepo.DB().WithContext(c.Context()).
|
|
||||||
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 = ?", projectFlock.Category, warehouse.Id).
|
|
||||||
Order("created_at DESC").
|
|
||||||
First(&productWarehouse).Error
|
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
s.Log.Errorf("Failed to get product warehouse: %+v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedQuantity := productWarehouse.Quantity + chickin.Quantity
|
|
||||||
err = s.ProductWarehouseRepo.PatchOne(c.Context(), productWarehouse.Id, map[string]any{
|
|
||||||
"quantity": updatedQuantity,
|
|
||||||
}, nil)
|
|
||||||
if err != nil {
|
|
||||||
s.Log.Errorf("Failed to update product warehouse quantity: %+v", err)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -244,3 +244,19 @@ func (u *ProjectflockController) GetFlockPeriodSummary(c *fiber.Ctx) error {
|
|||||||
Data: responseBody,
|
Data: responseBody,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ProjectflockController) LookupProjectFlockKandang(c *fiber.Ctx) error {
|
||||||
|
projectFlockIdStr := c.Query("project_flock_id", "")
|
||||||
|
kandangIdStr := c.Query("kandang_id", "")
|
||||||
|
|
||||||
|
result, err := u.ProjectflockService.GetProjectFlockKandangByParams(c, "", projectFlockIdStr, kandangIdStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).
|
||||||
|
JSON(response.Success{Code: fiber.StatusOK,
|
||||||
|
Status: "success",
|
||||||
|
Message: "Get projectflock kandang successfully",
|
||||||
|
Data: dto.ToProjectFlockKandangDTO(*result)})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
import (
|
||||||
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
|
areaDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto"
|
||||||
|
fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto"
|
||||||
|
flockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto"
|
||||||
|
kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
|
||||||
|
locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
|
||||||
|
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// internal DTO used only for lookup response: project flock with kandangs carrying pivot ids
|
||||||
|
type KandangWithPivotDTO struct {
|
||||||
|
kandangDTO.KandangBaseDTO
|
||||||
|
ProjectFlockKandangId *uint `json:"project_flock_kandang_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectFlockWithPivotDTO struct {
|
||||||
|
ProjectFlockBaseDTO
|
||||||
|
Flock *flockDTO.FlockBaseDTO `json:"flock,omitempty"`
|
||||||
|
Area *areaDTO.AreaBaseDTO `json:"area,omitempty"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
Fcr *fcrDTO.FcrBaseDTO `json:"fcr,omitempty"`
|
||||||
|
Location *locationDTO.LocationBaseDTO `json:"location,omitempty"`
|
||||||
|
Kandangs []KandangWithPivotDTO `json:"kandangs,omitempty"`
|
||||||
|
CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectFlockKandangDTO struct {
|
||||||
|
Id uint `json:"id"`
|
||||||
|
ProjectFlockId uint `json:"project_flock_id"`
|
||||||
|
KandangId uint `json:"kandang_id"`
|
||||||
|
Kandang *kandangDTO.KandangBaseDTO `json:"kandang,omitempty"`
|
||||||
|
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
|
||||||
|
var kandang *kandangDTO.KandangBaseDTO
|
||||||
|
if e.Kandang.Id != 0 {
|
||||||
|
mapped := kandangDTO.ToKandangBaseDTO(e.Kandang)
|
||||||
|
kandang = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
var pf *ProjectFlockWithPivotDTO
|
||||||
|
if e.ProjectFlock.Id != 0 {
|
||||||
|
// build project flock with kandangs that include pivot ids
|
||||||
|
pfLocal := ProjectFlockWithPivotDTO{
|
||||||
|
ProjectFlockBaseDTO: ProjectFlockBaseDTO{
|
||||||
|
Id: e.ProjectFlock.Id,
|
||||||
|
Period: e.ProjectFlock.Period,
|
||||||
|
},
|
||||||
|
Category: e.ProjectFlock.Category,
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill related small summaries
|
||||||
|
if e.ProjectFlock.Flock.Id != 0 {
|
||||||
|
mapped := ToFlockSummaryDTO(e.ProjectFlock.Flock)
|
||||||
|
pfLocal.Flock = &mapped
|
||||||
|
}
|
||||||
|
if e.ProjectFlock.Area.Id != 0 {
|
||||||
|
mapped := areaDTO.ToAreaBaseDTO(e.ProjectFlock.Area)
|
||||||
|
pfLocal.Area = &mapped
|
||||||
|
}
|
||||||
|
if e.ProjectFlock.Fcr.Id != 0 {
|
||||||
|
mapped := fcrDTO.ToFcrBaseDTO(e.ProjectFlock.Fcr)
|
||||||
|
pfLocal.Fcr = &mapped
|
||||||
|
}
|
||||||
|
if e.ProjectFlock.Location.Id != 0 {
|
||||||
|
mapped := locationDTO.ToLocationBaseDTO(e.ProjectFlock.Location)
|
||||||
|
pfLocal.Location = &mapped
|
||||||
|
}
|
||||||
|
if e.ProjectFlock.CreatedUser.Id != 0 {
|
||||||
|
mapped := userDTO.ToUserBaseDTO(e.ProjectFlock.CreatedUser)
|
||||||
|
pfLocal.CreatedUser = &mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
// build pivot map
|
||||||
|
pivotMap := make(map[uint]uint)
|
||||||
|
for _, ph := range e.ProjectFlock.KandangHistory {
|
||||||
|
pivotMap[ph.KandangId] = ph.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate kandangs with pivot ids
|
||||||
|
for _, k := range e.ProjectFlock.Kandangs {
|
||||||
|
kb := kandangDTO.ToKandangBaseDTO(k)
|
||||||
|
var pid *uint
|
||||||
|
if v, ok := pivotMap[k.Id]; ok {
|
||||||
|
vv := v
|
||||||
|
pid = &vv
|
||||||
|
}
|
||||||
|
pfLocal.Kandangs = append(pfLocal.Kandangs, KandangWithPivotDTO{
|
||||||
|
KandangBaseDTO: kb,
|
||||||
|
ProjectFlockKandangId: pid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pf = &pfLocal
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProjectFlockKandangDTO{
|
||||||
|
Id: e.Id,
|
||||||
|
ProjectFlockId: e.ProjectFlockId,
|
||||||
|
KandangId: e.KandangId,
|
||||||
|
Kandang: kandang,
|
||||||
|
ProjectFlock: pf,
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-1
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
type ProjectFlockKandangRepository interface {
|
type ProjectFlockKandangRepository interface {
|
||||||
GetByID(ctx context.Context, id uint) (*entity.ProjectFlockKandang, error)
|
GetByID(ctx context.Context, id uint) (*entity.ProjectFlockKandang, error)
|
||||||
|
GetByProjectFlockAndKandang(ctx context.Context, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, error)
|
||||||
CreateMany(ctx context.Context, records []*entity.ProjectFlockKandang) error
|
CreateMany(ctx context.Context, records []*entity.ProjectFlockKandang) error
|
||||||
DeleteMany(ctx context.Context, projectFlockID uint, kandangIDs []uint) error
|
DeleteMany(ctx context.Context, projectFlockID uint, kandangIDs []uint) error
|
||||||
GetAll(ctx context.Context) ([]entity.ProjectFlockKandang, error)
|
GetAll(ctx context.Context) ([]entity.ProjectFlockKandang, error)
|
||||||
@@ -45,6 +46,12 @@ func (r *projectFlockKandangRepositoryImpl) GetAll(ctx context.Context) ([]entit
|
|||||||
if err := r.db.WithContext(ctx).
|
if err := r.db.WithContext(ctx).
|
||||||
Preload("ProjectFlock").
|
Preload("ProjectFlock").
|
||||||
Preload("ProjectFlock.Flock").
|
Preload("ProjectFlock.Flock").
|
||||||
|
Preload("ProjectFlock.Fcr").
|
||||||
|
Preload("ProjectFlock.Area").
|
||||||
|
Preload("ProjectFlock.Location").
|
||||||
|
Preload("ProjectFlock.CreatedUser").
|
||||||
|
Preload("ProjectFlock.Kandangs").
|
||||||
|
Preload("ProjectFlock.KandangHistory").
|
||||||
Preload("Kandang").
|
Preload("Kandang").
|
||||||
Order("project_flock_id ASC, created_at ASC").
|
Order("project_flock_id ASC, created_at ASC").
|
||||||
Find(&records).Error; err != nil {
|
Find(&records).Error; err != nil {
|
||||||
@@ -66,10 +73,34 @@ func (r *projectFlockKandangRepositoryImpl) GetByID(ctx context.Context, id uint
|
|||||||
if err := r.db.WithContext(ctx).
|
if err := r.db.WithContext(ctx).
|
||||||
Preload("ProjectFlock").
|
Preload("ProjectFlock").
|
||||||
Preload("ProjectFlock.Flock").
|
Preload("ProjectFlock.Flock").
|
||||||
|
Preload("ProjectFlock.Fcr").
|
||||||
|
Preload("ProjectFlock.Area").
|
||||||
|
Preload("ProjectFlock.Location").
|
||||||
|
Preload("ProjectFlock.CreatedUser").
|
||||||
|
Preload("ProjectFlock.Kandangs").
|
||||||
|
Preload("ProjectFlock.KandangHistory").
|
||||||
Preload("Kandang").
|
Preload("Kandang").
|
||||||
Preload("CreatedUser").
|
|
||||||
First(record, id).Error; err != nil {
|
First(record, id).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return record, nil
|
return record, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *projectFlockKandangRepositoryImpl) GetByProjectFlockAndKandang(ctx context.Context, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, error) {
|
||||||
|
record := new(entity.ProjectFlockKandang)
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Where("project_flock_id = ? AND kandang_id = ?", projectFlockID, kandangID).
|
||||||
|
Preload("ProjectFlock").
|
||||||
|
Preload("ProjectFlock.Flock").
|
||||||
|
Preload("ProjectFlock.Fcr").
|
||||||
|
Preload("ProjectFlock.Area").
|
||||||
|
Preload("ProjectFlock.Location").
|
||||||
|
Preload("ProjectFlock.CreatedUser").
|
||||||
|
Preload("ProjectFlock.Kandangs").
|
||||||
|
Preload("ProjectFlock.KandangHistory").
|
||||||
|
Preload("Kandang").
|
||||||
|
First(record).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ func ProjectflockRoutes(v1 fiber.Router, u user.UserService, s projectflock.Proj
|
|||||||
route.Get("/:id", ctrl.GetOne)
|
route.Get("/:id", ctrl.GetOne)
|
||||||
route.Patch("/:id", ctrl.UpdateOne)
|
route.Patch("/:id", ctrl.UpdateOne)
|
||||||
route.Delete("/:id", ctrl.DeleteOne)
|
route.Delete("/:id", ctrl.DeleteOne)
|
||||||
|
route.Get("/kandangs/lookup", ctrl.LookupProjectFlockKandang)
|
||||||
route.Post("/approvals", ctrl.Approval)
|
route.Post("/approvals", ctrl.Approval)
|
||||||
route.Get("/flocks/:flock_id/periods", ctrl.GetFlockPeriodSummary)
|
route.Get("/flocks/:flock_id/periods", ctrl.GetFlockPeriodSummary)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
@@ -28,6 +29,7 @@ type ProjectflockService interface {
|
|||||||
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectFlock, error)
|
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectFlock, error)
|
||||||
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectFlock, error)
|
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectFlock, error)
|
||||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||||
|
GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, error)
|
||||||
GetFlockPeriodSummary(ctx *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error)
|
GetFlockPeriodSummary(ctx *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error)
|
||||||
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error)
|
Approval(ctx *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error)
|
||||||
}
|
}
|
||||||
@@ -639,6 +641,57 @@ func (s projectflockService) DeleteOne(c *fiber.Ctx, id uint) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s projectflockService) GetProjectFlockKandang(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandang, error) {
|
||||||
|
// keep for backward compatibility; delegate to new consolidated method
|
||||||
|
return s.GetProjectFlockKandangByParams(ctx, fmt.Sprintf("%d", id), "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s projectflockService) GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, error) {
|
||||||
|
|
||||||
|
pfk, err := s.PivotRepo.GetByProjectFlockAndKandang(ctx.Context(), projectFlockID, kandangID)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pfk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s projectflockService) GetProjectFlockKandangByParams(ctx *fiber.Ctx, idStr string, projectFlockIdStr string, kandangIdStr string) (*entity.ProjectFlockKandang, error) {
|
||||||
|
idStr = strings.TrimSpace(idStr)
|
||||||
|
projectFlockIdStr = strings.TrimSpace(projectFlockIdStr)
|
||||||
|
kandangIdStr = strings.TrimSpace(kandangIdStr)
|
||||||
|
|
||||||
|
if idStr != "" {
|
||||||
|
id, err := strconv.Atoi(idStr)
|
||||||
|
if err != nil || id <= 0 {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid Id")
|
||||||
|
}
|
||||||
|
pfk, err := s.PivotRepo.GetByID(ctx.Context(), uint(id))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "ProjectFlockKandang not found")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return pfk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if projectFlockIdStr == "" || kandangIdStr == "" {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Missing lookup parameters")
|
||||||
|
}
|
||||||
|
pfid, err := strconv.Atoi(projectFlockIdStr)
|
||||||
|
if err != nil || pfid <= 0 {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project_flock_id")
|
||||||
|
}
|
||||||
|
kid, err := strconv.Atoi(kandangIdStr)
|
||||||
|
if err != nil || kid <= 0 {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid kandang_id")
|
||||||
|
}
|
||||||
|
return s.GetProjectFlockKandangByProjectAndKandang(ctx, uint(pfid), uint(kid))
|
||||||
|
}
|
||||||
|
|
||||||
func (s projectflockService) GetFlockPeriodSummary(c *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error) {
|
func (s projectflockService) GetFlockPeriodSummary(c *fiber.Ctx, flockID uint) (*FlockPeriodSummary, error) {
|
||||||
flock, err := s.FlockRepo.GetByID(c.Context(), flockID, func(db *gorm.DB) *gorm.DB {
|
flock, err := s.FlockRepo.GetByID(c.Context(), flockID, func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Preload("CreatedUser")
|
return db.Preload("CreatedUser")
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AuditLogRepository interface {
|
|
||||||
repository.BaseRepository[entity.AuditLog]
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuditLogRepositoryImpl struct {
|
|
||||||
*repository.BaseRepositoryImpl[entity.AuditLog]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAuditLogRepository(db *gorm.DB) AuditLogRepository {
|
|
||||||
return &AuditLogRepositoryImpl{
|
|
||||||
BaseRepositoryImpl: repository.NewBaseRepository[entity.AuditLog](db),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StockAvailabilityRepository interface {
|
|
||||||
repository.BaseRepository[entity.StockAvailability]
|
|
||||||
}
|
|
||||||
|
|
||||||
type StockAvailabilityRepositoryImpl struct {
|
|
||||||
*repository.BaseRepositoryImpl[entity.StockAvailability]
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStockAvailabilityRepository(db *gorm.DB) StockAvailabilityRepository {
|
|
||||||
return &StockAvailabilityRepositoryImpl{
|
|
||||||
BaseRepositoryImpl: repository.NewBaseRepository[entity.StockAvailability](db),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user