Dev Product bug each other?

So I got two small scripts one for tools that are given if u buy the dev product or Cash given and somewhy when I join only one works and when I delete one script of those the other works perfectly but I need both and IDK if I can combine them but ye:
ServerScriptService(ServerScript)

local MPS = game:GetService("MarketplaceService")
local toolFolder = game.ServerStorage.DevProducts -- Tool storage

-- πŸ”„ Load Cash Dev Products (from ModuleScript in ReplicatedStorage)
local function getCashDevProducts()
	local success, cashDevProducts = pcall(function()
		return require(game.ReplicatedStorage:WaitForChild("DevProducts")) -- Ensure it exists
	end)

	if not success then
		warn("⚠ Failed to load cash dev products!")
		return {} -- Return empty table to avoid breaking the script
	end

	print("βœ… Cash Dev Products Loaded:", cashDevProducts)
	return cashDevProducts
end

-- πŸ›  Tool Dev Products (stored inside this script)
local toolDevProducts = {
	[3235590181] = { Tool = "Invisible" },
	[1828475960] = { Tool = "Speed" },
	[3228363764] = { Tool = "Aura" }
}

-- πŸ”„ Function to merge Cash & Tool Products
local function getMergedDevProducts()
	local cashDevProducts = getCashDevProducts()

	-- Merge tools into cash products table
	for productId, toolData in pairs(toolDevProducts) do
		cashDevProducts[productId] = toolData
	end

	print("πŸ“œ Final Merged DevProducts:", cashDevProducts)
	return cashDevProducts
end

-- πŸ’°πŸ›  Handle Purchases
MPS.ProcessReceipt = function(receiptInfo)
	print("πŸ›’ ProcessReceipt triggered. Product ID: " .. tostring(receiptInfo.ProductId))

	local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not player then
		print("❌ Player not found!")
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	-- πŸ”„ Refresh & Merge Dev Products each time
	local devproducts = getMergedDevProducts()

	-- Get product data
	local productData = devproducts[receiptInfo.ProductId]
	if not productData then
		print("❌ Error: No Developer Product found for Product ID: " .. tostring(receiptInfo.ProductId))
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	print("βœ… Found product data for: " .. tostring(receiptInfo.ProductId))

	-- πŸ’° Handle Cash Purchases
	if productData.Cash then
		print("πŸ’° Adding cash: " .. productData.Cash .. " to player " .. player.Name)

		local leaderstats = player:FindFirstChild("leaderstats")
		if not leaderstats then
			print("❌ Error: leaderstats not found! Creating one.")
			leaderstats = Instance.new("Folder")
			leaderstats.Name = "leaderstats"
			leaderstats.Parent = player
		end

		local cashStat = leaderstats:FindFirstChild("Cash")
		if not cashStat then
			print("❌ Error: Cash stat not found! Creating one.")
			cashStat = Instance.new("IntValue")
			cashStat.Name = "Cash"
			cashStat.Parent = leaderstats
		end

		-- Update Cash
		local oldCash = cashStat.Value
		cashStat.Value = cashStat.Value + productData.Cash
		print("βœ… " .. player.Name .. " cash updated: " .. oldCash .. " ➑ " .. cashStat.Value)
	end

	-- πŸ›  Handle Tool Purchases
	if productData.Tool then
		print("πŸ”§ Granting tool: " .. productData.Tool)

		local inventory = player:FindFirstChild("Inventory")
		if not inventory then
			inventory = Instance.new("Folder")
			inventory.Name = "Inventory"
			inventory.Parent = player
		end

		-- Check if player already has the tool
		local existingTool = inventory:FindFirstChild(productData.Tool)
		if existingTool then
			print("♻️ Removing existing tool before granting a new one.")
			existingTool:Destroy() -- Remove old tool
		end

		-- Grant the tool
		local tool = toolFolder:FindFirstChild(productData.Tool)
		if tool then
			local clonedTool = tool:Clone()
			clonedTool.Parent = inventory
			print("βœ… Tool '" .. productData.Tool .. "' added to Inventory!")
		else
			print("❌ Error: Tool '" .. productData.Tool .. "' not found in ServerStorage.DevProducts!")
		end
	end

	print("βœ… Purchase process completed for Product ID: " .. tostring(receiptInfo.ProductId))
	return Enum.ProductPurchaseDecision.PurchaseGranted
end



ReplicatedStorage(ModuleScript)

local devproducts = {}

devproducts[1827603254] = { Cash = 50 }
devproducts[1827608966] = { Cash = 200 }
devproducts[1827625322] = { Cash = 500 }
devproducts[1827630970] = { Cash = 1000 }
devproducts[1827632701] = { Cash = 2500 }
devproducts[1827656787] = { Cash = 5000 }
devproducts[1827657912] = { Cash = 10000 }
devproducts[1827659233] = { Cash = 20000 }
devproducts[1827659880] = { Cash = 50000 }

