mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE-278): unrestrict feat warehouse purchase,adding purchase upload document
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"mime/multipart"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -57,6 +58,7 @@ type purchaseService struct {
|
||||
ApprovalSvc commonSvc.ApprovalService
|
||||
ExpenseBridge PurchaseExpenseBridge
|
||||
FifoSvc commonSvc.FifoService
|
||||
DocumentSvc commonSvc.DocumentService
|
||||
approvalWorkflow approvalutils.ApprovalWorkflowKey
|
||||
}
|
||||
|
||||
@@ -76,6 +78,7 @@ func NewPurchaseService(
|
||||
approvalSvc commonSvc.ApprovalService,
|
||||
expenseBridge PurchaseExpenseBridge,
|
||||
fifoSvc commonSvc.FifoService,
|
||||
documentSvc commonSvc.DocumentService,
|
||||
) PurchaseService {
|
||||
return &purchaseService{
|
||||
Log: utils.Log,
|
||||
@@ -89,6 +92,7 @@ func NewPurchaseService(
|
||||
ApprovalSvc: approvalSvc,
|
||||
ExpenseBridge: expenseBridge,
|
||||
FifoSvc: fifoSvc,
|
||||
DocumentSvc: documentSvc,
|
||||
approvalWorkflow: utils.ApprovalWorkflowPurchase,
|
||||
}
|
||||
}
|
||||
@@ -615,9 +619,7 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := c.Context()
|
||||
|
||||
action, err := parseApprovalActionInput(req.Action)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -664,6 +666,30 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
if action == entity.ApprovalActionApproved && len(req.TravelDocuments) > 0 {
|
||||
if len(req.TravelDocuments) > len(req.Items) {
|
||||
return nil, utils.BadRequest("Travel documents exceed total receiving items")
|
||||
}
|
||||
for idx, file := range req.TravelDocuments {
|
||||
if file == nil {
|
||||
continue
|
||||
}
|
||||
if idx >= len(req.Items) {
|
||||
break
|
||||
}
|
||||
itemID := req.Items[idx].PurchaseItemID
|
||||
if itemID == 0 {
|
||||
return nil, utils.BadRequest("Purchase item id is required for travel document upload")
|
||||
}
|
||||
uploadedURL, err := s.uploadTravelDocument(ctx, actorID, itemID, file)
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to upload travel document for item %d: %+v", itemID, err)
|
||||
return nil, utils.Internal("Failed to upload travel document")
|
||||
}
|
||||
req.Items[idx].TravelDocumentPath = &uploadedURL
|
||||
}
|
||||
}
|
||||
|
||||
itemMap := make(map[uint]*entity.PurchaseItem, len(purchase.Items))
|
||||
for i := range purchase.Items {
|
||||
itemMap[purchase.Items[i].Id] = &purchase.Items[i]
|
||||
@@ -807,32 +833,20 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
||||
for _, prep := range prepared {
|
||||
item := prep.item
|
||||
|
||||
var oldPWID *uint
|
||||
if item.ProductWarehouseId != nil {
|
||||
idCopy := uint(*item.ProductWarehouseId)
|
||||
oldPWID = &idCopy
|
||||
}
|
||||
|
||||
var newPWID *uint
|
||||
clearPW := false
|
||||
|
||||
// Always ensure PW when qty > 0 so stockable has target.
|
||||
if prep.receivedQty > 0 {
|
||||
pwID, err := pwRepoTx.EnsureProductWarehouse(
|
||||
c.Context(),
|
||||
uint(item.ProductId),
|
||||
prep.warehouseID,
|
||||
item.ProjectFlockKandangId,
|
||||
purchase.CreatedBy,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newPWID = &pwID
|
||||
} else if oldPWID != nil {
|
||||
newPWID = oldPWID
|
||||
clearPW = true
|
||||
// Always ensure PW after receiving so linkage stays stable.
|
||||
pwID, err := pwRepoTx.EnsureProductWarehouse(
|
||||
c.Context(),
|
||||
uint(item.ProductId),
|
||||
prep.warehouseID,
|
||||
item.ProjectFlockKandangId,
|
||||
purchase.CreatedBy,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newPWID = &pwID
|
||||
|
||||
deltaQty := prep.receivedQty - item.TotalQty
|
||||
switch {
|
||||
@@ -857,7 +871,7 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
||||
VehicleNumber: prep.payload.VehicleNumber,
|
||||
ReceivedQty: &qtyCopy,
|
||||
ProductWarehouseID: newPWID,
|
||||
ClearProductWarehouse: clearPW,
|
||||
ClearProductWarehouse: false,
|
||||
}
|
||||
|
||||
if prep.overrideWarehouse || uint(item.WarehouseId) != prep.warehouseID {
|
||||
@@ -972,6 +986,38 @@ func (s *purchaseService) ReceiveProducts(c *fiber.Ctx, id uint, req *validation
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s *purchaseService) uploadTravelDocument(
|
||||
ctx context.Context,
|
||||
actorID uint,
|
||||
itemID uint,
|
||||
file *multipart.FileHeader,
|
||||
) (string, error) {
|
||||
if file == nil {
|
||||
return "", errors.New("travel document file is required")
|
||||
}
|
||||
if s.DocumentSvc == nil {
|
||||
return "", errors.New("document service not available")
|
||||
}
|
||||
|
||||
documentFiles := []commonSvc.DocumentFile{{
|
||||
File: file,
|
||||
Type: string(utils.DocumentTypePurchaseTravel),
|
||||
}}
|
||||
results, err := s.DocumentSvc.UploadDocuments(ctx, commonSvc.DocumentUploadRequest{
|
||||
DocumentableType: string(utils.DocumentableTypePurchaseItem),
|
||||
DocumentableID: uint64(itemID),
|
||||
CreatedBy: &actorID,
|
||||
Files: documentFiles,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(results) == 0 {
|
||||
return "", errors.New("upload result is empty")
|
||||
}
|
||||
return results[0].URL, nil
|
||||
}
|
||||
|
||||
func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.DeletePurchaseItemsRequest) (*entity.Purchase, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user