sozsoft-platform/configs/seeds/postgres/object/Prc_P_MaterialRequestPlan.sql
2026-10-14 22:26:03 +03:00

193 lines
12 KiB
PL/PgSQL
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.

-- Planlama kararı: talep kaleminin planlanacak kalanından p_plan_quantity 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 p_plan_lot_no 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 (Inv_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 REPLACE PROCEDURE public."Prc_P_MaterialRequestPlan"(
p_id uuid,
p_plan_method varchar,
p_plan_quantity numeric(18, 4),
p_plan_supplier_id uuid,
p_plan_source_location_id uuid,
p_plan_lot_no varchar,
p_tenant_id uuid,
p_last_modifier_id uuid
)
LANGUAGE plpgsql AS $$
DECLARE v_product uuid; v_uom varchar(64); v_due timestamp; v_reason varchar(256); v_branch uuid; v_warehouse uuid; v_location uuid;
v_request_no varchar(32); v_remaining numeric(18, 4); v_doc uuid; v_line uuid; v_op_type uuid; v_src_warehouse uuid;
v_free numeric(18, 4); v_no varchar(128);
BEGIN
-- Kalem kilitlenir: aynı kalemin eşzamanlı iki planı kalanı iki kez dağıtamaz.
SELECT i."ProductId", i."UomId", i."DueDate", i."RequestReason", r."BranchId", r."WarehouseId", r."LocationId", r."RequestNo"
INTO v_product, v_uom, v_due, v_reason, v_branch, v_warehouse, v_location, v_request_no
FROM "Prc_T_MaterialRequestItem" i
INNER JOIN "Prc_T_MaterialRequest" r ON r."Id" = i."MaterialRequestId"
WHERE i."Id" = p_id AND i."IsDeleted" = false AND i."LineStatus" = 'Waiting' AND r."IsDeleted" = false
AND i."TenantId" IS NOT DISTINCT FROM p_tenant_id
AND r."ApprovalStatus" IN ('Onaylandı', 'Teklif Talebi', 'Teklif Talebi Gönderildi', 'Satınalma Siparişi')
FOR UPDATE OF i;
IF v_product IS NULL THEN
RAISE EXCEPTION 'Kalem planlanamaz: talep onaylı değil ya da kalem kapalı.' USING ERRCODE = 'P0001', DETAIL = '50191';
END IF;
SELECT "RemainingQuantity" INTO v_remaining FROM public."Prc_V_MaterialRequestItemPlan" WHERE "Id" = p_id;
IF COALESCE(p_plan_quantity, 0) <= 0 THEN
RAISE EXCEPTION 'Plan miktarı sıfırdan büyük olmalıdır.' USING ERRCODE = 'P0001', DETAIL = '50192';
END IF;
IF p_plan_quantity > v_remaining THEN
RAISE EXCEPTION 'Plan miktarı planlanacak kalanı aşamaz (kalan: % %).', trim_scale(v_remaining), v_uom USING ERRCODE = 'P0001', DETAIL = '50193';
END IF;
IF p_plan_method = 'Purchase' THEN
IF p_plan_supplier_id IS NULL THEN
RAISE EXCEPTION 'Satınalma kararında tedarikçi seçilmelidir.' USING ERRCODE = 'P0001', DETAIL = '50194';
END IF;
SELECT "Id" INTO v_doc
FROM "Prc_T_PurchaseRfq"
WHERE "IsDeleted" = false AND "Status" = 'Draft' AND "SupplierId" = p_plan_supplier_id AND "BranchId" = v_branch AND "WarehouseId" = v_warehouse
AND "TenantId" IS NOT DISTINCT FROM p_tenant_id
ORDER BY "CreationTime" DESC
LIMIT 1;
IF v_doc IS NULL THEN
SELECT "Id" INTO v_op_type
FROM "Inv_T_OperationType"
WHERE "IsDeleted" = false AND "IsActive" = true AND "OperationKind" = 'Receipt' AND "WarehouseId" = v_warehouse
AND "TenantId" IS NOT DISTINCT FROM p_tenant_id
ORDER BY CASE WHEN "SequenceName" LIKE '%.' || "OperationKind" THEN 0 ELSE 1 END, "Name"
LIMIT 1;
IF v_op_type IS NULL THEN
RAISE EXCEPTION 'Talebin deposu için aktif bir alım operasyon türü tanımlı değil.' USING ERRCODE = 'P0001', DETAIL = '50195';
END IF;
v_doc := gen_random_uuid();
CALL public."Adm_P_SequenceNext"('Prc.PurchaseRfq', p_tenant_id, v_no);
INSERT INTO "Prc_T_PurchaseRfq" ("Id", "TenantId", "RfqNo", "TenderGroupId", "SupplierId", "BranchId", "OperationTypeId", "WarehouseId", "CurrencyId",
"BuyerUserId", "IncotermId", "IncotermLocation", "PaymentTermId", "CreationTime", "CreatorId", "IsDeleted")
SELECT v_doc, p_tenant_id, left(v_no, 32), v_doc, c."Id", v_branch, v_op_type, v_warehouse, COALESCE(c."SupplierCurrency", 'TRY'),
p_last_modifier_id, c."PurchaseIncotermId", c."PurchaseIncotermLocation", c."PurchasePaymentTermId",
NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false
FROM "Adm_T_Contact" c
WHERE c."Id" = p_plan_supplier_id AND c."IsDeleted" = false;
IF NOT FOUND THEN
RAISE EXCEPTION 'Satınalma kararında tedarikçi seçilmelidir.' USING ERRCODE = 'P0001', DETAIL = '50194';
END IF;
END IF;
SELECT "Id" INTO v_line FROM "Prc_T_PurchaseRfqLine" WHERE "PurchaseRfqId" = v_doc AND "MaterialRequestItemId" = p_id AND "IsDeleted" = false LIMIT 1;
IF v_line IS NOT NULL THEN
UPDATE "Prc_T_PurchaseRfqLine"
SET "Quantity" = "Quantity" + public."Inv_F_UomConvert"(p_plan_quantity, v_uom, "UomId"),
"LastModificationTime" = NOW() AT TIME ZONE 'UTC', "LastModifierId" = p_last_modifier_id
WHERE "Id" = v_line;
ELSE
INSERT INTO "Prc_T_PurchaseRfqLine" ("Id", "TenantId", "PurchaseRfqId", "ProductId", "Description", "Quantity", "UomId", "UnitPrice", "TaxRate", "Amount",
"DeliveryDate", "MaterialRequestItemId", "CreationTime", "CreatorId", "IsDeleted")
SELECT gen_random_uuid(), p_tenant_id, v_doc, v_product, v_reason, p_plan_quantity, v_uom,
COALESCE((SELECT ps."Price" FROM "Inv_T_ProductSupplier" ps
WHERE ps."ProductId" = v_product AND ps."ContactId" = p_plan_supplier_id AND ps."IsDeleted" = false
ORDER BY ps."MinQuantity" LIMIT 1), 0),
COALESCE(p."PurchaseTaxRate", 0), 0, v_due, p_id, NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false
FROM "Inv_T_Product" p
WHERE p."Id" = v_product;
END IF;
CALL public."Prc_P_PurchaseRfqRecalc"(v_doc);
ELSIF p_plan_method IN ('Transfer', 'Stock') THEN
IF p_plan_method = 'Stock' THEN
p_plan_source_location_id := v_location;
END IF;
IF p_plan_source_location_id IS NULL THEN
RAISE EXCEPTION 'İç transfer kararında kaynak konum seçilmelidir.' USING ERRCODE = 'P0001', DETAIL = '50196';
END IF;
-- Konum ve serbest stok kuralı diyaloğun İç Transfer ızgarasıyla aynıdır.
SELECT "WarehouseId", "FreeQuantity" INTO v_src_warehouse, v_free
FROM public."Prc_V_MaterialRequestPlanSource"
WHERE "BaseId" = p_id AND "LocationId" = p_plan_source_location_id AND COALESCE("LotNo", '') = COALESCE(p_plan_lot_no, '');
IF v_src_warehouse IS NULL OR (p_plan_method = 'Transfer' AND p_plan_source_location_id = v_location) THEN
RAISE EXCEPTION '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.' USING ERRCODE = 'P0001', DETAIL = '50197';
END IF;
IF p_plan_quantity > v_free THEN
RAISE EXCEPTION 'Kaynak konumda yeterli serbest stok yok (serbest: % %).', trim_scale(GREATEST(v_free, 0)), v_uom USING ERRCODE = 'P0001', DETAIL = '50198';
END IF;
SELECT "Id" INTO v_op_type
FROM "Inv_T_OperationType"
WHERE "IsDeleted" = false AND "IsActive" = true AND "OperationKind" = 'InternalTransfer' AND "WarehouseId" = v_src_warehouse
AND "TenantId" IS NOT DISTINCT FROM p_tenant_id
ORDER BY CASE WHEN "SequenceName" LIKE '%.' || "OperationKind" THEN 0 ELSE 1 END, "Name"
LIMIT 1;
IF v_op_type IS NULL THEN
RAISE EXCEPTION 'Kaynak depo için aktif bir iç transfer operasyon türü tanımlı değil.' USING ERRCODE = 'P0001', DETAIL = '50199';
END IF;
SELECT "Id" INTO v_doc
FROM "Inv_T_Transfer"
WHERE "IsDeleted" = false AND "OperationTypeId" = v_op_type AND "Status" = 'Draft' AND "ReturnOfId" IS NULL AND "BackorderOfId" IS NULL
AND "SourceLocationId" = p_plan_source_location_id AND "DestinationLocationId" = v_location
AND "TenantId" IS NOT DISTINCT FROM p_tenant_id
ORDER BY "CreationTime" DESC
LIMIT 1;
IF v_doc IS NULL THEN
v_doc := gen_random_uuid();
INSERT INTO "Inv_T_Transfer" ("Id", "TenantId", "BranchId", "WarehouseId", "OperationTypeId", "OperationKind", "SourceLocationId", "DestinationLocationId",
"SourceDocument", "ResponsibleUserId", "Status", "CreationTime", "CreatorId", "IsDeleted")
SELECT v_doc, p_tenant_id, ot."BranchId", ot."WarehouseId", ot."Id", 'InternalTransfer', p_plan_source_location_id, v_location,
v_request_no, p_last_modifier_id, 'Draft', NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false
FROM "Inv_T_OperationType" ot
WHERE ot."Id" = v_op_type;
ELSE
UPDATE "Inv_T_Transfer"
SET "SourceDocument" = left(COALESCE("SourceDocument", '') || CASE WHEN COALESCE("SourceDocument", '') = '' THEN '' ELSE ', ' END || v_request_no, 128)
WHERE "Id" = v_doc AND strpos(COALESCE("SourceDocument", ''), v_request_no) = 0;
END IF;
-- Planlanan miktar yapılacak miktardır: lotsuz satırda doğrudan yazılır, lotlu satırda lot dağılımından (Inv_P_TransferRecalc) gelir.
SELECT "Id" INTO v_line FROM "Inv_T_TransferLine" WHERE "TransferId" = v_doc AND "MaterialRequestItemId" = p_id AND "IsDeleted" = false LIMIT 1;
IF v_line IS NOT NULL THEN
UPDATE "Inv_T_TransferLine"
SET "DemandQuantity" = "DemandQuantity" + public."Inv_F_UomConvert"(p_plan_quantity, v_uom, "UomId"),
"Quantity" = "Quantity" + CASE WHEN COALESCE(p_plan_lot_no, '') = '' THEN public."Inv_F_UomConvert"(p_plan_quantity, v_uom, "UomId") ELSE 0 END,
"LastModificationTime" = NOW() AT TIME ZONE 'UTC', "LastModifierId" = p_last_modifier_id
WHERE "Id" = v_line;
ELSE
v_line := gen_random_uuid();
INSERT INTO "Inv_T_TransferLine" ("Id", "TenantId", "TransferId", "ProductId", "Description", "DemandQuantity", "Quantity", "UomId", "MaterialRequestItemId",
"CreationTime", "CreatorId", "IsDeleted")
VALUES (v_line, p_tenant_id, v_doc, v_product, v_reason, p_plan_quantity, CASE WHEN COALESCE(p_plan_lot_no, '') = '' THEN p_plan_quantity ELSE 0 END, v_uom, p_id,
NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false);
END IF;
IF COALESCE(p_plan_lot_no, '') <> '' THEN
UPDATE "Inv_T_TransferLineLot" ll
SET "Quantity" = ll."Quantity" + public."Inv_F_UomConvert"(p_plan_quantity, v_uom, tl."UomId"),
"LastModificationTime" = NOW() AT TIME ZONE 'UTC', "LastModifierId" = p_last_modifier_id
FROM "Inv_T_TransferLine" tl
WHERE tl."Id" = ll."TransferLineId" AND ll."TransferLineId" = v_line AND ll."LotNo" = p_plan_lot_no AND ll."IsDeleted" = false;
IF NOT FOUND THEN
INSERT INTO "Inv_T_TransferLineLot" ("Id", "TenantId", "TransferLineId", "LotNo", "Quantity", "CreationTime", "CreatorId", "IsDeleted")
SELECT gen_random_uuid(), p_tenant_id, tl."Id", p_plan_lot_no, public."Inv_F_UomConvert"(p_plan_quantity, v_uom, tl."UomId"),
NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false
FROM "Inv_T_TransferLine" tl
WHERE tl."Id" = v_line;
END IF;
END IF;
-- Numara ve yeniden hesap (kalemin kapanması dahil) belge kaydı sonrasıyla aynıdır.
CALL public."Inv_P_TransferAfterSave"(v_doc, p_last_modifier_id);
ELSE
RAISE EXCEPTION 'Karar Satınalma, İç Transfer ya da Stoktan olmalıdır.' USING ERRCODE = 'P0001', DETAIL = '50192';
END IF;
END;
$$;