O33 Commerce
O33 Commerce is a B2B commerce platform for wholesale and distribution. It gives a client's customers a self-service ordering channel — catalogue, basket, checkout, order history and account documents — while the client's ERP stays the system of record for pricing, stock, credit and the order itself. It is being built first for FashionBiz, across three countries on Microsoft Dynamics 365 Business Central, and generalised as it goes so that the next client is a configuration exercise rather than a fork.
- Sector B2B wholesale and distribution
- ERP Business Central
- Runs on .NET 10, Azure
- Storefront Angular, and replaceable
Five words this site uses precisely
Two of them are ambiguous everywhere else, and getting them the wrong way round inverts the meaning of most sentences here. These match the names in the code.
| Term | Means here | Does not mean |
|---|---|---|
| Client | The business that runs Commerce. FashionBiz today. | Never a piece of software. A front end is a front end. |
| Customer | A business that buys from the client. Holds the wholesale account, the price list, the credit position, the ship-to addresses. | Not the client. Not one person. |
| User | A person who signs in, acting for a customer, with a role that decides what they may do. | Not the customer — one customer has many users. |
| ERP | The client's system of record. Business Central today, by design not forever. | |
| Region | One complete deployment, with its own database and its own configuration. | Not a tenant. Nothing is shared between regions. |
flowchart LR
ERP["<b>ERP</b><br/>Business Central<br/>· · ·<br/>products · prices · stock<br/>customers · invoices"]
C["<b>O33 Commerce</b><br/>· · ·<br/>catalogue · search · basket<br/>checkout · sessions · content"]
SF["<b>Storefront</b><br/>· · ·<br/>vanilla, themed,<br/>or your own"]
ERP -->|"the data a shop needs"| C
C -->|"the orders it takes"| ERP
C <-->|"HTTP + cookie session"| SF
style ERP fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#1e1b4b
style C fill:#e8f4f9,stroke:#00415a,stroke-width:2px,color:#002230
style SF fill:#fffbeb,stroke:#b45309,stroke-width:2px,color:#451a03
Wholesale rules, not retail rules
A user sees their customer's prices, the brands that customer is entitled to, and its credit position. Entitlement is applied inside the query — so paging and facet counts stay correct, and the sidebar never advertises a brand they cannot buy.
Built for how customers order
Size and colourway grids, bulk entry by SKU, purchase-order numbers, delivery or branch pickup, ordering again from history. The awkward parts of wholesale buying, treated as the normal case.
The ERP stays the system of record
Commerce never becomes a second source of truth for price, stock or credit. It reads what the ERP publishes and hands back orders — which is what stops the next client becoming a second integration project.
Who owns what
The single most useful line in the system. Almost every "where does X live" question resolves here.
ERP owns
- Who the customer is, and their trading terms
- What they pay — price lists, contract pricing
- What stock exists
- What they owe — invoices, credits, the ledger
- The order, once placed
Commerce owns
- Finding a product — search, browse, facets
- The basket, and everything it costs
- The checkout, and taking payment
- Who is signed in, and what they may see
- The content around the catalogue
What it does
Customers, users and entitlement
- Customers, ship-to addresses, trading terms
- Users with roles, invited and provisioned automatically
- Brand-level entitlement, per customer and per user
- All-customers access for the client's own service staff
Pricing and promotions
- Price lists specific to a customer
- Promotions, including buy-X-get-Y and bonus products
- Freight quoting, per country
- Tax, and card surcharges
Discovery at catalogue scale
- Faceted search, typeahead and autocomplete
- Category browse, independent of search
- Variants — colourways and size scales
- Only what the user is entitled to see
Basket and checkout
- A rule set that decides whether a basket may proceed
- Stock reservation held to a single deadline
- Card payment, and on-account, COD or bank transfer
- Bulk entry by SKU for large orders
Orders and account documents
- Order history, with line-level status from the ERP
- Ledger — invoices, credits, what is owed
- Transactional email from editable templates
Integration and administration
- A published inbound contract per data type
- Orders posted to the ERP asynchronously
- Content, settings, locations and promotions, editable live
- Queue and cache visible and replayable
Implementations
| Client | Sector | Regions | Status |
|---|---|---|---|
| FashionBiz | Apparel and workwear wholesale | Australia, New Zealand, Canada | In implementation — test and UAT |
FashionBiz is the first implementation: a replatform of its existing portal, and the codebase the product is being generalised from. Six regional environments are deployed — test and UAT in each of the three countries — and no production release has been made yet.
The working goal is that the second client is a configuration exercise rather than a fork, which is why boundaries here are firmer than one implementation would justify. Where a rule looks strict, the second client is usually the reason.
Note
Each region is a complete deployment with its own database and its own configuration. There is no shared multi-tenant database.
ERP support
Business Central today. The intent is that a different ERP is a new adapter, not a new product — but the two directions are not equally far along, and a consultant should know which is which.
| Direction | How it works | ERP-neutral? |
|---|---|---|
| Inbound — products, prices, stock, customers, ledger | The ERP or its middleware pushes to Commerce's integration API against a published contract | Already neutral Anything that can speak the contract can feed it |
| Outbound — placing an order, fetching a document | Commerce calls Business Central directly through a typed client | BC-specific today Needs a port and a mapper per ERP |
Two things make the outbound side smaller than it sounds. The call is asynchronous — an order is queued and posted by a background handler, so an adapter never sits in a user's checkout. And the pattern is already proven in one place: fetching ledger documents goes through a port with a BC implementation behind it, rather than calling BC inline.
Per-client config Which ERP, its endpoints and its credentials. Product core The integration contract and the queueing behaviour.
Storefront
Commerce is an API with a session. The storefront is a separate application that calls it — which leaves three honest options for an implementation.
| Option | What it means | Good when |
|---|---|---|
| Vanilla | Deploy the reference storefront as it ships | Speed matters and the requirements are conventional |
| Themed | The reference storefront, rebranded and adjusted | The default journey is right, the look is not |
| Bespoke | Build a storefront against the API | The buying journey is itself a differentiator, or an existing site must absorb it |
The reference storefront runs entirely in the browser. It holds no secrets and calls the same API a bespoke storefront would — which is what makes the third option a genuine option rather than a fork: a new storefront is a new caller, not a new backend.
Where to start
| Architecture | How the code is organised, and why that way |
| API surfaces | The four ways in, and how each behaves differently |
| Support and diagnostics | Where to look when something has gone wrong |
| CI/CD | How a change reaches an environment |
| Release notes | What changed, most recent first |
Note
These pages carry what the code cannot tell you — why something exists, what was rejected, and which constraint forced an odd-looking shape. For how a mechanism works, read the code.