We developed our app using Titanium Studio and Appcelerator offers a free module for In-App Billing which only support API v2 (I know we should use v3 but we're an indie group so $100 for the module that supports API v3 is a no for the time being).
I've read the documentation on the In-App Billing workflow for API v2, and so far the purchase logic works like a charm.
That is until we got to the part of the refunds. We have managed products and subscriptions in our app.
According to the documentation, when a refund is made, the IN_APP_NOTIFY event is triggered, which requires us to make a getPurchaseInformation call. What we have doubt is what happens after we make the getPurchaseInformation call. Does a PURCHASE_STATE_CHANGED event is triggered? If it is, then the signed data with the orders is returned updated?
For example, let's say a user Uriel buys Managed Product A, then Uriel asks for a refund. This would trigger an IN_APP_NOTIFY event and a getPurchaseInformation call is made.
What event will be triggered so I can update the app to lock the content previously available to the user? Will PURCHASE_STATE_CHANGED be triggered? If it is, then the signed data with the orders information will be returned empty? In my PURCHASE_STATE_CHANGED I validate if there are orders, if no orders are found, then all of the content is blocked.
So in short, is my guessing right or the work flow for refunds is different?
For reference, here are my PURCHASE_STATE_CHANGED function:
function PURCHASE_STATE_CHANGED_EVENT(e)
{
Ti.API.info('PURCHASE STATE CHANGED CALLED');
Ti.API.info('Signature Verification Result:\n' + VerificationString(e.result));
Ti.API.info('Signed Data:\n' + e.signedData);
/*
* We receive an object that might look like this
* {
* "nonce":-2458019374247073515,
* "orders":[
* {
* "notificationId":"notificationId",
* "orderId":"transactionId",
* "packageName":"my.package",
* "productId":"in_app_identifier",
* "purchaseTime":1394062412214,
* "purchaseState":0
* }
* ]
* }
*/
if (e.signedData != null) {
var response = JSON.parse(e.signedData);
/*
* We are not guaranteed to have any orders returned so
* we need to make sure that this one exists before using it.
*
* If there is no notificationId then there is no need to confirmNotifications().
* This happens when restoreTransactions() triggers a PURCHASE_STATE_CHANGED_EVENT.
*/
if(response.orders.length === 0)
{
Ti.API.info('nothing to restore');
setNoTransactionsToRestore();
return;
}
for(var i = 0; i < response.orders.length; i++)
{
if(typeof response.orders[i] !== 'undefined')
{
Ti.API.info('set purchase flag');
setPurchaseFlag(response.orders[i].productId);
}
if (response.orders[i] && response.orders[i].notificationId)
{
Ti.API.info('confirming notification for order ' + JSON.stringify(response.orders[i]));
var synchronousResponse = InAppBilling.confirmNotifications({
notificationIds: [response.orders[i].notificationId]
});
displaySynchronousResponseCodes(synchronousResponse);
}
}
}
else
{
Ti.API.info('signed data was null');
}
}
InAppBilling.addEventListener(InAppBilling.PURCHASE_STATE_CHANGED_EVENT, PURCHASE_STATE_CHANGED_EVENT);
and my IN_APP_NOTIFY function:
function NOTIFY_EVENT(e)
{
Ti.API.info('NOTIFY CALLED \n' + 'Notify Id:\n' + e.notifyId);
var synchronousResponse = InAppBilling.getPurchaseInformation({
notificationIds: [e.notifyId]
});
displaySynchronousResponseCodes(synchronousResponse);
}
InAppBilling.addEventListener(InAppBilling.NOTIFY_EVENT, NOTIFY_EVENT);