mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 07:15:43 +00:00
Merge branch 'development' into feat/inventory-logs
This commit is contained in:
@@ -125,6 +125,11 @@ func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
scope, err := m.ResolveLocationScope(c, s.PurchaseRepo.DB())
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (params.Page - 1) * params.Limit
|
||||
|
||||
createdFrom, createdTo, err := utils.ParseDateRangeForQuery(params.CreatedFrom, params.CreatedTo)
|
||||
@@ -148,6 +153,21 @@ func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti
|
||||
db = db.Where("created_at < ?", *createdTo)
|
||||
}
|
||||
|
||||
if scope.Restrict {
|
||||
if len(scope.IDs) == 0 {
|
||||
return db.Where("1 = 0")
|
||||
}
|
||||
db = db.Where(
|
||||
`EXISTS (
|
||||
SELECT 1
|
||||
FROM purchase_items pi
|
||||
JOIN warehouses w ON w.id = pi.warehouse_id
|
||||
WHERE pi.purchase_id = purchases.id AND w.location_id IN ?
|
||||
)`,
|
||||
scope.IDs,
|
||||
)
|
||||
}
|
||||
|
||||
if params.AreaID > 0 {
|
||||
db = db.Where(
|
||||
`EXISTS (
|
||||
@@ -202,7 +222,42 @@ func (s *purchaseService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti
|
||||
}
|
||||
|
||||
func (s *purchaseService) GetOne(c *fiber.Ctx, id uint) (*entity.Purchase, error) {
|
||||
return s.loadPurchase(c.Context(), id)
|
||||
scope, err := m.ResolveLocationScope(c, s.PurchaseRepo.DB())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
purchase, err := s.PurchaseRepo.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB {
|
||||
db = s.withRelations(db)
|
||||
if scope.Restrict {
|
||||
if len(scope.IDs) == 0 {
|
||||
return db.Where("1 = 0")
|
||||
}
|
||||
db = db.Where(
|
||||
`EXISTS (
|
||||
SELECT 1
|
||||
FROM purchase_items pi
|
||||
JOIN warehouses w ON w.id = pi.warehouse_id
|
||||
WHERE pi.purchase_id = purchases.id AND w.location_id IN ?
|
||||
)`,
|
||||
scope.IDs,
|
||||
)
|
||||
}
|
||||
return db
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, utils.NotFound("Purchase not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to get purchase %d: %+v", id, err)
|
||||
return nil, utils.Internal("Failed to get purchase")
|
||||
}
|
||||
if err := s.attachLatestApproval(c.Context(), purchase); err != nil {
|
||||
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", id, err)
|
||||
}
|
||||
s.applyTravelDocumentURLs(c.Context(), purchase)
|
||||
|
||||
return purchase, nil
|
||||
}
|
||||
|
||||
func (s *purchaseService) CreateOne(c *fiber.Ctx, req *validation.CreatePurchaseRequest) (*entity.Purchase, error) {
|
||||
@@ -1271,6 +1326,10 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error {
|
||||
}
|
||||
|
||||
ctx := c.Context()
|
||||
actorID, err := m.ActorIDFromContext(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
purchase, err := s.loadPurchase(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1284,7 +1343,16 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error {
|
||||
itemsToDelete[i] = item
|
||||
}
|
||||
|
||||
note := fmt.Sprintf("Purchase-Delete#%d", purchase.Id)
|
||||
if purchase.PoNumber != nil && strings.TrimSpace(*purchase.PoNumber) != "" {
|
||||
note = fmt.Sprintf("%s#delete", strings.TrimSpace(*purchase.PoNumber))
|
||||
}
|
||||
|
||||
transactionErr := s.PurchaseRepo.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := s.rollbackPurchaseStock(ctx, tx, itemsToDelete, note, actorID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
approvalRepoTx := commonRepo.NewApprovalRepository(tx)
|
||||
if err := approvalRepoTx.DeleteByTarget(ctx, utils.ApprovalWorkflowPurchase.String(), uint(id)); err != nil {
|
||||
return err
|
||||
@@ -1320,6 +1388,91 @@ func (s *purchaseService) DeletePurchase(c *fiber.Ctx, id uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *purchaseService) rollbackPurchaseStock(ctx context.Context, tx *gorm.DB, items []entity.PurchaseItem, note string, actorID uint) error {
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
pwRepoTx := rProductWarehouse.NewProductWarehouseRepository(tx)
|
||||
stockLogRepoTx := rStockLogs.NewStockLogRepository(tx)
|
||||
deltas := make(map[uint]float64)
|
||||
affected := make(map[uint]struct{})
|
||||
logEntries := make([]struct {
|
||||
pwID uint
|
||||
qty float64
|
||||
}, 0, len(items))
|
||||
|
||||
for _, item := range items {
|
||||
if item.ProductWarehouseId == nil || *item.ProductWarehouseId == 0 {
|
||||
continue
|
||||
}
|
||||
if item.TotalQty == 0 {
|
||||
continue
|
||||
}
|
||||
pwID := *item.ProductWarehouseId
|
||||
qty := item.TotalQty
|
||||
|
||||
if s.FifoSvc != nil {
|
||||
if err := s.FifoSvc.AdjustStockableQuantity(ctx, commonSvc.StockAdjustRequest{
|
||||
StockableKey: fifo.StockableKeyPurchaseItems,
|
||||
StockableID: item.Id,
|
||||
ProductWarehouseID: pwID,
|
||||
Quantity: -qty,
|
||||
Tx: tx,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
logEntries = append(logEntries, struct {
|
||||
pwID uint
|
||||
qty float64
|
||||
}{pwID: pwID, qty: qty})
|
||||
continue
|
||||
}
|
||||
|
||||
deltas[pwID] -= qty
|
||||
affected[pwID] = struct{}{}
|
||||
logEntries = append(logEntries, struct {
|
||||
pwID uint
|
||||
qty float64
|
||||
}{pwID: pwID, qty: qty})
|
||||
}
|
||||
|
||||
if s.FifoSvc == nil && len(deltas) > 0 {
|
||||
if err := pwRepoTx.AdjustQuantities(ctx, deltas, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(affected) > 0 {
|
||||
if err := pwRepoTx.CleanupEmpty(ctx, affected); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.TrimSpace(note) != "" && actorID != 0 && len(logEntries) > 0 {
|
||||
logs := make([]*entity.StockLog, 0, len(logEntries))
|
||||
for _, entry := range logEntries {
|
||||
if entry.pwID == 0 || entry.qty <= 0 {
|
||||
continue
|
||||
}
|
||||
logs = append(logs, &entity.StockLog{
|
||||
ProductWarehouseId: entry.pwID,
|
||||
CreatedBy: actorID,
|
||||
Decrease: entry.qty,
|
||||
LoggableType: string(utils.StockLogTypePurchase),
|
||||
LoggableId: items[0].PurchaseId,
|
||||
Notes: note,
|
||||
})
|
||||
}
|
||||
if len(logs) > 0 {
|
||||
if err := stockLogRepoTx.CreateMany(ctx, logs, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *purchaseService) createPurchaseApproval(
|
||||
ctx context.Context,
|
||||
db *gorm.DB,
|
||||
|
||||
Reference in New Issue
Block a user