package service import ( "context" "github.com/Caknoooo/go-gin-clean-starter/database/entities" dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/query" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/repository" 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 InventoryRequestService interface { Create(ctx context.Context, req dtodomain.InventoryRequestCreateRequest) (dtodomain.InventoryRequestResponse, error) GetById(ctx context.Context, id string) (dtodomain.InventoryRequestResponse, error) GetAll(ctx context.Context, filter query.InventoryRequestFilter) ([]dtodomain.InventoryRequestResponse, int64, error) Update(ctx context.Context, req dtodomain.InventoryRequestUpdateRequest, id string) (dtodomain.InventoryRequestResponse, error) Delete(ctx context.Context, id string) error CreateLine(ctx context.Context, requestId string, req dtodomain.InventoryRequestLineCreateRequest) (dtodomain.InventoryRequestLineResponse, error) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryRequestLineUpdateRequest) (dtodomain.InventoryRequestLineResponse, error) DeleteLine(ctx context.Context, lineId string) error } type inventoryRequestService struct { db *gorm.DB requestRepo repository.InventoryRequestRepository requestLineRepo repository.InventoryRequestLineRepository } func (s *inventoryRequestService) DeleteLine(ctx context.Context, lineId string) error { return s.requestLineRepo.Delete(ctx, nil, lineId) } func (s *inventoryRequestService) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryRequestLineUpdateRequest) (dtodomain.InventoryRequestLineResponse, error) { line, err := s.requestLineRepo.GetById(ctx, nil, lineId) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } if req.Quantity != nil { line.Quantity = *req.Quantity } if req.ProductID != nil { if *req.ProductID != "" { tmp, err := uuid.Parse(*req.ProductID) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } line.ProductID = tmp } else { line.ProductID = uuid.Nil } } updated, err := s.requestLineRepo.Update(ctx, nil, line) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } product := dtodomain.InventoryRequestLineProductResponse{} if updated.Product.ID != uuid.Nil { product = dtodomain.InventoryRequestLineProductResponse{ ID: updated.Product.ID.String(), Name: updated.Product.Name, RefNumber: updated.Product.RefNumber, Uom: pkgdto.IdNameResponse{ ID: updated.Product.Uom.ID.String(), Name: updated.Product.Uom.Name, }, } } return dtodomain.InventoryRequestLineResponse{ ID: updated.ID.String(), Quantity: updated.Quantity, Product: product, ClientID: updated.ClientID.String(), }, nil } func toAssignmentResponse(e entities.TAssignmentEntity) dtodomain.AssignmentResponse { users := make([]dtodomain.AssignmentUserResponse, 0) for _, user := range e.AssignmentUsers { userResp := dtodomain.AssignmentUserResponse{ ID: user.ID.String(), TaskType: user.TaskType, User: pkgdto.IdNameResponse{ID: user.User.ID.String(), Name: user.User.Name}, Role: pkgdto.IdNameResponse{ID: user.Role.ID.String(), Name: user.Role.Name}, } users = append(users, userResp) } return dtodomain.AssignmentResponse{ ID: e.ID.String(), DocumentType: e.DocumentType, DocumentID: e.DocumentID.String(), AssignmentUsers: users, } } func toInventoryRequestResponse(e entities.TInventoryRequestEntity) dtodomain.InventoryRequestResponse { client := pkgdto.IdNameResponse{} if e.Client.ID != uuid.Nil { client = pkgdto.IdNameResponse{ ID: e.Client.ID.String(), Name: e.Client.Name, } } lines := make([]dtodomain.InventoryRequestLineResponse, 0) for _, line := range e.RequestLines { product := dtodomain.InventoryRequestLineProductResponse{} if line.Product.ID != uuid.Nil { product = dtodomain.InventoryRequestLineProductResponse{ ID: line.Product.ID.String(), Name: line.Product.Name, RefNumber: line.Product.RefNumber, Uom: pkgdto.IdNameResponse{ ID: line.Product.Uom.ID.String(), Name: line.Product.Uom.Name, }, } } lines = append(lines, dtodomain.InventoryRequestLineResponse{ ID: line.ID.String(), Quantity: line.Quantity, Product: product, ClientID: line.ClientID.String(), }) } assignment := dtodomain.AssignmentResponse{} if e.Assignment.ID != uuid.Nil { assignment = toAssignmentResponse(e.Assignment) } return dtodomain.InventoryRequestResponse{ ID: e.ID.String(), ReferenceNumber: e.ReferenceNumber, DocumentNumber: e.DocumentNumber, DueDate: utils.DateTimeToString(e.DueDate), RequestType: e.RequestType, Note: e.Note, Status: e.Status, Client: client, LineCount: len(lines), RequestLines: lines, Assignment: assignment, } } func (s *inventoryRequestService) Create(ctx context.Context, req dtodomain.InventoryRequestCreateRequest) (dtodomain.InventoryRequestResponse, 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.InventoryRequestResponse{}, err } docNum, err := entities.GenerateDocumentNumberInventoryRequest(s.db, req.ClientID) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } request := entities.TInventoryRequestEntity{ ReferenceNumber: req.ReferenceNumber, DocumentNumber: docNum, DueDate: utils.StringToDateTime(req.DueDate), RequestType: req.RequestType, Note: req.Note, ClientID: clientUUID, Status: req.Status, } created, err := s.requestRepo.Create(ctx, tx, request) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } var lines []entities.TInventoryRequestLineEntity for _, lineReq := range req.RequestLines { var productUUID uuid.UUID if lineReq.ProductID != "" { productUUID, err = uuid.Parse(lineReq.ProductID) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } } else { productUUID = uuid.Nil } clientLineUUID, err := uuid.Parse(lineReq.ClientID) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } lines = append(lines, entities.TInventoryRequestLineEntity{ Quantity: lineReq.Quantity, InvRequestID: created.ID, ProductID: productUUID, ClientID: clientLineUUID, }) } if len(lines) > 0 { err = s.requestLineRepo.BulkCreate(ctx, tx, lines) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } } tx.Commit() result, err := s.requestRepo.GetById(ctx, nil, created.ID.String()) if err != nil { return dtodomain.InventoryRequestResponse{}, err } return toInventoryRequestResponse(result), nil } func (s *inventoryRequestService) GetById(ctx context.Context, id string) (dtodomain.InventoryRequestResponse, error) { request, err := s.requestRepo.GetById(ctx, nil, id) if err != nil { return dtodomain.InventoryRequestResponse{}, err } return toInventoryRequestResponse(request), nil } func (s *inventoryRequestService) GetAll(ctx context.Context, filter query.InventoryRequestFilter) ([]dtodomain.InventoryRequestResponse, int64, error) { requests, total, err := s.requestRepo.GetAll(ctx, filter) if err != nil { return nil, 0, err } var responses []dtodomain.InventoryRequestResponse for _, e := range requests { responses = append(responses, toInventoryRequestResponse(e)) } if responses == nil { responses = make([]dtodomain.InventoryRequestResponse, 0) } return responses, total, nil } func (s *inventoryRequestService) Update(ctx context.Context, req dtodomain.InventoryRequestUpdateRequest, id string) (dtodomain.InventoryRequestResponse, error) { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() request, err := s.requestRepo.GetById(ctx, tx, id) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } if req.ReferenceNumber != "" { request.ReferenceNumber = req.ReferenceNumber } request.DocumentNumber = req.DocumentNumber request.DueDate = utils.StringToDateTime(req.DueDate) request.RequestType = req.RequestType request.Note = req.Note request.Status = req.Status updated, err := s.requestRepo.Update(ctx, tx, request) if err != nil { tx.Rollback() return dtodomain.InventoryRequestResponse{}, err } tx.Commit() result, err := s.requestRepo.GetById(ctx, nil, updated.ID.String()) if err != nil { return dtodomain.InventoryRequestResponse{}, err } return toInventoryRequestResponse(result), nil } func (s *inventoryRequestService) Delete(ctx context.Context, id string) error { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() if err := s.requestRepo.Delete(ctx, tx, id); err != nil { tx.Rollback() return err } tx.Commit() return nil } func (s *inventoryRequestService) CreateLine(ctx context.Context, requestId string, req dtodomain.InventoryRequestLineCreateRequest) (dtodomain.InventoryRequestLineResponse, error) { requestUUID, err := uuid.Parse(requestId) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } var productUUID uuid.UUID if req.ProductID != "" { productUUID, err = uuid.Parse(req.ProductID) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } } else { productUUID = uuid.Nil } clientLineUUID, err := uuid.Parse(req.ClientID) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } line := entities.TInventoryRequestLineEntity{ Quantity: req.Quantity, InvRequestID: requestUUID, ProductID: productUUID, ClientID: clientLineUUID, } created, err := s.requestLineRepo.Create(ctx, nil, line) if err != nil { return dtodomain.InventoryRequestLineResponse{}, err } product := dtodomain.InventoryRequestLineProductResponse{} if created.Product.ID != uuid.Nil { product = dtodomain.InventoryRequestLineProductResponse{ ID: created.Product.ID.String(), Name: created.Product.Name, RefNumber: created.Product.RefNumber, Uom: pkgdto.IdNameResponse{ ID: created.Product.Uom.ID.String(), Name: created.Product.Uom.Name, }, } } return dtodomain.InventoryRequestLineResponse{ ID: created.ID.String(), Quantity: created.Quantity, Product: product, ClientID: created.ClientID.String(), }, nil } func NewInventoryRequestService(db *gorm.DB, requestRepo repository.InventoryRequestRepository, requestLineRepo repository.InventoryRequestLineRepository) InventoryRequestService { return &inventoryRequestService{ db: db, requestRepo: requestRepo, requestLineRepo: requestLineRepo, } }