stripe embedded and other fixes

This commit is contained in:
Thomas Demirdjian
2025-11-18 11:40:39 +01:00
parent 016f7c27ac
commit 7ab8685180
17 changed files with 2346 additions and 2504 deletions
+213
View File
@@ -0,0 +1,213 @@
const { HttpsError, onCall } = require("firebase-functions/https");
const { getStripeClient, mapStripeErrorToHttps } = require("../../helpers/stripe");
const { REGION } = require("./config");
const {
CANCELABLE_SUBSCRIPTION_STATUSES,
ACTIVE_SUBSCRIPTION_STATUSES,
} = require("./constants");
const {
refsList,
formatSubscriptionForClient,
resolveUserContext,
} = require("./shared");
const cancelActiveSubscription = onCall({ region: REGION }, async (request) => {
try {
const uid = request?.auth?.uid;
if (!uid) {
throw new HttpsError(
"unauthenticated",
"Connecte-toi pour gérer ton abonnement.",
);
}
const stripe = getStripeClient();
const userRef = refsList?.users?.doc(uid) || null;
const snapshot = userRef ? await userRef.get() : null;
const userData = snapshot?.exists ? snapshot.data() || {} : {};
const inputSubscriptionId =
typeof request?.data?.subscriptionId === "string"
? request.data.subscriptionId.trim()
: "";
let subscriptionId =
inputSubscriptionId ||
userData?.stripeSubscription?.id ||
userData?.stripeSubscription?.subscriptionId ||
null;
const customerId = userData?.stripeCustomerId || null;
if (!subscriptionId && customerId) {
try {
const response = await stripe.subscriptions.list({
customer: customerId,
status: "all",
limit: 5,
});
const { data: subscriptionList = [] } = response || {};
const activeSubscription = subscriptionList.find(
(candidate) =>
candidate?.status &&
CANCELABLE_SUBSCRIPTION_STATUSES.has(candidate.status),
);
if (activeSubscription?.id) {
subscriptionId = activeSubscription.id;
}
} catch (error) {
console.warn(
"[subscription-cancelActiveSubscription] Unable to list subscriptions",
customerId,
error?.message || error,
);
}
}
if (!subscriptionId) {
throw new HttpsError(
"failed-precondition",
"Aucun abonnement actif à annuler.",
);
}
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
if (!subscription) {
throw new HttpsError("not-found", "Abonnement introuvable côté Stripe.");
}
if (subscription.status === "canceled") {
return {
subscriptionId: subscription.id,
status: subscription.status,
cancelAtPeriodEnd: subscription.cancel_at_period_end === true,
currentPeriodEnd: subscription.current_period_end || null,
alreadyCanceled: true,
};
}
if (subscription.cancel_at_period_end === true) {
return {
subscriptionId: subscription.id,
status: subscription.status,
cancelAtPeriodEnd: true,
currentPeriodEnd: subscription.current_period_end || null,
alreadyCanceled: false,
};
}
const updatedSubscription = await stripe.subscriptions.update(
subscriptionId,
{
cancel_at_period_end: true,
},
);
return {
subscriptionId: updatedSubscription.id,
status: updatedSubscription.status,
cancelAtPeriodEnd: updatedSubscription.cancel_at_period_end === true,
currentPeriodEnd: updatedSubscription.current_period_end || null,
alreadyCanceled: false,
};
} catch (error) {
console.error("[subscription-cancelActiveSubscription] error", error);
if (error instanceof HttpsError) {
throw error;
}
throw mapStripeErrorToHttps(
error,
"Impossible d'annuler l'abonnement Stripe.",
);
}
});
const getActiveSubscription = onCall({ region: REGION }, async (request) => {
try {
const uid = request?.auth?.uid;
if (!uid) {
throw new HttpsError(
"unauthenticated",
"Connecte-toi pour récupérer ton abonnement.",
);
}
const stripe = getStripeClient();
const {
uid: resolvedUid,
userRef,
userData,
} = await resolveUserContext({
metadata: request?.data?.metadata || {},
customerId: null,
});
const lookupUid = resolvedUid || uid;
const lookupRef = userRef || refsList?.users?.doc(lookupUid) || null;
const snapshot = lookupRef ? await lookupRef.get() : null;
const data = snapshot?.exists ? snapshot.data() || {} : userData || {};
const subscriptionId =
data?.stripeSubscription?.id ||
data?.stripeSubscription?.subscriptionId ||
null;
const customerId = data?.stripeCustomerId || null;
if (!subscriptionId && !customerId) {
return {
subscription: null,
customerId: null,
};
}
if (subscriptionId) {
const subscription = await stripe.subscriptions.retrieve(subscriptionId, {
expand: ["items.data.price.product"],
});
if (subscription) {
return {
subscription: formatSubscriptionForClient(subscription),
customerId: subscription.customer || customerId || null,
};
}
}
if (customerId) {
const response = await stripe.subscriptions.list({
customer: customerId,
status: "all",
limit: 5,
expand: ["data.items.data.price.product"],
});
const [subscription] = response?.data || [];
if (subscription && ACTIVE_SUBSCRIPTION_STATUSES.has(subscription.status)) {
return {
subscription: formatSubscriptionForClient(subscription),
customerId,
};
}
}
return {
subscription: null,
customerId,
};
} catch (error) {
console.error("[subscription-getActiveSubscription] error", error);
if (error instanceof HttpsError) {
throw error;
}
throw mapStripeErrorToHttps(
error,
"Impossible de récupérer l'abonnement Stripe.",
);
}
});
module.exports = {
cancelActiveSubscription,
getActiveSubscription,
};