Problem/Motivation

Since #3629242: Let subscribers choose a plan, not a connector: list plans in the subscribe flow and preselect the plan in redirectToSubscribe() a plan has one price in one currency (PlanPrice), so a site selling the same tier in CAD and USD has two plans per tier. The chooser lists every shown plan, so such a visitor sees both variants of every tier in every group — twice the rows, half of them irrelevant — with nothing but the price label to tell them apart. A site cannot fix this with ordering alone, and hiding one variant per visitor is not something a plan's Show flag can express.

Proposed resolution

  • Derived, not configured. The chooser already asks each plan's connector for its price. Collect the distinct currencies of the shown, priced plans; when there are two or more, the chooser gains a currency switcher. One currency, or none (no connector implements PlanPricingConnectorInterface): nothing appears and nothing changes. No new setting.
  • One switcher for the page, filtering every group. A single <select> of the currencies sits above all the groups, the current one selected, and nothing per connector. It has no submit button: choosing an entry reloads the page with that currency (a small library attached by the chooser navigates to ?currency=CAD on change). Without JavaScript it degrades to a GET form with a plain Apply button that the library hides, so the page still works. With a currency chosen, every group lists only its plans priced in that currency; plans without a price are always listed, since they cannot be excluded on a currency they do not state. The switcher never reorders groups or changes which one is open: the default-connector steering of #3629242: Let subscribers choose a plan, not a connector: list plans in the subscribe flow and preselect the plan in redirectToSubscribe() is untouched. A group left with no plans is still shown (collapsed, with a "No plans in CUR" line), so a connector does not silently vanish.
  • Default and memory. The default is the currency of the subscriber's current plan when they have one, else the currency of the first priced plan in the default connector's group. A chosen currency is remembered in user data (subscription_manager module, key currency) and used on later visits without the query parameter; subscribers are always logged in, so no cookie is needed. An invalid or unknown ?currency= falls back to the default.
  • Direct hand-offs are unaffected. ?connector=&plan= still names a plan outright; the single-plan short-cut counts plans across all currencies, as now (a site with a CAD plan and a USD plan has two plans, and gets the chooser with the switcher).
  • API. The chooser shape of api/subscribe-url gains currencies (the distinct list, in the order offered) and currency (the one applied); ?currency= filters its plans[] the same way and is remembered the same way. Front ends that want all plans at once pass ?currency=all, which is also accepted by the page.
  • Cache. The chooser adds url.query_args:currency; the remembered choice is per user, which the existing user context covers.
  • Plan switching. #3629796: Let a charge-based subscriber switch plans on the native management page, upgrading now and downgrading at period end's in-page list should offer only plans in the subscription's currency, which this issue's currency grouping makes a one-line filter; the engine's proration assumes one currency per subscription.

Remaining tasks

  • Design pass: where the switcher sits in subscription-manager-plan-chooser.html.twig (new currencies and currency variables, so themes already overriding the template keep working); whether the switcher is a render-array form element passed to the template or markup the template builds, given that the chooser is a plain theme hook rather than a form; whether the empty-group line is wanted or the group should hide; whether ?currency=all is worth having on the page.
  • Implementation in PlanChooser (currency collection, filter, default) with Kernel tests (one currency: no switcher; two: switcher, filter, unpriced plans kept, default from the current plan, memory in user data, invalid values, API fields) and a browser test for the links.
  • Change record (additive: template variables, API fields, query parameter; no connector impact).

User interface changes

A currency drop-down above the plan chooser's groups, reloading the list on selection, only when the shown plans are priced in more than one currency.

API changes

api/subscribe-url's chooser shape gains currencies and currency and honours ?currency=. Two new template variables and a small JavaScript library. No connector interface changes.

Data model changes

None. The remembered currency lives in user data.

Comments

colan created an issue.