wms-be/modules/inventory_movement/service/inventory_movement_service.go

341 lines
12 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_movement/dto"
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/query"
"github.com/Caknoooo/go-gin-clean-starter/modules/inventory_movement/repository"
sequenceservice "github.com/Caknoooo/go-gin-clean-starter/modules/sequence/service"
"github.com/Caknoooo/go-gin-clean-starter/pkg/constants"
"github.com/Caknoooo/go-gin-clean-starter/pkg/utils"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
type InventoryMovementService interface {
Create(ctx context.Context, req dtodomain.InventoryMovementCreateRequest) (dtodomain.InventoryMovementResponse, error)
GetById(ctx context.Context, id string) (dtodomain.InventoryMovementResponse, error)
GetAll(ctx context.Context, filter query.InventoryMovementFilter) ([]dtodomain.InventoryMovementResponse, int64, error)
Update(ctx context.Context, req dtodomain.InventoryMovementUpdateRequest, id string) (dtodomain.InventoryMovementResponse, error)
Delete(ctx context.Context, id string) error
GetLinesByMovementId(ctx context.Context, movementId string) ([]dtodomain.InventoryMovementLineResponse, error)
GetLineById(ctx context.Context, lineId string) (dtodomain.InventoryMovementLineResponse, error)
CreateLine(ctx context.Context, movementId string, req dtodomain.InventoryMovementLineCreateRequest) (dtodomain.InventoryMovementLineResponse, error)
UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryMovementLineUpdateRequest) (dtodomain.InventoryMovementLineResponse, error)
DeleteLine(ctx context.Context, lineId string) error
}
type inventoryMovementService struct {
db *gorm.DB
movementRepo repository.InventoryMovementRepository
movementLineRepo repository.InventoryMovementLineRepository
sequenceService sequenceservice.SequenceService
log *logrus.Logger
}
// GetLineById implements InventoryMovementService.
func (s *inventoryMovementService) GetLineById(ctx context.Context, lineId string) (dtodomain.InventoryMovementLineResponse, error) {
line, err := s.movementLineRepo.GetById(ctx, nil, lineId)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
return dtodomain.ToInventoryMovementLineResponse(line), nil
}
// GetLinesByMovementId implements InventoryMovementService.
func (s *inventoryMovementService) GetLinesByMovementId(ctx context.Context, movementId string) ([]dtodomain.InventoryMovementLineResponse, error) {
lines, err := s.movementLineRepo.GetAllByMovementId(ctx, movementId)
if err != nil {
return nil, err
}
var responses []dtodomain.InventoryMovementLineResponse
for _, e := range lines {
responses = append(responses, dtodomain.ToInventoryMovementLineResponse(e))
}
if responses == nil {
responses = make([]dtodomain.InventoryMovementLineResponse, 0)
}
return responses, nil
}
func (s *inventoryMovementService) Create(ctx context.Context, req dtodomain.InventoryMovementCreateRequest) (dtodomain.InventoryMovementResponse, 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.InventoryMovementResponse{}, err
}
movNumber, err := entities.GenerateDocumentNumberInvMovement(s.db, req.ClientID)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
movement := entities.TInventoryMovementEntity{
MovementNumber: movNumber,
MovementDate: utils.StringToDateTime(req.MovementDate),
MovementType: req.MovementType,
ClientID: clientUUID,
Status: req.Status,
SourceLocationID: uuid.MustParse(req.SourceLocationID),
DestinationLocationID: uuid.MustParse(req.DestinationLocationID),
FullAuditTrail: utils.FillAuditTrail(ctx, constants.CREATE),
}
created, err := s.movementRepo.Create(ctx, tx, movement)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
// Bulk create lines
var lines []entities.TInventoryMovementLineEntity
for _, lineReq := range req.MovementLines {
productUUID := uuid.Nil
if lineReq.ProductID != "" {
productUUID, err = uuid.Parse(lineReq.ProductID)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
}
clientLineUUID, err := uuid.Parse(lineReq.ClientID)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
lines = append(lines, entities.TInventoryMovementLineEntity{
MovedQuantity: lineReq.MovedQuantity,
InvMovementID: created.ID,
ProductID: productUUID,
StorageID: uuid.MustParse(lineReq.StorageID),
ClientID: clientLineUUID,
Status: lineReq.Status,
})
}
if len(lines) > 0 {
err = s.movementLineRepo.BulkCreate(ctx, tx, lines)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
}
tx.Commit()
result, err := s.movementRepo.GetById(ctx, nil, created.ID.String())
if err != nil {
return dtodomain.InventoryMovementResponse{}, err
}
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "create",
"entity": "inventory_movement",
"entity_id": created.ID.String(),
}).Info("Inventory Movement created")
return dtodomain.ToInventoryMovementResponse(result), nil
}
func (s *inventoryMovementService) GetById(ctx context.Context, id string) (dtodomain.InventoryMovementResponse, error) {
movement, err := s.movementRepo.GetById(ctx, nil, id)
if err != nil {
return dtodomain.InventoryMovementResponse{}, err
}
return dtodomain.ToInventoryMovementResponse(movement), nil
}
func (s *inventoryMovementService) GetAll(ctx context.Context, filter query.InventoryMovementFilter) ([]dtodomain.InventoryMovementResponse, int64, error) {
movements, total, err := s.movementRepo.GetAll(ctx, filter)
if err != nil {
return nil, 0, err
}
var responses []dtodomain.InventoryMovementResponse
for _, e := range movements {
responses = append(responses, dtodomain.ToInventoryMovementResponse(e))
}
if responses == nil {
responses = make([]dtodomain.InventoryMovementResponse, 0)
}
return responses, total, nil
}
func (s *inventoryMovementService) Update(ctx context.Context, req dtodomain.InventoryMovementUpdateRequest, id string) (dtodomain.InventoryMovementResponse, error) {
tx := s.db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
movement, err := s.movementRepo.GetById(ctx, tx, id)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
before := movement
movement.MovementDate = utils.StringToDateTime(req.MovementDate)
movement.MovementType = req.MovementType
movement.Status = req.Status
movement.FullAuditTrail = utils.FillAuditTrail(ctx, constants.UPDATE)
updated, err := s.movementRepo.Update(ctx, tx, movement)
if err != nil {
tx.Rollback()
return dtodomain.InventoryMovementResponse{}, err
}
tx.Commit()
result, err := s.movementRepo.GetById(ctx, nil, updated.ID.String())
if err != nil {
return dtodomain.InventoryMovementResponse{}, err
}
changes := utils.GetChangedFields(before, result)
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "update",
"entity": "inventory_movement",
"entity_id": id,
"changes": changes,
}).Info("Inventory Movement updated")
return dtodomain.ToInventoryMovementResponse(result), nil
}
func (s *inventoryMovementService) Delete(ctx context.Context, id string) error {
tx := s.db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
movement, err := s.movementRepo.GetById(ctx, tx, id)
if err != nil {
tx.Rollback()
return err
}
movement.FullAuditTrail = utils.FillAuditTrail(ctx, constants.DELETE)
if _, err := s.movementRepo.Update(ctx, tx, movement); err != nil {
tx.Rollback()
return err
}
if err := s.movementRepo.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_movement",
"entity_id": id,
}).Info("Inventory Movement deleted")
return nil
}
func (s *inventoryMovementService) CreateLine(ctx context.Context, movementId string, req dtodomain.InventoryMovementLineCreateRequest) (dtodomain.InventoryMovementLineResponse, error) {
movementUUID, err := uuid.Parse(movementId)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
productUUID := uuid.Nil
if req.ProductID != "" {
productUUID, err = uuid.Parse(req.ProductID)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
}
clientLineUUID, err := uuid.Parse(req.ClientID)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
line := entities.TInventoryMovementLineEntity{
MovedQuantity: req.MovedQuantity,
InvMovementID: movementUUID,
ProductID: productUUID,
StorageID: uuid.MustParse(req.StorageID),
ClientID: clientLineUUID,
Status: req.Status,
FullAuditTrail: utils.FillAuditTrail(ctx, constants.CREATE),
}
created, err := s.movementLineRepo.Create(ctx, nil, line)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "create",
"entity": "inventory_movement_line",
"entity_id": created.ID.String(),
}).Info("Inventory Movement Line created")
return dtodomain.ToInventoryMovementLineResponse(created), nil
}
func (s *inventoryMovementService) UpdateLine(ctx context.Context, lineId string, req dtodomain.InventoryMovementLineUpdateRequest) (dtodomain.InventoryMovementLineResponse, error) {
line, err := s.movementLineRepo.GetById(ctx, nil, lineId)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
before := line
if req.MovedQuantity != nil {
line.MovedQuantity = *req.MovedQuantity
}
if req.Status != nil {
line.Status = *req.Status
}
updated, err := s.movementLineRepo.Update(ctx, nil, line)
if err != nil {
return dtodomain.InventoryMovementLineResponse{}, err
}
changes := utils.GetChangedFields(before, updated)
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "update",
"entity": "inventory_movement_line",
"entity_id": lineId,
"changes": changes,
}).Info("Inventory Movement Line updated")
return dtodomain.ToInventoryMovementLineResponse(updated), nil
}
func (s *inventoryMovementService) DeleteLine(ctx context.Context, lineId string) error {
line, err := s.movementLineRepo.GetById(ctx, nil, lineId)
if err != nil {
return err
}
line.FullAuditTrail = utils.FillAuditTrail(ctx, constants.DELETE)
if _, err := s.movementLineRepo.Update(ctx, nil, line); err != nil {
return err
}
result := s.movementLineRepo.Delete(ctx, nil, lineId)
if result != nil {
return result
}
s.log.WithFields(logrus.Fields{
"user_id": utils.GetUserID(ctx),
"action": "delete",
"entity": "inventory_movement_line",
"entity_id": lineId,
}).Info("Inventory Movement Line deleted")
return nil
}
func NewInventoryMovementService(db *gorm.DB, movementRepo repository.InventoryMovementRepository, movementLineRepo repository.InventoryMovementLineRepository, sequenceService sequenceservice.SequenceService, log *logrus.Logger) InventoryMovementService {
return &inventoryMovementService{
db: db,
movementRepo: movementRepo,
movementLineRepo: movementLineRepo,
sequenceService: sequenceService,
log: log,
}
}