diff --git a/packages/core/docs/.vuepress/config.js b/packages/core/docs/.vuepress/config.js index f3dd707265b..968d80bfda7 100644 --- a/packages/core/docs/.vuepress/config.js +++ b/packages/core/docs/.vuepress/config.js @@ -68,7 +68,11 @@ module.exports = { ['/commercetools/composables/use-facet', 'useFacet'], ['/commercetools/composables/use-cart', 'useCart'], ['/commercetools/composables/use-wishlist', 'useWishlist'], - ['/commercetools/composables/use-category', 'useCategory'] + ['/commercetools/composables/use-category', 'useCategory'], + ['/commercetools/composables/use-shipping', 'useShipping'], + ['/commercetools/composables/use-shipping-provider', 'useShippingProvider'], + ['/commercetools/composables/use-billing', 'useBilling'], + ['/commercetools/composables/use-make-order', 'useMakeOrder'] ] }, { @@ -166,7 +170,8 @@ module.exports = { ['/guide/configuration', 'Configuration'], ['/guide/composables', 'Composables'], ['/guide/authentication', 'Authentication'], - ['/guide/user-profile', 'User profile'] + ['/guide/user-profile', 'User profile'], + ['/guide/checkout', 'Checkout'] ] }, { diff --git a/packages/core/docs/commercetools/composables/use-billing.md b/packages/core/docs/commercetools/composables/use-billing.md new file mode 100644 index 00000000000..a6333b42e4d --- /dev/null +++ b/packages/core/docs/commercetools/composables/use-billing.md @@ -0,0 +1,82 @@ +# `useBilling` + +## Features + +`useBilling` composable can be used for: + +* Loading billing address for the current cart. +* Saving billing address for the current cart. + +## API + +- `load` - function for fetching billing address. When invoked, it requests data from the API and populates `billing` property. This method accepts a single optional `params` object. The `params` has the following option: + + - `customQuery?: CustomQuery` + +- `save` - function for saving billing address. This method accepts a single `saveParams` object. The `saveParams` has the following options: + + - `billingDetails: Address` + + - `customQuery?: CustomQuery` + +```ts +type Address = { + __typename?: "Address"; + id?: Maybe; + title?: Maybe; + salutation?: Maybe; + firstName?: Maybe; + lastName?: Maybe; + streetName?: Maybe; + streetNumber?: Maybe; + additionalStreetInfo?: Maybe; + postalCode?: Maybe; + city?: Maybe; + region?: Maybe; + state?: Maybe; + country: Scalars["Country"]; + company?: Maybe; + department?: Maybe; + building?: Maybe; + apartment?: Maybe; + pOBox?: Maybe; + contactInfo: AddressContactInfo; + phone?: Maybe; + email?: Maybe; + additionalAddressInfo?: Maybe; + externalId?: Maybe; + key?: Maybe; +}; +type CustomQuery = Record +``` +- `billing: Address` - a main data object that contains a billing address. +- `loading: boolean` - a reactive object containing information about loading state of your `load` or `save` method. +- `error: UseBillingErrors` - a reactive object containing the error message, if `load` or `save` failed for any reason. +```ts +interface UseBillingErrors { + load?: Error; + save?: Error; +} +``` + +## Getters + +We do not provide getters for checkout and its parts. + +## Example + +```js +import { useBilling } from '@vue-storefront/commercetools'; +import { onSSR } from '@vue-storefront/core' +export default { + setup () { + const { load, billing } = useBilling(); + onSSR(async () => { + await load(); + }); + return { + billing + }; + } +} +``` diff --git a/packages/core/docs/commercetools/composables/use-make-order.md b/packages/core/docs/commercetools/composables/use-make-order.md new file mode 100644 index 00000000000..6d2688469f7 --- /dev/null +++ b/packages/core/docs/commercetools/composables/use-make-order.md @@ -0,0 +1,103 @@ +# `useMakeOrder` + +## Features + +`useMakeOrder` composable is responsible for making an order + +## API + +- `make` - function for making an order. This method accepts a single optional `params` object. The `params` has the following option: + + - `customQuery?: CustomQuery` + +```ts +type CustomQuery = Record +``` +- `order: Order` - a main data object that contains a made order. +```ts +type Order = Versioned & { + __typename?: "Order"; + customerId?: Maybe; + customer?: Maybe; + customerEmail?: Maybe; + anonymousId?: Maybe; + lineItems: Array; + customLineItems: Array; + totalPrice: Money; + taxedPrice?: Maybe; + shippingAddress?: Maybe
; + billingAddress?: Maybe
; + inventoryMode: InventoryMode; + taxMode: TaxMode; + taxRoundingMode: RoundingMode; + taxCalculationMode: TaxCalculationMode; + customerGroup?: Maybe; + customerGroupRef?: Maybe; + country?: Maybe; + shippingInfo?: Maybe; + discountCodes: Array; + refusedGifts: Array; + refusedGiftsRefs: Array; + paymentInfo?: Maybe; + locale?: Maybe; + shippingRateInput?: Maybe; + origin: CartOrigin; + storeRef?: Maybe; + store?: Maybe; + itemShippingAddresses: Array
; + completedAt?: Maybe; + orderNumber?: Maybe; + orderState: OrderState; + stateRef?: Maybe; + state?: Maybe; + shipmentState?: Maybe; + paymentState?: Maybe; + syncInfo: Array; + returnInfo: Array; + lastMessageSequenceNumber: Scalars["Long"]; + cartRef?: Maybe; + cart?: Maybe; + /** This field contains non-typed data. Consider using `customFields` as a typed alternative. */ + customFieldsRaw?: Maybe>; + /** This field would contain type data */ + customFields?: Maybe; + custom?: Maybe; + id: Scalars["String"]; + version: Scalars["Long"]; + createdAt: Scalars["DateTime"]; + lastModifiedAt: Scalars["DateTime"]; + createdBy?: Maybe; + lastModifiedBy?: Maybe; + /** Custom fields are returned as a list instead of an object structure. */ + customFieldList?: Maybe>; +}; +``` + +- `loading: boolean` - a reactive object containing information about loading state of your `make` method. + +- `error: UseMakeOrderErrors` - a reactive object containing the error message, if `load` or `save` failed for any reason. + +```ts +interface UseMakeOrderErrors { + make?: Error; +} +``` + +## Getters + +We do not provide getters for checkout and its parts. + +## Example + +```js +import { useMakeOrder } from '@vue-storefront/commercetools'; +export default { + setup () { + const { make, order } = useMakeOrder(); + return { + make, + order + }; + } +} +``` \ No newline at end of file diff --git a/packages/core/docs/commercetools/composables/use-shipping-provider.md b/packages/core/docs/commercetools/composables/use-shipping-provider.md new file mode 100644 index 00000000000..849ad4f2c15 --- /dev/null +++ b/packages/core/docs/commercetools/composables/use-shipping-provider.md @@ -0,0 +1,100 @@ +# `useShippingProvider` + +## Features + +`useShippingProvider` composable can be used for: + +* Loading shipping methods for the current cart. +* Selecting shipping method for the current cart. + +## API + +- `load` - function for fetching shipping method. When invoked, it requests data from the API and populates the `response` key inside the `state` property. This method accepts a single optional `params` object. The `params` has the following option: + + - `customQuery?: CustomQuery` + +- `save` - function for selecting shipping method. This method accepts a single `saveParams` object. The `saveParams` has the following options: + + - `shippingMethod: ShippingMethod` + + - `customQuery?: CustomQuery` + +```ts +type ShippingMethod = Versioned & { + __typename?: "ShippingMethod"; + id: Scalars["String"]; + version: Scalars["Long"]; + name: Scalars["String"]; + description?: Maybe; + zoneRates: Array; + isDefault: Scalars["Boolean"]; + predicate?: Maybe; + createdAt: Scalars["DateTime"]; + lastModifiedAt: Scalars["DateTime"]; + key?: Maybe; + lastModifiedBy?: Maybe; + createdBy?: Maybe; + taxCategoryRef?: Maybe; + taxCategory?: Maybe; +}; + +type CustomQuery = Record +``` +- `state: ShippingProviderState` - a main data object that contains a shipping method +```ts +interface ShippingProviderState { + response: ShippingInfo +} + +type ShippingInfo = { + __typename?: "ShippingInfo"; + shippingMethodName: Scalars["String"]; + price: Money; + shippingRate: ShippingRate; + taxRate?: Maybe; + taxCategory?: Maybe; + deliveries: Array; + discountedPrice?: Maybe; + taxedPrice?: Maybe; + shippingMethodState: ShippingMethodState; + shippingMethod?: Maybe; + shippingMethodRef?: Maybe; +}; +``` + +- `loading: boolean` - a reactive object containing information about loading state of your `load` or `save` method. + +- `error: UseShippingProviderErrors` - a reactive object containing the error message, if `load` or `save` failed for any reason. + +```ts +interface UseShippingProviderErrors { + load?: Error; + save?: Error; +} +``` + +## Getters + +We do not provide getters for checkout and its parts. + +## Example + +```js +import { useShippingProvider } from '@vue-storefront/commercetools'; +import { onSSR } from '@vue-storefront/core'; +import { computed } from '@vue/composition-api'; + +export default { + setup () { + const { load, state } = useShippingProvider(); + + onSSR(async () => { + await load(); + }); + + return { + selectedShippingMethod: computed(() => state.value && state.value.response) + }; + } +} +``` diff --git a/packages/core/docs/commercetools/composables/use-shipping.md b/packages/core/docs/commercetools/composables/use-shipping.md new file mode 100644 index 00000000000..85e917039b1 --- /dev/null +++ b/packages/core/docs/commercetools/composables/use-shipping.md @@ -0,0 +1,89 @@ +# `useShipping` + +## Features + +`useShipping` composable can be used for: + +* Loading shipping address for the current cart. +* Saving shipping address for the current cart. + +## API + +- `load` - function for fetching shipping address. When invoked, it requests data from the API and populates `shipping` property. This method accepts a single optional `params` object. The `params` has the following option: + + - `customQuery?: CustomQuery` + +- `save` - function for saving shipping address. This method accepts a single `saveParams` object. The `saveParams` has the following options: + + - `shippingDetails: Address` + + - `customQuery?: CustomQuery` + +```ts +type Address = { + __typename?: "Address"; + id?: Maybe; + title?: Maybe; + salutation?: Maybe; + firstName?: Maybe; + lastName?: Maybe; + streetName?: Maybe; + streetNumber?: Maybe; + additionalStreetInfo?: Maybe; + postalCode?: Maybe; + city?: Maybe; + region?: Maybe; + state?: Maybe; + country: Scalars["Country"]; + company?: Maybe; + department?: Maybe; + building?: Maybe; + apartment?: Maybe; + pOBox?: Maybe; + contactInfo: AddressContactInfo; + phone?: Maybe; + email?: Maybe; + additionalAddressInfo?: Maybe; + externalId?: Maybe; + key?: Maybe; +}; + +type CustomQuery = Record +``` +- `shipping: Address` - a main data object that contains a shipping address. + +- `loading: boolean` - a reactive object containing information about loading state of your `load` or `save` method. + +- `error: UseShippingErrors` - a reactive object containing the error message, if `load` or `save` failed for any reason. + +```ts +interface UseShippingErrors { + load?: Error; + save?: Error; +} +``` + +## Getters + +We do not provide getters for checkout and its parts. + +## Example + +```js +import { useShipping } from '@vue-storefront/commercetools'; +import { onSSR } from '@vue-storefront/core'; + +export default { + setup () { + const { load, shipping } = useShipping(); + + onSSR(async () => { + await load(); + }); + + return { + shipping + }; + } +} +``` diff --git a/packages/core/docs/commercetools/feature-list.md b/packages/core/docs/commercetools/feature-list.md index d233aa0a872..c8073d95100 100644 --- a/packages/core/docs/commercetools/feature-list.md +++ b/packages/core/docs/commercetools/feature-list.md @@ -85,17 +85,14 @@ - Remove product from wishlist ## Checkout -- Personal Details - - Fill in name - - Fill in surname - - Fill in email - - Create a new account from provided data by setting up a password - - Use saved personal details (logged in) - - Open log in modal (not logged in) - Shipping - Choose from saved shipping addresses (logged in) - Add new shipping address (logged in) - Change default shipping address (logged in) +- Billing + - Choose from saved billing addresses (logged in) + - Add new billing address (logged in) + - Change default billing address (logged in) - Payment - Review - Order summary diff --git a/packages/core/docs/enterprise/feature-list.md b/packages/core/docs/enterprise/feature-list.md index 19688c863bf..9bfa3d88896 100644 --- a/packages/core/docs/enterprise/feature-list.md +++ b/packages/core/docs/enterprise/feature-list.md @@ -177,13 +177,6 @@ Vue Storefront is the only truly Open Source eCommerce frontend framework with a - Order types - Logged in - Guest -- Personal Details - - Fill in name - - Fill in surname - - Fill in email - - Create a new account from provided data by setting up a password - - Use saved personal details (logged in) - - Open log in modal (not logged in) - Shipping - Choose from saved shipping addresses (logged in) - Add new shipping address (logged in) @@ -192,6 +185,14 @@ Vue Storefront is the only truly Open Source eCommerce frontend framework with a - Fill in First and Last Name - Fill in Street name and apartment number - Fill in City and Zip Code +- Billing + - Choose from saved billing addresses (logged in) + - Add new billing address (logged in) + - Change default billing address (logged in) + - Provide Billing Details + - Fill in First and Last Name + - Fill in Street name and apartment number + - Fill in City and Zip Code - Payment - Choose Payment Method - Coupons diff --git a/packages/core/docs/guide/checkout.md b/packages/core/docs/guide/checkout.md new file mode 100644 index 00000000000..b481f2dda7d --- /dev/null +++ b/packages/core/docs/guide/checkout.md @@ -0,0 +1,370 @@ +# Checkout + +> This document only outlines the general checkout flow. Each eCommerce, Payment provider, and Shipping provider could implement it slightly differently. Please follow the instructions from the documentation of your payment or shipping provider to learn about its caveats + +Checkout is a process of providing shipping and billing addresses and selecting shipping and payment methods needed to place an order and pay for it. + +## Collecting and saving shipping details + +Shipping details are information about the recipient's address required to ship the order. + +You can load shipping details by calling the `load` method in `useShipping` composable and accessing the `shipping` property after loading is done. +```js{8,16} +import { useShipping } from '{INTEGRATION}'; +import { onSSR } from '@vue-storefront/core'; + +export default { + setup () { + const { + load, + shipping + } = useShipping(); + + onSSR(async () => { + await load(); + }); + + return { + shipping + }; + } +} +``` +`shipping` property returns `null` if the `load` function was not invoked or nothing is saved. + +You can use the `save` method to save shipping details so they are available next time you `load` them. + +```vue{2,15,24} + + + +``` + +## Selecting a shipping method + +`VsfShippingProvider` is a component that aggregates one or more shipping methods from a single provider like FedEx or DHL. This component is usually the only thing that you need to integrate a particular vendor into your project and is always delivered as third-party integration. + +The component is responsible for: +- Loading and displaying available shipping methods. +- Loading selected shipping method. +- Selecting and configuring shipping method. + +All you have to do is to import a component and add it to the template. + +```vue + +``` + +`VsfShippingProvider` emits the `submit` event when a shipping method is selected, configured and a user clicks submit button. + +### Extending `VsfShippingProvider` and reacting to its events + +You can pass asynchronous functions to the `VsfShippingProvider` component to hook into different events within its lifecycle, override initial function parameters or react to specific events like method selection. Let's call these methods "hooks". + +Because every shipping provider is different, not all of them are present in every integration. Always refer to the documentation of a specific provider to learn which hooks are available. + +- **beforeLoad** `(config => config)` - Called before loading shipping methods. +- **afterLoad** `(shippingMethodsResponse => shippingMethodsResponse.shippingMethods)` - Called after loading shipping methods. +- **beforeSelect** `(shippingMethod => shippingMethod)` - Called before selecting shipping method. +- **afterSelect** `(selectedShippingMethod => void)` - Called after selecting shipping method. +- **beforeSelectedDetailsChange** `(details => details)` - Called before modifying currently picked shipping method, e.g. selecting parcel locker on the map. +- **afterSelectedDetailsChange** `(details => void)` - Called after modifying currently picked shipping method. +- **onError** `(({ action, error }) => void)` - Called when some operation throws an error. + +```vue + +``` + +### Accessing current shipping method's details outside the component + +Sometimes you have to show the information about a selected shipping method in a different place than the `VsfShippingProvider` component. + +For such cases, you can use `useShippingProvider` composable. It has been made for loading and saving a current shipping method. After loading the data via the `load` method, it stores the information in some property of a `state` object, so you can access it from many places. + +```ts +import { useShippingProvider } from '{INTEGRATION}'; +import { onSSR } from '@vue-storefront/core'; +import { computed } from '@vue/composition-api'; + +export default { + setup () { + const { load, state } = useShippingProvider(); + + onSSR(async () => { + await load(); + }); + + return { + selectedShippingMethod: computed(() => ...) + } + } +} +``` + +## Collecting and saving billing details + +Billing details are information about the payer's address used by store owners to prepare invoices and payment providers to evaluate the probability of fraud payment. + +You can load billing details by calling the `load` method in `useBilling` composable and accessing the `billing` property after loading is done. + +```js{8,16} +import { useBilling } from '{INTEGRATION}'; +import { onSSR } from '@vue-storefront/core'; + +export default { + setup () { + const { + load, + billing + } = useBilling(); + + onSSR(async () => { + await load(); + }); + + return { + billing + }; + } +} +``` +`billing` property returns `null` if the `load` function was not invoked or nothing is saved. + +You can use the `save` method to save billing details. + +```vue{2,15,24} + + + +``` + +## Making an order + +After the user has provided all the information required by your eCommerce, you are ready to *make an order*. To do that, you have to call a `make` method from the `useMakeOrder` composable. +```js +import { useMakeOrder } from '{INTEGRATION}'; + +export default { + setup () { + const { make } = useMakeOrder(); + + return { + make + } + } +} +``` + +When the order is created, you can redirect the user to the page thanking them for making an order and refresh the cart. + +```js +import { useMakeOrder, useCart } from '{INTEGRATION}'; + +export default { + setup (_, context) { + const { make, order } = useMakeOrder(); + const { setCart } = useCart(); + + const processOrder = async () => { + await make(); + context.root.$router.push(`/checkout/thank-you?order=${order.value.id}`); + setCart(null); + } + } +} +``` + +## Payment providers + +A `VsfPaymentProvider` is a component that provides one or more payment methods. One such component integrates one third-party provider of payments like Checkout.com or Adyen. This component is usually the only thing that you need to integrate a particular vendor into your project and is always delivered as third-party integration. + +The component is responsible for: +- Loading and displaying available payment methods. +- Loading selected payment method. +- Picking and configuring payment method. + +The first thing you have to do is to import the component and add it to the template. + +```vue + + + +``` + +The next step is making a payment. Each package with a payment provider might use a slightly different approach, but below we described the two most common. + +### SDK takes the full control + +If the payment provider's SDK handles the whole payment and you can only provide your own callbacks for certain events. You want to make an order in the `beforePay` async hook. +```vue + + + +``` + +### SDK allows externalizing pay method + +If the payment provider's SDK handles the process of configuring payment but allows you to decide when to finalize then: +- VsfPaymentProvider emits `status` event. Use this information to enable/disable a `Place order` button. +- Composable shares a `pay` method. + +```vue + + + +``` + +### Extending `VsfPaymentProvider` and reacting to its events + +You can pass asynchronous functions to the `VsfPaymentProvider` component to hook into different events within its lifecycle, override initial function parameters or react to specific events like method selection. Let's call these methods "hooks". + +Because every payment provider is different, not all of them are present in every integration. Always refer to the documentation of a specific provider to learn which hooks are available. + +- **beforeLoad** `(config => config)` - Called before loading payment methods. +- **afterLoad** `(shippingMethodsResponse => shippingMethodsResponse.shippingMethods)` - Called after loading payment methods. +- **beforeSelect** `(shippingMethod => shippingMethod)` - Called before selecting payment method. +- **afterSelect** `(selectedShippingMethod => void)` - Called after selecting payment method. +- **beforePay** `(paymentDetails => paymentDetails)` - Called before pay. +- **afterPay** `(paymentResponse => void)` - Called after pay. +- **beforeSelectedDetailsChange** `(details => details)` - Called before modifying currently picked payment method, e.g. changing credit card's details. +- **afterSelectedDetailsChange** `(details => void)` - Called after modifying currently picked payment method, e.g. changing credit card's details. +- **onError** `(({ action, error }) => void)` - Called when some operation throws an error. + +```vue + +``` + +### Why some integrations have a mocked `VsfPaymentProvider`? + +There are eCommerce backends that do not provide any payment methods out-of-the-box, e.g. commercetools. For these, you provide a mock component that has exactly the same interface like a real integration so you can easily swap it with a payment integration of your choice. You can find available payment integrations [here](/v2/integrations/). diff --git a/packages/core/docs/guide/composables.md b/packages/core/docs/guide/composables.md index ed950a0ecc6..63c215a68a6 100644 --- a/packages/core/docs/guide/composables.md +++ b/packages/core/docs/guide/composables.md @@ -267,38 +267,41 @@ Vue Storefront integrations are exposing the following composables: #### Product Catalog -- `useProduct` for managing a single product with variants (or a list) -- `useCategory` for managing category lists (but not category products) -- `useFacet` for complex catalog search with filtering -- `useReview` for product reviews +- `useProduct` - Managing a single product with variants (or a list). +- `useCategory` - Managing category lists (but not category products). +- `useFacet` - Complex catalog search with filtering. +- `useReview` - Product reviews. #### User Profile and Authorization -- `useUser` for managing user sessions, credentials and registration -- `useUserShipping` for managing shipping addresses -- `useUserBilling` for managing billing addresses -- `useUserOrder` for managing past and active user orders +- `useUser` - Managing user sessions, credentials and registration. +- `useUserShipping` - Managing shipping addresses. +- `useUserBilling` - Managing billing addresses. +- `useUserOrder` - Managing past and active user orders. #### Shopping Cart -- `useCart` for loading the cart, adding/removing products and discounts +- `useCart` - Loading the cart, adding/removing products and discounts. #### Wishlist/Favourite -- `useWishlist` for loading the wishlist, adding/removing products +- `useWishlist` - Loading the wishlist, adding/removing products. #### CMS Content -- `useContent` for fetching the CMS content. It is usually used in combination with ``component +- `useContent` - Fetching the CMS content. It is usually used in combination with ``component. #### Checkout -- `useCheckout` for saving the shipping and billing address for a current order, choosing a shipping method, making payments, and placing the order +- `useShipping` - Saving the shipping address for a current order. +- `useShippingProvider` - Choosing a shipping method for a current order. +- `useBilling` - Saving the billing address for a current order. +- `usePaymentProvider` - Choosing a payment method for a current order. +- `useMakeOrder` - Placing the order. #### Other -- `useVSFContext` for accessing the integration API methods and client instances - +- `useVSFContext` - Accessing the integration API methods and client instances. In a real-world application, these composables will most likely use different backend services under the hood yet still leverage the same frontend API. For instance within the same application `useProduct` and `useCategory` could use `commercetools`, `useCart` some ERP system, `useFacet` - Algolia etc. ## Error handling diff --git a/packages/core/docs/integrate/integration-guide.md b/packages/core/docs/integrate/integration-guide.md index f428965c475..a57f9dd36ba 100644 --- a/packages/core/docs/integrate/integration-guide.md +++ b/packages/core/docs/integrate/integration-guide.md @@ -69,7 +69,7 @@ Vue Storefront will require **at least** the following features from your eComme **Checkout** - get shipping methods -- get payment methods +- get payment methods (depends on integration) - place order **i18n**