package service import ( "context" "github.com/Caknoooo/go-gin-clean-starter/database/entities" dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_issue/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_issue/query" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_issue/repository" sequenceservice "github.com/Caknoooo/go-gin-clean-starter/modules/sequence/service" pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto" "github.com/Caknoooo/go-gin-clean-starter/pkg/utils" "github.com/google/uuid" "gorm.io/gorm" ) type InventoryIssueService interface { Create(ctx context.Context, req dtodomain.InventoryIssueCreateRequest) (dtodomain.InventoryIssueResponse, error) GetById(ctx context.Context, id string) (dtodomain.InventoryIssueResponse, error) GetAll(ctx context.Context, filter query.InventoryIssueFilter) ([]dtodomain.InventoryIssueResponse, int64, error) Update(ctx context.Context, req dtodomain.InventoryIssueUpdateRequest, id string) (dtodomain.InventoryIssueResponse, error) Delete(ctx context.Context, id string) error GetLinesByIssueId(ctx context.Context, issueId string) ([]dtodomain.InventoryIssueLineResponse, error) CreateLine(ctx context.Context, issueId string, req dtodomain.InventoryIssueLineCreateRequest) (dtodomain.InventoryIssueLineResponse, error) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryIssueLineUpdateRequest) (dtodomain.InventoryIssueLineResponse, error) DeleteLine(ctx context.Context, lineId string) error } type inventoryIssueService struct { db *gorm.DB issueRepo repository.InventoryIssueRepository issueLineRepo repository.InventoryIssueLineRepository sequenceService sequenceservice.SequenceService } // GetLinesByIssueId implements InventoryIssueService. func (s *inventoryIssueService) GetLinesByIssueId(ctx context.Context, issueId string) ([]dtodomain.InventoryIssueLineResponse, error) { lines, err := s.issueLineRepo.GetAllByIssueId(ctx, issueId) if err != nil { return nil, err } return dtodomain.ToInventoryIssueLineResponses(lines), nil } func NewInventoryIssueService(db *gorm.DB, issueRepo repository.InventoryIssueRepository, issueLineRepo repository.InventoryIssueLineRepository, sequenceService sequenceservice.SequenceService) InventoryIssueService { return &inventoryIssueService{db: db, issueRepo: issueRepo, issueLineRepo: issueLineRepo, sequenceService: sequenceService} } func (s *inventoryIssueService) Create(ctx context.Context, req dtodomain.InventoryIssueCreateRequest) (dtodomain.InventoryIssueResponse, error) { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() clientUUID, err := uuid.Parse(req.ClientID) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } issuerUUID, err := uuid.Parse(req.IssuerBy) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } invRequestUUID, err := uuid.Parse(req.InvRequestID) if err != nil && req.InvRequestID != "" { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } docNum, err := s.sequenceService.GenerateDocumentNumber(ctx, req.ClientID, "ISSUE", pkgdto.SequenceConfig{ Prefix: "ISSUE", EntityType: "INV_ISSUE", Period: "", }) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } issue := entities.TInventoryIssueEntity{ DocumentNumber: docNum, DocumentDate: utils.StringToDateTime(req.DocumentDate), DueDate: utils.StringToDateTime(req.DueDate), IssuerBy: issuerUUID, InvRequestID: invRequestUUID, ClientID: clientUUID, Status: req.Status, } created, err := s.issueRepo.Create(ctx, tx, issue) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } // Bulk create lines var lines []entities.TInventoryIssueLineEntity for _, lineReq := range req.IssueLines { productUUID, err := uuid.Parse(lineReq.ProductID) if err != nil && lineReq.ProductID != "" { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } warehouseUUID, err := uuid.Parse(lineReq.WarehouseID) if err != nil && lineReq.WarehouseID != "" { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } clientLineUUID, err := uuid.Parse(lineReq.ClientID) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } lines = append(lines, entities.TInventoryIssueLineEntity{ CurrentStock: lineReq.CurrentStock, MinStock: lineReq.MinStock, RequestQuantity: lineReq.RequestQuantity, IssuedQuantity: lineReq.IssuedQuantity, Remarks: lineReq.Remarks, InvIssueID: created.ID, ProductID: productUUID, WarehouseID: warehouseUUID, ClientID: clientLineUUID, }) } if len(lines) > 0 { err = s.issueLineRepo.BulkCreate(ctx, tx, lines) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } } tx.Commit() result, err := s.issueRepo.GetById(ctx, nil, created.ID.String()) if err != nil { return dtodomain.InventoryIssueResponse{}, err } return dtodomain.ToInventoryIssueResponse(result), nil } func (s *inventoryIssueService) GetById(ctx context.Context, id string) (dtodomain.InventoryIssueResponse, error) { issue, err := s.issueRepo.GetById(ctx, nil, id) if err != nil { return dtodomain.InventoryIssueResponse{}, err } return dtodomain.ToInventoryIssueResponse(issue), nil } func (s *inventoryIssueService) GetAll(ctx context.Context, filter query.InventoryIssueFilter) ([]dtodomain.InventoryIssueResponse, int64, error) { issues, total, err := s.issueRepo.GetAll(ctx, filter) if err != nil { return nil, 0, err } var responses []dtodomain.InventoryIssueResponse for _, e := range issues { responses = append(responses, dtodomain.ToInventoryIssueResponse(e)) } if responses == nil { responses = make([]dtodomain.InventoryIssueResponse, 0) } return responses, total, nil } func (s *inventoryIssueService) Update(ctx context.Context, req dtodomain.InventoryIssueUpdateRequest, id string) (dtodomain.InventoryIssueResponse, error) { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() issue, err := s.issueRepo.GetById(ctx, tx, id) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } issue.DocumentDate = utils.StringToDateTime(req.DocumentDate) issue.DueDate = utils.StringToDateTime(req.DueDate) issue.Status = req.Status updated, err := s.issueRepo.Update(ctx, tx, issue) if err != nil { tx.Rollback() return dtodomain.InventoryIssueResponse{}, err } tx.Commit() result, err := s.issueRepo.GetById(ctx, nil, updated.ID.String()) if err != nil { return dtodomain.InventoryIssueResponse{}, err } return dtodomain.ToInventoryIssueResponse(result), nil } func (s *inventoryIssueService) Delete(ctx context.Context, id string) error { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() if err := s.issueRepo.Delete(ctx, tx, id); err != nil { tx.Rollback() return err } tx.Commit() return nil } func (s *inventoryIssueService) CreateLine(ctx context.Context, issueId string, req dtodomain.InventoryIssueLineCreateRequest) (dtodomain.InventoryIssueLineResponse, error) { issueUUID, err := uuid.Parse(issueId) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } productUUID, err := uuid.Parse(req.ProductID) if err != nil && req.ProductID != "" { return dtodomain.InventoryIssueLineResponse{}, err } warehouseUUID, err := uuid.Parse(req.WarehouseID) if err != nil && req.WarehouseID != "" { return dtodomain.InventoryIssueLineResponse{}, err } clientLineUUID, err := uuid.Parse(req.ClientID) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } line := entities.TInventoryIssueLineEntity{ CurrentStock: req.CurrentStock, MinStock: req.MinStock, RequestQuantity: req.RequestQuantity, IssuedQuantity: req.IssuedQuantity, Remarks: req.Remarks, InvIssueID: issueUUID, ProductID: productUUID, WarehouseID: warehouseUUID, ClientID: clientLineUUID, } created, err := s.issueLineRepo.Create(ctx, nil, line) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } product := dtodomain.InventoryIssueProductResponse{} if created.Product.ID != uuid.Nil { product = dtodomain.InventoryIssueProductResponse{ ID: created.Product.ID.String(), RefNumber: created.Product.RefNumber, Name: created.Product.Name, } } warehouse := pkgdto.IdNameResponse{} if created.Warehouse.ID != uuid.Nil { warehouse = pkgdto.IdNameResponse{ ID: created.Warehouse.ID.String(), Name: created.Warehouse.Name, } } clientLine := pkgdto.IdNameResponse{} if created.Client.ID != uuid.Nil { clientLine = pkgdto.IdNameResponse{ ID: created.Client.ID.String(), Name: created.Client.Name, } } return dtodomain.InventoryIssueLineResponse{ ID: created.ID.String(), CurrentStock: created.CurrentStock, MinStock: created.MinStock, RequestQuantity: created.RequestQuantity, IssuedQuantity: created.IssuedQuantity, Remarks: created.Remarks, Product: product, Warehouse: warehouse, Client: clientLine, }, nil } func (s *inventoryIssueService) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryIssueLineUpdateRequest) (dtodomain.InventoryIssueLineResponse, error) { line, err := s.issueLineRepo.GetById(ctx, nil, lineId) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } if req.CurrentStock != nil { line.CurrentStock = *req.CurrentStock } if req.MinStock != nil { line.MinStock = *req.MinStock } if req.RequestQuantity != nil { line.RequestQuantity = *req.RequestQuantity } if req.IssuedQuantity != nil { line.IssuedQuantity = *req.IssuedQuantity } if req.Remarks != nil { line.Remarks = *req.Remarks } if req.ProductID != nil { if *req.ProductID != "" { tmp, err := uuid.Parse(*req.ProductID) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } line.ProductID = tmp } else { line.ProductID = uuid.Nil } } if req.WarehouseID != nil { if *req.WarehouseID != "" { tmp, err := uuid.Parse(*req.WarehouseID) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } line.WarehouseID = tmp } else { line.WarehouseID = uuid.Nil } } if req.ClientID != nil { if *req.ClientID != "" { tmp, err := uuid.Parse(*req.ClientID) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } line.ClientID = tmp } else { line.ClientID = uuid.Nil } } updated, err := s.issueLineRepo.Update(ctx, nil, line) if err != nil { return dtodomain.InventoryIssueLineResponse{}, err } product := dtodomain.InventoryIssueProductResponse{} if updated.Product.ID != uuid.Nil { product = dtodomain.InventoryIssueProductResponse{ ID: updated.Product.ID.String(), RefNumber: updated.Product.RefNumber, Name: updated.Product.Name, } } warehouse := pkgdto.IdNameResponse{} if updated.Warehouse.ID != uuid.Nil { warehouse = pkgdto.IdNameResponse{ ID: updated.Warehouse.ID.String(), Name: updated.Warehouse.Name, } } clientLine := pkgdto.IdNameResponse{} if updated.Client.ID != uuid.Nil { clientLine = pkgdto.IdNameResponse{ ID: updated.Client.ID.String(), Name: updated.Client.Name, } } return dtodomain.InventoryIssueLineResponse{ ID: updated.ID.String(), CurrentStock: updated.CurrentStock, MinStock: updated.MinStock, RequestQuantity: updated.RequestQuantity, IssuedQuantity: updated.IssuedQuantity, Remarks: updated.Remarks, Product: product, Warehouse: warehouse, Client: clientLine, }, nil } func (s *inventoryIssueService) DeleteLine(ctx context.Context, lineId string) error { return s.issueLineRepo.Delete(ctx, nil, lineId) }