I am having an issue with my ProcessReceipt implementation where some players are receiving the perks every time they rejoin the game. The issue is resolved when they join a private server. It’s due to the purchase history DataStore not saving their purchase, but I’m not sure why this could be.
The errors I have are not actually outputting, meaning everything should be successful? The only thing that doesn’t throw an error is the elseif
clause in the bottom of the function, which could be the issue. When querying the datastore with the key that it’s supposed to save, it returns nil
, until they join a private server which for some reason saves properly.
My implementation is based off the official Roblox one: MarketplaceService | Documentation - Roblox Creator Hub
Posting here in case I’ve made a stupid mistake that others can spot.
---> services
local players = game:GetService("Players")
local dataStoreService = game:GetService("DataStoreService")
---> variables
local purchaseHistoryStore = dataStoreService:GetDataStore("PurchaseHistory")
---> functions
local function processReceipt(receiptInfo)
local dataStoreKey = `{receiptInfo.PlayerId}_{receiptInfo.PurchaseId}`
-- check if user was already granted the purchase
local purchased = false
local success, errorMessage = pcall(function()
purchased = purchaseHistoryStore:GetAsync(dataStoreKey)
end)
if success and purchased then
-- purchase has already been granted
return Enum.ProductPurchaseDecision.PurchaseGranted
elseif not success then
-- purchase process errored, try again later
error(`Failed to process purchase due to data store error: {errorMessage}`)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- attempt to handle the purchase
local succes2, isPurchaseRecorded = pcall(function()
return purchaseHistoryStore:UpdateAsync(dataStoreKey, function(alreadyPurchased)
-- make sure purchase has not already been granted
if alreadyPurchased then return true end
-- make sure player is still in the game
local player = players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then return nil end
-- handle award function
local func = purchaseFunctions[receiptInfo.ProductId]
if func then
-- attempt to run the function
local handleSuccess, handleResult = pcall(func, player, receiptInfo)
if not handleSuccess then
-- purchase errored, try again later
error(`Failed to process purchase for {receiptInfo.ProductId} due to handler error: {handleResult}`)
return nil
end
-- record the transaction in the datastore
return true
else
error(`A handler function for {receiptInfo.ProductId} does not exist.`)
return nil
end
end)
end)
-- handle any datastore errors
if not success2 then
-- purchase process errored, will be tried again later
error(`Failed to process purchase due to data store error`)
return Enum.ProductPurchaseDecision.NotProcessedYet
elseif isPurchaseRecorded == nil then
-- value was not updated in the data store
-- I THINK THIS COULD BE THE ISSUE
return Enum.ProductPurchaseDecision.NotProcessedYet
else
-- tell roblox the purchase was granted
return Enum.ProductPurchaseDecision.PurchaseGranted
end
end