const { HttpsError, onCall } = require("firebase-functions/https"); const { getStripeClient, mapStripeErrorToHttps } = require("../../helpers/stripe"); const { REGION } = require("./config"); const { SUBSCRIPTION_PRICE_IDS, SUBSCRIPTION_PRICE_METADATA, COIN_PACK_PRODUCTS, } = require("./constants"); const { parseCoinsPerMonth, formatCoinPack } = require("./shared"); const formatPlan = (price, priceId) => { if (!price || typeof price !== "object") { return null; } const product = typeof price.product === "object" && price.product !== null ? price.product : {}; return { id: price.id || priceId, priceId: price.id || priceId, active: price.active !== false, currency: price.currency || "eur", unitAmount: price.unit_amount, unitAmountDecimal: price.unit_amount_decimal, transformQuantity: price.transform_quantity || null, recurring: price.recurring || null, nickname: price.nickname || null, billingScheme: price.billing_scheme || null, coinsPerMonth: parseCoinsPerMonth(product?.metadata || {}) || (SUBSCRIPTION_PRICE_METADATA[price.id || priceId]?.coinsPerMonth ?? null), metadata: price.metadata || {}, product: { id: product.id || null, name: product.name || "", description: product.description || "", metadata: product.metadata || {}, }, }; }; const listSubscriptionPlans = onCall({ region: REGION }, async () => { try { const stripe = getStripeClient(); const entries = await Promise.all( Object.entries(SUBSCRIPTION_PRICE_IDS).map(async ([period, priceIds]) => { const periodPlans = await Promise.all( priceIds.map(async (priceId) => { try { const price = await stripe.prices.retrieve(priceId, { expand: ["product"], }); return formatPlan(price, priceId); } catch (error) { console.error( `[subscription-listSubscriptionPlans] Impossible de récupérer ${priceId}`, error?.message || error, ); return null; } }), ); return [period, periodPlans.filter(Boolean)]; }), ); return { plans: Object.fromEntries(entries), }; } catch (error) { console.error("[subscription-listSubscriptionPlans] error", error); throw mapStripeErrorToHttps( error, "Impossible de récupérer les abonnements Stripe.", ); } }); const listCoinPacks = onCall({ region: REGION }, async () => { try { const stripe = getStripeClient(); const packs = await Promise.all( COIN_PACK_PRODUCTS.map(async (pack) => { try { const product = await stripe.products.retrieve(pack.productId, { expand: ["default_price"], }); let resolvedPrice = null; if (typeof product?.default_price === "string") { resolvedPrice = await stripe.prices.retrieve(product.default_price); } else if ( product?.default_price && typeof product.default_price === "object" ) { resolvedPrice = product.default_price; } const formatted = formatCoinPack({ product, price: resolvedPrice, }); return { ...formatted, coinPackKey: pack.key || null, }; } catch (error) { console.error( "[subscription-listCoinPacks] Unable to retrieve product", pack.productId, error?.message || error, ); return null; } }), ); return { packs: packs.filter(Boolean), }; } catch (error) { console.error("[subscription-listCoinPacks] error", error); throw mapStripeErrorToHttps( error, "Impossible de récupérer les packs de pièces.", ); } }); module.exports = { listSubscriptionPlans, listCoinPacks, };