question

Adam Matheny avatar image
Adam Matheny asked

Requesting Help with implementing Real Money Purchases in Unity C#

While I managed to get Virtual Currency transactions functioning on our project some time ago, I've been having some difficulty with figuring out the proper implementation of the StartPurchase/PayForPurchase/ConfirmPurchase sequence in C# when handling Real Money (RM) transactions.

In this example I'm trying to use Real Money to purchase a catalog item that will grant the user Virtual Currency (VC).

Here's what I have so far:

//Try to purchase the 100 VC pack ~Adam

                #region Start the Purchase
                //Declare the item to purchase ~Adam
                ItemPuchaseRequest itemToPurchase = new ItemPuchaseRequest();
                itemToPurchase.ItemId = "currency_pack_100";
                itemToPurchase.Quantity = 1;

                //Create a request to purchase the item ~adam
                StartPurchaseRequest startRequest = new StartPurchaseRequest(); 
                startRequest.CatalogVersion = items[CurrencyPackNumber].CatalogVersion;
                startRequest.StoreId = "currency_pack_100";
                startRequest.Items[0] = itemToPurchase;

                StartPurchaseResult startResult = new StartPurchaseResult();//ERROR HERE

                PlayFabClientAPI.StartPurchaseCallback startCallback = new PlayFabClientAPI.StartPurchaseCallback(startResult);
                ErrorCallback purchaseErrorCallback = new ErrorCallback((PlayFabError error) => new PlayFabError());
                PlayFabClientAPI.StartPurchase (startRequest,startCallback, purchaseErrorCallback);


                #endregion

                #region Pay for the Purchase
                //Create a request to pay for the item ~Adam
                PayForPurchaseRequest payRequest = new PayForPurchaseRequest();
                payRequest.OrderId = startResult.OrderId;
                payRequest.ProviderName = "PayPal";
                payRequest.Currency = "RM";

// payRequest.Items[0] = itemToPurchase;

                PayForPurchaseResult payResult = new PayForPurchaseResult();//ERROR HERE

                PlayFabClientAPI.PayForPurchaseCallback payCallback = new PlayFabClientAPI.PayForPurchaseCallback(payResult);


                PlayFabClientAPI.PayForPurchase(payRequest,payCallback, purchaseErrorCallback);


                #endregion


                #region Confirm the Purchase
                ConfirmPurchaseRequest confirmRequest = new ConfirmPurchaseRequest();
                confirmRequest.OrderId = startResult.OrderId;

                ConfirmPurchaseResult confirmResult = new ConfirmPurchaseResult();//ERROR HERE

                PlayFabClientAPI.ConfirmPurchaseCallback confirmCallback = new PlayFabClientAPI.ConfirmPurchaseCallback(confirmResult);

                PlayFabClientAPI.ConfirmPurchase (confirmRequest, confirmCallback, purchaseErrorCallback);

                #endregion

I think I mostly have it set up right, but I'm not sure how to properly access the OrderID from the StartPurchase results to use for PayForPurchase and ConfirmPurchase. My current thought was to declare a StartPurchaseResult variable whose OrderId I can reference, but attempting to declare such a variable gives me the following error:

"Expression denotes a 'variable', where a 'type' or 'method group' was expected"

If anyone could please point out where I am going wrong here, it would be greatly appreciated.

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

simon avatar image simon commented ·

18 bullet points i need to code manually? Why aren't they all handled for me? Isnt that one of the reasons to have Playfab? Why are payments so over complicated? Everyone wants to do exactly the same thing - send a payment & that changes a variable. No?

0 Likes 0 ·
brendan avatar image brendan simon commented ·

I take it you're referring to the flow with was posted by Adam? He's describing a specific code flow for his game which includes far more than purchasing. Have a look at our commerce tutorials: https://api.playfab.com/docs/tutorials#landing-commerce. The number of API calls required are actually fairly minimal (only one each for any VC purchase, receipt validation, or entitlement check, and at most three for things like Facebook/PayPal/Steam, where we have to set up a "cart" in advance of payment confirmation, and don't necessarily get notified by the payment provider when the purchase is complete).

0 Likes 0 ·
brendan avatar image
brendan answered

From looking at your title configuration, I'm seeing two problems. The first is that you don't actually have any Stores defined, so setting the StoreId in the StartPurchase call will cause an error. The second is that the only RM price defined for the item in question is RM 0 - the item does need to have a non-zero price defined.

Now, the way this normally works is that on the callback from StartPurchase, you would indeed use a payment provider from the array returned in your StartPurchaseResult. You shouldn't need to instantiate that distinctly, though - it will be returned as part of the callback. So for example, you might have a callback declared like so:

