One method, which allows for a little more complexity than just JOINing the IB table to "cte" in your final SELECT is to nest another CTE using the current one as the table. For example:
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
),
filtered AS (
SELECT IJLOC, IJITEM, IJDATE, IJLCGT
FROM cte
WHERE rn = 1
)
SELECT ib.QOO, ib.QOH, ib.QCM, ib.[AVG]
FROM ib
INNER JOIN filtered
ON filtered.IJITEM = IB.IBITEM
AND filtered.IJLOC = IB.IBLOC
Another option, depending on how the query optimizer handles the JOINs between all the tables, and if you don't need to return any of the fields from the IJ table, is to insert the results of your CTE into a temp table and then JOIN to that. For example:
CREATE TABLE #Temp (IJITEM DataType, IJLOC DataType)
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
)
INSERT INTO #Temp (IJITEM, IJLOC)
SELECT IJITEM, IJLOC
FROM cte
WHERE rn = 1;
SELECT ib.QOO, ib.QOH, ib.QCM, ib.[AVG]
FROM ib
INNER JOIN #Temp tmp
ON tmp.IJITEM = IB.IBITEM
AND tmp.IJLOC = IB.IBLOC