Open stevebrowndotco opened 2 years ago
For what it's worth, I found a solution by handling transaction receipts with the applicationUsername
corresponding to my user's UID in my own database. Then I have the webhook service from the Fovea Billing service post to my Firebase Cloud API function.
Within this function, I am iterating through all purchases to find expired: false
. If at least one is found, an active subscription is determined to be open regardless of whether or not the user is on iOS, android, or web (my app runs on all three places)
However I am having issues with the webhook service from Fovea where when a subscription has expired, it won't trigger the webhook, unless I manually refresh the receipt. I have contacted support about this...
I'm having to do a custom implementation because fovea billing isn't able to really be trust 100% of the time.
Not sure if this is the right place to say it here, but is there any open source implementation that you are using? Or totally custom?
It has to be custom server validation, because fovea would be used instead. I do feel that this plugin was built with mainly forcing the users of the plugin to use Fovea...it makes sense because they can make money that way.
It make sense to force people using Fovea but still they are providing flexibility to build your own validator to have full control, for free. Documentation is also really nice, I was able to build my own validator on the rest api side.
@alanmilinovic Would you open source your validator by any means?
I have no issues paying Fovea, but I fear that the service might just be stopped without notice at some point, as support for this project is somehow lacking.
Sure, I can show you part of my code, as an example how I did it on my end, just to give you an idea.
$rootScope.subscription_state_status = "Loading...";
// Show errors for 10 seconds.
store.error(function (error) {
$rootScope.subscription_state_error = "ERROR " + error.code + " - " + " " + error.message;
setTimeout(function () {
$rootScope.subscription_state_error = "";
}, 10000);
$ionicLoading.hide();
});
// Register all products
store.register([{
id: '1_year_subscription',
type: store.PAID_SUBSCRIPTION,
}, {
id: '1_month_subscription',
type: store.PAID_SUBSCRIPTION,
}]);
// Contact API webservice to validate
store.validator = function (product, callback) {
var token;
if (product.transaction.type == "android-playstore") {
token = product.transaction.purchaseToken;
}
$rootScope.subscription_state_status = "Processing, please wait...";
$appService.verifyPurchase(product.id, token, $localStorage.get('USER_ID')).then(function (data) {
if ($appHelper.ResultMessage(data)) {
if (data.ResultSets[0][0]) {
$rootScope.premium_expiry_date = moment.utc(data.ResultSets[0][0].PremiumExpirityDate).local().format('DD MMM YYYY HH:mm:ss');
$rootScope.premium = moment.utc(data.ResultSets[0][0].PremiumExpirityDate).toDate() > moment() ? true : false;
$rootScope.premium_verified = true;
$localStorage.set('SESSION_PREMIUM_EXPIRITY_DATE', $rootScope.premium_expiry_date);
$localStorage.set('SESSION_PREMIUM', $rootScope.premium);
callback(true, { transaction: "Success!" });
} else {
$rootScope.premium = false;
$rootScope.subscription_state_error = "";
callback(false, "Something went wrong");
}
}
else {
$rootScope.premium = false;
$rootScope.subscription_state_error = "";
callback(false, "Something went wrong");
}
}, function (errorResponse) {
// Check if true error occurs, not a manual abort().
if (errorResponse && errorResponse.statusText != 'abort') {
$rootScope.premium = false;
//$rootScope.subscription_state_error = "";
callback(false, "Something went wrong");
}
});
};
// Call when order (purchase) requested by the user
store.when('product').requested(function (p) {
$ionicLoading.show({
template: '<ion-spinner></ion-spinner><br/>Processing, please wait...',
delay: 250
});
});
// Call when a product order is cancelled by the user
store.when('product').cancelled(function (p) {
//store.update();
$rootScope.subscription_state_status = "";
$ionicLoading.hide();
});
// Call when payment approved
store.when('product').approved(function (p) {
p.verify();
});
// Call when payment verified
store.when('product').verified(function (p) {
p.finish();
});
// Call when payment finished
store.when('product').finished(function (p) {
store.update();
$rootScope.subscription_state_status = "";
$ionicLoading.hide();
});
// Called when any subscription product is updated
store.when('subscription').updated(function () {
const product1 = store.get('1_year_subscription') || {};
const product2 = store.get('1_month_subscription') || {};
if (product1.owned) {
//status = 'Subscribed to premium';
//$rootScope.premium = true;
} else if (product2.owned) {
//status = 'Subscribed to premium';
//$rootScope.premium = true;
} else if (product1.state === 'approved' || product2.state === 'approved') {
$rootScope.subscription_state_status = "Processing, please wait...";
} else {
$rootScope.subscription_state_status = "";
}
$rootScope.subscription_state_product1 = product1;
$rootScope.subscription_state_product2 = product2;
});
// Load informations about products and purchases
store.refresh();
General question and I can't find this in the documentation anywhere.
If a user purchases a subscription on Android, but then views the app on an iOS device, I would like to know if their "subscription" is active, regardless of the device.
I am using Fovea.Billing receipt validator if that helps...
Thank you!