Better handling for cancellation when user had multiple subs

This commit is contained in:
Phillip Thelen
2022-11-04 13:30:50 +01:00
committed by Phillip Thelen
parent 967717a010
commit ddf1b4060d
2 changed files with 44 additions and 37 deletions

View File

@@ -412,41 +412,41 @@ describe('Apple Payments', () => {
it('uses the most recent subscription data', async () => { it('uses the most recent subscription data', async () => {
iap.getPurchaseData.restore(); iap.getPurchaseData.restore();
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData') iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
.returns([{ .returns([{
expirationDate: moment.utc().add({ day: 4 }).toDate(), expirationDate: moment.utc().add({ day: 4 }).toDate(),
purchaseDate: moment.utc().subtract({ day: 5 }).toDate(), purchaseDate: moment.utc().subtract({ day: 5 }).toDate(),
productId: 'com.habitrpg.ios.habitica.subscription.3month', productId: 'com.habitrpg.ios.habitica.subscription.3month',
transactionId: token + 'oldest', transactionId: `${token}oldest`,
originalTransactionId: token + 'evenOlder', originalTransactionId: `${token}evenOlder`,
}, { }, {
expirationDate: moment.utc().add({ day: 2 }).toDate(), expirationDate: moment.utc().add({ day: 2 }).toDate(),
purchaseDate: moment.utc().subtract({ day: 1 }).toDate(), purchaseDate: moment.utc().subtract({ day: 1 }).toDate(),
productId: 'com.habitrpg.ios.habitica.subscription.12month', productId: 'com.habitrpg.ios.habitica.subscription.12month',
transactionId: token + 'newest', transactionId: `${token}newest`,
originalTransactionId: token + 'newest', originalTransactionId: `${token}newest`,
}, { }, {
expirationDate: moment.utc().add({ day: 1 }).toDate(), expirationDate: moment.utc().add({ day: 1 }).toDate(),
purchaseDate: moment.utc().subtract({ day: 2 }).toDate(), purchaseDate: moment.utc().subtract({ day: 2 }).toDate(),
productId: 'com.habitrpg.ios.habitica.subscription.6month', productId: 'com.habitrpg.ios.habitica.subscription.6month',
transactionId: token, transactionId: token,
originalTransactionId: token, originalTransactionId: token,
}]); }]);
sub = common.content.subscriptionBlocks['basic_12mo']; sub = common.content.subscriptionBlocks.basic_12mo;
await applePayments.subscribe(user, receipt, headers, nextPaymentProcessing); await applePayments.subscribe(user, receipt, headers, nextPaymentProcessing);
expect(paymentsCreateSubscritionStub).to.be.calledOnce; expect(paymentsCreateSubscritionStub).to.be.calledOnce;
expect(paymentsCreateSubscritionStub).to.be.calledWith({ expect(paymentsCreateSubscritionStub).to.be.calledWith({
user, user,
customerId: token + 'newest', customerId: `${token}newest`,
paymentMethod: applePayments.constants.PAYMENT_METHOD_APPLE, paymentMethod: applePayments.constants.PAYMENT_METHOD_APPLE,
sub, sub,
headers, headers,
additionalData: receipt, additionalData: receipt,
nextPaymentProcessing, nextPaymentProcessing,
}); });
}) });
describe('does not apply multiple times', async () => { describe('does not apply multiple times', async () => {
it('errors when a user is using the same subscription', async () => { it('errors when a user is using the same subscription', async () => {

View File

@@ -97,8 +97,8 @@ api.subscribe = async function subscribe (user, receipt, headers, nextPaymentPro
if ((!newestDate || datePurchased > newestDate) && dateTerminated > new Date()) { if ((!newestDate || datePurchased > newestDate) && dateTerminated > new Date()) {
originalTransactionId = purchaseData.originalTransactionId; originalTransactionId = purchaseData.originalTransactionId;
newTransactionId = purchaseData.transactionId; newTransactionId = purchaseData.transactionId;
newestDate = datePurchased newestDate = datePurchased;
sku = purchaseData.productId sku = purchaseData.productId;
} }
} }
@@ -255,9 +255,16 @@ api.cancelSubscribe = async function cancelSubscribe (user, headers) {
const purchases = iap.getPurchaseData(appleRes); const purchases = iap.getPurchaseData(appleRes);
if (purchases.length === 0) throw new NotAuthorized(this.constants.RESPONSE_INVALID_RECEIPT); if (purchases.length === 0) throw new NotAuthorized(this.constants.RESPONSE_INVALID_RECEIPT);
const subscriptionData = purchases[0]; let newestDate;
for (const purchaseData of purchases) {
const datePurchased = new Date(Number(purchaseData.purchaseDate));
if (!newestDate || datePurchased > newestDate) {
dateTerminated = new Date(Number(purchaseData.expirationDate));
newestDate = datePurchased;
}
}
dateTerminated = new Date(Number(subscriptionData.expirationDate));
if (dateTerminated > new Date()) throw new NotAuthorized(this.constants.RESPONSE_STILL_VALID); if (dateTerminated > new Date()) throw new NotAuthorized(this.constants.RESPONSE_STILL_VALID);
} catch (err) { } catch (err) {
// If we have an invalid receipt, cancel anyway // If we have an invalid receipt, cancel anyway