Developer Product Script giving the product mutiple times when purchased

My Developer Product Hander script is giving the player that purchases the developer products more products than they are suppose to get linearly like this:

1st purchase: 1 product given (1 total)
2nd purchase: 2 product given (3 total)
3rd purchase: 3 product given (6 total)
4th purchase: 4 product given (10 total)

What is wrong?

Script:

local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")


local BadgeService = game:GetService("BadgeService")
local function awardBadge(player, badgeId)
	-- Fetch badge information
	local success, badgeInfo = pcall(BadgeService.GetBadgeInfoAsync, BadgeService, badgeId)
	if success then
		-- Confirm that badge can be awarded
		if badgeInfo.IsEnabled then
			-- Award badge
			local awarded, errorMessage = pcall(BadgeService.AwardBadge, BadgeService, player.UserId, badgeId)
			if not awarded then
				warn("Error while awarding badge:", errorMessage)
			end
		end
	else
		warn("Error while fetching badge info!")
	end
end

-- Data store for tracking purchases that were successfully processed
local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")

-- Table setup containing product IDs and functions for handling purchases
local productFunctions = {}

-- Gifting Dev Prods
productFunctions[ReplicatedStorage.DevProdIDs["Speedy Sniper GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Speedy Sniper")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Speedy Sniper")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Speedy Sniper").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Speedy Sniper").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Deadly Sniper GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Deadly Sniper")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Deadly Sniper")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Deadly Sniper").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Deadly Sniper").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Pro Sniper GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Pro Sniper")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Pro Sniper")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Pro Sniper").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Pro Sniper").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Instant Respawn GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Instant Respawn")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Instant Respawn")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Instant Respawn").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Instant Respawn").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Adjust Skope GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Adjust Skope")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Adjust Skope")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Adjust Skope").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Adjust Skope").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Infinite Ammo GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Infinite Ammo")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Infinite Ammo")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Infinite Ammo").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Infinite Ammo").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Disable Pop Ups GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Disable Pop Ups")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Disable Pop Ups")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Disable Pop Ups").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Disable Pop Ups").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Infinite Jump GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Infinite Jump")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Infinite Jump")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Infinite Jump").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Infinite Jump").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Double Cash GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local stat = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Gifted_Double Cash")

		if stat and stat.Value == false then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Double Cash")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			stat.Value = true
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Double Cash").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Double Cash").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end



productFunctions[ReplicatedStorage.DevProdIDs["Tiny Pack GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Tiny Pack (+20 Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 20
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Tiny Pack").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Tiny Pack").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Small Pack GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Small Pack (+20 Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 50
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Small Pack").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Small Pack").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Medium Pack GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Medium Pack (+130 Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 130
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Medium Pack").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Medium Pack").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Large Pack GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Large Pack (+450 Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 450
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Large Pack").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Large Pack").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["Huge Pack GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Huge Pack (+900 Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 900
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Huge Pack").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Huge Pack").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end


productFunctions[ReplicatedStorage.DevProdIDs["Mega Pack GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "Mega Pack (+1.8k Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 1800
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_Mega Pack").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_Mega Pack").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

productFunctions[ReplicatedStorage.DevProdIDs["MEGA HUGE PACK GIFT"].Value] = function(receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local giftingPlayerID = nonleaderstats and nonleaderstats:FindFirstChild("Gifting_PlayerID") and nonleaderstats:FindFirstChild("Gifting_PlayerID").Value
	local giftingPlayer = giftingPlayerID and game.Players:GetPlayerByUserId(tonumber(giftingPlayerID))

	if giftingPlayer then
		local giftingPlayer_nonleaderstats = giftingPlayer:FindFirstChild("nonleaderstats")
		local cash = giftingPlayer_nonleaderstats and giftingPlayer_nonleaderstats:FindFirstChild("Cash")

		if cash then
			ReplicatedStorage.Events.Gifting.GiftMessageEvent:FireAllClients(giftingPlayer, player, "MEGA HUGE PACK (+3k Cash)")
			awardBadge(player, 1449994504734374)
			awardBadge(giftingPlayer, 3747307266877750)
			cash.Value += 3000
			return true
		else
			nonleaderstats:FindFirstChild("Gifts_MEGA HUGE PACK").Value += 1
			ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
			return true
		end
	else
		nonleaderstats:FindFirstChild("Gifts_MEGA HUGE PACK").Value += 1
		ReplicatedStorage.Events.ErrorMessage:FireClient(player, "The user you are trying to gift has either left the game or already owns the product. Please try again!")
		return true
	end
end

-- ProductId 1284314592 for Kill All
productFunctions[ReplicatedStorage.DevProdIDs["Kill All"].Value] = function(_receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	ReplicatedStorage.Events.KillAllMessage:FireAllClients(player)
	for _, v in pairs(Players:GetPlayers()) do
		if v.UserId ~= player.UserId and v.Character and v.Character:FindFirstChild("Humanoid") then
			v.Character.Humanoid.Health = 0
		end
	end
	return true
end

-- ProductId 1831786644 for Freeze All
productFunctions[ReplicatedStorage.DevProdIDs["Freeze All"].Value] = function(_receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	ReplicatedStorage.Events.FreezeAllMessage:FireAllClients(player)

	-- Find the "Freeze" object in Lighting, and enable it if found
	local freezeEffect = game.Lighting:FindFirstChild("Freeze")
	if freezeEffect then
		freezeEffect.Enabled = true
	else
		warn("Freeze effect not found in Lighting.")
	end

	-- Unfreeze players after 10 seconds using a non-yielding method
	for _, v in pairs(Players:GetPlayers()) do
		if v.UserId ~= player.UserId and v.Character and v.Character:FindFirstChild("HumanoidRootPart") then
			local humanoidRootPart = v.Character.HumanoidRootPart
			humanoidRootPart.Anchored = true

			-- Move the delay to a separate event to avoid yielding
			local hrpCopy = humanoidRootPart -- Capture reference for delayed function
			task.delay(10, function()
				if hrpCopy and hrpCopy.Anchored then
					hrpCopy.Anchored = false
				end
			end)
		end
	end

	-- Disable the freeze effect after all players are unfrozen, also with a delay
	if freezeEffect then
		local freezeCopy = freezeEffect -- Capture reference for delayed function
		task.delay(10, function()
			if freezeCopy and freezeCopy.Enabled then
				freezeCopy.Enabled = false
			end
		end)
	end

	return true
end

-- ProductId 1831786782 for Fling All
productFunctions[ReplicatedStorage.DevProdIDs["Fling All"].Value] = function(_receipt, player)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	ReplicatedStorage.Events.FlingAllMessage:FireAllClients(player)

	-- Handle flinging players
	for _, v in pairs(Players:GetPlayers()) do
		if v.Character and v.Character:FindFirstChild("HumanoidRootPart") then
			local humanoid = v.Character:FindFirstChild("Humanoid")
			if humanoid then
				humanoid.Sit = false
				humanoid.Jump = false

				local bodyVelocity = Instance.new("BodyVelocity")
				bodyVelocity.Velocity = Vector3.new(math.random(-200, 200), 200, math.random(-200, 200))
				bodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
				bodyVelocity.P = math.huge
				bodyVelocity.Parent = v.Character.HumanoidRootPart

				-- Destroy the BodyVelocity after 0.4 seconds
				local bvCopy = bodyVelocity -- Capture reference for delayed function
				task.delay(0.4, function()
					if bvCopy then
						bvCopy:Destroy()
					end
				end)
			end
		end
	end

	return true
end


-- Leaderstats Dev Prods

-- Helper function to update player cash
local function updatePlayerCash(player, amount)
	ReplicatedStorage.Events.DevProductPurchase:FireClient(player)
	local nonleaderstats = player:FindFirstChild("nonleaderstats")
	local cash = nonleaderstats and nonleaderstats:FindFirstChild("Cash")
	if cash then
		cash.Value = cash.Value + amount
		return true
	end
	return false
end

-- Product IDs for Cash Packs
productFunctions[ReplicatedStorage.DevProdIDs["Tiny Pack"].Value] = function(_receipt, player) return updatePlayerCash(player, 20) end -- Tiny Pack
productFunctions[ReplicatedStorage.DevProdIDs["Small Pack"].Value] = function(_receipt, player) return updatePlayerCash(player, 50) end -- Small Pack
productFunctions[ReplicatedStorage.DevProdIDs["Medium Pack"].Value] = function(_receipt, player) return updatePlayerCash(player, 130) end -- Medium Pack
productFunctions[ReplicatedStorage.DevProdIDs["Large Pack"].Value] = function(_receipt, player) return updatePlayerCash(player, 450) end -- Large Pack
productFunctions[ReplicatedStorage.DevProdIDs["Huge Pack"].Value] = function(_receipt, player) return updatePlayerCash(player, 900) end -- Huge Pack
productFunctions[ReplicatedStorage.DevProdIDs["Mega Pack"].Value] = function(_receipt, player) return updatePlayerCash(player, 1800) end -- Mega Pack
productFunctions[ReplicatedStorage.DevProdIDs["MEGA HUGE PACK"].Value] = function(_receipt, player) return updatePlayerCash(player, 3000) end -- MEGA HUGE Pack

-- DataStore to save all purchases globally
local purchaseDataStore = DataStoreService:GetDataStore("GlobalPurchaseDataStore")

-- Function to log purchases
local function logPurchase(player, productType, productId, productName, productPrice)
	local playerId = player.UserId
	local purchaseTime = os.time()
	local SAC = player:WaitForChild("nonleaderstats"):WaitForChild("SAC").Value

	-- Create a table to hold purchase information
	local purchaseInfo = {
		purchaseTime = purchaseTime,
		playerId = playerId,
		productType = productType,
		productId = productId,
		productName = productName,
		productPrice = productPrice,
		PlayerSAC = SAC
	}

	-- Save the purchase data to the global DataStore
	local success, err = pcall(function()
		-- Use a single key for all purchases
		local key = "GlobalPurchases"
		-- Get the existing data (all purchases) and append the new purchase
		local existingData = purchaseDataStore:GetAsync(key) or {}
		table.insert(existingData, purchaseInfo)
		-- Save the updated data back to the DataStore
		purchaseDataStore:SetAsync(key, existingData)
	end)

	if not success then
		warn("Error saving purchase data: " .. err)
	end
end

-- The core 'ProcessReceipt' callback function
MarketplaceService.ProcessReceipt = function(receiptInfo)
	-- Get player by user ID
	local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not player then
		-- The player probably left the game. If they come back, the callback will be called again.
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	-- Combine the playerProductKey to check if the product was already granted
	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
	local purchased = false

	-- Check the purchase history data store for this product
	local success, errorMessage = pcall(function()
		purchased = purchaseHistoryStore:GetAsync(playerProductKey)
	end)

	-- If the purchase was already recorded, return PurchaseGranted
	if success and purchased then
		warn("Purchase already recorded for Player:", player.Name, "Product ID:", receiptInfo.ProductId)
		return Enum.ProductPurchaseDecision.PurchaseGranted
	elseif not success then
		-- Handle data store errors
		warn("Data store error:", errorMessage)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	-- Proceed with purchase processing if it wasn't recorded already
	local purchaseProcessed = false

	-- UpdateAsync is used to ensure the purchase is processed only once
	local success, errorMessage = pcall(function()
		purchaseProcessed = purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
			if alreadyPurchased then
				-- If the purchase has been recorded, return true to avoid processing again
				warn("Purchase already processed for Player:", player.Name, "Product ID:", receiptInfo.ProductId)
				return alreadyPurchased
			end

			-- Process the purchase only once
			local productId = receiptInfo.ProductId
			local productInfo = MarketplaceService:GetProductInfo(productId, Enum.InfoType.Product)

			-- Look for a specific handler for this product ID
			local handler = productFunctions[productId]
			if handler then
				local success, result = pcall(handler, receiptInfo, player)
				if success and result then
					-- Successfully processed, log the purchase and return true
					logPurchase(player, "DevProd", productId, productInfo.Name, productInfo.PriceInRobux)
					return true -- Mark purchase as processed
				else
					-- If processing failed, don't record the purchase
					warn("Failed to process product purchase for ProductId:", productId, "Player:", player)
					return false -- Do not record
				end
			else
				-- No handler for this product
				warn("No handler found for ProductId:", productId)
				return false -- Do not record
			end
		end)
	end)

	-- Handle possible errors in updating the data store
	if not success then
		warn("Failed to process receipt due to data store error:", errorMessage)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	elseif not purchaseProcessed then
		-- If the purchase wasn't processed, avoid granting product
		warn("Purchase processing failed for Player:", player.Name, "Product ID:", receiptInfo.ProductId)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	else
		-- Return PurchaseGranted to indicate success
		warn("Purchase successfully processed for Player:", player.Name, "Product ID:", receiptInfo.ProductId)
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
end

Dev products are given multiple times if you do not successfully return PurchaseGranted

Can you please add some print statements near the end of the ProcessReceipt callback function to check if the code there is firing, and if so what if condition it is triggering.


(Also, please ensure that you put the ``` on seperate lines to the actual code when posting to the devforum, so that the syntax is correctly highlighted :slight_smile: )

1 Like

I understand, what I don’t understand is how it is not successfully not returning PurchaseGranted, When I purchase a dev product I am getting the 2nd warn command indicating that the was not purchaseProcessed. I am not that familiar with MPS could you help me out?