141 lines
3.9 KiB
JavaScript
141 lines
3.9 KiB
JavaScript
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,
|
|
};
|