return devproducts

That’s just the nature of process receipt - there can only be one occurance of it within the game.

You’ll need to merge the 2 scripts so that it handles both types of dev products

1 Like

litarilly tried even with chat gpt but didn’t work

Please elaborate.

What script did you end up with? Did you remove any other ProcessReceipt handlign scripts?

1 Like

Youre better off creating a module script for the dev products then importing the module for the script that handles the product processing.

1 Like

To fix your product handling issue call the dev product function with the same productid being purchased.Or i can show you an example of my dev product handling that is more efficient.

This is how your dev products functions should be handled in a modulescript ignore some irrelevant code but look at the functions:

local Marketingmodule = {}
local Players=game:GetService("Players")
local DataStoreService=game:GetService("DataStoreService")
local DonationRobuxHistory=DataStoreService:GetOrderedDataStore("GlobalDonation")
local availableMessages={"Lol Bye Bye"," your my Enemy","has kicked you out of the Server","XD have Fun!"," On Top"}
local MarketPlaceService=game:GetService("MarketplaceService")
local BindableNetwork=require(game.ServerStorage:WaitForChild("BindableNetwork"))
local NetworkServer=require(game.ServerStorage:WaitForChild("NetworkServer"))
local GameFrameWork=require(game.ServerStorage:WaitForChild("GameFrameWork"))
Marketingmodule.Products={}
local function ProductsAbility(products,ProductCategory)
	local Ability={Cash=Marketingmodule.AwardCoins;Kick=Marketingmodule.KickPlayer,Robux=Marketingmodule.RobuxDonation;ShieldPotion=Marketingmodule.ShieldProtection}
	for _,product in pairs(products) do
		Marketingmodule.Products[product.ProductId]=Ability[ProductCategory]
	end
end
local function ReturnSearchedProducts(keyword)
	local ProductResults={}
	local CurrentPages=MarketPlaceService:GetDeveloperProductsAsync():GetCurrentPage()
	for _,currentproduct in pairs(CurrentPages) do
		if string.match(currentproduct["Name"],keyword) then
			table.insert(ProductResults,currentproduct)
		end
	end
	table.sort(ProductResults,function(a,b)
		return a.PriceInRobux>b.PriceInRobux
	end)
	return ProductResults
end
local function InitializeProducts()
	local AvailableProducts={"Kick","Cash","Robux","ShieldPotion"}
	for _,product in pairs(AvailableProducts) do
		local Products=ReturnSearchedProducts(product)
		ProductsAbility(Products,product)
	end
end
local Products,Products2=ReturnSearchedProducts("Cash"),ReturnSearchedProducts("ShieldPotion")
local CashProducts={}
local ShieldProdcuts={}
local AvailbleCash={4500,2095,1025,700,100}
local AvailableShieldTime={60*10,60*5,60*2}
for Cashindex,Cashproduct in pairs(Products) do
	CashProducts[Cashproduct.ProductId]=AvailbleCash[Cashindex]
end
for ShieldTime,ShieldProduct in pairs(Products2) do
	ShieldProdcuts[ShieldProduct.ProductId]=AvailableShieldTime[ShieldTime]
end
NetworkServer.ReturnServerEventSignal("GetProductCash").OnInvoke=function(player:Player)
	return CashProducts
end
function Marketingmodule.KickPlayer(receipt,player:Player)
	local VotedPlayer=player:GetAttribute("SelectedPlayer") -- Selected player User Id
	if (VotedPlayer and Players:GetPlayerByUserId(VotedPlayer)) then
		player:SetAttribute("SelectedPlayer",nil)
		VotedPlayer=Players:GetPlayerByUserId(VotedPlayer) --becomes an actual player Instance
		if VotedPlayer==player then
			player:Kick(player.Name.."-You kicked yourself of the game Lol!")
		else
			VotedPlayer:Kick(player.Name.."-"..availableMessages[math.random(1,5)])
		end
		return true
	end
end
function Marketingmodule.AwardCoins(receipt,player:Player)
	local coins=player:FindFirstChild("Coins")
	if not coins then
		return
	end
	if player:GetAttribute("SelectedItem") then
		NetworkServer.FireClient(player,"BuyInventoryGuiItem",player:GetAttribute("SelectedItem"))
		player:SetAttribute("SelectedItem",nil)
	end
	local ReceiptProductID=receipt.ProductId
	coins.Value+=CashProducts[ReceiptProductID]
	require(game.ServerStorage:WaitForChild("DataProfile")):UpdateData(player,{Id="Currency"},coins.Value)
	return true
