-- 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 serbest stoğu (Prc_V_MaterialRequestPlanSource) yetmelidir; aynı kaynak → talebin konumu için onaya -- girmemiş taslak iç transfer varsa satır ona, yoksa kaynak deponun iç transfer operasyon türüyle yeni taslak açılır. 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; belge açılmaz, serbest stok yetmelidir. Miktar kalemin stoktan karşılanan ve teslim edilen -- miktarına eklenir; satınalma payı olmayan ve kalanı biten kalem kapanı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_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 ORDER BY "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 = 'Transfer' THEN 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; IF v_src_warehouse IS NULL OR p_plan_source_location_id = v_location THEN RAISE EXCEPTION 'Kaynak konum, talebin teslim konumundan farklı ve ürünün 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_doc FROM "Inv_T_Transfer" WHERE "IsDeleted" = false AND "OperationKind" = 'InternalTransfer' AND "Status" = 'Draft' AND "ReturnOfId" IS NULL AND "BackorderOfId" IS NULL AND "SourceLocationId" = p_plan_source_location_id AND "DestinationLocationId" = v_location AND COALESCE("ApprovalStatus", 'Onay Gerekmez') = 'Onay Gerekmez' 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" = 'InternalTransfer' AND "WarehouseId" = v_src_warehouse ORDER BY "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; 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; 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"), "LastModificationTime" = NOW() AT TIME ZONE 'UTC', "LastModifierId" = p_last_modifier_id WHERE "Id" = v_line; ELSE INSERT INTO "Inv_T_TransferLine" ("Id", "TenantId", "TransferId", "ProductId", "Description", "DemandQuantity", "Quantity", "UomId", "MaterialRequestItemId", "CreationTime", "CreatorId", "IsDeleted") VALUES (gen_random_uuid(), p_tenant_id, v_doc, v_product, v_reason, p_plan_quantity, 0, v_uom, p_id, NOW() AT TIME ZONE 'UTC', p_last_modifier_id, false); END IF; -- Numara, kaynak depo onaycısı ve yeniden hesap (kalemin kapanması dahil) belge kaydı sonrasıyla aynıdır. CALL public."Inv_P_TransferAfterSave"(v_doc, p_last_modifier_id); ELSIF p_plan_method = 'Stock' THEN SELECT "FreeQuantity" INTO v_free FROM public."Prc_V_MaterialRequestPlanSource" WHERE "BaseId" = p_id AND "LocationId" = v_location; IF p_plan_quantity > COALESCE(v_free, 0) THEN RAISE EXCEPTION 'Teslim konumunda yeterli serbest stok yok (serbest: % %).', trim_scale(GREATEST(COALESCE(v_free, 0), 0)), v_uom USING ERRCODE = 'P0001', DETAIL = '50198'; END IF; UPDATE "Prc_T_MaterialRequestItem" SET "FromStockQuantity" = "FromStockQuantity" + p_plan_quantity, "DeliveredQuantity" = "DeliveredQuantity" + p_plan_quantity, "LastModificationTime" = NOW() AT TIME ZONE 'UTC', "LastModifierId" = p_last_modifier_id WHERE "Id" = p_id; UPDATE "Prc_T_MaterialRequestItem" i SET "LineStatus" = 'Done' FROM public."Prc_V_MaterialRequestItemPlan" p WHERE p."Id" = i."Id" AND i."Id" = p_id AND p."PurchaseQuantity" = 0 AND p."RemainingQuantity" <= 0; ELSE RAISE EXCEPTION 'Karar Satınalma, İç Transfer ya da Stoktan olmalıdır.' USING ERRCODE = 'P0001', DETAIL = '50192'; END IF; END; $$;