Inventory only shows items that are in weekly shop

I’m adding a revamp of the shop in my game, and one of the new features for it is a weekly shop, 3 UNIQUE skins in the shop per week. If you buy one of the skins, it’ll go into the limiteds tab in the shop. This is all fine until the weekly skins rotate. It’ll only show in the limiteds tabs your own weeklys if they are currently in the shop.

First image is my data, which shows evidence that I own pretty much all of the weeklys (ones circled are the weekly skins), second is it showing that only the ones in the weekly shop are in my inventory.
image

Shop script: (local script)

-- Muh Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local MarketService = game:GetService("MarketplaceService")
-- Meh Folders
local functions = ReplicatedStorage:WaitForChild("Functions")
local events = ReplicatedStorage:WaitForChild("Events")
local teddyFolder = ReplicatedStorage:WaitForChild("Teddy")
-- Mah Remotes
local getData = functions:WaitForChild("getData")
local selectCharacter = functions:WaitForChild("selectCharacter")
local buyCharacter = functions:WaitForChild("buyCharacter")
local buyCurrency = functions:WaitForChild("buyCurrency")
local resetWeekly = functions:WaitForChild("resetWeekly")
local togglePopup = events:WaitForChild("togglePopup")
local getWeeklySkins = functions:WaitForChild("getWeeklySkins")
-- Mih References

local shopFrame = script.Parent:WaitForChild("Frame")
local itemsFrame = shopFrame:WaitForChild("Items")

local player = game.Players.LocalPlayer
local shop = script.Parent
local popup = shop.Parent.Popup
local pieces = shopFrame.Pieces

local shopCurrencyStock = itemsFrame.CurrencyStock
local normalStock = itemsFrame.NormalStock
local weeklyStock = itemsFrame.WeeklyStock
local limitedStock = itemsFrame.LimitedStock

-- Moh Modules
local availableCharacters = require(teddyFolder:WaitForChild("CharacterList"))

local weeklySkins = {}

local ownedCharacters = {}
local teddySelection

local weeklySkinsButton = shopFrame:WaitForChild("WeeklySkins")
local normalSkinsButton = shopFrame:WaitForChild("NormalSkins")
local currencyButton = shopFrame:WaitForChild("CurrencyButton")
local limitedSkinsButton = shopFrame:WaitForChild("LimitedSkins")

local resetWeeklyButton = shopFrame:WaitForChild("ResetWeekly")

-- Different colours used to identify different item 'states'
local colors = {
	red = Color3.fromRGB(170, 0, 0),
	orange = Color3.fromRGB(223, 142, 12),
	light_red = Color3.fromRGB(206, 27, 27),
	green = Color3.fromRGB(100, 193, 66),
	yellow = Color3.fromRGB(255, 216, 0),
	neutral = Color3.fromRGB(225, 168, 139),
	white = Color3.fromRGB(255, 255, 255)
}


-- Multi-purpose 'Are you sure' window
-- Used for confirming purchases
local function popupPrompt(msg, cancelOption)
	local result
	local cancel
	local confirm

	popup.Visible = true
	popup.Title.Text = msg
	popup.Buttons.Cancel.Visible = false

	if cancelOption then
		popup.Buttons.Cancel.Visible = true
		cancel = popup.Buttons.Cancel.Activated:Connect(function()
			if cancel then
				cancel:Disconnect()
			end
			if confirm then
				confirm:Disconnect()
			end
			popup.Visible = false
			result = false
		end)
	end

	confirm = popup.Buttons.Okay.Activated:Connect(function()
		if cancel then
			cancel:Disconnect()
		end
		if confirm then
			confirm:Disconnect()
		end
		popup.Visible = false
		result = true
	end)

	while not result do
		wait()
	end

	return result
end
togglePopup.OnClientEvent:Connect(popupPrompt)

