CREATE OR ALTER PROCEDURE [HM].[UpdateDocumentReservationsFromXML] (@docHandle INT, 
															@tblDocumentPositions [HM].[DocumentReservationsPositionsType] READONLY,
															@DP [HM].[DocumentPositionsType] READONLY,
															@DeletedDocumentPositionsRZ [HM].[DocumentPositionsType] READONLY,
															@docId INT, 
															@docDate DATETIME,	
															@docKhId INT,		
															@correction BIT, 
															@anyOrderRelatedDocuments BIT,
															@tworzacy int
															)
AS
BEGIN
	DECLARE @dataName varchar(255) = '',
	@positionName varchar(255) = '',
	@docType INT,		
	@bazaDokRZ INT,		
	@bazaPozRZ INT

	SELECT TOP 1 @dataName = localname 
	FROM OPENXML(@docHandle, '/')

	IF (@dataName = 'SaleDocument')
	BEGIN
		SELECT @docType = 0,
		@bazaDokRZ = 16,
		@bazaPozRZ = 18,
		@positionName = 'SalePosition'
	END
	ELSE IF (@dataName = 'ForeignOrderDocument')
	BEGIN
		SELECT @docType = 1,
		@bazaDokRZ = 45,
		@bazaPozRZ = 30,
		@positionName = 'ForeignOrderPosition'
	END
	ELSE IF (@dataName = 'InventoryDocument')
	BEGIN
		SELECT @docType = 2,
		@bazaDokRZ = 33,
		@bazaPozRZ = 37,
		@positionName = 'InventoryPosition'
	END
	ELSE
	BEGIN
		DECLARE @msg varchar(2048) = CONCAT('Nieobslugiwany charakter dokumentu: ', @dataName);
		THROW 51000, @msg, 1;  
	END

	--Tabela tymczasowa odczytywania rezerwacji dokumentu
	DECLARE @tblPositionsReservations AS TABLE
	(
		[Id] INT,
		[PositionId] INT,
		[NodeId] INT,
		[AvailableQuantity] DECIMAL(24,4),
		[ReservedQuantity] DECIMAL(24,4),
		[ReservedQuantityAuxiliary] DECIMAL(24,4),
		[RealizedReservedQuantity] DECIMAL(24,4),
		[InventoryId] INT
	)

	-- Deserializacja danych rezerwacji z xml
	DECLARE @PositionsReservationsXPath varchar(500) = CONCAT('/', @dataName, '/DocumentPositions/', @positionName,'/Reservations/Reservation')

	INSERT INTO @tblPositionsReservations
	SELECT 
		0,
		[PositionId],
		[NodeId],
		[AvailableQuantity],
		[ReservedQuantity],
		[ReservedQuantityAuxiliary],
		[RealizedReservedQuantity],
		[InventoryId]
	FROM 
		OPENXML(@docHandle, @PositionsReservationsXPath)
		WITH
		(
		--[Id] INT 'Id',	--nie możemy polegać na id z xml-a ponieważ może się on zmienić w trakcie edycji rezerwacji (z nie zerowego stać się zerowy)
		[PositionId] INT 'PositionId',
		[NodeId] INT './../../NodeId',	--NodeId z pozycji jest zawsze aktualny
		[AvailableQuantity] DECIMAL(24,4) 'AvailableQuantity',
		[ReservedQuantity] DECIMAL(24,4) 'ReservedQuantity',
		[ReservedQuantityAuxiliary] DECIMAL(24,4) 'ReservedQuantityAuxiliary',
		[RealizedReservedQuantity] DECIMAL(24,4) 'RealizedReservedQuantity',
		[InventoryId] INT 'InventoryId',
		[ModificationStatus] VARCHAR(30) './../../@ModificationStatus'
		)
		WHERE [ModificationStatus] <> 'Deleted' OR [ModificationStatus] IS NULL  -- pomijamy pozycje oznaczone jako 'Deleted', warunek konieczny ponieważ NodeId dla pozycji usuniętych, powtarza się z nie usuniętymi
			AND	[NodeId] IN (SELECT NodeId FROM @tblDocumentPositions)	--wybieramy tylko te dla których aktualizowaliśmy pozycje

	--Zabezpieczenie przed przypadkową rezerwacją przy zapisie dokumentu rezerwowanego wydaniem
	UPDATE @tblPositionsReservations SET ReservedQuantity = IIF(ReservedQuantity - RealizedReservedQuantity < 0,0,ReservedQuantity - RealizedReservedQuantity)
	FROM @tblPositionsReservations
	WHERE RealizedReservedQuantity > 0

	--Aktualizacja Id pozycji (DP), z xmla przyjdą zera dla nowych pozycji
	UPDATE tblRZ SET PositionId = tblDP.Id
	FROM @tblDocumentPositions tblDP
		JOIN @tblPositionsReservations tblRZ ON tblDP.NodeId = tblRZ.NodeId
	WHERE tblRZ.PositionId = 0;

	--odtworzenie id-ów rezerwacji, które już istnieją (z xml-a przyszły same zera)
	UPDATE tblRZ SET tblRZ.Id = RZ.id
	FROM @tblPositionsReservations tblRZ
		JOIN @tblDocumentPositions tblDP ON tblDP.Id = tblRZ.PositionId
		JOIN HM.RZ ON RZ.idpozrz = tblRZ.PositionId AND RZ.magazyn = tblRZ.InventoryId AND RZ.bazapozrz = @bazaPozRZ AND RZ.idtw = tblDP.ProductId 
	WHERE tblDP.ReservationType = IIF(rz.subtyp & 0x01 = 0,2,1) --odtwarzamy jeśli nie został zmieniony typ rezerwacji (ilościowy/ze wskazaniem), w przeciwnym razie traktujemy jako nową

	--usuwamy rezerwacje z pozycji które mają zmieniony typ rezerwacji na 'brak' lub zostały wyzerowane
	DELETE tblRZ
	FROM @tblDocumentPositions tblDP 
		JOIN @tblPositionsReservations tblRZ ON tblRZ.PositionId = tblDP.Id
	WHERE tblDP.ReservationType = 0 OR 
		(tblRZ.ReservedQuantity = 0 AND ISNULL(tblRZ.RealizedReservedQuantity,0) = 0)
			and tblRZ.id not in (SELECT id2 FROM HM.ZZ WHERE typ=96 AND baza1 = 152) -- rezerwacje które realizują, pozostają pomimo zera 


	--Tabela tymczasowa do odczytania rezerwacji ze wskazaniem dostawy
	DECLARE @tblPositionsReservationsDelivery AS TABLE
	(
		[Id] INT,
		[PositionId] INT,
		[NodeId] INT,
		[AvailableQuantity] DECIMAL(24,4),
		[ReservedQuantity] DECIMAL(24,4),
		[ReservedQuantityAuxiliary] DECIMAL(24,4),
		[InventoryId] INT,
		[DeliveryId] INT,
		[Price] DECIMAL(35,15)
	)

	-- Deserializacja danych rezerwacji ze wskazaniem dostawy z xml
	DECLARE @PositionsReservationsDeliveryXPath varchar(500) = CONCAT('/', @dataName, '/DocumentPositions/', @positionName,'/ReservationsDelivery/ReservationDelivery')

	INSERT INTO @tblPositionsReservationsDelivery
	SELECT 
		xmlData.[Id],
		xmlData.[PositionId],
		xmlData.[NodeId],
		xmlData.[AvailableQuantity],
		xmlData.[ReservedQuantity],
		xmlData.[ReservedQuantityAuxiliary],
		xmlData.[InventoryId],
		xmlData.[DeliveryId],
		xmlData.[Price]
	FROM 
		OPENXML(@docHandle, @PositionsReservationsDeliveryXPath)
		WITH
		(
			[Id] INT 'Id',
			[PositionId] INT 'PositionId',
			[NodeId] INT './../../NodeId', 	--NodeId z pozycji jest zawsze aktualny
			[AvailableQuantity] DECIMAL(24,4) 'AvailableQuantity',
			[ReservedQuantity] DECIMAL(24,4) 'ReservedQuantity',
			[ReservedQuantityAuxiliary] DECIMAL(24,4) 'ReservedQuantityAuxiliary',
			[InventoryId] INT 'Delivery/InventoryId',
			[DeliveryId] INT 'Delivery/Id',
			[Price] DECIMAL(35,15) 'Delivery/Price',
			[ModificationStatus] VARCHAR(30) './../../@ModificationStatus'
		) xmlData
		JOIN @tblDocumentPositions tblPos ON tblPos.NodeId = xmlData.[NodeId]	--wybieramy tylko te dla których aktualizowaliśmy pozycje
		WHERE [ModificationStatus] <> 'Deleted' OR [ModificationStatus] IS NULL  -- pomijamy pozycje oznaczone jako 'Deleted', warunek konieczny ponieważ NodeId dla pozycji usuniętych, powtarza się z nie usuniętymi
			AND tblPos.ReservationType = 2	--pomijamy rozliczenia jeśli rezerwacja nie jest ze wskazaniem dostaw, potrafią przyjść takie z XML-a, przy zmianie typu rezewacji na ilościową

	--aktualizacja id pozycji (DP)
	UPDATE tblRZD SET PositionId = tblDP.Id
	FROM @tblDocumentPositions tblDP
	JOIN @tblPositionsReservationsDelivery tblRZD ON tblDP.NodeId = tblRZD.NodeId
	WHERE tblRZD.PositionId = 0;

	--odtworzenie id-ów PW, które już istnieją (z xml-a mogą przyjść nie prawdziwe)
	UPDATE tblRZD SET Id = pw.id
	FROM @tblPositionsReservationsDelivery tblRZD 
		JOIN @tblPositionsReservations tblRZ ON tblRZ.PositionId = tblRZD.PositionId AND tblRZ.InventoryId = tblRZD.InventoryId
		JOIN HM.PW pw ON pw.idmg = tblRZ.Id AND pw.iddw = tblRZD.DeliveryId AND pw.typ = 26

	--Tabela tymczasowa do odczytania realizowanych rezerwacji
	DECLARE @tblDeliverySettlements AS TABLE
	(
		[ReservationId] INT,				
		[DeliverySettlementId] INT,				
		[Quantity] DECIMAL(24,4),
		[RealizationQuantity] DECIMAL(24,4),
		[MaxQuantity] DECIMAL(24,4),
		[DeliveryMaxQuantity] DECIMAL(24,4),
		[MaxRealizationQuantity] DECIMAL(24,4),
		[NodeId] INT,
		[ParentId] INT,
		[DeliveryId] INT,
		[InventoryId] INT
	)

	-- Deserializacja danych realizowanych rezerwacji z xml
	DECLARE @DeliverySettlementsXPath varchar(500) = CONCAT('/', @dataName, '/DocumentPositions/', @positionName,'/Reservations/Reservation/DeliverySettlements/DeliverySettlement')

	INSERT INTO @tblDeliverySettlements
	SELECT 
		[ReservationId],				
		[DeliverySettlementId],				
		[Quantity],
		[RealizationQuantity],
		[MaxQuantity],
		[DeliveryMaxQuantity],
		[MaxRealizationQuantity],
		[NodeId],
		0,
		[DeliveryId],
		[InventoryId]
	FROM 
		OPENXML(@docHandle, @DeliverySettlementsXPath)
		WITH
		(
			[ReservationId] INT 'ReservationId',				
			[DeliverySettlementId] INT 'DeliverySettlementId',				
			[Quantity] DECIMAL(24,4) 'Quantity',
			[RealizationQuantity] DECIMAL(24,4) 'RealizationQuantity',
			[MaxQuantity] DECIMAL(24,4) 'MaxQuantity',
			[DeliveryMaxQuantity] DECIMAL(24,4) 'DeliveryMaxQuantity',
			[MaxRealizationQuantity] DECIMAL(24,4) 'MaxRealizationQuantity',
			[ModificationStatus] VARCHAR(30) './../../../../@ModificationStatus',
			[NodeId] INT './../../../../NodeId',
			[DeliveryId] INT 'DeliveryId',
			[InventoryId] INT './../../InventoryId'
		)
		WHERE [ModificationStatus] <> 'Deleted' OR [ModificationStatus] IS NULL  -- pomijamy pozycje oznaczone jako 'Deleted', warunek konieczny ponieważ NodeId dla pozycji usuniętych, powtarza się z nie usuniętymi
			AND [NodeId] IN (SELECT NodeId FROM @tblDocumentPositions)	--wybieramy tylko te dla których aktualizowaliśmy pozycje

	--uzupełnienie id rezerwacji na potrzeby dalszych obliczeń
	UPDATE @tblDeliverySettlements SET ReservationId = pw.idmg 
	FROM @tblDeliverySettlements tds
	JOIN HM.PW pw ON tds.DeliverySettlementId = pw.id
	WHERE IsNull(tds.ReservationId, 0) = 0

	--tabela z uzupełnieniem informacji o realizacjach ze wskazaniem dostaw (w celu obsłużenia powrotu wartości)
	DECLARE @tblDeliverySettlements2 AS TABLE
	(
		[SettlementLeft] INT,				
		[SettlementRight] INT,				
		[NewValueLeft] DECIMAL(24,2),
		[NewValueRight] DECIMAL(24,2),
		[OldQuantityLeft] DECIMAL(24,4)
	)

	INSERT INTO @tblDeliverySettlements2
	SELECT 
		pwL.id AS [SettlementLeft],				
		pwR.id AS [SettlementRight],				
		newValueLeft.v AS NewValueLeft,
		(pwL.wartosc + pwR.wartosc) - overValue.v - newValueLeft.v AS NewValueRight,
		pwL.ilosc AS OldQuantityLeft
	FROM @tblDeliverySettlements tds 
	JOIN HM.ZZ zz ON tds.DeliverySettlementId = zz.id1 and zz.typ = 96 and zz.baza1 = 36
	JOIN HM.PW pwL ON pwL.id = tds.DeliverySettlementId 
	JOIN HM.PW pwR ON pwR.id = zz.id2
	JOIN @tblPositionsReservations tpr ON pwR.idmg = tpr.Id AND pwR.typ = 26	--pomijamy PW z innych dokumentów które również aktualnie realizują tą samą rezerwację.
