clear last tickets

This commit is contained in:
Thomas Demirdjian
2025-11-25 14:58:06 +01:00
parent 72852ad92b
commit ee9cc5dccd
31 changed files with 1009 additions and 531 deletions
+127 -7
View File
@@ -14,15 +14,11 @@ const {
computeNextGrantTimestamp,
parseCoinsPerMonth,
getSubscriptionMetaFromPrice,
formatSubscriptionForClient,
buildSubscriptionPayload,
resolveUserContext,
upsertPaymentDocument,
} = require("./shared");
const {
SUBSCRIPTION_LEVEL_ALLOWANCES,
PREMIUM_SUBSCRIPTION_STATUSES,
} = require("./constants");
const { PREMIUM_SUBSCRIPTION_STATUSES } = require("./constants");
const handleCheckoutSessionCompleted = async (
session,
@@ -250,7 +246,8 @@ const handleCustomerSubscriptionEvent = async (
const priceMeta = getSubscriptionMetaFromPrice(subscriptionPayload?.priceId);
const metadataLevel = subscription.metadata?.subscriptionLevel || null;
const metadataPeriod = subscription.metadata?.subscriptionBillingPeriod || null;
const metadataPeriod =
subscription.metadata?.subscriptionBillingPeriod || null;
const resolvedLevel = metadataLevel || priceMeta?.level || null;
const resolvedPeriod = metadataPeriod || priceMeta?.billingPeriod || null;
@@ -457,6 +454,126 @@ const handleInvoiceEvent = async (invoice, event, { stripe } = {}) => {
}
await userRef.set(userUpdate, { merge: true });
const subscriptionLine = Array.isArray(invoice?.lines?.data)
? invoice.lines.data.find(
(line) =>
line &&
typeof line === "object" &&
(line.type === "subscription" || line.price),
)
: null;
const priceId =
typeof subscriptionLine?.price?.id === "string"
? subscriptionLine.price.id
: typeof subscriptionLine?.price === "string"
? subscriptionLine.price
: null;
const priceMeta = getSubscriptionMetaFromPrice(priceId) || {};
const billingPeriod =
priceMeta.billingPeriod ||
(subscriptionLine?.price?.recurring?.interval === "year"
? "annual"
: subscriptionLine?.price?.recurring?.interval === "month"
? "monthly"
: null);
const coinsPerMonth =
priceMeta.coinsPerMonth ??
parseCoinsPerMonth(subscriptionLine?.price?.product?.metadata || {}) ??
null;
const coinsToGrant =
billingPeriod === "annual" && typeof coinsPerMonth === "number"
? coinsPerMonth * 12
: null;
const targetSubscriptionId =
resolvedSubscriptionId ||
(typeof invoice.subscription === "string" ? invoice.subscription : null) ||
(typeof subscriptionLine?.subscription === "string"
? subscriptionLine.subscription
: null);
const shouldGrantUpfront =
isInvoicePaid &&
coinsToGrant &&
(billingReason === "subscription_create" ||
billingReason === "subscription_cycle");
if (shouldGrantUpfront && targetSubscriptionId) {
let grantSnapshot = null;
try {
grantSnapshot = await paymentDocRef.get();
} catch (error) {
console.warn(
"[subscription-handleInvoiceEvent] Unable to read payment doc before grant",
invoice?.id || null,
error?.message || error,
);
}
const alreadyGranted =
grantSnapshot?.exists &&
Boolean(grantSnapshot.data()?.subscriptionCoinsGrantedAt);
if (!alreadyGranted) {
const targetUserId = uid || firebaseUid || userRef.id;
const orderId = `subscription_${targetSubscriptionId}_invoice_${invoice.id}`;
try {
const { orderId: processedOrderId } = await createOrderDocument({
userId: targetUserId,
type: ORDER_TYPES.SUBSCRIPTION,
amount: coinsToGrant,
metadata: {
source: "STRIPE_INVOICE",
billingPeriod,
coinsPerMonth,
invoiceId: invoice.id || null,
subscriptionId: targetSubscriptionId,
grantStrategy: "upfront",
},
orderId,
});
await paymentDocRef.set(
{
subscriptionCoinsGrantedAt: getServerTimestamp(),
subscriptionCoinsGrantAmount: coinsToGrant,
subscriptionCoinsGrantOrderId: processedOrderId,
subscriptionCoinsGrantSource: "invoice_upfront",
},
{ merge: true },
);
await userRef.set(
{
subscriptionLastGrantAt: getServerTimestamp(),
subscriptionLastGrantAmount: coinsToGrant,
subscriptionLastGrantOrderId: processedOrderId,
subscriptionLastGrantSource: "invoice_upfront",
subscriptionNextGrantAt: null,
subscriptionGrantInterval: null,
subscriptionGrantStrategy: "upfront",
subscriptionCoinsPerMonth: coinsPerMonth,
},
{ merge: true },
);
} catch (error) {
console.error(
"[subscription-handleInvoiceEvent] Unable to grant upfront subscription coins",
{
invoiceId: invoice?.id || null,
subscriptionId: targetSubscriptionId,
error: error?.message || error,
},
);
}
}
}
};
const handleStripeWebhookEvent = async ({ event, stripe }) => {
@@ -517,7 +634,10 @@ const handleStripeWebhook = onRequest({ region: REGION }, async (req, res) => {
try {
stripe = getStripeClient();
} catch (error) {
console.error("[subscription-handleStripeWebhook] Stripe client error", error);
console.error(
"[subscription-handleStripeWebhook] Stripe client error",
error,
);
res.status(500).send("Client Stripe indisponible");
return;
}