-- Changes how the shop icons will look
local function setStatus(btn, status, color)
	-- DEFAULT 'FOR SALE' STATE
	if status == "For Sale" then
		btn.Info.Status.Size = UDim2.new(0.25,0,1,0)
		btn.Info.Status.Position = UDim2.new(0.4,0,0,0)
		btn.Info.Pieces.Visible = true
		btn.Info.Status.TextColor3 = Color3.fromRGB(255, 216, 0)
		btn.Title.TextStrokeColor3 = Color3.fromRGB(255, 216, 0)
	else -- OWNED OR SELECTD
		btn.Info.Status.Text = status
		btn.Info.Status.Size = UDim2.new(1,0,1,0)
		btn.Info.Status.Position = UDim2.new(0,0,0,0)
		btn.Info.Pieces.Visible = false
		btn.Info.Status.TextColor3 = colors[color]
		btn.Title.TextStrokeColor3 = colors[color]
	end

	btn.ViewportFrame.BackgroundColor3 = colors[color]
end

-- Checks our local table of the players session data, reduces unnecessary server calls
local function playerOwnsCharacter(name)
	if ownedCharacters then
		for index, character in pairs(ownedCharacters) do
			if character == name then
				return true
			end
		end
	end

	return false
end

-- Updates store whenever anything changes
function updateStore()
	setupCharacterShop()
	-- Gets the latest player data
	local data = getData:InvokeServer()
	if data then
		ownedCharacters = data.characters
		teddySelection = data.teddy
	end

	-- Sets shop icons to appropriate status
	for index, gui in pairs(normalStock:GetChildren()) do
		if gui:IsA("TextButton") and gui.Visible == true then
			if gui.Name == teddySelection then
				setStatus(gui, "Selected", "red")
			elseif playerOwnsCharacter(gui.Name) then
				setStatus(gui, "Owned", "green")
			end
		end
	end

	for index, gui in pairs(limitedStock:GetChildren()) do
		if gui:IsA("TextButton") and gui.Visible == true then
			if gui.Name == teddySelection then
				setStatus(gui, "Selected", "red")
			elseif playerOwnsCharacter(gui.Name) then
				setStatus(gui, "Owned", "green")
			end
		end
	end

	for index, gui in pairs(weeklyStock:GetChildren()) do
		if gui:IsA("TextButton") and gui.Visible == true then
			setStatus(gui, "For Sale", "orange")
		end
	end

	for index, gui in pairs(shopCurrencyStock:GetChildren()) do
		if gui:IsA("TextButton") and gui.Visible == true and not string.find(gui.Name, "CoinPurchase", 1) and gui.Name ~= "TeddyChance" then
			if gui.Name == teddySelection then
				setStatus(gui, "Selected", "red")
			elseif playerOwnsCharacter(gui.Name) then
				setStatus(gui, "Owned", "green")
			end
		end
	end

	-- Updates the players money tally
	pieces.Amount.Text = player.Pieces.Value
end
player.Pieces.Changed:Connect(updateStore)

-- Different colours represent different states
-- Not used for proper authentication, but provides easy client-side check
local function checkStatus(btn)
	if btn.Parent == weeklyStock then
		return "For Sale"
	else
		if btn.Info.Status.TextColor3 == colors["red"] then
			return "Selected"
		elseif btn.Info.Status.TextColor3 == colors["green"] or btn.Info.Status.TextColor3 == colors["orange"] or btn.Info.Status.TextColor3 == colors["white"] or btn.Info.Status.TextColor3 == colors["light_red"] then
			return "Owned"
		elseif btn.Info.Status.TextColor3 == colors["yellow"] then
			return "For Sale"
		end
	end
end

local function clickCharacter(btn)
	local status = checkStatus(btn)
	if btn.Parent == weeklyStock then
		local price = tonumber(btn.Info.Status.Text)
		if price and price > player.Pieces.Value then
			popupPrompt("You cannot afford this", false)
		else
			local confirm = popupPrompt("Purchase " .. btn.Name .. "?", true)
			if confirm then
				local serialNumber = 0
				local status = buyCharacter:InvokeServer(btn.Name, true)
				if status == "Success" then
					setupCharacterShop()
					updateStore()
					popupPrompt("You have successfully purchased the weekly skin " .. btn.Name .. --[[" #" .. serialNumber ..]] "!", false)
				else
					if not status then status = "Error" end
					popupPrompt(status, false)
				end
			end
		end
	end
	if playerOwnsCharacter(btn.Name) then
		if status == "Owned" then
			local status = selectCharacter:InvokeServer(btn.Name)
			if status == "Success" then
				updateStore()
			else
				if not status then status = "Error" end
				popupPrompt(status, false)
			end
		end
	else
		if status == "For Sale" then
			local price = tonumber(btn.Info.Status.Text)
			if price and price > player.Pieces.Value then
				popupPrompt("You cannot afford this", false)
			else
				local confirm = popupPrompt("Purchase " .. btn.Name .. "?", true)
				if confirm then
					local status = buyCharacter:InvokeServer(btn.Name)
					if status == "Success" then
						updateStore()
					else
						if not status then status = "Error" end
						popupPrompt(status, false)
					end
				end
			end
		else
			popupPrompt("You do not own this item", false)
		end
	end
