Let buyers manage and buy for their company - #214
Conversation
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 ReviewWarning This pull request has 2 commits after the last Strix review ( No security issues found. Updated for Reviewed by Strix |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
|
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.
|
Also carries a build fix: |
Matches the customer's own address book and what the endpoint accepts: a lone label or default flag, without resending the whole address.
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::CompanyMailerhas 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.
AddressManagementtakes 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.mdin the monorepo.