void onStartPurchase(StartPurchaseResult result)
{
    // process the StartPurchaseResult, call PayForPurchase
}

And then you would pass that in as the callback for your StartPurchase call. Make sense?

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

bbord22 avatar image bbord22 commented ·

For some reason, StartPurchaseCallback doesn't seem to be a class available to me in PlayFabClientAPI. Why could this be?

0 Likes 0 ·
brendan avatar image brendan bbord22 commented ·

The callbacks are actually your code - not part of the SDK. If you have a look at the StartPurchase call in the SDK you're using, you'll see that they accept callbacks (we just happened to call ours "StartPurchaseCallback" in our example) that our code calls into, where you can take any action you need to based on the results. There's also an error callback that you should use to process any error cases.

0 Likes 0 ·
Adam Matheny avatar image
Adam Matheny answered

Thank you for letting me know that about the RM amounts and Store definitions. I had left the RM value at 0 because I didn't want to be accidentally charging myself money when I debug and test my code implementations, and I didn't think to define a Store since the Virtual Currency transactions were working directly out of the catalog.

It still does not however answer my original question of how I access the StartPurchaseResult information (namely, the generated OrderID) for use in the PayForPurchase function.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

The StartPurchaseResult is passed to your callback function. So, the example I posted showed a function named onStartPurchase. You would pass that into the call to StartPurchase as the callback. When it is called, the StartPurchaseResult is passed in, and you can access the OrderID there.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Adam Matheny avatar image
Adam Matheny answered

Thank you for your help and patience. I think I mostly have this working now. At any rate, all of my Debug message are firing at each step of the transaction, and the player account that I've been using for testing now has several items with a "Create Cart" status and one with a "Succeeded" status and Virtual Currency was added to that player's account after the one item succeeded.

Oddly though, the transaction that succeeded is logged as having a price of "0" while the ones that are stuck on "Create Cart" have a logged price of "1 RM" even though the successful item has a price of "1 RM" in the Store and Catalog.
Also, after I execute the transaction code in Unity, Unity's Console gives an error saying "409 Conflict" with no explanation as to what a 409 Conflict is. While I suspect this has something to do with why only one transaction fully completed, without knowing what that error is I have little recourse for fixing it.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

If you don't mind us creating a user and testing on your title, could you let us know the specific repro steps to get this error?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Adam Matheny avatar image
Adam Matheny answered

I don't mind you making a user to test on our title at all.  However since the error is occurring in-game (specifically I've been testing in the Unity Editor) I'll need to provide you with a build of the game to reproduce the error.  What would be the best way to get an .exe build of the game to you to test?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Sorry - to be clear, we should be able to reproduce any error through the simple expedient of using Postman. The client application usually isn't necessary. What are the specific logic steps the title goes through for your repro? We can test it out in Postman here, and see if there are any issues.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Adam Matheny avatar image
Adam Matheny answered

Steps the code goes through:

When the scene is opened:

1)Get user inventory

2)Request catalog version, and construct catalog/GetCatalogItems

When the button to purchase Currency is pressed:

3)Figure out which item in the catalog the button pressed corresponds to

4)Create an ItemPurchaseRequest and set its ItemID and Quantity

5)Create a StartPurchaseRequest, set its CatalogVersion and StoreID and add the ItemPurchaseRequest created in the previous step

6)Create a StartPurchaseCallback, passing in a custom function called OnStartPurchase()

7)Call the StartPurchase() function, passing in the StartPurchaseRequest and StartPurchaseCallback created in steps 5 and 6. This activates the OnStartPurchase() functinon

In OnStartPurchase():

8)Create a PayForPurchaseRequest and set its OrderID, ProviderName and Currency

9)Create a PayForPurchaseCallback

10)Call the PayForPurchase() function, passing in the PayForPurchaseRequest and PayForPurchaseCallback created in steps 8 and 9

11)Create a ConfirmPurchaseRequest and set its OrderID

12)Create a ConfirmPurchaseCallback

13)Call the ConfirmPurchase() function, passing in the ConfirmPurchaseRequest and ConfirmPurchaseCallback created in steps 11 and 12

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Okay, so once you've created the purchase record with us (StartPurchase), told us that you want to use PayPal (PayForPurcahse - which is the point where we inform PayPal of the impending purchase), how are you popping the PayPal window to ask the player to make the payment? Are you using their SDK, or are you using a web page?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Adam Matheny avatar image
Adam Matheny answered

That would be my problem.  I haven't fully implemented the PayPal communication side of things yet.  I was trying to make sure I had the Playfab side of things set up properly first. 

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.