package service import ( "context" "time" "github.com/Caknoooo/go-gin-clean-starter/database/entities" invstoragerepository "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_storage/repository" productrepository "github.com/Caknoooo/go-gin-clean-starter/modules/product/repository" dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/quarantine/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/quarantine/query" "github.com/Caknoooo/go-gin-clean-starter/modules/quarantine/repository" uomrepository "github.com/Caknoooo/go-gin-clean-starter/modules/uom/repository" "github.com/google/uuid" "gorm.io/gorm" ) type QuarantineService interface { Create(ctx context.Context, req dtodomain.QuarantineCreateRequest) (dtodomain.QuarantineResponse, error) GetById(ctx context.Context, id string) (dtodomain.QuarantineResponse, error) GetAll(ctx context.Context, filter query.QuarantineFilter) ([]dtodomain.QuarantineResponse, int64, error) Update(ctx context.Context, req dtodomain.QuarantineUpdateRequest, id string) (dtodomain.QuarantineResponse, error) Delete(ctx context.Context, id string) error CreateLine(ctx context.Context, quarantineId string, req dtodomain.QuarantineLineCreateRequest) (dtodomain.QuarantineLineResponse, error) UpdateLine(ctx context.Context, lineId string, req dtodomain.QuarantineLineUpdateRequest) (dtodomain.QuarantineLineResponse, error) DeleteLine(ctx context.Context, lineId string) error OnComplete(ctx context.Context, id string) (dtodomain.QuarantineResponse, error) } type quarantineService struct { db *gorm.DB quarantineRepo repository.QuarantineRepository quarantineLineRepo repository.QuarantineLineRepository productRepo productrepository.ProductRepository } func NewQuarantineService(db *gorm.DB, quarantineRepo repository.QuarantineRepository, quarantineLineRepo repository.QuarantineLineRepository, productRepo productrepository.ProductRepository, uomRepo uomrepository.UomRepository, invStorageRepository invstoragerepository.InventoryStorageRepository) QuarantineService { return &quarantineService{ db: db, quarantineRepo: quarantineRepo, quarantineLineRepo: quarantineLineRepo, productRepo: productRepo, } } func (s *quarantineService) Create(ctx context.Context, req dtodomain.QuarantineCreateRequest) (dtodomain.QuarantineResponse, error) { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() entity := entities.TInventoryQuarantineEntity{ DocumentNumber: req.ReferenceNumber, DocumentDate: parseDate(req.DocumentDate), Status: req.Status, ClientID: parseUUID(req.ClientID), } created, err := s.quarantineRepo.Create(ctx, tx, entity) if err != nil { tx.Rollback() return dtodomain.QuarantineResponse{}, err } var lines []entities.TInventoryQuarantineLineEntity for _, lineReq := range req.QuarantineLines { line := entities.TInventoryQuarantineLineEntity{ QuarantineID: created.ID, ProductID: parseUUID(lineReq.ProductID), ClientID: parseUUID(lineReq.ClientID), } lines = append(lines, line) } if len(lines) > 0 { err = s.quarantineLineRepo.BulkCreate(ctx, tx, lines) if err != nil { tx.Rollback() return dtodomain.QuarantineResponse{}, err } } tx.Commit() return mapQuarantineToResponse(created, lines), nil } func (s *quarantineService) GetById(ctx context.Context, id string) (dtodomain.QuarantineResponse, error) { entity, err := s.quarantineRepo.GetById(ctx, nil, id) if err != nil { return dtodomain.QuarantineResponse{}, err } lines, _ := s.quarantineLineRepo.GetAllByQuarantineId(ctx, id) return mapQuarantineToResponse(entity, lines), nil } func (s *quarantineService) GetAll(ctx context.Context, filter query.QuarantineFilter) ([]dtodomain.QuarantineResponse, int64, error) { entities, total, err := s.quarantineRepo.GetAll(ctx, filter) if err != nil { return nil, 0, err } var responses []dtodomain.QuarantineResponse for _, entity := range entities { lines, _ := s.quarantineLineRepo.GetAllByQuarantineId(ctx, entity.ID.String()) responses = append(responses, mapQuarantineToResponse(entity, lines)) } return responses, total, nil } func (s *quarantineService) Update(ctx context.Context, req dtodomain.QuarantineUpdateRequest, id string) (dtodomain.QuarantineResponse, error) { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() entity, err := s.quarantineRepo.GetById(ctx, tx, id) if err != nil { tx.Rollback() return dtodomain.QuarantineResponse{}, err } entity.DocumentNumber = req.ReferenceNumber entity.DocumentDate = parseDate(req.DocumentDate) entity.Status = req.Status updated, err := s.quarantineRepo.Update(ctx, tx, entity) if err != nil { tx.Rollback() return dtodomain.QuarantineResponse{}, err } tx.Commit() lines, _ := s.quarantineLineRepo.GetAllByQuarantineId(ctx, id) return mapQuarantineToResponse(updated, lines), nil } func (s *quarantineService) Delete(ctx context.Context, id string) error { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() if err := s.quarantineLineRepo.DeleteByQuarantineId(ctx, tx, id); err != nil { tx.Rollback() return err } if err := s.quarantineRepo.Delete(ctx, tx, id); err != nil { tx.Rollback() return err } tx.Commit() return nil } func (s *quarantineService) CreateLine(ctx context.Context, quarantineId string, req dtodomain.QuarantineLineCreateRequest) (dtodomain.QuarantineLineResponse, error) { line := entities.TInventoryQuarantineLineEntity{ QuarantineID: parseUUID(quarantineId), ProductID: parseUUID(req.ProductID), ClientID: parseUUID(req.ClientID), } created, err := s.quarantineLineRepo.Create(ctx, nil, line) if err != nil { return dtodomain.QuarantineLineResponse{}, err } return mapQuarantineLineToResponse(created), nil } func (s *quarantineService) UpdateLine(ctx context.Context, lineId string, req dtodomain.QuarantineLineUpdateRequest) (dtodomain.QuarantineLineResponse, error) { line, err := s.quarantineLineRepo.GetById(ctx, nil, lineId) if err != nil { return dtodomain.QuarantineLineResponse{}, err } line.ProductID = parseUUID(req.ProductID) line.ClientID = parseUUID(req.ClientID) updated, err := s.quarantineLineRepo.Update(ctx, nil, line) if err != nil { return dtodomain.QuarantineLineResponse{}, err } return mapQuarantineLineToResponse(updated), nil } func (s *quarantineService) DeleteLine(ctx context.Context, lineId string) error { return s.quarantineLineRepo.Delete(ctx, nil, lineId) } func (s *quarantineService) OnComplete(ctx context.Context, id string) (dtodomain.QuarantineResponse, error) { entity, err := s.quarantineRepo.GetById(ctx, nil, id) if err != nil { return dtodomain.QuarantineResponse{}, err } entity.Status = "completed" updated, err := s.quarantineRepo.Update(ctx, nil, entity) if err != nil { return dtodomain.QuarantineResponse{}, err } lines, _ := s.quarantineLineRepo.GetAllByQuarantineId(ctx, id) return mapQuarantineToResponse(updated, lines), nil } func parseUUID(id string) uuid.UUID { uid, _ := uuid.Parse(id) return uid } func parseDate(dateStr string) time.Time { t, _ := time.Parse("2006-01-02", dateStr) return t } func mapQuarantineToResponse(entity entities.TInventoryQuarantineEntity, lines []entities.TInventoryQuarantineLineEntity) dtodomain.QuarantineResponse { resp := dtodomain.QuarantineResponse{ ID: entity.ID.String(), DocumentNumber: entity.DocumentNumber, DocumentDate: entity.DocumentDate.Format("2006-01-02"), Status: entity.Status, WarehouseID: entity.WarehouseID.String(), ZonaID: entity.ZonaID.String(), ClientID: entity.ClientID.String(), Warehouse: entity.Warehouse.Name, Zona: entity.Zona.Name, Client: entity.Client.Name, } for _, line := range lines { resp.QuarantineLines = append(resp.QuarantineLines, mapQuarantineLineToResponse(line)) } return resp } func mapQuarantineLineToResponse(line entities.TInventoryQuarantineLineEntity) dtodomain.QuarantineLineResponse { return dtodomain.QuarantineLineResponse{ ID: line.ID.String(), QuarantineID: line.QuarantineID.String(), StorageID: line.StorageID.String(), ProductID: line.ProductID.String(), ClientID: line.ClientID.String(), Product: line.Product.Name, Storage: line.StorageID.String(), // gunakan StorageID, karena field Name tidak ada Quarantine: line.Quarantine.DocumentNumber, Client: line.Client.Name, } }