Files
calendar/packages/features/ee/billing/api/webhook/_invoice.upcoming.ts
T
sean-brydonGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
7e73d675d7 refactor: improve invoice.upcoming logging and add strategyName to billing strategies (#28143)
- Add strategyName property to ISeatBillingStrategy interface and all implementations
- Log which strategy handled the invoice.upcoming webhook (not just whether it applied)
- Always log strategy result (not just when applied=true) for better observability
- Rename highWaterMarkApplied to strategyApplied since applied covers multiple strategies

Co-Authored-By: unknown <>

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-23 15:57:13 +00:00

45 lines
1.4 KiB
TypeScript

import { getSeatBillingStrategyFactory } from "@calcom/features/ee/billing/di/containers/Billing";
import logger from "@calcom/lib/logger";
import type { SWHMap } from "./__handler";
type Data = SWHMap["invoice.upcoming"]["data"];
const log = logger.getSubLogger({ prefix: ["stripe-webhook-invoice-upcoming"] });
const handler = async (data: Data) => {
const invoice = data.object;
if (!invoice.subscription) {
log.debug("Not a subscription invoice, skipping");
return { success: false, message: "Not a subscription invoice" };
}
const subscriptionId =
typeof invoice.subscription === "string" ? invoice.subscription : invoice.subscription.id;
log.info("Processing invoice.upcoming webhook", {
invoiceId: invoice.id,
subscriptionId,
customerId: typeof invoice.customer === "string" ? invoice.customer : invoice.customer?.id,
});
try {
const factory = getSeatBillingStrategyFactory();
const strategy = await factory.createBySubscriptionId(subscriptionId);
const { applied } = await strategy.onInvoiceUpcoming(subscriptionId);
log.info("invoice.upcoming handled", {
subscriptionId,
strategy: strategy.strategyName,
applied,
});
return { success: true, strategyApplied: applied };
} catch (error) {
log.error("Failed to process invoice.upcoming", { subscriptionId, error });
return { success: false, error: String(error) };
}
};
export default handler;