Skip to content

dev#886

Merged
johnyeocx merged 3 commits intomainfrom
dev
Mar 5, 2026
Merged

dev#886
johnyeocx merged 3 commits intomainfrom
dev

Conversation

@johnyeocx
Copy link
Collaborator

@johnyeocx johnyeocx commented Mar 5, 2026

Summary by cubic

Improve Stripe billing accuracy and UX by linking upgrade invoices to subscriptions, applying discounts to allocated/overage invoices, and avoiding false past_due transitions. Shorter resume windows and better cache invalidation reduce stale state.

  • New Features

    • Apply Stripe discounts to allocated/overage line items; no extra discount tag when Stripe discounts apply.
    • Create manual invoices with subscription link and metadata; option to skip link in deletion flows.
    • For subscriptions with only consumables, invoice at end of cycle (skip add_invoice_items on create).
    • Shorten metadata resume windows for non-deferred flows to 10 minutes.
  • Bug Fixes

    • Prevent false past_due on upgrade invoices by checking invoice metadata before changing product status.
    • Invalidate cached full customer after invoice.paid and deferred plan execution to avoid stale data.
    • Stabilize invoice and checkout flows in tests; verify invoice product IDs and effective discounts.

Written for commit 8144bc8. Summary will update on new commits.

Greptile Summary

This PR makes several improvements to Autumn's billing engine, primarily targeting correct status tracking for subscription upgrades, proper discount propagation to line items, support for consumable-only subscription invoicing, and customer cache invalidation after billing events.

Key changes:

  • [Bug fixes] Adds handleFalsePositivePastDue logic in syncCustomerProductStatus to prevent Stripe upgrade invoices (tagged with autumn_billing_update metadata) from incorrectly transitioning a customer to past_due status. However, the current check does not verify the invoice was actually paid — a genuine card failure on an Autumn-created upgrade invoice would still be suppressed. See inline comment.

  • [Improvements] Attaches autumn_billing_update and autumn_invoice_mode metadata to all manually created Stripe invoices in createInvoiceForBilling, enabling downstream webhook handlers to distinguish Autumn-initiated invoices from Stripe-cycle invoices.

  • [Improvements] Introduces willStripeSubscriptionInvoiceEndOfCycle to detect when all subscription items are consumable prices. When true, addInvoiceItems is omitted from the subscription create params and a separate manual invoice is created instead (shouldCreateManualStripeInvoice). This properly handles one-off consumable products.

  • [Bug fixes] Adds Stripe discount application to the allocated invoice pipeline (computeAllocatedInvoicePlan) and updates applyAmountOffDiscountToLineItems / applyPercentOffDiscountToLineItems to use the discountable context flag to decide whether to annotate descriptions with a discount tag.

  • [Improvements] Adds deleteCachedFullCustomer calls in executeDeferredBillingPlan and the two legacy handleStripeInvoiceMetadata branches to ensure customer state is evicted from cache after billing events complete.

  • [API changes] processInvoice in InvoiceService now maps invoice.product_ids to the plan_ids field in the ApiInvoiceV1 response (with product_ids commented out). This is a potential breaking change for API consumers relying on product_ids.

  • [Bug fixes] processConsumablePricesForSubscriptionDeleted now detects trial-end cancellations and skips arrear charges, preventing unexpected final invoices for customers whose free trials expired.

Confidence Score: 2/5

  • PR contains a logic gap in the false-positive past_due suppression that could mask genuine payment failures, warranting a fix before merging.
  • The false-positive past_due suppression in syncCustomerProductStatus does not check whether the Autumn-created upgrade invoice was actually paid. If a card is declined on an upgrade invoice, the subscription moves to past_due but the customer would be incorrectly shown as Active. The remaining changes (discount propagation, cache invalidation, consumable invoicing, metadata tagging) are well-structured and low-risk.
  • Pay close attention to server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts — specifically the handleFalsePositivePastDue function. Also review server/src/internal/invoices/InvoiceService.ts for the product_idsplan_ids API field rename.

Important Files Changed

