wms-be/modules/inventory_issue/service/inventory_issue_service.go

468 lines
15 KiB
Go

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"
invrequestservice "github.com/Caknoooo/go-gin-clean-starter/modules/inventory_request/service"
sequenceservice "github.com/Caknoooo/go-gin-clean-starter/modules/sequence/service"
"github.com/Caknoooo/go-gin-clean-starter/pkg/constants"
pkgdto "github.com/Caknoooo/go-gin-clean-starter/pkg/dto"
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"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)
GetLineById(ctx context.Context, lineId 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
invRequestService invrequestservice.InventoryRequestService
sequenceService sequenceservice.SequenceService
log *logrus.Logger
}
// GetLineById implements InventoryIssueService.
func (s *inventoryIssueService) GetLineById(ctx context.Context, lineId string) (dtodomain.InventoryIssueLineResponse, error) {
line, err := s.issueLineRepo.GetById(ctx, nil, lineId)
if err != nil {
return dtodomain.InventoryIssueLineResponse{}, err
}
clientLine := pkgdto.IdNameResponse{}
if line.Client.ID != uuid.Nil {
clientLine = pkgdto.IdNameResponse{
ID: line.Client.ID.String(),
Name: line.Client.Name,
}
}
product := dtodomain.InventoryIssueProductResponse{}
if line.Product.ID != uuid.Nil {
product = dtodomain.InventoryIssueProductResponse{
ID: line.Product.ID.String(),
RefNumber: line.Product.RefNumber,
Name: line.Product.Name,
}
}
warehouse := pkgdto.IdNameResponse{}
if line.Warehouse.ID != uuid.Nil {
warehouse = pkgdto.IdNameResponse{
ID: line.Warehouse.ID.String(),
Name: line.Warehouse.Name,
}
}
return dtodomain.InventoryIssueLineResponse{
ID: line.ID.String(),
CurrentStock: line.CurrentStock,
MinStock: line.MinStock,
RequestQuantity: line.RequestQuantity,
IssuedQuantity: line.IssuedQuantity,
Remarks: line.Remarks,
Product: product,
Warehouse: warehouse,
Client: clientLine,
}, nil
}
// 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, invRequestService invrequestservice.InventoryRequestService, sequenceService sequenceservice.SequenceService, log *logrus.Logger) InventoryIssueService {
return &inventoryIssueService{db: db, issueRepo: issueRepo, issueLineRepo: issueLineRepo, invRequestService: invRequestService, sequenceService: sequenceService, log: log}
}
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
}
// get inventory request line by InvRequestID
invRequestLinesResponse, err := s.invRequestService.GetLinesByRequestId(ctx, invRequestUUID.String())
if err != nil {
tx.Rollback()
return dtodomain.InventoryIssueResponse{}, err
}
issue := entities.TInventoryIssueEntity{
DocumentNumber: docNum,
DocumentType: req.DocumentType,
DocumentDate: utils.StringToDateTime(req.DocumentDate),
DueDate: utils.StringToDateTime(req.DueDate),
IssuerBy: issuerUUID,
InvRequestID: invRequestUUID,
ClientID: clientUUID,
Status: req.Status,
FullAuditTrail: utils.FillAuditTrail(ctx, constants.CREATE),
}
created, err := s.issueRepo.Create(ctx, tx, issue)
if err != nil {
tx.Rollback()
return dtodomain.InventoryIssueResponse{}, err
}
// Bulk create lines from inv request lines InvRequestID
var lines []entities.TInventoryIssueLineEntity
for _, lineReq := range invRequestLinesResponse {
productUUID, err := uuid.Parse(lineReq.Product.ID)
if err != nil && lineReq.Product.ID != "" {
tx.Rollback()
return dtodomain.InventoryIssueResponse{}, err
}
warehouseID := utils.GetWarehouseID(ctx)
var warehouseUUID uuid.UUID
if warehouseID == "" {
warehouseUUID = uuid.Nil
} else {
warehouseUUID, err = uuid.Parse(warehouseID)
if err != nil {
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: 0,
RequestQuantity: lineReq.Quantity,
IssuedQuantity: 0,
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()
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "create",
"entity": "inventory_issue",
"entity_id": created.ID.String(),
}).Info("Inventory Issue created")
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
}
before := issue
issue.DocumentDate = utils.StringToDateTime(req.DocumentDate)
issue.DocumentType = req.DocumentType
issue.DueDate = utils.StringToDateTime(req.DueDate)
issue.Status = req.Status
issue.FullAuditTrail = utils.FillAuditTrail(ctx, constants.UPDATE)
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
}
changes := utils.GetChangedFields(before, result)
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "update",
"entity": "inventory_issue",
"entity_id": id,
"changes": changes,
}).Info("Inventory Issue updated")
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()
}
}()
issue, err := s.issueRepo.GetById(ctx, tx, id)
if err != nil {
tx.Rollback()
return err
}
issue.FullAuditTrail = utils.FillAuditTrail(ctx, constants.DELETE)
if _, err := s.issueRepo.Update(ctx, tx, issue); err != nil {
tx.Rollback()
return err
}
if err := s.issueRepo.Delete(ctx, tx, id); err != nil {
tx.Rollback()
return err
}
tx.Commit()
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "delete",
"entity": "inventory_issue",
"entity_id": id,
}).Info("Inventory Issue deleted")
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)
}