end

local function createCharacterButton(character, parentContainer)
	local name = character["Name"]
	local characterModel = teddyFolder:FindFirstChild(name)
	
	local btn = script.Template:Clone()
	
	if characterModel then
		if character["Weekly"] then
			if not table.find(weeklySkins, name) then
				print("Can't find " .. name .. " inside weekly skins")
				btn:Destroy()
				return
			end
			if playerOwnsCharacter(name) then
				-- TODO make this into a function instead of cloning
				-- i hate this
				local ownedBtn = btn:Clone()

				ownedBtn.Name = character["Name"]
				ownedBtn.Visible = true
				ownedBtn.LayoutOrder = character["Shop Index"]
				ownedBtn.Parent = limitedStock

				-- Setup text info
				ownedBtn.Title.Text = character["Name"]
				ownedBtn.Info.Status.Text = character["Price"]
				ownedBtn.Info.Status.Size = UDim2.new(0.25, 0, 1, 0)
				ownedBtn.Info.Status.Position = UDim2.new(0.4, 0, 0, 0)

				-- Clone Teddy for viewportframe

				local teddy = characterModel:Clone()
				local cframe, size = teddy:GetBoundingBox()
				teddy.Parent = ownedBtn.ViewportFrame

				ownedBtn.ViewportFrame.BackgroundColor3 = colors["green"]

				local viewportCamera = Instance.new("Camera")
				ownedBtn.ViewportFrame.CurrentCamera = viewportCamera
				viewportCamera.Parent = ownedBtn.ViewportFrame
				viewportCamera.FieldOfView = 40
				viewportCamera.CFrame = cframe * CFrame.new(0, 1, -8) * CFrame.Angles(0, math.rad(180), 0)

				ownedBtn.Activated:Connect(function()
					clickCharacter(ownedBtn)
				end)
				setStatus(ownedBtn, "Owned", "green")
			end

			local weeklyTimeLeftScript = script.WeeklyTimeLeft:Clone()
			weeklyTimeLeftScript.Parent = btn
			weeklyTimeLeftScript.Enabled = true
		end
		
		-- Create new button
		btn.Name = character["Name"]
		btn.Visible = true
		btn.LayoutOrder = character["Shop Index"]
		btn.Parent = parentContainer

		-- Setup text info
		btn.Title.Text = character["Name"]
		btn.Info.Status.Text = character["Price"]
		btn.Info.Status.Size = UDim2.new(0.25, 0, 1, 0)
		btn.Info.Status.Position = UDim2.new(0.4, 0, 0, 0)

		-- Clone Teddy for viewportframe

		local teddy = characterModel:Clone()
		local cframe, size = teddy:GetBoundingBox()
		teddy.Parent = btn.ViewportFrame

		-- Highlight if Limited Edition
		if character["Limited Edition"] then
			btn.ViewportFrame.BackgroundColor3 = colors["white"]
		elseif character["VIP"] then
			btn.ViewportFrame.BackgroundColor3 = colors["yellow"]
		elseif character["Season Pass"] then
			btn.ViewportFrame.BackgroundColor3 = colors["light_red"]
		elseif character["Weekly"] then
			btn.ViewportFrame.BackgroundColor3 = colors["orange"]
		end

		-- Setup viewportframe
		local viewportCamera = Instance.new("Camera")
		btn.ViewportFrame.CurrentCamera = viewportCamera
		viewportCamera.Parent = btn.ViewportFrame
		viewportCamera.FieldOfView = 40
		viewportCamera.CFrame = cframe * CFrame.new(0, 1, -8) * CFrame.Angles(0, math.rad(180), 0)

		-- Handle button activation
		btn.Activated:Connect(function()
			clickCharacter(btn)
		end)
	else
		warn(name .. " doesn't have a corresponding model!")
	end