Filename Overview
server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts Adds false-positive past_due suppression, but the metadata check doesn't verify the invoice was actually paid — genuine payment failures on Autumn-created upgrade invoices could be silently masked as Active.
server/src/internal/billing/v2/providers/stripe/utils/subscriptions/willStripeSubscriptionInvoiceEndOfCycle.ts New utility that returns true only when ALL recurring stripe item specs are consumable prices; correctly handles the empty-array edge case by requiring length > 0.
server/src/internal/billing/v2/providers/stripe/utils/invoices/shouldCreateManualStripeInvoice.ts Updated to detect consumable-only create actions needing end-of-cycle invoicing, but control flow falls through to the shared path when isCreateAction is true but willCreateInvoiceEndOfCycle is false, which may be unintentional.
server/src/internal/billing/v2/providers/stripe/utils/invoices/createInvoiceForBilling.ts Adds autumn_billing_update and autumn_invoice_mode metadata to all manually created Stripe invoices; correctly threads discounts and invoice mode through to invoice creation.
server/src/internal/billing/v2/providers/stripe/utils/discounts/applyAmountOffDiscountToLineItems.ts Applies amount_off discounts proportionally across eligible charge line items; uses discountable context to decide whether to tag descriptions. Mathematically sound when chained with percent_off discounts.
server/src/internal/invoices/InvoiceService.ts Renames product_ids to plan_ids in the API response object and conditionally preserves product_ids/internal_product_ids in upsert only when non-empty — the API field rename may be a breaking change for existing clients.
server/src/internal/balances/utils/allocatedInvoice/compute/computeAllocatedInvoicePlan.ts Now applies Stripe discounts to allocated invoice line items when discounts are present on the billing context, completing the discount pipeline for balance-tracked invoices.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Autumn
    participant Stripe
    participant Webhook as Stripe Webhook

    Client->>Autumn: Attach / upgrade plan
    Autumn->>Stripe: Create manual invoice<br/>(metadata: autumn_billing_update=true,<br/>autumn_invoice_mode=false)
    Stripe-->>Autumn: Invoice created

    alt Subscription has consumable-only items
        Autumn->>Stripe: Create subscription<br/>(addInvoiceItems: undefined)
        Autumn->>Stripe: Create separate manual invoice<br/>for one-off line items
    else Normal subscription
        Autumn->>Stripe: Create/update subscription<br/>(addInvoiceItems included)
    end

    Stripe->>Webhook: subscription.updated (status=past_due)
    Webhook->>Stripe: Fetch latest_invoice
    Stripe-->>Webhook: Invoice with metadata

    alt autumn_billing_update=true AND invoice_mode≠true
        Note over Webhook: False-positive suppressed →<br/>status stays Active
    else No autumn metadata or invoice_mode=true
        Note over Webhook: Genuine past_due →<br/>status set to PastDue
    end

    Webhook->>Autumn: Update CusProduct status
    Autumn->>Autumn: deleteCachedFullCustomer
Loading

Comments Outside Diff (2)

  1. General comment

    Leftover commented-out option

    The // skipSubscriptionCreateInvoice?: boolean; line inside the options type definition is dead code. It should either be removed or documented with a TODO explaining why it was kept if it's planned for the future.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: server/src/external/stripe/webhookHandlers/common/upsertAutumnInvoice.ts
    Line: 28-31
    
    Comment:
    **Leftover commented-out option**
    
    The `// skipSubscriptionCreateInvoice?: boolean;` line inside the options type definition is dead code. It should either be removed or documented with a `TODO` explaining why it was kept if it's planned for the future.
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. General comment

    product_ids renamed to plan_ids in API response — verify consumers

    processInvoice now maps invoice.product_ids to plan_ids instead of product_ids in the ApiInvoiceV1 response. The original product_ids field is commented out.

    If any external API consumers depend on product_ids being present in the invoice response, this is a breaking change. Please ensure all SDK/client code that reads product_ids from invoice objects has been updated, or that this field rename is documented in a migration/changelog.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: server/src/internal/invoices/InvoiceService.ts
    Line: 31
    
    Comment:
    **`product_ids` renamed to `plan_ids` in API response — verify consumers**
    
    `processInvoice` now maps `invoice.product_ids` to `plan_ids` instead of `product_ids` in the `ApiInvoiceV1` response. The original `product_ids` field is commented out.
    
    If any external API consumers depend on `product_ids` being present in the invoice response, this is a breaking change. Please ensure all SDK/client code that reads `product_ids` from invoice objects has been updated, or that this field rename is documented in a migration/changelog.
    
    How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 8144bc8

Greptile also left 2 inline comments on this PR.

@johnyeocx johnyeocx requested a review from ay-rod as a code owner March 5, 2026 12:54
@vercel
Copy link

vercel bot commented Mar 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
autumn-vite Building Building Mar 5, 2026 0:54am

