From 83c3e611136617ea63751d05b282182abd576f66 Mon Sep 17 00:00:00 2001 From: aguhh18 Date: Mon, 20 Oct 2025 06:01:16 +0700 Subject: [PATCH] feat(BE-115,116,117): implement chickin CRUD, approve logic, and stock availabilit --- ...53_create_project_chick_ins_table.down.sql | 18 -- ...5953_create_project_chick_ins_table.up.sql | 1 - ...49_create_project_chick_ins_table.down.sql | 1 + ...0649_create_project_chick_ins_table.up.sql | 21 ++ ...create_stock_availabilities_table.down.sql | 1 + ...6_create_stock_availabilities_table.up.sql | 15 ++ ...019141014_create_audit_logs_table.down.sql | 1 + ...51019141014_create_audit_logs_table.up.sql | 13 ++ internal/entities/audit_log.go | 18 ++ internal/entities/project_chickin.go | 28 +-- internal/entities/stock_availabilites.go | 26 +++ internal/entities/stock_log.go | 1 + .../modules/inventory/adjustments/module.go | 2 +- .../services/adjustment.service.go | 2 +- .../product_warehouse.controller.go | 3 +- .../services/product_warehouse.service.go | 21 +- .../product_warehouse.validation.go | 9 +- .../inventory/transfers/dto/transfer.dto.go | 64 ++---- .../modules/inventory/transfers/module.go | 2 +- .../transfers/services/transfer.service.go | 4 +- .../repositories/kandang.repository.go | 12 ++ .../repositories/warehouse.repository.go | 13 ++ .../controllers/chickin.controller.go | 23 ++- .../production/chickins/dto/chickin.dto.go | 141 +++++++++---- .../modules/production/chickins/module.go | 15 +- .../repositories/chickin.repository.go | 21 -- .../project_chickin.repository.go | 36 ++++ internal/modules/production/chickins/route.go | 1 + .../chickins/services/chickin.service.go | 195 ++++++++++++++++-- .../validations/chickin.validation.go | 5 +- internal/modules/production/route.go | 2 +- .../repositories/audit-logs.repository.go | 21 ++ .../stock-availabilites.repository.go | 21 ++ .../repositories/stock-logs.repository.go | 0 34 files changed, 558 insertions(+), 199 deletions(-) delete mode 100644 internal/database/migrations/20251017135953_create_project_chick_ins_table.down.sql delete mode 100644 internal/database/migrations/20251017135953_create_project_chick_ins_table.up.sql create mode 100644 internal/database/migrations/20251018120649_create_project_chick_ins_table.down.sql create mode 100644 internal/database/migrations/20251018120649_create_project_chick_ins_table.up.sql create mode 100644 internal/database/migrations/20251019040246_create_stock_availabilities_table.down.sql create mode 100644 internal/database/migrations/20251019040246_create_stock_availabilities_table.up.sql create mode 100644 internal/database/migrations/20251019141014_create_audit_logs_table.down.sql create mode 100644 internal/database/migrations/20251019141014_create_audit_logs_table.up.sql create mode 100644 internal/entities/audit_log.go create mode 100644 internal/entities/stock_availabilites.go delete mode 100644 internal/modules/production/chickins/repositories/chickin.repository.go create mode 100644 internal/modules/production/chickins/repositories/project_chickin.repository.go create mode 100644 internal/modules/shared/repositories/audit-logs.repository.go create mode 100644 internal/modules/shared/repositories/stock-availabilites.repository.go rename internal/modules/shared/{stock-logs => }/repositories/stock-logs.repository.go (100%) diff --git a/internal/database/migrations/20251017135953_create_project_chick_ins_table.down.sql b/internal/database/migrations/20251017135953_create_project_chick_ins_table.down.sql deleted file mode 100644 index ac9a0f59..00000000 --- a/internal/database/migrations/20251017135953_create_project_chick_ins_table.down.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE project_chick_ins ( - id BIGSERIAL PRIMARY KEY, - project_floc_id BIGINT NOT NULL REFERENCES project_flocs (id), - product_warehouse_id BIGINT NOT NULL REFERENCES product_warehouses (id), - chick_in_date DATE NOT NULL, - quantity NUMERIC(15, 3) NOT NULL CHECK (quantity > 0), - note TEXT, - created_by BIGINT NOT NULL REFERENCES users (id), - created_at TIMESTAMPTZ DEFAULT now(), - updated_at TIMESTAMPTZ DEFAULT now(), - deleted_at TIMESTAMPTZ -); - -CREATE INDEX idx_project_chick_ins_project_floc_id ON project_chick_ins (project_floc_id); - -CREATE INDEX idx_project_chick_ins_product_warehouse_id ON project_chick_ins (product_warehouse_id); - -CREATE INDEX idx_project_chick_ins_created_by ON project_chick_ins (created_by); \ No newline at end of file diff --git a/internal/database/migrations/20251017135953_create_project_chick_ins_table.up.sql b/internal/database/migrations/20251017135953_create_project_chick_ins_table.up.sql deleted file mode 100644 index b1435759..00000000 --- a/internal/database/migrations/20251017135953_create_project_chick_ins_table.up.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE IF EXISTS project_chick_ins; \ No newline at end of file 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..a3b7dfb3 --- /dev/null +++ b/internal/database/migrations/20251018120649_create_project_chick_ins_table.up.sql @@ -0,0 +1,21 @@ +CREATE TABLE project_chickins ( + id BIGSERIAL PRIMARY KEY, + project_floc_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 +); + +CREATE INDEX idx_project_chickins_project_floc_id ON project_chickins (project_floc_id); + +CREATE INDEX idx_project_chickins_created_by ON project_chickins (created_by); + +ALTER TABLE project_chickins +ADD CONSTRAINT fk_project_floc_id FOREIGN KEY (project_floc_id) REFERENCES project_flocks (id); + +ALTER TABLE project_chickins +ADD CONSTRAINT fk_created_by FOREIGN KEY (created_by) REFERENCES users (id); \ No newline at end of file diff --git a/internal/database/migrations/20251019040246_create_stock_availabilities_table.down.sql b/internal/database/migrations/20251019040246_create_stock_availabilities_table.down.sql new file mode 100644 index 00000000..1d50d98b --- /dev/null +++ b/internal/database/migrations/20251019040246_create_stock_availabilities_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS stock_availabilities; \ No newline at end of file diff --git a/internal/database/migrations/20251019040246_create_stock_availabilities_table.up.sql b/internal/database/migrations/20251019040246_create_stock_availabilities_table.up.sql new file mode 100644 index 00000000..bce6f7e6 --- /dev/null +++ b/internal/database/migrations/20251019040246_create_stock_availabilities_table.up.sql @@ -0,0 +1,15 @@ +CREATE TABLE stock_availabilities ( + id BIGSERIAL PRIMARY KEY, + entity_type VARCHAR(50) NOT NULL, + entity_id BIGINT NOT NULL, + product_id BIGINT, + quantity NUMERIC(15, 3) NOT NULL DEFAULT 0, + reserved_quantity NUMERIC(15, 3) NOT NULL DEFAULT 0, + unit VARCHAR(20), + last_updated TIMESTAMPTZ DEFAULT now(), + created_at TIMESTAMPTZ DEFAULT now(), + deleted_at TIMESTAMPTZ +); + +ALTER TABLE stock_availabilities +ADD CONSTRAINT fk_product_id FOREIGN KEY (product_id) REFERENCES products (id); \ No newline at end of file diff --git a/internal/database/migrations/20251019141014_create_audit_logs_table.down.sql b/internal/database/migrations/20251019141014_create_audit_logs_table.down.sql new file mode 100644 index 00000000..4cf6b411 --- /dev/null +++ b/internal/database/migrations/20251019141014_create_audit_logs_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS audit_logs; \ No newline at end of file diff --git a/internal/database/migrations/20251019141014_create_audit_logs_table.up.sql b/internal/database/migrations/20251019141014_create_audit_logs_table.up.sql new file mode 100644 index 00000000..13731dcc --- /dev/null +++ b/internal/database/migrations/20251019141014_create_audit_logs_table.up.sql @@ -0,0 +1,13 @@ +CREATE TABLE audit_logs ( + id BIGSERIAL PRIMARY KEY, + table_name VARCHAR(100) NOT NULL, + record_id BIGINT NOT NULL, + action VARCHAR(30) NOT NULL, + before_data JSONB, + after_data JSONB, + changed_by BIGINT, + created_at TIMESTAMPTZ DEFAULT now() +); + +ALTER TABLE audit_logs +ADD CONSTRAINT fk_changed_by FOREIGN KEY (changed_by) REFERENCES users (id); \ No newline at end of file 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 index a4a00596..631c8ff3 100644 --- a/internal/entities/project_chickin.go +++ b/internal/entities/project_chickin.go @@ -6,19 +6,19 @@ import ( "gorm.io/gorm" ) -type ProjectChickin struct { - Id uint `gorm:"primaryKey"` - ProjectFlocId uint `gorm:"not null"` - ProductWarehouseId 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:"-"` +const () - ProjectFloc ProjectFlock `gorm:"foreignKey:ProjectFlocId;references:Id"` - ProductWarehouse ProductWarehouse `gorm:"foreignKey:ProductWarehouseId;references:Id"` - CreatedUser User `gorm:"foreignKey:CreatedBy;references:Id"` +type ProjectChickin struct { + Id uint `gorm:"primaryKey"` + ProjectFlocId 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:"-"` + + ProjectFlock ProjectFlock `gorm:"foreignKey:ProjectFlocId;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/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 af89f442..69654b85 100644 --- a/internal/modules/inventory/adjustments/services/adjustment.service.go +++ b/internal/modules/inventory/adjustments/services/adjustment.service.go @@ -9,7 +9,7 @@ import ( 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" diff --git a/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go b/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go index f21eef96..a0b72a4d 100644 --- a/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go +++ b/internal/modules/inventory/product-warehouses/controllers/product_warehouse.controller.go @@ -28,7 +28,6 @@ func (u *ProductWarehouseController) GetAll(c *fiber.Ctx) error { Limit: c.QueryInt("limit", 10), ProductId: uint(c.QueryInt("product_id", 0)), WarehouseId: uint(c.QueryInt("warehouse_id", 0)), - Flag: c.Query("flag"), } result, totalResults, err := u.ProductWarehouseService.GetAll(c, query) @@ -72,3 +71,5 @@ func (u *ProductWarehouseController) GetOne(c *fiber.Ctx) error { Data: dto.ToProductWarehouseListDTO(*result), }) } + + 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 a36e3621..9afe5707 100644 --- a/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go +++ b/internal/modules/inventory/product-warehouses/services/product_warehouse.service.go @@ -34,14 +34,7 @@ func NewProductWarehouseService(repo repository.ProductWarehouseRepository, vali } func (s productWarehouseService) withRelations(db *gorm.DB) *gorm.DB { - return db. - Preload("Product"). - Preload("Product.Flags"). - Preload("Warehouse"). - Preload("Warehouse.Location"). - Preload("Warehouse.Kandang"). - Preload("Warehouse.Area"). - Preload("CreatedUser") + return db.Preload("Product.Flags").Preload("Product").Preload("Warehouse").Preload("CreatedUser") } func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProductWarehouse, int64, error) { @@ -62,12 +55,6 @@ func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query) db = db.Where("warehouse_id = ?", params.WarehouseId) } - if params.Flag != "" { - db = db.Joins("JOIN products ON products.id = product_warehouses.product_id") - db = db.Joins("JOIN flags ON flags.flagable_id = products.id AND flags.flagable_type = ?", "products") - db = db.Where("flags.name = ?", params.Flag) - } - return db.Order("created_at DESC").Order("updated_at DESC") }) @@ -75,11 +62,6 @@ func (s productWarehouseService) GetAll(c *fiber.Ctx, params *validation.Query) s.Log.Errorf("Failed to get productWarehouses: %+v", err) return nil, 0, err } - - if len(productWarehouses) == 0 { - return nil, 0, fiber.NewError(fiber.StatusNotFound, "ProductWarehouses not found") - } - return productWarehouses, total, nil } @@ -88,7 +70,6 @@ func (s productWarehouseService) GetOne(c *fiber.Ctx, id uint) (*entity.ProductW if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fiber.NewError(fiber.StatusNotFound, "ProductWarehouse not found") } - if err != nil { s.Log.Errorf("Failed get productWarehouse by id: %+v", err) return nil, err diff --git a/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go b/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go index 30a5bed1..02648300 100644 --- a/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go +++ b/internal/modules/inventory/product-warehouses/validations/product_warehouse.validation.go @@ -13,9 +13,8 @@ type Update struct { } type Query struct { - Page int `query:"page" validate:"omitempty,number,min=1"` - Limit int `query:"limit" validate:"omitempty,number,min=1,max=100"` - ProductId uint `query:"product_id" validate:"omitempty,number,min=1"` - WarehouseId uint `query:"warehouse_id" validate:"omitempty,number,min=1"` - Flag string `query:"flag" validate:"omitempty"` + Page int `query:"page" validate:"omitempty,number,min=1"` + Limit int `query:"limit" validate:"omitempty,number,min=1,max=100"` + ProductId uint `query:"product_id" validate:"omitempty,number,min=1"` + WarehouseId uint `query:"warehouse_id" validate:"omitempty,number,min=1"` } diff --git a/internal/modules/inventory/transfers/dto/transfer.dto.go b/internal/modules/inventory/transfers/dto/transfer.dto.go index 1b08ecbb..217e5038 100644 --- a/internal/modules/inventory/transfers/dto/transfer.dto.go +++ b/internal/modules/inventory/transfers/dto/transfer.dto.go @@ -57,17 +57,17 @@ type TransferDetailDTO struct { // Detail produk type TransferDetailItemDTO struct { - Id uint64 `json:"id"` - Product *ProductDTO `json:"product,omitempty"` - Quantity float64 `json:"quantity"` - BeforeQuantity float64 `json:"before_quantity"` - AfterQuantity float64 `json:"after_quantity"` + Id uint64 `json:"id"` + ProductId uint64 `json:"product_id"` + Quantity float64 `json:"quantity"` + BeforeQuantity float64 `json:"before_quantity"` + AfterQuantity float64 `json:"after_quantity"` } // Delivery ekspedisi type TransferDeliveryDTO struct { Id uint64 `json:"id"` - Supplier *SupplierDTO `json:"supplier,omitempty"` + SupplierId uint64 `json:"supplier_id"` VehiclePlate string `json:"vehicle_plate"` DriverName string `json:"driver_name"` DocumentNumber string `json:"document_number"` @@ -83,16 +83,6 @@ type TransferDeliveryItemDTO struct { Quantity float64 `json:"quantity"` } -type ProductDTO struct { - Id uint64 `json:"id"` - Name string `json:"name"` -} - -type SupplierDTO struct { - Id uint64 `json:"id"` - Name string `json:"name"` -} - // === Mapper Functions === func ToTransferBaseDTO(e entity.StockTransfer) TransferBaseDTO { @@ -124,26 +114,6 @@ func toAreaDTO(a *entity.Area) *AreaDTO { } } -func toProductDTO(p *entity.Product) *ProductDTO { - if p == nil { - return nil - } - return &ProductDTO{ - Id: uint64(p.Id), - Name: p.Name, - } -} - -func toSupplierDTO(s *entity.Supplier) *SupplierDTO { - if s == nil { - return nil - } - return &SupplierDTO{ - Id: uint64(s.Id), - Name: s.Name, - } -} - func toLocationDTO(l *entity.Location) *LocationDTO { if l == nil { return nil @@ -172,19 +142,19 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO { mapped := userDTO.ToUserBaseDTO(*e.CreatedUser) createdUser = &mapped } - + // Map details var details []TransferDetailItemDTO for _, d := range e.Details { details = append(details, TransferDetailItemDTO{ - Id: d.Id, - Product: toProductDTO(d.Product), - Quantity: d.Quantity, + Id: d.Id, + ProductId: d.ProductId, + Quantity: d.Quantity, }) } - + // Map deliveries var deliveries []TransferDeliveryDTO for _, del := range e.Deliveries { - + // Map delivery items var items []TransferDeliveryItemDTO for _, item := range del.Items { items = append(items, TransferDeliveryItemDTO{ @@ -195,8 +165,8 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO { } deliveries = append(deliveries, TransferDeliveryDTO{ Id: del.Id, + SupplierId: del.SupplierId, VehiclePlate: del.VehiclePlate, - Supplier: toSupplierDTO(del.Supplier), DriverName: del.DriverName, DocumentNumber: del.DocumentNumber, DocumentPath: del.DocumentPath, @@ -228,9 +198,9 @@ func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO { var details []TransferDetailItemDTO for _, d := range e.Details { details = append(details, TransferDetailItemDTO{ - Id: d.Id, - Product: toProductDTO(d.Product), - Quantity: d.Quantity, + Id: d.Id, + ProductId: d.ProductId, + Quantity: d.Quantity, }) } // Map deliveries @@ -238,7 +208,7 @@ func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO { for _, del := range e.Deliveries { deliveries = append(deliveries, TransferDeliveryDTO{ Id: del.Id, - Supplier: toSupplierDTO(del.Supplier), + SupplierId: del.SupplierId, 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 4579d4c0..bdc8abf6 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,8 +60,6 @@ func (s transferService) withRelations(db *gorm.DB) *gorm.DB { Preload("ToWarehouse.Location"). Preload("ToWarehouse.Area"). Preload("Details"). - Preload("Details.Product"). - Preload("Deliveries.Supplier"). Preload("Deliveries.Items") } 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 index aae59ff2..6514f8c8 100644 --- a/internal/modules/production/chickins/controllers/chickin.controller.go +++ b/internal/modules/production/chickins/controllers/chickin.controller.go @@ -88,7 +88,7 @@ func (u *ChickinController) CreateOne(c *fiber.Ctx) error { Code: fiber.StatusCreated, Status: "success", Message: "Create chickin successfully", - Data: dto.ToChickinListDTO(*result), + Data: result, }) } @@ -138,3 +138,24 @@ func (u *ChickinController) DeleteOne(c *fiber.Ctx) error { 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 index 6e317e79..7a8b6773 100644 --- a/internal/modules/production/chickins/dto/chickin.dto.go +++ b/internal/modules/production/chickins/dto/chickin.dto.go @@ -1,84 +1,135 @@ package dto import ( - "time" + "time" - entity "gitlab.com/mbugroup/lti-api.git/internal/entities" - userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" + entity "gitlab.com/mbugroup/lti-api.git/internal/entities" ) // === DTO Structs === type ChickinBaseDTO struct { - Id uint `json:"id"` - Name string `json:"name"` + Id uint `json:"id"` + ProjectFlocId uint `json:"project_floc_id"` + ChickInDate time.Time `json:"chick_in_date"` + Quantity float64 `json:"quantity"` + Note string `json:"note"` } type ChickinSimpleDTO struct { - Id uint `json:"id"` - Name string `json:"name"` + Id uint `json:"id"` + ProjectFlocId uint `json:"project_floc_id"` + ChickInDate time.Time `json:"chick_in_date"` + Quantity float64 `json:"quantity"` + Note string `json:"note"` + CreatedBy uint `json:"created_by"` +} + +type UserBaseDTO struct { + Id uint `json:"id"` + Name string `json:"name"` } type ChickinListDTO struct { - ChickinBaseDTO - CreatedUser *userDTO.UserBaseDTO `json:"created_user"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ChickinBaseDTO + ProjectFlock *ProjectFlockDTO `json:"project_flock"` + CreatedUser *UserBaseDTO `json:"created_user"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type ProjectFlockDTO struct { + Id uint `json:"id"` + Period int `json:"period"` + FlockId uint `json:"flock_id"` + FlockName string `json:"flock_name"` +} + +// === Mapper Functions === + +func ToProjectFlockDTO(e entity.ProjectFlock) ProjectFlockDTO { + return ProjectFlockDTO{ + Id: e.Id, + Period: e.Period, + FlockId: e.FlockId, + FlockName: e.Flock.Name, + } } type ChickinDetailDTO struct { - ChickinListDTO + ChickinListDTO } // === Mapper Functions === func ToChickinBaseDTO(e entity.ProjectChickin) ChickinBaseDTO { - return ChickinBaseDTO{ - Id: e.Id, - - } + return ChickinBaseDTO{ + Id: e.Id, + ProjectFlocId: e.ProjectFlocId, + ChickInDate: e.ChickInDate, + Quantity: e.Quantity, + Note: e.Note, + } } func ToChickinSimpleDTO(e entity.ProjectChickin) ChickinSimpleDTO { - return ChickinSimpleDTO{ - Id: e.Id, - - } + return ChickinSimpleDTO{ + Id: e.Id, + ProjectFlocId: e.ProjectFlocId, + ChickInDate: e.ChickInDate, + Quantity: e.Quantity, + Note: e.Note, + CreatedBy: e.CreatedBy, + } } func ToChickinListDTO(e entity.ProjectChickin) ChickinListDTO { - var createdUser *userDTO.UserBaseDTO - if e.CreatedUser.Id != 0 { - mapped := userDTO.ToUserBaseDTO(e.CreatedUser) - createdUser = &mapped - } + var createdUser *UserBaseDTO + if e.CreatedUser.Id != 0 { + mapped := ToUserBaseDTO(e.CreatedUser) + createdUser = &mapped + } - return ChickinListDTO{ - ChickinBaseDTO: ToChickinBaseDTO(e), - CreatedAt: e.CreatedAt, - UpdatedAt: e.UpdatedAt, - CreatedUser: createdUser, - } + var projectFlock *ProjectFlockDTO + if e.ProjectFlock.Id != 0 { + mapped := ToProjectFlockDTO(e.ProjectFlock) + projectFlock = &mapped + } + + return ChickinListDTO{ + ChickinBaseDTO: ToChickinBaseDTO(e), + ProjectFlock: projectFlock, + CreatedAt: e.CreatedAt, + UpdatedAt: e.UpdatedAt, + CreatedUser: createdUser, + } } func ToChickinListDTOs(e []entity.ProjectChickin) []ChickinListDTO { - result := make([]ChickinListDTO, len(e)) - for i, r := range e { - result[i] = ToChickinListDTO(r) - } - return result + 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 + 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), - } -} \ No newline at end of file + return ChickinDetailDTO{ + ChickinListDTO: ToChickinListDTO(e), + } +} + +func ToUserBaseDTO(e entity.User) UserBaseDTO { + return UserBaseDTO{ + Id: e.Id, + Name: e.Name, + } +} diff --git a/internal/modules/production/chickins/module.go b/internal/modules/production/chickins/module.go index 330bf698..30146724 100644 --- a/internal/modules/production/chickins/module.go +++ b/internal/modules/production/chickins/module.go @@ -5,8 +5,14 @@ import ( "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" @@ -16,11 +22,16 @@ 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) + projectFlockRepo := rProjectFlock.NewProjectflockRepository(db) + productWarehouseRepo := rProductWarehouse.NewProductWarehouseRepository(db) + userRepo := rUser.NewUserRepository(db) - chickinService := sChickin.NewChickinService(chickinRepo, validate) + chickinService := sChickin.NewChickinService(chickinRepo, kandangRepo, warehouseRepo, productWarehouseRepo, projectFlockRepo, auditlogrepo, validate) userService := sUser.NewUserService(userRepo, validate) ChickinRoutes(router, userService, chickinService) } - diff --git a/internal/modules/production/chickins/repositories/chickin.repository.go b/internal/modules/production/chickins/repositories/chickin.repository.go deleted file mode 100644 index e8c3fccf..00000000 --- a/internal/modules/production/chickins/repositories/chickin.repository.go +++ /dev/null @@ -1,21 +0,0 @@ -package repository - -import ( - "gitlab.com/mbugroup/lti-api.git/internal/common/repository" - entity "gitlab.com/mbugroup/lti-api.git/internal/entities" - "gorm.io/gorm" -) - -type ChickinRepository interface { - repository.BaseRepository[entity.ProjectChickin] -} - -type ChickinRepositoryImpl struct { - *repository.BaseRepositoryImpl[entity.ProjectChickin] -} - -func NewChickinRepository(db *gorm.DB) ChickinRepository { - return &ChickinRepositoryImpl{ - BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectChickin](db), - } -} 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 index 8948459e..5fa5237a 100644 --- a/internal/modules/production/chickins/route.go +++ b/internal/modules/production/chickins/route.go @@ -25,4 +25,5 @@ func ChickinRoutes(v1 fiber.Router, u user.UserService, s chickin.ChickinService 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 index 00a3012e..75dc0242 100644 --- a/internal/modules/production/chickins/services/chickin.service.go +++ b/internal/modules/production/chickins/services/chickin.service.go @@ -4,8 +4,14 @@ 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" + 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" @@ -20,24 +26,39 @@ type ChickinService interface { 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.ChickinRepository + Log *logrus.Logger + Validate *validator.Validate + Repository repository.ProjectChickinRepository + KandangRepo KandangRepo.KandangRepository + WarehouseRepo rWarehouse.WarehouseRepository + ProductWarehouseRepo rProductWarehouse.ProductWarehouseRepository + ProjectFlockRepo rProjectFlock.ProjectflockRepository + AuditLogRepo AuditLogRepo.AuditLogRepository } -func NewChickinService(repo repository.ChickinRepository, validate *validator.Validate) ChickinService { +func NewChickinService(repo repository.ProjectChickinRepository, kandangRepo KandangRepo.KandangRepository, warehouseRepo rWarehouse.WarehouseRepository, productWarehouseRepo rProductWarehouse.ProductWarehouseRepository, projectFlockRepo rProjectFlock.ProjectflockRepository, auditLogRepo AuditLogRepo.AuditLogRepository, validate *validator.Validate) ChickinService { return &chickinService{ - Log: utils.Log, - Validate: validate, - Repository: repo, + Log: utils.Log, + Validate: validate, + Repository: repo, + KandangRepo: kandangRepo, + WarehouseRepo: warehouseRepo, + ProductWarehouseRepo: productWarehouseRepo, + ProjectFlockRepo: projectFlockRepo, + AuditLogRepo: auditLogRepo, } } func (s chickinService) withRelations(db *gorm.DB) *gorm.DB { - return db.Preload("CreatedUser") + return db. + Preload("CreatedUser"). + Preload("ProjectFlock"). + Preload("ProjectFlock.ProductCategory") + } func (s chickinService) GetAll(c *fiber.Ctx, params *validation.Query) ([]entity.ProjectChickin, int64, error) { @@ -79,16 +100,125 @@ func (s *chickinService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit return nil, err } - createBody := &entity.ProjectChickin{ - ProjectFlocId: 1, + // ambil salah satu kandang dari project_floc_id dari kandang repository + kandang, err := s.KandangRepo.GetFirstByProjectFlockID(c.Context(), 1) + if err != nil { + s.Log.Errorf("Failed to get kandang: %+v", err) + return nil, err + } + // ambil warehouse dari kandangid + warehouse, err := s.WarehouseRepo.GetByKandangID(c.Context(), kandang.Id) + if err != nil { + s.Log.Errorf("Failed to get warehouse: %+v", err) + return nil, err + } + // getprojectflock id with relation + projectFlock, err := s.ProjectFlockRepo.GetByID( + c.Context(), + req.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") + } + // ambil quantity + 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 nil, 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 nil, err } - if err := s.Repository.CreateOne(c.Context(), createBody, nil); err != nil { + if productWarehouse.Quantity < 1 { + return nil, fiber.NewError(fiber.StatusBadRequest, "Insufficient product quantity in warehouse") + } + + // masukan ke chic in + 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{ + ProjectFlocId: req.ProjectFlockId, + ChickInDate: chickinDate, + Quantity: productWarehouse.Quantity, + Note: "", + CreatedBy: 1, //todo: ganti dengan + } + + err = s.Repository.CreateOne(c.Context(), newChickin, nil) + if err != nil { s.Log.Errorf("Failed to create chickin: %+v", err) return nil, err } - return s.GetOne(c, createBody.Id) + // Kurangi quantity di product warehouse + updatedQuantity := productWarehouse.Quantity - newChickin.Quantity + if updatedQuantity < 0 { + updatedQuantity = 0 + } + 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 nil, err + } + + // masukan check apakah stock availability ada, jika ada update, jika tidak buat baru + stockAvailability := &entity.StockAvailability{ + EntityType: entity.EntityTypeProjectFlockKandang, + ReservedQuantity: productWarehouse.Quantity, + EntityId: req.ProjectFlockId, //todo: nanti pakek projct flock kandang id + ProductId: productWarehouse.ProductId, + } + + var existingStockAvailability entity.StockAvailability + err = s.ProductWarehouseRepo.DB().WithContext(c.Context()). + Where("entity_type = ? AND entity_id = ? AND product_id = ?", stockAvailability.EntityType, stockAvailability.EntityId, stockAvailability.ProductId). + First(&existingStockAvailability).Error + + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + // buat baru + stockAvailability.ReservedQuantity = newChickin.Quantity + stockAvailability.Quantity = 0 + err = s.ProductWarehouseRepo.DB().WithContext(c.Context()).Create(stockAvailability).Error + if err != nil { + s.Log.Errorf("Failed to create stock availability: %+v", err) + return nil, err + } + } else { + s.Log.Errorf("Failed to get stock availability: %+v", err) + return nil, err + } + } else { + // update existing + newQuantity := existingStockAvailability.ReservedQuantity + newChickin.Quantity + err = s.ProductWarehouseRepo.DB().WithContext(c.Context()). + Model(&existingStockAvailability). + Update("reserved_quantity", newQuantity).Error + if err != nil { + s.Log.Errorf("Failed to update stock availability: %+v", err) + return nil, err + } + + } + return nil, nil } func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectChickin, error) { @@ -98,10 +228,9 @@ func (s chickinService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) updateBody := make(map[string]any) - if req.Name != nil { - updateBody["name"] = *req.Name + if req.ChickInDate != "" { + updateBody["chick_in_date"] = req.ChickInDate } - if len(updateBody) == 0 { return s.GetOne(c, id) } @@ -125,5 +254,41 @@ func (s chickinService) DeleteOne(c *fiber.Ctx, id uint) error { s.Log.Errorf("Failed to delete chickin: %+v", err) return err } + return nil +} + +func (s *chickinService) Approve(c *fiber.Ctx, id uint) error { + + 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 + } + + //pindahkan stock dari reserved ke actual stock + // get stock avaibility untuk di update + var stockAvailability entity.StockAvailability + err = s.ProductWarehouseRepo.DB().WithContext(c.Context()). + Where("entity_type = ? AND entity_id = ? ", entity.EntityTypeProjectFlockKandang, chickin.ProjectFlocId). + First(&stockAvailability).Error + if err != nil { + s.Log.Errorf("Failed to get stock availability: %+v", err) + return err + } + + newReservedQuantity := stockAvailability.ReservedQuantity - chickin.Quantity + if newReservedQuantity < 0 { + newReservedQuantity = 0 + } + + + return nil } diff --git a/internal/modules/production/chickins/validations/chickin.validation.go b/internal/modules/production/chickins/validations/chickin.validation.go index 95505746..152b3f22 100644 --- a/internal/modules/production/chickins/validations/chickin.validation.go +++ b/internal/modules/production/chickins/validations/chickin.validation.go @@ -1,11 +1,12 @@ package validation type Create struct { - Name string `json:"name" validate:"required_strict,min=3"` + ProjectFlockId uint `json:"project_flock_id" validate:"required,number,min=1"` + ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"` } type Update struct { - Name *string `json:"name,omitempty" validate:"omitempty"` + ChickInDate string `json:"chick_in_date" validate:"required,datetime=2006-01-02"` } type Query struct { diff --git a/internal/modules/production/route.go b/internal/modules/production/route.go index 597fbc62..b41ef1e7 100644 --- a/internal/modules/production/route.go +++ b/internal/modules/production/route.go @@ -7,9 +7,9 @@ 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" - chickins "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins" // MODULE IMPORTS ) 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