Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3772678
feat: add normalized data model for carts and Medusa.js integration
marcinkrasowski Feb 9, 2026
45e02db
feat: introduce support for customers, payments, and checkout modules
marcinkrasowski Feb 12, 2026
efe4d29
feat: refactor checkout and cart modules with updated field mappings
marcinkrasowski Feb 12, 2026
8f3a81c
feat: localize payment providers and enhance cart module functionality
marcinkrasowski Feb 13, 2026
f350204
feat(integration.medusajs): add extensive test coverage for carts, pr…
marcinkrasowski Feb 13, 2026
0e74310
feat(docs): expand normalized data model with new modules and enhance…
marcinkrasowski Feb 13, 2026
b2c0d84
refactor: improve Medusa.js cart and checkout module handling
marcinkrasowski Feb 16, 2026
0004632
chore(ci): added changesets
marcinkrasowski Feb 16, 2026
27fdc94
refactor: rolled back `customerId` the the one used previously
marcinkrasowski Feb 16, 2026
c556cda
refactor: replace `productId` and `variantId` with `sku` across cart …
marcinkrasowski Feb 16, 2026
986bfb6
refactor: standardize currency handling and improve field mappings ac…
marcinkrasowski Feb 16, 2026
871587a
refactor: add `locale` support to cart models, mappers, and services
marcinkrasowski Feb 16, 2026
c9002b7
refactor: simplify cart item validation in checkout service
marcinkrasowski Feb 16, 2026
f5c7da2
refactor: improve error handling and standardize imports across modules
marcinkrasowski Feb 16, 2026
1bbc3b3
refactor(integrations.medusajs): standardize exception types and impr…
marcinkrasowski Feb 17, 2026
d1c3f49
refactor(integrations.medusajs): remove unused fields and standardize…
marcinkrasowski Feb 17, 2026
fc13c1a
refactor(integrations.medusajs): standardize error handling and excep…
marcinkrasowski Feb 17, 2026
c8fb00c
refactor(integrations.medusajs): centralize `mapAddress` and enhance …
marcinkrasowski Feb 17, 2026
b39c9aa
refactor(scripts): filter out `locale` query param in Postman collect…
marcinkrasowski Feb 17, 2026
30ceeff
Merge remote-tracking branch 'refs/remotes/origin/main' into feat/med…
marcinkrasowski Feb 18, 2026
6fadbea
fix(blocks.product-list): remove permission checks for unauthenticate…
marcinkrasowski Feb 18, 2026
5ac2db8
fix(integrations.medusajs): include `shipping_methods` in cart item f…
marcinkrasowski Feb 18, 2026
359a2e9
fix(integrations.medusajs): include `fields` parameter for cart metho…
marcinkrasowski Feb 18, 2026
4070820
fix(integrations.medusajs): add missing auth token support for Store …
marcinkrasowski Feb 18, 2026
60a4695
fix(integrations.medusajs): handle undefined shipping option prices a…
marcinkrasowski Feb 18, 2026
2a599ba
docs(integrations.medusajs): update Medusa.js integration docs
marcinkrasowski Feb 18, 2026
c3be5b1
fix(integrations.mocked): add missing auth token support for product …
marcinkrasowski Feb 18, 2026
3e3753f
docs(integrations): update integration overviews
marcinkrasowski Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/easy-sides-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@o2s/integrations.medusajs': minor
---

Medusa.js integration implementations for carts, checkout, customers, and payments.
5 changes: 5 additions & 0 deletions .changeset/good-webs-wish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@o2s/blocks.product-list': patch
---

removed permission check from `ProductList` block as it should be accessible also for unauthenticated users
9 changes: 9 additions & 0 deletions .changeset/lucky-sides-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@o2s/framework': minor
---

Added the normalized data model for a cart/checkout system with full CRUD operations for items and promotions:

- Checkout flow supporting address, shipping, and payment setup
- Customer address management for authenticated users
- Payment provider integration and session handling
6 changes: 6 additions & 0 deletions .changeset/red-peaches-strive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@o2s/blocks.product-details': patch
'@o2s/blocks.product-list': patch
---

added missing auth token to products service calls
5 changes: 5 additions & 0 deletions .changeset/silent-bees-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@o2s/integrations.mocked': minor
---

