feat: fixes and formatter
This commit is contained in:
+195
-236
@@ -1,281 +1,263 @@
|
||||
const admin = require("firebase-admin");
|
||||
const { HttpsError } = require("firebase-functions/https");
|
||||
const Stripe = require("stripe");
|
||||
const { URL } = require("url");
|
||||
const admin = require('firebase-admin')
|
||||
const { HttpsError } = require('firebase-functions/https')
|
||||
const Stripe = require('stripe')
|
||||
const { URL } = require('url')
|
||||
|
||||
const {
|
||||
STRIPE_SECRET_KEY = "",
|
||||
STRIPE_RETURN_URL = "",
|
||||
STRIPE_PORTAL_CONFIGURATION = "",
|
||||
STRIPE_SECRET_KEY = '',
|
||||
STRIPE_RETURN_URL = '',
|
||||
STRIPE_PORTAL_CONFIGURATION = '',
|
||||
STRIPE_MODE: CONFIG_STRIPE_MODE,
|
||||
} = require("../config/keys");
|
||||
} = require('../config/keys')
|
||||
|
||||
const STRIPE_MODE =
|
||||
typeof CONFIG_STRIPE_MODE === "string" && CONFIG_STRIPE_MODE.trim()
|
||||
typeof CONFIG_STRIPE_MODE === 'string' && CONFIG_STRIPE_MODE.trim()
|
||||
? CONFIG_STRIPE_MODE.trim()
|
||||
: "test";
|
||||
: 'test'
|
||||
|
||||
const requireEnv = (key) => {
|
||||
const value = process.env?.[key];
|
||||
if (typeof value === "string" && value.trim()) {
|
||||
return value.trim();
|
||||
const value = process.env?.[key]
|
||||
if (typeof value === 'string' && value.trim()) {
|
||||
return value.trim()
|
||||
}
|
||||
throw new Error(`${key} not configured`);
|
||||
};
|
||||
throw new Error(`${key} not configured`)
|
||||
}
|
||||
|
||||
const STRIPE_API_VERSION = "2023-10-16";
|
||||
const DEFAULT_TEST_RETURN_URL = "http://localhost:8081";
|
||||
const ALLOWED_RETURN_SCHEMES = ["http", "https", "minuit"];
|
||||
const STRIPE_API_VERSION = '2023-10-16'
|
||||
const DEFAULT_TEST_RETURN_URL = 'http://localhost:8081'
|
||||
const ALLOWED_RETURN_SCHEMES = ['http', 'https', 'minuit']
|
||||
|
||||
let cachedStripeClient = null;
|
||||
let cachedPortalConfigurationId = null;
|
||||
let cachedStripeClient = null
|
||||
let cachedPortalConfigurationId = null
|
||||
|
||||
const resolveStripeSecretKey = () => {
|
||||
const inlineKey =
|
||||
typeof STRIPE_SECRET_KEY === "string" ? STRIPE_SECRET_KEY.trim() : "";
|
||||
const inlineKey = typeof STRIPE_SECRET_KEY === 'string' ? STRIPE_SECRET_KEY.trim() : ''
|
||||
|
||||
if (inlineKey) {
|
||||
return inlineKey;
|
||||
return inlineKey
|
||||
}
|
||||
|
||||
const required = requireEnv("STRIPE_SECRET_KEY");
|
||||
if (typeof required === "string" && required.trim()) {
|
||||
return required.trim();
|
||||
const required = requireEnv('STRIPE_SECRET_KEY')
|
||||
if (typeof required === 'string' && required.trim()) {
|
||||
return required.trim()
|
||||
}
|
||||
|
||||
throw new Error("STRIPE_SECRET_KEY not configured");
|
||||
};
|
||||
throw new Error('STRIPE_SECRET_KEY not configured')
|
||||
}
|
||||
|
||||
const getStripeClient = () => {
|
||||
if (cachedStripeClient) {
|
||||
return cachedStripeClient;
|
||||
return cachedStripeClient
|
||||
}
|
||||
|
||||
let secretKey;
|
||||
let secretKey
|
||||
try {
|
||||
secretKey = resolveStripeSecretKey();
|
||||
secretKey = resolveStripeSecretKey()
|
||||
} catch (error) {
|
||||
console.error("[getStripeClient] Missing STRIPE_SECRET_KEY", error);
|
||||
console.error('[getStripeClient] Missing STRIPE_SECRET_KEY', error)
|
||||
throw new HttpsError(
|
||||
"failed-precondition",
|
||||
"Stripe n’est pas configuré. Ajoute STRIPE_SECRET_KEY pour activer cette fonctionnalité.",
|
||||
);
|
||||
'failed-precondition',
|
||||
'Stripe n’est pas configuré. Ajoute STRIPE_SECRET_KEY pour activer cette fonctionnalité.'
|
||||
)
|
||||
}
|
||||
|
||||
cachedStripeClient = new Stripe(secretKey, {
|
||||
apiVersion: STRIPE_API_VERSION,
|
||||
});
|
||||
})
|
||||
|
||||
return cachedStripeClient;
|
||||
};
|
||||
return cachedStripeClient
|
||||
}
|
||||
|
||||
const getReturnBaseUrl = () => {
|
||||
const resolveBase = () => {
|
||||
if (STRIPE_RETURN_URL) {
|
||||
return STRIPE_RETURN_URL;
|
||||
return STRIPE_RETURN_URL
|
||||
}
|
||||
if (STRIPE_MODE !== "prod") {
|
||||
return DEFAULT_TEST_RETURN_URL;
|
||||
if (STRIPE_MODE !== 'prod') {
|
||||
return DEFAULT_TEST_RETURN_URL
|
||||
}
|
||||
return requireEnv("STRIPE_RETURN_URL");
|
||||
};
|
||||
|
||||
const rawBase = resolveBase();
|
||||
const sanitizedBase = typeof rawBase === "string" ? rawBase.trim() : "";
|
||||
if (!sanitizedBase) {
|
||||
if (STRIPE_MODE !== "prod") {
|
||||
return DEFAULT_TEST_RETURN_URL;
|
||||
}
|
||||
throw new Error("STRIPE_RETURN_URL not configured");
|
||||
return requireEnv('STRIPE_RETURN_URL')
|
||||
}
|
||||
|
||||
return sanitizedBase.endsWith("/")
|
||||
? sanitizedBase.slice(0, -1)
|
||||
: sanitizedBase;
|
||||
};
|
||||
const rawBase = resolveBase()
|
||||
const sanitizedBase = typeof rawBase === 'string' ? rawBase.trim() : ''
|
||||
if (!sanitizedBase) {
|
||||
if (STRIPE_MODE !== 'prod') {
|
||||
return DEFAULT_TEST_RETURN_URL
|
||||
}
|
||||
throw new Error('STRIPE_RETURN_URL not configured')
|
||||
}
|
||||
|
||||
return sanitizedBase.endsWith('/') ? sanitizedBase.slice(0, -1) : sanitizedBase
|
||||
}
|
||||
|
||||
const sanitizeReturnUrl = (value) => {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
if (typeof value !== 'string') {
|
||||
return null
|
||||
}
|
||||
|
||||
const trimmed = value.trim();
|
||||
const trimmed = value.trim()
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const validateScheme = (scheme) => {
|
||||
if (!ALLOWED_RETURN_SCHEMES.includes(scheme)) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`Le schéma d'URL "${scheme}" n'est pas autorisé pour les retours Stripe.`,
|
||||
);
|
||||
'invalid-argument',
|
||||
`Le schéma d'URL "${scheme}" n'est pas autorisé pour les retours Stripe.`
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const parsedUrl = new URL(trimmed);
|
||||
const scheme = parsedUrl.protocol.replace(":", "").toLowerCase();
|
||||
validateScheme(scheme);
|
||||
return trimmed;
|
||||
const parsedUrl = new URL(trimmed)
|
||||
const scheme = parsedUrl.protocol.replace(':', '').toLowerCase()
|
||||
validateScheme(scheme)
|
||||
return trimmed
|
||||
} catch (_error) {
|
||||
const schemeMatch = trimmed.match(/^([a-z][a-z0-9+\-.]*):\/\//i);
|
||||
const schemeMatch = trimmed.match(/^([a-z][a-z0-9+\-.]*):\/\//i)
|
||||
if (schemeMatch && schemeMatch[1]) {
|
||||
const scheme = schemeMatch[1].toLowerCase();
|
||||
validateScheme(scheme);
|
||||
return trimmed;
|
||||
const scheme = schemeMatch[1].toLowerCase()
|
||||
validateScheme(scheme)
|
||||
return trimmed
|
||||
}
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`URL de retour Stripe invalide: ${trimmed}`,
|
||||
);
|
||||
throw new HttpsError('invalid-argument', `URL de retour Stripe invalide: ${trimmed}`)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const getReturnUrls = (overrides) => {
|
||||
if (overrides && typeof overrides === "object") {
|
||||
const successOverride = sanitizeReturnUrl(overrides.successUrl);
|
||||
const cancelOverride = sanitizeReturnUrl(overrides.cancelUrl);
|
||||
if (overrides && typeof overrides === 'object') {
|
||||
const successOverride = sanitizeReturnUrl(overrides.successUrl)
|
||||
const cancelOverride = sanitizeReturnUrl(overrides.cancelUrl)
|
||||
|
||||
if (!successOverride) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
"successUrl est requis pour configurer les retours Stripe.",
|
||||
);
|
||||
'invalid-argument',
|
||||
'successUrl est requis pour configurer les retours Stripe.'
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
successUrl: successOverride,
|
||||
cancelUrl: cancelOverride || successOverride,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const baseUrl = getReturnBaseUrl();
|
||||
const baseUrl = getReturnBaseUrl()
|
||||
|
||||
const joinPath = (url, path) => {
|
||||
const trimmedUrl = url.endsWith("/") ? url.slice(0, -1) : url;
|
||||
const trimmedPath = path.startsWith("/") ? path.slice(1) : path;
|
||||
return `${trimmedUrl}/${trimmedPath}`;
|
||||
};
|
||||
const trimmedUrl = url.endsWith('/') ? url.slice(0, -1) : url
|
||||
const trimmedPath = path.startsWith('/') ? path.slice(1) : path
|
||||
return `${trimmedUrl}/${trimmedPath}`
|
||||
}
|
||||
|
||||
const appendQuery = (url, query) =>
|
||||
url.includes("?") ? `${url}&${query}` : `${url}?${query}`;
|
||||
const appendQuery = (url, query) => (url.includes('?') ? `${url}&${query}` : `${url}?${query}`)
|
||||
|
||||
const successBase = joinPath(baseUrl, "payment-success");
|
||||
const cancelBase = joinPath(baseUrl, "payment-error");
|
||||
const successBase = joinPath(baseUrl, 'payment-success')
|
||||
const cancelBase = joinPath(baseUrl, 'payment-error')
|
||||
|
||||
return {
|
||||
successUrl: appendQuery(successBase, "session_id={CHECKOUT_SESSION_ID}"),
|
||||
cancelUrl: appendQuery(cancelBase, "session_id={CHECKOUT_SESSION_ID}"),
|
||||
};
|
||||
};
|
||||
successUrl: appendQuery(successBase, 'session_id={CHECKOUT_SESSION_ID}'),
|
||||
cancelUrl: appendQuery(cancelBase, 'session_id={CHECKOUT_SESSION_ID}'),
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeBoolean = (value) => value === true;
|
||||
const normalizeBoolean = (value) => value === true
|
||||
|
||||
const buildCheckoutLineItems = async (productList, { stripe } = {}) => {
|
||||
if (!Array.isArray(productList) || productList.length === 0) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
"Au moins un produit est requis pour créer une session de paiement.",
|
||||
);
|
||||
'invalid-argument',
|
||||
'Au moins un produit est requis pour créer une session de paiement.'
|
||||
)
|
||||
}
|
||||
|
||||
const lineItems = [];
|
||||
const summary = [];
|
||||
let hasSubscription = false;
|
||||
const lineItems = []
|
||||
const summary = []
|
||||
let hasSubscription = false
|
||||
|
||||
for (let index = 0; index < productList.length; index += 1) {
|
||||
const rawItem = productList[index];
|
||||
const item = rawItem && typeof rawItem === "object" ? rawItem : {};
|
||||
const rawItem = productList[index]
|
||||
const item = rawItem && typeof rawItem === 'object' ? rawItem : {}
|
||||
|
||||
const isRenewable = normalizeBoolean(item.isRenewable);
|
||||
const isRenewable = normalizeBoolean(item.isRenewable)
|
||||
const rawQuantity =
|
||||
typeof item.quantity === "number" && Number.isFinite(item.quantity)
|
||||
typeof item.quantity === 'number' && Number.isFinite(item.quantity)
|
||||
? item.quantity
|
||||
: parseInt(item.quantity, 10);
|
||||
const quantity =
|
||||
Number.isFinite(rawQuantity) && rawQuantity > 0 ? rawQuantity : 1;
|
||||
: parseInt(item.quantity, 10)
|
||||
const quantity = Number.isFinite(rawQuantity) && rawQuantity > 0 ? rawQuantity : 1
|
||||
|
||||
const priceId = typeof item.priceID === "string" ? item.priceID.trim() : "";
|
||||
const priceId = typeof item.priceID === 'string' ? item.priceID.trim() : ''
|
||||
|
||||
if (isRenewable && !priceId) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`Un price ID Stripe est requis pour l'élément ${index + 1} (abonnement).`,
|
||||
);
|
||||
'invalid-argument',
|
||||
`Un price ID Stripe est requis pour l'élément ${index + 1} (abonnement).`
|
||||
)
|
||||
}
|
||||
|
||||
if (priceId) {
|
||||
let stripePrice = null;
|
||||
let stripePrice = null
|
||||
if (stripe) {
|
||||
try {
|
||||
stripePrice = await stripe.prices.retrieve(priceId);
|
||||
stripePrice = await stripe.prices.retrieve(priceId)
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[buildCheckoutLineItems] Unable to retrieve price",
|
||||
priceId,
|
||||
error,
|
||||
);
|
||||
console.error('[buildCheckoutLineItems] Unable to retrieve price', priceId, error)
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`Le price ID "${priceId}" est introuvable (élément ${index + 1}).`,
|
||||
);
|
||||
'invalid-argument',
|
||||
`Le price ID "${priceId}" est introuvable (élément ${index + 1}).`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const priceIsRecurring =
|
||||
stripePrice?.type === "recurring" || !!stripePrice?.recurring;
|
||||
const priceIsRecurring = stripePrice?.type === 'recurring' || !!stripePrice?.recurring
|
||||
if (isRenewable && !priceIsRecurring) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`Le price ID "${priceId}" n'est pas compatible avec un abonnement.`,
|
||||
);
|
||||
'invalid-argument',
|
||||
`Le price ID "${priceId}" n'est pas compatible avec un abonnement.`
|
||||
)
|
||||
}
|
||||
|
||||
const resolvedIsRenewable = priceIsRecurring ? true : isRenewable;
|
||||
const resolvedIsRenewable = priceIsRecurring ? true : isRenewable
|
||||
|
||||
if (resolvedIsRenewable) {
|
||||
hasSubscription = true;
|
||||
hasSubscription = true
|
||||
}
|
||||
|
||||
lineItems.push({
|
||||
price: priceId,
|
||||
quantity,
|
||||
});
|
||||
})
|
||||
summary.push({
|
||||
type: "price",
|
||||
type: 'price',
|
||||
priceID: priceId,
|
||||
quantity,
|
||||
isRenewable: resolvedIsRenewable,
|
||||
});
|
||||
continue;
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
const rawUnitAmount = Number(item.unitAmount);
|
||||
const unitAmount = Math.round(rawUnitAmount);
|
||||
const rawUnitAmount = Number(item.unitAmount)
|
||||
const unitAmount = Math.round(rawUnitAmount)
|
||||
if (!Number.isFinite(unitAmount) || unitAmount <= 0) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`Le montant indiqué pour l'élément ${index + 1} est invalide.`,
|
||||
);
|
||||
'invalid-argument',
|
||||
`Le montant indiqué pour l'élément ${index + 1} est invalide.`
|
||||
)
|
||||
}
|
||||
|
||||
const currency =
|
||||
typeof item.currency === "string"
|
||||
? item.currency.trim().toLowerCase()
|
||||
: "eur";
|
||||
const currency = typeof item.currency === 'string' ? item.currency.trim().toLowerCase() : 'eur'
|
||||
|
||||
if (!/^[a-z]{3}$/.test(currency)) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
`La devise indiquée pour l'élément ${index + 1} est invalide.`,
|
||||
);
|
||||
'invalid-argument',
|
||||
`La devise indiquée pour l'élément ${index + 1} est invalide.`
|
||||
)
|
||||
}
|
||||
|
||||
const label =
|
||||
typeof item.label === "string" && item.label.trim()
|
||||
? item.label.trim()
|
||||
: "Paiement ponctuel";
|
||||
typeof item.label === 'string' && item.label.trim() ? item.label.trim() : 'Paiement ponctuel'
|
||||
|
||||
lineItems.push({
|
||||
price_data: {
|
||||
@@ -286,95 +268,84 @@ const buildCheckoutLineItems = async (productList, { stripe } = {}) => {
|
||||
unit_amount: unitAmount,
|
||||
},
|
||||
quantity,
|
||||
});
|
||||
})
|
||||
|
||||
summary.push({
|
||||
type: "custom",
|
||||
type: 'custom',
|
||||
currency,
|
||||
unitAmount,
|
||||
quantity,
|
||||
isRenewable: false,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if (hasSubscription) {
|
||||
const hasNonSubscription = summary.some((item) => !item.isRenewable);
|
||||
const hasNonSubscription = summary.some((item) => !item.isRenewable)
|
||||
if (hasNonSubscription) {
|
||||
throw new HttpsError(
|
||||
"invalid-argument",
|
||||
"Impossible de mélanger abonnements et paiements ponctuels dans une seule session Checkout.",
|
||||
);
|
||||
'invalid-argument',
|
||||
'Impossible de mélanger abonnements et paiements ponctuels dans une seule session Checkout.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return { lineItems, summary, hasSubscription };
|
||||
};
|
||||
return { lineItems, summary, hasSubscription }
|
||||
}
|
||||
|
||||
const ensureStripeCustomer = async ({
|
||||
uid,
|
||||
stripe,
|
||||
refsList,
|
||||
createIfMissing = true,
|
||||
}) => {
|
||||
const ensureStripeCustomer = async ({ uid, stripe, refsList, createIfMissing = true }) => {
|
||||
if (!uid) {
|
||||
return { customerId: null, userData: null };
|
||||
return { customerId: null, userData: null }
|
||||
}
|
||||
|
||||
const userRef = refsList?.users?.doc(uid);
|
||||
const snapshot = userRef ? await userRef.get() : null;
|
||||
const userData = snapshot?.exists ? snapshot.data() : null;
|
||||
const userRef = refsList?.users?.doc(uid)
|
||||
const snapshot = userRef ? await userRef.get() : null
|
||||
const userData = snapshot?.exists ? snapshot.data() : null
|
||||
|
||||
let customerId = userData?.stripeCustomerId;
|
||||
let customerId = userData?.stripeCustomerId
|
||||
if (customerId) {
|
||||
return { customerId, userData };
|
||||
return { customerId, userData }
|
||||
}
|
||||
|
||||
if (!createIfMissing) {
|
||||
return { customerId: null, userData };
|
||||
return { customerId: null, userData }
|
||||
}
|
||||
|
||||
let authRecord = null;
|
||||
let authRecord = null
|
||||
try {
|
||||
authRecord = await admin.auth().getUser(uid);
|
||||
authRecord = await admin.auth().getUser(uid)
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[ensureStripeCustomer] Impossible de récupérer auth user",
|
||||
error,
|
||||
);
|
||||
console.warn('[ensureStripeCustomer] Impossible de récupérer auth user', error)
|
||||
}
|
||||
|
||||
const email = userData?.email || authRecord?.email || undefined;
|
||||
const nameFromProfile = [userData?.firstName, userData?.lastName]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
.trim();
|
||||
const name = nameFromProfile || authRecord?.displayName || undefined;
|
||||
const email = userData?.email || authRecord?.email || undefined
|
||||
const nameFromProfile = [userData?.firstName, userData?.lastName].filter(Boolean).join(' ').trim()
|
||||
const name = nameFromProfile || authRecord?.displayName || undefined
|
||||
|
||||
const customer = await stripe.customers.create({
|
||||
email,
|
||||
name,
|
||||
metadata: {
|
||||
firebaseUID: uid,
|
||||
appMode: STRIPE_MODE || "test",
|
||||
appMode: STRIPE_MODE || 'test',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
customerId = customer.id;
|
||||
customerId = customer.id
|
||||
|
||||
if (userRef) {
|
||||
await userRef.set(
|
||||
{
|
||||
stripeCustomerId: customerId,
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
{ merge: true }
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
customerId,
|
||||
userData: { ...userData, stripeCustomerId: customerId },
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const formatCheckoutSessionResponse = (session) => ({
|
||||
id: session.id,
|
||||
@@ -391,84 +362,72 @@ const formatCheckoutSessionResponse = (session) => ({
|
||||
created: session.created,
|
||||
expires_at: session.expires_at,
|
||||
client_secret: session.client_secret || null,
|
||||
});
|
||||
})
|
||||
|
||||
const getPortalConfigurationId = async (stripe) => {
|
||||
if (STRIPE_PORTAL_CONFIGURATION) {
|
||||
return STRIPE_PORTAL_CONFIGURATION;
|
||||
return STRIPE_PORTAL_CONFIGURATION
|
||||
}
|
||||
|
||||
if (cachedPortalConfigurationId) {
|
||||
return cachedPortalConfigurationId;
|
||||
return cachedPortalConfigurationId
|
||||
}
|
||||
|
||||
if (
|
||||
!stripe ||
|
||||
typeof stripe.billingPortal?.configurations?.list !== "function"
|
||||
) {
|
||||
throw new HttpsError(
|
||||
"internal",
|
||||
"Client Stripe indisponible pour la configuration du portail.",
|
||||
);
|
||||
if (!stripe || typeof stripe.billingPortal?.configurations?.list !== 'function') {
|
||||
throw new HttpsError('internal', 'Client Stripe indisponible pour la configuration du portail.')
|
||||
}
|
||||
|
||||
try {
|
||||
const configurations = await stripe.billingPortal.configurations.list({
|
||||
limit: 100,
|
||||
});
|
||||
})
|
||||
|
||||
const defaultConfiguration =
|
||||
configurations.data.find((config) => config.is_default) ||
|
||||
configurations.data.find((config) => config.active);
|
||||
configurations.data.find((config) => config.active)
|
||||
|
||||
if (defaultConfiguration?.id) {
|
||||
cachedPortalConfigurationId = defaultConfiguration.id;
|
||||
return cachedPortalConfigurationId;
|
||||
cachedPortalConfigurationId = defaultConfiguration.id
|
||||
return cachedPortalConfigurationId
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[getPortalConfigurationId] Impossible de lister les configurations de portail",
|
||||
error?.message || error,
|
||||
);
|
||||
'[getPortalConfigurationId] Impossible de lister les configurations de portail',
|
||||
error?.message || error
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const defaultReturnUrl = getReturnBaseUrl();
|
||||
const createdConfiguration =
|
||||
await stripe.billingPortal.configurations.create({
|
||||
default_return_url: defaultReturnUrl,
|
||||
business_profile: {
|
||||
headline: "Minuit Starter",
|
||||
},
|
||||
});
|
||||
const defaultReturnUrl = getReturnBaseUrl()
|
||||
const createdConfiguration = await stripe.billingPortal.configurations.create({
|
||||
default_return_url: defaultReturnUrl,
|
||||
business_profile: {
|
||||
headline: 'Minuit Starter',
|
||||
},
|
||||
})
|
||||
|
||||
if (createdConfiguration?.id) {
|
||||
cachedPortalConfigurationId = createdConfiguration.id;
|
||||
return cachedPortalConfigurationId;
|
||||
cachedPortalConfigurationId = createdConfiguration.id
|
||||
return cachedPortalConfigurationId
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[getPortalConfigurationId] Impossible de créer une configuration de portail par défaut",
|
||||
error?.message || error,
|
||||
);
|
||||
'[getPortalConfigurationId] Impossible de créer une configuration de portail par défaut',
|
||||
error?.message || error
|
||||
)
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
return null
|
||||
}
|
||||
|
||||
const mapStripeErrorToHttps = (error, fallbackMessage) => {
|
||||
const message =
|
||||
error?.raw?.message ||
|
||||
error?.message ||
|
||||
fallbackMessage ||
|
||||
"Erreur Stripe.";
|
||||
const statusCode = error?.statusCode || error?.raw?.statusCode;
|
||||
const isClientError =
|
||||
typeof statusCode === "number" && statusCode >= 400 && statusCode < 500;
|
||||
const message = error?.raw?.message || error?.message || fallbackMessage || 'Erreur Stripe.'
|
||||
const statusCode = error?.statusCode || error?.raw?.statusCode
|
||||
const isClientError = typeof statusCode === 'number' && statusCode >= 400 && statusCode < 500
|
||||
|
||||
const code = isClientError ? "failed-precondition" : "internal";
|
||||
return new HttpsError(code, message);
|
||||
};
|
||||
const code = isClientError ? 'failed-precondition' : 'internal'
|
||||
return new HttpsError(code, message)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getStripeClient,
|
||||
@@ -479,4 +438,4 @@ module.exports = {
|
||||
formatCheckoutSessionResponse,
|
||||
getPortalConfigurationId,
|
||||
mapStripeErrorToHttps,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user