141 lines
9.1 KiB
PL/PgSQL
141 lines
9.1 KiB
PL/PgSQL
-- Tamamla: yapılan miktarlar stoğa işlenir (Stk_T_Stock, ürün biriminde, lot kırılımlı). İç konumdan çıkışta stok yetmezse
|
||
-- işlem durur; dış konumlar stok tutmaz. Kaynak ve hedefi aynı konum olan belge stoğa dokunmaz (teslim kaydıdır). 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);
|
||
-- siparişli alım ürün–tedarikçi fiyatını yazar (Stk_P_TransferSupplierPrice).
|
||
-- Talepten az yapılan satırların kalanı aynı türde yeni belgeye (backorder) geçer.
|
||
CREATE OR REPLACE PROCEDURE public."Stk_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 "Stk_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 "Stk_T_Location" WHERE "Id" = v_src;
|
||
SELECT "LocationType" = 'Internal', "BranchId", "WarehouseId" INTO v_dst_internal, v_dst_branch, v_dst_warehouse
|
||
FROM "Stk_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 "Stk_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 "Stk_T_TransferLine" l
|
||
INNER JOIN "Stk_T_Product" p ON p."Id" = l."ProductId"
|
||
CROSS JOIN LATERAL (SELECT COALESCE(SUM(lt."Quantity"), 0) AS q FROM "Stk_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 "Stk_T_TransferLineLot" z
|
||
INNER JOIN "Stk_T_TransferLine" l ON l."Id" = z."TransferLineId"
|
||
INNER JOIN "Stk_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 "Stk_T_TransferLineLot" z2
|
||
INNER JOIN "Stk_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."Stk_F_UomConvert"(CASE WHEN p."TrackingMethod" IN ('Lot', 'Serial') THEN z."Quantity" ELSE l."Quantity" END, l."UomId", p."UomId") AS "Quantity"
|
||
FROM "Stk_T_TransferLine" l
|
||
INNER JOIN "Stk_T_Product" p ON p."Id" = l."ProductId"
|
||
LEFT JOIN "Stk_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 "Stk_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 "Stk_T_Product" p ON p."Id" = m."ProductId"
|
||
LEFT JOIN "Stk_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;
|
||
|
||
-- Kaynak ve hedef aynıysa stok yerinde kalır: belge teslimi kaydeder (yeterlilik yine denetlenir).
|
||
IF v_src <> v_dst THEN
|
||
UPDATE "Stk_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;
|
||
END IF;
|
||
|
||
IF v_dst_internal AND v_src <> v_dst THEN
|
||
UPDATE "Stk_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 "Stk_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 "Stk_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 "Stk_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."Stk_F_UomConvert"(l."Quantity", l."UomId", pl."UomId")) AS "Quantity"
|
||
FROM "Stk_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";
|
||
|
||
CALL public."Stk_P_TransferSupplierPrice"(p_id, p_user_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."Stk_F_UomConvert"(l."Quantity", l."UomId", mi."UomId")) AS "Quantity"
|
||
FROM "Stk_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 "Stk_T_TransferLine" WHERE "TransferId" = p_id AND "IsDeleted" = false AND "Quantity" < "DemandQuantity") THEN
|
||
CALL public."Stk_P_TransferCopy"(p_id, 'Backorder', p_user_id, v_new);
|
||
END IF;
|
||
|
||
CALL public."Stk_P_TransferRecalc"(p_id);
|
||
END;
|
||
$$;
|