Closed KingdomGames closed 5 years ago
I am also not sure how to handle this, in the docs it says that "if the validator returns a purchase expired error code then the product will automatically lose its owned status" but I can't get this to work with a custom validation method. If I find anything out I will post here, please do the same.
@KingdomGames @OJcode14 did you ever come up with a solution to this? I'm experiencing the same thing. If a product.verify() fails with a custom validation method, how do we stop the plugin from continuing to try to verify?
Not sure if this is what you were looking for but in #162 I asked how to make a product lose owned status with a custom verification.
Thanks @OJcode14 . That's not quite my case, so I'm still a little unclear what the process should be. I have a consumable product and the following validator:
store.validator = function(product, callback) {
sendToServer(product).then(
function(data) { //deferred resolve
console.log('server validated order');
callback(true, product);
},
function(data) { //deferred reject
console.log('server error validating order');
callback(false, data.error);
}
);
};
where sendToServer() makes a call to my server with the transaction details. My server tries to validate the purchase with Apple or Google Play, and if it fails it returns an error. When my server returns an error in sendToServer(), the plugin continues to try to verify() the product for 5 times. After the 5th error the plugin fires the unverified event but leaves the product in a state such that 1) it cannot be purchased by the user and 2) when the store is refreshed the product is "approved" and kicks off the "verify()" loop again, resulting in the same unpurchaseable product.
What am I supposed to do when a transaction is not verified to avoid this loop?
Yeah, I'm not sure, I kind of dumped the verified/unverified events and handle it manually depending on what my server tells me is the state of the transaction.
@j3k0 any pointers here?
Even if my server verification fails, product.canPurchase remains "false" and the product is in an "approved" state until product.finish() is called. Even if the server verification fails are we to still call product.finish()?
The docs say:
To verfify a purchase you'll have to do three things:
- configure the validator.
- call product.verify() from the approved event, before finishing the transaction.
- finish the transaction when transaction is verified.
What do we do when the transaction fails verification? Thank you!
what did you do here @daveande ?
@OJcode14 I didn't come up with a solution. I just ended up just calling product.finish() on all transactions, regardless of server verification. It still seems like there should be a way to handle the transaction if it fails server verification, but I couldn't come up with a solution that avoided leaving the product in an "approved" state.
Hmm, I'm having the exact same problems as @daveande, it tries to verify 5 times and only on the 5th time it correctly fires an expired-error
The problem is that the documentation for the error object is wrong, it should be like: callback(false, { code: store.PURCHASE_EXPIRED, message: "..." });
Not "error : {code: ...}"
That sets the product back to valid, but on restart it is still validated again, so that is still a problem.
Any news on this? There is no way to abort a purchase? Either the customer is charged, or you have to retry forever? Even though it might never go through?
Any updates on this? I am having the same problem with an app I have in App Store.
Hello, any news on this? I'm having the same problem in App Store. I am using a server side validator. Is it ok to finish the order when unverified?
store.when("myproduct").unverified(function (order) {
console.log("Sorry, transaction unverified");
order.finish();
});
Thanks
Hey. It's OK to finish some unverified orders. Make sure you understand the reason of validation failure.
Without much explanation, what I think is valid behavior.
Wow, that was fast, thanks! So if I don't finish the order/product, should I just leave it alone and do nothing? It seems to me just weird leaving it like pending forever... I have only consumable products, so I should not even bother handling/checking the expired status right?
Exactly, for a consumable no need to bother with expiry status. Invalid transactions are either due to "fake" transactions generated on a jailbroken device, or a sign that something went wrong went validating with your server. In the second case, it has to stay pending. In the first case, I guess any behavior is fine (for example, start a background loop that drowns the users battery)
In my understanding the (consumable) product should end up being unverified only if the transaction is actually never been made 'legally' by/through the app (passing through store.verify()
) or if the app doesn't receive an answer for our server/validator, for whatever reason.
In this case I should call product.finish()
only if the product is valid.
store.when("myproduct").unverified(function (product) {
alert("Sorry, something wrong happened...");
if (product.status == store.VALID) {
product.finish();
}
});
Am I correct? Or should I implement the if statement in the error callback?
VALID
state means the product exists on the store. (INVALID
when product doesn't).
This is different from verified and unverified.
Anyway, if the transaction isn't valid (not the product) you can finish the transaction as well. It'll clean it up from the queue, that's actually better.
Any update on this? My question is... If the server validation fails (because connection error, google or ios server errors, incorrect token, magic bunny...), how can i change the product state back to VALID? This is my code:
store.when(subscription.id).approved(function(p) {
alert("Store approved");
verifyTransaction(p).then(function() {
p.finish();
}).catch(function(error) {
alert(angular.toJson(error));
});
});
function verifyTransaction(product) {
var token;
if (product.transaction.type == "ios-appstore") {
token = product.transaction.appStoreReceipt;
} else {
token = product.transaction.purchaseToken;
}
return $http.post(validatorSubscriptionPurchaseUrl, {
product_id: product.id,
purchase_token: token
});
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Is it fine to call product.finish(); inside the validator method? verified never fires for me, so considering just to finish inside store.validator after my backend has returned if the receipt was valid or not . Is that fine or must i finish within the verified method? Thanks
Are there any examples of how to handle verification failures?
Using 3.9, my products are stuck in the APPROVED state and never return to valid, making them un-purchaseable forevermore.
I've tried setting the product state back to VALID in the unverified callback, but no dice.
Every time the app is opened store.refresh is called and the product once again tries to verify / validate. If its receipt data is bad however, this loop will never be broken: (Open App --> store.refresh --> product.approved --> product.verify --> FAIL).
I am really lost on this, any help would be greatly appreciated