Skip to content

Let buyers manage and buy for their company - #214

Open
damianlegawiec wants to merge 3 commits into
6-0-devfrom
feat/b2b-purchasing
Open

Let buyers manage and buy for their company#214
damianlegawiec wants to merge 3 commits into
6-0-devfrom
feat/b2b-purchasing

Conversation

@damianlegawiec

Copy link
Copy Markdown
Member

Puts a face on the company self-service the Store API already shipped, and makes checkout aware of who a purchase is for.

Account area — a company section appears for buyers who have standing over one: members with add-by-email (the server decides between a membership and an invitation), pending invitations with revoke, the address book, and the organization's orders across its whole subtree.

The invitation link now works. Spree::CompanyMailer has been linking /account/company-invitation?token=… all along; that page 404'd. It handles both people who arrive there — someone registering (the account is created with the invited address) and someone already signed in, refused plainly if they are signed in as anyone but the invitee.

Checkout knows the buyer's organization. A "buying for" picker sits on the cart as well as checkout, because pricing reads the cart's company — chosen late, the buyer reviews a basket priced for the wrong audience and watches the totals move at the last step. Once a company is named, the address step offers its sites instead of the buyer's personal book: a purchase for the organization ships to the organization, and offering someone's home address beside their employer's invites the mis-click.

One address book component, two owners. AddressManagement takes its mutations as props now, so a company keeps addresses exactly the way a person does — only where the rows live differs.

Needs the matching backend change (spree/spree#TBD): the cart's ownership guard accepted only the buyer's own addresses, so a company address id was silently dropped.

Design: docs/plans/6.0-b2b-storefront-purchasing.md in the monorepo.

A company's members could already do all of this through the Store API —
manage each other, keep an address book, read the organization's orders
— but there was no way to reach any of it, and the invitation email
linked to a page that did not exist.

The account area gains a company section (members with add-by-email,
pending invitations, the address book, the organization's orders) and
the invite link now lands somewhere: a page that registers the invitee
or binds the account they are already signed into, refusing plainly when
that is not the invited address.

Checkout learns who the purchase is for. The picker sits on the cart as
well, because pricing reads the cart's company — chosen late, the buyer
reviews a basket priced for the wrong audience. Once a company is named,
the address step offers its sites instead of the buyer's own: a purchase
for the organization ships to the organization.

The address book itself is the shopper's component with its mutations
injected — a company keeps addresses the same way a person does, and
only where the rows live differs.
@strix-security

strix-security Bot commented Aug 26, 2026

Copy link
Copy Markdown

Strix Security Review

Warning

This pull request has 2 commits after the last Strix review (b57ab2e). Strix has not reviewed these changes.
Automatic review on push is off for this repository. To review the latest changes, tag @strix-security in a comment, or turn on re-review on push.

No security issues found.

Updated for b57ab2e.


Reviewed by Strix
Re-run review · Configure security review settings

@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
storefront Error Error Aug 26, 2026 2:34pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c9fcf3d9-04ee-42f5-b50b-05e63a0eff67

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@damianlegawiec

Copy link
Copy Markdown
Member Author

Backend half: spree/spree#14498 — without it the cart silently drops a company address id.

The build has been failing on 6-0-dev: the Store API renamed an
address's country field to country_code, and the storefront still sent
country_iso, which is now a read-only alias.

Fixed at the boundary rather than through the flow. formDataToAddress is
the one place form state becomes API params, so the form keeps the names
the checkout components have always used and only the conversion knows
about the rename. Express checkout builds its params directly, so those
two call sites are renamed as well.
@damianlegawiec

Copy link
Copy Markdown
Member Author

Also carries a build fix: 6-0-dev has been failing type checking since the Store API renamed an address's country field to country_code — the storefront still sent country_iso, now a read-only alias. Fixed at formDataToAddress, the one place form state becomes API params, so the checkout components keep their existing field names. Typecheck goes from 7 errors to 0.

Matches the customer's own address book and what the endpoint accepts: a
lone label or default flag, without resending the whole address.
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