Request Review

@johnyeocx johnyeocx merged commit e6bfb6f into main Mar 5, 2026
5 of 10 checks passed
Comment on lines +25 to +53
const handleFalsePositivePastDue = async ({
ctx,
stripeSubscription,
autumnStatus,
}: {
ctx: StripeWebhookContext;
stripeSubscription: ExpandedStripeSubscription;
autumnStatus: CusProductStatus;
}): Promise<CusProductStatus> => {
if (!isStripeSubscriptionPastDue(stripeSubscription)) return autumnStatus;

// const latestInvoice = await get
const latestInvoice = await getStripeInvoice({
stripeClient: ctx.stripeCli,
invoiceId: stripeSubscription.latest_invoice,
expand: [],
});

const metadata = latestInvoice?.metadata;

if (
metadata?.autumn_billing_update &&
metadata?.autumn_invoice_mode !== "true"
) {
return CusProductStatus.Active;
}

return autumnStatus;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False-positive suppression may hide genuine payment failures

The current handleFalsePositivePastDue logic returns CusProductStatus.Active whenever the latest invoice has autumn_billing_update: "true" and autumn_invoice_mode !== "true", regardless of whether the invoice was actually paid.

Consider the scenario:

  1. A customer upgrades their plan → Autumn creates a manual invoice with autumn_billing_update: "true"
  2. The payment fails (card declined) → Stripe marks the subscription as past_due
  3. subscription.updated fires → handleFalsePositivePastDue sees the metadata and returns CusProductStatus.Active
  4. The customer is incorrectly shown as Active despite having a failed payment

The intent is to avoid marking a subscription as past_due when the invoice is an Autumn-initiated upgrade invoice (not a recurring charge failure). However, the check also needs to confirm the invoice was paid. A safe fix would be to also verify the invoice status is "paid":

if (
    metadata?.autumn_billing_update &&
    metadata?.autumn_invoice_mode !== "true" &&
    latestInvoice?.status === "paid"
) {
    return CusProductStatus.Active;
}

This way, if the upgrade invoice itself fails to pay, the genuine past_due status is preserved.

Prompt To Fix With AI
This is a comment left during a code review.
Path: server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts
Line: 25-53

Comment:
**False-positive suppression may hide genuine payment failures**

The current `handleFalsePositivePastDue` logic returns `CusProductStatus.Active` whenever the latest invoice has `autumn_billing_update: "true"` and `autumn_invoice_mode !== "true"`, regardless of whether the invoice was actually paid.

Consider the scenario:
1. A customer upgrades their plan → Autumn creates a manual invoice with `autumn_billing_update: "true"`
2. The payment **fails** (card declined) → Stripe marks the subscription as `past_due`
3. `subscription.updated` fires → `handleFalsePositivePastDue` sees the metadata and returns `CusProductStatus.Active`
4. The customer is incorrectly shown as `Active` despite having a failed payment

The intent is to avoid marking a subscription as `past_due` when the invoice is an Autumn-initiated upgrade invoice (not a recurring charge failure). However, the check also needs to confirm the invoice was paid. A safe fix would be to also verify the invoice status is `"paid"`:

```typescript
if (
    metadata?.autumn_billing_update &&
    metadata?.autumn_invoice_mode !== "true" &&
    latestInvoice?.status === "paid"
) {
    return CusProductStatus.Active;
}
```

This way, if the upgrade invoice itself fails to pay, the genuine `past_due` status is preserved.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 23 to +34
const isCreateAction = stripeSubscriptionAction?.type === "create";
if (isCreateAction) return false;
if (isCreateAction) {
const willCreateInvoiceEndOfCycle = willStripeSubscriptionInvoiceEndOfCycle(
{
ctx,
billingContext,
autumnBillingPlan,
},
);

return willCreateInvoiceEndOfCycle;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Early return when isCreateAction is false

When isCreateAction is true but willCreateInvoiceEndOfCycle is false, the function falls through to the custom line items check and the no-subscription path. This could produce unexpected behavior when a subscription create action exists but no consumable end-of-cycle invoicing is needed — for example, if there are no custom line items and no existing subscription, the function uses lineItems total as the decision, which may or may not be the right default for a create action.

Consider returning early for the create action regardless of willCreateInvoiceEndOfCycle:

if (isCreateAction) {
    const willCreateInvoiceEndOfCycle = willStripeSubscriptionInvoiceEndOfCycle({
        ctx,
        billingContext,
        autumnBillingPlan,
    });

    return willCreateInvoiceEndOfCycle;
    // If false, no manual invoice needed for a create action (subscription creates its own first invoice)
}

If the intent is to also handle custom line items during a create action, that logic should be made explicit rather than falling through to the shared path.

Prompt To Fix With AI
This is a comment left during a code review.
Path: server/src/internal/billing/v2/providers/stripe/utils/invoices/shouldCreateManualStripeInvoice.ts
Line: 23-34

Comment:
**Early return when `isCreateAction` is false**

When `isCreateAction` is `true` but `willCreateInvoiceEndOfCycle` is `false`, the function falls through to the custom line items check and the no-subscription path. This could produce unexpected behavior when a subscription create action exists but no consumable end-of-cycle invoicing is needed — for example, if there are no custom line items and no existing subscription, the function uses `lineItems` total as the decision, which may or may not be the right default for a create action.

Consider returning early for the create action regardless of `willCreateInvoiceEndOfCycle`:

```typescript
if (isCreateAction) {
    const willCreateInvoiceEndOfCycle = willStripeSubscriptionInvoiceEndOfCycle({
        ctx,
        billingContext,
        autumnBillingPlan,
    });

    return willCreateInvoiceEndOfCycle;
    // If false, no manual invoice needed for a create action (subscription creates its own first invoice)
}
```

If the intent is to also handle custom line items during a create action, that logic should be made explicit rather than falling through to the shared path.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 34 files

Confidence score: 2/5

  • There are concrete billing-behavior regressions with fairly high confidence, so merge risk is elevated rather than just cosmetic or cleanup-level.
  • In shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts, dropping the explicit false fallback for discountable can make fixed-price charge lines discountable by default, which can directly change invoice totals.
  • In server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts, missing invoice payment-status validation in handleFalsePositivePastDue can incorrectly treat failed-payment past_due subscriptions as active, creating product-access/revenue leakage risk.
  • Pay close attention to shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts and server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts - both alter core billing/subscription state decisions with user-facing impact.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts">

<violation number="1" location="shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts:37">
P1: This drops the explicit `false` default for `discountable`, allowing `undefined` to flow into `buildLineItem` and changing fixed-price items to default discountable on charge lines. Restore the fallback to avoid unintended discount application behavior.</violation>
</file>

<file name="server/tests/integration/billing/attach/new-plan/attach-recurring-oneoff.test.ts">

<violation number="1" location="server/tests/integration/billing/attach/new-plan/attach-recurring-oneoff.test.ts:291">
P2: The new integration test has no behavioral assertions; it only logs the attach result, so regressions in billing behavior can pass undetected.</violation>
</file>

<file name="server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts">

<violation number="1" location="server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts:46">
P1: Missing invoice payment status check in `handleFalsePositivePastDue` — if an Autumn-initiated upgrade invoice fails to pay (e.g., card declined), Stripe will mark the subscription as `past_due`, but this logic will still override the status to `Active` because it only checks metadata without verifying the invoice was actually paid. This hides genuine payment failures. Add a check for `latestInvoice?.status === "paid"` to the condition.</violation>
</file>

<file name="server/src/internal/billing/v2/providers/stripe/utils/invoices/createInvoiceForBilling.ts">

<violation number="1" location="server/src/internal/billing/v2/providers/stripe/utils/invoices/createInvoiceForBilling.ts:19">
P2: This function duplicates the existing `stripeDiscountsToParams` in `utils/discounts/stripeDiscountsToParams.ts`. Consider reusing that function instead of duplicating the logic here.</violation>
</file>

<file name="server/src/internal/billing/v2/execute/executeDeferredBillingPlan.ts">

<violation number="1" location="server/src/internal/billing/v2/execute/executeDeferredBillingPlan.ts:63">
P2: Cache deletion fails to delete customer data when `customerId` falls back to an empty string.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

const updatedContext: LineItemContext = {
...context,
discountable: context.discountable ?? false,
discountable: context.discountable,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This drops the explicit false default for discountable, allowing undefined to flow into buildLineItem and changing fixed-price items to default discountable on charge lines. Restore the fallback to avoid unintended discount application behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At shared/utils/billingUtils/invoicingUtils/lineItemBuilders/fixedPriceToLineItem.ts, line 37:

<comment>This drops the explicit `false` default for `discountable`, allowing `undefined` to flow into `buildLineItem` and changing fixed-price items to default discountable on charge lines. Restore the fallback to avoid unintended discount application behavior.</comment>

<file context>
@@ -34,7 +34,7 @@ export const fixedPriceToLineItem = ({
 	const updatedContext: LineItemContext = {
 		...context,
-		discountable: context.discountable ?? false,
+		discountable: context.discountable,
 	};
 
</file context>
Suggested change
discountable: context.discountable,
discountable: context.discountable ?? false,
Fix with Cubic

Comment on lines +46 to +47
metadata?.autumn_billing_update &&
metadata?.autumn_invoice_mode !== "true"
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Missing invoice payment status check in handleFalsePositivePastDue — if an Autumn-initiated upgrade invoice fails to pay (e.g., card declined), Stripe will mark the subscription as past_due, but this logic will still override the status to Active because it only checks metadata without verifying the invoice was actually paid. This hides genuine payment failures. Add a check for latestInvoice?.status === "paid" to the condition.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/external/stripe/webhookHandlers/handleStripeSubscriptionUpdated/tasks/syncCustomerProductStatus/syncCustomerProductStatus.ts, line 46:

<comment>Missing invoice payment status check in `handleFalsePositivePastDue` — if an Autumn-initiated upgrade invoice fails to pay (e.g., card declined), Stripe will mark the subscription as `past_due`, but this logic will still override the status to `Active` because it only checks metadata without verifying the invoice was actually paid. This hides genuine payment failures. Add a check for `latestInvoice?.status === "paid"` to the condition.</comment>

<file context>
@@ -16,6 +19,39 @@ import { trackCustomerProductUpdate } from "../../../common/trackCustomerProduct
+	const metadata = latestInvoice?.metadata;
+
+	if (
+		metadata?.autumn_billing_update &&
+		metadata?.autumn_invoice_mode !== "true"
+	) {
</file context>
Suggested change
metadata?.autumn_billing_update &&
metadata?.autumn_invoice_mode !== "true"
metadata?.autumn_billing_update &&
metadata?.autumn_invoice_mode !== "true" &&
latestInvoice?.status === "paid"
Fix with Cubic

product_id: pro.id,
});

console.log("Result:", result);
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new integration test has no behavioral assertions; it only logs the attach result, so regressions in billing behavior can pass undetected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/tests/integration/billing/attach/new-plan/attach-recurring-oneoff.test.ts, line 291:

<comment>The new integration test has no behavioral assertions; it only logs the attach result, so regressions in billing behavior can pass undetected.</comment>

<file context>
@@ -257,3 +257,36 @@ test.concurrent(`${chalk.yellowBright("recurring-oneoff 2: attach with only one-
+		product_id: pro.id,
+	});
+
+	console.log("Result:", result);
+});
</file context>
Fix with Cubic

import { createStripeCli } from "@/external/connect/createStripeCli";
import type { AutumnContext } from "@/honoUtils/HonoEnv";

const stripeDiscountsToInvoiceParams = ({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This function duplicates the existing stripeDiscountsToParams in utils/discounts/stripeDiscountsToParams.ts. Consider reusing that function instead of duplicating the logic here.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/internal/billing/v2/providers/stripe/utils/invoices/createInvoiceForBilling.ts, line 19:

<comment>This function duplicates the existing `stripeDiscountsToParams` in `utils/discounts/stripeDiscountsToParams.ts`. Consider reusing that function instead of duplicating the logic here.</comment>

<file context>
@@ -12,19 +12,35 @@ import {
 import { createStripeCli } from "@/external/connect/createStripeCli";
 import type { AutumnContext } from "@/honoUtils/HonoEnv";
 
+const stripeDiscountsToInvoiceParams = ({
+	stripeDiscounts,
+}: {
</file context>
Fix with Cubic


await deleteCachedFullCustomer({
ctx,
customerId: billingContext.fullCustomer.id ?? "",
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Cache deletion fails to delete customer data when customerId falls back to an empty string.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/internal/billing/v2/execute/executeDeferredBillingPlan.ts, line 63:

<comment>Cache deletion fails to delete customer data when `customerId` falls back to an empty string.</comment>

<file context>
@@ -56,4 +57,10 @@ export const executeDeferredBillingPlan = async ({
+
+	await deleteCachedFullCustomer({
+		ctx,
+		customerId: billingContext.fullCustomer.id ?? "",
+		source: "executeInvoiceDeferredBillingPlan",
+	});
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant