sozsoft-platform/configs/seeds/sql/object/Stk_P_TransferValidate.sql
2026-10-19 17:35:08 +03:00

145 lines
8.8 KiB
Transact-SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Tamamla: yapılan miktarlar stoğa işlenir (Stk_T_Stock, ürün biriminde, lot kırılımlı). İç konumdan çıkışta stok yetmezse
-- işlem durur; dış konumlar stok tutmaz. Kaynak ve hedefi aynı konum olan belge stoğa dokunmaz (teslim kaydıdır). Envanter takibi kapalı ürün stoğa girmez. Lot/seri takipli üründe lot toplamı
-- yapılan miktara eşit olmalıdır. Sipariş kalemlerinin alınan, talep kalemlerinin teslim edilen miktarı güncellenir (iadede düşülür);
-- siparişli alım ürün–tedarikçi fiyatını yazar (Stk_P_TransferSupplierPrice).
-- Talepten az yapılan satırların kalanı aynı türde yeni belgeye (backorder) geçer.
CREATE OR ALTER PROCEDURE [dbo].[Stk_P_TransferValidate]
@Id uniqueidentifier,
@UserId uniqueidentifier = NULL
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @Tenant uniqueidentifier, @Status nvarchar(16), @Kind nvarchar(32), @ReturnOf uniqueidentifier,
@Src uniqueidentifier, @Dst uniqueidentifier, @SrcInternal bit = 0, @DstInternal bit = 0,
@DstBranch uniqueidentifier, @DstWarehouse uniqueidentifier, @Sign int, @New uniqueidentifier,
@Now datetime = GETUTCDATE(), @Msg nvarchar(512);
BEGIN TRANSACTION;
SELECT @Tenant = TenantId, @Status = Status, @Kind = OperationKind, @ReturnOf = ReturnOfId,
@Src = SourceLocationId, @Dst = DestinationLocationId
FROM Stk_T_Transfer WITH (UPDLOCK, HOLDLOCK)
WHERE Id = @Id;
IF @Status <> 'Ready' THROW 50306, N'Yalnız hazır belge tamamlanabilir.', 1;
SET @Sign = CASE WHEN @ReturnOf IS NULL THEN 1 ELSE -1 END;
SELECT @SrcInternal = CASE WHEN LocationType = 'Internal' THEN 1 ELSE 0 END FROM Stk_T_Location WHERE Id = @Src;
SELECT @DstInternal = CASE WHEN LocationType = 'Internal' THEN 1 ELSE 0 END, @DstBranch = BranchId, @DstWarehouse = WarehouseId
FROM Stk_T_Location WHERE Id = @Dst;
IF NOT EXISTS (SELECT 1 FROM Stk_T_TransferLine WHERE TransferId = @Id AND IsDeleted = 0 AND Quantity > 0)
THROW 50309, N'Yapılan miktarı girilmiş satır yok.', 1;
SELECT TOP 1 @Msg = CONCAT(p.Name, N': lot/seri toplamı ', FORMAT(z.Quantity, '0.####'), N', yapılan miktar ', FORMAT(l.Quantity, '0.####'))
FROM Stk_T_TransferLine l
INNER JOIN Stk_T_Product p ON p.Id = l.ProductId
CROSS APPLY (SELECT ISNULL(SUM(lt.Quantity), 0) AS Quantity FROM Stk_T_TransferLineLot lt WHERE lt.TransferLineId = l.Id AND lt.IsDeleted = 0) z
WHERE l.TransferId = @Id AND l.IsDeleted = 0 AND l.Quantity > 0 AND p.TrackInventory = 1 AND p.TrackingMethod IN ('Lot', 'Serial')
AND z.Quantity <> l.Quantity;
IF @Msg IS NOT NULL
BEGIN
SET @Msg = CONCAT(N'Lot/seri miktarı yapılan miktara eşit değil — ', @Msg);
THROW 50310, @Msg, 1;
END
SELECT TOP 1 @Msg = CONCAT(p.Name, ' / ', z.LotNo)
FROM Stk_T_TransferLineLot z
INNER JOIN Stk_T_TransferLine l ON l.Id = z.TransferLineId
INNER JOIN Stk_T_Product p ON p.Id = l.ProductId
WHERE l.TransferId = @Id AND l.IsDeleted = 0 AND z.IsDeleted = 0 AND p.TrackingMethod = 'Serial'
AND (z.Quantity <> 1 OR EXISTS (SELECT 1 FROM Stk_T_TransferLineLot z2
INNER JOIN Stk_T_TransferLine l2 ON l2.Id = z2.TransferLineId
WHERE l2.TransferId = @Id AND l2.IsDeleted = 0 AND z2.IsDeleted = 0
AND l2.ProductId = l.ProductId AND z2.LotNo = z.LotNo AND z2.Id <> z.Id));
IF @Msg IS NOT NULL
BEGIN
SET @Msg = CONCAT(N'Seri numaralı üründe her seri 1 adet ve tekil olmalıdır: ', @Msg);
THROW 50311, @Msg, 1;
END
-- Stoğa işlenecek hareket: ürün × lot, ürün biriminde.
DECLARE @Move TABLE (ProductId uniqueidentifier NOT NULL, LotNo nvarchar(64) NOT NULL, Quantity decimal(18, 4) NOT NULL, UomId nvarchar(64) NOT NULL,
PRIMARY KEY (ProductId, LotNo));
INSERT INTO @Move (ProductId, LotNo, Quantity, UomId)
SELECT m.ProductId, m.LotNo, SUM(m.Quantity), m.UomId
FROM (SELECT l.ProductId, p.UomId,
CASE WHEN p.TrackingMethod IN ('Lot', 'Serial') THEN z.LotNo ELSE '' END AS LotNo,
dbo.Stk_F_UomConvert(CASE WHEN p.TrackingMethod IN ('Lot', 'Serial') THEN z.Quantity ELSE l.Quantity END, l.UomId, p.UomId) AS Quantity
FROM Stk_T_TransferLine l
INNER JOIN Stk_T_Product p ON p.Id = l.ProductId
LEFT JOIN Stk_T_TransferLineLot z ON z.TransferLineId = l.Id AND z.IsDeleted = 0 AND p.TrackingMethod IN ('Lot', 'Serial')
WHERE l.TransferId = @Id AND l.IsDeleted = 0 AND l.Quantity > 0 AND p.TrackInventory = 1) m
GROUP BY m.ProductId, m.LotNo, m.UomId;
IF @SrcInternal = 1
BEGIN
SELECT TOP 1 @Msg = CONCAT(p.Name, CASE WHEN m.LotNo = '' THEN '' ELSE CONCAT(' / ', m.LotNo) END)
FROM @Move m
INNER JOIN Stk_T_Product p ON p.Id = m.ProductId
LEFT JOIN Stk_T_Stock s WITH (UPDLOCK, HOLDLOCK)
ON s.LocationId = @Src AND s.ProductId = m.ProductId AND s.LotNo = m.LotNo
AND (s.TenantId = @Tenant OR (s.TenantId IS NULL AND @Tenant IS NULL))
WHERE ISNULL(s.Quantity, 0) < m.Quantity;
IF @Msg IS NOT NULL
BEGIN
SET @Msg = CONCAT(N'Kaynak konumda yeterli stok yok: ', @Msg);
THROW 50312, @Msg, 1;
END
-- Kaynak ve hedef aynıysa stok yerinde kalır: belge teslimi kaydeder (yeterlilik yine denetlenir).
IF @Src <> @Dst
UPDATE s SET Quantity = s.Quantity - m.Quantity, LastMoveDate = @Now, LastModificationTime = @Now, LastModifierId = @UserId
FROM Stk_T_Stock s
INNER JOIN @Move m ON m.ProductId = s.ProductId AND m.LotNo = s.LotNo
WHERE s.LocationId = @Src AND (s.TenantId = @Tenant OR (s.TenantId IS NULL AND @Tenant IS NULL));
END
IF @DstInternal = 1 AND @Src <> @Dst
BEGIN
UPDATE s SET Quantity = s.Quantity + m.Quantity, LastMoveDate = @Now, LastModificationTime = @Now, LastModifierId = @UserId,
InDate = CASE WHEN s.Quantity <= 0 THEN @Now ELSE s.InDate END
FROM Stk_T_Stock s WITH (UPDLOCK, HOLDLOCK)
INNER JOIN @Move m ON m.ProductId = s.ProductId AND m.LotNo = s.LotNo
WHERE s.LocationId = @Dst AND (s.TenantId = @Tenant OR (s.TenantId IS NULL AND @Tenant IS NULL));
INSERT INTO Stk_T_Stock (Id, TenantId, BranchId, WarehouseId, LocationId, ProductId, LotNo, Quantity, UomId, InDate, LastMoveDate, CreationTime, CreatorId, IsDeleted)
SELECT NEWID(), @Tenant, @DstBranch, @DstWarehouse, @Dst, m.ProductId, m.LotNo, m.Quantity, m.UomId, @Now, @Now, @Now, @UserId, 0
FROM @Move m
WHERE NOT EXISTS (SELECT 1 FROM Stk_T_Stock s
WHERE s.LocationId = @Dst AND s.ProductId = m.ProductId AND s.LotNo = m.LotNo
AND (s.TenantId = @Tenant OR (s.TenantId IS NULL AND @Tenant IS NULL)));
END
UPDATE Stk_T_Transfer
SET Status = 'Done', EffectiveDate = @Now,
ReceivedByUserId = CASE WHEN @Kind = 'InternalTransfer' THEN @UserId ELSE ReceivedByUserId END,
ReceivedDate = CASE WHEN @Kind = 'InternalTransfer' THEN @Now ELSE ReceivedDate END
WHERE Id = @Id;
UPDATE ol SET ReceivedQuantity = ol.ReceivedQuantity + @Sign * x.Quantity
FROM Prc_T_PurchaseOrderLine ol
INNER JOIN (SELECT l.PurchaseOrderLineId, SUM(dbo.Stk_F_UomConvert(l.Quantity, l.UomId, pl.UomId)) AS Quantity
FROM Stk_T_TransferLine l
INNER JOIN Prc_T_PurchaseOrderLine pl ON pl.Id = l.PurchaseOrderLineId
WHERE l.TransferId = @Id AND l.IsDeleted = 0 AND l.Quantity > 0
GROUP BY l.PurchaseOrderLineId) x ON x.PurchaseOrderLineId = ol.Id;
EXEC Stk_P_TransferSupplierPrice @Id, @UserId;
UPDATE i SET DeliveredQuantity = i.DeliveredQuantity + @Sign * x.Quantity,
LineStatus = CASE WHEN i.DeliveredQuantity + @Sign * x.Quantity >= i.Quantity THEN 'Done'
WHEN i.LineStatus = 'Done' THEN 'Waiting' ELSE i.LineStatus END
FROM Prc_T_MaterialRequestItem i
INNER JOIN (SELECT l.MaterialRequestItemId, SUM(dbo.Stk_F_UomConvert(l.Quantity, l.UomId, mi.UomId)) AS Quantity
FROM Stk_T_TransferLine l
INNER JOIN Prc_T_MaterialRequestItem mi ON mi.Id = l.MaterialRequestItemId
WHERE l.TransferId = @Id AND l.IsDeleted = 0 AND l.Quantity > 0
GROUP BY l.MaterialRequestItemId) x ON x.MaterialRequestItemId = i.Id;
IF @ReturnOf IS NULL AND EXISTS (SELECT 1 FROM Stk_T_TransferLine WHERE TransferId = @Id AND IsDeleted = 0 AND Quantity < DemandQuantity)
EXEC Stk_P_TransferCopy @Id, 'Backorder', @UserId, @New OUTPUT;
EXEC Stk_P_TransferRecalc @Id;
COMMIT TRANSACTION;
END