Feat[BE]: refactor document handling in transfer service and introduce document type constants

This commit is contained in:
aguhh18
2025-12-23 17:51:42 +07:00
committed by Hafizh A. Y
parent 7dc5c9e9a5
commit ebf0f8c5ab
5 changed files with 72 additions and 52 deletions
@@ -20,4 +20,5 @@ type StockTransferDelivery struct {
StockTransfer *StockTransfer `gorm:"foreignKey:StockTransferId"` StockTransfer *StockTransfer `gorm:"foreignKey:StockTransferId"`
Supplier *Supplier `gorm:"foreignKey:SupplierId"` Supplier *Supplier `gorm:"foreignKey:SupplierId"`
Items []StockTransferDeliveryItem `gorm:"foreignKey:StockTransferDeliveryId"` Items []StockTransferDeliveryItem `gorm:"foreignKey:StockTransferDeliveryId"`
Documents []Document `gorm:"foreignKey:DocumentableId;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
} }
@@ -68,7 +68,7 @@ func (u *TransferController) GetOne(c *fiber.Ctx) error {
Code: fiber.StatusOK, Code: fiber.StatusOK,
Status: "success", Status: "success",
Message: "Get transfer successfully", Message: "Get transfer successfully",
Data: dto.ToTransferListDTO(*result), Data: dto.ToTransferDetailDTO(*result),
}) })
} }
@@ -87,6 +87,11 @@ func (u *TransferController) CreateOne(c *fiber.Ctx) error {
files := form.File["documents"] files := form.File["documents"]
if len(files) != len(req.Deliveries) {
return fiber.NewError(fiber.StatusBadRequest,
fiber.NewError(fiber.StatusBadRequest, "Jumlah dokumen harus sama dengan jumlah deliveries").Message)
}
result, err := u.TransferService.CreateOne(c, &req, files) result, err := u.TransferService.CreateOne(c, &req, files)
if err != nil { if err != nil {
return err return err
@@ -97,6 +102,6 @@ func (u *TransferController) CreateOne(c *fiber.Ctx) error {
Code: fiber.StatusCreated, Code: fiber.StatusCreated,
Status: "success", Status: "success",
Message: "Create transfer successfully", Message: "Create transfer successfully",
Data: dto.ToTransferListDTO(*result), Data: dto.ToTransferDetailDTO(*result),
}) })
} }
@@ -7,8 +7,6 @@ import (
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto" userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
) )
// === DTO Structs ===
type TransferRelationDTO struct { type TransferRelationDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
TransferReason string `json:"transfer_reason"` TransferReason string `json:"transfer_reason"`
@@ -17,7 +15,6 @@ type TransferRelationDTO struct {
DestinationWarehouse *WarehouseDetailDTO `json:"destination_warehouse,omitempty"` DestinationWarehouse *WarehouseDetailDTO `json:"destination_warehouse,omitempty"`
} }
// Only id and name for warehouse simple view
type WarehouseSimpleDTO struct { type WarehouseSimpleDTO struct {
Id uint `json:"id"` Id uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@@ -65,7 +62,6 @@ type TransferListDTO struct {
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
Details []TransferDetailItemDTO `json:"details"` Details []TransferDetailItemDTO `json:"details"`
Deliveries []TransferDeliveryDTO `json:"deliveries"` Deliveries []TransferDeliveryDTO `json:"deliveries"`
Documents []DocumentDTO `json:"documents"`
} }
type TransferDetailDTO struct { type TransferDetailDTO struct {
@@ -74,14 +70,12 @@ type TransferDetailDTO struct {
Deliveries []TransferDeliveryDTO `json:"deliveries"` Deliveries []TransferDeliveryDTO `json:"deliveries"`
} }
// Detail produk
type TransferDetailItemDTO struct { type TransferDetailItemDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
Proudct ProductSimpleDTO `json:"product"` Product ProductSimpleDTO `json:"product"`
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
} }
// Delivery ekspedisi
type TransferDeliveryDTO struct { type TransferDeliveryDTO struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
Supplier SupplierSimpleDTO `json:"supplier"` Supplier SupplierSimpleDTO `json:"supplier"`
@@ -91,6 +85,7 @@ type TransferDeliveryDTO struct {
ShippingCostItem float64 `json:"shipping_cost_item"` ShippingCostItem float64 `json:"shipping_cost_item"`
ShippingCostTotal float64 `json:"shipping_cost_total"` ShippingCostTotal float64 `json:"shipping_cost_total"`
Items []TransferDeliveryItemDTO `json:"items"` Items []TransferDeliveryItemDTO `json:"items"`
Documents []DocumentDTO `json:"documents"`
} }
type TransferDeliveryItemDTO struct { type TransferDeliveryItemDTO struct {
@@ -99,10 +94,7 @@ type TransferDeliveryItemDTO struct {
Quantity float64 `json:"quantity"` Quantity float64 `json:"quantity"`
} }
// === Mapper Functions ===
func ToTransferRelationDTO(e entity.StockTransfer) TransferRelationDTO { func ToTransferRelationDTO(e entity.StockTransfer) TransferRelationDTO {
var sourceWarehouse *WarehouseDetailDTO var sourceWarehouse *WarehouseDetailDTO
if e.FromWarehouse != nil && e.FromWarehouse.Id != 0 { if e.FromWarehouse != nil && e.FromWarehouse.Id != 0 {
sourceWarehouse = toWarehouseDetailDTO(e.FromWarehouse) sourceWarehouse = toWarehouseDetailDTO(e.FromWarehouse)
@@ -148,7 +140,7 @@ func toWarehouseDetailDTO(w *entity.Warehouse) *WarehouseDetailDTO {
Id: w.Id, Id: w.Id,
Name: w.Name, Name: w.Name,
Location: toLocationDTO(w.Location), Location: toLocationDTO(w.Location),
Area: toAreaDTO(&w.Area), // Ambil area langsung dari warehouse (area_id) Area: toAreaDTO(&w.Area),
} }
} }
@@ -158,22 +150,21 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
mapped := userDTO.ToUserRelationDTO(*e.CreatedUser) mapped := userDTO.ToUserRelationDTO(*e.CreatedUser)
createdUser = &mapped createdUser = &mapped
} }
// Map details
var details []TransferDetailItemDTO var details []TransferDetailItemDTO
for _, d := range e.Details { for _, d := range e.Details {
details = append(details, TransferDetailItemDTO{ details = append(details, TransferDetailItemDTO{
Id: d.Id, Id: d.Id,
Proudct: ProductSimpleDTO{ Product: ProductSimpleDTO{
Id: d.Product.Id, Id: d.Product.Id,
Name: d.Product.Name, Name: d.Product.Name,
}, },
Quantity: d.Quantity, Quantity: d.Quantity,
}) })
} }
// Map deliveries
var deliveries []TransferDeliveryDTO var deliveries []TransferDeliveryDTO
for _, del := range e.Deliveries { for _, del := range e.Deliveries {
// Map delivery items
var items []TransferDeliveryItemDTO var items []TransferDeliveryItemDTO
for _, item := range del.Items { for _, item := range del.Items {
items = append(items, TransferDeliveryItemDTO{ items = append(items, TransferDeliveryItemDTO{
@@ -183,6 +174,17 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
}) })
} }
var documents []DocumentDTO
for _, doc := range del.Documents {
documents = append(documents, DocumentDTO{
Id: doc.Id,
Path: doc.Path,
Name: doc.Name,
Ext: doc.Ext,
Size: doc.Size,
})
}
deliveries = append(deliveries, TransferDeliveryDTO{ deliveries = append(deliveries, TransferDeliveryDTO{
Id: del.Id, Id: del.Id,
Supplier: SupplierSimpleDTO{ Supplier: SupplierSimpleDTO{
@@ -195,16 +197,7 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
ShippingCostItem: del.ShippingCostItem, ShippingCostItem: del.ShippingCostItem,
ShippingCostTotal: del.ShippingCostTotal, ShippingCostTotal: del.ShippingCostTotal,
Items: items, Items: items,
}) Documents: documents,
}
var documents []DocumentDTO
for _, doc := range e.Documents {
documents = append(documents, DocumentDTO{
Id: doc.Id,
Path: doc.Path,
Name: doc.Name,
Ext: doc.Ext,
Size: doc.Size,
}) })
} }
@@ -215,7 +208,6 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
UpdatedAt: e.UpdatedAt, UpdatedAt: e.UpdatedAt,
Details: details, Details: details,
Deliveries: deliveries, Deliveries: deliveries,
Documents: documents,
} }
} }
@@ -228,21 +220,31 @@ func ToTransferListDTOs(e []entity.StockTransfer) []TransferListDTO {
} }
func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO { func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO {
// Map details
var details []TransferDetailItemDTO var details []TransferDetailItemDTO
for _, d := range e.Details { for _, d := range e.Details {
details = append(details, TransferDetailItemDTO{ details = append(details, TransferDetailItemDTO{
Id: d.Id, Id: d.Id,
Proudct: ProductSimpleDTO{ Product: ProductSimpleDTO{
Id: d.Product.Id, Id: d.Product.Id,
Name: d.Product.Name, Name: d.Product.Name,
}, },
Quantity: d.Quantity, Quantity: d.Quantity,
}) })
} }
// Map deliveries
var deliveries []TransferDeliveryDTO var deliveries []TransferDeliveryDTO
for _, del := range e.Deliveries { for _, del := range e.Deliveries {
var documents []DocumentDTO
for _, doc := range del.Documents {
documents = append(documents, DocumentDTO{
Id: doc.Id,
Path: doc.Path,
Name: doc.Name,
Ext: doc.Ext,
Size: doc.Size,
})
}
deliveries = append(deliveries, TransferDeliveryDTO{ deliveries = append(deliveries, TransferDeliveryDTO{
Id: del.Id, Id: del.Id,
Supplier: SupplierSimpleDTO{ Supplier: SupplierSimpleDTO{
@@ -254,8 +256,10 @@ func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO {
DocumentNumber: del.DocumentNumber, DocumentNumber: del.DocumentNumber,
ShippingCostItem: del.ShippingCostItem, ShippingCostItem: del.ShippingCostItem,
ShippingCostTotal: del.ShippingCostTotal, ShippingCostTotal: del.ShippingCostTotal,
Documents: documents,
}) })
} }
return TransferDetailDTO{ return TransferDetailDTO{
TransferListDTO: ToTransferListDTO(e), TransferListDTO: ToTransferListDTO(e),
Details: details, Details: details,
@@ -76,8 +76,8 @@ func (s transferService) withRelations(db *gorm.DB) *gorm.DB {
Preload("Details.Product"). Preload("Details.Product").
Preload("Deliveries.Items"). Preload("Deliveries.Items").
Preload("Deliveries.Supplier"). Preload("Deliveries.Supplier").
Preload("Documents", func(db *gorm.DB) *gorm.DB { Preload("Deliveries.Documents", func(db *gorm.DB) *gorm.DB {
return db.Where("documentable_type = ?", "STOCK_TRANSFER") return db.Where("documentable_type = ?", string(utils.DocumentableTypeTransfer))
}) })
} }
@@ -258,29 +258,26 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
return err return err
} }
actorIDCopy := actorID
if s.DocumentSvc != nil && len(files) > 0 { if s.DocumentSvc != nil && len(files) > 0 {
s.Log.Infof("Starting document upload for %d files", len(files)) // Upload documents for each delivery
documentFiles := make([]commonSvc.DocumentFile, 0, len(files))
for idx, file := range files { for idx, file := range files {
docIndex := idx documentFiles := []commonSvc.DocumentFile{
documentFiles = append(documentFiles, commonSvc.DocumentFile{ {
File: file, File: file,
Type: "STOCK_TRANSFER_DOCUMENT", Type: string(utils.DocumentTypeTransfer),
Index: &docIndex, Index: &idx,
},
}
_, err := s.DocumentSvc.UploadDocuments(c.Context(), commonSvc.DocumentUploadRequest{
DocumentableType: string(utils.DocumentableTypeTransfer),
DocumentableID: deliveries[idx].Id,
CreatedBy: &actorID,
Files: documentFiles,
}) })
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to upload document for delivery %d", idx+1))
}
} }
_, err := s.DocumentSvc.UploadDocuments(c.Context(), commonSvc.DocumentUploadRequest{
DocumentableType: "STOCK_TRANSFER",
DocumentableID: entityTransfer.Id,
CreatedBy: &actorIDCopy,
Files: documentFiles,
})
if err != nil {
s.Log.Errorf("Failed to upload documents for transfer %d: %+v", entityTransfer.Id, err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to upload transfer documents")
}
s.Log.Infof("Successfully uploaded documents for transfer ID %d", entityTransfer.Id)
} }
for _, product := range req.Products { for _, product := range req.Products {
+13
View File
@@ -398,6 +398,19 @@ var InjectionApprovalSteps = map[approvalutils.ApprovalStep]string{
InjectionStepDisetujui: "Disetujui", InjectionStepDisetujui: "Disetujui",
} }
// -------------------------------------------------------------------
// Document
// -------------------------------------------------------------------
type DocumentType string
type DocumentableType string
const (
DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT"
DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER"
)
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Validators // Validators
// ------------------------------------------------------------------- // -------------------------------------------------------------------