sozsoft-platform/configs/seeds/postgres/object/Inv_P_TransferValidate.sql

136 lines
8.7 KiB
MySQL
Raw Normal View History

2026-10-12 21:43:05 +00:00
-- Tamamla: yapılan miktarlar stoğa işlenir (Inv_T_Stock, ürün biriminde, lot kırılımlı). İç konumdan çıkışta stok yetmezse
-- işlem durur; dış konumlar stok tutmaz. 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).
-- Talepten az yapılan satırların kalanı aynı türde yeni belgeye (backorder) geçer.
CREATE OR REPLACE PROCEDURE public."Inv_P_TransferValidate"(p_id uuid, p_user_id uuid DEFAULT NULL)
LANGUAGE plpgsql AS $$
DECLARE v_tenant uuid; v_status varchar(16); v_kind varchar(32); v_return_of uuid; v_src uuid; v_dst uuid;
v_src_internal boolean := false; v_dst_internal boolean := false; v_dst_branch uuid; v_dst_warehouse uuid;
v_sign int; v_new uuid; v_now timestamp := NOW() AT TIME ZONE 'UTC'; v_msg varchar(512);
BEGIN
SELECT "TenantId", "Status", "OperationKind", "ReturnOfId", "SourceLocationId", "DestinationLocationId"
INTO v_tenant, v_status, v_kind, v_return_of, v_src, v_dst
FROM "Inv_T_Transfer" WHERE "Id" = p_id
FOR UPDATE;
IF v_status <> 'Ready' THEN
RAISE EXCEPTION 'Yalnız hazır belge tamamlanabilir.' USING ERRCODE = 'P0001', DETAIL = '50306';
END IF;
v_sign := CASE WHEN v_return_of IS NULL THEN 1 ELSE -1 END;
SELECT "LocationType" = 'Internal' INTO v_src_internal FROM "Inv_T_Location" WHERE "Id" = v_src;
SELECT "LocationType" = 'Internal', "BranchId", "WarehouseId" INTO v_dst_internal, v_dst_branch, v_dst_warehouse
FROM "Inv_T_Location" WHERE "Id" = v_dst;
v_src_internal := COALESCE(v_src_internal, false);
v_dst_internal := COALESCE(v_dst_internal, false);
IF NOT EXISTS (SELECT 1 FROM "Inv_T_TransferLine" WHERE "TransferId" = p_id AND "IsDeleted" = false AND "Quantity" > 0) THEN
RAISE EXCEPTION 'Yapılan miktarı girilmiş satır yok.' USING ERRCODE = 'P0001', DETAIL = '50309';
END IF;
SELECT p."Name" || ': lot/seri toplamı ' || rtrim(rtrim(z.q::text, '0'), '.') || ', yapılan miktar ' || rtrim(rtrim(l."Quantity"::text, '0'), '.') INTO v_msg
FROM "Inv_T_TransferLine" l
INNER JOIN "Inv_T_Product" p ON p."Id" = l."ProductId"
CROSS JOIN LATERAL (SELECT COALESCE(SUM(lt."Quantity"), 0) AS q FROM "Inv_T_TransferLineLot" lt WHERE lt."TransferLineId" = l."Id" AND lt."IsDeleted" = false) z
WHERE l."TransferId" = p_id AND l."IsDeleted" = false AND l."Quantity" > 0 AND p."TrackInventory" = true AND p."TrackingMethod" IN ('Lot', 'Serial')
AND z.q <> l."Quantity"
LIMIT 1;
IF v_msg IS NOT NULL THEN
RAISE EXCEPTION 'Lot/seri miktarı yapılan miktara eşit değil — %', v_msg USING ERRCODE = 'P0001', DETAIL = '50310';
END IF;
SELECT p."Name" || ' / ' || z."LotNo" INTO v_msg
FROM "Inv_T_TransferLineLot" z
INNER JOIN "Inv_T_TransferLine" l ON l."Id" = z."TransferLineId"
INNER JOIN "Inv_T_Product" p ON p."Id" = l."ProductId"
WHERE l."TransferId" = p_id AND l."IsDeleted" = false AND z."IsDeleted" = false AND p."TrackingMethod" = 'Serial'
AND (z."Quantity" <> 1 OR EXISTS (SELECT 1 FROM "Inv_T_TransferLineLot" z2
INNER JOIN "Inv_T_TransferLine" l2 ON l2."Id" = z2."TransferLineId"
WHERE l2."TransferId" = p_id AND l2."IsDeleted" = false AND z2."IsDeleted" = false
AND l2."ProductId" = l."ProductId" AND z2."LotNo" = z."LotNo" AND z2."Id" <> z."Id"))
LIMIT 1;
IF v_msg IS NOT NULL THEN
RAISE EXCEPTION 'Seri numaralı üründe her seri 1 adet ve tekil olmalıdır: %', v_msg USING ERRCODE = 'P0001', DETAIL = '50311';
END IF;
-- Stoğa işlenecek hareket: ürün × lot, ürün biriminde.
DROP TABLE IF EXISTS tmp_inv_move;
CREATE TEMP TABLE tmp_inv_move AS
SELECT m."ProductId", m."LotNo", SUM(m."Quantity") AS "Quantity", m."UomId"
FROM (SELECT l."ProductId", p."UomId",
CASE WHEN p."TrackingMethod" IN ('Lot', 'Serial') THEN z."LotNo" ELSE '' END AS "LotNo",
public."Inv_F_UomConvert"(CASE WHEN p."TrackingMethod" IN ('Lot', 'Serial') THEN z."Quantity" ELSE l."Quantity" END, l."UomId", p."UomId") AS "Quantity"
FROM "Inv_T_TransferLine" l
INNER JOIN "Inv_T_Product" p ON p."Id" = l."ProductId"
LEFT JOIN "Inv_T_TransferLineLot" z ON z."TransferLineId" = l."Id" AND z."IsDeleted" = false AND p."TrackingMethod" IN ('Lot', 'Serial')
WHERE l."TransferId" = p_id AND l."IsDeleted" = false AND l."Quantity" > 0 AND p."TrackInventory" = true) m
GROUP BY m."ProductId", m."LotNo", m."UomId";
IF v_src_internal THEN
PERFORM 1 FROM "Inv_T_Stock" s
WHERE s."LocationId" = v_src AND s."TenantId" IS NOT DISTINCT FROM v_tenant
AND (s."ProductId", s."LotNo") IN (SELECT "ProductId", "LotNo" FROM tmp_inv_move)
FOR UPDATE;
SELECT p."Name" || CASE WHEN m."LotNo" = '' THEN '' ELSE ' / ' || m."LotNo" END INTO v_msg
FROM tmp_inv_move m
INNER JOIN "Inv_T_Product" p ON p."Id" = m."ProductId"
LEFT JOIN "Inv_T_Stock" s ON s."LocationId" = v_src AND s."ProductId" = m."ProductId" AND s."LotNo" = m."LotNo"
AND s."TenantId" IS NOT DISTINCT FROM v_tenant
WHERE COALESCE(s."Quantity", 0) < m."Quantity"
LIMIT 1;
IF v_msg IS NOT NULL THEN
RAISE EXCEPTION 'Kaynak konumda yeterli stok yok: %', v_msg USING ERRCODE = 'P0001', DETAIL = '50312';
END IF;
UPDATE "Inv_T_Stock" s SET "Quantity" = s."Quantity" - m."Quantity", "LastMoveDate" = v_now, "LastModificationTime" = v_now, "LastModifierId" = p_user_id
FROM tmp_inv_move m
WHERE m."ProductId" = s."ProductId" AND m."LotNo" = s."LotNo" AND s."LocationId" = v_src AND s."TenantId" IS NOT DISTINCT FROM v_tenant;
END IF;
IF v_dst_internal THEN
UPDATE "Inv_T_Stock" s SET "Quantity" = s."Quantity" + m."Quantity", "LastMoveDate" = v_now, "LastModificationTime" = v_now, "LastModifierId" = p_user_id,
"InDate" = CASE WHEN s."Quantity" <= 0 THEN v_now ELSE s."InDate" END
FROM tmp_inv_move m
WHERE m."ProductId" = s."ProductId" AND m."LotNo" = s."LotNo" AND s."LocationId" = v_dst AND s."TenantId" IS NOT DISTINCT FROM v_tenant;
INSERT INTO "Inv_T_Stock" ("Id", "TenantId", "BranchId", "WarehouseId", "LocationId", "ProductId", "LotNo", "Quantity", "UomId", "InDate", "LastMoveDate", "CreationTime", "CreatorId", "IsDeleted")
SELECT gen_random_uuid(), v_tenant, v_dst_branch, v_dst_warehouse, v_dst, m."ProductId", m."LotNo", m."Quantity", m."UomId", v_now, v_now, v_now, p_user_id, false
FROM tmp_inv_move m
WHERE NOT EXISTS (SELECT 1 FROM "Inv_T_Stock" s
WHERE s."LocationId" = v_dst AND s."ProductId" = m."ProductId" AND s."LotNo" = m."LotNo"
AND s."TenantId" IS NOT DISTINCT FROM v_tenant);
END IF;
DROP TABLE tmp_inv_move;
UPDATE "Inv_T_Transfer"
SET "Status" = 'Done', "EffectiveDate" = v_now,
"ReceivedByUserId" = CASE WHEN v_kind = 'InternalTransfer' THEN p_user_id ELSE "ReceivedByUserId" END,
"ReceivedDate" = CASE WHEN v_kind = 'InternalTransfer' THEN v_now ELSE "ReceivedDate" END
WHERE "Id" = p_id;
UPDATE "Prc_T_PurchaseOrderLine" ol SET "ReceivedQuantity" = ol."ReceivedQuantity" + v_sign * x."Quantity"
FROM (SELECT l."PurchaseOrderLineId", SUM(public."Inv_F_UomConvert"(l."Quantity", l."UomId", pl."UomId")) AS "Quantity"
FROM "Inv_T_TransferLine" l
INNER JOIN "Prc_T_PurchaseOrderLine" pl ON pl."Id" = l."PurchaseOrderLineId"
WHERE l."TransferId" = p_id AND l."IsDeleted" = false AND l."Quantity" > 0
GROUP BY l."PurchaseOrderLineId") x
WHERE x."PurchaseOrderLineId" = ol."Id";
UPDATE "Prc_T_MaterialRequestItem" i SET "DeliveredQuantity" = i."DeliveredQuantity" + v_sign * x."Quantity",
"LineStatus" = CASE WHEN i."DeliveredQuantity" + v_sign * x."Quantity" >= i."Quantity" THEN 'Done'
WHEN i."LineStatus" = 'Done' THEN 'Waiting' ELSE i."LineStatus" END
FROM (SELECT l."MaterialRequestItemId", SUM(public."Inv_F_UomConvert"(l."Quantity", l."UomId", mi."UomId")) AS "Quantity"
FROM "Inv_T_TransferLine" l
INNER JOIN "Prc_T_MaterialRequestItem" mi ON mi."Id" = l."MaterialRequestItemId"
WHERE l."TransferId" = p_id AND l."IsDeleted" = false AND l."Quantity" > 0
GROUP BY l."MaterialRequestItemId") x
WHERE x."MaterialRequestItemId" = i."Id";
IF v_return_of IS NULL AND EXISTS (SELECT 1 FROM "Inv_T_TransferLine" WHERE "TransferId" = p_id AND "IsDeleted" = false AND "Quantity" < "DemandQuantity") THEN
CALL public."Inv_P_TransferCopy"(p_id, 'Backorder', p_user_id, v_new);
END IF;
CALL public."Inv_P_TransferRecalc"(p_id);
END;
$$;