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

193 lines
12 KiB
Transact-SQL
Raw Permalink 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.

-- Planlama kararı: talep kaleminin planlanacak kalanından @PlanQuantity kadarını satınalmaya ya da iç transfere ayırır; kalanın geri kalanı
-- listede kalır. Planla diyaloğunun onayı (Prc_P_MaterialRequestPlanConfirm) her taslak plan satırı için çağırır.
-- Purchase: tedarikçinin talebin şubesi ve deposu için taslak teklif talebi varsa kalem ona eklenir (kalem zaten oradaysa miktarı artar), yoksa
-- talebin deposunun alım operasyon türüyle yeni taslak teklif talebi açılır (para birimi ve koşullar kontak kartından; alıcı — satınalma sorumlusu —
-- planlayan). Fiyat tedarikçinin fiyat listesinden gelir; teklif → sipariş → alım akışı oradan sürer.
-- Transfer: kaynak konumun (lot/seri takipli üründe @PlanLotNo lotunun) serbest stoğu (Prc_V_MaterialRequestPlanSource) yetmelidir; aynı
-- kaynak → talebin konumu için taslak iç transfer varsa satır ona, yoksa kaynak deponun iç transfer operasyon türüyle yeni
-- taslak açılır. Depoda aynı türden birkaç operasyon türü olabilir (Bakım Sarf Tüketimi, Departman Sarf Çıkışı …); türün kendi
-- numaratörünü taşıyanı (SequenceName '….InternalTransfer' / '….Receipt' ile biter) seçilir, taslak da yalnız o türde aranır. Lot planlandıysa transfer satırının lot dağılımına (Stk_T_TransferLineLot, satırın biriminde) eklenir; depo Detaylar ya da
-- Otomatik Ata ile değiştirebilir. Kalanın tamamı transferle
-- planlanan, satınalma payı olmayan kalem transfer belgesinin yeniden hesabında kapanır (Prc_P_MaterialRequestItemSync).
-- Stock: stok talebin teslim konumundadır; Transfer gibi iç transfer açılır, kaynak ve hedef teslim konumudur (Doğrula stoğa dokunmaz,
-- teslimi kaydeder: kalemin teslim edilen miktarı artar). Belge numarası ve durumu Plan Takibi'ne transferden yansır.
CREATE OR ALTER PROCEDURE [dbo].[Prc_P_MaterialRequestPlan]
@Id uniqueidentifier,
@PlanMethod nvarchar(16),
@PlanQuantity decimal(18, 4),
@PlanSupplierId uniqueidentifier,
@PlanSourceLocationId uniqueidentifier,
@PlanLotNo nvarchar(64),
@TenantId uniqueidentifier,
@LastModifierId uniqueidentifier
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @ProductId uniqueidentifier, @UomId nvarchar(64), @DueDate datetime, @Reason nvarchar(256), @Branch uniqueidentifier,
@Warehouse uniqueidentifier, @Location uniqueidentifier, @RequestNo nvarchar(32), @Remaining decimal(18, 4),
@Doc uniqueidentifier, @Line uniqueidentifier, @OpType uniqueidentifier, @SrcWarehouse uniqueidentifier,
@Free decimal(18, 4), @No nvarchar(128), @Msg nvarchar(400);
BEGIN TRANSACTION;
-- Kalem kilitlenir: aynı kalemin eşzamanlı iki planı kalanı iki kez dağıtamaz.
SELECT @ProductId = i.ProductId, @UomId = i.UomId, @DueDate = i.DueDate, @Reason = i.RequestReason, @Branch = r.BranchId,
@Warehouse = r.WarehouseId, @Location = r.LocationId, @RequestNo = r.RequestNo
FROM Prc_T_MaterialRequestItem i WITH (UPDLOCK, HOLDLOCK)
INNER JOIN Prc_T_MaterialRequest r ON r.Id = i.MaterialRequestId
WHERE i.Id = @Id AND i.IsDeleted = 0 AND i.LineStatus = 'Waiting' AND r.IsDeleted = 0
AND (i.TenantId = @TenantId OR (i.TenantId IS NULL AND @TenantId IS NULL))
AND r.ApprovalStatus IN (N'Onaylandı', N'Teklif Talebi', N'Teklif Talebi Gönderildi', N'Satınalma Siparişi');
IF @ProductId IS NULL
THROW 50191, N'Kalem planlanamaz: talep onaylı değil ya da kalem kapalı.', 1;
SELECT @Remaining = RemainingQuantity FROM Prc_V_MaterialRequestItemPlan WHERE Id = @Id;
IF ISNULL(@PlanQuantity, 0) <= 0
THROW 50192, N'Plan miktarı sıfırdan büyük olmalıdır.', 1;
IF @PlanQuantity > @Remaining
BEGIN
SET @Msg = CONCAT(N'Plan miktarı planlanacak kalanı aşamaz (kalan: ', FORMAT(@Remaining, '0.####'), N' ', @UomId, N').');
THROW 50193, @Msg, 1;
END
IF @PlanMethod = 'Purchase'
BEGIN
IF @PlanSupplierId IS NULL
THROW 50194, N'Satınalma kararında tedarikçi seçilmelidir.', 1;
SELECT TOP 1 @Doc = Id
FROM Prc_T_PurchaseRfq
WHERE IsDeleted = 0 AND Status = 'Draft' AND SupplierId = @PlanSupplierId AND BranchId = @Branch AND WarehouseId = @Warehouse
AND (TenantId = @TenantId OR (TenantId IS NULL AND @TenantId IS NULL))
ORDER BY CreationTime DESC;
IF @Doc IS NULL
BEGIN
SELECT TOP 1 @OpType = Id
FROM Stk_T_OperationType
WHERE IsDeleted = 0 AND IsActive = 1 AND OperationKind = 'Receipt' AND WarehouseId = @Warehouse
AND (TenantId = @TenantId OR (TenantId IS NULL AND @TenantId IS NULL))
ORDER BY CASE WHEN SequenceName LIKE CONCAT('%.', OperationKind) THEN 0 ELSE 1 END, Name;
IF @OpType IS NULL
THROW 50195, N'Talebin deposu için aktif bir alım operasyon türü tanımlı değil.', 1;
SET @Doc = NEWID();
EXEC Adm_P_SequenceNext N'Prc.PurchaseRfq', @TenantId, @No OUTPUT;
INSERT INTO Prc_T_PurchaseRfq (Id, TenantId, RfqNo, TenderGroupId, SupplierId, BranchId, OperationTypeId, WarehouseId, CurrencyId,
BuyerUserId, IncotermId, IncotermLocation, PaymentTermId, CreationTime, CreatorId, IsDeleted)
SELECT @Doc, @TenantId, LEFT(@No, 32), @Doc, c.Id, @Branch, @OpType, @Warehouse, COALESCE(c.SupplierCurrency, 'TRY'),
@LastModifierId, c.PurchaseIncotermId, c.PurchaseIncotermLocation, c.PurchasePaymentTermId,
GETUTCDATE(), @LastModifierId, 0
FROM Adm_T_Contact c
WHERE c.Id = @PlanSupplierId AND c.IsDeleted = 0;
IF @@ROWCOUNT = 0
THROW 50194, N'Satınalma kararında tedarikçi seçilmelidir.', 1;
END
SELECT @Line = Id FROM Prc_T_PurchaseRfqLine WHERE PurchaseRfqId = @Doc AND MaterialRequestItemId = @Id AND IsDeleted = 0;
IF @Line IS NOT NULL
UPDATE Prc_T_PurchaseRfqLine
SET Quantity = Quantity + dbo.Stk_F_UomConvert(@PlanQuantity, @UomId, UomId), LastModificationTime = GETUTCDATE(), LastModifierId = @LastModifierId
WHERE Id = @Line;
ELSE
INSERT INTO Prc_T_PurchaseRfqLine (Id, TenantId, PurchaseRfqId, ProductId, Description, Quantity, UomId, UnitPrice, TaxRate, Amount,
DeliveryDate, MaterialRequestItemId, CreationTime, CreatorId, IsDeleted)
SELECT NEWID(), @TenantId, @Doc, @ProductId, @Reason, @PlanQuantity, @UomId,
ISNULL((SELECT TOP 1 ps.Price FROM Stk_T_ProductSupplier ps
WHERE ps.ProductId = @ProductId AND ps.ContactId = @PlanSupplierId AND ps.IsDeleted = 0
ORDER BY ps.MinQuantity), 0),
ISNULL(p.PurchaseTaxRate, 0), 0, @DueDate, @Id, GETUTCDATE(), @LastModifierId, 0
FROM Stk_T_Product p
WHERE p.Id = @ProductId;
EXEC Prc_P_PurchaseRfqRecalc @Doc;
END
ELSE IF @PlanMethod IN ('Transfer', 'Stock')
BEGIN
IF @PlanMethod = 'Stock'
SET @PlanSourceLocationId = @Location;
IF @PlanSourceLocationId IS NULL
THROW 50196, N'İç transfer kararında kaynak konum seçilmelidir.', 1;
-- Konum ve serbest stok kuralı diyaloğun İç Transfer ızgarasıyla aynıdır.
SELECT @SrcWarehouse = WarehouseId, @Free = FreeQuantity
FROM Prc_V_MaterialRequestPlanSource
WHERE BaseId = @Id AND LocationId = @PlanSourceLocationId AND ISNULL(LotNo, '') = ISNULL(@PlanLotNo, '');
IF @SrcWarehouse IS NULL OR (@PlanMethod = 'Transfer' AND @PlanSourceLocationId = @Location)
THROW 50197, N'Kaynak konum, talebin teslim konumundan farklı ve ürünün (lot/seri takipli üründe lotun) stoğu olan bir iç konum olmalıdır.', 1;
IF @PlanQuantity > @Free
BEGIN
SET @Msg = CONCAT(N'Kaynak konumda yeterli serbest stok yok (serbest: ', FORMAT(CASE WHEN @Free > 0 THEN @Free ELSE 0 END, '0.####'), N' ', @UomId, N').');
THROW 50198, @Msg, 1;
END
SELECT TOP 1 @OpType = Id
FROM Stk_T_OperationType
WHERE IsDeleted = 0 AND IsActive = 1 AND OperationKind = 'InternalTransfer' AND WarehouseId = @SrcWarehouse
AND (TenantId = @TenantId OR (TenantId IS NULL AND @TenantId IS NULL))
ORDER BY CASE WHEN SequenceName LIKE CONCAT('%.', OperationKind) THEN 0 ELSE 1 END, Name;
IF @OpType IS NULL
THROW 50199, N'Kaynak depo için aktif bir iç transfer operasyon türü tanımlı değil.', 1;
SELECT TOP 1 @Doc = Id
FROM Stk_T_Transfer
WHERE IsDeleted = 0 AND OperationTypeId = @OpType AND Status = 'Draft' AND ReturnOfId IS NULL AND BackorderOfId IS NULL
AND SourceLocationId = @PlanSourceLocationId AND DestinationLocationId = @Location
AND (TenantId = @TenantId OR (TenantId IS NULL AND @TenantId IS NULL))
ORDER BY CreationTime DESC;
IF @Doc IS NULL
BEGIN
SET @Doc = NEWID();
INSERT INTO Stk_T_Transfer (Id, TenantId, BranchId, WarehouseId, OperationTypeId, OperationKind, SourceLocationId, DestinationLocationId,
SourceDocument, ResponsibleUserId, Status, CreationTime, CreatorId, IsDeleted)
SELECT @Doc, @TenantId, ot.BranchId, ot.WarehouseId, ot.Id, 'InternalTransfer', @PlanSourceLocationId, @Location,
@RequestNo, @LastModifierId, 'Draft', GETUTCDATE(), @LastModifierId, 0
FROM Stk_T_OperationType ot
WHERE ot.Id = @OpType;
END
ELSE
UPDATE Stk_T_Transfer
SET SourceDocument = LEFT(CONCAT(SourceDocument, CASE WHEN ISNULL(SourceDocument, '') = '' THEN '' ELSE N', ' END, @RequestNo), 128)
WHERE Id = @Doc AND CHARINDEX(@RequestNo, ISNULL(SourceDocument, '')) = 0;
-- Planlanan miktar yapılacak miktardır: lotsuz satırda doğrudan yazılır, lotlu satırda lot dağılımından (Stk_P_TransferRecalc) gelir.
SELECT @Line = Id FROM Stk_T_TransferLine WHERE TransferId = @Doc AND MaterialRequestItemId = @Id AND IsDeleted = 0;
IF @Line IS NOT NULL
UPDATE Stk_T_TransferLine
SET DemandQuantity = DemandQuantity + dbo.Stk_F_UomConvert(@PlanQuantity, @UomId, UomId),
Quantity = Quantity + CASE WHEN ISNULL(@PlanLotNo, '') = '' THEN dbo.Stk_F_UomConvert(@PlanQuantity, @UomId, UomId) ELSE 0 END,
LastModificationTime = GETUTCDATE(), LastModifierId = @LastModifierId
WHERE Id = @Line;
ELSE
BEGIN
SET @Line = NEWID();
INSERT INTO Stk_T_TransferLine (Id, TenantId, TransferId, ProductId, Description, DemandQuantity, Quantity, UomId, MaterialRequestItemId,
CreationTime, CreatorId, IsDeleted)
VALUES (@Line, @TenantId, @Doc, @ProductId, @Reason, @PlanQuantity, CASE WHEN ISNULL(@PlanLotNo, '') = '' THEN @PlanQuantity ELSE 0 END, @UomId, @Id,
GETUTCDATE(), @LastModifierId, 0);
END
IF ISNULL(@PlanLotNo, '') <> ''
BEGIN
UPDATE ll
SET Quantity = ll.Quantity + dbo.Stk_F_UomConvert(@PlanQuantity, @UomId, tl.UomId), LastModificationTime = GETUTCDATE(),
LastModifierId = @LastModifierId
FROM Stk_T_TransferLineLot ll
INNER JOIN Stk_T_TransferLine tl ON tl.Id = ll.TransferLineId
WHERE ll.TransferLineId = @Line AND ll.LotNo = @PlanLotNo AND ll.IsDeleted = 0;
IF @@ROWCOUNT = 0
INSERT INTO Stk_T_TransferLineLot (Id, TenantId, TransferLineId, LotNo, Quantity, CreationTime, CreatorId, IsDeleted)
SELECT NEWID(), @TenantId, tl.Id, @PlanLotNo, dbo.Stk_F_UomConvert(@PlanQuantity, @UomId, tl.UomId), GETUTCDATE(), @LastModifierId, 0
FROM Stk_T_TransferLine tl
WHERE tl.Id = @Line;
END
-- Numara ve yeniden hesap (kalemin kapanması dahil) belge kaydı sonrasıyla aynıdır.
EXEC Stk_P_TransferAfterSave @Doc, @LastModifierId;
END
ELSE
THROW 50192, N'Karar Satınalma, İç Transfer ya da Stoktan olmalıdır.', 1;
COMMIT TRANSACTION;
END