package service import ( "context" "github.com/Caknoooo/go-gin-clean-starter/database/entities" dtodomain "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/dto" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/query" "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_receipt/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 InventoryReceiptService interface { Create(ctx context.Context, req dtodomain.InventoryReceiptCreateRequest) (dtodomain.InventoryReceiptResponse, error) GetById(ctx context.Context, id string) (dtodomain.InventoryReceiptResponse, error) GetAll(ctx context.Context, filter query.InventoryReceiptFilter) ([]dtodomain.InventoryReceiptResponse, int64, error) Update(ctx context.Context, req dtodomain.InventoryReceiptUpdateRequest, id string) (dtodomain.InventoryReceiptResponse, error) Delete(ctx context.Context, id string) error CreateLine(ctx context.Context, receiptId string, req dtodomain.InventoryReceiptLineCreateRequest) (dtodomain.InventoryReceiptLineResponse, error) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryReceiptLineUpdateRequest) (dtodomain.InventoryReceiptLineResponse, error) DeleteLine(ctx context.Context, lineId string) error } type inventoryReceiptService struct { db *gorm.DB receiptRepo repository.InventoryReceiptRepository receiptLineRepo repository.InventoryReceiptLineRepository } // DeleteLine implements InventoryReceiptService. func (s *inventoryReceiptService) DeleteLine(ctx context.Context, lineId string) error { return s.receiptLineRepo.Delete(ctx, nil, lineId) } // UpdateLine implements InventoryReceiptService. func (s *inventoryReceiptService) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryReceiptLineUpdateRequest) (dtodomain.InventoryReceiptLineResponse, error) { line, err := s.receiptLineRepo.GetById(ctx, nil, lineId) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } if req.Quantity != nil { line.Quantity = *req.Quantity } if req.BatchNumber != nil { line.BatchNumber = *req.BatchNumber } if req.RepackingSuggestion != nil { line.RepackingSuggestion = *req.RepackingSuggestion } if req.RepackUomID != nil { if *req.RepackUomID != "" { tmp, err := uuid.Parse(*req.RepackUomID) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } line.RepackUomID = &tmp } else { line.RepackUomID = nil } } if req.ProductID != nil { if *req.ProductID != "" { tmp, err := uuid.Parse(*req.ProductID) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } line.ProductID = tmp } else { line.ProductID = uuid.Nil } } updated, err := s.receiptLineRepo.Update(ctx, nil, line) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } var repackUomID *string if updated.RepackUomID != nil { tmp := updated.RepackUomID.String() repackUomID = &tmp } product := dtodomain.InventoryReceiptLineProductResponse{} if updated.Product.ID != uuid.Nil { product = dtodomain.InventoryReceiptLineProductResponse{ ID: updated.Product.ID.String(), Name: updated.Product.Name, } } return dtodomain.InventoryReceiptLineResponse{ ID: updated.ID.String(), Quantity: updated.Quantity, BatchNumber: updated.BatchNumber, RepackingSuggestion: updated.RepackingSuggestion, RepackUomID: repackUomID, Product: product, ClientID: updated.ClientID.String(), }, nil } func toAssignmentResponse(e entities.TAssignmentEntity) dtodomain.AssignmentResponse { // client := pkgdto.IdNameResponse{} // if e.Client.ID != uuid.Nil { // client = pkgdto.IdNameResponse{ // ID: e.Client.ID.String(), // Name: e.Client.Name, // } // } 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}, // Client: pkgdto.IdNameResponse{ID: user.Client.ID.String(), Name: user.Client.Name}, } users = append(users, userResp) } return dtodomain.AssignmentResponse{ ID: e.ID.String(), DocumentType: e.DocumentType, DocumentID: e.DocumentID.String(), // Client: client, AssignmentUsers: users, } } func toInventoryReceiptResponse(e entities.TInventoryReceiptEntity) dtodomain.InventoryReceiptResponse { client := pkgdto.IdNameResponse{} if e.Client.ID != uuid.Nil { client = pkgdto.IdNameResponse{ ID: e.Client.ID.String(), Name: e.Client.Name, } } lines := make([]dtodomain.InventoryReceiptLineResponse, 0) for _, line := range e.ReceiptLines { product := dtodomain.InventoryReceiptLineProductResponse{} if line.Product.ID != uuid.Nil { product = dtodomain.InventoryReceiptLineProductResponse{ 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, }, DimLength: line.Product.DimLength, DimWidth: line.Product.DimWidth, DimHeight: line.Product.DimHeight, DimUom: pkgdto.IdNameResponse{ ID: line.Product.DimUom.ID.String(), Name: line.Product.DimUom.Name, }, } } var repackUomID *string if line.RepackUomID != nil { tmp := line.RepackUomID.String() repackUomID = &tmp } else { repackUomID = nil } lines = append(lines, dtodomain.InventoryReceiptLineResponse{ ID: line.ID.String(), Quantity: line.Quantity, BatchNumber: line.BatchNumber, RepackingSuggestion: line.RepackingSuggestion, RepackUomID: repackUomID, Product: product, ClientID: line.ClientID.String(), }) } assignment := dtodomain.AssignmentResponse{} if e.Assignment.ID != uuid.Nil { assignment = toAssignmentResponse(e.Assignment) } return dtodomain.InventoryReceiptResponse{ ID: e.ID.String(), ReferenceNumber: e.ReferenceNumber, DocumentNumber: e.DocumentNumber, Status: e.Status, DocumentDate: utils.DateTimeToString(e.DocumentDate), Source: e.Source, QrCodeFile: e.QrCodeFile, // ClientID: e.ClientID.String(), Client: client, LineCount: len(lines), ReceiptLines: lines, Assignment: assignment, } } func (s *inventoryReceiptService) Create(ctx context.Context, req dtodomain.InventoryReceiptCreateRequest) (dtodomain.InventoryReceiptResponse, 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.InventoryReceiptResponse{}, err } docNum, err := entities.GenerateDocumentNumber(s.db, req.ClientID) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } receipt := entities.TInventoryReceiptEntity{ ReferenceNumber: req.ReferenceNumber, DocumentNumber: docNum, DocumentDate: utils.StringToDateTime(req.DocumentDate), Source: req.Source, QrCodeFile: req.QrCodeFile, ClientID: clientUUID, Status: req.Status, } created, err := s.receiptRepo.Create(ctx, tx, receipt) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } // Bulk create lines var lines []entities.TInventoryReceiptLineEntity for _, lineReq := range req.ReceiptLines { var productUUID uuid.UUID if lineReq.ProductID != "" { productUUID, err = uuid.Parse(lineReq.ProductID) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } } else { productUUID = uuid.Nil } var repackUomUUID *uuid.UUID if lineReq.RepackUomID != "" { tmp, err := uuid.Parse(lineReq.RepackUomID) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } repackUomUUID = &tmp } else { repackUomUUID = nil } clientLineUUID, err := uuid.Parse(lineReq.ClientID) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } lines = append(lines, entities.TInventoryReceiptLineEntity{ Quantity: lineReq.Quantity, BatchNumber: lineReq.BatchNumber, RepackingSuggestion: lineReq.RepackingSuggestion, RepackUomID: repackUomUUID, InvReceiptID: created.ID, ProductID: productUUID, ClientID: clientLineUUID, }) } if len(lines) > 0 { err = s.receiptLineRepo.BulkCreate(ctx, tx, lines) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } } tx.Commit() result, err := s.receiptRepo.GetById(ctx, nil, created.ID.String()) if err != nil { return dtodomain.InventoryReceiptResponse{}, err } return toInventoryReceiptResponse(result), nil } func (s *inventoryReceiptService) GetById(ctx context.Context, id string) (dtodomain.InventoryReceiptResponse, error) { receipt, err := s.receiptRepo.GetById(ctx, nil, id) if err != nil { return dtodomain.InventoryReceiptResponse{}, err } return toInventoryReceiptResponse(receipt), nil } func (s *inventoryReceiptService) GetAll(ctx context.Context, filter query.InventoryReceiptFilter) ([]dtodomain.InventoryReceiptResponse, int64, error) { receipts, total, err := s.receiptRepo.GetAll(ctx, filter) if err != nil { return nil, 0, err } var responses []dtodomain.InventoryReceiptResponse for _, e := range receipts { responses = append(responses, toInventoryReceiptResponse(e)) } if responses == nil { responses = make([]dtodomain.InventoryReceiptResponse, 0) } return responses, total, nil } func (s *inventoryReceiptService) Update(ctx context.Context, req dtodomain.InventoryReceiptUpdateRequest, id string) (dtodomain.InventoryReceiptResponse, error) { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() receipt, err := s.receiptRepo.GetById(ctx, tx, id) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } if req.ReferenceNumber != "" { receipt.ReferenceNumber = req.ReferenceNumber } receipt.DocumentDate = utils.StringToDateTime(req.DocumentDate) receipt.Source = req.Source receipt.QrCodeFile = req.QrCodeFile receipt.Status = req.Status updated, err := s.receiptRepo.Update(ctx, tx, receipt) if err != nil { tx.Rollback() return dtodomain.InventoryReceiptResponse{}, err } tx.Commit() result, err := s.receiptRepo.GetById(ctx, nil, updated.ID.String()) if err != nil { return dtodomain.InventoryReceiptResponse{}, err } return toInventoryReceiptResponse(result), nil } func (s *inventoryReceiptService) Delete(ctx context.Context, id string) error { tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() if err := s.receiptRepo.Delete(ctx, tx, id); err != nil { tx.Rollback() return err } tx.Commit() return nil } func (s *inventoryReceiptService) CreateLine(ctx context.Context, receiptId string, req dtodomain.InventoryReceiptLineCreateRequest) (dtodomain.InventoryReceiptLineResponse, error) { receiptUUID, err := uuid.Parse(receiptId) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } var productUUID uuid.UUID if req.ProductID != "" { productUUID, err = uuid.Parse(req.ProductID) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } } else { productUUID = uuid.Nil } var repackUomUUID *uuid.UUID if req.RepackUomID != "" { tmp, err := uuid.Parse(req.RepackUomID) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } repackUomUUID = &tmp } else { repackUomUUID = nil } clientLineUUID, err := uuid.Parse(req.ClientID) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } line := entities.TInventoryReceiptLineEntity{ Quantity: req.Quantity, BatchNumber: req.BatchNumber, RepackingSuggestion: req.RepackingSuggestion, RepackUomID: repackUomUUID, InvReceiptID: receiptUUID, ProductID: productUUID, ClientID: clientLineUUID, } created, err := s.receiptLineRepo.Create(ctx, nil, line) if err != nil { return dtodomain.InventoryReceiptLineResponse{}, err } var repackUomID *string if created.RepackUomID != nil { tmp := created.RepackUomID.String() repackUomID = &tmp } product := dtodomain.InventoryReceiptLineProductResponse{} if created.Product.ID != uuid.Nil { product = dtodomain.InventoryReceiptLineProductResponse{ ID: created.Product.ID.String(), Name: created.Product.Name, } } return dtodomain.InventoryReceiptLineResponse{ ID: created.ID.String(), Quantity: created.Quantity, BatchNumber: created.BatchNumber, RepackingSuggestion: created.RepackingSuggestion, RepackUomID: repackUomID, Product: product, ClientID: created.ClientID.String(), }, nil } func NewInventoryReceiptService(db *gorm.DB, receiptRepo repository.InventoryReceiptRepository, receiptLineRepo repository.InventoryReceiptLineRepository) InventoryReceiptService { return &inventoryReceiptService{ db: db, receiptRepo: receiptRepo, receiptLineRepo: receiptLineRepo, } }