diff --git a/.DS_Store b/.DS_Store index 4c14efd8..e39247fd 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/internal/database/migrations/20251229125951_adjustment_standart_production_projectflock.down.sql b/internal/database/migrations/20251229125951_adjustment_standart_production_projectflock.down.sql new file mode 100644 index 00000000..7433c93d --- /dev/null +++ b/internal/database/migrations/20251229125951_adjustment_standart_production_projectflock.down.sql @@ -0,0 +1,7 @@ +DROP INDEX IF EXISTS idx_project_flocks_production_standard_id; + +ALTER TABLE project_flocks + DROP CONSTRAINT IF EXISTS fk_project_flocks_production_standard_id; + +ALTER TABLE project_flocks + DROP COLUMN IF EXISTS production_standard_id; diff --git a/internal/database/migrations/20251229125951_adjustment_standart_production_projectflock.up.sql b/internal/database/migrations/20251229125951_adjustment_standart_production_projectflock.up.sql new file mode 100644 index 00000000..f513c447 --- /dev/null +++ b/internal/database/migrations/20251229125951_adjustment_standart_production_projectflock.up.sql @@ -0,0 +1,15 @@ +-- Add production_standard_id to project_flocks +ALTER TABLE project_flocks + ADD COLUMN IF NOT EXISTS production_standard_id BIGINT; + +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'production_standards') THEN + ALTER TABLE project_flocks + ADD CONSTRAINT fk_project_flocks_production_standard_id + FOREIGN KEY (production_standard_id) REFERENCES production_standards (id) ON DELETE RESTRICT ON UPDATE CASCADE; + END IF; +END $$; + +CREATE INDEX IF NOT EXISTS idx_project_flocks_production_standard_id + ON project_flocks (production_standard_id); diff --git a/internal/database/migrations/20251230014159_alter_table_production_standards_add_fcr_column.down.sql b/internal/database/migrations/20251230014159_alter_table_production_standards_add_fcr_column.down.sql new file mode 100644 index 00000000..b686a59a --- /dev/null +++ b/internal/database/migrations/20251230014159_alter_table_production_standards_add_fcr_column.down.sql @@ -0,0 +1,3 @@ +-- Remove standard_fcr column from production_standard_details table +ALTER TABLE production_standard_details +DROP COLUMN IF EXISTS standard_fcr; diff --git a/internal/database/migrations/20251230014159_alter_table_production_standards_add_fcr_column.up.sql b/internal/database/migrations/20251230014159_alter_table_production_standards_add_fcr_column.up.sql new file mode 100644 index 00000000..560a24ac --- /dev/null +++ b/internal/database/migrations/20251230014159_alter_table_production_standards_add_fcr_column.up.sql @@ -0,0 +1,3 @@ +-- Add standard_fcr column to production_standard_details table +ALTER TABLE production_standard_details +ADD COLUMN standard_fcr NUMERIC(15, 3); diff --git a/internal/database/seed/seeder.go b/internal/database/seed/seeder.go index bb4090bb..26c3f6e8 100644 --- a/internal/database/seed/seeder.go +++ b/internal/database/seed/seeder.go @@ -891,14 +891,14 @@ func seedProductWarehouse(tx *gorm.DB, createdBy uint) error { WarehouseName string Quantity float64 }{ - {ProductName: "DOC Broiler", WarehouseName: "Gudang Priangan", Quantity: 100}, - {ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Singaparna", Quantity: 200}, - {ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Banten", Quantity: 300}, - {ProductName: "DOC Broiler", WarehouseName: "Gudang Singaparna 1", Quantity: 5000}, - {ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Singaparna 1", Quantity: 600}, - {ProductName: "Telur Pecah", WarehouseName: "Gudang Singaparna 1", Quantity: 80}, - {ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Cikaum 1", Quantity: 450}, - {ProductName: "Telur Pecah", WarehouseName: "Gudang Cikaum 1", Quantity: 60}, + {ProductName: "DOC Broiler", WarehouseName: "Gudang Priangan", Quantity: 0}, + {ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Singaparna", Quantity: 0}, + {ProductName: "281 SPECIAL STARTER", WarehouseName: "Gudang Banten", Quantity: 0}, + {ProductName: "DOC Broiler", WarehouseName: "Gudang Singaparna 1", Quantity: 0}, + {ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Singaparna 1", Quantity: 0}, + {ProductName: "Telur Pecah", WarehouseName: "Gudang Singaparna 1", Quantity: 0}, + {ProductName: "Telur Konsumsi Baik", WarehouseName: "Gudang Cikaum 1", Quantity: 0}, + {ProductName: "Telur Pecah", WarehouseName: "Gudang Cikaum 1", Quantity: 0}, } for _, seed := range seeds { @@ -962,12 +962,24 @@ func seedTransferStock(tx *gorm.DB) error { { StockTransferId: transfer.Id, ProductId: 1, - Quantity: 10, + + SourceProductWarehouseID: func() *uint64 { id := uint64(1); return &id }(), + DestProductWarehouseID: func() *uint64 { id := uint64(2); return &id }(), + UsageQty: 10, + PendingQty: 0, + TotalQty: 10, + TotalUsed: 0, }, { StockTransferId: transfer.Id, ProductId: 2, - Quantity: 5, + + SourceProductWarehouseID: func() *uint64 { id := uint64(1); return &id }(), + DestProductWarehouseID: func() *uint64 { id := uint64(2); return &id }(), + UsageQty: 5, + PendingQty: 0, + TotalQty: 5, + TotalUsed: 0, }, } for i := range details { diff --git a/internal/entities/production_standard_detail.go b/internal/entities/production_standard_detail.go index cd50a572..1a18c8b8 100644 --- a/internal/entities/production_standard_detail.go +++ b/internal/entities/production_standard_detail.go @@ -12,6 +12,7 @@ type ProductionStandardDetail struct { TargetHenHouseProduction *float64 `gorm:"type:numeric(15,3)"` TargetEggWeight *float64 `gorm:"type:numeric(15,3)"` TargetEggMass *float64 `gorm:"type:numeric(15,3)"` + StandardFCR *float64 `gorm:"type:numeric(15,3)"` CreatedAt time.Time `gorm:"type:timestamptz;not null"` UpdatedAt time.Time `gorm:"type:timestamptz;not null"` diff --git a/internal/entities/projectflock.go b/internal/entities/projectflock.go index 0a92b54b..7243c9c4 100644 --- a/internal/entities/projectflock.go +++ b/internal/entities/projectflock.go @@ -12,6 +12,7 @@ type ProjectFlock struct { AreaId uint `gorm:"not null"` Category string `gorm:"type:varchar(20);not null"` FcrId uint `gorm:"not null"` + ProductionStandardId uint `gorm:"column:production_standard_id"` LocationId uint `gorm:"not null"` CreatedBy uint `gorm:"not null"` CreatedAt time.Time `gorm:"autoCreateTime"` @@ -20,6 +21,7 @@ type ProjectFlock struct { Area Area `gorm:"foreignKey:AreaId;references:Id"` Fcr Fcr `gorm:"foreignKey:FcrId;references:Id"` + ProductionStandard ProductionStandard `gorm:"foreignKey:ProductionStandardId;references:Id"` Location Location `gorm:"foreignKey:LocationId;references:Id"` CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` Kandangs []Kandang `gorm:"many2many:project_flock_kandangs;joinTableForeignKey:project_flock_id;joinTableReferences:kandang_id" json:"kandangs,omitempty"` diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index a08d431b..a831c25b 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -104,12 +104,11 @@ func AuthenticatedUser(c *fiber.Ctx) (*entity.User, bool) { } func ActorIDFromContext(c *fiber.Ctx) (uint, error) { - // user, ok := AuthenticatedUser(c) - // if !ok || user == nil || user.Id == 0 { - // return 0, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate") - // } - // return user.Id, nil - return 1, nil + user, ok := AuthenticatedUser(c) + if !ok || user == nil || user.Id == 0 { + return 0, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate") + } + return user.Id, nil } // AuthDetails returns the full authentication context (token, claims, user). diff --git a/internal/middleware/permissions.go b/internal/middleware/permissions.go index 7a21262c..f0056149 100644 --- a/internal/middleware/permissions.go +++ b/internal/middleware/permissions.go @@ -162,8 +162,32 @@ const ( P_WarehousesCreateOne = "lti.master.warehouses.create" P_WarehousesUpdateOne = "lti.master.warehouses.update" P_WarehousesDeleteOne = "lti.master.warehouses.delete" + + P_Production_Standart_GetAll = "lti.master.production_standards.list" + P_Production_Standart_CreateOne = "lti.master.production_standards.create" + P_Production_Standart_GetOne = "lti.master.production_standards.detail" + P_Production_Standart_UpdateOne = "lti.master.production_standards.update" + P_Production_Standart_DeleteOne = "lti.master.production_standards.delete" ) +// finance +const ( + P_Finances_Initial_Balances_CreateOne = "lti.finance.initial_balances.create" + P_Finances_Initial_Balances_GetOne = "lti.finance.initial_balances.detail" + P_Finances_Initial_Balances_UpdateOne = "lti.finance.initial_balances.update" + + P_Finances_Injections_CreateOne = "lti.finance.injections.create" + P_Finances_Injections_GetOne = "lti.finance.injections.detail" + P_Finances_Injections_UpdateOne = "lti.finance.injections.update" + + P_Finances_Payments_CreateOne = "lti.finance.payments.create" + P_Finances_Payments_UpdateOne = "lti.finance.payments.update" + P_Finances_Payments_GetOne = "lti.finance.payments.detail" + + P_Finances_Transaction_GetAll = "lti.finance.transactions.list" + P_Finances_Transaction_GetOne = "lti.finance.transactions.detail" + P_Finances_Transaction_DeleteOne = "lti.finance.transactions.delete" +) const ( P_ChickinsCreateOne = "lti.production.chickins.create" P_ChickinsGetOne = "lti.production.chickins.detail" diff --git a/internal/modules/closings/dto/closing.dto.go b/internal/modules/closings/dto/closing.dto.go index c05bd741..ac172c83 100644 --- a/internal/modules/closings/dto/closing.dto.go +++ b/internal/modules/closings/dto/closing.dto.go @@ -28,18 +28,19 @@ type ClosingDetailDTO struct { } type ClosingListItemDTO struct { - Id uint `json:"id"` - LocationID uint `json:"location_id"` - LocationName string `json:"location_name"` - ProjectCategory string `json:"project_category"` - Period int `json:"period"` - ClosingDate string `json:"closing_date"` - ShedLabel string `json:"shed_label"` - ShedCount int `json:"shed_count"` - SalesPaidAmount int64 `json:"sales_paid_amount"` - SalesRemainingAmount int64 `json:"sales_remaining_amount"` - SalesPaymentStatus string `json:"sales_payment_status"` - ProjectStatus string `json:"project_status"` + Id uint `json:"id"` + ProjectName string `json:"project_name"` + LocationID uint `json:"location_id"` + LocationName string `json:"location_name"` + ProjectCategory string `json:"project_category"` + Period int `json:"period"` + ClosingDate string `json:"closing_date"` + ShedLabel string `json:"shed_label"` + ShedCount int `json:"shed_count"` + // SalesPaidAmount int64 `json:"sales_paid_amount"` + // SalesRemainingAmount int64 `json:"sales_remaining_amount"` + // SalesPaymentStatus string `json:"sales_payment_status"` + ProjectStatus string `json:"project_status"` } type ClosingSummaryDTO struct { @@ -133,18 +134,19 @@ func ToClosingListItemDTO(project entity.ProjectFlock, projectStatus string) Clo shedCount := len(project.KandangHistory) return ClosingListItemDTO{ - Id: project.Id, - LocationID: project.LocationId, - LocationName: project.Location.Name, - ProjectCategory: project.Category, - Period: maxPeriod(project.KandangHistory), - ClosingDate: "17-Nov-2025", - ShedLabel: fmt.Sprintf("%d Kandang", shedCount), - ShedCount: shedCount, - SalesPaidAmount: 21993726, - SalesRemainingAmount: 11075919, - SalesPaymentStatus: "Lunas", - ProjectStatus: projectStatus, + Id: project.Id, + ProjectName: project.FlockName, + LocationID: project.LocationId, + LocationName: project.Location.Name, + ProjectCategory: project.Category, + Period: maxPeriod(project.KandangHistory), + ClosingDate: "17-Nov-2025", + ShedLabel: fmt.Sprintf("%d Kandang", shedCount), + ShedCount: shedCount, + // SalesPaidAmount: 21993726, + // SalesRemainingAmount: 11075919, + // SalesPaymentStatus: "Lunas", + ProjectStatus: projectStatus, } } diff --git a/internal/modules/closings/repositories/closing.repository.go b/internal/modules/closings/repositories/closing.repository.go index e3f09dda..912f2f25 100644 --- a/internal/modules/closings/repositories/closing.repository.go +++ b/internal/modules/closings/repositories/closing.repository.go @@ -330,13 +330,33 @@ SELECT COALESCE(p.po_number, '') AS reference_number, 'Purchase' AS transaction_type, prod.name AS product_name, - pc.name AS product_category, COALESCE(( - SELECT string_agg(f.name, ' ') + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_category, + COALESCE(( + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) FROM flags f WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id ), '') AS product_sub_category, - 'External Supplier' AS source_warehouse, + '-' AS source_warehouse, w.name AS destination_warehouse, '' AS destination, pi.total_qty AS quantity, @@ -345,7 +365,6 @@ SELECT FROM purchase_items pi JOIN purchases p ON p.id = pi.purchase_id JOIN products prod ON prod.id = pi.product_id -JOIN product_categories pc ON pc.id = prod.product_category_id JOIN uoms u ON u.id = prod.uom_id JOIN warehouses w ON w.id = pi.warehouse_id WHERE pi.warehouse_id IN ? @@ -359,9 +378,29 @@ SELECT st.movement_number AS reference_number, 'Internal Transfer In' AS transaction_type, prod.name AS product_name, - pc.name AS product_category, COALESCE(( - SELECT string_agg(f.name, ' ') + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_category, + COALESCE(( + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) FROM flags f WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id ), '') AS product_sub_category, @@ -376,7 +415,6 @@ JOIN stock_transfers st ON st.id = std.stock_transfer_id LEFT JOIN warehouses fw ON fw.id = st.from_warehouse_id LEFT JOIN warehouses tw ON tw.id = st.to_warehouse_id JOIN products prod ON prod.id = std.product_id -JOIN product_categories pc ON pc.id = prod.product_category_id JOIN uoms u ON u.id = prod.uom_id WHERE st.to_warehouse_id IN ? ` @@ -389,9 +427,29 @@ SELECT st.movement_number AS reference_number, 'Internal Transfer Out' AS transaction_type, prod.name AS product_name, - pc.name AS product_category, COALESCE(( - SELECT string_agg(f.name, ' ') + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_category, + COALESCE(( + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) FROM flags f WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id ), '') AS product_sub_category, @@ -406,7 +464,6 @@ JOIN stock_transfers st ON st.id = std.stock_transfer_id LEFT JOIN warehouses fw ON fw.id = st.from_warehouse_id LEFT JOIN warehouses tw ON tw.id = st.to_warehouse_id JOIN products prod ON prod.id = std.product_id -JOIN product_categories pc ON pc.id = prod.product_category_id JOIN uoms u ON u.id = prod.uom_id WHERE st.from_warehouse_id IN ? ` @@ -419,9 +476,29 @@ SELECT m.so_number AS reference_number, 'Trading Sales' AS transaction_type, prod.name AS product_name, - pc.name AS product_category, COALESCE(( - SELECT string_agg(f.name, ' ') + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) + FROM flags f + WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id + ), '') AS product_category, + COALESCE(( + SELECT string_agg( + f.name, + ' ' ORDER BY + CASE + WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0 + ELSE 1 + END, + f.name + ) FROM flags f WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id ), '') AS product_sub_category, @@ -435,7 +512,6 @@ FROM marketing_products mp JOIN marketings m ON m.id = mp.marketing_id JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id JOIN products prod ON prod.id = pw.product_id -JOIN product_categories pc ON pc.id = prod.product_category_id JOIN uoms u ON u.id = prod.uom_id JOIN warehouses w ON w.id = pw.warehouse_id WHERE pw.project_flock_kandang_id IN ? @@ -808,12 +884,12 @@ func (r *ClosingRepositoryImpl) FetchSapronakTransfers(ctx context.Context, kand } type ActualUsageCostRow struct { - ProductID uint `gorm:"column:product_id"` - ProductName string `gorm:"column:product_name"` - FlagName string `gorm:"column:flag_name"` - TotalQty float64 `gorm:"column:total_qty"` - TotalPrice float64 `gorm:"column:total_price"` - AveragePrice float64 `gorm:"column:average_price"` + ProductID uint `gorm:"column:product_id"` + ProductName string `gorm:"column:product_name"` + FlagName string `gorm:"column:flag_name"` + TotalQty float64 `gorm:"column:total_qty"` + TotalPrice float64 `gorm:"column:total_price"` + AveragePrice float64 `gorm:"column:average_price"` } func (r *ClosingRepositoryImpl) GetActualUsageCostByProjectFlockID(ctx context.Context, projectFlockID uint) ([]ActualUsageCostRow, error) { diff --git a/internal/modules/closings/services/closing.service.go b/internal/modules/closings/services/closing.service.go index 9f643a78..47e30a7f 100644 --- a/internal/modules/closings/services/closing.service.go +++ b/internal/modules/closings/services/closing.service.go @@ -6,6 +6,7 @@ import ( "math" "strconv" "strings" + "time" commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" @@ -332,18 +333,20 @@ func (s closingService) getApprovalStatuses(ctx context.Context, projectFlockID } var ( - minStep uint16 - statusProject string - completed int + minStep uint16 + statusProject string + completed int + latestActionAt time.Time ) for _, rec := range records { if minStep == 0 || rec.StepNumber < minStep { minStep = rec.StepNumber - statusProject = rec.StepName } - if rec.StepNumber == uint16(utils.ProjectFlockStepAktif) { - completed++ + + if latestActionAt.IsZero() || rec.ActionAt.After(latestActionAt) { + latestActionAt = rec.ActionAt + statusProject = rec.StepName } } diff --git a/internal/modules/finance/initials/route.go b/internal/modules/finance/initials/route.go index 21232493..b216fd23 100644 --- a/internal/modules/finance/initials/route.go +++ b/internal/modules/finance/initials/route.go @@ -1,7 +1,7 @@ package initials import ( - // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + m "gitlab.com/mbugroup/lti-api.git/internal/middleware" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/initials/controllers" initial "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/initials/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -13,9 +13,9 @@ func InitialRoutes(v1 fiber.Router, u user.UserService, s initial.InitialService ctrl := controller.NewInitialController(s) route := v1.Group("/initial-balances") - // route.Use(m.Auth(u)) + route.Use(m.Auth(u)) - route.Post("/", ctrl.CreateOne) - route.Get("/:id", ctrl.GetOne) - route.Patch("/:id", ctrl.UpdateOne) + route.Post("/",m.RequirePermissions(m.P_Finances_Initial_Balances_CreateOne), ctrl.CreateOne) + route.Get("/:id",m.RequirePermissions(m.P_Finances_Initial_Balances_GetOne), ctrl.GetOne) + route.Patch("/:id",m.RequirePermissions(m.P_Finances_Initial_Balances_UpdateOne), ctrl.UpdateOne) } diff --git a/internal/modules/finance/injections/route.go b/internal/modules/finance/injections/route.go index cb66ccb7..25d1047f 100644 --- a/internal/modules/finance/injections/route.go +++ b/internal/modules/finance/injections/route.go @@ -1,7 +1,7 @@ package injections import ( - // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + m "gitlab.com/mbugroup/lti-api.git/internal/middleware" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/injections/controllers" injection "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/injections/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -13,9 +13,9 @@ func InjectionRoutes(v1 fiber.Router, u user.UserService, s injection.InjectionS ctrl := controller.NewInjectionController(s) route := v1.Group("/injections") - // route.Use(m.Auth(u)) + route.Use(m.Auth(u)) - route.Post("/", ctrl.CreateOne) - route.Get("/:id", ctrl.GetOne) - route.Patch("/:id", ctrl.UpdateOne) + route.Post("/", m.RequirePermissions(m.P_Finances_Injections_CreateOne), ctrl.CreateOne) + route.Get("/:id", m.RequirePermissions(m.P_Finances_Injections_GetOne), ctrl.GetOne) + route.Patch("/:id", m.RequirePermissions(m.P_Finances_Injections_UpdateOne), ctrl.UpdateOne) } diff --git a/internal/modules/finance/payments/route.go b/internal/modules/finance/payments/route.go index 4b0e8bd2..c5147fc0 100644 --- a/internal/modules/finance/payments/route.go +++ b/internal/modules/finance/payments/route.go @@ -1,7 +1,7 @@ package payments import ( - // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + m "gitlab.com/mbugroup/lti-api.git/internal/middleware" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/payments/controllers" payment "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/payments/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -13,9 +13,9 @@ func PaymentRoutes(v1 fiber.Router, u user.UserService, s payment.PaymentService ctrl := controller.NewPaymentController(s) route := v1.Group("/payments") - // route.Use(m.Auth(u)) + route.Use(m.Auth(u)) - route.Post("/", ctrl.CreateOne) - route.Get("/:id", ctrl.GetOne) - route.Patch("/:id", ctrl.UpdateOne) + route.Post("/",m.RequirePermissions(m.P_Finances_Payments_CreateOne), ctrl.CreateOne) + route.Get("/:id",m.RequirePermissions(m.P_Finances_Payments_GetOne), ctrl.GetOne) + route.Patch("/:id",m.RequirePermissions(m.P_Finances_Payments_UpdateOne), ctrl.UpdateOne) } diff --git a/internal/modules/finance/transactions/route.go b/internal/modules/finance/transactions/route.go index d21f5441..17baa9e8 100644 --- a/internal/modules/finance/transactions/route.go +++ b/internal/modules/finance/transactions/route.go @@ -1,7 +1,7 @@ package transactions import ( - // m "gitlab.com/mbugroup/lti-api.git/internal/middleware" + m "gitlab.com/mbugroup/lti-api.git/internal/middleware" controller "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/transactions/controllers" transaction "gitlab.com/mbugroup/lti-api.git/internal/modules/finance/transactions/services" user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services" @@ -13,9 +13,9 @@ func TransactionRoutes(v1 fiber.Router, u user.UserService, s transaction.Transa ctrl := controller.NewTransactionController(s) route := v1.Group("/transactions") - // route.Use(m.Auth(u)) + route.Use(m.Auth(u)) - route.Get("/", ctrl.GetAll) - route.Get("/:id", ctrl.GetOne) - route.Delete("/:id", ctrl.DeleteOne) + route.Get("/",m.RequirePermissions(m.P_Finances_Transaction_GetAll), ctrl.GetAll) + route.Get("/:id",m.RequirePermissions(m.P_Finances_Transaction_GetOne), ctrl.GetOne) + route.Delete("/:id",m.RequirePermissions(m.P_Finances_Transaction_DeleteOne), ctrl.DeleteOne) } diff --git a/internal/modules/inventory/adjustments/services/adjustment.service.go b/internal/modules/inventory/adjustments/services/adjustment.service.go index d7b1641b..edf5f72b 100644 --- a/internal/modules/inventory/adjustments/services/adjustment.service.go +++ b/internal/modules/inventory/adjustments/services/adjustment.service.go @@ -117,39 +117,37 @@ func (s *adjustmentService) Adjustment(c *fiber.Ctx, req *validation.Create) (*e var createdLogId uint - isProductWarehouseExist, err := s.ProductWarehouseRepo.ProductWarehouseExistByProductAndWarehouseID(ctx, uint(req.ProductID), uint(req.WarehouseID)) - if err != nil { - s.Log.Errorf("Failed to check product warehouse existence: %+v", err) - return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product warehouse") + var projectFlockKandangID *uint + pfk, err := s.ProjectFlockKandangRepo.GetActiveByKandangID(ctx, uint(req.WarehouseID)) + if err == nil && pfk != nil { + idCopy := uint(pfk.Id) + projectFlockKandangID = &idCopy } - if !isProductWarehouseExist { - projectFlockKandangID, err := s.getActiveProjectFlockKandangID(ctx, uint(req.WarehouseID)) - if err != nil { - return nil, err + + pw, err := s.ProductWarehouseRepo.FindByProductWarehouseAndPfk( + ctx, + uint(req.ProductID), + uint(req.WarehouseID), + projectFlockKandangID, + ) + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + s.Log.Errorf("Failed to find product warehouse: %+v", err) + return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get product warehouse") } + newPW := &entity.ProductWarehouse{ ProductId: uint(req.ProductID), WarehouseId: uint(req.WarehouseID), Quantity: 0, - ProjectFlockKandangId: &projectFlockKandangID, - // CreatedBy: 1, // TODO: should Get from auth middleware + ProjectFlockKandangId: projectFlockKandangID, } 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") } - s.Log.Infof("Product warehouse created: %+v", newPW.Id) - } - - pw, err := s.ProductWarehouseRepo.GetProductWarehouseByProductAndWarehouseID( - ctx, - uint(req.ProductID), - uint(req.WarehouseID), - ) - if err != nil { - s.Log.Errorf("Failed to get product warehouse for project flock check: %+v", err) - return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate product warehouse") + pw = newPW } if err := common.EnsureProjectFlockNotClosedForProductWarehouses( diff --git a/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go b/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go index e759138e..92330f26 100644 --- a/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go +++ b/internal/modules/inventory/product-warehouses/repositories/product_warehouse.repository.go @@ -18,6 +18,7 @@ type ProductWarehouseRepository interface { ProductWarehouseExistByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (bool, error) ExistsByID(ctx context.Context, id uint) (bool, error) GetProductWarehouseByProductAndWarehouseID(ctx context.Context, productId, warehouseId uint) (*entity.ProductWarehouse, error) + FindByProductWarehouseAndPfk(ctx context.Context, productID uint, warehouseID uint, projectFlockKandangID *uint) (*entity.ProductWarehouse, error) GetByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint) ([]entity.ProductWarehouse, error) GetLatestByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint, db *gorm.DB) (*entity.ProductWarehouse, error) GetByFlagAndWarehouseID(ctx context.Context, flagName string, warehouseId uint) ([]entity.ProductWarehouse, error) @@ -107,6 +108,20 @@ func (r *ProductWarehouseRepositoryImpl) GetProductWarehouseByProductAndWarehous return &productWarehouse, nil } +func (r *ProductWarehouseRepositoryImpl) FindByProductWarehouseAndPfk(ctx context.Context, productID uint, warehouseID uint, projectFlockKandangID *uint) (*entity.ProductWarehouse, error) { + var productWarehouse entity.ProductWarehouse + + err := r.DB().WithContext(ctx). + Where("product_id = ? AND warehouse_id = ? AND project_flock_kandang_id IS NOT DISTINCT FROM ?", productID, warehouseID, projectFlockKandangID). + First(&productWarehouse).Error + + if err != nil { + return nil, err + } + + return &productWarehouse, nil +} + func (r *ProductWarehouseRepositoryImpl) GetByCategoryCodeAndWarehouseID(ctx context.Context, categoryCode string, warehouseId uint) ([]entity.ProductWarehouse, error) { var productWarehouses []entity.ProductWarehouse q := r.DB().WithContext(ctx).Model(&entity.ProductWarehouse{}). diff --git a/internal/modules/inventory/transfers/services/transfer.service.go b/internal/modules/inventory/transfers/services/transfer.service.go index 8ae019a4..1ca35a71 100644 --- a/internal/modules/inventory/transfers/services/transfer.service.go +++ b/internal/modules/inventory/transfers/services/transfer.service.go @@ -106,23 +106,17 @@ func (s transferService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entit } func (s transferService) GetOne(c *fiber.Ctx, id uint) (*entity.StockTransfer, error) { - s.Log.Infof("Attempting to get StockTransfer with ID: %d", id) transferPtr, err := s.StockTransferRepo.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB { return s.withRelations(db) }) if err != nil { - s.Log.Errorf("Error getting StockTransfer ID %d: %+v", id, err) if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fiber.NewError(fiber.StatusNotFound, "Transfer not found") } return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get transfer") } - if transferPtr != nil { - s.Log.Infof("StockTransfer %d has %d documents", transferPtr.Id, len(transferPtr.Documents)) - } - return transferPtr, nil } @@ -336,7 +330,9 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques Files: documentFiles, }) if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to upload document for delivery %d", idx+1)) + s.Log.WithError(err).Errorf("Failed to upload document for delivery %d (delivery_id: %d, filename: %s)", + idx+1, deliveries[idx].Id, file.Filename) + return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to upload document for delivery %d: %v", idx+1, err)) } } } @@ -396,7 +392,6 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques }) if err != nil { - s.Log.Errorf("Transaction failed in CreateOne: %+v", err) return nil, fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to process transfer transaction: %v", err)) } diff --git a/internal/modules/marketing/services/deliveryorder.service.go b/internal/modules/marketing/services/deliveryorder.service.go index e864a778..a1f4e1dd 100644 --- a/internal/modules/marketing/services/deliveryorder.service.go +++ b/internal/modules/marketing/services/deliveryorder.service.go @@ -247,11 +247,15 @@ func (s *deliveryOrdersService) CreateOne(c *fiber.Ctx, req *validation.Delivery itemDeliveryDate = &parsedDate } + // Hitung total_weight dan total_price otomatis + totalWeight := requestedProduct.Qty * requestedProduct.AvgWeight + totalPrice := requestedProduct.UnitPrice * requestedProduct.Qty + deliveryProduct.ProductWarehouseId = foundMarketingProduct.ProductWarehouseId deliveryProduct.UnitPrice = requestedProduct.UnitPrice deliveryProduct.AvgWeight = requestedProduct.AvgWeight - deliveryProduct.TotalWeight = requestedProduct.TotalWeight - deliveryProduct.TotalPrice = requestedProduct.TotalPrice + deliveryProduct.TotalWeight = totalWeight + deliveryProduct.TotalPrice = totalPrice deliveryProduct.DeliveryDate = itemDeliveryDate deliveryProduct.VehicleNumber = requestedProduct.VehicleNumber @@ -357,11 +361,15 @@ func (s deliveryOrdersService) UpdateOne(c *fiber.Ctx, req *validation.DeliveryO oldRequestedQty := deliveryProduct.UsageQty + deliveryProduct.PendingQty + // Hitung total_weight dan total_price otomatis + totalWeight := requestedProduct.Qty * requestedProduct.AvgWeight + totalPrice := requestedProduct.UnitPrice * requestedProduct.Qty + deliveryProduct.ProductWarehouseId = foundMarketingProduct.ProductWarehouseId deliveryProduct.UnitPrice = requestedProduct.UnitPrice deliveryProduct.AvgWeight = requestedProduct.AvgWeight - deliveryProduct.TotalWeight = requestedProduct.TotalWeight - deliveryProduct.TotalPrice = requestedProduct.TotalPrice + deliveryProduct.TotalWeight = totalWeight + deliveryProduct.TotalPrice = totalPrice deliveryProduct.DeliveryDate = itemDeliveryDate deliveryProduct.VehicleNumber = requestedProduct.VehicleNumber diff --git a/internal/modules/marketing/services/salesorder.service.go b/internal/modules/marketing/services/salesorder.service.go index dc6e62de..d57b323e 100644 --- a/internal/modules/marketing/services/salesorder.service.go +++ b/internal/modules/marketing/services/salesorder.service.go @@ -75,7 +75,6 @@ func (s salesOrdersService) getOne(c *fiber.Ctx, id uint) (*entity.Marketing, er return nil, fiber.NewError(fiber.StatusNotFound, "SalesOrders not found") } if err != nil { - s.Log.Errorf("Failed get marketing by id: %+v", err) return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch sales order") } @@ -293,13 +292,17 @@ func (s salesOrdersService) UpdateOne(c *fiber.Ctx, req *validation.Update, id u for _, rp := range req.MarketingProducts { if old, ok := oldByPW[rp.ProductWarehouseId]; ok { + // Hitung total_weight dan total_price otomatis + totalWeight := rp.Qty * rp.AvgWeight + totalPrice := rp.UnitPrice * rp.Qty + updateBody := map[string]any{ "product_warehouse_id": rp.ProductWarehouseId, "qty": rp.Qty, "unit_price": rp.UnitPrice, "avg_weight": rp.AvgWeight, - "total_weight": rp.TotalWeight, - "total_price": rp.TotalPrice, + "total_weight": totalWeight, + "total_price": totalPrice, } if err := marketingProductRepoTx.PatchOne(c.Context(), old.Id, updateBody, nil); err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Failed to update marketing product") @@ -589,30 +592,34 @@ func (s salesOrdersService) Approval(c *fiber.Ctx, req *validation.Approve) ([]e func (s *salesOrdersService) createMarketingProductWithDelivery(ctx context.Context, marketingId uint, rp validation.CreateMarketingProduct, marketingProductRepo repository.MarketingProductRepository, invDeliveryRepo repository.MarketingDeliveryProductRepository) error { + // Hitung total_weight dan total_price otomatis + totalWeight := rp.Qty * rp.AvgWeight + totalPrice := rp.UnitPrice * rp.Qty + marketingProduct := &entity.MarketingProduct{ MarketingId: marketingId, ProductWarehouseId: rp.ProductWarehouseId, Qty: rp.Qty, UnitPrice: rp.UnitPrice, AvgWeight: rp.AvgWeight, - TotalWeight: rp.TotalWeight, - TotalPrice: rp.TotalPrice, + TotalWeight: totalWeight, + TotalPrice: totalPrice, } if err := marketingProductRepo.CreateOne(ctx, marketingProduct, nil); err != nil { return err } marketingDeliveryProduct := &entity.MarketingDeliveryProduct{ - MarketingProductId: marketingProduct.Id, - ProductWarehouseId: marketingProduct.ProductWarehouseId, - UnitPrice: 0, - TotalWeight: 0, - AvgWeight: 0, - TotalPrice: 0, - DeliveryDate: nil, - VehicleNumber: rp.VehicleNumber, - UsageQty: 0, - PendingQty: 0, + MarketingProductId: marketingProduct.Id, + ProductWarehouseId: marketingProduct.ProductWarehouseId, + UnitPrice: 0, + TotalWeight: 0, + AvgWeight: 0, + TotalPrice: 0, + DeliveryDate: nil, + VehicleNumber: rp.VehicleNumber, + UsageQty: 0, + PendingQty: 0, } if err := invDeliveryRepo.CreateOne(ctx, marketingDeliveryProduct, nil); err != nil { return err diff --git a/internal/modules/marketing/validations/deliveryorder.validation.go b/internal/modules/marketing/validations/deliveryorder.validation.go index 7db2cdd1..a879db6f 100644 --- a/internal/modules/marketing/validations/deliveryorder.validation.go +++ b/internal/modules/marketing/validations/deliveryorder.validation.go @@ -5,8 +5,6 @@ type DeliveryProduct struct { Qty float64 `json:"qty" validate:"omitempty,gte=0"` UnitPrice float64 `json:"unit_price" validate:"omitempty,gte=0"` AvgWeight float64 `json:"avg_weight" validate:"omitempty,gte=0"` - TotalWeight float64 `json:"total_weight" validate:"omitempty,gte=0"` - TotalPrice float64 `json:"total_price" validate:"omitempty,gte=0"` DeliveryDate string `json:"delivery_date" validate:"omitempty,datetime=2006-01-02"` VehicleNumber string `json:"vehicle_number" validate:"omitempty,max=50"` } diff --git a/internal/modules/marketing/validations/salesorder.validation.go b/internal/modules/marketing/validations/salesorder.validation.go index 47d2e616..b69da394 100644 --- a/internal/modules/marketing/validations/salesorder.validation.go +++ b/internal/modules/marketing/validations/salesorder.validation.go @@ -12,10 +12,8 @@ type CreateMarketingProduct struct { VehicleNumber string `json:"vehicle_number" validate:"required,min=1,max=50"` ProductWarehouseId uint `json:"product_warehouse_id" validate:"required,gt=0"` UnitPrice float64 `json:"unit_price" validate:"required,gt=0"` - TotalWeight float64 `json:"total_weight" validate:"required,gt=0"` Qty float64 `json:"qty" validate:"required,gt=0"` AvgWeight float64 `json:"avg_weight" validate:"required,gt=0"` - TotalPrice float64 `json:"total_price" validate:"required,gt=0"` } type Update struct { diff --git a/internal/modules/master/production-standards/controllers/production-standard.controller.go b/internal/modules/master/production-standards/controllers/production-standard.controller.go index 1635385d..d7794e41 100644 --- a/internal/modules/master/production-standards/controllers/production-standard.controller.go +++ b/internal/modules/master/production-standards/controllers/production-standard.controller.go @@ -40,7 +40,7 @@ func (u *ProductionStandardController) GetAll(c *fiber.Ctx) error { } return c.Status(fiber.StatusOK). - JSON(response.SuccessWithPaginate[dto.ProductionStandardListDTO]{ + JSON(response.SuccessWithPaginate[dto.ProductionStandardRelationDTO]{ Code: fiber.StatusOK, Status: "success", Message: "Get all productionStandards successfully", diff --git a/internal/modules/master/production-standards/dto/production-standard.dto.go b/internal/modules/master/production-standards/dto/production-standard.dto.go index 9544732a..a77cdf8b 100644 --- a/internal/modules/master/production-standards/dto/production-standard.dto.go +++ b/internal/modules/master/production-standards/dto/production-standard.dto.go @@ -7,7 +7,7 @@ import ( // === DTO Structs === -type ProductionStandardListDTO struct { +type ProductionStandardRelationDTO struct { Id uint `json:"id"` Name string `json:"name"` ProjectCategory string `json:"project_category"` @@ -15,7 +15,7 @@ type ProductionStandardListDTO struct { } type ProductionStandardDetailDTO struct { - ProductionStandardListDTO + ProductionStandardRelationDTO Details []WeeklyProductionStandardDTO `json:"details"` } @@ -33,6 +33,7 @@ type EggProductionStandardDetailDTO struct { TargetHenHouseProduction *float64 `json:"target_hen_house_production"` TargetEggWeight *float64 `json:"target_egg_weight"` TargetEggMass *float64 `json:"target_egg_mass"` + StandardFCR *float64 `json:"standard_fcr"` } type WeeklyProductionStandardDTO struct { @@ -43,14 +44,14 @@ type WeeklyProductionStandardDTO struct { // === Mapper Functions === -func ToProductionStandardListDTO(e entity.ProductionStandard) ProductionStandardListDTO { +func ToProductionStandardListDTO(e entity.ProductionStandard) ProductionStandardRelationDTO { var createdUser *userDTO.UserRelationDTO if e.CreatedUser.Id != 0 { mapped := userDTO.ToUserRelationDTO(e.CreatedUser) createdUser = &mapped } - return ProductionStandardListDTO{ + return ProductionStandardRelationDTO{ Id: e.Id, Name: e.Name, ProjectCategory: e.ProjectCategory, @@ -58,8 +59,16 @@ func ToProductionStandardListDTO(e entity.ProductionStandard) ProductionStandard } } -func ToProductionStandardListDTOs(e []entity.ProductionStandard) []ProductionStandardListDTO { - result := make([]ProductionStandardListDTO, len(e)) +func ToProductionStandardRelationDTO(e entity.ProductionStandard) ProductionStandardRelationDTO { + return ProductionStandardRelationDTO{ + Id: e.Id, + Name: e.Name, + ProjectCategory: e.ProjectCategory, + } +} + +func ToProductionStandardListDTOs(e []entity.ProductionStandard) []ProductionStandardRelationDTO { + result := make([]ProductionStandardRelationDTO, len(e)) for i, r := range e { result[i] = ToProductionStandardListDTO(r) } @@ -87,6 +96,7 @@ func ToWeeklyProductionStandardDTOWithDetails(growth entity.StandardGrowthDetail TargetHenHouseProduction: detail.TargetHenHouseProduction, TargetEggWeight: detail.TargetEggWeight, TargetEggMass: detail.TargetEggMass, + StandardFCR: detail.StandardFCR, } return WeeklyProductionStandardDTO{ @@ -140,6 +150,7 @@ func ToEggProductionStandardDetailDTO(e entity.ProductionStandardDetail) EggProd TargetHenHouseProduction: e.TargetHenHouseProduction, TargetEggWeight: e.TargetEggWeight, TargetEggMass: e.TargetEggMass, + StandardFCR: e.StandardFCR, } } @@ -149,7 +160,7 @@ func ToProductionStandardDetailDTO( productionStandardDetails []entity.ProductionStandardDetail, ) ProductionStandardDetailDTO { return ProductionStandardDetailDTO{ - ProductionStandardListDTO: ToProductionStandardListDTO(standard), + ProductionStandardRelationDTO: ToProductionStandardRelationDTO(standard), Details: ToWeeklyProductionStandardDTOsWithDetails(growthDetails, productionStandardDetails), } } diff --git a/internal/modules/master/production-standards/route.go b/internal/modules/master/production-standards/route.go index d2035bea..e0296fd3 100644 --- a/internal/modules/master/production-standards/route.go +++ b/internal/modules/master/production-standards/route.go @@ -15,9 +15,9 @@ func ProductionStandardRoutes(v1 fiber.Router, u user.UserService, s productionS route := v1.Group("/production-standards") route.Use(m.Auth(u)) - route.Get("/", ctrl.GetAll) - route.Post("/", ctrl.CreateOne) - route.Get("/:id", ctrl.GetOne) - route.Patch("/:id", ctrl.UpdateOne) - route.Delete("/:id", ctrl.DeleteOne) + route.Get("/", m.RequirePermissions(m.P_Production_Standart_GetAll), ctrl.GetAll) + route.Post("/", m.RequirePermissions(m.P_Production_Standart_CreateOne), ctrl.CreateOne) + route.Get("/:id", m.RequirePermissions(m.P_Production_Standart_GetOne), ctrl.GetOne) + route.Patch("/:id", m.RequirePermissions(m.P_Production_Standart_UpdateOne), ctrl.UpdateOne) + route.Delete("/:id", m.RequirePermissions(m.P_Production_Standart_DeleteOne), ctrl.DeleteOne) } diff --git a/internal/modules/master/production-standards/services/production-standard.service.go b/internal/modules/master/production-standards/services/production-standard.service.go index b81faf8b..4005b014 100644 --- a/internal/modules/master/production-standards/services/production-standard.service.go +++ b/internal/modules/master/production-standards/services/production-standard.service.go @@ -84,7 +84,6 @@ func (s productionStandardService) GetOne(c *fiber.Ctx, id uint) (*entity.Produc return nil, fiber.NewError(fiber.StatusNotFound, "ProductionStandard not found") } if err != nil { - s.Log.Errorf("Failed get productionStandard by id: %+v", err) return nil, err } return productionStandard, nil @@ -111,6 +110,7 @@ func (s *productionStandardService) CreateOne(c *fiber.Ctx, req *validation.Crea var createdStandard *entity.ProductionStandard err = s.Repository.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error { + standardRepoTx := repository.NewProductionStandardRepository(tx) productionStandardDetailRepoTx := repository.NewProductionStandardDetailRepository(tx) standardGrowthDetailRepoTx := repository.NewStandardGrowthDetailRepository(tx) @@ -142,6 +142,7 @@ func (s *productionStandardService) CreateOne(c *fiber.Ctx, req *validation.Crea TargetHenHouseProduction: detailReq.ProductionStandardDetails.TargetHenHouseProduction, TargetEggWeight: detailReq.ProductionStandardDetails.TargetEggWeight, TargetEggMass: detailReq.ProductionStandardDetails.TargetEggMass, + StandardFCR: detailReq.ProductionStandardDetails.StandardFCR, } if err := productionStandardDetailRepoTx.CreateOne(c.Context(), productionStandardDetail, nil); err != nil { @@ -206,7 +207,6 @@ func (s productionStandardService) UpdateOne(c *fiber.Ctx, req *validation.Updat nameExists, err := s.Repository.NameExists(c.Context(), *req.Name, &id) if err != nil { - s.Log.Errorf("Failed to check existing production standard: %+v", err) return err } if nameExists { @@ -255,6 +255,7 @@ func (s productionStandardService) UpdateOne(c *fiber.Ctx, req *validation.Updat TargetHenHouseProduction: detailReq.ProductionStandardDetails.TargetHenHouseProduction, TargetEggWeight: detailReq.ProductionStandardDetails.TargetEggWeight, TargetEggMass: detailReq.ProductionStandardDetails.TargetEggMass, + StandardFCR: detailReq.ProductionStandardDetails.StandardFCR, } if err := productionStandardDetailRepoTx.CreateOne(c.Context(), productionStandardDetail, nil); err != nil { @@ -283,7 +284,6 @@ func (s productionStandardService) UpdateOne(c *fiber.Ctx, req *validation.Updat }) if err != nil { - s.Log.Errorf("Failed to update production standard: %+v", err) return nil, err } @@ -295,7 +295,6 @@ func (s productionStandardService) DeleteOne(c *fiber.Ctx, id uint) error { if errors.Is(err, gorm.ErrRecordNotFound) { return fiber.NewError(fiber.StatusNotFound, "ProductionStandard not found") } - s.Log.Errorf("Failed to delete productionStandard: %+v", err) return err } return nil diff --git a/internal/modules/master/production-standards/validations/production-standard.validation.go b/internal/modules/master/production-standards/validations/production-standard.validation.go index 51aeecc7..cdc321f8 100644 --- a/internal/modules/master/production-standards/validations/production-standard.validation.go +++ b/internal/modules/master/production-standards/validations/production-standard.validation.go @@ -5,6 +5,7 @@ type ProductionStandardDetailItem struct { TargetHenHouseProduction *float64 `json:"target_hen_house_production" validate:"omitempty,gte=0"` TargetEggWeight *float64 `json:"target_egg_weight" validate:"omitempty,gte=0"` TargetEggMass *float64 `json:"target_egg_mass" validate:"omitempty,gte=0"` + StandardFCR *float64 `json:"standard_fcr" validate:"omitempty,gte=0"` } type StandardGrowthDetailItem struct { diff --git a/internal/modules/master/products/services/product.service.go b/internal/modules/master/products/services/product.service.go index 35e24927..f40d92be 100644 --- a/internal/modules/master/products/services/product.service.go +++ b/internal/modules/master/products/services/product.service.go @@ -70,6 +70,7 @@ func (s productService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity products, total, err := s.Repository.GetAll(c.Context(), offset, params.Limit, func(db *gorm.DB) *gorm.DB { db = s.withRelations(db) + db = db.Where("is_visible = ?", true) if params.Search != "" { return db.Where("name LIKE ?", "%"+params.Search+"%") } diff --git a/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go b/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go index 677f527b..a2ba8ad2 100644 --- a/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go +++ b/internal/modules/production/project-flock-kandangs/dto/project_flock_kandang.dto.go @@ -10,6 +10,7 @@ import ( fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/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" + productionStandardDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/dto" productDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/products/dto" warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto" chickinDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/dto" @@ -30,6 +31,7 @@ type ProjectFlockDTO struct { Area *areaDTO.AreaRelationDTO `json:"area,omitempty"` Category string `json:"category"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"` + ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` CreatedAt time.Time `json:"created_at"` @@ -82,6 +84,7 @@ func toProjectFlockDTO(pf *projectFlockDTO.ProjectFlockListDTO) *ProjectFlockDTO Area: pf.Area, Category: pf.Category, Fcr: pf.Fcr, + ProductionStandard: pf.ProductionStandard, Location: pf.Location, CreatedUser: pf.CreatedUser, CreatedAt: pf.CreatedAt, diff --git a/internal/modules/production/project_flocks/dto/projectflock.dto.go b/internal/modules/production/project_flocks/dto/projectflock.dto.go index 0922b160..504d439c 100644 --- a/internal/modules/production/project_flocks/dto/projectflock.dto.go +++ b/internal/modules/production/project_flocks/dto/projectflock.dto.go @@ -10,6 +10,7 @@ import ( kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto" locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto" nonstockDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/nonstocks/dto" + productionStandardDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/dto" // pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" @@ -28,6 +29,7 @@ type ProjectFlockListDTO struct { Area *areaDTO.AreaRelationDTO `json:"area,omitempty"` Category string `json:"category"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"` + ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"` Kandangs []KandangWithProjectFlockIdDTO `json:"kandangs,omitempty"` ProjectBudgets []ProjectBudgetDTO `json:"project_budgets,omitempty"` @@ -103,6 +105,12 @@ func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectF fcrSummary = &mapped } + var productionStandardSummary *productionStandardDTO.ProductionStandardRelationDTO + if e.ProductionStandard.Id != 0 { + mapped := productionStandardDTO.ToProductionStandardRelationDTO(e.ProductionStandard) + productionStandardSummary = &mapped + } + var locationSummary *locationDTO.LocationRelationDTO if e.Location.Id != 0 { mapped := locationDTO.ToLocationRelationDTO(e.Location) @@ -122,6 +130,7 @@ func ToProjectFlockListDTOWithPeriod(e entity.ProjectFlock, period int) ProjectF ProjectBudgets: ToProjectBudgetDTOs(e.Budgets), Category: e.Category, Fcr: fcrSummary, + ProductionStandard: productionStandardSummary, Location: locationSummary, CreatedAt: e.CreatedAt, UpdatedAt: e.UpdatedAt, diff --git a/internal/modules/production/project_flocks/dto/projectflock_kandang.dto.go b/internal/modules/production/project_flocks/dto/projectflock_kandang.dto.go index d5ed5a46..d1f0d40b 100644 --- a/internal/modules/production/project_flocks/dto/projectflock_kandang.dto.go +++ b/internal/modules/production/project_flocks/dto/projectflock_kandang.dto.go @@ -6,6 +6,7 @@ import ( fcrDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/fcrs/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" + productionStandardDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" ) @@ -19,6 +20,7 @@ type ProjectFlockWithPivotDTO struct { Area *areaDTO.AreaRelationDTO `json:"area,omitempty"` Category string `json:"category"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"` + ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"` Kandangs []KandangWithPivotDTO `json:"kandangs,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` @@ -61,6 +63,10 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD mapped := fcrDTO.ToFcrRelationDTO(e.ProjectFlock.Fcr) pfLocal.Fcr = &mapped } + if e.ProjectFlock.ProductionStandard.Id != 0 { + mapped := productionStandardDTO.ToProductionStandardRelationDTO(e.ProjectFlock.ProductionStandard) + pfLocal.ProductionStandard = &mapped + } if e.ProjectFlock.Location.Id != 0 { mapped := locationDTO.ToLocationRelationDTO(e.ProjectFlock.Location) pfLocal.Location = &mapped diff --git a/internal/modules/production/project_flocks/repositories/projectflock.repository.go b/internal/modules/production/project_flocks/repositories/projectflock.repository.go index 4af5cbcd..6cd98a8f 100644 --- a/internal/modules/production/project_flocks/repositories/projectflock.repository.go +++ b/internal/modules/production/project_flocks/repositories/projectflock.repository.go @@ -22,6 +22,7 @@ type ProjectflockRepository interface { GetActiveByLocationID(ctx context.Context, locationID uint64) ([]entity.ProjectFlock, error) AreaExists(ctx context.Context, id uint) (bool, error) FcrExists(ctx context.Context, id uint) (bool, error) + ProductionStandardExists(ctx context.Context, id uint) (bool, error) LocationExists(ctx context.Context, id uint) (bool, error) } type KandangPeriodRow struct { @@ -52,6 +53,7 @@ func (r *ProjectflockRepositoryImpl) WithDefaultRelations() func(*gorm.DB) *gorm Preload("CreatedUser"). Preload("Area"). Preload("Fcr"). + Preload("ProductionStandard"). Preload("Location"). Preload("Kandangs"). Preload("KandangHistory"). @@ -118,12 +120,14 @@ func (r *ProjectflockRepositoryImpl) applySearchFilters(db *gorm.DB, rawSearch s return db. Joins("LEFT JOIN areas ON areas.id = project_flocks.area_id"). Joins("LEFT JOIN fcrs ON fcrs.id = project_flocks.fcr_id"). + Joins("LEFT JOIN production_standards ON production_standards.id = project_flocks.production_standard_id"). Joins("LEFT JOIN locations ON locations.id = project_flocks.location_id"). Joins("LEFT JOIN users AS created_users ON created_users.id = project_flocks.created_by"). Where(` LOWER(areas.name) LIKE ? OR LOWER(project_flocks.category) LIKE ? OR LOWER(fcrs.name) LIKE ? + OR LOWER(production_standards.name) LIKE ? OR LOWER(locations.name) LIKE ? OR LOWER(locations.address) LIKE ? OR LOWER(created_users.name) LIKE ? @@ -153,6 +157,7 @@ func (r *ProjectflockRepositoryImpl) applySearchFilters(db *gorm.DB, rawSearch s likeQuery, likeQuery, likeQuery, + likeQuery, ) } @@ -164,6 +169,10 @@ func (r *ProjectflockRepositoryImpl) FcrExists(ctx context.Context, id uint) (bo return repository.Exists[entity.Fcr](ctx, r.DB(), id) } +func (r *ProjectflockRepositoryImpl) ProductionStandardExists(ctx context.Context, id uint) (bool, error) { + return repository.Exists[entity.ProductionStandard](ctx, r.DB(), id) +} + func (r *ProjectflockRepositoryImpl) LocationExists(ctx context.Context, id uint) (bool, error) { return repository.Exists[entity.Location](ctx, r.DB(), id) } diff --git a/internal/modules/production/project_flocks/services/projectflock.service.go b/internal/modules/production/project_flocks/services/projectflock.service.go index 62e1d389..9431729f 100644 --- a/internal/modules/production/project_flocks/services/projectflock.service.go +++ b/internal/modules/production/project_flocks/services/projectflock.service.go @@ -249,6 +249,7 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (* if err := commonSvc.EnsureRelations(c.Context(), commonSvc.RelationCheck{Name: "Area", ID: &req.AreaId, Exists: s.Repository.AreaExists}, commonSvc.RelationCheck{Name: "FCR", ID: &req.FcrId, Exists: s.Repository.FcrExists}, + commonSvc.RelationCheck{Name: "Production Standard", ID: &req.ProductionStandardId, Exists: s.Repository.ProductionStandardExists}, commonSvc.RelationCheck{Name: "Location", ID: &req.LocationId, Exists: s.Repository.LocationExists}, ); err != nil { return nil, err @@ -300,6 +301,7 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (* AreaId: req.AreaId, Category: cat, FcrId: req.FcrId, + ProductionStandardId: req.ProductionStandardId, LocationId: req.LocationId, CreatedBy: actorID, } diff --git a/internal/modules/production/project_flocks/validations/projectflock.validation.go b/internal/modules/production/project_flocks/validations/projectflock.validation.go index 66045dc1..5b2a9407 100644 --- a/internal/modules/production/project_flocks/validations/projectflock.validation.go +++ b/internal/modules/production/project_flocks/validations/projectflock.validation.go @@ -1,13 +1,14 @@ package validation type Create struct { - FlockName string `json:"flock_name" validate:"required_strict"` - AreaId uint `json:"area_id" validate:"required_strict,number,gt=0"` - Category string `json:"category" validate:"required_strict"` - FcrId uint `json:"fcr_id" validate:"required_strict,number,gt=0"` - LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` - KandangIds []uint `json:"kandang_ids" validate:"required,min=1,dive,gt=0"` - ProjectBudgets []ProjectBudget `json:"project_budgets" validate:"required,min=1,dive"` + FlockName string `json:"flock_name" validate:"required_strict"` + AreaId uint `json:"area_id" validate:"required_strict,number,gt=0"` + Category string `json:"category" validate:"required_strict"` + FcrId uint `json:"fcr_id" validate:"required_strict,number,gt=0"` + ProductionStandardId uint `json:"production_standard_id" validate:"required_strict,number,gt=0"` + LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` + KandangIds []uint `json:"kandang_ids" validate:"required,min=1,dive,gt=0"` + ProjectBudgets []ProjectBudget `json:"project_budgets" validate:"required,min=1,dive"` } type Query struct {