fix: resolve subscription ID lookup and checkout URL issues
- Fix getBaseUrl() ReferenceError by changing to resolveBaseUrl(req) for free-to-paid upgrades - Add subscription lookup by customer email when dodoSubscriptionId is missing - Log critical issues when paid users have no subscription ID in database or Dodo - Return clear error message to contact support when subscription cannot be found - Prevent silent failures in plan changes from settings page
This commit is contained in:
@@ -2247,7 +2247,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tourSteps = [
|
const tourSteps = [
|
||||||
{ target: null, color: '#008060' },
|
{ target: '#apps-content', color: '#008060' },
|
||||||
{ target: '#create-new-app', color: '#5A31F4' },
|
{ target: '#create-new-app', color: '#5A31F4' },
|
||||||
{ target: '#upload-app-btn', color: '#F59E0B' },
|
{ target: '#upload-app-btn', color: '#F59E0B' },
|
||||||
{ target: '#browse-templates-btn', color: '#10B981' },
|
{ target: '#browse-templates-btn', color: '#10B981' },
|
||||||
|
|||||||
@@ -12115,6 +12115,62 @@ async function handleAccountSettingsUpdate(req, res) {
|
|||||||
const isPaidToPaid = PAID_PLANS.has(user.plan) && PAID_PLANS.has(requestedPlan);
|
const isPaidToPaid = PAID_PLANS.has(user.plan) && PAID_PLANS.has(requestedPlan);
|
||||||
const isFreeToPaid = user.plan === 'hobby' && PAID_PLANS.has(requestedPlan);
|
const isFreeToPaid = user.plan === 'hobby' && PAID_PLANS.has(requestedPlan);
|
||||||
|
|
||||||
|
// Helper function to lookup subscription by customer
|
||||||
|
async function lookupSubscriptionByCustomer(user) {
|
||||||
|
try {
|
||||||
|
const customerId = await ensureDodoCustomer(user);
|
||||||
|
if (!customerId) return null;
|
||||||
|
|
||||||
|
const subscriptions = await dodoRequest('/subscriptions', {
|
||||||
|
method: 'GET',
|
||||||
|
query: { customer_id: customerId, status: 'active' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (subscriptions?.items && subscriptions.items.length > 0) {
|
||||||
|
const activeSub = subscriptions.items[0];
|
||||||
|
log('Found missing subscription ID via Dodo lookup', {
|
||||||
|
userId: user.id,
|
||||||
|
email: user.email,
|
||||||
|
subscriptionId: activeSub.subscription_id || activeSub.id,
|
||||||
|
customerId
|
||||||
|
});
|
||||||
|
return activeSub.subscription_id || activeSub.id;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
log('Failed to lookup subscription by customer', {
|
||||||
|
userId: user.id,
|
||||||
|
email: user.email,
|
||||||
|
error: String(error)
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If paid user is missing dodoSubscriptionId, try to look it up
|
||||||
|
if ((isPaidToFree || isPaidToPaid) && !user.dodoSubscriptionId && PAID_PLANS.has(user.plan)) {
|
||||||
|
const foundSubscriptionId = await lookupSubscriptionByCustomer(user);
|
||||||
|
if (foundSubscriptionId) {
|
||||||
|
user.dodoSubscriptionId = foundSubscriptionId;
|
||||||
|
await persistUsersDb();
|
||||||
|
log('Recovered missing subscription ID', {
|
||||||
|
userId: user.id,
|
||||||
|
email: user.email,
|
||||||
|
subscriptionId: foundSubscriptionId
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Log the issue for investigation
|
||||||
|
log('CRITICAL: Paid user missing dodoSubscriptionId and no active subscription found in Dodo', {
|
||||||
|
userId: user.id,
|
||||||
|
email: user.email,
|
||||||
|
currentPlan: user.plan,
|
||||||
|
requestedPlan: requestedPlan,
|
||||||
|
billingStatus: user.billingStatus,
|
||||||
|
subscriptionRenewsAt: user.subscriptionRenewsAt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Schedule cancellation at period end when changing from paid to free hobby plan
|
// Schedule cancellation at period end when changing from paid to free hobby plan
|
||||||
// User keeps premium features until the end of their billing period
|
// User keeps premium features until the end of their billing period
|
||||||
if (isPaidToFree && user.dodoSubscriptionId) {
|
if (isPaidToFree && user.dodoSubscriptionId) {
|
||||||
@@ -12171,6 +12227,19 @@ async function handleAccountSettingsUpdate(req, res) {
|
|||||||
return sendJson(res, 400, { error: error.message || 'Unable to change subscription plan' });
|
return sendJson(res, 400, { error: error.message || 'Unable to change subscription plan' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Handle paid-to-free or paid-to-paid when subscription ID is still missing after lookup
|
||||||
|
else if ((isPaidToFree || isPaidToPaid) && !user.dodoSubscriptionId) {
|
||||||
|
log('ERROR: Cannot change plan - paid user missing dodoSubscriptionId after lookup', {
|
||||||
|
userId: user.id,
|
||||||
|
email: user.email,
|
||||||
|
currentPlan: user.plan,
|
||||||
|
requestedPlan: requestedPlan,
|
||||||
|
changeType: isPaidToFree ? 'paid_to_free' : 'paid_to_paid'
|
||||||
|
});
|
||||||
|
return sendJson(res, 400, {
|
||||||
|
error: 'Subscription ID not found. Please contact support to resolve this issue.'
|
||||||
|
});
|
||||||
|
}
|
||||||
// For free-to-paid upgrades, create a checkout session and return the URL
|
// For free-to-paid upgrades, create a checkout session and return the URL
|
||||||
else if (isFreeToPaid || (!user.dodoSubscriptionId && PAID_PLANS.has(requestedPlan))) {
|
else if (isFreeToPaid || (!user.dodoSubscriptionId && PAID_PLANS.has(requestedPlan))) {
|
||||||
try {
|
try {
|
||||||
@@ -12217,7 +12286,7 @@ async function handleAccountSettingsUpdate(req, res) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const returnUrl = `${getBaseUrl()}/subscription-success`;
|
const returnUrl = `${resolveBaseUrl(req)}/subscription-success`;
|
||||||
checkoutBody.return_url = returnUrl;
|
checkoutBody.return_url = returnUrl;
|
||||||
|
|
||||||
const checkoutSession = await dodoRequest('/checkouts', {
|
const checkoutSession = await dodoRequest('/checkouts', {
|
||||||
|
|||||||
Reference in New Issue
Block a user