Allow sub upgrades/downgrades on iOS (#14303)

* Allow sub upgrades/downgrades on iOS

* fix check

* fix(lint): line length

* fix(typo): customER

* fix tests

* Implement correct handling for when subs are up/downgraded

* fix lint errors

* fix test

Co-authored-by: SabreCat <sabe@habitica.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
This commit is contained in:
Phillip Thelen
2022-11-02 03:07:23 +01:00
committed by GitHub
parent c16207c9ba
commit 9e98e56e9b
4 changed files with 347 additions and 17 deletions
+24 -12
View File
@@ -106,10 +106,6 @@ api.verifyGemPurchase = async function verifyGemPurchase (options) {
};
api.subscribe = async function subscribe (sku, user, receipt, headers, nextPaymentProcessing) {
if (user && user.isSubscribed()) {
throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED);
}
if (!sku) throw new BadRequest(shared.i18n.t('missingSubscriptionCode'));
let subCode;
@@ -140,33 +136,49 @@ api.subscribe = async function subscribe (sku, user, receipt, headers, nextPayme
throw new NotAuthorized(api.constants.RESPONSE_NO_ITEM_PURCHASED);
}
let transactionId;
let originalTransactionId;
let newTransactionId;
for (const purchaseData of purchaseDataList) {
const dateTerminated = new Date(Number(purchaseData.expirationDate));
if (purchaseData.productId === sku && dateTerminated > new Date()) {
transactionId = purchaseData.transactionId;
originalTransactionId = purchaseData.originalTransactionId;
newTransactionId = purchaseData.transactionId;
break;
}
}
if (transactionId) {
if (originalTransactionId) {
let existingSub;
if (user && user.isSubscribed()) {
if (user.purchased.plan.customerId !== originalTransactionId) {
throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED);
}
existingSub = shared.content.subscriptionBlocks[user.purchased.plan.planId];
}
const existingUser = await User.findOne({
'purchased.plan.customerId': transactionId,
'purchased.plan.customerId': originalTransactionId,
}).exec();
if (existingUser) throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED);
if (existingUser
&& (originalTransactionId === newTransactionId || existingUser._id !== user._id)) {
throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED);
}
nextPaymentProcessing = nextPaymentProcessing || moment.utc().add({ days: 2 }); // eslint-disable-line max-len, no-param-reassign
await payments.createSubscription({
const data = {
user,
customerId: transactionId,
customerId: originalTransactionId,
paymentMethod: this.constants.PAYMENT_METHOD_APPLE,
sub,
headers,
nextPaymentProcessing,
additionalData: receipt,
});
};
if (existingSub) {
data.updatedFrom = existingSub;
}
await payments.createSubscription(data);
} else {
throw new NotAuthorized(api.constants.RESPONSE_INVALID_RECEIPT);
}
@@ -75,7 +75,15 @@ async function prepareSubscriptionValues (data) {
? data.gift.subscription.key
: data.sub.key];
const autoRenews = data.autoRenews !== undefined ? data.autoRenews : true;
const months = Number(block.months);
const updatedFrom = data.updatedFrom
? shared.content.subscriptionBlocks[data.updatedFrom.key]
: undefined;
let months;
if (updatedFrom && Number(updatedFrom.months) !== 1) {
months = Math.max(0, Number(block.months) - Number(updatedFrom.months));
} else {
months = Number(block.months);
}
const today = new Date();
let group;
let groupId;