diff --git a/internal/database/migrations/20251018120649_create_project_chick_ins_table.down.sql b/internal/database/migrations/20251018120649_create_project_chick_ins_table.down.sql new file mode 100644 index 00000000..bb8f8a2d --- /dev/null +++ b/internal/database/migrations/20251018120649_create_project_chick_ins_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS project_chickins; \ No newline at end of file diff --git a/internal/database/migrations/20251018120649_create_project_chick_ins_table.up.sql b/internal/database/migrations/20251018120649_create_project_chick_ins_table.up.sql new file mode 100644 index 00000000..25d3476d --- /dev/null +++ b/internal/database/migrations/20251018120649_create_project_chick_ins_table.up.sql @@ -0,0 +1,36 @@ +CREATE TABLE IF NOT EXISTS project_chickins ( + id BIGSERIAL PRIMARY KEY, + project_flock_kandang_id BIGINT NOT NULL, + chick_in_date DATE NOT NULL, + quantity NUMERIC(15, 3) NOT NULL, + note TEXT, + 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_flock_kandangs') THEN + ALTER TABLE project_chickins + ADD CONSTRAINT fk_project_flock_kandang_id + FOREIGN KEY (project_flock_kandang_id) + REFERENCES project_flock_kandangs(id) + ON DELETE RESTRICT ON UPDATE CASCADE; + END IF; + + IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'users') THEN + ALTER TABLE project_chickins + 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_chickins_project_flock_kandang_id ON project_chickins (project_flock_kandang_id); + +CREATE INDEX IF NOT EXISTS idx_project_chickins_created_by ON project_chickins (created_by); \ No newline at end of file diff --git a/internal/database/migrations/20251020022357_create_project_flock_populations_table.down.sql b/internal/database/migrations/20251020022357_create_project_flock_populations_table.down.sql new file mode 100644 index 00000000..8fa11576 --- /dev/null +++ b/internal/database/migrations/20251020022357_create_project_flock_populations_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS project_flock_populations; \ No newline at end of file diff --git a/internal/database/migrations/20251020022357_create_project_flock_populations_table.up.sql b/internal/database/migrations/20251020022357_create_project_flock_populations_table.up.sql new file mode 100644 index 00000000..82b3e9a7 --- /dev/null +++ b/internal/database/migrations/20251020022357_create_project_flock_populations_table.up.sql @@ -0,0 +1,36 @@ +CREATE TABLE IF NOT EXISTS project_flock_populations ( + id BIGSERIAL PRIMARY KEY, + project_flock_kandang_id BIGINT NOT NULL, + initial_quantity NUMERIC(15, 3) NOT NULL, + current_quantity NUMERIC(15, 3) NOT NULL, + reserved_quantity NUMERIC(15, 3), + 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_flock_kandangs') THEN + ALTER TABLE project_flock_populations + ADD CONSTRAINT fk_project_flock_kandang_id + FOREIGN KEY (project_flock_kandang_id) + REFERENCES project_flock_kandangs(id) + ON DELETE RESTRICT ON UPDATE CASCADE; + END IF; + + IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'users') THEN + ALTER TABLE project_flock_populations + 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_flock_populations_project_flock_kandang_id ON project_flock_populations (project_flock_kandang_id); + +CREATE INDEX IF NOT EXISTS idx_project_flock_populations_created_by ON project_flock_populations (created_by); \ No newline at end of file diff --git a/internal/database/seed/seeder.go b/internal/database/seed/seeder.go index f718cde9..e3a0b8bc 100644 --- a/internal/database/seed/seeder.go +++ b/internal/database/seed/seeder.go @@ -92,6 +92,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 + } fmt.Println("✅ Master data seeding completed") return nil @@ -975,6 +978,7 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error { {ProductID: 1, WarehouseID: 1, Quantity: 100}, {ProductID: 2, WarehouseID: 2, Quantity: 200}, {ProductID: 2, WarehouseID: 1, Quantity: 300}, + {ProductID: 1, WarehouseID: 3, Quantity: 5000}, } for _, seed := range seeds { @@ -999,8 +1003,7 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error { } func seedTransferStock(tx *gorm.DB, createdBy uint) error { - // Seeder Transfer Stock - // 1. Insert StockTransfer (header) + transfer := entity.StockTransfer{ FromWarehouseId: 1, ToWarehouseId: 2, @@ -1013,7 +1016,6 @@ func seedTransferStock(tx *gorm.DB, createdBy uint) error { return err } - // 2. Insert StockTransferDetail (detail) details := []entity.StockTransferDetail{ { StockTransferId: transfer.Id, @@ -1032,7 +1034,6 @@ func seedTransferStock(tx *gorm.DB, createdBy uint) error { } } - // 3. Insert StockTransferDelivery (delivery) deliveries := []entity.StockTransferDelivery{ { StockTransferId: transfer.Id, @@ -1076,6 +1077,75 @@ 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"}, + } + + 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 + } + + // Update/Insert ProjectFlockPopulation + 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 + } + } + } + + return nil +} + func ptr[T any](v T) *T { return &v } diff --git a/internal/entities/audit_log.go b/internal/entities/audit_log.go new file mode 100644 index 00000000..3b770125 --- /dev/null +++ b/internal/entities/audit_log.go @@ -0,0 +1,18 @@ +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"` +} diff --git a/internal/entities/project_chickin.go b/internal/entities/project_chickin.go new file mode 100644 index 00000000..95a658c8 --- /dev/null +++ b/internal/entities/project_chickin.go @@ -0,0 +1,24 @@ +package entities + +import ( + "time" + + "gorm.io/gorm" +) + +const () + +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"` + 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"` +} diff --git a/internal/entities/project_flock_population.go b/internal/entities/project_flock_population.go new file mode 100644 index 00000000..184ace65 --- /dev/null +++ b/internal/entities/project_flock_population.go @@ -0,0 +1,22 @@ +package entities + +import ( + "time" + + "gorm.io/gorm" +) + +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"` + + ProjectFlockKandang *ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` + CreatedUser *User `gorm:"foreignKey:CreatedBy;references:Id"` +} diff --git a/internal/entities/stock_availabilites.go b/internal/entities/stock_availabilites.go new file mode 100644 index 00000000..ec24d36b --- /dev/null +++ b/internal/entities/stock_availabilites.go @@ -0,0 +1,26 @@ +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"` +} diff --git a/internal/entities/stock_log.go b/internal/entities/stock_log.go index 21e86bd4..6546e790 100644 --- a/internal/entities/stock_log.go +++ b/internal/entities/stock_log.go @@ -8,6 +8,7 @@ import ( const ( LogTypeAdjustment = "ADJUSTMENT" + LogTypeTransfer = "TRANSFER" ) const ( diff --git a/internal/modules/inventory/adjustments/controllers/adjustment.controller.go b/internal/modules/inventory/adjustments/controllers/adjustment.controller.go index dc3df0a9..617a1b5f 100644 --- a/internal/modules/inventory/adjustments/controllers/adjustment.controller.go +++ b/internal/modules/inventory/adjustments/controllers/adjustment.controller.go @@ -49,8 +49,8 @@ func (u *AdjustmentController) AdjustmentHistory(c *fiber.Ctx) error { query := &validation.Query{ Page: c.QueryInt("page", 1), Limit: c.QueryInt("limit", 10), - ProductID: c.QueryInt("product_id", 0), - WarehouseID: c.QueryInt("warehouse_id", 0), + ProductID: uint(c.QueryInt("product_id", 0)), + WarehouseID: uint(c.QueryInt("warehouse_id", 0)), TransactionType: c.Query("transaction_type", ""), } diff --git a/internal/modules/inventory/adjustments/module.go b/internal/modules/inventory/adjustments/module.go index cfe01118..b3e12676 100644 --- a/internal/modules/inventory/adjustments/module.go +++ b/internal/modules/inventory/adjustments/module.go @@ -9,7 +9,7 @@ import ( rProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" rproduct "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/repositories" rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories" - rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/stock-logs/repositories" + rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories" rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" diff --git a/internal/modules/inventory/adjustments/services/adjustment.service.go b/internal/modules/inventory/adjustments/services/adjustment.service.go index 929a5c8a..7a2d06bc 100644 --- a/internal/modules/inventory/adjustments/services/adjustment.service.go +++ b/internal/modules/inventory/adjustments/services/adjustment.service.go @@ -4,12 +4,14 @@ import ( "errors" "strings" + common "gitlab.com/mbugroup/lti-api.git/internal/common/service" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/adjustments/validations" ProductWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/product-warehouses/repositories" productRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/repositories" warehouseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/repositories" - stockLogsRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/stock-logs/repositories" + stockLogsRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories" "gitlab.com/mbugroup/lti-api.git/internal/utils" "gorm.io/gorm" @@ -77,22 +79,11 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e } ctx := c.Context() - isProductExist, err := s.ProductRepo.IdExists(c.Context(), uint(req.ProductID)) - if err != nil { - s.Log.Errorf("Failed to check product existence: %+v", err) - return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product") - } - if !isProductExist { - return nil, fiber.NewError(fiber.StatusBadRequest, "Product not found") - } - - isWarehouseExist, err := s.WarehouseRepo.IdExists(c.Context(), uint(req.WarehouseID)) - if err != nil { - s.Log.Errorf("Failed to check warehouse existence: %+v", err) - return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate warehouse") - } - if !isWarehouseExist { - return nil, fiber.NewError(fiber.StatusBadRequest, "Warehouse not found") + if err := common.EnsureRelations(c.Context(), + common.RelationCheck{Name: "Product", ID: &req.ProductID, Exists: s.ProductRepo.IdExists}, + common.RelationCheck{Name: "Warehouse", ID: &req.WarehouseID, Exists: s.WarehouseRepo.IdExists}, + ); err != nil { + return nil, err } if req.Quantity <= 0 { @@ -118,6 +109,7 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e Quantity: 0, CreatedBy: 1, // TODO: should Get from auth middleware } + if err := s.ProductWarehouseRepo.CreateOne(ctx, newPW, nil); err != nil { s.Log.Errorf("Failed to create product warehouse: %+v", err) return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to create product warehouse") @@ -126,7 +118,6 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e } err = s.StockLogsRepository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error { - productWarehouse, err := s.ProductWarehouseRepo.GetProductWarehouseByProductAndWarehouseID(ctx, uint(req.ProductID), uint(req.WarehouseID)) if err != nil { s.Log.Errorf("Failed to get product warehouse: %+v", err) @@ -159,14 +150,12 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e s.Log.Errorf("Failed to create stock log: %+v", err) return err } - s.Log.Infof("Stock log created: %+v", newLog.Id) productWarehouse.Quantity = afterQuantity if err := s.ProductWarehouseRepo.WithTx(tx).UpdateOne(ctx, productWarehouse.Id, productWarehouse, nil); err != nil { s.Log.Errorf("Failed to update product warehouse quantity: %+v", err) return err } - s.Log.Infof("Product warehouse quantity updated: %+v", productWarehouse.Id) createdLogId = newLog.Id return nil @@ -184,9 +173,26 @@ func (s *adjustmentService) AdjustmentHistory(c *fiber.Ctx, query *validation.Qu if err := s.Validate.Struct(query); err != nil { return nil, 0, err } - offset := (query.Page - 1) * query.Limit + isWarehousesExist, err := s.WarehouseRepo.IdExists(c.Context(), uint(query.WarehouseID)) + if err != nil { + s.Log.Errorf("Failed to check warehouse existence: %+v", err) + return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate warehouse") + } + if query.WarehouseID > 0 && !isWarehousesExist { + return nil, 0, fiber.NewError(fiber.StatusNotFound, "Warehouse not found") + } + + isProductsExist, err := s.ProductRepo.IdExists(c.Context(), uint(query.ProductID)) + if err != nil { + s.Log.Errorf("Failed to check product existence: %+v", err) + return nil, 0, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product") + } + if query.ProductID > 0 && !isProductsExist { + return nil, 0, fiber.NewError(fiber.StatusNotFound, "Product not found") + } + stockLogs, total, err := s.StockLogsRepository.GetAll(c.Context(), offset, query.Limit, func(db *gorm.DB) *gorm.DB { db = s.withRelations(db) diff --git a/internal/modules/inventory/adjustments/validations/adjustment.validation.go b/internal/modules/inventory/adjustments/validations/adjustment.validation.go index 7d2385cc..2e7259f2 100644 --- a/internal/modules/inventory/adjustments/validations/adjustment.validation.go +++ b/internal/modules/inventory/adjustments/validations/adjustment.validation.go @@ -11,7 +11,7 @@ type Create struct { type Query struct { Page int `query:"page" validate:"omitempty,min=1"` Limit int `query:"limit" validate:"omitempty,min=1,max=100"` - ProductID int `query:"product_id" validate:"omitempty,min=0"` - WarehouseID int `query:"warehouse_id" validate:"omitempty,min=0"` + ProductID uint `query:"product_id" validate:"omitempty,min=0"` + WarehouseID uint `query:"warehouse_id" validate:"omitempty,min=0"` TransactionType string `query:"transaction_type" validate:"omitempty,oneof=increase decrease"` } diff --git a/internal/modules/inventory/product-warehouses/dto/product_warehouse.dto.go b/internal/modules/inventory/product-warehouses/dto/product_warehouse.dto.go index fdebb519..8c9f3846 100644 --- a/internal/modules/inventory/product-warehouses/dto/product_warehouse.dto.go +++ b/internal/modules/inventory/product-warehouses/dto/product_warehouse.dto.go @@ -4,7 +4,6 @@ import ( "time" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" - userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" ) // === DTO Structs === @@ -18,11 +17,16 @@ type ProductWarehouseBaseDTO struct { type ProductWarehouseListDTO struct { ProductWarehouseBaseDTO - Product *ProductBaseDTO `json:"product,omitempty"` - Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"` - CreatedUser *userDTO.UserBaseDTO `json:"created_user,omitempty"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + Product *ProductBaseDTO `json:"product,omitempty"` + Warehouse *WarehouseBaseDTO `json:"warehouse,omitempty"` + CreatedUser *UserBaseDTO `json:"created_user,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type UserBaseDTO struct { + Id uint `json:"id"` + Username string `json:"username"` } type ProductWarehouseDetailDTO struct { @@ -38,6 +42,24 @@ type ProductBaseDTO struct { } type WarehouseBaseDTO struct { + Id uint `json:"id"` + Name string `json:"name"` + Kandang *KandangBaseDTO `json:"kandang,omitempty"` + Location *LocationBaseDTO `json:"location,omitempty"` + Area *AreaBaseDTO `json:"area,omitempty"` +} + +type KandangBaseDTO struct { + Id uint `json:"id"` + Name string `json:"name"` +} + +type LocationBaseDTO struct { + Id uint `json:"id"` + Name string `json:"name"` +} + +type AreaBaseDTO struct { Id uint `json:"id"` Name string `json:"name"` } @@ -69,7 +91,6 @@ func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDT if e.Product.Sku != nil { product.Sku = *e.Product.Sku } - // Map flags from Product relation if len(e.Product.Flags) > 0 { for _, f := range e.Product.Flags { product.Flags = append(product.Flags, f.Name) @@ -84,12 +105,37 @@ func ToProductWarehouseListDTO(e entity.ProductWarehouse) ProductWarehouseListDT Id: e.Warehouse.Id, Name: e.Warehouse.Name, } + // Map Kandang jika ada + if e.Warehouse.Kandang != nil && e.Warehouse.Kandang.Id != 0 { + warehouse.Kandang = &KandangBaseDTO{ + Id: e.Warehouse.Kandang.Id, + Name: e.Warehouse.Kandang.Name, + } + } + // Map Location jika ada + if e.Warehouse.Location != nil && e.Warehouse.Location.Id != 0 { + warehouse.Location = &LocationBaseDTO{ + Id: e.Warehouse.Location.Id, + Name: e.Warehouse.Location.Name, + } + } + + if &e.Warehouse.Area != nil && e.Warehouse.Area.Id != 0 { + warehouse.Area = &AreaBaseDTO{ + Id: e.Warehouse.Area.Id, + Name: e.Warehouse.Area.Name, + } + } + dto.Warehouse = &warehouse } // Map CreatedUser relation jika ada if e.CreatedUser.Id != 0 { - user := userDTO.ToUserBaseDTO(e.CreatedUser) + user := UserBaseDTO{ + Id: e.CreatedUser.Id, + Username: e.CreatedUser.Name, + } dto.CreatedUser = &user } @@ -109,3 +155,24 @@ func ToProductWarehouseDetailDTO(e entity.ProductWarehouse) ProductWarehouseDeta ProductWarehouseListDTO: ToProductWarehouseListDTO(e), } } + +func ToKandangBaseDTO(e entity.Kandang) KandangBaseDTO { + return KandangBaseDTO{ + Id: e.Id, + Name: e.Name, + } +} + +func ToLocationBaseDTO(e entity.Location) LocationBaseDTO { + return LocationBaseDTO{ + Id: e.Id, + Name: e.Name, + } +} + +func ToAreaBaseDTO(e entity.Area) AreaBaseDTO { + return AreaBaseDTO{ + Id: e.Id, + Name: e.Name, + } +} diff --git a/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go b/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go index 9afe5707..4fad5dc5 100644 --- a/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go +++ b/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go @@ -34,7 +34,14 @@ func NewProductWarehouseService(repo repository.ProductWarehouseRepository, vali } func (s productWarehouseService) withRelations(db *gorm.DB) *gorm.DB { - return db.Preload("Product.Flags").Preload("Product").Preload("Warehouse").Preload("CreatedUser") + return db. + Preload("Product.Flags"). + Preload("Product"). + Preload("Warehouse"). + Preload("Warehouse.Location"). + Preload("Warehouse.Area"). + Preload("Warehouse.Kandang"). + Preload("CreatedUser") } func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProductWarehouse, int64, error) { diff --git a/internal/modules/inventory/transfers/dto/transfer.dto.go b/internal/modules/inventory/transfers/dto/transfer.dto.go index 217e5038..cb85af94 100644 --- a/internal/modules/inventory/transfers/dto/transfer.dto.go +++ b/internal/modules/inventory/transfers/dto/transfer.dto.go @@ -23,6 +23,11 @@ type WarehouseSimpleDTO struct { Name string `json:"name"` } +type ProductSimpleDTO struct { + Id uint `json:"id"` + Name string `json:"name"` +} + type AreaDTO struct { Id uint `json:"id"` Name string `json:"name"` @@ -33,6 +38,11 @@ type LocationDTO struct { Name string `json:"name"` } +type SupplierSimpleDTO struct { + Id uint `json:"id"` + Name string `json:"name"` +} + type WarehouseDetailDTO struct { Id uint `json:"id"` Name string `json:"name"` @@ -57,17 +67,15 @@ type TransferDetailDTO struct { // Detail produk type TransferDetailItemDTO struct { - Id uint64 `json:"id"` - ProductId uint64 `json:"product_id"` - Quantity float64 `json:"quantity"` - BeforeQuantity float64 `json:"before_quantity"` - AfterQuantity float64 `json:"after_quantity"` + Id uint64 `json:"id"` + Proudct ProductSimpleDTO `json:"product"` + Quantity float64 `json:"quantity"` } // Delivery ekspedisi type TransferDeliveryDTO struct { Id uint64 `json:"id"` - SupplierId uint64 `json:"supplier_id"` + Supplier SupplierSimpleDTO `json:"supplier"` VehiclePlate string `json:"vehicle_plate"` DriverName string `json:"driver_name"` DocumentNumber string `json:"document_number"` @@ -146,9 +154,12 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO { var details []TransferDetailItemDTO for _, d := range e.Details { details = append(details, TransferDetailItemDTO{ - Id: d.Id, - ProductId: d.ProductId, - Quantity: d.Quantity, + Id: d.Id, + Proudct: ProductSimpleDTO{ + Id: d.Product.Id, + Name: d.Product.Name, + }, + Quantity: d.Quantity, }) } // Map deliveries @@ -164,8 +175,11 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO { }) } deliveries = append(deliveries, TransferDeliveryDTO{ - Id: del.Id, - SupplierId: del.SupplierId, + Id: del.Id, + Supplier: SupplierSimpleDTO{ + Id: del.Supplier.Id, + Name: del.Supplier.Name, + }, VehiclePlate: del.VehiclePlate, DriverName: del.DriverName, DocumentNumber: del.DocumentNumber, @@ -198,17 +212,23 @@ func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO { var details []TransferDetailItemDTO for _, d := range e.Details { details = append(details, TransferDetailItemDTO{ - Id: d.Id, - ProductId: d.ProductId, - Quantity: d.Quantity, + Id: d.Id, + Proudct: ProductSimpleDTO{ + Id: d.Product.Id, + Name: d.Product.Name, + }, + Quantity: d.Quantity, }) } // Map deliveries var deliveries []TransferDeliveryDTO for _, del := range e.Deliveries { deliveries = append(deliveries, TransferDeliveryDTO{ - Id: del.Id, - SupplierId: del.SupplierId, + Id: del.Id, + Supplier: SupplierSimpleDTO{ + Id: del.Supplier.Id, + Name: del.Supplier.Name, + }, VehiclePlate: del.VehiclePlate, DriverName: del.DriverName, DocumentNumber: del.DocumentNumber, diff --git a/internal/modules/inventory/transfers/module.go b/internal/modules/inventory/transfers/module.go index 21f0ec89..734f0f03 100644 --- a/internal/modules/inventory/transfers/module.go +++ b/internal/modules/inventory/transfers/module.go @@ -9,7 +9,7 @@ import ( rStockTransfer "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/transfers/repositories" sTransfer "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/transfers/services" rSupplier "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/repositories" - rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/stock-logs/repositories" + rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories" rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" ) diff --git a/internal/modules/inventory/transfers/services/transfer.service.go b/internal/modules/inventory/transfers/services/transfer.service.go index 7f18d257..90642f6c 100644 --- a/internal/modules/inventory/transfers/services/transfer.service.go +++ b/internal/modules/inventory/transfers/services/transfer.service.go @@ -10,7 +10,7 @@ import ( rStockTransfer "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/transfers/repositories" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/inventory/transfers/validations" rSupplier "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/repositories" - rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/stock-logs/repositories" + rStockLogs "gitlab.com/mbugroup/lti-api.git/internal/modules/shared/repositories" "gitlab.com/mbugroup/lti-api.git/internal/utils" "github.com/go-playground/validator/v10" @@ -60,7 +60,9 @@ func (s transferService) withRelations(db *gorm.DB) *gorm.DB { Preload("ToWarehouse.Location"). Preload("ToWarehouse.Area"). Preload("Details"). - Preload("Deliveries.Items") + Preload("Details.Product"). + Preload("Deliveries.Items"). + Preload("Deliveries.Supplier") } func (s transferService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.StockTransfer, int64, error) { @@ -208,7 +210,7 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques SupplierId: uint64(delivery.SupplierID), VehiclePlate: delivery.VehiclePlate, DriverName: delivery.DriverName, - DocumentPath: "dummy duls", // todo: tunggu ada aws baru proses + DocumentPath: "https://tourism.gov.in/sites/default/files/2019-04/dummy-pdf_2.pdf", // todo: tunggu ada aws baru proses ShippingCostItem: delivery.DeliveryCostPerItem, ShippingCostTotal: delivery.DeliveryCost, }) diff --git a/internal/modules/master/kandangs/repositories/kandang.repository.go b/internal/modules/master/kandangs/repositories/kandang.repository.go index b253fade..bcb03854 100644 --- a/internal/modules/master/kandangs/repositories/kandang.repository.go +++ b/internal/modules/master/kandangs/repositories/kandang.repository.go @@ -15,6 +15,7 @@ type KandangRepository interface { PicExists(ctx context.Context, areaId uint) (bool, error) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) ProjectFlockExists(ctx context.Context, projectFlockID uint) (bool, error) + GetFirstByProjectFlockID(ctx context.Context, projectFlockID uint) (*entity.Kandang, error) HasActiveKandangForProjectFlock(ctx context.Context, projectFlockID uint, excludeID *uint) (bool, error) } @@ -69,3 +70,14 @@ func (r *KandangRepositoryImpl) HasActiveKandangForProjectFlock(ctx context.Cont } return count > 0, nil } + +func (r *KandangRepositoryImpl) GetFirstByProjectFlockID(ctx context.Context, projectFlockID uint) (*entity.Kandang, error) { + kandang := new(entity.Kandang) + err := r.db.WithContext(ctx). + Where("project_flock_id = ?", projectFlockID). + First(kandang).Error + if err != nil { + return nil, err + } + return kandang, nil +} diff --git a/internal/modules/master/warehouses/repositories/warehouse.repository.go b/internal/modules/master/warehouses/repositories/warehouse.repository.go index 5c791e01..956c30ef 100644 --- a/internal/modules/master/warehouses/repositories/warehouse.repository.go +++ b/internal/modules/master/warehouses/repositories/warehouse.repository.go @@ -15,6 +15,7 @@ type WarehouseRepository interface { KandangExists(ctx context.Context, kandangId uint) (bool, error) NameExists(ctx context.Context, name string, excludeID *uint) (bool, error) IdExists(ctx context.Context, id uint) (bool, error) + GetByKandangID(ctx context.Context, kandangId uint) (*entity.Warehouse, error) } type WarehouseRepositoryImpl struct { @@ -47,3 +48,15 @@ func (r *WarehouseRepositoryImpl) NameExists(ctx context.Context, name string, e func (r *WarehouseRepositoryImpl) IdExists(ctx context.Context, id uint) (bool, error) { return repository.Exists[entity.Warehouse](ctx, r.db, id) } + +func (r *WarehouseRepositoryImpl) GetByKandangID(ctx context.Context, kandangId uint) (*entity.Warehouse, error) { + var warehouse entity.Warehouse + err := r.db.WithContext(ctx). + Where("kandang_id = ?", kandangId). + Where("deleted_at IS NULL"). + First(&warehouse).Error + if err != nil { + return nil, err + } + return &warehouse, nil +} diff --git a/internal/modules/production/chickins/controllers/chickin.controller.go b/internal/modules/production/chickins/controllers/chickin.controller.go new file mode 100644 index 00000000..fadcbc3e --- /dev/null +++ b/internal/modules/production/chickins/controllers/chickin.controller.go @@ -0,0 +1,161 @@ +package controller + +import ( + "math" + "strconv" + + "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/dto" + service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/services" + validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/validations" + "gitlab.com/mbugroup/lti-api.git/internal/response" + + "github.com/gofiber/fiber/v2" +) + +type ChickinController struct { + ChickinService service.ChickinService +} + +func NewChickinController(chickinService service.ChickinService) *ChickinController { + return &ChickinController{ + ChickinService: chickinService, + } +} + +func (u *ChickinController) GetAll(c *fiber.Ctx) error { + query := &validation.Query{ + Page: c.QueryInt("page", 1), + Limit: c.QueryInt("limit", 10), + ProjectFlockKandangId: uint(c.QueryInt("project_flock_kandang_id", 0)), + } + + result, totalResults, err := u.ChickinService.GetAll(c, query) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.SuccessWithPaginate[dto.ChickinListDTO]{ + Code: fiber.StatusOK, + Status: "success", + Message: "Get all chickins successfully", + Meta: response.Meta{ + Page: query.Page, + Limit: query.Limit, + TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))), + TotalResults: totalResults, + }, + Data: dto.ToChickinListDTOs(result), + }) +} + +func (u *ChickinController) GetOne(c *fiber.Ctx) error { + param := c.Params("id") + + id, err := strconv.Atoi(param) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") + } + + result, err := u.ChickinService.GetOne(c, uint(id)) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: "Get chickin successfully", + Data: dto.ToChickinListDTO(*result), + }) +} + +func (u *ChickinController) CreateOne(c *fiber.Ctx) error { + req := new(validation.Create) + + if err := c.BodyParser(req); err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + } + + result, err := u.ChickinService.CreateOne(c, req) + if err != nil { + return err + } + + return c.Status(fiber.StatusCreated). + JSON(response.Success{ + Code: fiber.StatusCreated, + Status: "success", + Message: "Create chickin successfully", + Data: dto.ToChickinListDTO(*result), + }) +} + +func (u *ChickinController) UpdateOne(c *fiber.Ctx) error { + req := new(validation.Update) + param := c.Params("id") + + id, err := strconv.Atoi(param) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") + } + + if err := c.BodyParser(req); err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") + } + + result, err := u.ChickinService.UpdateOne(c, req, uint(id)) + if err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: "Update chickin successfully", + Data: dto.ToChickinListDTO(*result), + }) +} + +func (u *ChickinController) DeleteOne(c *fiber.Ctx) error { + param := c.Params("id") + + id, err := strconv.Atoi(param) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") + } + + if err := u.ChickinService.DeleteOne(c, uint(id)); err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Common{ + Code: fiber.StatusOK, + Status: "success", + Message: "Delete chickin successfully", + }) +} + +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") + } + + if err := u.ChickinService.Approve(c, uint(id)); err != nil { + return err + } + + return c.Status(fiber.StatusOK). + JSON(response.Success{ + Code: fiber.StatusOK, + Status: "success", + Message: "Approve chickin successfully", + Data: nil, + }) +} diff --git a/internal/modules/production/chickins/dto/chickin.dto.go b/internal/modules/production/chickins/dto/chickin.dto.go new file mode 100644 index 00000000..96115b58 --- /dev/null +++ b/internal/modules/production/chickins/dto/chickin.dto.go @@ -0,0 +1,216 @@ +package dto + +import ( + "time" + + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" + areaBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/areas/dto" + fcrBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/dto" + flockBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/dto" + kandangBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto" + locationBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto" + productCategoryBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/product-categories/dto" + userBaseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" +) + +// === DTO Structs (ordered) === + +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"` +} + +type ProjectFlockDTO struct { + Id uint `json:"id"` + Period int `json:"period"` + Flock *flockBaseDTO.FlockBaseDTO `json:"flock"` + ProductCategory *productCategoryBaseDTO.ProductCategoryBaseDTO `json:"product_category"` + Area *areaBaseDTO.AreaBaseDTO `json:"area"` + Fcr *fcrBaseDTO.FcrBaseDTO `json:"fcr"` + Location *locationBaseDTO.LocationBaseDTO `json:"location"` +} + +type ProjectFlockKandangDTO struct { + Id uint `json:"id"` + ProjectFlock *ProjectFlockDTO `json:"project_flock"` + Kandang *kandangBaseDTO.KandangBaseDTO `json:"kandang"` +} + +// gunakan base DTO dari package users + +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"` + CreatedBy uint `json:"created_by"` +} + +type ChickinListDTO struct { + ChickinBaseDTO + ProjectFlockKandang *ProjectFlockKandangDTO `json:"project_flock_kandang"` + CreatedUser *userBaseDTO.UserBaseDTO `json:"created_user"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type ChickinDetailDTO struct { + ChickinListDTO +} + +// === Mapper Functions (ordered) === + +func ToFlockDTO(e entity.Flock) flockBaseDTO.FlockBaseDTO { + return flockBaseDTO.ToFlockBaseDTO(e) +} + +func ToKandangDTO(e entity.Kandang) kandangBaseDTO.KandangBaseDTO { + return kandangBaseDTO.ToKandangBaseDTO(e) +} + +func ToProductCategoryDTO(e entity.ProductCategory) productCategoryBaseDTO.ProductCategoryBaseDTO { + return productCategoryBaseDTO.ToProductCategoryBaseDTO(e) +} + +func ToAreaDTO(e entity.Area) areaBaseDTO.AreaBaseDTO { + return areaBaseDTO.ToAreaBaseDTO(e) +} + +func ToFcrDTO(e entity.Fcr) fcrBaseDTO.FcrBaseDTO { + return fcrBaseDTO.ToFcrBaseDTO(e) +} + +func ToLocationDTO(e entity.Location) locationBaseDTO.LocationBaseDTO { + return locationBaseDTO.ToLocationBaseDTO(e) +} + +func ToUserBaseDTO(e entity.User) userBaseDTO.UserBaseDTO { + return userBaseDTO.ToUserBaseDTO(e) +} + +func ToProjectFlockDTO(e entity.ProjectFlock) ProjectFlockDTO { + var flock *flockBaseDTO.FlockBaseDTO + if e.Flock.Id != 0 { + mapped := flockBaseDTO.ToFlockBaseDTO(e.Flock) + flock = &mapped + } + var productCategory *productCategoryBaseDTO.ProductCategoryBaseDTO + if e.ProductCategory.Id != 0 { + mapped := productCategoryBaseDTO.ToProductCategoryBaseDTO(e.ProductCategory) + productCategory = &mapped + } + var area *areaBaseDTO.AreaBaseDTO + if e.Area.Id != 0 { + mapped := areaBaseDTO.ToAreaBaseDTO(e.Area) + area = &mapped + } + var fcr *fcrBaseDTO.FcrBaseDTO + if e.Fcr.Id != 0 { + mapped := fcrBaseDTO.ToFcrBaseDTO(e.Fcr) + fcr = &mapped + } + var location *locationBaseDTO.LocationBaseDTO + if e.Location.Id != 0 { + mapped := locationBaseDTO.ToLocationBaseDTO(e.Location) + location = &mapped + } + return ProjectFlockDTO{ + Id: e.Id, + Period: e.Period, + Flock: flock, + ProductCategory: productCategory, + Area: area, + Fcr: fcr, + Location: location, + } +} + +func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO { + var pf *ProjectFlockDTO + if e.ProjectFlock.Id != 0 { + mapped := ToProjectFlockDTO(e.ProjectFlock) + pf = &mapped + } + var kandang *kandangBaseDTO.KandangBaseDTO + if e.Kandang.Id != 0 { + mapped := kandangBaseDTO.ToKandangBaseDTO(e.Kandang) + kandang = &mapped + } + return ProjectFlockKandangDTO{ + Id: e.Id, + ProjectFlock: pf, + Kandang: kandang, + } +} + +func ToChickinBaseDTO(e entity.ProjectChickin) ChickinBaseDTO { + var pfk *ProjectFlockKandangDTO + if 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, + } +} + +func ToChickinSimpleDTO(e entity.ProjectChickin) ChickinSimpleDTO { + return ChickinSimpleDTO{ + Id: e.Id, + ProjectFlockKandangId: e.ProjectFlockKandangId, + ChickInDate: e.ChickInDate, + Quantity: e.Quantity, + Note: e.Note, + CreatedBy: e.CreatedBy, + } +} + +func ToChickinListDTO(e entity.ProjectChickin) ChickinListDTO { + var createdUser *userBaseDTO.UserBaseDTO + if e.CreatedUser.Id != 0 { + mapped := userBaseDTO.ToUserBaseDTO(e.CreatedUser) + createdUser = &mapped + } + var pfk *ProjectFlockKandangDTO + if e.ProjectFlockKandang.Id != 0 { + mapped := ToProjectFlockKandangDTO(e.ProjectFlockKandang) + pfk = &mapped + } + return ChickinListDTO{ + ChickinBaseDTO: ToChickinBaseDTO(e), + ProjectFlockKandang: pfk, + CreatedUser: createdUser, + CreatedAt: e.CreatedAt, + UpdatedAt: e.UpdatedAt, + } +} + +func ToChickinListDTOs(e []entity.ProjectChickin) []ChickinListDTO { + result := make([]ChickinListDTO, len(e)) + for i, r := range e { + result[i] = ToChickinListDTO(r) + } + return result +} + +func ToChickinSimpleDTOs(e []entity.ProjectChickin) []ChickinSimpleDTO { + result := make([]ChickinSimpleDTO, len(e)) + for i, r := range e { + result[i] = ToChickinSimpleDTO(r) + } + return result +} + +func ToChickinDetailDTO(e entity.ProjectChickin) ChickinDetailDTO { + return ChickinDetailDTO{ + ChickinListDTO: ToChickinListDTO(e), + } +} diff --git a/internal/modules/production/chickins/module.go b/internal/modules/production/chickins/module.go new file mode 100644 index 00000000..116e2fbb --- /dev/null +++ b/internal/modules/production/chickins/module.go @@ -0,0 +1,39 @@ +package chickins + +import ( + "github.com/go-playground/validator/v10" + "github.com/gofiber/fiber/v2" + "gorm.io/gorm" + + 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" + rChickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories" + 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" + + rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" + sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" +) + +type ChickinModule struct{} + +func (ChickinModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) { + chickinRepo := rChickin.NewChickinRepository(db) + kandangRepo := rKandang.NewKandangRepository(db) + auditlogrepo := rAuditLog.NewAuditLogRepository(db) + warehouseRepo := rWarehouse.NewWarehouseRepository(db) + projectflockkandangrepo := rProjectFlock.NewProjectFlockKandangRepository(db) + projectflockpopulationrepo := rProjectFlock.NewProjectFlockPopulationRepository(db) + projectFlockRepo := rProjectFlock.NewProjectflockRepository(db) + productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db) + + userRepo := rUser.NewUserRepository(db) + + chickinService := sChickin.NewChickinService(chickinRepo, kandangRepo, warehouseRepo, productWarehouseRepo, projectFlockRepo, auditlogrepo, projectflockkandangrepo, projectflockpopulationrepo, validate) + userService := sUser.NewUserService(userRepo, validate) + + ChickinRoutes(router, userService, chickinService) +} diff --git a/internal/modules/production/chickins/repositories/project_chickin.repository.go b/internal/modules/production/chickins/repositories/project_chickin.repository.go new file mode 100644 index 00000000..64e2e4b4 --- /dev/null +++ b/internal/modules/production/chickins/repositories/project_chickin.repository.go @@ -0,0 +1,36 @@ +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" +) + +type ProjectChickinRepository interface { + repository.BaseRepository[entity.ProjectChickin] + GetFirstByProjectFlockID(ctx context.Context, projectFlockID uint) (*entity.ProjectChickin, error) +} + +type ChickinRepositoryImpl struct { + *repository.BaseRepositoryImpl[entity.ProjectChickin] +} + +func NewChickinRepository(db *gorm.DB) ProjectChickinRepository { + return &ChickinRepositoryImpl{ + BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectChickin](db), + } +} + +func (r *ChickinRepositoryImpl) GetFirstByProjectFlockID(ctx context.Context, projectFlockID uint) (*entity.ProjectChickin, error) { + var chickin entity.ProjectChickin + err := r.DB().WithContext(ctx). + Where("project_floc_id = ?", projectFlockID). + Where("deleted_at IS NULL"). + First(&chickin).Error + if err != nil { + return nil, err + } + return &chickin, nil +} diff --git a/internal/modules/production/chickins/route.go b/internal/modules/production/chickins/route.go new file mode 100644 index 00000000..5fa5237a --- /dev/null +++ b/internal/modules/production/chickins/route.go @@ -0,0 +1,29 @@ +package chickins + +import ( + // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + controller "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/controllers" + chickin "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/services" + user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" + + "github.com/gofiber/fiber/v2" +) + +func ChickinRoutes(v1 fiber.Router, u user.UserService, s chickin.ChickinService) { + ctrl := controller.NewChickinController(s) + + route := v1.Group("/chickins") + + // route.Get("/", m.Auth(u), ctrl.GetAll) + // route.Post("/", m.Auth(u), ctrl.CreateOne) + // route.Get("/:id", m.Auth(u), ctrl.GetOne) + // route.Patch("/:id", m.Auth(u), ctrl.UpdateOne) + // route.Delete("/:id", m.Auth(u), ctrl.DeleteOne) + + route.Get("/", ctrl.GetAll) + route.Post("/", ctrl.CreateOne) + route.Get("/:id", ctrl.GetOne) + route.Patch("/:id", ctrl.UpdateOne) + route.Delete("/:id", ctrl.DeleteOne) + route.Post("/:id/approve", ctrl.Approve) +} diff --git a/internal/modules/production/chickins/services/chickin.service.go b/internal/modules/production/chickins/services/chickin.service.go new file mode 100644 index 00000000..46bc8069 --- /dev/null +++ b/internal/modules/production/chickins/services/chickin.service.go @@ -0,0 +1,371 @@ +package service + +import ( + "errors" + + 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" + rWarehouse "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/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" + 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" + + "github.com/go-playground/validator/v10" + "github.com/gofiber/fiber/v2" + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +type ChickinService interface { + GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectChickin, int64, error) + GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectChickin, error) + 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 +} + +type chickinService struct { + Log *logrus.Logger + Validate *validator.Validate + Repository repository.ProjectChickinRepository + KandangRepo KandangRepo.KandangRepository + WarehouseRepo rWarehouse.WarehouseRepository + ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository + ProjectFlockRepo rProjectFlock.ProjectflockRepository + AuditLogRepo AuditLogRepo.AuditLogRepository + ProjectflockKandangRepo rProjectFlockKandang.ProjectFlockKandangRepository + ProjectflockPopulationRepo rProjectFlock.ProjectFlockPopulationRepository +} + +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 { + return &chickinService{ + Log: utils.Log, + Validate: validate, + Repository: repo, + KandangRepo: kandangRepo, + WarehouseRepo: warehouseRepo, + ProductWarehouseRepo: productWarehouseRepo, + ProjectFlockRepo: projectFlockRepo, + AuditLogRepo: auditLogRepo, + ProjectflockKandangRepo: projectflockkandangRepo, + ProjectflockPopulationRepo: projectflockpopulationRepo, + } +} + +func (s chickinService) withRelations(db *gorm.DB) *gorm.DB { + return db. + Preload("CreatedUser"). + Preload("ProjectFlockKandang.Kandang"). + Preload("ProjectFlockKandang.Kandang.Location"). + Preload("ProjectFlockKandang.Kandang.Location.Area"). + Preload("ProjectFlockKandang.Kandang.Pic"). + Preload("ProjectFlockKandang.ProjectFlock"). + Preload("ProjectFlockKandang.ProjectFlock.Flock"). + Preload("ProjectFlockKandang.ProjectFlock.ProductCategory"). + Preload("ProjectFlockKandang.ProjectFlock.Area"). + Preload("ProjectFlockKandang.ProjectFlock.Fcr"). + Preload("ProjectFlockKandang.ProjectFlock.Location"). + Preload("ProjectFlockKandang.ProjectFlock.Location.Area") + +} + +func (s chickinService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectChickin, int64, error) { + if err := s.Validate.Struct(params); err != nil { + return nil, 0, err + } + + offset := (params.Page - 1) * params.Limit + chickins, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB { + db = s.withRelations(db) + if params.ProjectFlockKandangId != 0 { + return db.Where("project_flock_kandang_id = ?", params.ProjectFlockKandangId) + } + return db.Order("created_at DESC").Order("updated_at DESC") + }) + if err != nil { + s.Log.Errorf("Failed to get chickins: %+v", err) + return nil, 0, err + } + return chickins, total, nil +} + +func (s chickinService) GetOne(c *fiber.Ctx, id uint) (*entity.ProjectChickin, error) { + + chickin, err := s.Repository.GetByID(c.Context(), id, s.withRelations) + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fiber.NewError(fiber.StatusNotFound, "Chickin not found") + } + if err != nil { + s.Log.Errorf("Failed get chickin by id: %+v", err) + return nil, err + } + return chickin, nil +} + +func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entity.ProjectChickin, error) { + if err := s.Validate.Struct(req); err != nil { + return nil, err + } + + projectflockkandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), 1) + if err != nil { + s.Log.Errorf("Failed to get projectflock kandang: %+v", err) + return nil, err + } + + warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), projectflockkandang.KandangId) + if err != nil { + s.Log.Errorf("Failed to get warehouse: %+v", err) + return nil, err + } + + projectFlock, err := s.ProjectFlockRepo.GetByID( + c.Context(), + projectflockkandang.ProjectFlockId, + func(db *gorm.DB) *gorm.DB { + return db.Preload("ProductCategory") + }, + ) + 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 + 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.ProductCategory.Code, warehouse.Id). + Order("created_at DESC"). + Find(&productWarehouses).Error + 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") + } + + // Jumlahkan semua quantity DOC + totalQuantity := 0.0 + for _, pw := range productWarehouses { + totalQuantity += pw.Quantity + } + + if totalQuantity < 1 { + return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient quantity in Product Warehouses") + } + + // Buat satu chickin dengan total quantity + 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.ProjectFlockId, + ChickInDate: chickinDate, + Quantity: totalQuantity, + Note: "", + CreatedBy: 1, //todo: ganti dengan user login + } + err = s.Repository.CreateOne(c.Context(), newChickin, nil) + if err != nil { + s.Log.Errorf("Failed to create chickin: %+v", err) + return nil, err + } + + // 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 + } + } + + 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) +} + +func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectChickin, error) { + if err := s.Validate.Struct(req); err != nil { + return nil, err + } + + updateBody := make(map[string]any) + + if req.ChickInDate != "" { + updateBody["chick_in_date"] = req.ChickInDate + } + if len(updateBody) == 0 { + return s.GetOne(c, id) + } + + if err := s.Repository.PatchOne(c.Context(), id, updateBody, nil); err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, fiber.NewError(fiber.StatusNotFound, "Chickin not found") + } + s.Log.Errorf("Failed to update chickin: %+v", err) + return nil, err + } + + return s.GetOne(c, id) +} + +func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error { + // todo: cek apakah chickin sudah di approve atau belum + + chickin, err := s.Repository.GetByID(c.Context(), id, nil) + if errors.Is(err, gorm.ErrRecordNotFound) { + return fiber.NewError(fiber.StatusNotFound, "Chickin not found") + } + 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, + }, 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) { + return fiber.NewError(fiber.StatusNotFound, "Chickin not found") + } + s.Log.Errorf("Failed to delete chickin: %+v", err) + return err + } + + projectflockkandang, err := s.ProjectflockKandangRepo.GetByID(c.Context(), population.ProjectFlockKandangId) + if err != nil { + s.Log.Errorf("Failed to get projectflock kandang: %+v", 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.Preload("ProductCategory") + }, + ) + + 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.ProductCategory.Code, 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 +} + +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") + } + 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 +} diff --git a/internal/modules/production/chickins/validations/chickin.validation.go b/internal/modules/production/chickins/validations/chickin.validation.go new file mode 100644 index 00000000..c122c100 --- /dev/null +++ b/internal/modules/production/chickins/validations/chickin.validation.go @@ -0,0 +1,16 @@ +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"` +} + +type Update struct { + ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"` +} + +type Query struct { + Page int `query:"page" validate:"omitempty,number,min=1"` + Limit int `query:"limit" validate:"omitempty,number,min=1,max=100"` + ProjectFlockKandangId uint `query:"project_flock_kandang_id" validate:"omitempty,number,min=1"` +} diff --git a/internal/modules/production/project_flocks/module.go b/internal/modules/production/project_flocks/module.go index 5f1afbe3..5b91ab13 100644 --- a/internal/modules/production/project_flocks/module.go +++ b/internal/modules/production/project_flocks/module.go @@ -8,6 +8,7 @@ import ( rFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories" rKandang "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" rProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories" + sProjectflock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services" rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories" diff --git a/internal/modules/production/project_flocks/repositories/project_flock_population_repository.go b/internal/modules/production/project_flocks/repositories/project_flock_population_repository.go new file mode 100644 index 00000000..cb4b0d5f --- /dev/null +++ b/internal/modules/production/project_flocks/repositories/project_flock_population_repository.go @@ -0,0 +1,35 @@ +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" +) + +type ProjectFlockPopulationRepository interface { + repository.BaseRepository[entity.ProjectFlockPopulation] + GetByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (*entity.ProjectFlockPopulation, error) +} + +type projectFlockPopulationRepositoryImpl struct { + *repository.BaseRepositoryImpl[entity.ProjectFlockPopulation] +} + +func NewProjectFlockPopulationRepository(db *gorm.DB) ProjectFlockPopulationRepository { + return &projectFlockPopulationRepositoryImpl{ + BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectFlockPopulation](db), + } +} + +func (r *projectFlockPopulationRepositoryImpl) GetByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (*entity.ProjectFlockPopulation, error) { + var record entity.ProjectFlockPopulation + err := r.DB().WithContext(ctx). + Where("project_flock_kandang_id = ?", projectFlockKandangID). + First(&record).Error + if err != nil { + return nil, err + } + return &record, nil +} 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 b5ce21a4..a5ceaf7f 100644 --- a/internal/modules/production/project_flocks/repositories/projectflock_kandang.repository.go +++ b/internal/modules/production/project_flocks/repositories/projectflock_kandang.repository.go @@ -8,6 +8,7 @@ import ( ) type ProjectFlockKandangRepository interface { + GetByID(ctx context.Context, id uint) (*entity.ProjectFlockKandang, error) CreateMany(ctx context.Context, records []*entity.ProjectFlockKandang) error DeleteMany(ctx context.Context, projectFlockID uint, kandangIDs []uint) error GetAll(ctx context.Context) ([]entity.ProjectFlockKandang, error) @@ -59,3 +60,16 @@ func (r *projectFlockKandangRepositoryImpl) WithTx(tx *gorm.DB) ProjectFlockKand func (r *projectFlockKandangRepositoryImpl) DB() *gorm.DB { return r.db } + +func (r *projectFlockKandangRepositoryImpl) GetByID(ctx context.Context, id uint) (*entity.ProjectFlockKandang, error) { + record := new(entity.ProjectFlockKandang) + if err := r.db.WithContext(ctx). + Preload("ProjectFlock"). + Preload("ProjectFlock.Flock"). + Preload("Kandang"). + Preload("CreatedUser"). + First(record, id).Error; err != nil { + return nil, err + } + return record, nil +} diff --git a/internal/modules/production/route.go b/internal/modules/production/route.go index 73bbe8da..b41ef1e7 100644 --- a/internal/modules/production/route.go +++ b/internal/modules/production/route.go @@ -7,6 +7,7 @@ import ( "github.com/gofiber/fiber/v2" "gorm.io/gorm" + chickins "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins" projectflocks "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks" recordings "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings" // MODULE IMPORTS @@ -18,6 +19,7 @@ func RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Valida allModules := []modules.Module{ projectflocks.ProjectflockModule{}, recordings.RecordingModule{}, + chickins.ChickinModule{}, // MODULE REGISTRY } diff --git a/internal/modules/shared/repositories/audit-logs.repository.go b/internal/modules/shared/repositories/audit-logs.repository.go new file mode 100644 index 00000000..b247f3f2 --- /dev/null +++ b/internal/modules/shared/repositories/audit-logs.repository.go @@ -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 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), + } +} diff --git a/internal/modules/shared/repositories/stock-availabilites.repository.go b/internal/modules/shared/repositories/stock-availabilites.repository.go new file mode 100644 index 00000000..9d3ae632 --- /dev/null +++ b/internal/modules/shared/repositories/stock-availabilites.repository.go @@ -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 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), + } +} diff --git a/internal/modules/shared/stock-logs/repositories/stock-logs.repository.go b/internal/modules/shared/repositories/stock-logs.repository.go similarity index 100% rename from internal/modules/shared/stock-logs/repositories/stock-logs.repository.go rename to internal/modules/shared/repositories/stock-logs.repository.go