mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 15:25:43 +00:00
feat(BE): fix delete project flock budget and uniformity, and fix uniformity with update purchase document
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
"mime"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
|
"net/url"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -305,6 +306,56 @@ func (s *documentService) PresignURL(ctx context.Context, document entity.Docume
|
|||||||
return s.storage.PresignURL(ctx, document.Path, expires)
|
return s.storage.PresignURL(ctx, document.Path, expires)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResolveDocumentURL normalizes a stored path or URL into a presigned URL.
|
||||||
|
func ResolveDocumentURL(
|
||||||
|
ctx context.Context,
|
||||||
|
svc DocumentService,
|
||||||
|
rawPath string,
|
||||||
|
expires time.Duration,
|
||||||
|
) (string, error) {
|
||||||
|
if svc == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rawPath = strings.TrimSpace(rawPath)
|
||||||
|
if rawPath == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
key := rawPath
|
||||||
|
lower := strings.ToLower(rawPath)
|
||||||
|
if strings.HasPrefix(lower, "http://") || strings.HasPrefix(lower, "https://") {
|
||||||
|
key = extractS3KeyFromURL(rawPath)
|
||||||
|
if key == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc.PresignURL(ctx, entity.Document{Path: key}, expires)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractS3KeyFromURL(raw string) string {
|
||||||
|
parsed, err := url.Parse(strings.TrimSpace(raw))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
path := strings.TrimPrefix(parsed.Path, "/")
|
||||||
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
host := strings.ToLower(strings.TrimSpace(parsed.Host))
|
||||||
|
if strings.HasPrefix(host, "s3.") || strings.HasPrefix(host, "s3-") {
|
||||||
|
parts := strings.SplitN(path, "/", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
return parts[1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
func (s *documentService) generateObjectKey(ext string) (string, error) {
|
func (s *documentService) generateObjectKey(ext string) (string, error) {
|
||||||
normalizedExt := strings.TrimSpace(ext)
|
normalizedExt := strings.TrimSpace(ext)
|
||||||
if normalizedExt != "" && !strings.HasPrefix(normalizedExt, ".") {
|
if normalizedExt != "" && !strings.HasPrefix(normalizedExt, ".") {
|
||||||
|
|||||||
@@ -192,17 +192,6 @@ func (s *fifoService) Consume(ctx context.Context, req StockConsumeRequest) (*St
|
|||||||
if req.Quantity < 0 {
|
if req.Quantity < 0 {
|
||||||
return nil, errors.New("quantity must be zero or greater")
|
return nil, errors.New("quantity must be zero or greater")
|
||||||
}
|
}
|
||||||
if s.logger.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.logger.WithFields(logrus.Fields{
|
|
||||||
"usable_key": req.UsableKey.String(),
|
|
||||||
"usable_id": req.UsableID,
|
|
||||||
"requested_quantity": req.Quantity,
|
|
||||||
"allow_pending": req.AllowPending,
|
|
||||||
"product_warehouse_id": req.ProductWarehouseID,
|
|
||||||
}).Debug("fifo consume request")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
cfg, ok := fifo.Usable(req.UsableKey)
|
cfg, ok := fifo.Usable(req.UsableKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("usable %q is not registered", req.UsableKey)
|
return nil, fmt.Errorf("usable %q is not registered", req.UsableKey)
|
||||||
@@ -230,20 +219,6 @@ func (s *fifoService) Consume(ctx context.Context, req StockConsumeRequest) (*St
|
|||||||
currentPending := ctxRow.PendingQty
|
currentPending := ctxRow.PendingQty
|
||||||
currentTotal := currentUsage + currentPending
|
currentTotal := currentUsage + currentPending
|
||||||
delta := req.Quantity - currentTotal
|
delta := req.Quantity - currentTotal
|
||||||
if s.logger.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.logger.WithFields(logrus.Fields{
|
|
||||||
"usable_key": req.UsableKey.String(),
|
|
||||||
"usable_id": req.UsableID,
|
|
||||||
"product_warehouse_id": productWarehouseID,
|
|
||||||
"current_usage_qty": currentUsage,
|
|
||||||
"current_pending_qty": currentPending,
|
|
||||||
"current_total_qty": currentTotal,
|
|
||||||
"requested_quantity": req.Quantity,
|
|
||||||
"calculated_delta": delta,
|
|
||||||
"input_warehouse_match": req.ProductWarehouseID == 0 || req.ProductWarehouseID == productWarehouseID,
|
|
||||||
}).Debug("fifo consume context")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
usageDelta float64
|
usageDelta float64
|
||||||
pendingDelta float64
|
pendingDelta float64
|
||||||
@@ -308,21 +283,6 @@ func (s *fifoService) Consume(ctx context.Context, req StockConsumeRequest) (*St
|
|||||||
result.ReleasedQuantity = releasedAmount
|
result.ReleasedQuantity = releasedAmount
|
||||||
result.UsageQuantity = currentUsage + usageDelta
|
result.UsageQuantity = currentUsage + usageDelta
|
||||||
result.PendingQuantity = currentPending + pendingDelta
|
result.PendingQuantity = currentPending + pendingDelta
|
||||||
if s.logger.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.logger.WithFields(logrus.Fields{
|
|
||||||
"usable_key": req.UsableKey.String(),
|
|
||||||
"usable_id": req.UsableID,
|
|
||||||
"product_warehouse_id": productWarehouseID,
|
|
||||||
"usage_delta": usageDelta,
|
|
||||||
"pending_delta": pendingDelta,
|
|
||||||
"released_quantity": releasedAmount,
|
|
||||||
"added_allocations": len(addedAlloc),
|
|
||||||
"final_usage_qty": result.UsageQuantity,
|
|
||||||
"final_pending_qty": result.PendingQuantity,
|
|
||||||
"final_requested_qty": result.RequestedQuantity,
|
|
||||||
}).Debug("fifo consume result")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -336,14 +296,6 @@ func (s *fifoService) ReleaseUsage(ctx context.Context, req StockReleaseRequest)
|
|||||||
if req.UsableID == 0 || strings.TrimSpace(req.UsableKey.String()) == "" {
|
if req.UsableID == 0 || strings.TrimSpace(req.UsableKey.String()) == "" {
|
||||||
return errors.New("usable key and id are required")
|
return errors.New("usable key and id are required")
|
||||||
}
|
}
|
||||||
if s.logger.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.logger.WithFields(logrus.Fields{
|
|
||||||
"usable_key": req.UsableKey.String(),
|
|
||||||
"usable_id": req.UsableID,
|
|
||||||
"reason": req.Reason,
|
|
||||||
}).Debug("fifo release request")
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.withTransaction(ctx, req.Tx, func(tx *gorm.DB) error {
|
return s.withTransaction(ctx, req.Tx, func(tx *gorm.DB) error {
|
||||||
cfg, ok := fifo.Usable(req.UsableKey)
|
cfg, ok := fifo.Usable(req.UsableKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -354,17 +306,6 @@ func (s *fifoService) ReleaseUsage(ctx context.Context, req StockReleaseRequest)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if s.logger.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.logger.WithFields(logrus.Fields{
|
|
||||||
"usable_key": req.UsableKey.String(),
|
|
||||||
"usable_id": req.UsableID,
|
|
||||||
"product_warehouse_id": ctxRow.ProductWarehouseID,
|
|
||||||
"current_usage_qty": ctxRow.UsageQty,
|
|
||||||
"current_pending_qty": ctxRow.PendingQty,
|
|
||||||
"current_total_qty": ctxRow.UsageQty + ctxRow.PendingQty,
|
|
||||||
}).Debug("fifo release context")
|
|
||||||
}
|
|
||||||
|
|
||||||
var usageDelta, pendingDelta float64
|
var usageDelta, pendingDelta float64
|
||||||
if ctxRow.UsageQty > 0 {
|
if ctxRow.UsageQty > 0 {
|
||||||
if _, err := s.releaseUsagePortion(ctx, tx, req.UsableKey, req.UsableID, ctxRow.UsageQty); err != nil {
|
if _, err := s.releaseUsagePortion(ctx, tx, req.UsableKey, req.UsableID, ctxRow.UsageQty); err != nil {
|
||||||
@@ -380,15 +321,6 @@ func (s *fifoService) ReleaseUsage(ctx context.Context, req StockReleaseRequest)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.logger.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.logger.WithFields(logrus.Fields{
|
|
||||||
"usable_key": req.UsableKey.String(),
|
|
||||||
"usable_id": req.UsableID,
|
|
||||||
"usage_delta": usageDelta,
|
|
||||||
"pending_delta": pendingDelta,
|
|
||||||
}).Debug("fifo release applied")
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.allocations.ReleaseByUsable(ctx, req.UsableKey.String(), req.UsableID, req.Reason, func(db *gorm.DB) *gorm.DB {
|
return s.allocations.ReleaseByUsable(ctx, req.UsableKey.String(), req.UsableID, req.Reason, func(db *gorm.DB) *gorm.DB {
|
||||||
return s.txOrDB(tx, db)
|
return s.txOrDB(tx, db)
|
||||||
})
|
})
|
||||||
|
|||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_constraint
|
||||||
|
WHERE conname = 'fk_project_flock_kandang_uniformity_project_flock_kandang'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
DROP CONSTRAINT fk_project_flock_kandang_uniformity_project_flock_kandang;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
ADD CONSTRAINT fk_project_flock_kandang_uniformity_project_flock_kandang
|
||||||
|
FOREIGN KEY (project_flock_kandang_id)
|
||||||
|
REFERENCES project_flock_kandangs (id)
|
||||||
|
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_tables
|
||||||
|
WHERE tablename = 'project_budgets'
|
||||||
|
) THEN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_constraint
|
||||||
|
WHERE conname = 'fk_project_budgets_project_flock_id'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_budgets
|
||||||
|
DROP CONSTRAINT fk_project_budgets_project_flock_id;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
ALTER TABLE project_budgets
|
||||||
|
ADD CONSTRAINT fk_project_budgets_project_flock_id
|
||||||
|
FOREIGN KEY (project_flock_id)
|
||||||
|
REFERENCES project_flocks(id);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_tables
|
||||||
|
WHERE tablename = 'project_flock_kandang_uniformity'
|
||||||
|
) THEN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'project_flock_kandang_uniformity'
|
||||||
|
AND column_name = 'created_at'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
ADD COLUMN created_at TIMESTAMPTZ DEFAULT NOW();
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'project_flock_kandang_uniformity'
|
||||||
|
AND column_name = 'updated_at'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
ADD COLUMN updated_at TIMESTAMPTZ DEFAULT NOW();
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'project_flock_kandang_uniformity'
|
||||||
|
AND column_name = 'deleted_at'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
ADD COLUMN deleted_at TIMESTAMPTZ;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_constraint
|
||||||
|
WHERE conname = 'fk_project_flock_kandang_uniformity_project_flock_kandang'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
DROP CONSTRAINT fk_project_flock_kandang_uniformity_project_flock_kandang;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
ADD CONSTRAINT fk_project_flock_kandang_uniformity_project_flock_kandang
|
||||||
|
FOREIGN KEY (project_flock_kandang_id)
|
||||||
|
REFERENCES project_flock_kandangs (id)
|
||||||
|
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_tables
|
||||||
|
WHERE tablename = 'project_budgets'
|
||||||
|
) THEN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_constraint
|
||||||
|
WHERE conname = 'fk_project_budgets_project_flock_id'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_budgets
|
||||||
|
DROP CONSTRAINT fk_project_budgets_project_flock_id;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
ALTER TABLE project_budgets
|
||||||
|
ADD CONSTRAINT fk_project_budgets_project_flock_id
|
||||||
|
FOREIGN KEY (project_flock_id)
|
||||||
|
REFERENCES project_flocks(id)
|
||||||
|
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_trigger
|
||||||
|
WHERE tgname = 'trg_soft_delete_fk_project_flock_kandang_uniformity'
|
||||||
|
) THEN
|
||||||
|
DROP TRIGGER trg_soft_delete_fk_project_flock_kandang_uniformity
|
||||||
|
ON project_flock_kandang_uniformity;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'project_flock_kandang_uniformity'
|
||||||
|
AND column_name = 'created_at'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
DROP COLUMN created_at;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'project_flock_kandang_uniformity'
|
||||||
|
AND column_name = 'updated_at'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
DROP COLUMN updated_at;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'project_flock_kandang_uniformity'
|
||||||
|
AND column_name = 'deleted_at'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE project_flock_kandang_uniformity
|
||||||
|
DROP COLUMN deleted_at;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
import (
|
import "time"
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectFlockKandangUniformity struct {
|
type ProjectFlockKandangUniformity struct {
|
||||||
Id uint `gorm:"primaryKey"`
|
Id uint `gorm:"primaryKey"`
|
||||||
@@ -18,9 +14,6 @@ type ProjectFlockKandangUniformity struct {
|
|||||||
UniformQty float64 `gorm:"type:numeric(15,3)"`
|
UniformQty float64 `gorm:"type:numeric(15,3)"`
|
||||||
NotUniformQty float64 `gorm:"type:numeric(15,3)"`
|
NotUniformQty float64 `gorm:"type:numeric(15,3)"`
|
||||||
UniformDate *time.Time `gorm:"type:timestamptz"`
|
UniformDate *time.Time `gorm:"type:timestamptz"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
|
||||||
CreatedBy uint `gorm:"not null"`
|
CreatedBy uint `gorm:"not null"`
|
||||||
|
|
||||||
ProjectFlockKandang ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"`
|
ProjectFlockKandang ProjectFlockKandang `gorm:"foreignKey:ProjectFlockKandangId;references:Id"`
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
|
pfutils "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/utils"
|
||||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
|
||||||
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||||
|
uniformityRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories"
|
||||||
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
utils "gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||||
|
|
||||||
@@ -866,6 +867,14 @@ func (s projectflockService) detachKandangs(ctx context.Context, dbTransaction *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(pfkIDs) > 0 {
|
if len(pfkIDs) > 0 {
|
||||||
|
uniformityRepo := uniformityRepository.NewUniformityRepository(s.Repository.DB())
|
||||||
|
if dbTransaction != nil {
|
||||||
|
uniformityRepo = uniformityRepository.NewUniformityRepository(dbTransaction)
|
||||||
|
}
|
||||||
|
if err := uniformityRepo.DeleteByProjectFlockKandangIDs(ctx, pfkIDs); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove uniformity data for project flock kandang")
|
||||||
|
}
|
||||||
|
|
||||||
pwRepo := s.ProductWarehouseRepo
|
pwRepo := s.ProductWarehouseRepo
|
||||||
if dbTransaction != nil {
|
if dbTransaction != nil {
|
||||||
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
pwRepo = productWarehouseRepository.NewProductWarehouseRepository(dbTransaction)
|
||||||
|
|||||||
@@ -333,13 +333,6 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
|||||||
s.Log.Errorf("Failed to list existing stocks: %+v", err)
|
s.Log.Errorf("Failed to list existing stocks: %+v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if s.Log != nil && s.Log.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.Log.WithFields(logrus.Fields{
|
|
||||||
"recording_id": recordingEntity.Id,
|
|
||||||
"existing": summarizeExistingStocks(existingStocks),
|
|
||||||
"incoming": summarizeIncomingStocks(req.Stocks),
|
|
||||||
}).Debug("recording update stock comparison")
|
|
||||||
}
|
|
||||||
if stocksMatch(existingStocks, req.Stocks) {
|
if stocksMatch(existingStocks, req.Stocks) {
|
||||||
hasStockChanges = false
|
hasStockChanges = false
|
||||||
}
|
}
|
||||||
@@ -698,16 +691,6 @@ func (s *recordingService) consumeRecordingStocks(ctx context.Context, tx *gorm.
|
|||||||
}
|
}
|
||||||
desiredTotal := desired + pending
|
desiredTotal := desired + pending
|
||||||
|
|
||||||
if s.Log != nil && s.Log.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.Log.WithFields(logrus.Fields{
|
|
||||||
"recording_stock_id": stock.Id,
|
|
||||||
"product_warehouse_id": stock.ProductWarehouseId,
|
|
||||||
"desired_usage_qty": desired,
|
|
||||||
"desired_pending_qty": pending,
|
|
||||||
"desired_total_qty": desiredTotal,
|
|
||||||
}).Debug("recording fifo consume start")
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := s.FifoSvc.Consume(ctx, commonSvc.StockConsumeRequest{
|
result, err := s.FifoSvc.Consume(ctx, commonSvc.StockConsumeRequest{
|
||||||
UsableKey: recordingStockUsableKey,
|
UsableKey: recordingStockUsableKey,
|
||||||
UsableID: stock.Id,
|
UsableID: stock.Id,
|
||||||
@@ -721,17 +704,6 @@ func (s *recordingService) consumeRecordingStocks(ctx context.Context, tx *gorm.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Log != nil && s.Log.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.Log.WithFields(logrus.Fields{
|
|
||||||
"recording_stock_id": stock.Id,
|
|
||||||
"product_warehouse_id": stock.ProductWarehouseId,
|
|
||||||
"result_usage_qty": result.UsageQuantity,
|
|
||||||
"result_pending_qty": result.PendingQuantity,
|
|
||||||
"released_qty": result.ReleasedQuantity,
|
|
||||||
"added_allocations": len(result.AddedAllocations),
|
|
||||||
}).Debug("recording fifo consume result")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.Repository.UpdateStockUsage(tx, stock.Id, result.UsageQuantity, result.PendingQuantity); err != nil {
|
if err := s.Repository.UpdateStockUsage(tx, stock.Id, result.UsageQuantity, result.PendingQuantity); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -754,23 +726,6 @@ func (s *recordingService) releaseRecordingStocks(ctx context.Context, tx *gorm.
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var usage float64
|
|
||||||
var pending float64
|
|
||||||
if stock.UsageQty != nil {
|
|
||||||
usage = *stock.UsageQty
|
|
||||||
}
|
|
||||||
if stock.PendingQty != nil {
|
|
||||||
pending = *stock.PendingQty
|
|
||||||
}
|
|
||||||
if s.Log != nil && s.Log.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
s.Log.WithFields(logrus.Fields{
|
|
||||||
"recording_stock_id": stock.Id,
|
|
||||||
"product_warehouse_id": stock.ProductWarehouseId,
|
|
||||||
"current_usage_qty": usage,
|
|
||||||
"current_pending_qty": pending,
|
|
||||||
}).Debug("recording fifo release start")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.FifoSvc.ReleaseUsage(ctx, commonSvc.StockReleaseRequest{
|
if err := s.FifoSvc.ReleaseUsage(ctx, commonSvc.StockReleaseRequest{
|
||||||
UsableKey: recordingStockUsableKey,
|
UsableKey: recordingStockUsableKey,
|
||||||
UsableID: stock.Id,
|
UsableID: stock.Id,
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ type UniformityListDTO struct {
|
|||||||
MeanDown float64 `json:"mean_down"`
|
MeanDown float64 `json:"mean_down"`
|
||||||
StandardMeanWeight *float64 `json:"standard_mean_weight"`
|
StandardMeanWeight *float64 `json:"standard_mean_weight"`
|
||||||
StandardUniformity *float64 `json:"standard_uniformity"`
|
StandardUniformity *float64 `json:"standard_uniformity"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
CreatedBy uint `json:"created_by"`
|
CreatedBy uint `json:"created_by"`
|
||||||
LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"`
|
LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"`
|
||||||
}
|
}
|
||||||
@@ -154,7 +153,6 @@ func ToUniformityListDTOs(items []entity.ProjectFlockKandangUniformity) []Unifor
|
|||||||
UniformQty: item.UniformQty,
|
UniformQty: item.UniformQty,
|
||||||
MeanUp: item.MeanUp,
|
MeanUp: item.MeanUp,
|
||||||
MeanDown: item.MeanDown,
|
MeanDown: item.MeanDown,
|
||||||
CreatedAt: item.CreatedAt,
|
|
||||||
CreatedBy: item.CreatedBy,
|
CreatedBy: item.CreatedBy,
|
||||||
LatestApproval: latestApproval,
|
LatestApproval: latestApproval,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -8,6 +10,7 @@ import (
|
|||||||
|
|
||||||
type UniformityRepository interface {
|
type UniformityRepository interface {
|
||||||
repository.BaseRepository[entity.ProjectFlockKandangUniformity]
|
repository.BaseRepository[entity.ProjectFlockKandangUniformity]
|
||||||
|
DeleteByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type UniformityRepositoryImpl struct {
|
type UniformityRepositoryImpl struct {
|
||||||
@@ -19,3 +22,13 @@ func NewUniformityRepository(db *gorm.DB) UniformityRepository {
|
|||||||
BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectFlockKandangUniformity](db),
|
BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectFlockKandangUniformity](db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UniformityRepositoryImpl) DeleteByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) error {
|
||||||
|
if len(projectFlockKandangIDs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return r.DB().WithContext(ctx).
|
||||||
|
Unscoped().
|
||||||
|
Where("project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
||||||
|
Delete(&entity.ProjectFlockKandangUniformity{}).Error
|
||||||
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func (s uniformityService) GetAll(c *fiber.Ctx, params *validation.Query) ([]ent
|
|||||||
if params.Week != 0 {
|
if params.Week != 0 {
|
||||||
db = db.Where("week = ?", params.Week)
|
db = db.Where("week = ?", params.Week)
|
||||||
}
|
}
|
||||||
return db.Order("uniform_date DESC").Order("created_at DESC")
|
return db.Order("uniform_date DESC").Order("id DESC")
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -180,7 +180,10 @@ func (ctrl *PurchaseController) ReceiveProducts(c *fiber.Ctx) error {
|
|||||||
req.Items = []validation.ReceivePurchaseItemRequest{singleItem}
|
req.Items = []validation.ReceivePurchaseItemRequest{singleItem}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req.TravelDocuments = form.File["documents"]
|
req.TravelDocuments = form.File["travel_documents"]
|
||||||
|
if len(req.TravelDocuments) == 0 {
|
||||||
|
req.TravelDocuments = form.File["documents"]
|
||||||
|
}
|
||||||
result, err := ctrl.service.ReceiveProducts(c, uint(id), req)
|
result, err := ctrl.service.ReceiveProducts(c, uint(id), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -999,6 +999,22 @@ func (s *purchaseService) uploadTravelDocument(
|
|||||||
return "", errors.New("document service not available")
|
return "", errors.New("document service not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
documents, err := s.DocumentSvc.ListByTarget(ctx, string(utils.DocumentableTypePurchaseItem), uint64(itemID))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(documents) > 0 {
|
||||||
|
var ids []uint
|
||||||
|
for _, doc := range documents {
|
||||||
|
if doc.Type == string(utils.DocumentTypePurchaseTravel) {
|
||||||
|
ids = append(ids, doc.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := s.DocumentSvc.DeleteDocuments(ctx, ids, true); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
documentFiles := []commonSvc.DocumentFile{{
|
documentFiles := []commonSvc.DocumentFile{{
|
||||||
File: file,
|
File: file,
|
||||||
Type: string(utils.DocumentTypePurchaseTravel),
|
Type: string(utils.DocumentTypePurchaseTravel),
|
||||||
@@ -1015,7 +1031,7 @@ func (s *purchaseService) uploadTravelDocument(
|
|||||||
if len(results) == 0 {
|
if len(results) == 0 {
|
||||||
return "", errors.New("upload result is empty")
|
return "", errors.New("upload result is empty")
|
||||||
}
|
}
|
||||||
return results[0].URL, nil
|
return results[0].Document.Path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.DeletePurchaseItemsRequest) (*entity.Purchase, error) {
|
func (s *purchaseService) DeleteItems(c *fiber.Ctx, id uint, req *validation.DeletePurchaseItemsRequest) (*entity.Purchase, error) {
|
||||||
@@ -1499,10 +1515,56 @@ func (s *purchaseService) loadPurchase(
|
|||||||
if err := s.attachLatestApproval(ctx, purchase); err != nil {
|
if err := s.attachLatestApproval(ctx, purchase); err != nil {
|
||||||
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", id, err)
|
s.Log.Warnf("Unable to attach latest approval for purchase %d: %+v", id, err)
|
||||||
}
|
}
|
||||||
|
s.applyTravelDocumentURLs(ctx, purchase)
|
||||||
|
|
||||||
return purchase, nil
|
return purchase, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *purchaseService) applyTravelDocumentURLs(ctx context.Context, purchase *entity.Purchase) {
|
||||||
|
if purchase == nil || s.DocumentSvc == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range purchase.Items {
|
||||||
|
item := &purchase.Items[i]
|
||||||
|
documents, err := s.DocumentSvc.ListByTarget(ctx, string(utils.DocumentableTypePurchaseItem), uint64(item.Id))
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Warnf("Unable to load travel documents for purchase item %d: %+v", item.Id, err)
|
||||||
|
} else {
|
||||||
|
var targetDoc *entity.Document
|
||||||
|
for j := len(documents) - 1; j >= 0; j-- {
|
||||||
|
if documents[j].Type == string(utils.DocumentTypePurchaseTravel) {
|
||||||
|
targetDoc = &documents[j]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if targetDoc != nil {
|
||||||
|
url, err := s.DocumentSvc.PresignURL(ctx, *targetDoc, 15*time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Warnf("Unable to presign travel document for purchase item %d: %+v", item.Id, err)
|
||||||
|
} else if url != "" {
|
||||||
|
item.TravelNumberDocs = &url
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path := item.TravelNumberDocs
|
||||||
|
if path == nil || strings.TrimSpace(*path) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
url, err := commonSvc.ResolveDocumentURL(ctx, s.DocumentSvc, *path, 15*time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Warnf("Unable to presign travel document for purchase item %d: %+v", item.Id, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if url == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item.TravelNumberDocs = &url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func collectPFKIDsFromPurchase(p *entity.Purchase) []uint {
|
func collectPFKIDsFromPurchase(p *entity.Purchase) []uint {
|
||||||
seen := make(map[uint]struct{})
|
seen := make(map[uint]struct{})
|
||||||
ids := make([]uint, 0)
|
ids := make([]uint, 0)
|
||||||
|
|||||||
@@ -426,12 +426,12 @@ const (
|
|||||||
DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT"
|
DocumentTypeTransfer DocumentType = "STOCK_TRANSFER_DOCUMENT"
|
||||||
DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT"
|
DocumentTypeExpense DocumentType = "EXPENSE_DOCUMENT"
|
||||||
DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT"
|
DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT"
|
||||||
DocumentTypePurchaseTravel DocumentType = "PURCHASE_TRAVEL_DOCUMENT"
|
DocumentTypePurchaseTravel DocumentType = "PURCHASE_TRAVEL_DOCUMENT"
|
||||||
|
|
||||||
DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER"
|
DocumentableTypeTransfer DocumentableType = "STOCK_TRANSFER"
|
||||||
DocumentableTypeExpense DocumentableType = "EXPENSE"
|
DocumentableTypeExpense DocumentableType = "EXPENSE"
|
||||||
DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
|
DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
|
||||||
DocumentableTypePurchaseItem DocumentableType = "PURCHASE_ITEM"
|
DocumentableTypePurchaseItem DocumentableType = "PURCHASE_ITEM"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user