mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'FEAT/BE/Transfer_stock' into 'development'
[FEAT][BE-transfer_Stock]L Update StockTransferDelivery and TransferDeliveryDTO to allow optional SupplierId See merge request mbugroup/lti-api!265
This commit is contained in:
@@ -6,7 +6,7 @@ import "time"
|
|||||||
type StockTransferDelivery struct {
|
type StockTransferDelivery struct {
|
||||||
Id uint64 `gorm:"primaryKey;autoIncrement"`
|
Id uint64 `gorm:"primaryKey;autoIncrement"`
|
||||||
StockTransferId uint64
|
StockTransferId uint64
|
||||||
SupplierId uint64
|
SupplierId *uint64
|
||||||
VehiclePlate string
|
VehiclePlate string
|
||||||
DriverName string
|
DriverName string
|
||||||
DocumentNumber string
|
DocumentNumber string
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TransferRelationDTO struct {
|
type TransferRelationDTO struct {
|
||||||
Id uint64 `json:"id"`
|
Id uint64 `json:"id"`
|
||||||
MovementNumber string `json:"movement_number"`
|
MovementNumber string `json:"movement_number"`
|
||||||
TransferReason string `json:"transfer_reason"`
|
TransferReason string `json:"transfer_reason"`
|
||||||
TransferDate string `json:"transfer_date"`
|
TransferDate string `json:"transfer_date"`
|
||||||
SourceWarehouse *warehouseDTO.WarehouseRelationDTO `json:"source_warehouse,omitempty"`
|
SourceWarehouse *warehouseDTO.WarehouseRelationDTO `json:"source_warehouse,omitempty"`
|
||||||
DestinationWarehouse *warehouseDTO.WarehouseRelationDTO `json:"destination_warehouse,omitempty"`
|
DestinationWarehouse *warehouseDTO.WarehouseRelationDTO `json:"destination_warehouse,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductSimpleDTO struct {
|
type ProductSimpleDTO struct {
|
||||||
@@ -51,16 +51,16 @@ type TransferDetailDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TransferDetailItemDTO struct {
|
type TransferDetailItemDTO struct {
|
||||||
Id uint64 `json:"id"`
|
Id uint64 `json:"id"`
|
||||||
Product ProductSimpleDTO `json:"product"`
|
Product ProductSimpleDTO `json:"product"`
|
||||||
Quantity float64 `json:"quantity"`
|
Quantity float64 `json:"quantity"`
|
||||||
TransportPerItem *float64 `json:"transport_per_item,omitempty"` // Biaya ekspedisi per item
|
TransportPerItem *float64 `json:"transport_per_item,omitempty"` // Biaya ekspedisi per item
|
||||||
ExpeditionVendor *SupplierSimpleDTO `json:"expedition_vendor,omitempty"` // Vendor ekspedisi
|
ExpeditionVendor *SupplierSimpleDTO `json:"expedition_vendor,omitempty"` // Vendor ekspedisi
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransferDeliveryDTO struct {
|
type TransferDeliveryDTO struct {
|
||||||
Id uint64 `json:"id"`
|
Id uint64 `json:"id"`
|
||||||
Supplier SupplierSimpleDTO `json:"supplier"`
|
Supplier *SupplierSimpleDTO `json:"supplier,omitempty"`
|
||||||
VehiclePlate string `json:"vehicle_plate"`
|
VehiclePlate string `json:"vehicle_plate"`
|
||||||
DriverName string `json:"driver_name"`
|
DriverName string `json:"driver_name"`
|
||||||
DocumentNumber string `json:"document_number"`
|
DocumentNumber string `json:"document_number"`
|
||||||
@@ -115,7 +115,6 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
|
|||||||
Quantity: d.UsageQty + d.PendingQty, // Total actual quantity allocated
|
Quantity: d.UsageQty + d.PendingQty, // Total actual quantity allocated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if d.ExpenseNonstock != nil {
|
if d.ExpenseNonstock != nil {
|
||||||
priceCopy := d.ExpenseNonstock.Price
|
priceCopy := d.ExpenseNonstock.Price
|
||||||
detailDTO.TransportPerItem = &priceCopy
|
detailDTO.TransportPerItem = &priceCopy
|
||||||
@@ -155,12 +154,17 @@ func ToTransferListDTO(e entity.StockTransfer) TransferListDTO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deliveries = append(deliveries, TransferDeliveryDTO{
|
var supplier *SupplierSimpleDTO
|
||||||
Id: del.Id,
|
if del.Supplier != nil {
|
||||||
Supplier: SupplierSimpleDTO{
|
supplier = &SupplierSimpleDTO{
|
||||||
Id: del.Supplier.Id,
|
Id: del.Supplier.Id,
|
||||||
Name: del.Supplier.Name,
|
Name: del.Supplier.Name,
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deliveries = append(deliveries, TransferDeliveryDTO{
|
||||||
|
Id: del.Id,
|
||||||
|
Supplier: supplier,
|
||||||
VehiclePlate: del.VehiclePlate,
|
VehiclePlate: del.VehiclePlate,
|
||||||
DriverName: del.DriverName,
|
DriverName: del.DriverName,
|
||||||
DocumentNumber: del.DocumentNumber,
|
DocumentNumber: del.DocumentNumber,
|
||||||
@@ -201,7 +205,6 @@ func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO {
|
|||||||
Quantity: d.UsageQty + d.PendingQty, // Total actual quantity allocated
|
Quantity: d.UsageQty + d.PendingQty, // Total actual quantity allocated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if d.ExpenseNonstock != nil {
|
if d.ExpenseNonstock != nil {
|
||||||
priceCopy := d.ExpenseNonstock.Price
|
priceCopy := d.ExpenseNonstock.Price
|
||||||
detailDTO.TransportPerItem = &priceCopy
|
detailDTO.TransportPerItem = &priceCopy
|
||||||
@@ -241,12 +244,17 @@ func ToTransferDetailDTO(e entity.StockTransfer) TransferDetailDTO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deliveries = append(deliveries, TransferDeliveryDTO{
|
var supplier *SupplierSimpleDTO
|
||||||
Id: del.Id,
|
if del.Supplier != nil {
|
||||||
Supplier: SupplierSimpleDTO{
|
supplier = &SupplierSimpleDTO{
|
||||||
Id: del.Supplier.Id,
|
Id: del.Supplier.Id,
|
||||||
Name: del.Supplier.Name,
|
Name: del.Supplier.Name,
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deliveries = append(deliveries, TransferDeliveryDTO{
|
||||||
|
Id: del.Id,
|
||||||
|
Supplier: supplier,
|
||||||
VehiclePlate: del.VehiclePlate,
|
VehiclePlate: del.VehiclePlate,
|
||||||
DriverName: del.DriverName,
|
DriverName: del.DriverName,
|
||||||
DocumentNumber: del.DocumentNumber,
|
DocumentNumber: del.DocumentNumber,
|
||||||
|
|||||||
@@ -196,6 +196,11 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, delivery := range req.Deliveries {
|
for _, delivery := range req.Deliveries {
|
||||||
|
// Skip supplier validation if SupplierID is 0 (optional)
|
||||||
|
if delivery.SupplierID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
supplier, err := s.SupplierRepo.GetByID(c.Context(), uint(delivery.SupplierID), nil)
|
supplier, err := s.SupplierRepo.GetByID(c.Context(), uint(delivery.SupplierID), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
@@ -310,9 +315,16 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
|
|
||||||
var deliveries []*entity.StockTransferDelivery
|
var deliveries []*entity.StockTransferDelivery
|
||||||
for _, delivery := range req.Deliveries {
|
for _, delivery := range req.Deliveries {
|
||||||
|
supplierId := func() *uint64 {
|
||||||
|
if delivery.SupplierID > 0 {
|
||||||
|
id := uint64(delivery.SupplierID)
|
||||||
|
return &id
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
deliveries = append(deliveries, &entity.StockTransferDelivery{
|
deliveries = append(deliveries, &entity.StockTransferDelivery{
|
||||||
StockTransferId: entityTransfer.Id,
|
StockTransferId: entityTransfer.Id,
|
||||||
SupplierId: uint64(delivery.SupplierID),
|
SupplierId: supplierId,
|
||||||
VehiclePlate: delivery.VehiclePlate,
|
VehiclePlate: delivery.VehiclePlate,
|
||||||
DriverName: delivery.DriverName,
|
DriverName: delivery.DriverName,
|
||||||
ShippingCostItem: delivery.DeliveryCostPerItem,
|
ShippingCostItem: delivery.DeliveryCostPerItem,
|
||||||
@@ -458,6 +470,11 @@ func (s *transferService) CreateOne(c *fiber.Ctx, req *validation.TransferReques
|
|||||||
|
|
||||||
if len(req.Deliveries) > 0 {
|
if len(req.Deliveries) > 0 {
|
||||||
for _, delivery := range req.Deliveries {
|
for _, delivery := range req.Deliveries {
|
||||||
|
// Skip adding to expensePayloads if SupplierID is 0 (optional)
|
||||||
|
if delivery.SupplierID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, prod := range delivery.Products {
|
for _, prod := range delivery.Products {
|
||||||
detail := detailMap[uint64(prod.ProductID)]
|
detail := detailMap[uint64(prod.ProductID)]
|
||||||
if detail == nil {
|
if detail == nil {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type TransferDelivery struct {
|
|||||||
DocumentIndex int `json:"document_index" validate:"omitempty,min=-1" default:"-1"`
|
DocumentIndex int `json:"document_index" validate:"omitempty,min=-1" default:"-1"`
|
||||||
DriverName string `json:"driver_name" validate:"required"`
|
DriverName string `json:"driver_name" validate:"required"`
|
||||||
VehiclePlate string `json:"vehicle_plate" validate:"required"`
|
VehiclePlate string `json:"vehicle_plate" validate:"required"`
|
||||||
SupplierID uint `json:"supplier_id" validate:"required"`
|
SupplierID uint `json:"supplier_id" `
|
||||||
Products []TransferDeliveryProduct `json:"products" validate:"required,dive"`
|
Products []TransferDeliveryProduct `json:"products" validate:"required,dive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -650,9 +650,9 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
|||||||
repoTx := s.Repository.WithTx(dbTransaction)
|
repoTx := s.Repository.WithTx(dbTransaction)
|
||||||
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
approvalSvcTx := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
||||||
|
|
||||||
// Gunakan repo baru untuk transaction scope agar bisa akses method custom
|
|
||||||
sourceRepoTx := repository.NewLayingTransferSourceRepository(dbTransaction)
|
sourceRepoTx := repository.NewLayingTransferSourceRepository(dbTransaction)
|
||||||
targetRepoTx := repository.NewLayingTransferTargetRepository(dbTransaction)
|
targetRepoTx := repository.NewLayingTransferTargetRepository(dbTransaction)
|
||||||
|
stockLogRepoTx := rStockLogs.NewStockLogRepository(dbTransaction)
|
||||||
|
|
||||||
for _, approvableID := range approvableIDs {
|
for _, approvableID := range approvableIDs {
|
||||||
transfer, err := repoTx.GetByID(c.Context(), approvableID, nil)
|
transfer, err := repoTx.GetByID(c.Context(), approvableID, nil)
|
||||||
@@ -687,23 +687,28 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
|||||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil targets transfer")
|
return fiber.NewError(fiber.StatusInternalServerError, "Gagal mengambil targets transfer")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitung total quantity dari targets untuk di-consume dari sources
|
|
||||||
totalTargetQty := 0.0
|
totalTargetQty := 0.0
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
totalTargetQty += target.TotalQty
|
totalTargetQty += target.TotalQty
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume dari laying_transfer_sources (Usable) - akan consume dari ProjectFlockPopulation (Stockable)
|
totalSourceRequested := 0.0
|
||||||
|
for _, source := range sources {
|
||||||
|
totalSourceRequested += source.RequestedQty
|
||||||
|
}
|
||||||
|
|
||||||
for _, source := range sources {
|
for _, source := range sources {
|
||||||
if source.ProductWarehouseId == nil {
|
if source.ProductWarehouseId == nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Source product warehouse tidak ditemukan untuk transfer %d", approvableID))
|
return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Source product warehouse tidak ditemukan untuk transfer %d", approvableID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceShare := (source.RequestedQty / totalSourceRequested) * totalTargetQty
|
||||||
|
|
||||||
consumeResult, err := s.FifoSvc.Consume(c.Context(), commonSvc.StockConsumeRequest{
|
consumeResult, err := s.FifoSvc.Consume(c.Context(), commonSvc.StockConsumeRequest{
|
||||||
UsableKey: fifo.UsableKeyTransferToLayingOut,
|
UsableKey: fifo.UsableKeyTransferToLayingOut,
|
||||||
UsableID: source.Id,
|
UsableID: source.Id,
|
||||||
ProductWarehouseID: *source.ProductWarehouseId,
|
ProductWarehouseID: *source.ProductWarehouseId,
|
||||||
Quantity: totalTargetQty,
|
Quantity: sourceShare,
|
||||||
AllowPending: false,
|
AllowPending: false,
|
||||||
Tx: dbTransaction,
|
Tx: dbTransaction,
|
||||||
})
|
})
|
||||||
@@ -717,6 +722,19 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
|||||||
}, nil); err != nil {
|
}, nil); err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal update source usage qty")
|
return fiber.NewError(fiber.StatusInternalServerError, "Gagal update source usage qty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stockLogDecrease := &entity.StockLog{
|
||||||
|
ProductWarehouseId: *source.ProductWarehouseId,
|
||||||
|
CreatedBy: actorID,
|
||||||
|
Increase: 0,
|
||||||
|
Decrease: sourceShare,
|
||||||
|
LoggableType: string(utils.StockLogTypeTransferLaying),
|
||||||
|
LoggableId: approvableID,
|
||||||
|
Notes: fmt.Sprintf("TL #%s", transfer.TransferNumber),
|
||||||
|
}
|
||||||
|
if err := stockLogRepoTx.CreateOne(c.Context(), stockLogDecrease, nil); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok keluar")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
@@ -725,7 +743,7 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
note := fmt.Sprintf("Transfer to Laying #%s", transfer.TransferNumber)
|
note := fmt.Sprintf("Transfer to Laying #%s", transfer.TransferNumber)
|
||||||
replenishResult, err := s.FifoSvc.Replenish(c.Context(), commonSvc.StockReplenishRequest{
|
_, err := s.FifoSvc.Replenish(c.Context(), commonSvc.StockReplenishRequest{
|
||||||
StockableKey: fifo.StockableKeyTransferToLayingIn,
|
StockableKey: fifo.StockableKeyTransferToLayingIn,
|
||||||
StockableID: target.Id,
|
StockableID: target.Id,
|
||||||
ProductWarehouseID: *target.ProductWarehouseId,
|
ProductWarehouseID: *target.ProductWarehouseId,
|
||||||
@@ -738,10 +756,23 @@ func (s transferLayingService) Approval(c *fiber.Ctx, req *validation.Approve) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := targetRepoTx.PatchOne(c.Context(), target.Id, map[string]interface{}{
|
if err := targetRepoTx.PatchOne(c.Context(), target.Id, map[string]interface{}{
|
||||||
"total_qty": replenishResult.AddedQuantity,
|
"total_qty": target.TotalQty,
|
||||||
}, nil); err != nil {
|
}, nil); err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Gagal update target total qty")
|
return fiber.NewError(fiber.StatusInternalServerError, "Gagal update target total qty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stockLogIncrease := &entity.StockLog{
|
||||||
|
ProductWarehouseId: *target.ProductWarehouseId,
|
||||||
|
CreatedBy: actorID,
|
||||||
|
Increase: target.TotalQty,
|
||||||
|
Decrease: 0,
|
||||||
|
LoggableType: string(utils.StockLogTypeTransferLaying),
|
||||||
|
LoggableId: approvableID,
|
||||||
|
Notes: fmt.Sprintf("TL #%s", transfer.TransferNumber),
|
||||||
|
}
|
||||||
|
if err := stockLogRepoTx.CreateOne(c.Context(), stockLogIncrease, nil); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Gagal membuat log stok masuk")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ type Update struct {
|
|||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
|
Page int `query:"page" validate:"omitempty,number,min=1,gt=0"`
|
||||||
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
|
Limit int `query:"limit" validate:"omitempty,number,min=1,gt=0"`
|
||||||
Search string `query:"search" validate:"omitempty"`
|
Search string `query:"search" validate:"omitempty"`
|
||||||
StartDate string `query:"start_date" validate:"omitempty"`
|
StartDate string `query:"start_date" validate:"omitempty"`
|
||||||
EndDate string `query:"end_date" validate:"omitempty"`
|
EndDate string `query:"end_date" validate:"omitempty"`
|
||||||
|
|||||||
@@ -109,12 +109,13 @@ const (
|
|||||||
type StockLogType string
|
type StockLogType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StockLogTypeAdjustment StockLogType = "ADJUSTMENT"
|
StockLogTypeAdjustment StockLogType = "ADJUSTMENT"
|
||||||
StockLogTypeTransfer StockLogType = "TRANSFER"
|
StockLogTypeTransfer StockLogType = "TRANSFER"
|
||||||
StockLogTypeMarketing StockLogType = "MARKETING"
|
StockLogTypeTransferLaying StockLogType = "TRANSFER_LAYING"
|
||||||
StockLogTypeChikin StockLogType = "CHICKIN"
|
StockLogTypeMarketing StockLogType = "MARKETING"
|
||||||
StockLogTypePurchase StockLogType = "PURCHASE"
|
StockLogTypeChikin StockLogType = "CHICKIN"
|
||||||
StockLogTypeRecording StockLogType = "RECORDING"
|
StockLogTypePurchase StockLogType = "PURCHASE"
|
||||||
|
StockLogTypeRecording StockLogType = "RECORDING"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user