From 5c27453315172eee4273d92dd99a4a1a78bf4130 Mon Sep 17 00:00:00 2001 From: Habib Fatkhul Rohman Date: Mon, 1 Dec 2025 15:58:35 +0700 Subject: [PATCH] feat: refactor warehouse service to include logging and audit trail functionality --- modules/warehouse/dto/warehouse_dto.go | 85 +++++++++++- .../warehouse/service/warehouse_service.go | 129 ++++++------------ providers/core.go | 2 +- 3 files changed, 127 insertions(+), 89 deletions(-) diff --git a/modules/warehouse/dto/warehouse_dto.go b/modules/warehouse/dto/warehouse_dto.go index 04737cd..9fd4874 100644 --- a/modules/warehouse/dto/warehouse_dto.go +++ b/modules/warehouse/dto/warehouse_dto.go @@ -3,7 +3,9 @@ package dto import ( "errors" + "github.com/Caknoooo/go-gin-clean-starter/database/entities" pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" + "github.com/google/uuid" ) const ( @@ -54,7 +56,7 @@ type WarehouseResponse struct { DissallowNegativeInventory bool `json:"dissallow_negative_inventory"` Client pkgdto.IdNameResponse `json:"client"` PIC *pkgdto.IdNameResponse `json:"pic"` - Zonas []WarehouseZonaResponse `json:"zones"` + Zonas []WarehouseZonaResponse `json:"zonas"` } type WarehouseZonaResponse struct { @@ -88,3 +90,84 @@ type ZonaAisleResponse struct { WeightUom pkgdto.IdNameResponse `json:"weight_uom_id"` Client pkgdto.IdNameResponse `json:"client_id"` } + +func ToWarehouseResponse(e entities.MWarehouseEntity) WarehouseResponse { + client := pkgdto.IdNameResponse{} + if e.Client.ID != uuid.Nil { + client = pkgdto.IdNameResponse{ + ID: e.Client.ID.String(), + Name: e.Client.Name, + } + } + + pic := pkgdto.IdNameResponse{} + if e.PIC.ID != uuid.Nil { + pic = pkgdto.IdNameResponse{ + ID: e.PIC.ID.String(), + Name: e.PIC.Name, + } + } + + zonas := make([]WarehouseZonaResponse, 0) + for _, zona := range e.Zonas { + zonas = append(zonas, WarehouseZonaResponse{ + ID: zona.ID.String(), + Code: zona.Code, + Name: zona.Name, + Type: zona.Type, + Temperature: zona.Temperature, + Hazardous: zona.Hazardous, + QRCodeZone: zona.QRCodeZone, + IsActive: zona.IsActive, + Client: pkgdto.IdNameResponse{ + ID: zona.Client.ID.String(), + Name: zona.Client.Name, + }, + Aisles: make([]ZonaAisleResponse, 0), + }) + for _, aisle := range zona.Aisles { + zonas[len(zonas)-1].Aisles = append(zonas[len(zonas)-1].Aisles, ZonaAisleResponse{ + ID: aisle.ID.String(), + Code: aisle.Code, + Name: aisle.Name, + IsleX: aisle.IsleX, + BinY: aisle.BinY, + LevelZ: aisle.LevelZ, + DimLength: aisle.DimLength, + DimWidth: aisle.DimWidth, + DimHeight: aisle.DimHeight, + Weight: aisle.Weight, + QrCodeAisle: aisle.QrCodeAisle, + IsActive: aisle.IsActive, + Zone: pkgdto.IdNameResponse{ + ID: aisle.Zona.ID.String(), + Name: aisle.Zona.Name, + }, + DimUom: pkgdto.IdNameResponse{ + ID: aisle.DimUom.ID.String(), + Name: aisle.DimUom.Name, + }, + WeightUom: pkgdto.IdNameResponse{ + ID: aisle.WeightUom.ID.String(), + Name: aisle.WeightUom.Name, + }, + Client: pkgdto.IdNameResponse{ + ID: aisle.Client.ID.String(), + Name: aisle.Client.Name, + }, + }) + } + } + + return WarehouseResponse{ + ID: e.ID.String(), + Code: e.Code, + Name: e.Name, + Description: e.Description, + Status: e.Status, + DissallowNegativeInventory: e.DissallowNegativeInventory, + Client: client, + PIC: &pic, + Zonas: zonas, + } +} diff --git a/modules/warehouse/service/warehouse_service.go b/modules/warehouse/service/warehouse_service.go index d188928..e818318 100644 --- a/modules/warehouse/service/warehouse_service.go +++ b/modules/warehouse/service/warehouse_service.go @@ -7,9 +7,10 @@ import ( dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/warehouse/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/warehouse/query" "github.com/Caknoooo/go-gin-clean-starter/modules/warehouse/repository" - pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" + "github.com/Caknoooo/go-gin-clean-starter/pkg/constants" "github.com/Caknoooo/go-gin-clean-starter/pkg/utils" "github.com/google/uuid" + "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -24,87 +25,7 @@ type WarehouseService interface { type warehouseService struct { db *gorm.DB warehouseRepo repository.WarehouseRepository -} - -func toWarehouseResponse(e entities.MWarehouseEntity) dtodomain.WarehouseResponse { - client := pkgdto.IdNameResponse{} - if e.Client.ID != uuid.Nil { - client = pkgdto.IdNameResponse{ - ID: e.Client.ID.String(), - Name: e.Client.Name, - } - } - - pic := pkgdto.IdNameResponse{} - if e.PIC.ID != uuid.Nil { - pic = pkgdto.IdNameResponse{ - ID: e.PIC.ID.String(), - Name: e.PIC.Name, - } - } - - zonas := make([]dtodomain.WarehouseZonaResponse, 0) - for _, zona := range e.Zonas { - zonas = append(zonas, dtodomain.WarehouseZonaResponse{ - ID: zona.ID.String(), - Code: zona.Code, - Name: zona.Name, - Type: zona.Type, - Temperature: zona.Temperature, - Hazardous: zona.Hazardous, - QRCodeZone: zona.QRCodeZone, - IsActive: zona.IsActive, - Client: pkgdto.IdNameResponse{ - ID: zona.Client.ID.String(), - Name: zona.Client.Name, - }, - Aisles: make([]dtodomain.ZonaAisleResponse, 0), - }) - for _, aisle := range zona.Aisles { - zonas[len(zonas)-1].Aisles = append(zonas[len(zonas)-1].Aisles, dtodomain.ZonaAisleResponse{ - ID: aisle.ID.String(), - Code: aisle.Code, - Name: aisle.Name, - IsleX: aisle.IsleX, - BinY: aisle.BinY, - LevelZ: aisle.LevelZ, - DimLength: aisle.DimLength, - DimWidth: aisle.DimWidth, - DimHeight: aisle.DimHeight, - Weight: aisle.Weight, - QrCodeAisle: aisle.QrCodeAisle, - IsActive: aisle.IsActive, - Zone: pkgdto.IdNameResponse{ - ID: aisle.Zona.ID.String(), - Name: aisle.Zona.Name, - }, - DimUom: pkgdto.IdNameResponse{ - ID: aisle.DimUom.ID.String(), - Name: aisle.DimUom.Name, - }, - WeightUom: pkgdto.IdNameResponse{ - ID: aisle.WeightUom.ID.String(), - Name: aisle.WeightUom.Name, - }, - Client: pkgdto.IdNameResponse{ - ID: aisle.Client.ID.String(), - Name: aisle.Client.Name, - }, - }) - } - } - - return dtodomain.WarehouseResponse{ - ID: e.ID.String(), - Code: e.Code, - Name: e.Name, - Description: e.Description, - Status: e.Status, - DissallowNegativeInventory: e.DissallowNegativeInventory, - Client: client, - PIC: &pic, - Zonas: zonas, - } + log *logrus.Logger } func (w *warehouseService) Create(ctx context.Context, req dtodomain.WarehouseCreateRequest) (dtodomain.WarehouseResponse, error) { @@ -127,6 +48,7 @@ func (w *warehouseService) Create(ctx context.Context, req dtodomain.WarehouseCr DissallowNegativeInventory: req.DissallowNegativeInventory, PICID: utils.ParseNullableUUID(req.PICID), ClientID: clientUUID, + FullAuditTrail: utils.FillAuditTrail(ctx, constants.CREATE), } created, err := w.warehouseRepo.Create(ctx, tx, warehouse) @@ -139,7 +61,13 @@ func (w *warehouseService) Create(ctx context.Context, req dtodomain.WarehouseCr if err != nil { return dtodomain.WarehouseResponse{}, err } - return toWarehouseResponse(result), nil + w.log.WithFields(logrus.Fields{ + "user_id": utils.GetUserID(ctx), + "action": "create", + "entity": "warehouse", + "entity_id": created.ID.String(), + }).Info("Warehouse created") + return dtodomain.ToWarehouseResponse(result), nil } func (w *warehouseService) GetById(ctx context.Context, warehouseId string) (dtodomain.WarehouseResponse, error) { @@ -147,7 +75,7 @@ func (w *warehouseService) GetById(ctx context.Context, warehouseId string) (dto if err != nil { return dtodomain.WarehouseResponse{}, err } - return toWarehouseResponse(warehouse), nil + return dtodomain.ToWarehouseResponse(warehouse), nil } func (w *warehouseService) GetAll(ctx context.Context, filter query.WarehouseFilter) ([]dtodomain.WarehouseResponse, int64, error) { @@ -157,7 +85,7 @@ func (w *warehouseService) GetAll(ctx context.Context, filter query.WarehouseFil } var responses []dtodomain.WarehouseResponse for _, e := range warehouses { - responses = append(responses, toWarehouseResponse(e)) + responses = append(responses, dtodomain.ToWarehouseResponse(e)) } if responses == nil { responses = make([]dtodomain.WarehouseResponse, 0) @@ -177,6 +105,7 @@ func (w *warehouseService) Update(ctx context.Context, req dtodomain.WarehouseUp tx.Rollback() return dtodomain.WarehouseResponse{}, err } + before := warehouse if req.Code != "" { warehouse.Code = req.Code } @@ -193,6 +122,7 @@ func (w *warehouseService) Update(ctx context.Context, req dtodomain.WarehouseUp } } warehouse.PICID = utils.ParseNullableUUID(req.PICID) + warehouse.FullAuditTrail = utils.FillAuditTrail(ctx, constants.UPDATE) updated, err := w.warehouseRepo.Update(ctx, tx, warehouse) if err != nil { tx.Rollback() @@ -203,7 +133,15 @@ func (w *warehouseService) Update(ctx context.Context, req dtodomain.WarehouseUp if err != nil { return dtodomain.WarehouseResponse{}, err } - return toWarehouseResponse(result), nil + changes := utils.GetChangedFields(before, result) + w.log.WithFields(logrus.Fields{ + "user_id": utils.GetUserID(ctx), + "action": "update", + "entity": "warehouse", + "entity_id": warehouseId, + "changes": changes, + }).Info("Warehouse updated") + return dtodomain.ToWarehouseResponse(result), nil } func (w *warehouseService) Delete(ctx context.Context, warehouseId string) error { @@ -213,17 +151,34 @@ func (w *warehouseService) Delete(ctx context.Context, warehouseId string) error tx.Rollback() } }() + warehouse, err := w.warehouseRepo.GetById(ctx, tx, warehouseId) + if err != nil { + tx.Rollback() + return err + } + warehouse.FullAuditTrail = utils.FillAuditTrail(ctx, constants.DELETE) + if _, err := w.warehouseRepo.Update(ctx, tx, warehouse); err != nil { + tx.Rollback() + return err + } if err := w.warehouseRepo.Delete(ctx, tx, warehouseId); err != nil { tx.Rollback() return err } tx.Commit() + w.log.WithFields(logrus.Fields{ + "user_id": utils.GetUserID(ctx), + "action": "delete", + "entity": "warehouse", + "entity_id": warehouseId, + }).Info("Warehouse deleted") return nil } -func NewWarehouseService(warehouseRepo repository.WarehouseRepository, db *gorm.DB) WarehouseService { +func NewWarehouseService(warehouseRepo repository.WarehouseRepository, db *gorm.DB, log *logrus.Logger) WarehouseService { return &warehouseService{ warehouseRepo: warehouseRepo, db: db, + log: log, } } diff --git a/providers/core.go b/providers/core.go index 5bbb4ce..c15c14e 100644 --- a/providers/core.go +++ b/providers/core.go @@ -184,7 +184,7 @@ func RegisterDependencies(injector *do.Injector) { categoryServ := categoryService.NewCategoryService(categoryRepository, db) uomServ := uomService.NewUomService(uomRepository, sequenceServ, db, log) mvendorServ := mvendorService.NewVendorService(mvendorRepository, sequenceServ, db) - warehouseServ := warehouseService.NewWarehouseService(warehouseRepository, db) + warehouseServ := warehouseService.NewWarehouseService(warehouseRepository, db, log) zonaServ := zonaService.NewZonaService(zonaRepository, db) aisleServ := aisleService.NewAisleService(aisleRepository, db) inventoryReceiptServ := inventoryReceiptService.NewInventoryReceiptService(db, inventoryReceiptRepository, inventoryReceiptLineRepository, productRepository, uomRepository, inventoryStorageRepository, sequenceServ)