The current plan's card shows the price of its subscription's first item, which can belong to another product #200

Open
opened 2026-10-09 16:01:37 +00:00 by cgalo5758 · 2 comments
Owner

What happens

On the Products page, the card for the tier an organization pays for carries a billing line: ", renews ", or "moves to …" or "ends …" while a change is scheduled. resolveCurrentPlanBilling takes that price from the first current item of the subscription behind the card (GetSubscriptionItemsBySubscriptionID, then items[0]). It never checks which product the item is for.

A subscription can carry more than one item. The console's Checkout creates a subscription with one item, but an edit at Stripe can add another. reconcileItems in internal/fulfillment/reconcile.go records every item Stripe reports and confers each item's product. On such a subscription:

  • When it pays for a tier on each of two ladders, both ladders' current cards show the price of the same item, so one card shows the other tier's price.
  • The query orders items by created_at alone, and the items recorded in one reconcile pass share that time, so the order among them is undefined.

The plan switch already picks the item by product: resolveLadderSubscription in internal/fulfillment/plan_change.go takes the item whose product is the ladder's current tier. A switch on the second ladder therefore reprices that ladder's item, and its card still shows the other item's price.

What should happen

The card shows the price of the subscription's current item for the product the organization holds on that ladder. The row the card reads for the ladder already names that product. When no current item carries the product, the card says its billing is pending, as it does when the items cannot be read.

Where

internal/server/member_plans.go (resolveCurrentPlanBilling)

Steps

  1. From the Products page, subscribe an organization to a paid tier on one ladder.
  2. At Stripe, add to that subscription a price of a product that is a tier on another ladder, and let the subscription reconcile.
  3. Open the Products page. The second ladder's current card shows the first tier's price.

Why it matters

A member sees another product's price presented as what they pay for their plan.

## What happens On the Products page, the card for the tier an organization pays for carries a billing line: "<price>, renews <date>", or "moves to …" or "ends …" while a change is scheduled. `resolveCurrentPlanBilling` takes that price from the first current item of the subscription behind the card (`GetSubscriptionItemsBySubscriptionID`, then `items[0]`). It never checks which product the item is for. A subscription can carry more than one item. The console's Checkout creates a subscription with one item, but an edit at Stripe can add another. `reconcileItems` in `internal/fulfillment/reconcile.go` records every item Stripe reports and confers each item's product. On such a subscription: - When it pays for a tier on each of two ladders, both ladders' current cards show the price of the same item, so one card shows the other tier's price. - The query orders items by `created_at` alone, and the items recorded in one reconcile pass share that time, so the order among them is undefined. The plan switch already picks the item by product: `resolveLadderSubscription` in `internal/fulfillment/plan_change.go` takes the item whose product is the ladder's current tier. A switch on the second ladder therefore reprices that ladder's item, and its card still shows the other item's price. ## What should happen The card shows the price of the subscription's current item for the product the organization holds on that ladder. The row the card reads for the ladder already names that product. When no current item carries the product, the card says its billing is pending, as it does when the items cannot be read. ## Where `internal/server/member_plans.go` (`resolveCurrentPlanBilling`) ## Steps 1. From the Products page, subscribe an organization to a paid tier on one ladder. 2. At Stripe, add to that subscription a price of a product that is a tier on another ladder, and let the subscription reconcile. 3. Open the Products page. The second ladder's current card shows the first tier's price. ## Why it matters A member sees another product's price presented as what they pay for their plan.
cgalo5758 added the
kind
bug
area/billingarea/member-ui
labels 2026-10-09 16:01:37 +00:00
Author
Owner

The same first-item assumption sits in the sweep: a deferred plan switch moves the subscription's oldest current item (items[0] by created_at, with ties undefined), and the environment check before the claim reads that same item, not the item on the ladder the switch names. It is latent while nothing writes commitments.

The same first-item assumption sits in the sweep: a deferred plan switch moves the subscription's oldest current item (`items[0]` by `created_at`, with ties undefined), and the environment check before the claim reads that same item, not the item on the ladder the switch names. It is latent while nothing writes commitments.
Author
Owner

The comment on resolveCurrentPlanBilling (internal/server/member_plans.go:750-753) says a tier an operator issued as a grant has no billing at all. A grant now holds a ladder against a subscription until the grant ends, and the subscription it took the ladder from keeps billing while the card shows the grant's tier with no price line. The card's reading of the provision is right; the comment's claim is not, and it is worth correcting with this fix.

The comment on `resolveCurrentPlanBilling` (`internal/server/member_plans.go:750-753`) says a tier an operator issued as a grant has no billing at all. A grant now holds a ladder against a subscription until the grant ends, and the subscription it took the ladder from keeps billing while the card shows the grant's tier with no price line. The card's reading of the provision is right; the comment's claim is not, and it is worth correcting with this fix.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wiki-cafe/member-console#200