end
function Marketingmodule.RobuxDonation(receipt,player:Player)
	local ProductInfo=MarketPlaceService:GetProductInfo(receipt.ProductId,Enum.InfoType.Product)
	if not ProductInfo then
		return 
	end
	local success,errormessage = pcall(function()
		DonationRobuxHistory:UpdateAsync(player.UserId,function(oldvalue)
			local newvalue=oldvalue or 0
			return newvalue+receipt.CurrencySpent
		end)
	end)
	if success then
		return true
	end
end
function Marketingmodule:AwardPlayerStand(player,awardedStand)
	warn(player.Name.."-awarded"..awardedStand.."Stand")
	NetworkServer.FireClient(player,"AwardedStandTemplate",awardedStand)
end
function Marketingmodule.ShieldProtection(receipt,player:Player)
	local ShieldPotion=player:GetAttribute("ShieldPotion")
	local ReceiptProductID=receipt.ProductId
	local shieldTime=ShieldProdcuts[ReceiptProductID]
	if not ShieldPotion then
		local PlayerStand=game.Workspace:FindFirstChild(player.Name.."-Stand")
		player:SetAttribute("ShieldCounter",shieldTime/60)
		player:SetAttribute("ShieldPotion",shieldTime)
		player:GetAttributeChangedSignal("ShieldPotion"):Connect(function()
			local ShieldPotion=player:GetAttribute("ShieldPotion")
			if ShieldPotion==0 then
				PlayerStand:SetAttribute("ShieldPotion",nil)
				player:SetAttribute("ShieldPotion",nil)
			end
		end)
		local shield=game.ServerStorage.ShieldModel:Clone()
		shield:PivotTo(PlayerStand:GetPivot()+Vector3.new(0,.4,0))
		shield.Parent=PlayerStand
		if not table.find(GameFrameWork.InRoundPlayers,player) then
			print("Eligbile for cutscene")
			NetworkServer.FireClient(player,"ShieldProtectionCutscene")
		end
		NetworkServer.FireClient(player,"ShieldTimerGui")
		BindableNetwork:Fire("ShieldTimerEvent",player)
		shield.Script.Enabled=true 
	else
		player:SetAttribute("ShieldCounter",player:GetAttribute("ShieldCounter")+(shieldTime/60))
		player:SetAttribute("ShieldPotion",ShieldPotion+shieldTime)
	end
	return true
end
function Marketingmodule:GetGamePassInfo(passid)
	print(passid)
	local success,gamepassinfo = pcall(function()
		return MarketPlaceService:GetProductInfo(passid,Enum.InfoType.GamePass)
	end)
	if success and gamepassinfo then
		warn(gamepassinfo)
		return gamepassinfo
	end
end
function Marketingmodule:PromptGamePass(player:Player,gamepassid)
	if not player then
		return
	end
	if not MarketPlaceService:UserOwnsGamePassAsync(player.UserId,gamepassid) then
		MarketPlaceService:PromptGamePassPurchase(player,gamepassid)
	else
		warn(Marketingmodule:GetGamePassInfo(gamepassid))
	end
end
function Marketingmodule:UserRequireGamePass(player:Player,gamepassid)
	if not player then
		return
	end
	return MarketPlaceService:UserOwnsGamePassAsync(player.UserId,gamepassid) 
end
InitializeProducts()
return Marketingmodule
[/quote]

The product handling should look like this were i import the products module then call upon the required dev product function

local function processReceipt(receiptInfo)
	-- check if the product was already granted by checking the data store
	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
	local purchased = false
	local success, result, errorMessage

	success, errorMessage = pcall(function()
		purchased = purchaseHistoryStore:GetAsync(playerProductKey)
	end)
	-- the product was already granted if purchased
	if success and purchased then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	elseif not success then
		error("Data store error:" .. errorMessage)
	end

	-- if the product was already granted by checking the data store  
	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId

	local success, isPurchaseRecorded = pcall(function()
		return purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
			if alreadyPurchased then
				return true
			end

			-- Find the player who made the purchase in the server
			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 nil
			end

			local handler = MarketingProducts.Products[receiptInfo.ProductId]

			local success, result = pcall(handler, receiptInfo, player)
			-- If granting the product failed, do NOT record the purchase in datastores.
			if not success or not result then
				error("Failed to process a product purchase for ProductId: " .. tostring(receiptInfo.ProductId) .. " Player: " .. tostring(player) .. " Error: " .. tostring(result))
				return nil
			end

			-- Record the transcation in purchaseHistoryStore.
			return true
		end)
	end)

	if not success then
		error("Failed to process receipt due to data store error.")
		return Enum.ProductPurchaseDecision.NotProcessedYet
	elseif isPurchaseRecorded == nil then
		-- Didn't update the value in data store.
		return Enum.ProductPurchaseDecision.NotProcessedYet
	else	
		-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
end
MarketPlaceService.ProcessReceipt = processReceipt
[/quote]