-- Planla diyaloğunun İç Transfer (App.Prc.MaterialRequestPlanSource) ve Satınalma (App.Prc.MaterialRequestPlanVendor) ızgaralarının satır kaydı: -- girilen Plan Miktarı kalemin taslak planına (Prc_T_MaterialRequestPlanLine) yazılır, 0 ya da boş satırı plandan çıkarır. p_id ızgara -- satırının anahtarıdır: kalem + ':' + hedef (Transfer'de kaynak konum + ':' + lot — takipsiz üründe lot boş —, Purchase'da tedarikçi). -- Kaynak talebin teslim konumuysa karar Stock'tur (Stoktan: kaynağı ve hedefi aynı iç transfer açılır). Belge açılmaz; onay -- Prc_P_MaterialRequestPlanConfirm'dedir. Taslak toplamı planlanacak kalanı, satır kullanılabilir stoğu (Prc_V_MaterialRequestPlanSource -- .AvailableQuantity: lotun ve konumun serbest stoğu) aşamaz. Batch kaydı satırları eşzamanlı gönderdiği için kalem kilitlenir. Eksi miktar -- "alabileceği en fazla"dır (Seçilenleri Planla, Öner): kalanın diğer taslak satırlardan arta kalanı, kullanılabilir stokla sınırlı; -- alınacak bir şey yoksa satır değişmez. CREATE OR REPLACE PROCEDURE public."Prc_P_MaterialRequestPlanLineSave"( p_id varchar, p_plan_method varchar, p_plan_quantity numeric(18, 4), p_tenant_id uuid, p_last_modifier_id uuid ) LANGUAGE plpgsql AS $$ DECLARE v_item uuid := left(p_id, 36)::uuid; v_target uuid := substring(p_id from 38 for 36)::uuid; v_qty numeric(18, 4) := COALESCE(p_plan_quantity, 0); v_lot varchar(64) := CASE WHEN p_plan_method = 'Purchase' THEN '' ELSE COALESCE(substring(p_id from 75 for 64), '') END; v_method varchar(16) := p_plan_method; v_location uuid; v_uom varchar(64); v_remaining numeric(18, 4); v_other numeric(18, 4); v_free numeric(18, 4); v_line uuid; BEGIN SELECT i."UomId", r."LocationId" INTO v_uom, v_location FROM "Prc_T_MaterialRequestItem" i INNER JOIN "Prc_T_MaterialRequest" r ON r."Id" = i."MaterialRequestId" WHERE i."Id" = v_item 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_uom IS NULL THEN RAISE EXCEPTION 'Kalem planlanamaz: talep onaylı değil ya da kalem kapalı.' USING ERRCODE = 'P0001', DETAIL = '50191'; END IF; IF v_method = 'Transfer' AND v_target = v_location THEN v_method := 'Stock'; END IF; SELECT "Id" INTO v_line FROM "Prc_T_MaterialRequestPlanLine" WHERE "MaterialRequestItemId" = v_item AND "PlanMethod" = v_method AND "IsDeleted" = false AND v_target = CASE WHEN v_method = 'Purchase' THEN "SupplierId" ELSE "SourceLocationId" END AND "LotNo" = v_lot; IF v_qty = 0 THEN DELETE FROM "Prc_T_MaterialRequestPlanLine" WHERE "Id" = v_line; RETURN; END IF; SELECT "RemainingQuantity" INTO v_remaining FROM public."Prc_V_MaterialRequestItemPlan" WHERE "Id" = v_item; SELECT COALESCE(SUM("Quantity"), 0) INTO v_other FROM "Prc_T_MaterialRequestPlanLine" WHERE "MaterialRequestItemId" = v_item AND "IsDeleted" = false AND "Id" IS DISTINCT FROM v_line; IF v_qty < 0 THEN v_qty := v_remaining - v_other; IF v_method IN ('Transfer', 'Stock') THEN SELECT "AvailableQuantity" INTO v_free FROM public."Prc_V_MaterialRequestPlanSource" WHERE "BaseId" = v_item AND "LocationId" = v_target AND COALESCE("LotNo", '') = v_lot; IF v_free < v_qty THEN v_qty := v_free; END IF; END IF; IF COALESCE(v_qty, 0) <= 0 THEN RETURN; END IF; END IF; IF v_other + v_qty > v_remaining THEN RAISE EXCEPTION 'Taslak plan toplamı planlanacak kalanı aşamaz (kalan: % %).', trim_scale(v_remaining - v_other), v_uom USING ERRCODE = 'P0001', DETAIL = '50200'; END IF; IF v_method IN ('Transfer', 'Stock') THEN SELECT "AvailableQuantity" INTO v_free FROM public."Prc_V_MaterialRequestPlanSource" WHERE "BaseId" = v_item AND "LocationId" = v_target AND COALESCE("LotNo", '') = v_lot; IF v_free IS NULL THEN RAISE EXCEPTION 'Kaynak konum (lot/seri takipli üründe lot) ürünün stoğu olan bir iç konum olmalıdır.' USING ERRCODE = 'P0001', DETAIL = '50197'; END IF; IF v_qty > v_free THEN RAISE EXCEPTION 'Kaynak konumda (lotta) yeterli serbest stok yok (kullanılabilir: % %).', trim_scale(GREATEST(v_free, 0)), v_uom USING ERRCODE = 'P0001', DETAIL = '50198'; END IF; ELSIF v_method = 'Purchase' THEN IF NOT EXISTS (SELECT 1 FROM public."Prc_V_MaterialRequestPlanVendor" WHERE "BaseId" = v_item AND "ContactId" = v_target) THEN RAISE EXCEPTION 'Satınalma kararında aktif bir tedarikçi seçilmelidir.' USING ERRCODE = 'P0001', DETAIL = '50194'; END IF; ELSE RAISE EXCEPTION 'Karar Satınalma ya da İç Transfer olmalıdır.' USING ERRCODE = 'P0001', DETAIL = '50192'; END IF; IF v_line IS NOT NULL THEN UPDATE "Prc_T_MaterialRequestPlanLine" SET "Quantity" = v_qty, "LastModificationTime" = NOW() AT TIME ZONE 'UTC', "LastModifierId" = p_last_modifier_id WHERE "Id" = v_line; ELSE INSERT INTO "Prc_T_MaterialRequestPlanLine" ("Id", "TenantId", "MaterialRequestItemId", "PlanMethod", "SupplierId", "SourceLocationId", "LotNo", "Quantity", "CreationTime", "CreatorId", "IsDeleted") VALUES (gen_random_uuid(), p_tenant_id, v_item, v_method, CASE WHEN v_method = 'Purchase' THEN v_target END, CASE WHEN v_method <> 'Purchase' THEN v_target END, v_lot, v_qty, NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false); END IF; END; $$;