Mock integrations updated with carts/customers/payments/checkout mocks and enhanced product/order handling.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,6 @@ dist
AGENTS.md
CLAUDE.md
agent-os

# Generated files
O2S-API.postman_collection.json
2 changes: 0 additions & 2 deletions apps/api-harmonization/.env.local
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ API_SURVEYJS_BASE_URL=https://api.surveyjs.io/public/v1
MEDUSAJS_BASE_URL=
MEDUSAJS_PUBLISHABLE_API_KEY=
MEDUSAJS_ADMIN_API_KEY=
MEDUSA_VARIANT_SPEC_FIELDS=
PRODUCTS_BASE_PATH=

SEARCH_ARTICLES_INDEX_NAME=mock

Expand Down
8 changes: 8 additions & 0 deletions apps/api-harmonization/src/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import {
BillingAccounts,
CMS,
Cache,
Carts,
Checkout,
Customers,
Invoices,
Notifications,
Orders,
Organizations,
Payments,
Products,
Resources,
Search,
Expand All @@ -32,6 +36,10 @@ export const AppConfig: ApiConfig = {
search: Search.SearchIntegrationConfig,
products: Products.ProductsIntegrationConfig,
orders: Orders.OrdersIntegrationConfig,
carts: Carts.CartsIntegrationConfig,
customers: Customers.CustomersIntegrationConfig,
payments: Payments.PaymentsIntegrationConfig,
checkout: Checkout.CheckoutIntegrationConfig,
auth: Auth.AuthIntegrationConfig,
},
};
12 changes: 12 additions & 0 deletions apps/api-harmonization/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ import {
BillingAccounts,
CMS,
Cache,
Carts,
Checkout,
Customers,
Invoices,
Notifications,
Orders,
Organizations,
Payments,
Products,
Resources,
Search,
Expand Down Expand Up @@ -79,6 +83,10 @@ export const ArticlesBaseModule = Articles.Module.register(AppConfig);
export const SearchBaseModule = Search.Module.register(AppConfig);
export const ProductsBaseModule = Products.Module.register(AppConfig);
export const OrdersBaseModule = Orders.Module.register(AppConfig);
export const CartsBaseModule = Carts.Module.register(AppConfig);
export const CustomersBaseModule = Customers.Module.register(AppConfig);
export const PaymentsBaseModule = Payments.Module.register(AppConfig);
export const CheckoutBaseModule = Checkout.Module.register(AppConfig);
export const AuthModuleBaseModule = AuthModule.Module.register(AppConfig);

@Module({
Expand Down Expand Up @@ -106,6 +114,10 @@ export const AuthModuleBaseModule = AuthModule.Module.register(AppConfig);
SearchBaseModule,
ProductsBaseModule,
OrdersBaseModule,
CartsBaseModule,
CustomersBaseModule,
PaymentsBaseModule,
CheckoutBaseModule,
AuthModuleBaseModule,

PageModule.register(AppConfig),
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/blog/releases/o2s/1.5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ The [Zendesk integration](../../../docs/integrations/tickets/zendesk/overview) n
![zendesk integration](../../../static/img/blog/o2s-zendesk-integration.png)

- You can now create new tickets via the Tickets API. The Zendesk integration implements `createTicket` and forwards requests to the Zendesk API.
- Attachments are supported when creating tickets.
- Custom field mapping is handled by the `ZendeskFieldMapper`. Configure environment variables (e.g., `ZENDESK_DEVICE_NAME_FIELD_ID`) and add corresponding entries in your CMS mappers to display custom field labels in the UI.
- Attachments are supported when creating tickets.
- Custom field mapping is handled by the `ZendeskFieldMapper`. Configure environment variables (e.g., `ZENDESK_DEVICE_NAME_FIELD_ID`) and add corresponding entries in your CMS mappers to display custom field labels in the UI.
- Using our [Survey.js form block](../../../docs/integrations/forms/surveyjs/overview), you can submit custom forms to Zendesk. This gives you full control over form layout (single- or multi-step, splitting fields into sections/columns, and more) independently of Zendesk configuration.

### Dev watch task improvement
Expand Down
8 changes: 4 additions & 4 deletions apps/docs/docs/integrations/articles/zendesk/how-to-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ After configuring the integration, you need to set up environment variables that

Configure the following environment variables in your API Harmonization server:

| Name | Type | Description | Required | Default |
| ------------------- | ------ | ------------------------------------------------------------------------ | -------- | ------- |
| ZENDESK_API_URL | string | Your Zendesk API URL (e.g., `https://your-subdomain.zendesk.com/api/v2`) | yes | - |
| ZENDESK_API_TOKEN | string | Base64-encoded authentication token | yes | - |
| Name | Type | Description | Required | Default |
| ----------------- | ------ | ------------------------------------------------------------------------ | -------- | ------- |
| ZENDESK_API_URL | string | Your Zendesk API URL (e.g., `https://your-subdomain.zendesk.com/api/v2`) | yes | - |
| ZENDESK_API_TOKEN | string | Base64-encoded authentication token | yes | - |

**Important notes:**

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/integrations/articles/zendesk/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 100

# Zendesk

This integration provides the integration with [Zendesk Help Center API](https://developer.zendesk.com/api-reference/help_center/help-center-api/introduction/), allowing users to browse knowledge base articles, categories, and search for content within your application.
this package provides the integration with [Zendesk Help Center API](https://developer.zendesk.com/api-reference/help_center/help-center-api/introduction/), allowing users to browse knowledge base articles, categories, and search for content within your application.

## In this section

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/integrations/cache/redis/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 100

# Redis Cache

This integration provides caching capabilities using [Redis](https://redis.io/). It implements the framework's `Cache.Service` interface and is used by CMS integrations (Strapi, Contentful) to cache pages, components, and configuration.
this package provides caching capabilities using [Redis](https://redis.io/). It implements the framework's `Cache.Service` interface and is used by CMS integrations (Strapi, Contentful) to cache pages, components, and configuration.

## In this section

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/integrations/cms/contentful/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 100

# Contentful CMS

This integration provides a full integration with [Contentful CMS](https://www.contentful.com/), enabling comprehensive content management capabilities for your application. The integration supports content management, page management, and content localization, allowing you to create and manage multilingual content with ease. Additionally, Contentful integration includes built-in support for Live Preview, enabling content editors to see their changes in real-time as they edit content in the Contentful web app.
this package provides a full integration with [Contentful CMS](https://www.contentful.com/), enabling comprehensive content management capabilities for your application. The integration supports content management, page management, and content localization, allowing you to create and manage multilingual content with ease. Additionally, Contentful integration includes built-in support for Live Preview, enabling content editors to see their changes in real-time as they edit content in the Contentful web app.

## In this section

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/integrations/cms/strapi/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 100

# Strapi CMS

This integration provides a full integration with [Strapi CMS](https://strapi.io/), enabling comprehensive content management capabilities for your application. The integration supports content management, page management, and content localization, allowing you to create and manage multilingual content with ease.
this package provides a full integration with [Strapi CMS](https://strapi.io/), enabling comprehensive content management capabilities for your application. The integration supports content management, page management, and content localization, allowing you to create and manage multilingual content with ease.

## In this section

Expand Down
97 changes: 97 additions & 0 deletions apps/docs/docs/integrations/commerce/medusa-js/cart-checkout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
sidebar_position: 400
---

# Cart & Checkout

This document describes the cart lifecycle and checkout process when using the Medusa.js integration. It is intended for developers familiar with O2S who need to understand how the Medusa.js flow maps to the O2S cart and checkout model.

## Understanding MedusaJS Concepts

If you are familiar with O2S but not Medusa, these concepts are essential:

### Regions

Medusa requires a **`region_id`** for every cart. Regions determine:

- **Pricing** — Currency and tax rules
- **Shipping** — Available shipping options
- **Taxes** — Tax calculation for the region

O2S maps `regionId` (in request bodies) to Medusa's `region_id`. You must create regions in Medusa Admin and pass a valid `regionId` when creating carts.

### Variants vs Products

Medusa uses **product variants** for cart line items, not products directly. Each variant has its own ID, SKU, price, and options (size, color, etc.).

- **O2S** uses the `sku` field when adding items to cart.
- **Medusa** expects `variant_id` — the integration maps O2S `sku` to Medusa `variant_id`.
- You must use the **variant ID** from the product catalog (e.g., from `GET /products/:id` response), not the product ID.

### Currency

Medusa expects lowercase currency codes (e.g., `eur`), while O2S typically uses uppercase (e.g., `EUR`). The integration converts automatically. The `DEFAULT_CURRENCY` environment variable is used when currency is not provided.

### Cart Ownership

- **Customer carts** — When a cart is associated with a logged-in customer, the `customerId` is extracted from the SSO token. The integration verifies ownership on cart access; unauthorized access throws `UnauthorizedException`.
- **Guest carts** — Carts created without authentication have no `customerId`. Anyone with the cart ID can access them.

## O2S to MedusaJS Mapping

### Cart Model

The O2S `Cart` model maps to Medusa's `StoreCart`:

| O2S Field | Medusa Field | Notes |
| ---------------- | ----------------- | -------------------------------------------------- |
| `id` | `id` | Cart identifier |
| `customerId` | `customer_id` | Present when cart is linked to a customer |
| `regionId` | `region_id` | Required for Medusa |
| `currency` | `currency_code` | Normalized to uppercase in O2S |
| `items` | `items` | Line items with variant references |
| `subtotal`, `total`, etc. | Calculated by Medusa | Mapped to O2S `Price` objects |
| `shippingAddress`| `shipping_address`| Set via checkout addresses |
| `billingAddress`| `billing_address` | Set via checkout addresses |
| `shippingMethod` | `shipping_methods[0]` | Single shipping method supported |
| `paymentMethod` | `metadata.paymentMethod` | Stored in cart metadata after setPayment |
| `metadata` | `metadata` | Notes stored in `metadata.notes`; payment session ID in `metadata.paymentSessionId` |

### Checkout Flow Mapping

Each O2S checkout step maps to a Medusa operation:

| O2S Step | Medusa Operation |
| ----------------- | ----------------------------------------------------- |
| `setAddresses` | `sdk.store.cart.update()` with `shipping_address`, `billing_address` |
| `setShippingMethod` | `sdk.store.cart.addShippingMethod()` with `option_id` |
| `setPayment` | `sdk.store.payment.initiatePaymentSession()` then store session ID and payment method in cart metadata |
| `placeOrder` | `sdk.store.cart.complete()` — single call creates the order; no separate order creation endpoint |

### Payment Session Storage

After `setPayment`, the integration stores:

- **`cart.metadata.paymentSessionId`** — ID of the created payment session
- **`cart.metadata.paymentMethod`** — Object with `{ id, name, type }` for display

These are used by `getCheckoutSummary` and validated before `placeOrder`.

### Address Handling

- **Saved addresses** — When `shippingAddressId` or `billingAddressId` is provided (authenticated users), the integration fetches the address from the Customers service and maps it to Medusa format via `mapAddressToMedusa()`.
- **Inline addresses** — When `shippingAddress` or `billingAddress` is provided (guests or one-off addresses), the integration maps directly to Medusa format.
- **Single address** — If only one address is provided, it is used for both shipping and billing.

## Important Caveats

| Caveat | Details |
| ------ | ------- |
| **Region required** | `regionId` is required for cart creation. It affects pricing, shipping options, and tax calculation. |
| **Variant ID required** | Use variant ID (from product catalog), not product ID. O2S `sku` expects the variant ID. |
| **Payment session storage** | Payment session ID and payment method are stored in `cart.metadata`. Do not clear metadata when updating cart. |
| **Guest checkout** | Email is required for guest order placement. Provide it in `setAddresses`, `placeOrder`, or `completeCheckout`. |
| **Shipping price calculation** | Options with `price_type=calculated` require a separate API call to `sdk.store.fulfillment.calculate()`. Flat-price options are returned as-is. |
| **Order creation** | Single operation (`cart.complete()`) — no separate order creation endpoint. The order is returned directly from the response. |
| **Cart ownership** | Customer carts verify ownership via SSO token. Unauthorized access throws `UnauthorizedException`. |
| **Unimplemented methods** | `getCartList`, `getCurrentCart`, `deleteCart` are not available due to Store API limitations. |
Loading