-- obliczenia
	CROSS APPLY( SELECT		--nadwyżka ilości (ponad realizację)
			IIF(pwL.ilosc + pwR.ilosc - tds.MaxRealizationQuantity > 0, pwL.ilosc + pwR.ilosc - tds.MaxRealizationQuantity, 0) AS q) overQuantity
	CROSS APPLY( SELECT		--nadwyżka wartości (ponad realizację)
			IIF(pwL.ilosc + pwR.ilosc <> 0, HM.ROUND2((pwL.wartosc + pwR.wartosc) / (pwL.ilosc + pwR.ilosc) * overQuantity.q), 0) AS v) overValue
	CROSS APPLY( SELECT
			IIF(pwL.ilosc + pwR.ilosc <> 0, HM.ROUND2((pwL.wartosc + pwR.wartosc) / (pwL.ilosc + pwR.ilosc) * tds.Quantity), 0) AS v) newValueLeft

	IF @correction = 0
	BEGIN
		--Aktualizacja typu rezerwacji na pozycji				
		IF (@docType = 0)
		BEGIN
			UPDATE [HM].[DP] SET
				typ = dp.typ | IIF(tblDP.[ReservationType] = 0,0,0x08) | IIF(tblDP.[ReservationType] = 1,IIF(tw.metoda = 0,0,0x04) | 0x02, 0)
				| IIF(tblDP.[ReservationType] = 2,0x20,0) --0x20 dotyczy jawnej zmiany przez użytkownika, zostawione tymczasowo dla wstecznej kompatybilności
			FROM [HM].[DP] dp
			JOIN [HM].[TW] tw ON dp.idtw = tw.id
			JOIN @tblDocumentPositions tblDP ON DP.[id] = tblDP.[Id]
			WHERE (dp.flag & 0x0200 <> 0) and dp.super = @docId
			--AND tblDP.MofificationStatus IN (@created, @updated)
		END 
		ELSE IF (@docType = 1)
		BEGIN
			UPDATE [HM].[ZP] SET
				typ = zp.typ | IIF(tblDP.[ReservationType] = 0,0,0x08) | IIF(tblDP.[ReservationType] = 1,IIF(tw.metoda = 0,0,0x04) | 0x02, 0)
				| IIF(tblDP.[ReservationType] = 2,0x20,0) --0x20 dotyczy jawnej zmiany przez użytkownika, zostawione tymczasowo dla wstecznej kompatybilności
			FROM [HM].[ZP] zp
			JOIN [HM].[TW] tw ON zp.idtw = tw.id
			JOIN @tblDocumentPositions tblDP ON ZP.[id] = tblDP.[Id]
			WHERE (zp.flag & 0x0200 <> 0) and zp.super = @docId
			--AND tblDP.MofificationStatus IN (@created, @updated)
		END
		ELSE IF (@docType = 2)
		BEGIN
			UPDATE HM.MZ SET
				typ = mz.typ | IIF(tblDP.ReservationType = 0,0,0x08) | IIF(tblDP.ReservationType = 1, IIF(tw.metoda = 0,0,0x04) | 0x02, 0)
				| IIF(tblDP.[ReservationType] = 2,0x20,0) --0x20 dotyczy jawnej zmiany przez użytkownika, zostawione tymczasowo dla wstecznej kompatybilności
			FROM HM.MZ mz
			JOIN HM.TW tw ON mz.idtw = tw.id
			JOIN @tblDocumentPositions tblDP ON MZ.id = tblDP.Id
			WHERE (mz.flag & 0x0200 <> 0) and mz.super = @docId
			--AND tblDP.MofificationStatus IN (@created, @updated)
		END
	END
    
	--aktualizacja kontrahenta na wszystkich rezerwacjach z dokumentu
	IF EXISTS(SELECT TOP 1 1 FROM HM.RZ rz WHERE rz.iddokrz = @docId AND rz.bazadokrz = @bazaDokRZ AND ISNULL(@docKhId, 0) != ISNULL(rz.idkh, 0))
	BEGIN --jeśli zmienił się kontrahent w jednej to zmień na wszystkich 
		UPDATE HM.RZ SET RZ.idkh = @docKhId WHERE RZ.iddokrz = @docId AND RZ.bazadokrz = @bazaDokRZ
	END

	--aktualizacja daty rezerwacji na wszystkich rezerwacjach z dokumentu
	IF EXISTS(SELECT TOP 1 1 FROM HM.RZ rz WHERE rz.iddokrz = @docId AND rz.bazadokrz = @bazaDokRZ AND @docDate != rz.data)
	BEGIN --jeśli zmieniła się data w jednej rezerwacji to zmień na wszystkich 
		UPDATE HM.RZ SET RZ.[data] = @docDate, RZ.termin = DATEADD(DAY, 7, @docDate) WHERE RZ.iddokrz = @docId AND RZ.bazadokrz = @bazaDokRZ

		UPDATE HM.PW SET [data] = @docDate 
			FROM HM.RZ rz
				JOIN HM.PW pw ON rz.id = pw.idmg AND pw.typ = 26 
			WHERE rz.iddokrz = @docId AND rz.bazadokrz = @bazaDokRZ
	END

	--indentyfikatory nowo dodanych rezerwacji
	DECLARE @newRzIds TABLE (Id INT, PositionId INT, InventoryId INT)

	-- Dodanie rekordów rezerwacji (RZ), dla pozycji i magazynów dla których ich nie ma
	INSERT INTO [HM].[RZ] (flag, subtyp, typ, idtw, idkh, magazyn, data, termin, iloscrz, iloscrl, wartosc, iddokrz, bazadokrz, idpozrz, bazapozrz, tworzacy) 
	OUTPUT inserted.id, inserted.idpozrz, inserted.magazyn INTO @newRzIds
	SELECT DISTINCT 0,IIF(tblDP.[ReservationType] = 2,0,1) | IIF(TW.metoda = 1, 0x02, 0),2,tblDP.ProductId,@docKhId,tblRZ.InventoryId, @docDate, DATEADD(DAY, 7, @docDate),0,0,0,@docId,@bazaDokRZ,tblDP.id,@bazaPozRZ,@tworzacy
	FROM @tblDocumentPositions tblDP
		JOIN @tblPositionsReservations tblRZ ON tblRZ.PositionId = tblDP.id
		JOIN [HM].[SM] SM ON SM.idtw = tblDP.ProductId AND SM.magazyn = tblRZ.InventoryId
		JOIN HM.TW ON TW.id = tblDP.ProductId 
		LEFT JOIN [HM].[OP] OP ON OP.owner_id = tblDP.id AND OP.owner_base = @bazaPozRZ
	WHERE HM.ROUND4(SM.stanHandl) >= 0 
		--AND (tblDP.id NOT IN (SELECT RR.idpozrz FROM [HM].[RZ] RR WHERE RR.iddokrz = @docId and RR.magazyn = tblRZ.InventoryId) 
		--`		OR tblDP.ProductId NOT IN (SELECT RR.idtw FROM [HM].[RZ] RR WHERE RR.iddokrz = @docId))
		AND tblRZ.Id = 0 AND tblRZ.ReservedQuantity > 0
		AND tblDP.[ReservationType] in (1,2) 		 
		--??? ilość dp rozliczenia większa od 0 AND (tblDP.iloscDP - ISNULL(OP.ilosc_rozl,0)) > 0
	--AND tblDP.MofificationStatus IN (@created, @updated)

	-- Aktualizacja Id nowo dodanych RZ w @tblPositionsReservations
	UPDATE tblRZ SET Id = newRzIds.Id
	FROM @tblPositionsReservations tblRZ
		JOIN @newRzIds newRzIds ON newRzIds.PositionId = tblRZ.PositionId AND newRzIds.InventoryId = tblRZ.InventoryId

	-- Aktualizacja ID rezerwacji na rozliczeniach rezerwacji w celu merga powiazań na ZZ
	UPDATE tds SET tds.ParentId = tpr.Id
	FROM @tblDeliverySettlements tds
	JOIN @tblPositionsReservations tpr on tds.NodeId = tpr.NodeId
				AND tds.InventoryId = tpr.InventoryId -- może być kilka rezerwacji pod jedną pozycją

	DECLARE @mergedZzIds TABLE (id1 INT, id2 INT)

	MERGE INTO HM.ZZ AS ZZ 
	USING (SELECT ReservationId,
				  ParentId,
				  SUM(RealizationQuantity) RealizationQuantity 
			FROM @tblDeliverySettlements
			GROUP BY ReservationId,
				     ParentId) AS TDS
	ON ZZ.TYP = 96 and zz.baza1 = 152 and zz.id1 = tds.ReservationId and zz.baza2 = 152 and zz.id2 = tds.ParentId
	WHEN NOT MATCHED BY TARGET THEN
		INSERT (flag, subtyp, typ, baza1, id1, baza2, id2, ilosc, kod1, kod2, cena, waluta, opis, baza3, ilosc2, magazyn)
		VALUES (0, 0, 96, 152, tds.ReservationId, 152, tds.ParentId, tds.RealizationQuantity, '', '', 0, '', '', 0, 0, 0)
	OUTPUT Inserted.id1, Inserted.id2 INTO @mergedZzIds;
			
--Rezerwacje przeznaczone do usunięcia
	DECLARE @rzToDel TABLE (Id INT, ProductId INT, InventoryId INT, ReservationType INT)

	--z usuniętych pozycji
	INSERT INTO @rzToDel
	SELECT delRZ.id, delRZ.IdTw, rz.magazyn, IIF(rz.subtyp & 0x01 = 0,2,1)
	FROM @DeletedDocumentPositionsRZ delRZ
		JOIN HM.RZ rz ON rz.id = delRz.Id

	--ze zmodyfikowanych pozycji np. zmiana towaru, magazynu
	INSERT INTO @rzToDel
	SELECT RZ.id, RZ.idtw, RZ.magazyn, IIF(rz.subtyp & 0x01 = 0,2,1)
	FROM @tblDocumentPositions tblDP 
		JOIN HM.RZ ON RZ.idpozrz = tblDP.Id AND RZ.bazapozrz = @bazaPozRZ 
	WHERE RZ.id NOT IN (SELECT Id FROM @tblPositionsReservations) 
	--AND tblDP.MofificationStatus IN (@created, @updated)

--pw przeznaczone do usunięcia
	DECLARE @pwToDel TABLE (Id INT)

--z usuwanych rezerwacji
	INSERT INTO @pwToDel
	SELECT pw.id FROM HM.PW WHERE typ = 26 AND idmg IN (SELECT DISTINCT Id FROM @rzToDel)

--z ilością 0
	INSERT INTO @pwToDel
	SELECT pw.id FROM HM.PW
	WHERE id IN (SELECT tblRZD.Id 
		 			FROM @tblPositionsReservationsDelivery tblRZD
					WHERE tblRZD.ReservedQuantity <= 0
						AND tblRZD.id NOT IN (SELECT id2 FROM HM.ZZ WHERE typ = 96 AND baza1 = 36) -- rekordów PW realizujących, nie usuwamy
				)

--pw których nie ma w xmlu w rozliczeniach dostaw
	INSERT INTO @pwToDel
	SELECT pw.id
	FROM @tblPositionsReservations tblRz
		JOIN HM.PW pw ON pw.idmg = tblRz.Id AND pw.typ = 26
		JOIN HM.DW dw ON dw.id = pw.iddw
	WHERE pw.id NOT IN (SELECT Id FROM @tblPositionsReservationsDelivery)
		AND dw.numer != -dw.magazyn	--pomijamy rekordy PW od rezerwacji ilościowej


	--stany które należy zaktualizować
	DECLARE @smToUpdate TABLE (ProductId INT, InventoryId INT, ReservationType INT)

	--z rezerwacji usuniętych
	INSERT INTO @smToUpdate 
	SELECT DISTINCT ProductId, InventoryId, ReservationType 
	FROM @rzToDel

	--z rezerwacji ze zmodyfikowanych pozycji
	INSERT INTO @smToUpdate 
	SELECT DISTINCT tblDP.ProductId, tblRz.InventoryId, tblDP.ReservationType 
	FROM @tblPositionsReservations tblRz
		JOIN @tblDocumentPositions tblDP ON tblDP.Id = tblRz.PositionId
	--WHERE tblDP.MofificationStatus IN (@created, @updated)


	-- dostawy wartościowe których stany trzeba będzie zauktualizować
	DECLARE @dwToUpdate TABLE (Id INT)

	--pochodzące z usuniętych rozliczeń (PW) rezerwacji
	INSERT INTO @dwToUpdate
	SELECT DISTINCT pw.iddw
	FROM @pwToDel pwToDel
		JOIN HM.PW pw ON pw.id = pwToDel.Id
		JOIN HM.DW dw ON dw.id = pw.iddw
	WHERE dw.numer != -dw.magazyn --pomijamy dostawy ilościowe

	-- ze zmodyfikowanych rezerwacji
	INSERT INTO @dwToUpdate
	SELECT DISTINCT tblRZD.DeliveryId
	FROM @tblPositionsReservationsDelivery tblRZD

	--Wyzerowanie rezerwacji do usunięcia
	UPDATE [HM].[RZ] SET 
		iloscrz = 0, 
		iloscrl = 0 
	WHERE id in (SELECT Id FROM @rzToDel)
		and (rz.iloscrz != 0 or rz.iloscrl != 0)
				

	--Dodanie brakujących dostaw rezerwacji ilościowej
	INSERT INTO [HM].[DW] (flag,subtyp,typ,kod,numer,idtw,data,ilosc,iloscdosp,cena,wartoscdosp,magazyn,iloscPz,stan,wartoscst,bufor)
	SELECT 0,0,0,'Rezerwacja ilościowa', -qReservations.InventoryId, qReservations.ProductId,'9999-01-01 00:00:00.000',0,0,0,0, qReservations.InventoryId,0,0,0,0
	FROM (
		SELECT tblDP.ProductId AS ProductId, tblRZ.InventoryId AS InventoryId
		FROM @tblDocumentPositions tblDP  
			JOIN @tblPositionsReservations tblRZ ON tblRZ.PositionId = tblDP.Id
		WHERE tblDP.[ReservationType] = 1
		GROUP BY tblDP.ProductId, tblRZ.InventoryId) AS qReservations  
	LEFT JOIN HM.DW ON DW.idtw = qReservations.ProductId and DW.magazyn = qReservations.InventoryId and DW.numer = -qReservations.InventoryId
	WHERE DW.id IS NULL --nie zjoinowały się a więc nie istnieją

	
	IF exists (select top 1 * from hm.zz zz join @rzToDel rzToDel on zz.id2 = rzToDel.Id and typ = 96 and baza1 = 152)
	BEGIN /* Obsługa rezerwacji powiązanych z zamówieniem przed usunięciem rezerwacji */

		UPDATE rzLeft SET rzLeft.iloscrz = rzLeft.iloscrz + zz.ilosc, rzLeft.wartosc = rzLeft.wartosc + rzRight.wartosc
		FROM HM.RZ rzLeft
		JOIN HM.ZZ zz ON rzLeft.id = zz.id1 and zz.typ = 96 and zz.baza1 = 152
		JOIN @rzToDel ddprz ON ddprz.Id = zz.id2
		JOIN HM.RZ rzRight ON rzRight.id = ddprz.Id
		WHERE rzLeft.iloscrz != rzLeft.iloscrz + zz.ilosc

		UPDATE pwLeft SET pwLeft.ilosc = pwLeft.ilosc + zz.ilosc, pwLeft.wartosc = pwLeft.wartosc + pwRight.wartosc
		FROM HM.PW pwRight
		JOIN @pwToDel pwToDel ON pwToDel.Id = pwRight.id
		JOIN HM.ZZ zz ON pwRight.id = zz.id2 and zz.typ = 96 and zz.baza1 = 36
		JOIN HM.PW pwLeft ON pwLeft.id = zz.id1

		--usunięcie powiązań ZZ z usuwanych rezerwacji
		DELETE HM.ZZ
		FROM HM.ZZ zz 
		JOIN @rzToDel tds ON tds.Id = zz.id2 and zz.typ = 96 and zz.baza1 = 152

		--usunięcie powiązań ZZ z usuwanych rekordów PW
		DELETE HM.ZZ
		FROM HM.ZZ zz 
		JOIN @pwToDel pwToDel ON zz.id2 = pwToDel.id and zz.typ = 96 and zz.baza1 = 36
	END

	--Usunięcie RZ i PW przewidzianych wcześniej do usunięca
	DELETE FROM HM.RZ WHERE id IN (SELECT DISTINCT id FROM @rzToDel)
	DELETE FROM HM.PW WHERE id IN (SELECT DISTINCT id FROM @pwToDel)

	--dodanie PW dla nowych rezerwacji ilościowych
	INSERT INTO [HM].[PW] (flag,subtyp,typ,idmg,iddw,idtw,ilosc,wartosc,ilosczreal,data)
	SELECT DISTINCT 1, 0, 26, tblRZ.id, dw.id, tblDP.ProductId, tblRZ.ReservedQuantity, 0, 0, @docDate 
		FROM @newRzIds newRz
			JOIN @tblPositionsReservations tblRZ ON tblRZ.Id = newRz.Id
			JOIN @tblDocumentPositions tblDP ON tblDP.Id = tblRZ.PositionId
			JOIN HM.DW dw ON dw.idtw = tblDP.ProductId AND dw.magazyn = tblRZ.InventoryId AND dw.numer = -dw.magazyn
		WHERE tblRZ.ReservedQuantity > 0 AND tblDP.ReservationType = 1

	--aktualizacja PW dla rezerwacji ilościowych
	UPDATE [HM].[PW] SET 
		ilosc = IIF(tblRZ.ReservedQuantity < pw.ilosc + sm.stanHandl + ISNULL(tds2.OldQuantityLeft, 0), 
				tblRZ.ReservedQuantity,
				pw.ilosc + sm.stanHandl + ISNULL(tds2.OldQuantityLeft, 0)), --rezerwacja tylko do dostępnego stanu w magazynie plus to co ew. jest w realizacji rezerwacji
		flag = 1
	FROM @tblPositionsReservations tblRZ
	JOIN [HM].[PW] PW ON PW.idmg = tblRZ.id AND PW.typ = 26
	JOIN @tblDocumentPositions tblDP ON tblDP.Id = tblRZ.PositionId
	JOIN HM.SM sm ON sm.idtw = tblDP.ProductId AND sm.magazyn = tblRZ.InventoryId
	LEFT JOIN @tblDeliverySettlements2 tds2 ON tds2.SettlementRight = pw.id 
	WHERE tblDP.[ReservationType] = 1


	DECLARE @newPwIds TABLE (Id INT, ReservationId INT, DeliveryId INT)
	--Dodanie PW dla rezerwacji ze wskazaniem dostaw
	INSERT INTO [HM].[PW] (flag, subtyp, typ, idmg, iddw, idtw, ilosc, wartosc, ilosczreal, data)
	OUTPUT inserted.id, inserted.idmg, inserted.iddw INTO @newPwIds
	SELECT DISTINCT IIF((dw.flag & 0x01 != 0), 0x04, 0), 0, 26, tblRZ.Id, tblRZD.DeliveryId, tblDP.ProductId, 0, 0, 0, @docDate 
	FROM @tblPositionsReservationsDelivery tblRZD
		JOIN @tblPositionsReservations tblRZ ON tblRZ.PositionId = tblRZD.PositionId AND tblRZ.InventoryId = tblRZD.InventoryId
		JOIN @tblDocumentPositions tblDP ON tblDP.Id = tblRZD.PositionId
		JOIN HM.DW dw ON dw.id = tblRZD.DeliveryId
		LEFT JOIN @tblDeliverySettlements tds ON tds.DeliveryId = tblRZD.DeliveryId AND tds.NodeId = tblRZD.NodeId --sprawdzenie czy PW realizuje inne PW
	WHERE tblRZD.Id = 0 AND (tblRZD.ReservedQuantity > 0 
									OR tds.DeliverySettlementId IS NOT NULL) --PW które realizuje dodajemy nawet jeśli jest z zerem

	--dodanie powiązań
	DECLARE @mergedPwIds TABLE (id1 INT, id2 INT)

	MERGE INTO HM.ZZ AS ZZ 
	USING (SELECT DISTINCT pw_dp.id id1, pw_mz.id id2, tds.RealizationQuantity ilosc
			FROM @tblDeliverySettlements tds 
			JOIN HM.RZ rz_mz on tds.ParentId = rz_mz.id
			JOIN HM.PW pw_mz ON pw_mz.typ = 26 AND pw_mz.idmg = rz_mz.id
			JOIN HM.DW dw_mz ON pw_mz.iddw = dw_mz.id
			JOIN HM.RZ rz_dp on tds.ReservationId = rz_dp.id
			JOIN HM.PW pw_dp ON pw_dp.typ = 26 AND pw_dp.idmg = rz_dp.id
			JOIN HM.DW dw_dp ON pw_dp.iddw = dw_dp.id
			WHERE dw_mz.id = dw_dp.id AND
				tds.DeliveryId = dw_mz.id) AS TDS
	ON ZZ.TYP = 96 and zz.baza1 = 36 and zz.id1 = tds.id1 and zz.baza2 = 36 and zz.id2 = tds.id2
	WHEN NOT MATCHED BY TARGET THEN
		INSERT (flag, subtyp, typ, baza1, id1, baza2, id2, ilosc, kod1, kod2, cena, waluta, opis, baza3, ilosc2, magazyn)
		VALUES (0, 0, 96, 36, tds.id1, 36, tds.id2, tds.ilosc, '', '', 0, '', '', 0, 0, 0)
	OUTPUT Inserted.id1, Inserted.id2 INTO @mergedPwIds;

	--aktualizacja nowych identyfikatorów w @tblPositionsReservationsDelivery
	UPDATE tblRZD SET id = newPW.Id
	FROM @tblPositionsReservationsDelivery tblRZD
		JOIN @tblPositionsReservations tblRZ ON tblRZ.PositionId = tblRZD.PositionId AND tblRZ.InventoryId = tblRZD.InventoryId
		JOIN @newPwIds newPW ON newPW.ReservationId = tblRZ.Id AND newPW.DeliveryId = tblRZD.DeliveryId
	WHERE tblRZD.Id = 0

	-- dodanie nowych identyfikatorów PW w @tblDeliverySettlements2
	INSERT INTO @tblDeliverySettlements2
	SELECT 
		mPwIDS.id1 AS [SettlementLeft],				
		mPwIDS.id2 AS [SettlementRight],				
		IIF(pwL.ilosc <> 0, HM.ROUND2(pwL.wartosc / pwL.ilosc  * tds.Quantity), 0) AS NewValueLeft,
		(pwL.wartosc) - IIF(pwL.ilosc <> 0, HM.ROUND2((pwL.wartosc) / (pwL.ilosc ) * tds.Quantity), 0)
			AS NewValueRight,
		pwL.ilosc AS OldQuantityLeft
	FROM @mergedPwIds mPwIDS 
	JOIN HM.PW pwL ON pwL.id = mPwIDS.id1
	JOIN @tblDeliverySettlements tds ON tds.DeliverySettlementId = mPwIDS.id1
	
	
	DECLARE @newQuantity DECIMAL(24, 4)

	--Aktualizacja ilości i wartości PW dla rezerwacji ze wskazaniem dostaw
	UPDATE pw SET 
		--rezerwacja tylko do dostępnego stanu w dostawie
		@newQuantity = IIF(tblRZD.ReservedQuantity - pw.ilosc < dw.iloscdosp + ISNULL(tds2.OldQuantityLeft, 0), 
							tblRZD.ReservedQuantity, 
							pw.ilosc + dw.iloscdosp + ISNULL(tds2.OldQuantityLeft, 0)),

		wartosc = CASE
				WHEN @newQuantity = pw.ilosc THEN wartosc	--skoro ilość bez zmian, wartość też bez zmian
				ELSE
					ISNULL(tds2.NewValueRight, 0) + 										-- wartość od ilości zrealizowanej
					HM.ROUND2((pw.wartosc + dw.wartoscdosp) / (pw.ilosc + dw.iloscdosp) 
								* (@newQuantity - ISNULL(tds.RealizationQuantity, 0)))		-- wartość od ilości ponad realizację 
				END,

		ilosc = @newQuantity,
		--flag = 0, 
		iddw = tblRZD.DeliveryId
	FROM HM.PW pw 
		JOIN @tblPositionsReservationsDelivery tblRZD ON tblRZD.Id = pw.id
		JOIN HM.DW dw ON dw.id = tblRZD.DeliveryId
		LEFT JOIN @tblDeliverySettlements2 tds2 ON tds2.SettlementRight = pw.id
		LEFT JOIN @tblDeliverySettlements tds ON tds.DeliveryId = tblRZD.DeliveryId AND tds.NodeId = tblRZD.NodeId


	-- aktualizacja ilości i wartości w rezerwacji na podstawie sumy rozliczeń (PW) - mamy spójność
	UPDATE rz SET
		rz.iloscrz = sumPW.ilosc,
		rz.wartosc = sumPW.wartosc
	FROM HM.RZ rz
		JOIN (SELECT pw.idmg AS ReservationId, SUM(pw.ilosc) AS ilosc, SUM(pw.wartosc) AS wartosc 
				FROM HM.PW pw 
				JOIN @tblPositionsReservations tblRZ ON tblRZ.Id = pw.idmg AND pw.typ = 26
				GROUP BY pw.idmg ) sumPW ON sumPW.ReservationId = rz.id


	IF @correction = 0
	BEGIN
		--Aktualizacja typu pozycji			
		IF (@docType = 0)
		BEGIN
			UPDATE [HM].[DP] SET
				typ = dp.typ | IIF(dp.[typ] & 0x08 = 0,0,IIF(dp.ilosc > ISNULL(R.[iloscrz],0),0x40,0))
			FROM [HM].[DP] dp
			JOIN @tblDocumentPositions tblDP ON tblDP.Id = dp.id
			LEFT JOIN HM.RZ R ON dp.id = R.idpozrz AND R.bazapozrz = @bazaPozRZ
			WHERE (dp.flag & 0x0200 <> 0)					
		END
		ELSE IF (@docType = 1)
		BEGIN
			UPDATE [HM].[ZP] SET
				typ = zp.typ | IIF(zp.[typ] & 0x08 = 0,0,IIF(zp.ilosc > ISNULL(R.[iloscrz],0),0x40,0))
			FROM [HM].[ZP] zp
			JOIN @tblDocumentPositions tblDP ON tblDP.Id = zp.id
			LEFT JOIN HM.RZ R ON zp.id = R.idpozrz AND R.bazapozrz = @bazaPozRZ
			WHERE (zp.flag & 0x0200 <> 0)					
		END
		ELSE IF (@docType = 2)
		BEGIN
			UPDATE [HM].[MZ] SET
				typ = mz.typ | IIF(mz.[typ] & 0x08 = 0,0,IIF(mz.ilosc > ISNULL(R.[iloscrz],0),0x40,0))
			FROM [HM].[MZ] mz
			JOIN @tblDocumentPositions tblDP ON tblDP.Id = mz.id
			LEFT JOIN HM.RZ R ON mz.id = R.idpozrz AND R.bazapozrz = @bazaPozRZ
			WHERE (mz.flag & 0x0200 <> 0)					
		END
	END
												
	IF exists (select top 1 * from @tblDeliverySettlements)
	BEGIN /* Obsługa rezerwacji powiązanych z zamówieniem */	

		--powracająca ilość, aktualizacja ilości i wartości w PW
		UPDATE HM.PW SET 
				pw.ilosc = tds.Quantity, 
				pw.wartosc = tds2.NewValueLeft
		FROM HM.PW pw
		JOIN @tblDeliverySettlements tds ON pw.id = tds.DeliverySettlementId	
		JOIN @tblDeliverySettlements2 tds2 ON tds2.SettlementLeft = tds.DeliverySettlementId

		--powracająca ilość i wartość - aktualizacja rezerwacji na podstawie sum z PW
		UPDATE HM.RZ SET rz.iloscrz = sumPW.ilosc, rz.wartosc = sumPW.wartosc
		FROM ( SELECT DISTINCT tds1.ReservationId FROM @tblDeliverySettlements tds1 ) tds 
		JOIN HM.RZ rz ON rz.id = tds.ReservationId
		JOIN ( SELECT pw.typ, pw.idmg idrz, SUM(pw.ilosc) ilosc, SUM(pw.wartosc) wartosc 
				FROM HM.PW 
				GROUP BY pw.typ, pw.idmg) sumPW ON sumPW.typ = 26 AND sumPW.idrz = rz.id

		--Uzupełnienie ilości zrealizowanych dla dokumentu sprzedaży
		UPDATE @tblDeliverySettlements SET DeliveryMaxQuantity = DeliveryMaxQuantity * -1
		WHERE DeliveryMaxQuantity < 0

		--uzupełnienie ilości zrealizowanej (po stronie Right) w rekordach PW 
		UPDATE pwR SET pwR.ilosczreal = IIF(pwR.ilosc > tds.MaxRealizationQuantity, tds.MaxRealizationQuantity,pwR.ilosc)
		FROM @tblDeliverySettlements tds 
		JOIN @tblDeliverySettlements2 tds2 ON tds2.SettlementLeft = tds.DeliverySettlementId
		JOIN HM.PW pwR ON pwR.id = tds2.SettlementRight

		-- to samo w rezerwacjach (po stronie Right), na podstawie sumy z PW
		UPDATE HM.RZ SET rz.iloscrl = sumPW.ilosczreal
		FROM ( SELECT DISTINCT tds1.ParentId FROM @tblDeliverySettlements tds1) tds 
		JOIN HM.RZ ON rz.id = tds.ParentId
		JOIN ( SELECT pw.typ, pw.idmg idrz, SUM(pw.ilosczreal) ilosczreal 
				FROM HM.PW 
				GROUP BY pw.typ, pw.idmg) sumPW ON sumPW.typ = 26 AND sumPW.idrz = RZ.id

		--uzupełnienie poprawne powiązań pomiędzy realizowanymi rezerwacjami (ZZ)
		UPDATE zz SET zz.ilosc = ISNULL(gDS.RealizationQuantitySum, 0)
		FROM (SELECT ParentId, SUM(RealizationQuantity) AS RealizationQuantitySum FROM @tblDeliverySettlements GROUP BY ParentId) gDS 
		JOIN HM.ZZ zz ON zz.typ = 96 AND zz.baza2 = 152 AND zz.id2 = gDS.ParentId 

		UPDATE zz SET zz.ilosc = ISNULL(tds.RealizationQuantity,0)
		FROM @tblDeliverySettlements tds
		JOIN @tblDeliverySettlements2 tds2 ON tds2.SettlementLeft = tds.DeliverySettlementId
		JOIN HM.ZZ ON zz.typ = 96 AND zz.baza2 = 36 AND zz.id2 = tds2.SettlementRight
				
	END

	--Aktualizacja stanu handlowego w dostawach ilościowych (na podstawie sumy z rezerwacji ilościowych), celowo po akrualizacji rezerwacji powiązanych
	UPDATE DW SET DW.iloscdosp = -ISNULL(sumRZ.iloscrz, 0),
				  DW.typ = IIF(ISNULL(sumRZ.iloscrz, 0) > 0,1,0)
	FROM HM.DW DW
		JOIN (SELECT DISTINCT ProductId, InventoryId FROM @smToUpdate WHERE ReservationType = 1) smToUpdate 
				ON smToUpdate.InventoryId = DW.magazyn AND smToUpdate.ProductId = DW.idtw AND DW.numer = -DW.magazyn
		LEFT JOIN (SELECT SUM(HM.ROUND4(iloscrz)) AS iloscrz, idtw, magazyn 
				FROM HM.RZ 
				WHERE RZ.subtyp & 0x01 = 1 
				GROUP BY RZ.idtw, RZ.magazyn) sumRZ ON sumRZ.idtw = DW.idtw AND sumRZ.magazyn = DW.magazyn

	--tabela ze stanami w dostawach po aktualizacji tych stanów
	DECLARE @tblDeliveryStateAfterUpdate TABLE (DeliveryId INT, ProductId INT, InventoryId INT, DeliveryState DECIMAL(24, 4))

	--Aktualizacja stanu handlowego w dostawach wartościowych (na podstawie sumy z PW)
	UPDATE DW SET dw.iloscdosp = dw.stan - ISNULL(sumPW.ilosc, 0),
				  dw.wartoscdosp = dw.wartoscst - ISNULL(sumPW.wartosc, 0)
	OUTPUT inserted.id, inserted.idtw, inserted.magazyn, inserted.iloscdosp INTO @tblDeliveryStateAfterUpdate
	FROM HM.DW dw
		JOIN @dwToUpdate dwToUpdate ON dwToUpdate.Id = dw.id
		LEFT JOIN (SELECT pw.iddw, SUM(HM.ROUND4(pw.ilosc)) AS ilosc, SUM(HM.ROUND2(pw.wartosc)) AS wartosc 
					FROM HM.PW pw WHERE pw.typ = 26 GROUP BY pw.iddw) AS sumPW ON sumPW.iddw = dw.id

	--próba zarezerwowania ponad stan w dostawie, zgłaszamy wyjątek z komunikatem
	IF EXISTS(SELECT TOP 1 1 FROM @tblDeliveryStateAfterUpdate WHERE DeliveryState < 0)
	BEGIN
        DECLARE @msgDeliveryState VARCHAR(MAX)

		--składanie komunikatu

        --SQL2017 i wyższe (polecenie STRING_AGG)
		-- SELECT @msgDeliveryState =  
		-- 		STRING_AGG('Towar: ''' + tw.kod + '''' + CHAR(13) + 
		-- 					'Magazyn: ''' + mg.kod + '''' + CHAR(13) + 
		-- 					'Dostawa: ''' + dw.kod + '''' + CHAR(13) + 
		-- 					'Ilość powyżej stanu: ' + CONVERT(VARCHAR, -tblDeliveryState.DeliveryState), CHAR(13) + CHAR(13)) 
		-- FROM @tblDeliveryStateAfterUpdate tblDeliveryState
		-- 	JOIN HM.TW tw ON tw.id = tblDeliveryState.ProductId
		-- 	JOIN HM.KH mg ON mg.id = tblDeliveryState.InventoryId
		-- 	JOIN HM.DW dw ON dw.id = tblDeliveryState.DeliveryId
		-- WHERE tblDeliveryState.DeliveryState < 0;
        ---

        --SQL2016
		SET @msgDeliveryState =  
				(SELECT CHAR(13) + CHAR(13) + 'Towar: ''' + tw.kod + '''' + CHAR(13) + 
							'Magazyn: ''' + mg.kod + '''' + CHAR(13) + 
							'Dostawa: ''' + dw.kod + '''' + CHAR(13) + 
							'Ilość powyżej stanu: ' + CONVERT(VARCHAR, -tblDeliveryState.DeliveryState) 
		            FROM @tblDeliveryStateAfterUpdate tblDeliveryState
			            JOIN HM.TW tw ON tw.id = tblDeliveryState.ProductId
			            JOIN HM.KH mg ON mg.id = tblDeliveryState.InventoryId
			            JOIN HM.DW dw ON dw.id = tblDeliveryState.DeliveryId
		            WHERE tblDeliveryState.DeliveryState < 0
                    FOR XML PATH(''))

        SET @msgDeliveryState = REPLACE(@msgDeliveryState, '&#x0D;', CHAR(13))   --przywrócone entery po wygenerowaniu XML-a
        SET @msgDeliveryState = STUFF(@msgDeliveryState, 1, 2, '')              --usunięcie dwóch pierwszych enterów
        ---

		SET @msgDeliveryState = 'Operacja nie powiodła się.' +  CHAR(13) + 'Próba zarezerwowania powyżej stanu w dostawie:' + CHAR(13) + CHAR(13) + @msgDeliveryState;

		THROW 50000, @msgDeliveryState, 1; 
	END


	--tabela ze stanami w magazynach po aktualizacji
	DECLARE @tblInventoryStateAfterUpdate TABLE (StateId INT, ProductId INT, InventoryId INT, InventoryState DECIMAL(24, 4))

	--Aktualizacja stanu handlowego, na podstawie sumy rezerwacji
	UPDATE [HM].[SM] SET 
		stanHandl =  SM.stan - pom.Ilosc
	OUTPUT inserted.id, inserted.idtw, inserted.magazyn, inserted.stanHandl INTO @tblInventoryStateAfterUpdate
	FROM (
		SELECT SM.id, ISNULL(sumRZ.iloscrz, 0) AS ilosc
		FROM HM.SM SM
			JOIN (SELECT DISTINCT ProductId, InventoryId FROM @smToUpdate) smToUpdate 
				ON smToUpdate.InventoryId = SM.magazyn AND smToUpdate.ProductId = SM.idtw
			LEFT JOIN (SELECT SUM(HM.ROUND4(iloscrz)) AS iloscrz, idtw, magazyn 
				FROM HM.RZ 
				GROUP BY RZ.idtw, RZ.magazyn) sumRZ ON sumRZ.idtw = SM.idtw AND sumRZ.magazyn = SM.magazyn
		) pom
	WHERE sm.Id = pom.Id and sm.stanHandl <> (SM.stan - pom.Ilosc)

	--próba zarezerwowania ponad stan w magazynie, zgłaszamy wyjątek z komunikatem
	IF EXISTS(SELECT TOP 1 1 FROM @tblInventoryStateAfterUpdate WHERE InventoryState < 0)
	BEGIN
		DECLARE @msgInventoryState VARCHAR(MAX)

		--składanie komunikatu

		--SQL2017 i wyższe (polecenie STRING_AGG)
		---
		-- SELECT @msgInventoryState =  
		-- 		STRING_AGG('Towar: ''' + tw.kod + '''' + CHAR(13) + 
		-- 					'Magazyn: ''' + mg.kod + '''' + CHAR(13) + 
		-- 					'Ilość powyżej stanu: ' + CONVERT(VARCHAR, -tblState.InventoryState), CHAR(13) + CHAR(13)) 
		-- FROM @tblInventoryStateAfterUpdate tblState
		-- 	JOIN HM.TW tw ON tw.id = tblState.ProductId
		-- 	JOIN HM.KH mg ON mg.id = tblState.InventoryId
		-- WHERE tblState.InventoryState < 0;
		---

		--SQL2016
		---
		SET @msgInventoryState =
			(SELECT CHAR(13) + CHAR(13) + 'Towar: ''' + tw.kod + '''' + CHAR(13) + 
							'Magazyn: ''' + mg.kod + '''' + CHAR(13) + 
							'Ilość powyżej stanu: ' + CONVERT(VARCHAR, -tblState.InventoryState) 
				FROM @tblInventoryStateAfterUpdate tblState
					JOIN HM.TW tw ON tw.id = tblState.ProductId
					JOIN HM.KH mg ON mg.id = tblState.InventoryId
				WHERE tblState.InventoryState < 0
				FOR XML PATH(''))

        SET @msgInventoryState = REPLACE(@msgInventoryState, '&#x0D;', CHAR(13))   --przywrócone entery po wygenerowaniu XML-a
        SET @msgInventoryState = STUFF(@msgInventoryState, 1, 2, '')              --usunięcie dwóch pierwszych enterów
		---

		SET @msgInventoryState = 'Operacja nie powiodła się.' +  CHAR(13) + 'Próba zarezerwowania powyżej stanu w magazynie:' + CHAR(13) + CHAR(13) + @msgInventoryState;
		THROW 50000, @msgInventoryState, 1; 
	END

END
