From 94aa9a5c47fee94a5d13e358b22d8a9a8bc62c07 Mon Sep 17 00:00:00 2001 From: Patryk Zawadzki Date: Tue, 18 Jun 2024 15:39:25 +0200 Subject: [PATCH 1/4] Structure overhaul - Split documentation into several pages with separate sidebars - Unified the structure somewhat - Removed what looks like accidental commits to the API reference - Got rid of some complex custom sidebar formatting - Dropped giscus and "was this page helpful?" --- docs/api-reference/api-reference.mdx | 1 + docs/api-reference/channels/api.mdx | 460 ----- docs/api-reference/channels/configuration.mdx | 544 ------ docs/api-reference/channels/cookbook.mdx | 544 ------ docs/api-reference/channels/lifecycle.mdx | 20 - docs/api-reference/channels/overview.mdx | 93 - .../channels/troubleshooting.mdx | 544 ------ docs/api-usage/overview.mdx | 5 +- docs/cloud.mdx | 3 +- .../apps/{ => adyen}/adyen-web-drop-in.png | Bin .../app-store/apps/adyen/architecture.mdx | 34 + .../app-store/apps/adyen/configuration.mdx | 69 + .../app-store/apps/adyen/overview.mdx | 30 + .../apps/{adyen.mdx => adyen/storefront.mdx} | 164 +- .../app-store/apps/avatax/architecture.mdx | 1 + .../app-store/apps/avatax/configuration.mdx | 1 + .../app-store/apps/avatax/development.mdx | 5 +- .../app-store/apps/avatax/overview.mdx | 15 +- .../app-store/apps/avatax/tax-codes.mdx | 5 +- .../apps/emails-and-messages/overview.mdx | 3 +- .../apps/emails-and-messages/sendgrid.mdx | 4 +- .../apps/emails-and-messages/smtp.mdx | 4 +- .../emails-and-messages/troubleshooting.mdx | 4 +- docs/developer/app-store/apps/overview.mdx | 23 +- .../app-store/apps/smtp/configuration.mdx | 4 +- .../app-store/apps/smtp/overview.mdx | 3 +- .../app-store/apps/smtp/troubleshooting.mdx | 4 +- .../app-store/legacy-plugins/adyen.mdx | 2 +- docs/developer/app-store/overview.mdx | 2 +- docs/developer/channels/api.mdx | 2 +- docs/developer/channels/configuration.mdx | 6 +- docs/developer/channels/lifecycle.mdx | 7 +- docs/developer/channels/overview.mdx | 2 +- docs/developer/checkout/overview.mdx | 5 +- docs/developer/discounts/overview.mdx | 2 +- docs/developer/export/export-overview.mdx | 1 + docs/developer/index.mdx | 3 + docs/index.mdx | 10 +- docusaurus.config.js | 53 +- package-lock.json | 1724 ++++++++--------- package.json | 11 +- sidebars.js | 345 ++-- src/css/components/api-reference.css | 13 +- src/css/components/menu.css | 72 +- src/theme/DocItem/Footer/index.js | 12 - src/theme/DocItem/Paginator/index.js | 39 - template/api-reference.mdx | 1 + versioned_docs/version-3.x/cloud.mdx | 3 +- .../apps/adyen/adyen-web-drop-in.png | Bin 0 -> 14775 bytes .../app-store/apps/adyen/architecture.mdx | 34 + .../app-store/apps/adyen/configuration.mdx | 69 + .../app-store/apps/adyen/overview.mdx | 30 + .../apps/{adyen.mdx => adyen/storefront.mdx} | 164 +- .../app-store/apps/avatax/architecture.mdx | 1 + .../app-store/apps/avatax/configuration.mdx | 1 + .../app-store/apps/avatax/development.mdx | 5 +- .../app-store/apps/avatax/overview.mdx | 15 +- .../app-store/apps/avatax/tax-codes.mdx | 5 +- .../apps/emails-and-messages/overview.mdx | 3 +- .../apps/emails-and-messages/sendgrid.mdx | 4 +- .../apps/emails-and-messages/smtp.mdx | 4 +- .../emails-and-messages/troubleshooting.mdx | 4 +- .../developer/app-store/apps/overview.mdx | 23 +- .../app-store/apps/smtp/configuration.mdx | 4 +- .../app-store/apps/smtp/overview.mdx | 3 +- .../app-store/apps/smtp/troubleshooting.mdx | 4 +- .../app-store/legacy-plugins/adyen.mdx | 2 +- .../developer/app-store/overview.mdx | 2 +- .../version-3.x/developer/channels/api.mdx | 2 +- .../developer/channels/configuration.mdx | 6 +- .../developer/channels/lifecycle.mdx | 7 +- .../developer/channels/overview.mdx | 2 +- .../developer/checkout/overview.mdx | 5 +- .../developer/discounts/overview.mdx | 2 +- .../developer/export/export-overview.mdx | 1 + .../version-3.x/developer/index.mdx | 3 + .../version-3.x/developer/payments.mdx | 205 ++ .../developer}/saleor-channels-data-model.png | Bin versioned_docs/version-3.x/index.mdx | 1 - versioned_sidebars/version-3.x-sidebars.json | 341 ++-- 80 files changed, 1825 insertions(+), 4029 deletions(-) delete mode 100644 docs/api-reference/channels/api.mdx delete mode 100644 docs/api-reference/channels/configuration.mdx delete mode 100644 docs/api-reference/channels/cookbook.mdx delete mode 100644 docs/api-reference/channels/lifecycle.mdx delete mode 100644 docs/api-reference/channels/overview.mdx delete mode 100644 docs/api-reference/channels/troubleshooting.mdx rename docs/developer/app-store/apps/{ => adyen}/adyen-web-drop-in.png (100%) create mode 100644 docs/developer/app-store/apps/adyen/architecture.mdx create mode 100644 docs/developer/app-store/apps/adyen/configuration.mdx create mode 100644 docs/developer/app-store/apps/adyen/overview.mdx rename docs/developer/app-store/apps/{adyen.mdx => adyen/storefront.mdx} (62%) create mode 100644 docs/developer/index.mdx delete mode 100644 src/theme/DocItem/Footer/index.js delete mode 100644 src/theme/DocItem/Paginator/index.js create mode 100644 versioned_docs/version-3.x/developer/app-store/apps/adyen/adyen-web-drop-in.png create mode 100644 versioned_docs/version-3.x/developer/app-store/apps/adyen/architecture.mdx create mode 100644 versioned_docs/version-3.x/developer/app-store/apps/adyen/configuration.mdx create mode 100644 versioned_docs/version-3.x/developer/app-store/apps/adyen/overview.mdx rename versioned_docs/version-3.x/developer/app-store/apps/{adyen.mdx => adyen/storefront.mdx} (62%) create mode 100644 versioned_docs/version-3.x/developer/index.mdx rename {docs/api-reference/channels => versioned_docs/version-3.x/developer}/saleor-channels-data-model.png (100%) diff --git a/docs/api-reference/api-reference.mdx b/docs/api-reference/api-reference.mdx index b130560e9..8d7b9dcc2 100644 --- a/docs/api-reference/api-reference.mdx +++ b/docs/api-reference/api-reference.mdx @@ -1,4 +1,5 @@ --- +sidebar_position: 1 title: API reference --- diff --git a/docs/api-reference/channels/api.mdx b/docs/api-reference/channels/api.mdx deleted file mode 100644 index ab952aab3..000000000 --- a/docs/api-reference/channels/api.mdx +++ /dev/null @@ -1,460 +0,0 @@ ---- -title: Channels API guide -sidebar_label: API guide ---- - -## API examples - -### Getting channel details - -Use [`channel`](api-reference/channels/queries/channel.mdx) query to get channel details. - -Channel query requires channel ID, but from Saleor 3.6 it can be executed with channel slug too. - -Available fields: - -- `id`: Channel object ID -- `slug`: When using channel-dependant queries, the slug is used to select the right one (for example, when requesting Product details) -- `name`: Channel name -- `isActive`: Flag signalling that the channel is available for shop customers. -- `currencyCode`: Currency code used by the channel. -- `hasOrders`: Returns `true` when there are already created orders using that channel. If that's the only channel using this currency, you won't be able to remove it. -- `defaultCountry`: Default country for the channel. The default country will be used in checkout to determine the stock quantities or calculate taxes when the country was not explicitly provided, either as a query parameter or through a shipping address. -- `warehouses`: Warehouses that are available in the given channel. -- `countries`: List of shippable countries for the channel. -- `availableShippingMethodsPerCountry`: Shipping methods that are available for the channel. -- `stockSettings`: contains all stock-related settings, - e.g. the [allocation strategy](developer/stock-allocation.mdx#allocation-strategies) for the channel. -- `orderSettings`: Channel-specific order settings. - -Request: - -```graphql -query { - channel(slug: "mobile") { - id - slug - name - isActive - currencyCode - hasOrders - defaultCountry { - code - country - } - warehouses { - slug - } - countries { - code - country - } - availableShippingMethodsPerCountry { - countryCode - shippingMethods { - id - name - } - } - stockSettings { - allocationStrategy - } - orderSettings { - allowUnpaidOrders - } - } -} -``` - -Response: - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "slug": "mobile", - "name": "Mobile", - "isActive": false, - "currencyCode": "USD", - "hasOrders": true, - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "warehouses": [ - { - "slug": "oceania" - }, - { - "slug": "europe" - } - ], - "availableShippingMethodsPerCountry": [ - { - "countryCode": "AD", - "shippingMethods": [ - { - "id": "U2hpcHBpbmdNZXRob2Q6Mg==", - "name": "DHL" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6Mw==", - "name": "UPS" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NA==", - "name": "Registered priority" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NQ==", - "name": "DB Schenker" - } - ] - } - // ... more countries - ], - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - }, - "orderSettings": { - "allowUnpaidOrders": false - } - } - } -} -``` - -### Permissions - -Listing channels is allowed only for users with the active [`isStaff`](api-reference/users/objects/user.mdx#userisstaffboolean--) flag. - -You need the `MANAGE_CHANNELS` permission to create, edit, and remove channels. -Changing `ChannelListing` does not require additional permissions. For example, changing Product availability requires only `MANAGE_PRODUCTS` permission. - -Objects with customized per-channel visibility are restricted by channel permissions. -If a user with restricted channel access fetches per-channel objects, only objects from accessible channels will be returned. -You can read more about channel permissions [here](developer/permissions.mdx). - -### Creating a new channel - -You can create a new channel using [`channelCreate`](api-reference/channels/mutations/channel-create.mdx) mutation. -During checkout creation, you can define the allocation strategy. Right now the -two possible options are available: `PRIORITIZE_HIGH_STOCK` and `PRIORITIZE_SORTING_ORDER`, -the `PRIORITIZE_SORTING_ORDER` strategy is used as default. -You can read more about the allocation strategies [`here`](developer/stock-allocation.mdx#allocation-strategies). - -Request: - -```graphql -mutation { - channelCreate( - input: { - currencyCode: "USD" - defaultCountry: US - name: "Mobile" - slug: "mobile" - stockSettings: { allocationStrategy: PRIORITIZE_HIGH_STOCK } - } - ) { - channel { - id - isActive - name - slug - currencyCode - defaultCountry { - code - country - } - stockSettings { - allocationStrategy - } - } - errors { - code - field - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelCreate": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "isActive": false, - "name": "Mobile", - "slug": "mobile", - "currencyCode": "USD", - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - } - }, - "errors": [] - } - } -} -``` - -### Channel list - -Because some of the channels may be considered non-public (for example - a channel for business partners), non-staff users cannot use the [`channels`](api-reference/channels/queries/channels.mdx) query. - -Request: - -```graphql -query { - channels { - name - } -} -``` - -Response: - -```json -{ - "data": { - "channels": [ - { - "name": "Mobile" - }, - { - "name": "Website" - } - ] - } -} -``` - -#### Activate / Deactivate channel - -If you want to make the channel unavailable for customers, you can change its status to `deactivated` using [`channelDeactivate`](api-reference/channels/mutations/channel-deactivate.mdx) mutation: - -```graphql -mutation { - channelDeactivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": false - }, - "channelErrors": [] - } - } -} -``` - -And to reverse the previous operation use the [`channelActivate`](api-reference/channels/mutations/channel-activate.mdx) mutation: - -```graphql -mutation { - channelActivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": true - }, - "channelErrors": [] - } - } -} -``` - -### Reorder warehouses within channels - -The warehouses assigned to the channel can be sorted. The provided order defines the -warehouses' order used in `PRIORITIZE_SORTING_ORDER` -[allocation strategy](developer/stock-allocation.mdx#allocation-strategies). -The `sort_order` in `moves` input represents the new relative position of the item. -So when 1 is provided, the item will be moved one position forward; when -1 - one -position backward. - -Let's assume that we have a `channel` with three warehouses in the following order. - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - } - ] - } - } -} -``` - -To move the `americas` warehouse to the first place and the `europe` warehouse to -third, we can run the following mutation. - -```graphql -mutation { - channelReorderWarehouses( - channelId: "Q2hhbm5lbDox" - moves: [ - { - # move for `americas` warehouse - id: "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==" - sortOrder: -2 - } - { - # move for `europe` warehouse - id: "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==" - sortOrder: 1 - } - ] - ) { - channel { - id - warehouses { - id - slug - } - } - errors { - field - code - message - warehouses - } - } -} -``` - -And as a response, we get: - -```json -{ - "data": { - "channelReorderWarehouses": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - } - ] - }, - "errors": [] - } - } -} -``` - -### Removing a channel - -Channels can be removed only when: - -- There are no orders created in them. -- If there are orders created, `targetChannel` is required. Its currency has to be the same as the channel you are about to delete. All orders will be moved to `targetChannel`. - -[`channelDelete`](api-reference/channels/mutations/channel-delete.mdx) mutation takes [input](api-reference/channels/inputs/channel-delete-input.mdx): - -- `id`: ID of the Channel that will be deleted -- `channelId`: all existing orders will be moved into this channel - -```graphql -channelDelete( - id: ID! - input: ChannelDeleteInput -): ChannelDelete - -input ChannelDeleteInput { - channelId: ID! # ID of the channel to migrate orders from origin channel. -} -``` - -### Errors - -```graphql -type ChannelError { - field: String - message: String - code: ChannelErrorCode! -} - -enum ChannelErrorCode { - ALREADY_EXISTS - GRAPHQL_ERROR - INVALID - NOT_FOUND - REQUIRED - UNIQUE - CHANNEL_TARGET_ID_MUST_BE_DIFFERENT - CHANNELS_CURRENCY_MUST_BE_THE_SAME -} -``` - -[`ChannelErrorCode`](api-reference/channels/enums/channel-error-code.mdx) values: - -- `ALREADY_EXISTS`: Object already exists in the database -- `GRAPHQL_ERROR`: Wrong query -- `INVALID`: Invalid data provided -- `NOT_FOUND`: Could not found object -- `REQUIRED`: Missing required fields -- `UNIQUE`: Provided value for field needs to be unique -- `CHANNEL_TARGET_ID_MUST_BE_DIFFERENT`: Cannot move orders into the channel you want to delete -- `CHANNELS_CURRENCY_MUST_BE_THE_SAME`: Target channel has to have the same currency diff --git a/docs/api-reference/channels/configuration.mdx b/docs/api-reference/channels/configuration.mdx deleted file mode 100644 index f9774e944..000000000 --- a/docs/api-reference/channels/configuration.mdx +++ /dev/null @@ -1,544 +0,0 @@ ---- -title: Channels -sidebar_label: Channels ---- - -## What are sales channels - -Sales channels allow you to model your data across different regions, brands, and business models where data can be customized and shared across different channels. Another way to describe channels is the ability to serve customers and markets differently from a **single backend** instance. - -### Relationships and scope - -Adding a channel creates a wide scope of customization options; below is the degree of customization per entity: - -| Entity | Degree of customization per channel | -| :------------------- | :-------------------------------------------------------------------------------- | -| **Checkout** | Contextualized to a channel to display the appropriate stock, prices, taxes, etc. | -| **Product** | Control visibility, availability, search, publication date | -| **Variants** | Control availability and price | -| **Taxes** | Control calculation methods, gross or net, country exceptions | -| **Vouchers** | Control availability, discount values, rules | -| **Orders** | Contextualized to the channel and required channel permission for access. | -| **Promotions** | Control availability, rules, and pricing | -| **Payment flow** | Settings for authorization, payment conditions, expiration, etc. | -| **Currency** | Channel belongs to a single currency. | -| **Warehouses** | Availability | -| **Permission group** | Assigned to channels to control access to sensitive data | -| **Shipping rates** | Availability, price, order total conditions | -| **Shipping zones** | Availability | - -### How Channels are used - -- **Multiple geographical markets:**. Each market has different prices, taxes, shipping options, stock availability, back-office integrations, etc. - -- **B2B and B2C:** Customer types can map Channels to grant exclusivity of prices and services. - -- **Different Legal Entities:** Businesses that have different legal entities can restrict access to customer and order data per entity - -- **Distribution channels:** Serving physical and online channels - -- **Multi-brand:** Businesses that wish to share customer data, loyalty programs, and products but want separate order data. - -- **A/B testing:** Testing different pricing strategies for product and fulfillment. - -- **External channels:** Create dedicated channels for marketplaces or other sales platforms. - -### Not ideal for - -- Dynamic Currency conversion. Each channel can have a different currency; however, `Checkout` belongs to a single channel, so converting to another channel would not be straightforward. That is because each channel can have different stock, prices, taxes, etc. - -- Customer-specific pricing. Potentially, you could serve customers differently using channels, but note that each channel also adds configuration complexity. See [relationships and scope](#relationships-and-scope) for more details.; - -- Supplier-specific pricing. If you wish to sell a single product at a different price depending on the supplier, using channels would not work because each checkout is scoped to a single channel; you would have to implement price list functionality instead. - -### Channels lifecycle - -Your store will have a default channel that can be deleted, but at least one channel is always required. - -#### Creation - -Channels are assigned to a single currency during creation and can not be changed afterward. - -#### Activation - -Channels can be activated and deactivated, affecting the channel's discoverability by the front end, which can be useful during the configuration phase. - -#### Removal - -You must first migrate the existing orders to a channel with the same currency to remove a channel. - -### Channel access control - -Admin access to order data can be configured on a channel level, this is useful for businesses that have different legal entities that should not have access to each other's data. -Other objects such as products, vouchers, shipping, can belong to multiple channels at once so their permissions are not scoped per channel to avoid complexity. - -### Configuration example - -Here is how configuration of a business with many markets would look like: - -- `EU` channel. Currency: EUR. Warehouse: Germany. Countries: NL, DE, FR, BE, PT, ES, IT, AT -- `IRELAND` channel. Currency: EUR. Warehouse: UK, Germany. Because of higher shipping costs and operational costs, new channel is introduced with higher prices and different stock availability. -- `UK` channel. Currency: GBP. Warehouse: UK. Countries: UK -- `US` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Business operates only in USD in North America and has same product price for all countries, shipping is adjusted per country differently. -- `B2B` wholesale channel. Currency: USD. Warehouse: Germany, US. Countries: JP, KR, AU. Business operates in USD for wholesale customers in Asia and Australia. -- `Sister brand` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Channel for separate storefront selling different line of product under different brand. - -### Data model - -![Channels data model](./saleor-channels-data-model.png) - -## API examples - -### Getting channel details - -Use [`channel`](api-reference/channels/queries/channel.mdx) query to get channel details. - -Channel query requires channel ID, but from Saleor 3.6 it can be executed with channel slug too. - -Available fields: - -- `id`: Channel object ID -- `slug`: When using channel-dependant queries, the slug is used to select the right one (for example, when requesting Product details) -- `name`: Channel name -- `isActive`: Flag signalling that the channel is available for shop customers. -- `currencyCode`: Currency code used by the channel. -- `hasOrders`: Returns `true` when there are already created orders using that channel. If that's the only channel using this currency, you won't be able to remove it. -- `defaultCountry`: Default country for the channel. The default country will be used in checkout to determine the stock quantities or calculate taxes when the country was not explicitly provided, either as a query parameter or through a shipping address. -- `warehouses`: Warehouses that are available in the given channel. -- `countries`: List of shippable countries for the channel. -- `availableShippingMethodsPerCountry`: Shipping methods that are available for the channel. -- `stockSettings`: contains all stock-related settings, - e.g. the [allocation strategy](developer/stock-allocation.mdx#allocation-strategies) for the channel. -- `orderSettings`: Channel-specific order settings. - -Request: - -```graphql -query { - channel(slug: "mobile") { - id - slug - name - isActive - currencyCode - hasOrders - defaultCountry { - code - country - } - warehouses { - slug - } - countries { - code - country - } - availableShippingMethodsPerCountry { - countryCode - shippingMethods { - id - name - } - } - stockSettings { - allocationStrategy - } - orderSettings { - allowUnpaidOrders - } - } -} -``` - -Response: - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "slug": "mobile", - "name": "Mobile", - "isActive": false, - "currencyCode": "USD", - "hasOrders": true, - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "warehouses": [ - { - "slug": "oceania" - }, - { - "slug": "europe" - } - ], - "availableShippingMethodsPerCountry": [ - { - "countryCode": "AD", - "shippingMethods": [ - { - "id": "U2hpcHBpbmdNZXRob2Q6Mg==", - "name": "DHL" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6Mw==", - "name": "UPS" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NA==", - "name": "Registered priority" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NQ==", - "name": "DB Schenker" - } - ] - } - // ... more countries - ], - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - }, - "orderSettings": { - "allowUnpaidOrders": false - } - } - } -} -``` - -### Permissions - -Listing channels is allowed only for users with the active [`isStaff`](api-reference/users/objects/user.mdx#userisstaffboolean--) flag. - -You need the `MANAGE_CHANNELS` permission to create, edit, and remove channels. -Changing `ChannelListing` does not require additional permissions. For example, changing Product availability requires only `MANAGE_PRODUCTS` permission. - -Objects with customized per-channel visibility are restricted by channel permissions. -If a user with restricted channel access fetches per-channel objects, only objects from accessible channels will be returned. -You can read more about channel permissions [here](developer/permissions.mdx). - -### Creating a new channel - -You can create a new channel using [`channelCreate`](api-reference/channels/mutations/channel-create.mdx) mutation. -During checkout creation, you can define the allocation strategy. Right now the -two possible options are available: `PRIORITIZE_HIGH_STOCK` and `PRIORITIZE_SORTING_ORDER`, -the `PRIORITIZE_SORTING_ORDER` strategy is used as default. -You can read more about the allocation strategies [`here`](developer/stock-allocation.mdx#allocation-strategies). - -Request: - -```graphql -mutation { - channelCreate( - input: { - currencyCode: "USD" - defaultCountry: US - name: "Mobile" - slug: "mobile" - stockSettings: { allocationStrategy: PRIORITIZE_HIGH_STOCK } - } - ) { - channel { - id - isActive - name - slug - currencyCode - defaultCountry { - code - country - } - stockSettings { - allocationStrategy - } - } - errors { - code - field - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelCreate": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "isActive": false, - "name": "Mobile", - "slug": "mobile", - "currencyCode": "USD", - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - } - }, - "errors": [] - } - } -} -``` - -### Channel list - -Because some of the channels may be considered non-public (for example - a channel for business partners), non-staff users cannot use the [`channels`](api-reference/channels/queries/channels.mdx) query. - -Request: - -```graphql -query { - channels { - name - } -} -``` - -Response: - -```json -{ - "data": { - "channels": [ - { - "name": "Mobile" - }, - { - "name": "Website" - } - ] - } -} -``` - -#### Activate / Deactivate channel - -If you want to make the channel unavailable for customers, you can change its status to `deactivated` using [`channelDeactivate`](api-reference/channels/mutations/channel-deactivate.mdx) mutation: - -```graphql -mutation { - channelDeactivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": false - }, - "channelErrors": [] - } - } -} -``` - -And to reverse the previous operation use the [`channelActivate`](api-reference/channels/mutations/channel-activate.mdx) mutation: - -```graphql -mutation { - channelActivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": true - }, - "channelErrors": [] - } - } -} -``` - -### Reorder warehouses within channels - -The warehouses assigned to the channel can be sorted. The provided order defines the -warehouses' order used in `PRIORITIZE_SORTING_ORDER` -[allocation strategy](developer/stock-allocation.mdx#allocation-strategies). -The `sort_order` in `moves` input represents the new relative position of the item. -So when 1 is provided, the item will be moved one position forward; when -1 - one -position backward. - -Let's assume that we have a `channel` with three warehouses in the following order. - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - } - ] - } - } -} -``` - -To move the `americas` warehouse to the first place and the `europe` warehouse to -third, we can run the following mutation. - -```graphql -mutation { - channelReorderWarehouses( - channelId: "Q2hhbm5lbDox" - moves: [ - { - # move for `americas` warehouse - id: "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==" - sortOrder: -2 - } - { - # move for `europe` warehouse - id: "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==" - sortOrder: 1 - } - ] - ) { - channel { - id - warehouses { - id - slug - } - } - errors { - field - code - message - warehouses - } - } -} -``` - -And as a response, we get: - -```json -{ - "data": { - "channelReorderWarehouses": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - } - ] - }, - "errors": [] - } - } -} -``` - -### Removing a channel - -Channels can be removed only when: - -- There are no orders created in them. -- If there are orders created, `targetChannel` is required. Its currency has to be the same as the channel you are about to delete. All orders will be moved to `targetChannel`. - -[`channelDelete`](api-reference/channels/mutations/channel-delete.mdx) mutation takes [input](api-reference/channels/inputs/channel-delete-input.mdx): - -- `id`: ID of the Channel that will be deleted -- `channelId`: all existing orders will be moved into this channel - -```graphql -channelDelete( - id: ID! - input: ChannelDeleteInput -): ChannelDelete - -input ChannelDeleteInput { - channelId: ID! # ID of the channel to migrate orders from origin channel. -} -``` - -### Errors - -```graphql -type ChannelError { - field: String - message: String - code: ChannelErrorCode! -} - -enum ChannelErrorCode { - ALREADY_EXISTS - GRAPHQL_ERROR - INVALID - NOT_FOUND - REQUIRED - UNIQUE - CHANNEL_TARGET_ID_MUST_BE_DIFFERENT - CHANNELS_CURRENCY_MUST_BE_THE_SAME -} -``` - -[`ChannelErrorCode`](api-reference/channels/enums/channel-error-code.mdx) values: - -- `ALREADY_EXISTS`: Object already exists in the database -- `GRAPHQL_ERROR`: Wrong query -- `INVALID`: Invalid data provided -- `NOT_FOUND`: Could not found object -- `REQUIRED`: Missing required fields -- `UNIQUE`: Provided value for field needs to be unique -- `CHANNEL_TARGET_ID_MUST_BE_DIFFERENT`: Cannot move orders into the channel you want to delete -- `CHANNELS_CURRENCY_MUST_BE_THE_SAME`: Target channel has to have the same currency diff --git a/docs/api-reference/channels/cookbook.mdx b/docs/api-reference/channels/cookbook.mdx deleted file mode 100644 index 565df3789..000000000 --- a/docs/api-reference/channels/cookbook.mdx +++ /dev/null @@ -1,544 +0,0 @@ ---- -title: Channels cookbook -sidebar_label: Cookbook ---- - -## What are sales channels - -Sales channels allow you to model your data across different regions, brands, and business models where data can be customized and shared across different channels. Another way to describe channels is the ability to serve customers and markets differently from a **single backend** instance. - -### Relationships and scope - -Adding a channel creates a wide scope of customization options; below is the degree of customization per entity: - -| Entity | Degree of customization per channel | -| :------------------- | :-------------------------------------------------------------------------------- | -| **Checkout** | Contextualized to a channel to display the appropriate stock, prices, taxes, etc. | -| **Product** | Control visibility, availability, search, publication date | -| **Variants** | Control availability and price | -| **Taxes** | Control calculation methods, gross or net, country exceptions | -| **Vouchers** | Control availability, discount values, rules | -| **Orders** | Contextualized to the channel and required channel permission for access. | -| **Promotions** | Control availability, rules, and pricing | -| **Payment flow** | Settings for authorization, payment conditions, expiration, etc. | -| **Currency** | Channel belongs to a single currency. | -| **Warehouses** | Availability | -| **Permission group** | Assigned to channels to control access to sensitive data | -| **Shipping rates** | Availability, price, order total conditions | -| **Shipping zones** | Availability | - -### How Channels are used - -- **Multiple geographical markets:**. Each market has different prices, taxes, shipping options, stock availability, back-office integrations, etc. - -- **B2B and B2C:** Customer types can map Channels to grant exclusivity of prices and services. - -- **Different Legal Entities:** Businesses that have different legal entities can restrict access to customer and order data per entity - -- **Distribution channels:** Serving physical and online channels - -- **Multi-brand:** Businesses that wish to share customer data, loyalty programs, and products but want separate order data. - -- **A/B testing:** Testing different pricing strategies for product and fulfillment. - -- **External channels:** Create dedicated channels for marketplaces or other sales platforms. - -### Not ideal for - -- Dynamic Currency conversion. Each channel can have a different currency; however, `Checkout` belongs to a single channel, so converting to another channel would not be straightforward. That is because each channel can have different stock, prices, taxes, etc. - -- Customer-specific pricing. Potentially, you could serve customers differently using channels, but note that each channel also adds configuration complexity. See [relationships and scope](#relationships-and-scope) for more details.; - -- Supplier-specific pricing. If you wish to sell a single product at a different price depending on the supplier, using channels would not work because each checkout is scoped to a single channel; you would have to implement price list functionality instead. - -### Channels lifecycle - -Your store will have a default channel that can be deleted, but at least one channel is always required. - -#### Creation - -Channels are assigned to a single currency during creation and can not be changed afterward. - -#### Activation - -Channels can be activated and deactivated, affecting the channel's discoverability by the front end, which can be useful during the configuration phase. - -#### Removal - -You must first migrate the existing orders to a channel with the same currency to remove a channel. - -### Channel access control - -Admin access to order data can be configured on a channel level, this is useful for businesses that have different legal entities that should not have access to each other's data. -Other objects such as products, vouchers, shipping, can belong to multiple channels at once so their permissions are not scoped per channel to avoid complexity. - -### Configuration example - -Here is how configuration of a business with many markets would look like: - -- `EU` channel. Currency: EUR. Warehouse: Germany. Countries: NL, DE, FR, BE, PT, ES, IT, AT -- `IRELAND` channel. Currency: EUR. Warehouse: UK, Germany. Because of higher shipping costs and operational costs, new channel is introduced with higher prices and different stock availability. -- `UK` channel. Currency: GBP. Warehouse: UK. Countries: UK -- `US` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Business operates only in USD in North America and has same product price for all countries, shipping is adjusted per country differently. -- `B2B` wholesale channel. Currency: USD. Warehouse: Germany, US. Countries: JP, KR, AU. Business operates in USD for wholesale customers in Asia and Australia. -- `Sister brand` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Channel for separate storefront selling different line of product under different brand. - -### Data model - -![Channels data model](./saleor-channels-data-model.png) - -## API examples - -### Getting channel details - -Use [`channel`](api-reference/channels/queries/channel.mdx) query to get channel details. - -Channel query requires channel ID, but from Saleor 3.6 it can be executed with channel slug too. - -Available fields: - -- `id`: Channel object ID -- `slug`: When using channel-dependant queries, the slug is used to select the right one (for example, when requesting Product details) -- `name`: Channel name -- `isActive`: Flag signalling that the channel is available for shop customers. -- `currencyCode`: Currency code used by the channel. -- `hasOrders`: Returns `true` when there are already created orders using that channel. If that's the only channel using this currency, you won't be able to remove it. -- `defaultCountry`: Default country for the channel. The default country will be used in checkout to determine the stock quantities or calculate taxes when the country was not explicitly provided, either as a query parameter or through a shipping address. -- `warehouses`: Warehouses that are available in the given channel. -- `countries`: List of shippable countries for the channel. -- `availableShippingMethodsPerCountry`: Shipping methods that are available for the channel. -- `stockSettings`: contains all stock-related settings, - e.g. the [allocation strategy](developer/stock-allocation.mdx#allocation-strategies) for the channel. -- `orderSettings`: Channel-specific order settings. - -Request: - -```graphql -query { - channel(slug: "mobile") { - id - slug - name - isActive - currencyCode - hasOrders - defaultCountry { - code - country - } - warehouses { - slug - } - countries { - code - country - } - availableShippingMethodsPerCountry { - countryCode - shippingMethods { - id - name - } - } - stockSettings { - allocationStrategy - } - orderSettings { - allowUnpaidOrders - } - } -} -``` - -Response: - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "slug": "mobile", - "name": "Mobile", - "isActive": false, - "currencyCode": "USD", - "hasOrders": true, - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "warehouses": [ - { - "slug": "oceania" - }, - { - "slug": "europe" - } - ], - "availableShippingMethodsPerCountry": [ - { - "countryCode": "AD", - "shippingMethods": [ - { - "id": "U2hpcHBpbmdNZXRob2Q6Mg==", - "name": "DHL" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6Mw==", - "name": "UPS" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NA==", - "name": "Registered priority" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NQ==", - "name": "DB Schenker" - } - ] - } - // ... more countries - ], - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - }, - "orderSettings": { - "allowUnpaidOrders": false - } - } - } -} -``` - -### Permissions - -Listing channels is allowed only for users with the active [`isStaff`](api-reference/users/objects/user.mdx#userisstaffboolean--) flag. - -You need the `MANAGE_CHANNELS` permission to create, edit, and remove channels. -Changing `ChannelListing` does not require additional permissions. For example, changing Product availability requires only `MANAGE_PRODUCTS` permission. - -Objects with customized per-channel visibility are restricted by channel permissions. -If a user with restricted channel access fetches per-channel objects, only objects from accessible channels will be returned. -You can read more about channel permissions [here](developer/permissions.mdx). - -### Creating a new channel - -You can create a new channel using [`channelCreate`](api-reference/channels/mutations/channel-create.mdx) mutation. -During checkout creation, you can define the allocation strategy. Right now the -two possible options are available: `PRIORITIZE_HIGH_STOCK` and `PRIORITIZE_SORTING_ORDER`, -the `PRIORITIZE_SORTING_ORDER` strategy is used as default. -You can read more about the allocation strategies [`here`](developer/stock-allocation.mdx#allocation-strategies). - -Request: - -```graphql -mutation { - channelCreate( - input: { - currencyCode: "USD" - defaultCountry: US - name: "Mobile" - slug: "mobile" - stockSettings: { allocationStrategy: PRIORITIZE_HIGH_STOCK } - } - ) { - channel { - id - isActive - name - slug - currencyCode - defaultCountry { - code - country - } - stockSettings { - allocationStrategy - } - } - errors { - code - field - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelCreate": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "isActive": false, - "name": "Mobile", - "slug": "mobile", - "currencyCode": "USD", - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - } - }, - "errors": [] - } - } -} -``` - -### Channel list - -Because some of the channels may be considered non-public (for example - a channel for business partners), non-staff users cannot use the [`channels`](api-reference/channels/queries/channels.mdx) query. - -Request: - -```graphql -query { - channels { - name - } -} -``` - -Response: - -```json -{ - "data": { - "channels": [ - { - "name": "Mobile" - }, - { - "name": "Website" - } - ] - } -} -``` - -#### Activate / Deactivate channel - -If you want to make the channel unavailable for customers, you can change its status to `deactivated` using [`channelDeactivate`](api-reference/channels/mutations/channel-deactivate.mdx) mutation: - -```graphql -mutation { - channelDeactivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": false - }, - "channelErrors": [] - } - } -} -``` - -And to reverse the previous operation use the [`channelActivate`](api-reference/channels/mutations/channel-activate.mdx) mutation: - -```graphql -mutation { - channelActivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": true - }, - "channelErrors": [] - } - } -} -``` - -### Reorder warehouses within channels - -The warehouses assigned to the channel can be sorted. The provided order defines the -warehouses' order used in `PRIORITIZE_SORTING_ORDER` -[allocation strategy](developer/stock-allocation.mdx#allocation-strategies). -The `sort_order` in `moves` input represents the new relative position of the item. -So when 1 is provided, the item will be moved one position forward; when -1 - one -position backward. - -Let's assume that we have a `channel` with three warehouses in the following order. - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - } - ] - } - } -} -``` - -To move the `americas` warehouse to the first place and the `europe` warehouse to -third, we can run the following mutation. - -```graphql -mutation { - channelReorderWarehouses( - channelId: "Q2hhbm5lbDox" - moves: [ - { - # move for `americas` warehouse - id: "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==" - sortOrder: -2 - } - { - # move for `europe` warehouse - id: "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==" - sortOrder: 1 - } - ] - ) { - channel { - id - warehouses { - id - slug - } - } - errors { - field - code - message - warehouses - } - } -} -``` - -And as a response, we get: - -```json -{ - "data": { - "channelReorderWarehouses": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - } - ] - }, - "errors": [] - } - } -} -``` - -### Removing a channel - -Channels can be removed only when: - -- There are no orders created in them. -- If there are orders created, `targetChannel` is required. Its currency has to be the same as the channel you are about to delete. All orders will be moved to `targetChannel`. - -[`channelDelete`](api-reference/channels/mutations/channel-delete.mdx) mutation takes [input](api-reference/channels/inputs/channel-delete-input.mdx): - -- `id`: ID of the Channel that will be deleted -- `channelId`: all existing orders will be moved into this channel - -```graphql -channelDelete( - id: ID! - input: ChannelDeleteInput -): ChannelDelete - -input ChannelDeleteInput { - channelId: ID! # ID of the channel to migrate orders from origin channel. -} -``` - -### Errors - -```graphql -type ChannelError { - field: String - message: String - code: ChannelErrorCode! -} - -enum ChannelErrorCode { - ALREADY_EXISTS - GRAPHQL_ERROR - INVALID - NOT_FOUND - REQUIRED - UNIQUE - CHANNEL_TARGET_ID_MUST_BE_DIFFERENT - CHANNELS_CURRENCY_MUST_BE_THE_SAME -} -``` - -[`ChannelErrorCode`](api-reference/channels/enums/channel-error-code.mdx) values: - -- `ALREADY_EXISTS`: Object already exists in the database -- `GRAPHQL_ERROR`: Wrong query -- `INVALID`: Invalid data provided -- `NOT_FOUND`: Could not found object -- `REQUIRED`: Missing required fields -- `UNIQUE`: Provided value for field needs to be unique -- `CHANNEL_TARGET_ID_MUST_BE_DIFFERENT`: Cannot move orders into the channel you want to delete -- `CHANNELS_CURRENCY_MUST_BE_THE_SAME`: Target channel has to have the same currency diff --git a/docs/api-reference/channels/lifecycle.mdx b/docs/api-reference/channels/lifecycle.mdx deleted file mode 100644 index fc22dabba..000000000 --- a/docs/api-reference/channels/lifecycle.mdx +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Channels lifecycle -sidebar_label: lifecycle ---- - -### Channels lifecycle - -Your store will have a default channel that can be deleted, but at least one channel is always required. - -#### Creation - -Channels are assigned to a single currency during creation and can not be changed afterward. - -#### Activation - -Channels can be activated and deactivated, affecting the channel's discoverability by the front end, which can be useful during the configuration phase. - -#### Removal - -You must first migrate the existing orders to a channel with the same currency to remove a channel. diff --git a/docs/api-reference/channels/overview.mdx b/docs/api-reference/channels/overview.mdx deleted file mode 100644 index 6964e6320..000000000 --- a/docs/api-reference/channels/overview.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Channels overview -sidebar_label: Overview ---- - -## What are sales channels - -Sales channels allow you to model your data across different regions, brands, and business models where data can be customized and shared across different channels. Another way to describe channels is the ability to serve customers and markets differently from a **single backend** instance. - -### Relationships and scope - -Adding a channel creates a wide scope of customization options; below is the degree of customization per entity: - -| Entity | Degree of customization per channel | -| :------------------- | :-------------------------------------------------------------------------------- | -| **Checkout** | Contextualized to a channel to display the appropriate stock, prices, taxes, etc. | -| **Product** | Control visibility, availability, search, publication date | -| **Variants** | Control availability and price | -| **Taxes** | Control calculation methods, gross or net, country exceptions | -| **Vouchers** | Control availability, discount values, rules | -| **Orders** | Contextualized to the channel and required channel permission for access. | -| **Promotions** | Control availability, rules, and pricing | -| **Payment flow** | Settings for authorization, payment conditions, expiration, etc. | -| **Currency** | Channel belongs to a single currency. | -| **Warehouses** | Availability | -| **Permission group** | Assigned to channels to control access to sensitive data | -| **Shipping rates** | Availability, price, order total conditions | -| **Shipping zones** | Availability | - -### How Channels are used - -- **Multiple geographical markets:**. Each market has different prices, taxes, shipping options, stock availability, back-office integrations, etc. - -- **B2B and B2C:** Customer types can map Channels to grant exclusivity of prices and services. - -- **Different Legal Entities:** Businesses that have different legal entities can restrict access to customer and order data per entity - -- **Distribution channels:** Serving physical and online channels - -- **Multi-brand:** Businesses that wish to share customer data, loyalty programs, and products but want separate order data. - -- **A/B testing:** Testing different pricing strategies for product and fulfillment. - -- **External channels:** Create dedicated channels for marketplaces or other sales platforms. - -### Not ideal for - -- Dynamic Currency conversion. Each channel can have a different currency; however, `Checkout` belongs to a single channel, so converting to another channel would not be straightforward. That is because each channel can have different stock, prices, taxes, etc. - -- Customer-specific pricing. Potentially, you could serve customers differently using channels, but note that each channel also adds configuration complexity. See [relationships and scope](#relationships-and-scope) for more details.; - -- Supplier-specific pricing. If you wish to sell a single product at a different price depending on the supplier, using channels would not work because each checkout is scoped to a single channel; you would have to implement price list functionality instead. - -### Channels lifecycle - -Your store will have a default channel that can be deleted, but at least one channel is always required. - -#### Creation - -Channels are assigned to a single currency during creation and can not be changed afterward. - -#### Activation - -Channels can be activated and deactivated, affecting the channel's discoverability by the front end, which can be useful during the configuration phase. - -#### Removal - -You must first migrate the existing orders to a channel with the same currency to remove a channel. - -### Channel access control - -Admin access to order data can be configured on a channel level, this is useful for businesses that have different legal entities that should not have access to each other's data. -Other objects such as products, vouchers, shipping, can belong to multiple channels at once so their permissions are not scoped per channel to avoid complexity. - -### Configuration example - -Here is how configuration of a business with many markets would look like: - -- `EU` channel. Currency: EUR. Warehouse: Germany. Countries: NL, DE, FR, BE, PT, ES, IT, AT -- `IRELAND` channel. Currency: EUR. Warehouse: UK, Germany. Because of higher shipping costs and operational costs, new channel is introduced with higher prices and different stock availability. -- `UK` channel. Currency: GBP. Warehouse: UK. Countries: UK -- `US` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Business operates only in USD in North America and has same product price for all countries, shipping is adjusted per country differently. -- `B2B` wholesale channel. Currency: USD. Warehouse: Germany, US. Countries: JP, KR, AU. Business operates in USD for wholesale customers in Asia and Australia. -- `Sister brand` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Channel for separate storefront selling different line of product under different brand. - -### Data model - -![Channels data model](./saleor-channels-data-model.png) - -### Channel access control - -Admin access to order data can be configured on a channel level, this is useful for businesses that have different legal entities that should not have access to each other's data. -Other objects such as products, vouchers, shipping, can belong to multiple channels at once so their permissions are not scoped per channel to avoid complexity. diff --git a/docs/api-reference/channels/troubleshooting.mdx b/docs/api-reference/channels/troubleshooting.mdx deleted file mode 100644 index f9774e944..000000000 --- a/docs/api-reference/channels/troubleshooting.mdx +++ /dev/null @@ -1,544 +0,0 @@ ---- -title: Channels -sidebar_label: Channels ---- - -## What are sales channels - -Sales channels allow you to model your data across different regions, brands, and business models where data can be customized and shared across different channels. Another way to describe channels is the ability to serve customers and markets differently from a **single backend** instance. - -### Relationships and scope - -Adding a channel creates a wide scope of customization options; below is the degree of customization per entity: - -| Entity | Degree of customization per channel | -| :------------------- | :-------------------------------------------------------------------------------- | -| **Checkout** | Contextualized to a channel to display the appropriate stock, prices, taxes, etc. | -| **Product** | Control visibility, availability, search, publication date | -| **Variants** | Control availability and price | -| **Taxes** | Control calculation methods, gross or net, country exceptions | -| **Vouchers** | Control availability, discount values, rules | -| **Orders** | Contextualized to the channel and required channel permission for access. | -| **Promotions** | Control availability, rules, and pricing | -| **Payment flow** | Settings for authorization, payment conditions, expiration, etc. | -| **Currency** | Channel belongs to a single currency. | -| **Warehouses** | Availability | -| **Permission group** | Assigned to channels to control access to sensitive data | -| **Shipping rates** | Availability, price, order total conditions | -| **Shipping zones** | Availability | - -### How Channels are used - -- **Multiple geographical markets:**. Each market has different prices, taxes, shipping options, stock availability, back-office integrations, etc. - -- **B2B and B2C:** Customer types can map Channels to grant exclusivity of prices and services. - -- **Different Legal Entities:** Businesses that have different legal entities can restrict access to customer and order data per entity - -- **Distribution channels:** Serving physical and online channels - -- **Multi-brand:** Businesses that wish to share customer data, loyalty programs, and products but want separate order data. - -- **A/B testing:** Testing different pricing strategies for product and fulfillment. - -- **External channels:** Create dedicated channels for marketplaces or other sales platforms. - -### Not ideal for - -- Dynamic Currency conversion. Each channel can have a different currency; however, `Checkout` belongs to a single channel, so converting to another channel would not be straightforward. That is because each channel can have different stock, prices, taxes, etc. - -- Customer-specific pricing. Potentially, you could serve customers differently using channels, but note that each channel also adds configuration complexity. See [relationships and scope](#relationships-and-scope) for more details.; - -- Supplier-specific pricing. If you wish to sell a single product at a different price depending on the supplier, using channels would not work because each checkout is scoped to a single channel; you would have to implement price list functionality instead. - -### Channels lifecycle - -Your store will have a default channel that can be deleted, but at least one channel is always required. - -#### Creation - -Channels are assigned to a single currency during creation and can not be changed afterward. - -#### Activation - -Channels can be activated and deactivated, affecting the channel's discoverability by the front end, which can be useful during the configuration phase. - -#### Removal - -You must first migrate the existing orders to a channel with the same currency to remove a channel. - -### Channel access control - -Admin access to order data can be configured on a channel level, this is useful for businesses that have different legal entities that should not have access to each other's data. -Other objects such as products, vouchers, shipping, can belong to multiple channels at once so their permissions are not scoped per channel to avoid complexity. - -### Configuration example - -Here is how configuration of a business with many markets would look like: - -- `EU` channel. Currency: EUR. Warehouse: Germany. Countries: NL, DE, FR, BE, PT, ES, IT, AT -- `IRELAND` channel. Currency: EUR. Warehouse: UK, Germany. Because of higher shipping costs and operational costs, new channel is introduced with higher prices and different stock availability. -- `UK` channel. Currency: GBP. Warehouse: UK. Countries: UK -- `US` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Business operates only in USD in North America and has same product price for all countries, shipping is adjusted per country differently. -- `B2B` wholesale channel. Currency: USD. Warehouse: Germany, US. Countries: JP, KR, AU. Business operates in USD for wholesale customers in Asia and Australia. -- `Sister brand` channel. Currency: USD. Warehouse: US. Countries: US, CA, MX. Channel for separate storefront selling different line of product under different brand. - -### Data model - -![Channels data model](./saleor-channels-data-model.png) - -## API examples - -### Getting channel details - -Use [`channel`](api-reference/channels/queries/channel.mdx) query to get channel details. - -Channel query requires channel ID, but from Saleor 3.6 it can be executed with channel slug too. - -Available fields: - -- `id`: Channel object ID -- `slug`: When using channel-dependant queries, the slug is used to select the right one (for example, when requesting Product details) -- `name`: Channel name -- `isActive`: Flag signalling that the channel is available for shop customers. -- `currencyCode`: Currency code used by the channel. -- `hasOrders`: Returns `true` when there are already created orders using that channel. If that's the only channel using this currency, you won't be able to remove it. -- `defaultCountry`: Default country for the channel. The default country will be used in checkout to determine the stock quantities or calculate taxes when the country was not explicitly provided, either as a query parameter or through a shipping address. -- `warehouses`: Warehouses that are available in the given channel. -- `countries`: List of shippable countries for the channel. -- `availableShippingMethodsPerCountry`: Shipping methods that are available for the channel. -- `stockSettings`: contains all stock-related settings, - e.g. the [allocation strategy](developer/stock-allocation.mdx#allocation-strategies) for the channel. -- `orderSettings`: Channel-specific order settings. - -Request: - -```graphql -query { - channel(slug: "mobile") { - id - slug - name - isActive - currencyCode - hasOrders - defaultCountry { - code - country - } - warehouses { - slug - } - countries { - code - country - } - availableShippingMethodsPerCountry { - countryCode - shippingMethods { - id - name - } - } - stockSettings { - allocationStrategy - } - orderSettings { - allowUnpaidOrders - } - } -} -``` - -Response: - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "slug": "mobile", - "name": "Mobile", - "isActive": false, - "currencyCode": "USD", - "hasOrders": true, - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "warehouses": [ - { - "slug": "oceania" - }, - { - "slug": "europe" - } - ], - "availableShippingMethodsPerCountry": [ - { - "countryCode": "AD", - "shippingMethods": [ - { - "id": "U2hpcHBpbmdNZXRob2Q6Mg==", - "name": "DHL" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6Mw==", - "name": "UPS" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NA==", - "name": "Registered priority" - }, - { - "id": "U2hpcHBpbmdNZXRob2Q6NQ==", - "name": "DB Schenker" - } - ] - } - // ... more countries - ], - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - }, - "orderSettings": { - "allowUnpaidOrders": false - } - } - } -} -``` - -### Permissions - -Listing channels is allowed only for users with the active [`isStaff`](api-reference/users/objects/user.mdx#userisstaffboolean--) flag. - -You need the `MANAGE_CHANNELS` permission to create, edit, and remove channels. -Changing `ChannelListing` does not require additional permissions. For example, changing Product availability requires only `MANAGE_PRODUCTS` permission. - -Objects with customized per-channel visibility are restricted by channel permissions. -If a user with restricted channel access fetches per-channel objects, only objects from accessible channels will be returned. -You can read more about channel permissions [here](developer/permissions.mdx). - -### Creating a new channel - -You can create a new channel using [`channelCreate`](api-reference/channels/mutations/channel-create.mdx) mutation. -During checkout creation, you can define the allocation strategy. Right now the -two possible options are available: `PRIORITIZE_HIGH_STOCK` and `PRIORITIZE_SORTING_ORDER`, -the `PRIORITIZE_SORTING_ORDER` strategy is used as default. -You can read more about the allocation strategies [`here`](developer/stock-allocation.mdx#allocation-strategies). - -Request: - -```graphql -mutation { - channelCreate( - input: { - currencyCode: "USD" - defaultCountry: US - name: "Mobile" - slug: "mobile" - stockSettings: { allocationStrategy: PRIORITIZE_HIGH_STOCK } - } - ) { - channel { - id - isActive - name - slug - currencyCode - defaultCountry { - code - country - } - stockSettings { - allocationStrategy - } - } - errors { - code - field - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelCreate": { - "channel": { - "id": "Q2hhbm5lbDo0MzM=", - "isActive": false, - "name": "Mobile", - "slug": "mobile", - "currencyCode": "USD", - "defaultCountry": { - "code": "US", - "country": "United States of America" - }, - "stockSettings": { - "allocationStrategy": "PRIORITIZE_HIGH_STOCK" - } - }, - "errors": [] - } - } -} -``` - -### Channel list - -Because some of the channels may be considered non-public (for example - a channel for business partners), non-staff users cannot use the [`channels`](api-reference/channels/queries/channels.mdx) query. - -Request: - -```graphql -query { - channels { - name - } -} -``` - -Response: - -```json -{ - "data": { - "channels": [ - { - "name": "Mobile" - }, - { - "name": "Website" - } - ] - } -} -``` - -#### Activate / Deactivate channel - -If you want to make the channel unavailable for customers, you can change its status to `deactivated` using [`channelDeactivate`](api-reference/channels/mutations/channel-deactivate.mdx) mutation: - -```graphql -mutation { - channelDeactivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": false - }, - "channelErrors": [] - } - } -} -``` - -And to reverse the previous operation use the [`channelActivate`](api-reference/channels/mutations/channel-activate.mdx) mutation: - -```graphql -mutation { - channelActivate(slug: "default-channel") { - channel { - name - isActive - } - errors { - message - } - } -} -``` - -Response: - -```json -{ - "data": { - "channelDeactivate": { - "channel": { - "name": "Facebook", - "isActive": true - }, - "channelErrors": [] - } - } -} -``` - -### Reorder warehouses within channels - -The warehouses assigned to the channel can be sorted. The provided order defines the -warehouses' order used in `PRIORITIZE_SORTING_ORDER` -[allocation strategy](developer/stock-allocation.mdx#allocation-strategies). -The `sort_order` in `moves` input represents the new relative position of the item. -So when 1 is provided, the item will be moved one position forward; when -1 - one -position backward. - -Let's assume that we have a `channel` with three warehouses in the following order. - -```json -{ - "data": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - } - ] - } - } -} -``` - -To move the `americas` warehouse to the first place and the `europe` warehouse to -third, we can run the following mutation. - -```graphql -mutation { - channelReorderWarehouses( - channelId: "Q2hhbm5lbDox" - moves: [ - { - # move for `americas` warehouse - id: "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==" - sortOrder: -2 - } - { - # move for `europe` warehouse - id: "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==" - sortOrder: 1 - } - ] - ) { - channel { - id - warehouses { - id - slug - } - } - errors { - field - code - message - warehouses - } - } -} -``` - -And as a response, we get: - -```json -{ - "data": { - "channelReorderWarehouses": { - "channel": { - "id": "Q2hhbm5lbDox", - "warehouses": [ - { - "id": "V2FyZWhvdXNlOjY4M2FkMzZhLTRmNjktNDI2ZS1iYzUyLTMyZGJiZTQ2NjUyZA==", - "slug": "americas" - }, - { - "id": "V2FyZWhvdXNlOjQwZWY1MTQwLWQ5OTYtNDVlNy04NzUzLTlkZThkMTdhMjg1Yw==", - "slug": "oceania" - }, - { - "id": "V2FyZWhvdXNlOjU1NTZiOWI0LTc1ZTItNGI3YS1hZWM1LTQxOTY4NDA2OGE4OA==", - "slug": "europe" - } - ] - }, - "errors": [] - } - } -} -``` - -### Removing a channel - -Channels can be removed only when: - -- There are no orders created in them. -- If there are orders created, `targetChannel` is required. Its currency has to be the same as the channel you are about to delete. All orders will be moved to `targetChannel`. - -[`channelDelete`](api-reference/channels/mutations/channel-delete.mdx) mutation takes [input](api-reference/channels/inputs/channel-delete-input.mdx): - -- `id`: ID of the Channel that will be deleted -- `channelId`: all existing orders will be moved into this channel - -```graphql -channelDelete( - id: ID! - input: ChannelDeleteInput -): ChannelDelete - -input ChannelDeleteInput { - channelId: ID! # ID of the channel to migrate orders from origin channel. -} -``` - -### Errors - -```graphql -type ChannelError { - field: String - message: String - code: ChannelErrorCode! -} - -enum ChannelErrorCode { - ALREADY_EXISTS - GRAPHQL_ERROR - INVALID - NOT_FOUND - REQUIRED - UNIQUE - CHANNEL_TARGET_ID_MUST_BE_DIFFERENT - CHANNELS_CURRENCY_MUST_BE_THE_SAME -} -``` - -[`ChannelErrorCode`](api-reference/channels/enums/channel-error-code.mdx) values: - -- `ALREADY_EXISTS`: Object already exists in the database -- `GRAPHQL_ERROR`: Wrong query -- `INVALID`: Invalid data provided -- `NOT_FOUND`: Could not found object -- `REQUIRED`: Missing required fields -- `UNIQUE`: Provided value for field needs to be unique -- `CHANNEL_TARGET_ID_MUST_BE_DIFFERENT`: Cannot move orders into the channel you want to delete -- `CHANNELS_CURRENCY_MUST_BE_THE_SAME`: Target channel has to have the same currency diff --git a/docs/api-usage/overview.mdx b/docs/api-usage/overview.mdx index b400e0af1..440c19630 100644 --- a/docs/api-usage/overview.mdx +++ b/docs/api-usage/overview.mdx @@ -1,10 +1,9 @@ --- -title: Overview +title: GraphQL +sidebar_label: Overview sidebar_position: 1 --- -## GraphQL - Saleor is powered by GraphQL. GraphQL is a query language that allows clients to talk to an API server. Unlike REST, it gives the client control over how much or how little data they want to receive about each object and allows relations within the object graph to be traversed easily. To learn more about the GraphQL language and its concepts, see the official [GraphQL website](https://graphql.org/). diff --git a/docs/cloud.mdx b/docs/cloud.mdx index 3ebe5feda..af50b8e6d 100644 --- a/docs/cloud.mdx +++ b/docs/cloud.mdx @@ -1,6 +1,5 @@ --- -title: Overview -sidebar_position: 1 +title: Saleor Cloud --- Saleor is an open-source project which means all of its code is [publicly available](https://github.com/saleor). diff --git a/docs/developer/app-store/apps/adyen-web-drop-in.png b/docs/developer/app-store/apps/adyen/adyen-web-drop-in.png similarity index 100% rename from docs/developer/app-store/apps/adyen-web-drop-in.png rename to docs/developer/app-store/apps/adyen/adyen-web-drop-in.png diff --git a/docs/developer/app-store/apps/adyen/architecture.mdx b/docs/developer/app-store/apps/adyen/architecture.mdx new file mode 100644 index 000000000..e000f20c2 --- /dev/null +++ b/docs/developer/app-store/apps/adyen/architecture.mdx @@ -0,0 +1,34 @@ +--- +sidebar_position: 2 +title: Architecture +--- + +## Webhook events + +The Adyen App implements the following [Saleor sync webhooks related to transactions](developer/extending/webhooks/synchronous-events/transaction.mdx): + +- [`PAYMENT_GATEWAY_INITIALIZE_SESSION`](api-reference/webhooks/enums/webhook-event-type-sync-enum.mdx#webhookeventtypesyncenumpayment_gateway_initialize_session) +- [`TRANSACTION_INITIALIZE_SESSION`](api-reference/webhooks/enums/webhook-event-type-sync-enum.mdx#webhookeventtypesyncenumtransaction_initialize_session) +- [`TRANSACTION_PROCESS_SESSION`](api-reference/webhooks/enums/webhook-event-type-sync-enum.mdx#webhookeventtypesyncenumtransaction_process_session) +- [`TRANSACTION_CHARGE_REQUESTED`](api-reference/webhooks/enums/webhook-event-type-sync-enum.mdx#webhookeventtypesyncenumtransaction_charge_requested) +- [`TRANSACTION_CANCEL_REQUESTED`](api-reference/webhooks/enums/webhook-event-type-sync-enum.mdx#webhookeventtypesyncenumtransaction_cancelation_requested) +- [`TRANSACTION_REFUND_REQUESTED`](api-reference/webhooks/enums/webhook-event-type-sync-enum.mdx#webhookeventtypesyncenumtransaction_refund_requested) + +Furthermore, it's also prepared to handle [async Adyen webhooks](https://docs.adyen.com/development-resources/webhooks). + +The Adyen App follows the flow described in detail in the [Saleor Payment App documentation](developer/payments.mdx#payment-app). + +## Limitations + +This section contains known limitations of this App. + +### Maximum timeout for Adyen calls is 15 seconds + +Saleor synchronous webhooks have a maximum response time limit of 20 seconds. The app restricts the Adyen response time to 15 seconds to allow graceful error handling. +If Adyen surpasses this limit, the App will return a FAILURE status with an appropriate error message (Timeout Error). + +### Maximum timeout for Saleor API calls is 5 seconds + +The app restricts Saleor API response time to 5 seconds for [`TransactionInitializeSession`](developer/extending/webhooks/synchronous-events/transaction.mdx#initialize-transaction-session) and [`TransactionProcessSession`](developer/extending/webhooks/synchronous-events/transaction.mdx#process-transaction-session) subscriptions. If Saleor API surpasses this limit, the App will gracefully continue processing. + +If such timeout happens, the created [`TransactionItem`](api-reference/payments/objects/transaction-item.mdx) will not have the metadata from Adyen on `additionalDetails` object, which includes payment method type, credit card brand, etc. diff --git a/docs/developer/app-store/apps/adyen/configuration.mdx b/docs/developer/app-store/apps/adyen/configuration.mdx new file mode 100644 index 000000000..24d5c859b --- /dev/null +++ b/docs/developer/app-store/apps/adyen/configuration.mdx @@ -0,0 +1,69 @@ +--- +sidebar_position: 3 +title: Configuration +--- + +import Video from "@site/components/Video"; + +For Adyen to appear as [available payment gateway](developer/checkout/finalizing.mdx#listing-available-payment-gateways), you need to [install it in the Saleor Dashboard](developer/app-store/overview.mdx#usage). You must obtain the API key from Adyen and paste it into the Adyen App configuration form. Then, a wizard will guide you through the process of configuring the Adyen App, setting up the webhook to receive notifications from Adyen, generating the HMAC key, and adding allowed origins for the Client Key that's used on your Storefront. + +## Configuring Adyen + +Video introduction to Adyen configuration in Saleor: + +