end

function setupCharacterShop()
	for _, v in pairs(normalStock:GetChildren()) do
		if v:IsA("TextButton") then
			v:Destroy()
		end
	end
	
	for _, v in pairs(limitedStock:GetChildren()) do
		if v:IsA("TextButton") then
			v:Destroy()
		end
	end
	
	for _, v in pairs(weeklyStock:GetChildren()) do
		if v:IsA("TextButton") then
			v:Destroy()
		end
	end
	
	for _, v in pairs(shopCurrencyStock:GetChildren()) do
		if v:IsA("TextButton") and not string.find(v.Name, "Coin") and v.Name ~= "TeddyChance" then
			v:Destroy()
		end
	end
	
	for index, character in pairs(availableCharacters) do
		if character["For Sale"] or character["Shown If Purchased"] then
			
			if character["VIP"] then
				local ownsVIP = false
				local success, err = pcall(function()
					ownsVIP = MarketService:UserOwnsGamePassAsync(player.UserId, 27018651)
				end)
				if success and ownsVIP then
					createCharacterButton(character, shopCurrencyStock)
				else
					warn("Error checking VIP ownership for", player.Name, err)
				end
			elseif character["Limited Edition"] then
				createCharacterButton(character, limitedStock)
			elseif character["Weekly"] then
				createCharacterButton(character, weeklyStock)
			else
				createCharacterButton(character, normalStock)
			end
		end
	end
end

-- Buy 100 Pieces
shopCurrencyStock.CoinPurchase100.Activated:Connect(function()
	MarketService:PromptProductPurchase(player, 1162320218)
end)

-- Buy 1000 Pieces
shopCurrencyStock.CoinPurchase1000.Activated:Connect(function()
	MarketService:PromptProductPurchase(player, 1162320376)
end)

currencyButton.Activated:Connect(function()
	shopCurrencyStock.Visible = true
	normalStock.Visible = false
	weeklyStock.Visible = false
	limitedStock.Visible = false
end)

normalSkinsButton.Activated:Connect(function()
	shopCurrencyStock.Visible = false
	normalStock.Visible = true
	weeklyStock.Visible = false
	limitedStock.Visible = false
end)

weeklySkinsButton.Activated:Connect(function()
	shopCurrencyStock.Visible = false
	normalStock.Visible = false
	weeklyStock.Visible = true
	limitedStock.Visible = false
end)

limitedSkinsButton.Activated:Connect(function()
	shopCurrencyStock.Visible = false
	normalStock.Visible = false
	weeklyStock.Visible = false
	limitedStock.Visible = true
end)

-- Buy Double Teddy Chance
local teddyChanceId = 14785149
shopCurrencyStock.TeddyChance.Activated:Connect(function()
	local hasPass = false

	local success, err = pcall(function()
		hasPass = MarketService:UserOwnsGamePassAsync(player.UserId, teddyChanceId)
	end)

	if not success then
		warn("Error getting gamepass info for", player.Name, err)
		popupPrompt("Error getting gamepass info", false)
		return
	end

	if hasPass then
		popupPrompt("You already own this", false)
	else
		-- Player does NOT own the game pass; prompt them to purchase
		MarketService:PromptGamePassPurchase(player, teddyChanceId)
	end
end)



shop:GetPropertyChangedSignal("Visible"):Connect(function()
	-- Update the store page when opened
	if shop.Visible then
		updateStore()
	else
		-- Hide any popups when closed
		popup.Visible = false
	end
end)

if game.Players.LocalPlayer.Name ~= "mlnitoon2" then
	resetWeeklyButton.Visible = false
end

resetWeeklyButton.Activated:Connect(function()
	local result = resetWeekly:InvokeServer()

	if result then
		weeklySkins = getWeeklySkins:InvokeServer()
		updateStore()
	end
end)

weeklySkins = getWeeklySkins:InvokeServer()

local data = getData:InvokeServer()
if data then
	ownedCharacters = data.characters
	teddySelection = data.teddy
end

setupCharacterShop()
updateStore()

--[[while task.wait(60) do -- do we need this?
	setupCharacterShop()
	updateStore()
end]]

bumping this because nobody has responded yet.