From a78d594542814eb2f9393f4c747e29608a90d70a Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 6 May 2022 15:45:05 +0300 Subject: [PATCH 01/34] added integration --- www/docs/docusaurus.config.js | 6 ++++++ www/docs/package.json | 1 + www/docs/yarn.lock | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/www/docs/docusaurus.config.js b/www/docs/docusaurus.config.js index 8944b88e84..9e9e2c5296 100644 --- a/www/docs/docusaurus.config.js +++ b/www/docs/docusaurus.config.js @@ -23,6 +23,12 @@ module.exports = { systemvars: true, // Set to true if you would rather load all system variables as well (useful for CI purposes) }, ], + [ + "docusaurus-plugin-segment", + { + apiKey: process.env.SEGMENT_API_KEY + } + ] ], themeConfig: { colorMode: { diff --git a/www/docs/package.json b/www/docs/package.json index b5d7c5e27a..f0de8815fd 100644 --- a/www/docs/package.json +++ b/www/docs/package.json @@ -23,6 +23,7 @@ "@svgr/webpack": "6.2.1", "algoliasearch-helper": "^3.8.2", "clsx": "^1.1.1", + "docusaurus-plugin-segment": "^1.0.3", "docusaurus2-dotenv": "^1.4.0", "file-loader": "^6.2.0", "lodash": "^4.17.21", diff --git a/www/docs/yarn.lock b/www/docs/yarn.lock index 2558b23f9c..6f63e596e0 100644 --- a/www/docs/yarn.lock +++ b/www/docs/yarn.lock @@ -1798,6 +1798,25 @@ resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== +"@ndhoule/each@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@ndhoule/each/-/each-2.0.1.tgz#bbed372a603e0713a3193c706a73ddebc5b426a9" + integrity sha1-u+03KmA+BxOjGTxwanPd68W0Jqk= + dependencies: + "@ndhoule/keys" "^2.0.0" + +"@ndhoule/keys@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@ndhoule/keys/-/keys-2.0.0.tgz#3d64ae677c65a261747bf3a457c62eb292a4e0ce" + integrity sha1-PWSuZ3xlomF0e/OkV8YuspKk4M4= + +"@ndhoule/map@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@ndhoule/map/-/map-2.0.1.tgz#f5ca0a47424ea67f46e2a6d499b9e9bc886aefa8" + integrity sha1-9coKR0JOpn9G4qbUmbnpvIhq76g= + dependencies: + "@ndhoule/each" "^2.0.1" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1824,6 +1843,13 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== +"@segment/snippet@^4.13.2": + version "4.15.3" + resolved "https://registry.yarnpkg.com/@segment/snippet/-/snippet-4.15.3.tgz#ac829ec4570b249f559756293f4736e434885de7" + integrity sha512-75kVTYaQGYMkwVjJvCLLOlzxV8jCDxvKG68U88joo/rBx95SIXETcjUmIXF6A7SFRCgz83B+zrZbo+JYsmHkig== + dependencies: + "@ndhoule/map" "^2.0.1" + "@sideway/address@^4.1.3": version "4.1.3" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" @@ -3628,6 +3654,13 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +docusaurus-plugin-segment@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/docusaurus-plugin-segment/-/docusaurus-plugin-segment-1.0.3.tgz#d32ec8ace8625837dee650f853bc89ae2221206a" + integrity sha512-9DqebTx9TqjujCnB22qEeCm8NGJUAH7VAKLAa20/CyfSSrs+khTQI0FmzEALtiCqKNO1D3GWm3VvE4gqbuGqnw== + dependencies: + "@segment/snippet" "^4.13.2" + docusaurus2-dotenv@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/docusaurus2-dotenv/-/docusaurus2-dotenv-1.4.0.tgz#9ab900e29de9081f9f1f28f7224ff63760385641" From 51bd461dcec4a9667ec95db4d37f07850b7b662e Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 6 May 2022 15:53:48 +0300 Subject: [PATCH 02/34] add segment for API reference --- www/reference/gatsby-config.js | 8 ++++++++ www/reference/package.json | 1 + www/reference/yarn.lock | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/www/reference/gatsby-config.js b/www/reference/gatsby-config.js index 90d5467b25..89feafe9af 100644 --- a/www/reference/gatsby-config.js +++ b/www/reference/gatsby-config.js @@ -65,6 +65,14 @@ module.exports = { allowList: ["ALGOLIA_API_KEY"], }, }, + { + resolve: `gatsby-plugin-segment-js`, + options: { + prodKey: process.env.SEGMENT_API_KEY, + devKey: process.env.SEGMENT_API_KEY_DEV, + trackPage: true, + } + }, // `gatsby-plugin-preact`, // { // resolve: `gatsby-source-openapi-aggregate`, diff --git a/www/reference/package.json b/www/reference/package.json index 1f0b25af62..0ccf61aa02 100644 --- a/www/reference/package.json +++ b/www/reference/package.json @@ -28,6 +28,7 @@ "gatsby-plugin-env-variables": "^2.1.0", "gatsby-plugin-preact": "^5.9.0", "gatsby-plugin-react-helmet": "^3.3.12", + "gatsby-plugin-segment-js": "^3.7.1", "gatsby-plugin-theme-ui": "^0.10.1", "gatsby-remark-autolink-headers": "^4.6.0", "gatsby-source-filesystem": "^3.9.0", diff --git a/www/reference/yarn.lock b/www/reference/yarn.lock index 3bf9eec530..3768a3367a 100644 --- a/www/reference/yarn.lock +++ b/www/reference/yarn.lock @@ -5425,6 +5425,11 @@ gatsby-plugin-react-helmet@^3.3.12: dependencies: "@babel/runtime" "^7.12.5" +gatsby-plugin-segment-js@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/gatsby-plugin-segment-js/-/gatsby-plugin-segment-js-3.7.1.tgz#3432d59be0e45ee82f36a42cff060af220a0dd68" + integrity sha512-zAsjRrF77Kih7YRUJVp84thnODbzjDE44H6ePtdQfLVyPWiJj3IpS/WAwyRg9Cu3+FciFAT8WEjfJ2I02V0sUw== + gatsby-plugin-theme-ui@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/gatsby-plugin-theme-ui/-/gatsby-plugin-theme-ui-0.10.1.tgz#d1ac7f4f1c4bf187694110a8670f0bb3ff470ad2" From 652fcdcaaae9eb567d6b709e2d99e6bea8d55848 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 11 May 2022 18:55:39 +0300 Subject: [PATCH 03/34] updated frontend checkout flow --- .../frontend-payment-flow-in-checkout.md | 117 ------- .../payment/how-to-create-payment-provider.md | 2 +- .../advanced/backend/payment/overview.md | 2 +- .../how-to-implement-checkout-flow.mdx | 329 ++++++++++++++++++ www/docs/sidebars.js | 15 +- 5 files changed, 342 insertions(+), 123 deletions(-) delete mode 100644 docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md create mode 100644 docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx diff --git a/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md b/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md deleted file mode 100644 index eeb1ba83a9..0000000000 --- a/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md +++ /dev/null @@ -1,117 +0,0 @@ -# Frontend Payment Flow in Checkout - -## Introduction -The purpose of this guide is to describe a checkout flow in Medusa. It is assumed that you've completed our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or [Tutorial](https://docs.medusajs.com/tutorial/set-up-your-development-environment) and are familiar with the technologies we use in our stack. Additionally, having an understanding of the [core API](https://docs.medusajs.com/api/store/auth) would serve as a great foundation for this walkthrough. - -:::note - -All code snippets in the following guide, use the JS SDK distributed through **npm**. To install it, run: - -```bash npm2yarn -npm install @medusajs/medusa-js -``` - -::: - -## Glossary -- **Cart**: The Cart contains all the information needed for customers to complete an Order. In the Cart customers gather the items they wish to purchase, they add shipping and billing details and complete payment information. -- **LineItem**: Line Items represent an expense added to a Cart. Typically this will be a Product Variant and a certain quantity of the same variant. Line Items hold descriptive fields that help communicate its contents and price. -- **PaymentSession**: A Payment Session is a Medusa abstraction that unifies the APIs of multiple payment gateways. Payment Sessions are _initialized_ when the customer begins a checkout and are _authorized_ prior to an Order being placed. Payment Sessions are created based on the available Payment Providers configured in a Cart's region. -- **ShippingOption**: A Shipping Option represents a way in which an Order can be fulfilled. Shipping Options have a price and are associated with a Fulfillment Provider that will handle the shipment later in the Order flow. Once a customer selects a Shipping Option it becomes a Shipping Method. -- **ShippingMethod**: Shipping Methods are unique to each Cart and can thereby hold either overwrites for fields in a Shipping Option (e.g. price) or additional details (e.g. an id representing a parcel pickup location). - -## Checkout flow -To create an order from a cart, we go through the following flow. - -:::note - -At this point, it assumed that the customer has created a cart, added items and is now at the initial step of the checkout flow. - -::: - -### Initializing the checkout -The first step in the flow is to _initialize_ the configured Payment Sessions for the Cart. If you are using the `medusa-starter-default` starter, this call will result in the `cart.payment_sessions` array being filled with one Payment Session for the manual payment provider. - -```javascript -const { cart } = await medusa.carts.createPaymentSessions("cart_id") -``` - -To give a more real life example, it is assumed that `medusa-payment-stripe` is installed in your project in which case the call will result in a [Stripe PaymentIntent](https://stripe.com/docs/api/payment_intents) being created. The unique provider data for each Payment Session can be found in the Payment Session's `data` field; this data can be used in front end implementations e.g. if using Stripe Elements the `client_secret` can be retrieved through `session.data.client_secret`. - -### Adding customer information -After initializing the checkout flow, you would typically have one big step or several smaller steps for gathering user information; email, address, country, and more. To store this data you may update the cart with each of field or all fields at the same time. - -```javascript -const { cart } = await medusa.carts.update("cart_id", { - email: "lebron@james.com", - shipping_address: { - first_name: "", - last_name: "", - ... - } -}) -``` - -### Selecting payment provider -This step is only applicable if you have multiple Payment Sessions installed in your project. In cases where only one Payment Provider is configured the Payment Session will be preselected. In all other cases your implementations should call: - -```javascript -const { cart } = await medusa.carts.setPaymentSession("cart_id", { - provider_id: "stripe" -}) -``` - -### Choosing a shipping method -Before reaching the payment step, you would typically require the customer to choose a Shipping Method from a number of options. In Medusa you can set rules that must be met for a Shipping Option to be available for a Cart. To get the available shipping options for a Cart you should call: -```javascript -const { shipping_options } = await medusa.carts.listCartOptions("cart_id") -``` - -Choosing a Shipping Option, will create a Shipping Method and attach it to the Cart. The second argument to the function in the snippet below holds the id of the selected option. -```javascript= -const { cart } = await medusa.carts.addShippingMethod("cart_id", { option_id: "option_id"}) -``` - -### Collecting payment details -The following snippet shows how we use Stripe to collect payment details from the customer. Note that we are using the `client_secret` from the Stripe PaymentIntent in `data` on the payment session as this is required by Stripe Elements. -```jsx -import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js"; - -... - -const stripe = useStripe(); -const elements = useElements(); - - -const handleSubmit = () => { - ... - const { paymentIntent, error } = await stripe.confirmCardPayment( - cart.payment_session.data.client_secret, - { - payment_method: { - card: elements.getElement(CardElement), - }, - } - ); - ... -} - -return -``` -After collecting the payment details, the customer can complete the checkout flow. - -### Completing the cart -When all relevant customer information has been captured, your implementation should proceed to the final step: completing the cart. -```javascript -const { order } = await medusa.carts.complete("cart_id") -``` -If all information is collected correctly throughout the checkout flow, the call will place an Order based on the details gathered in the Cart. - -## Summary -You now have a solid foundation for creating your own checkout flows using Medusa. Throughout this guide, we've used Stripe as a Payment Provider. Stripe is one of the most popular providers and we have an official plugin that you can easily install in your project. - -## What's next? -See the checkout flow, explained in the previous sections, in one of our frontend starters: -- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa) -- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa) - diff --git a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md index 8037f3374f..304446068e 100644 --- a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md +++ b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md @@ -384,4 +384,4 @@ async retrieveSavedMethods(customer) { ## What’s Next 🚀 - Check out the Payment Providers for [Stripe](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-stripe) and [PayPal](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-paypal) for implementation examples. -- Learn more about the [frontend checkout flow](./frontend-payment-flow-in-checkout.md). +- Learn more about the [frontend checkout flow](./../../storefront/how-to-implement-checkout-flow.mdx). diff --git a/docs/content/advanced/backend/payment/overview.md b/docs/content/advanced/backend/payment/overview.md index c65119176a..7a1b5eedac 100644 --- a/docs/content/advanced/backend/payment/overview.md +++ b/docs/content/advanced/backend/payment/overview.md @@ -126,5 +126,5 @@ This prevents any payment issues from occurring with the customers and allows fo ## What’s Next 🚀 -- [Check out how the checkout flow is implemented on the frontend.](./frontend-payment-flow-in-checkout.md) +- [Check out how the checkout flow is implemented on the frontend.](./../../storefront/how-to-implement-checkout-flow.mdx) - Check out payment plugins like [Stripe](../../../add-plugins/stripe.md), [Paypal](../../../add-plugins/paypal.md), and [Klarna](../../../add-plugins/klarna.md). diff --git a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx new file mode 100644 index 0000000000..724fa3c7bf --- /dev/null +++ b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx @@ -0,0 +1,329 @@ +# How to Implement Checkout Flow + +This document will guide you through the steps needed to implement the checkout flow in a Medusa storefront, including steps related to adding a custom payment provider. + +## Overview + +A checkout flow is composed of the necessary steps to allow a customer to perform a successful checkout. It’s generally made up of 2 primary steps: the shipping and payment steps. + +This document will take you through the general process of a checkout flow. You should follow along with this document if you’re creating a custom storefront, if you’re adding a custom payment provider, or if you’re just interested in learning more about how checkout works in Medusa. + +:::note + +It’s recommended to go through the [Shipping Architecture Overview](../backend/shipping/overview.md) and [Payment Architecture Overview](../backend/payment/overview.md) first to have a better understanding of Medusa’s architecture. + +::: + +## Prerequisites + +This document assumes you’ve already taken care of the add-to-cart flow. So, you should have a [cart created](https://docs.medusajs.com/api/store/cart/create-a-cart) for the customer with at least [one product in it](https://docs.medusajs.com/api/store/cart/add-a-line-item). + +To follow along with this tutorial, you can make use of the [Medusa JS Client](https://www.npmjs.com/package/@medusajs/medusa-js). You can install it with this command: + +```bash npm2yarn +npm install @medusajs/medusa-js +``` + +There’s also an alternative approach in this document using [JavaScript’s Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) in case you’re unable to use Medusa’s JS Client. Make sure to replace `` in those examples with your server URL. + +## Shipping Step + +In this step, the customer generally enters their shipping info, then chooses the available shipping option based on the entered info. + +### Add Shipping Address + +After the customer enters their shipping address information, you must send a `POST` request to the [Update a Cart](https://docs.medusajs.com/api/store/cart/update-a-cart) API endpoint passing it the new shipping address: + + + + +```jsx +medusa.carts.update(cart.id, { + shipping_address: { + company, + first_name, + last_name, + address_1, + address_2, + city, + country_code, + province, + postal_code, + phone + }, +}).then((response) => { + //updated cart is in response.cart +}) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}`, { + method: 'POST', + body: JSON.stringify({ + shipping_address: { + company, + first_name, + last_name, + address_1, + address_2, + city, + country_code, + province, + postal_code, + phone + }, + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can have access to the updated cart in `response.cart`, which now has the shipping address you added in `response.cart.shipping_address`. + +### List Shipping Options + +After updating the cart with the customer’s address, the list of available [shipping options](../backend/shipping/overview.md#shipping-option) for that cart might change. So, you should retrieve the updated list of options by sending a `GET` request to the [Retrieve Shipping Options for Cart API](https://docs.medusajs.com/api/store/shipping-option/retrieve-shipping-options-for-cart) endpoint: + + + + +```jsx +medusa.shippingOptions.listCartOptions(cart.id) + .then((response) => { + //shipping options available in response.shipping_options + }) +``` + + + + +```jsx +fetch(`/store/shipping-options/${cart.id}`) + .then((response) => response.json()) + .then((response) => { + //shipping options available in response.shipping_options + }) +``` + + + + +You can access all shipping options available with their info in `response.shipping_options` which is an array of [shipping options](https://docs.medusajs.com/api/store/shipping-option). Typically you would display those options to the customer to choose from. + +### Choose Shipping Option + +Once the customer chooses one of the available shipping options, send a `POST` request to the [Add a Shipping Method](https://docs.medusajs.com/api/store/cart/add-a-shipping-method) API endpoint. This will create a [shipping method](../backend/shipping/overview.md#shipping-method) based on the shipping option chosen and will associate it with the customer’s cart: + + + + +```jsx +medusa.carts.addShippingMethod(cart.id, { + option_id: shipping_option.id //shipping_option is the select option +}).then((response) => { + //updated cart is in response.cart + }) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/shipping-methods`, { + method: 'POST', + body: JSON.stringify({ + option_id: shipping_option.id //shipping_option is the select option + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can have access to the updated cart in `response.cart`, which now has one item in the array value of the property `shipping_methods`. + +## Payment Step + +In this step, the customer generally chooses a payment method to complete their purchase. The implementation of payment providers is done differently for each provider, so this section will just show the general steps you should follow when implementing this step. + +### Initialize Payment Sessions + +When the page opens and before the payment providers are displayed to the customer to choose from, you must initialize the [payment sessions](./../backend/payment/overview.md#payment-session) for the current cart. Each payment provider will have a payment session associated with it. These payment sessions will be used later when the customer chooses the payment provider they want to complete their purchase with. + +To initialize the payment sessions, send a `POST` request to the [Initialize Payment Sessions](https://docs.medusajs.com/api/store/cart/initialize-payment-sessions) API endpoint: + + + + +```jsx +medusa.carts.createPaymentSessions(cart.id) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/payment-sessions`, { + method: 'POST' +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can then access the initialized payment sessions under the `payment_sessions` array in `response.cart`. + +### Select Payment Session + +When the customer chooses the payment provider they want to complete purchase with, you should select the payment session associated with that payment provider. To do that, send a `POST` request to the [Select a Payment Session](https://docs.medusajs.com/api/store/cart/select-a-payment-session) API endpoint: + + + + +```jsx +medusa.carts.setPaymentSession(cart.id, { + provider_id: payment_session.provider_id //payment_session is the session chosen by the customer +}).then((response) => { + //updated cart is in response.cart +}) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/payment-session`, { + method: 'POST', + body: JSON.stringify({ + provider_id: payment_session.provider_id //payment_session is the session chosen by the customer + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can then access the selected payment session in `response.cart.payment_session`. + +:::tip + +If you have one payment provider or if only one payment provider is available for the current cart, its payment session will be automatically selected in the “[Initialize Payment Session](#initialize-payment-sessions)” step and this step becomes unnecessary. You can check whether there is a payment session selected or not by checking whether `cart.payment_session` is `null` or not. + +::: + +### Update Payment Session + +This step is optional and is only necessary for some payment providers. As mentioned in the [Payment Architecture](../backend/payment/overview.md#overview) documentation, the `PaymentSession` model has a `data` attribute that holds any data required for the Payment Provider to perform payment operations such as capturing payment. + +If you need to update that data at any point before the purchase is made, send a request to [Update a Payment Session](https://docs.medusajs.com/api/store/cart/update-a-payment-session) API endpoint passing it the updated data object: + + + + +```jsx +medusa.carts.updatePaymentSession(cart.id, cart.payment_session.provider_id, { + data: { + //pass any data you want to add in the `data` attribute + //for example: + "test": true + } +}).then((response) => { + //updated cart is in response.cart +}) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/payment-sessions/${cart.payment_session.provider_id}`, { + method: 'POST', + body: JSON.stringify({ + data: { + //pass any data you want to add in the `data` attribute + //for example: + "test": true + } + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can have access to the updated data in the payment session in `response.cart.payment_session.data`. + +### Complete Cart + +The last step is to place the order by completing the cart. When you complete the cart, your Medusa server will try to authorize the payment first, then place the order if the authorization is successful. So, you should perform any necessary action with your payment provider first to make sure the authorization is successful when you send the request to complete the cart. + +To complete a cart, send a `POST` request to the [Complete a Cart](https://docs.medusajs.com/api/store/cart/complete-a-cart) API endpoint: + + + + +```jsx +medusa.carts.complete(cart.id) + .then((response) => { + //order details is in response.data + }) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/complete`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //order details is in response.data + }) +``` + + + + +If the order is placed successfully, you can access the order data in `response.data` and the value for `response.type` is `order`. Otherwise, `response.data` holds the cart details and `response.type` is `cart`. + +## What’s Next 🚀 + +- Check out available plugins for popular payment providers such as [Stripe](../../add-plugins/stripe.md) and [PayPal](/add-plugins/paypal.md). +- Learn more about the [Payment](../backend/payment/overview.md) and [Shipping](../backend/shipping/overview.md) Architectures. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 7ede695603..d424849c9b 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -186,10 +186,6 @@ module.exports = { type: "doc", id: "advanced/backend/payment/how-to-create-payment-provider", }, - { - type: "doc", - id: "advanced/backend/payment/frontend-payment-flow-in-checkout", - }, ] }, { @@ -222,6 +218,17 @@ module.exports = { ] }, ] + }, + { + type: "category", + label: "Storefront", + collapsed: true, + items: [ + { + type: "doc", + id: "advanced/storefront/how-to-implement-checkout-flow", + }, + ] } ] }, From 9059a7c61efc88e3898587d6a8862fbfbe4a857e Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 2 Jun 2022 10:36:04 +0300 Subject: [PATCH 04/34] added documentation for entities --- docs/content/advanced/backend/entities.md | 160 ++++++++++++++++++++++ www/docs/sidebars.js | 5 + 2 files changed, 165 insertions(+) create mode 100644 docs/content/advanced/backend/entities.md diff --git a/docs/content/advanced/backend/entities.md b/docs/content/advanced/backend/entities.md new file mode 100644 index 0000000000..95b45dea02 --- /dev/null +++ b/docs/content/advanced/backend/entities.md @@ -0,0 +1,160 @@ +# How to Create Entities + +In this document, you’ll learn about entities in Medusa and how you can create your own entity. + +## Overview + +Entities in medusa represent tables in the database as classes. An example of this would be the `Order` entity which represents the `order` table in the database. Entities provide a uniform way of defining and interacting with data retrieved from the database. + +Aside from Medusa’s core entities, you can also create your own entities to use in your Medusa server. Custom entities must reside in the `src/models` directory of your Medusa server. + +Entities are TypeScript files and they are based on [Typeorm’s Entities](https://typeorm.io/entities) and use Typeorm decorators. + +All entities must extend either the `BaseEntity` or `SoftDeletableEntity` classes. The `BaseEntity` class holds common columns including the `id`, `created_at`, and `updated_at` columns. + +The `SoftDeletableEntity` class extends the `BaseEntity` class and adds another column `deleted_at`. If an entity can be soft deleted, meaning that a row in it can appear to the user as deleted but still be available in the database, it should extend `SoftDeletableEntity`. + +## How to Create a Custom Entity + +### Prerequisites + +It’s recommended to create a `tsconfig.json` file in the root of your Medusa server with the following content: + +```jsx +{ + "compilerOptions": { + "experimentalDecorators": true + } +} +``` + +This will remove any errors that show up in your IDE related to experimental decorators. + +### Create the Entity + +To create an entity, create a TypeScript file in `src/models`. For example, here’s a `Post` entity defined in the file `src/models/post.ts`: + +```tsx +import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm"; +import { BaseEntity} from "@medusajs/medusa"; +import { generateEntityId } from "@medusajs/medusa/dist/utils" + +@Entity() +export class Post extends BaseEntity { + @Column({type: 'varchar'}) + title: string | null; + + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "post") + } +} +``` + +This entity has one column `title` defined. However, since it extends `BaseEntity` it will also have the `id`, `created_at`, and `updated_at` columns. + +Medusa’s core entities all have the following format for IDs: `_`. For example, an order might have the ID `order_01G35WVGY4D1JCA4TPGVXPGCQM`. + +To generate an ID for your entity that matches the IDs generated for Medusa’s core entities, you should add a `BeforeInsert` event handler. Then, inside that handler use Medusa’s utility function `generateEntityId` to generate the ID. It accepts the ID as a first parameter and the prefix as a second parameter. The `Post` entity IDs will be of the format `post_`. + +If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead: + +```tsx +import { SoftDeletableEntity } from "@medusajs/medusa"; + +@Entity() +export class Post extends SoftDeletableEntity { + //... +} +``` + +You can learn more about what decorators and column types you can use in [Typeorm’s documentation](https://typeorm.io/entities). + +### Create the Migration + +Additionally, you must create a migration for your entity. Migrations are used to update the database schema with new tables or changes to existing tables. + +You can learn more about Migrations, how to create them, and how to run them in the [Migration documentation](migrations.md). + +### Create a Repository + +Entities data can be easily accessed and modified using Typeorm [Repositories](https://typeorm.io/working-with-repository). To create a repository, create a file in `src/repositories`. For example, here’s a repository `PostRepository` that resides in `src/repositories/post.ts`: + +```tsx +import { EntityRepository, Repository } from "typeorm" + +import { Post } from "../models/post" + +@EntityRepository(Post) +export class PostRepository extends Repository { } +``` + +This repository is created for the `Post` and that is indicated using the decorator `@EntityRepository`. + +:::tip + +Be careful with your file names as it can cause unclear errors in Typeorm. Make sure all your file names are small letters for both entities and repositories to avoid any issues with file names. + +::: + +## Access Your Custom Entity + +:::note + +Before trying this step make sure that you’ve created and run your migrations. You also need to re-build your code using: + +```bash npm2yarn +npm run build +``` + +::: + +You can access your custom entity data in the database in services or subscribers using the repository. For example, here’s a service that lists all posts: + +```tsx +import { TransactionBaseService } from "medusa-interfaces"; + +class PostService extends TransactionBaseService { + constructor({ postRepository, manager }) { + super({ postRepository, manager }); + + this.postRepository = postRepository; + this.manager_ = manager; + } + + async list() { + const postRepository = this.manager_.getCustomRepository(this.postRepository); + return await postRepository.find(); + } +} + +export default PostService; +``` + +In the constructor, you can use dependency injection to get access to instances of services and repositories. Here, you initialize class fields `postRepository` and `manager`. The `manager` is a [Typeorm Entity Manager](https://typeorm.io/working-with-entity-manager). + +Then, in the method `list`, you can obtain an instance of the `PostRepository` using `this.manager_.getCustomRepository` passing it `this.postRepository` as a parameter. This lets you use [Custom Repositories with Typeorm](https://typeorm.io/custom-repository) to create custom methods in your repository that work with the data in your database. + +After getting an instance of the repository, you can then use [Typeorm’s Repository methods](https://typeorm.io/repository-api) to perform CRUD (Create, Read, Update, Delete) operations on your entity. + +If you need access to your entity in endpoints, you can then use the methods you define in the service. + +:::note + +This same usage of repositories can be done in subscribers as well. + +::: + +### Deleting Soft-Deletable Entities + +To delete soft-deletable entities that extend the `SoftDeletableEntity` class, you can use the repository method `softDelete` method: + +```tsx +await postRepository.softDelete(post.id); +``` + +## What’s Next 🚀 + +- Learn more about [Services](services/create-service.md) and how to use them. +- Learn how to create an endpoint for [storefront](endpoints/add-storefront.md) and [admin](endpoints/add-admin.md). +- Learn about [migrations](migrations.md). \ No newline at end of file diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 6a6988e54a..213f8cbb0a 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -148,6 +148,11 @@ module.exports = { }, ] }, + { + type: "doc", + id: "advanced/backend/entities", + label: "Entities" + }, { type: "category", label: 'Shipping', From 5af629a10b9acddaa3e78464cfb29a34b43e224d Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 2 Jun 2022 12:07:12 +0300 Subject: [PATCH 05/34] docs: disable running tests for docs --- .github/workflows/action.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index e0a2f5e7b1..e77d96bd4e 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -1,5 +1,9 @@ name: Medusa Pipeline -on: [pull_request] +on: + pull_request: + paths-ignore: + - 'docs/**' + - 'www/**' jobs: unit-tests: From e562d2749f7c5fdccc4d3d82ddcffae02c9c1189 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 2 Jun 2022 19:05:04 +0300 Subject: [PATCH 06/34] added docs contribution guidelines --- CONTRIBUTING.md | 2 + docs/content/contribution-guidelines.md | 112 ++++++++++++++++++++++++ www/docs/sidebars.js | 5 ++ 3 files changed, 119 insertions(+) create mode 100644 docs/content/contribution-guidelines.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e3019cf472..17d405ccba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,8 @@ Thank you for considering contributing to Medusa! This document will outline how to submit changes to this repository and which conventions to follow. If you are ever in doubt about anything we encourage you to reach out either by submitting an issue here or reaching out [via Discord](https://discord.gg/xpCwq3Kfn8). +If you're contributing to our documentation, make sure to also check out the [contribution guidelines on our documentation website](https://docs.medusajs.com/contribution-guidelines). + ## Prerequisites - **You're familiar with GitHub Issues and Pull Requests** diff --git a/docs/content/contribution-guidelines.md b/docs/content/contribution-guidelines.md new file mode 100644 index 0000000000..9c1688b872 --- /dev/null +++ b/docs/content/contribution-guidelines.md @@ -0,0 +1,112 @@ +# Contribution Guidelines + +Thank you for your interest in contributing to the documentation! You will be helping the open source community and other developers interested in learning more about Medusa and using it. + +:::tip + +This guide is specific to contributing to the documentation. If you’re interested in contributing to Medusa’s codebase, check out the [contributing guidelines in the Medusa GitHub repository](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +::: + +## Site Setup + +The documentation website is built with [Docusaurus](https://docusaurus.io/), a framework that optimizes documentation creation. If you’re not familiar with Docusaurus, it’s recommended to check out the [Installation documentation](https://docusaurus.io/docs/installation) on their website to better understand Docusaurus, how it works, its structure, and more details. + +The documentation codebase is hosted as part of the [medusa repository](https://github.com/medusajs/medusa) on GitHub. You’ll find the code that runs the docusaurus website under the [www/docs](https://github.com/medusajs/medusa/tree/master/www/docs) directory. + +## Documentation Content + +The documentation content is written in Markdown format and is located in the [docs/content](https://github.com/medusajs/medusa/tree/master/docs/content) directory of the same repository. If you’re not familiar with Markdown, check out [this cheat sheet](https://www.markdownguide.org/cheat-sheet/) for a quick start. + +You’ll also find MDX files. MDX files combine the power of Markdown with React. So, the content of the file can contain JSX components and import statements, among other features. You can learn more about [MDX in docusaurus’s guide.](https://docusaurus.io/docs/markdown-features/react) + +## What You Can Contribute To + +- You can contribute to the Docusaurus codebase to add a new feature or fix a bug in the documentation website. +- You can contribute to the documentation content either by fixing errors you find or adding documentation pages. + +## What You Can’t Contribute To + +The [Services Reference](/references/services/classes/AuthService) is an automatically generated API reference using Typedoc. So, you can’t contribute to it by making changes to its markdown files. + +You can, however, contribute to the script generating it if you find any issues in it. + +## Style Guide + +When you contribute to the documentation content, make sure to follow the [documentation style guide](https://www.notion.so/Style-Guide-Docs-fad86dd1c5f84b48b145e959f36628e0). + +## How to Contribute + +If you’re fixing errors in an existing documentation page, you can scroll down to the end of the page and click on the “Edit this page” link. You’ll be redirected to the GitHub edit form of that page and you can make edits directly and submit a pull request (PR). + +If you’re adding a new page or contributing to the codebase, fork the repository, create a new branch, and make all changes necessary in your repository. Then, once you’re done creating a PR in the Medusa repository. + +For more details on how to contribute, check out [the contribution guidelines on our repository](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +### Branch Name + +When you make edit to an existing documentation page or fork the repository to make changes to the documentation, you have to create a new branch. + +Make sure that the branch name starts with `docs/`. For example, `docs/fix-services`. + +### Pull Request Conventions + +When you create a pull request, prefix the title with “docs:”. Make sure to keep “docs” in small letters. + +In the body of the PR, explain clearly what the PR does. If the PR solves an issue, use [closing keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) with the issue number. For example, “Closes #1333”. + +## Sidebar + +When you add a new page to the documentation, you must add the new page in `www/docs/sidebars.js` under the `tutorialSidebar`. You can learn more about the syntax used [here](https://docusaurus.io/docs/sidebar/items). + +## Notes and Additional Information + +When displaying notes and additional information in a documentation page, use [Admonitions](https://docusaurus.io/docs/markdown-features/admonitions). Make sure the type of admonition used matches the note’s importance to the current document. + +If the note is something developers have to be careful of doing or not doing, use the `caution` or `danger` admonitions based on how critical it is. + +If the note is defining something to the developer in case they’re not familiar with it, use the `info` admonition. + +If the note displays helpful information and tips use the `tip` admonition. + +If the admonition does not match any of the mentioned criteria, always default to the `note` admonition. + +## Images + +If you are adding images to a documentation page, you can host the image on [Imgur](https://imgur.com) for free. + +## NPM and Yarn Code Blocks + +If you’re adding code blocks that use NPM and Yarn, you must use the [npm2yarn syntax](https://docusaurus.io/docs/markdown-features/code-blocks#npm2yarn-remark-plugin). + +For example: + +~~~md +```bash npm2yarn +npm run start +``` +~~~ + +The code snippet must be written using NPM, and the `npm2yarn` plugin will automatically transform it to Yarn. + +### Expand Commands + +Don't use commands in their abbrivated terms. For example, instead of `npm i` use `npm install`. + +### Run Command + +Make sure to always use the `run` command when the command runs a script. + +For example, even though you can run the `start` script using NPM with `npm start`, however, to make sure it’s transformed properly to a Yarn command, you must add the `run` keyword before `start`. + +### Global Option + +When a command uses the global option `-g`, add it at the end of the NPM command to ensure that it’s transformed to a Yarn command properly. For example: + +```bash +npm install @medusajs/medusa-cli -g +``` + +## Need Additional Help? + +If you need any additional help while contributing, you can join our [Discord server](https://discord.gg/medusajs) and ask Medusa’s core team as well as the community any questions. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 6a6988e54a..5e00108afb 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -392,6 +392,11 @@ module.exports = { }, ], }, + { + type: "doc", + id: "contribution-guidelines", + label: "Contribution Guidelines", + }, ], servicesSidebar: [ { From 40f5ed89a6ced745e86a96331a442110806ac9ca Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 6 Jun 2022 19:12:40 +0300 Subject: [PATCH 07/34] Use npm2yarn where missing --- docs/content/add-plugins/minio.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/add-plugins/minio.md b/docs/content/add-plugins/minio.md index 77a1f16ceb..336484e410 100644 --- a/docs/content/add-plugins/minio.md +++ b/docs/content/add-plugins/minio.md @@ -76,7 +76,7 @@ You will not be able to access the Secret Key after closing the pop-up. So, make In the directory of your Medusa server, run the following command to install the MinIO plugin: -```bash +```bash npm2yarn npm install medusa-file-minio ``` From 37261e0eb4bf776b2641b7b3b1bd85f3cdd3772d Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 8 Jun 2022 15:35:57 +0300 Subject: [PATCH 08/34] added additional steps section --- docs/content/quickstart/quick-start.md | 52 ++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/content/quickstart/quick-start.md b/docs/content/quickstart/quick-start.md index 603bcdf765..288e941610 100644 --- a/docs/content/quickstart/quick-start.md +++ b/docs/content/quickstart/quick-start.md @@ -18,27 +18,29 @@ node -v You can install Node from the [official website](https://nodejs.org/en/). -## Getting started +## Create a Medusa Server -1. **Install Medusa CLI** +### 1. Install Medusa CLI ```bash npm2yarn npm install -g @medusajs/medusa-cli ``` -2. **Create a new Medusa project** +### 2. Create a new Medusa project ```bash medusa new my-medusa-store --seed ``` -3. **Start your Medusa engine** +### 3. Start your Medusa server ```bash cd my-medusa-store medusa develop ``` +### Test Your Server + After these 3 steps and in only a couple of minutes, you now have a complete commerce engine running locally. You can test it out by sending a request using a tool like Postman or through the command line: ```bash @@ -55,6 +57,48 @@ curl localhost:9000/store/products ::: +## Additional Steps + +### File Service Plugin + +To upload product images to your Medusa server, you must install and configure one of the following file service plugins: + +- [MinIO](../add-plugins/minio.md) (Recommended for local development) +- [S3](../add-plugins/s3.md) +- [DigitalOcean Spaces](../add-plugins/spaces.md) + +### Environment Variables + +Medusa allows you to choose how to load your environment variables. By default, it will only load environment variables on your system. + +If you want to load environment variables from a `.env` file add the following at the top of `medusa-config.js`: + +```js +const dotenv = require('dotenv') + + let ENV_FILE_NAME = ''; + switch (process.env.NODE_ENV) { + case 'production': + ENV_FILE_NAME = '.env.production'; + break; + case 'staging': + ENV_FILE_NAME = '.env.staging'; + break; + case 'test': + ENV_FILE_NAME = '.env.test'; + break; + case 'development': + default: + ENV_FILE_NAME = '.env'; + break; + } + + try { + dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME }); + } catch (e) { + } +``` + ## What's next :rocket: - Install our [Next.js](http://localhost:3000/starters/nextjs-medusa-starter) or [Gatsby](http://localhost:3000/starters/gatsby-medusa-starter) storefronts to set up your ecommerce storefront quickly. From c5d52240aab196a5d1ba021ad5059d309e2d5fc7 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 8 Jun 2022 18:55:01 +0300 Subject: [PATCH 09/34] added notification overview --- docs/content/add-plugins/sendgrid.mdx | 2 +- .../advanced/backend/notification/overview.md | 92 ++++++++++++++++ .../backend/subscribers/events-list.md | 2 +- docs/content/how-to/notification-api.md | 103 ------------------ www/docs/sidebars.js | 11 +- 5 files changed, 103 insertions(+), 107 deletions(-) create mode 100644 docs/content/advanced/backend/notification/overview.md delete mode 100644 docs/content/how-to/notification-api.md diff --git a/docs/content/add-plugins/sendgrid.mdx b/docs/content/add-plugins/sendgrid.mdx index 9f602f1601..4fcc04f60c 100644 --- a/docs/content/add-plugins/sendgrid.mdx +++ b/docs/content/add-plugins/sendgrid.mdx @@ -3963,5 +3963,5 @@ You can also track analytics related to emails sent from the SendGrid dashboard. ## What’s Next 🚀 -- Learn more about how [Notifications work in Medusa](../how-to/notification-api.md). +- Learn more about how [Notifications work in Medusa](../advanced/backend/notification/overview.md). - Install the [Medusa admin](https://github.com/medusajs/admin#-setting-up-admin) for functionalities like Gift Cards creation, swaps, claims, order return requests, and more. \ No newline at end of file diff --git a/docs/content/advanced/backend/notification/overview.md b/docs/content/advanced/backend/notification/overview.md new file mode 100644 index 0000000000..68426e450e --- /dev/null +++ b/docs/content/advanced/backend/notification/overview.md @@ -0,0 +1,92 @@ +# Architecture Overview + +This document gives an overview of the notification architecture and how it works. + +## Introduction + +Medusa provides a Notification API to mainly handle sending and resending notifications when an event occurs. For example, sending an email to the customer when they place an order. + +The Notification architecture is made up of 2 main components: the Notification Provider and the Notification. Simply put, the Notification Provider handles the sending and resending of a Notification. + +## Notification Provider + +### Overview + +A Notification Provider is a provider that handles sending and resending of notifications. You can either create and integrate your own provider or install a Notification Provider through a third-party plugin. + +An example of a notification provider is SendGrid. When an order is placed, the SendGrid plugin sends an email to the customer. + +### How it is Created + +A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a service file in your Medusa server. + +As a developer, you mainly work with the Notification Provider when integrating a third-party service that handles notifications in Medusa. + +When you run your Medusa server, the Notification Provider is registered on your server if it isn’t already. This means that it will be inserted into the `notification_provider` table in your database. + +### Entity Overview + +The `NotificationProvider` entity only has 2 attributes: `id` and `is_installed`. + +`id` is the value of the static property `identifier` defined inside the notification service class. + +`is_installed` indicates whether the Notification Provider is installed or not. When you install a Notification Provider, the value of this attribute is `true`. + +If you installed a Notification provider and then removed the service files or plugin that registered the Notification Provider, the Notification Provider remains in your database, but the value of the `is_installed` field changes to `false`. + +## Notification + +### Overview + +A notification is a form of an alert sent to the customers or users to inform them of an action that has occurred. For example, if an order is placed, the notification, in this case, can be an email that confirms their order and lists the order details. + +Notifications can take on other forms such as an SMS or a Slack message. + +### How it is Created + +Notifications are created in the `NotificationService` class in Medusa’s core after the Notification has been handled by the Notification Provider. + +The data and additional details that the Notification Provider returns to the `NotificationService` is used to fill some of the attributes of the Notification in the database. + +A Notification also represents a resent notification. So, when a notification is resent, a new one is created that references the original Notification as a parent. This Notification is also created by the `NotificationService` class. + +### Entity Overview + +The 2 most important properties in the `Notification` entity are the `to` and `data` properties. + +The `to` property is a string that represents the receiver of the Notification. For example, if the Notification was sent to an email address, the `to` property holds the email address the Notification was sent to. + +The `to` property can alternatively be a phone number or a chat username. It depends on the Notification Provider and how it sends the Notification. + +The `data` property is an object that holds all the data necessary to send the Notification. For example, in the case of an order confirmation Notification, it can hold data related to the order. + +The `data` property is useful when a notification is resent later. The same `data` can be used to resend the notification. + +In the case of resent notifications, the resent notification has a `parent_id` set to the ID of the original Notification. The value of the `parent_id` property in the original Notification is `null`. + +The `Notification` entity has some properties that determine the context of this Notification. This includes the `event_name` property which is the event that triggered the sending of this notification. + +Additionally, the `resource_type` property is used to determine what resource this event is associated with. For example, if the `event_name` is `order.placed`, the `resource_type` is `order`. + +You can also access the specific resource using the `resource_id` property, which is the ID of the resource. So, in case of the `order.placed` event, the `resource_id` is the ID of the order that was created. + +The `Notification` entity also includes properties related to the receiver of the Notification. In case the receiver is a customer, the `customer_id` property is used to identify which customer. + +## Automating Flows with Notifications + +With Medusa you can create notifications as a reaction to a wide spectrum of events, allowing you to automate communication and processes. + +An example of a flow that can be implemented using Medusa's Notification API is automated return flows: + +- A customer requests a return by sending a `POST` request to the `/store/returns` endpoint. +- The Notification Provider listens to the `order.return_requested` event and sends an email to the customer with a return invoice and return label generated by the Fulfillment Provider. +- The customer returns the items triggering the `return.recieved` event. +- The Notification Provider listens to the `return.received` event and sends an email to the customer with confirmation that their items have been received and that a refund has been issued. + +## What’s Next 🚀 + +- Learn how to create your own Notification Provider. +- [Check out the list of events in Medusa.](../subscribers/events-list.md) +- [Check the `NotificationService` API reference for more details on how it works.](../../../references/services/classes/NotificationService.md) +- [Check out the SendGrid Notification plugin.](../../../add-plugins/sendgrid.mdx) +- Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md) in Medusa. diff --git a/docs/content/advanced/backend/subscribers/events-list.md b/docs/content/advanced/backend/subscribers/events-list.md index 1f76d6fa2d..21b917d10f 100644 --- a/docs/content/advanced/backend/subscribers/events-list.md +++ b/docs/content/advanced/backend/subscribers/events-list.md @@ -1862,4 +1862,4 @@ Object of the following format: ## What’s Next 🚀 - Learn how you can [use services in subscribers](create-subscriber.md#using-services-in-subscribers). -- Learn how to [create notifications](../../../how-to/notification-api.md) in Medusa. +- Learn how to [create notifications](../notification/overview.md) in Medusa. diff --git a/docs/content/how-to/notification-api.md b/docs/content/how-to/notification-api.md deleted file mode 100644 index 2e39c2523a..0000000000 --- a/docs/content/how-to/notification-api.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Notifications and automated flows ---- - -# Notification API and how to structure email flows - -### Introduction - -Plugins offer a way to extend and integrate the core functionality of Medusa. For a walkthrough of the implementation details behind these, please see [Plugins in Medusa](https://docs.medusajs.com/guides/plugins). - -Medusa makes it possible for plugins to implement the Notification API. The API allows for different types of implementations of notifications (emails, text messages, Slack messages, etc), that are sent as a reaction to events in Medusa. All Notifications are stored in the database with information about the receiver of the notification and what plugin was in charge of sending it. This allows merchants to resend notifications, but also gives an overview of what communication has been sent to customers. - -### How it works - -The Notification API works by subscribing to all events that are emitted to the Event Bus and channeling them through to notification plugins that listen to the events. In a plugin you can subscribe to a notification event by exporting a subscriber class that calls `notificationService.subscribe`: - -```jsx -// src/subscribers/my-notification.js - -class MyNotification { - constructor({ notificationService }) { - // Subscribe to order.placed events - notificationService.subscribe("order.placed", "my-service"); - } -} - -export default MyNotification; -``` - -The above code tells the notification service to send `order.placed` events to the `my-service` notification service implemented in your plugin. - -For a plugin to work with the Notification API you must implement 2 methods `sendNotification` and `resendNotification`; - -```jsx -// src/services/my-notification.js - -class MyService extends NotificationService { - static identifier = "my-service"; - - constructor({ orderService }, options) { - super(); - - this.options_ = options; - this.orderService_ = orderService; - } - - async sendNotification(eventName, eventData, attachmentGenerator) { - let sendData; - switch (eventName) { - case "order.placed": - sendData = await this.orderService_.retrieve(eventData.id); - break; - default: - // If the return value is undefined no notification will be stored - return; - } - - await CoolEmailSender.send({ - email: sendData.email, - templateData: sendData, - }); - - return { to: sendData.email, data: sendData }; - } - - async resendNotification(notification, config, attachmentGenerator) { - const recipient = config.to || notification.to; - - await CoolEmailSender.send({ - email: recipient, - templateData: notification.data, - }); - - return { to: sendOptions.to, data: notification.data }; - } -} - -export default MyService; -``` - -:::note - - A notification service must have a static property called `identifier` this is used to determine which classes are called when subscribing to different events. In this case the service identifier is `my-service` so to subscribe to notifications you must use: - `notificationService.subscribe([eventname], "my-service")` - -::: - -The above class is an example implementation of a NotificationService. It uses a fictional email service called `CoolEmailSender` to send emails to a customer whenever an order is placed. The `sendNotification` implementation gets the event name and fetches relevant data based on what event is being processed; in this case it retrieves an order, which is later used when requesting `CoolEmailSender` to dispatch an email. The address to send the email to is likewise fetched from the order. - -The return type of `sendNotification` and `resendNotification` is an object with `to` and `data`. The `to` prop should identify the receiver of the notification, in this case an email, but it could also be a phone number, an ID, a channel name or something similar depending on the type of notification provider. The `data` prop contains the data as it was gathered when the notification was sent; the same data will be provided if the notification is resent at a later point. - -When `resendNotification` is called the original Notification is provided along with a config object. The config object may contain a `to` property that can be used to overwrite the original `to`. - -## Creating automated notification flows - -When running an ecommerce store you typically want to send communication to your customers when different events occur, these include messages like order confirmations and shipping updates. With Medusa you can create transactional notifications as a reaction to a wide spectrum of events, allowing you to automate communication and processes. An example of a flow that can be implemented using Medusa's Notification API is automated return flows. Below is an outline of how an automated return flow might work. - -- Customer requests a return with `POST /store/returns` -- Notification Service listens for `order.return_requested` and sends email to the customer with a return invoice and return label generated by fulfillment provider -- Customer returns items triggering `return.recieved` -- Notification Service listens for `return.received` and sends email to the customer with confirmation that their items have been received and that a refund has been issued. - -Check out `medusa-plugin-sendgrid` for an Notification API implementation that works with Sendgrid. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 6a6988e54a..f2208b538d 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -186,8 +186,15 @@ module.exports = { ] }, { - type: "doc", - id: "how-to/notification-api", + type: "category", + label: "Notification", + collapsed: true, + items: [ + { + type: "doc", + id: "advanced/backend/notification/overview" + } + ] }, { type: "doc", From f6d1d062288e5d91dd549faa41957beecaa0cacf Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 9 Jun 2022 11:06:34 +0300 Subject: [PATCH 10/34] Added guidelines for sidebar labels --- docs/content/contribution-guidelines.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/content/contribution-guidelines.md b/docs/content/contribution-guidelines.md index 9c1688b872..17d7f232c8 100644 --- a/docs/content/contribution-guidelines.md +++ b/docs/content/contribution-guidelines.md @@ -59,6 +59,12 @@ In the body of the PR, explain clearly what the PR does. If the PR solves an iss When you add a new page to the documentation, you must add the new page in `www/docs/sidebars.js` under the `tutorialSidebar`. You can learn more about the syntax used [here](https://docusaurus.io/docs/sidebar/items). +### Terminology + +When the documentation page is a conceptual or overview documentation, the label in the sidebar should start with a noun. + +When the documentation page is a tutorial documentation, the label in the sidebar should start with a verb. An exception of this rule are integration documentations and upgrade guides. + ## Notes and Additional Information When displaying notes and additional information in a documentation page, use [Admonitions](https://docusaurus.io/docs/markdown-features/admonitions). Make sure the type of admonition used matches the note’s importance to the current document. From 2ac07400a6f5136c2e4b87fb194b5a1b07327b57 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 9 Jun 2022 16:35:06 +0300 Subject: [PATCH 11/34] added how to create notification provider --- .../how-to-create-notification-provider.md | 272 ++++++++++++++++++ .../advanced/backend/notification/overview.md | 26 +- www/docs/sidebars.js | 5 + 3 files changed, 288 insertions(+), 15 deletions(-) create mode 100644 docs/content/advanced/backend/notification/how-to-create-notification-provider.md diff --git a/docs/content/advanced/backend/notification/how-to-create-notification-provider.md b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md new file mode 100644 index 0000000000..73ec0e949c --- /dev/null +++ b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md @@ -0,0 +1,272 @@ +# How to Create a Notification Provider + +In this document, you’ll learn how to add a Notification Provider to your Medusa server. If you’re unfamiliar with the Notification architecture in Medusa, it is recommended to check out the [architecture overview](overview.md) first. + +## Overview + +A Notification Provider is the custom or third-party service used to handle sending alerts to customers or users when an event occurs. + +For example, you can use SendGrid to send a confirmation email to a customer after they place an order. SendGrid in this example is a Notification Provider. + +:::tip + +If you’re interested in using SendGrid to send Notifications, you can use the [SendGrid](../../../add-plugins/sendgrid.mdx) plugin instead of using your own. + +::: + +Adding a Notification Provider is as simple as creating a [Service](../services/create-service.md) file in `src/services`. A Notification Provider is essentially a Service that extends the `NotificationService` from `medusa-interfaces`. + +:::info + +Notification Providers are loaded and installed at the server startup. + +::: + +After creating the Notification Provider Service, you must create a [Subscriber](../subscribers/create-subscriber.md) that subscribes the Notification Provider to specific events. + +## Prerequisites + +Before you start creating a Notification Provider, you need to install a [Medusa server](../../../quickstart/quick-start.md). + +You also need to install and configure Redis. You can check out the documentation “[Set Up Your Development Environment](../../../tutorial/0-set-up-your-development-environment.mdx)” for help. + +## Create a Notification Provider + +The first step to creating a Notification Provider is to create a file in `src/services` with the following content: + +```jsx +import { NotificationService } from "medusa-interfaces"; + +class EmailSenderService extends NotificationService { + +} + +export default EmailSenderService; +``` + +Where `EmailSenderService` is the name of your Notification Provider Service. + +Notification Providers must extend `NotificationService` from `medusa-interfaces`. + +:::info + +Following the naming convention of Services, the name of the file should be the slug name of the Notification Provider, and the name of the class should be the camel case name of the Notification Provider suffixed with “Service”. In the example above, the name of the file should be `email-sender.js`. You can learn more in the [service documentation](../services/create-service.md). + +::: + +### identifier + +Notification Provider Services must have a static property `identifier`. + +The `NotificationProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the Service class is used when the Notification Provider is created in the database. + +The value of this property is also used later when you want to subscribe the Notification Provider to events in a Subscriber. + +For example, in the class you created in the previous code snippet you can add the following property: + +```jsx +static identifier = "email-sender"; +``` + +### constructor + +You can use the `constructor` of your Notification Provider to have access to different Services in Medusa through dependency injection. + +You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the Service. + +Additionally, if you’re creating your Notification Provider as an external plugin to be installed on any Medusa server and you want to access the options added for the plugin, you can access it in the constructor. The options are passed as a second parameter. + +:::info + +You can learn more about plugins and how to create them in the [Plugins](../../../guides/plugins.md) documentation. + +::: + +Continuing on with the previous example, if you want to use the [`OrderService`](../../../references/services/classes/OrderService.md) later when sending notifications, you can inject it into the constructor: + +```jsx +constructor({ orderService }, options) { + //you can access options here in case you're + //using a plugin + super(); + + this.orderService = orderService; +} +``` + +### sendNotification + +When an event is triggered that your Notification Provider is registered as a handler for, the [`NotificationService`](../../../references/services/classes/NotificationService.md) in Medusa’s core will execute the `sendNotification` method of your Notification Provider. + +In this method, you can perform the necessary operation to send the Notification. Following the example above, you can send an email to the customer when they place an order. + +This method receives 3 parameters: + +1. `eventName`: This is the name of the event that was triggered. For example, `order.placed`. +2. `eventData`: This is the data payload of the event that was triggered. For example, if the `order.placed` event is triggered, the `eventData` object contains the property `id` which is the ID of the order that was placed. +3. `attachmentGenerator`: If you’ve previously attached a generator to the `NotificationService` using the [`registerAttachmentGenerator`](../../../references/services/classes/NotificationService.md#registerattachmentgenerator) method, you have access to it here. You can use the `attachmentGenerator` to generate on-demand invoices or other documents. The default value of this parameter is null. + +:::info + +You can learn more about what events are triggered in Medusa and their data payload in the [Events List](../subscribers/events-list.md) documentation. + +::: + +This method must return an object containing two properties: + +1. `to`: a string that represents the receiver of the Notification. For example, if you sent an email to the customer then `to` is the email address of the customer. In other cases, it might be a phone number or a username. +2. `data`: an object that contains the data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object might include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data. + +Continuing with the previous example you can have the following implementation of the `sendNotification` method: + +```jsx +async sendNotification(eventName, eventData, attachmentGenerator) { + if (eventName === 'order.placed') { + //retrieve order + const order = await this.orderService.retrieve(eventData.id); + //TODO send email + + console.log('Notification sent'); + return { + to: order.email, + data: { + //any data necessary to send the email + //for example: + subject: 'You placed a new order!', + items: order.items + } + }; + } +} +``` + +In this code snippet, you check first if the event is `order.placed`. This can be helpful if you’re handling multiple events using the same Notification Provider. + +You then retrieve the order using the ID and send the email. Here, the logic related to sending the email is not implemented as it is generally specific to your Notification Provider. + +Finally, you return an object with the `to` property set to the customer email and the `data` property is an object that contains data necessary to send the email such as a `subject` or `items`. + +:::note + +The `to` and `data` properties are used in the `NotificationService` in Medusa’s core to create a new `Notification` record in the database. You can learn more about the `Notification` entity in the [Architecture Overview](overview.md#notification-entity-overview) documentation. + +::: + +### resendNotification + +Using the [Resend Notification endpoint](https://docs.medusajs.com/api/admin/notification/resend-notification), an admin user can resend a Notification to the customer. The [`NotificationService`](../../../references/services/classes/NotificationService.md) in Medusa’s core then executes the `resendNotification` method in your Notification Provider. + +This method receives 3 parameters: + +1. `notification`: This is the original Notification record that was created after you sent the notification with `sendNotification`. You can get an overview of the entity and its attributes in the [architecture overview](overview.md#notification-entity-overview), but most notably it includes the `to` and `data` attributes which are populated originally using the `to` and `data` properties of the object you return in `sendNotification`. +2. `config`: In the Resend Notification endpoint you may specify an alternative receiver of the notification using the `to` request body parameter. For example, you may want to resend the order confirmation email to a different email. If that’s the case, you have access to it in the `config` parameter object. Otherwise, `config` will be an empty object. +3. `attachmentGenerator`: If you’ve previously attached a generator to the Notification Service using the [`registerAttachmentGenerator`](../../../references/services/classes/NotificationService.md#registerattachmentgenerator) method, you have access to it here. You can use the `attachmentGenerator` to generate on-demand invoices or other documents. The default value of this parameter is null. + +Similarly to the `sendNotification` method, this method must return an object containing two properties: + +1. `to`: a string that represents the receiver of the Notification. You can either return the same `to` available in the `notification` parameter or the updated one in the `config` parameter. +2. `data`: an object that contains the data used to send the Notification. You can either return the same `data` in the `notification` parameter or make any necessary updates to it. + +Continuing with the previous example you can have the following implementation of the `resendNotification` method: + +```jsx +resendNotification(notification, config, attachmentGenerator) { + //check if the receiver of the notification should be changed + const to = config.to ? config.to : notification.to; + + //TODO resend the notification using the same data that is saved under notification.data + + console.log('Notification resent'); + return { + to, + data: notification.data //you can also make changes to the data + } +} +``` + +In the above snippet, you check if the `to` should be changed by checking if the `config` parameter has a `to` property. Otherwise, you keep the same `to` address stored in the `notification` parameter. + +You then resend the email. Here, the logic related to sending the email is not implemented as it is generally specific to your Notification Provider. + +Finally, you return an object with the `to` property set to the email (either new or old) and the `data` property is the same data used before to send the original notification. you can alternatively make any changes to the data. + +:::note + +The `to` and `data` properties are used in the `NotificationService` in Medusa’s core to create a new `Notification` record in the database. No changes are made to the original `Notification` record created after the `sendNotification` method. This new record is associated with the original `Notification` record using the `parent_id` attribute in the entity. You can learn more about the `Notification` entity in the [Architecture Overview](overview.md#notification-entity-overview) documentation. + +::: + +## Create a Subscriber + +After creating your Notification Provider Service, you must create a Subscriber that registers this Service as a notification handler of events. + +:::note + +This section will not cover the basics of Subscribers. You can read the [Subscribers](../subscribers/create-subscriber.md) documentation to learn more about them and how to create them. + +::: + +Following the previous example, to make sure the `email-sender` Notification Provider handles the `order.placed` event, create the file `src/subscribers/notification.js` with the following content: + +```jsx +class NotificationSubscriber { + constructor({ notificationService }) { + notificationService.subscribe('order.placed', 'email-sender'); + } +} + +export default NotificationSubscriber; +``` + +This subscriber accesses the `notificationService` using dependency injection. The `notificationService` contains a `subscribe` method that accepts 2 parameters. The first one is the name of the event to subscribe to, and the second is the identifier of the Notification Provider that is subscribing to that event. + +:::tip + +Notice that the value of the `identifier` static property defined in the `EmailSenderService` is used to register the Notification Provider to handle the `order.placed` event. + +::: + +## Test Sending Notifications with your Notification Provider + +Make sure you've configured Redis with your Medusa server as explained in the Prerequisites section and that the Redis service is running. + +Then, start by running your Medusa server: + +```bash +npm run start +``` + +Then, place an order either using the [REST APIs](https://docs.medusajs.com/api/store/auth) or using the storefront. + +:::tip + +If you don’t have a storefront installed you can get started with either our [Next.js](../../../starters/nextjs-medusa-starter.md) or [Gatsby](../../../starters/gatsby-medusa-starter.md) starter storefronts in minutes. + +::: + +After placing an order, you can see in your console the message “Notification Sent”. If you added your own notification sending logic, you should receive an email or alternatively the type of notification you’ve set up. + +## Test Resending Notifications with your Notification Provider + +To test resending a notification, first, retrieve the ID of the notification you just sent using the [List Notifications admin endpoint](https://docs.medusajs.com/api/admin/notification/list-notifications). You can pass as a body parameter the `to` or `event_name` parameters to filter out the notification you just sent. + +:::tip + +You must be authenticated as an admin user before sending this request. You can use the [Authenticate a User](https://docs.medusajs.com/api/admin/auth/) endpoint to get authenticated. + +::: + +![List Notifications Request](https://i.imgur.com/iF1rZX1.png) + +Then, send a request to the [Resend Notification](https://docs.medusajs.com/api/admin/notification/resend-notification) endpoint using the ID retrieved from the previous request. You can pass the `to` parameter in the body to change the receiver of the notification. You should see the message “Notification Resent” in your console and if you implemented your own logic for resending the notification it will be resent. + +![Resend Notifications Request](https://i.imgur.com/0zFfPed.png) + +This request returns the same notification object as the List Notifications endpoint, but it now has a new object in the `resends` array. This is the resent notification. If you supplied a `to` parameter in the request body, you should see its value in the `to` property of the resent notification object. + +## What’s Next 🚀 + +- Check out the [list of events](../subscribers/events-list.md) you can listen to. +- Check out the [SendGrid](../../../add-plugins/sendgrid.mdx) plugin for easy integration of email notifications. +- Learn how to [create your own plugin](../../../guides/plugins.md). +- Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md). diff --git a/docs/content/advanced/backend/notification/overview.md b/docs/content/advanced/backend/notification/overview.md index 68426e450e..b2ed328272 100644 --- a/docs/content/advanced/backend/notification/overview.md +++ b/docs/content/advanced/backend/notification/overview.md @@ -10,39 +10,35 @@ The Notification architecture is made up of 2 main components: the Notification ## Notification Provider -### Overview - A Notification Provider is a provider that handles sending and resending of notifications. You can either create and integrate your own provider or install a Notification Provider through a third-party plugin. An example of a notification provider is SendGrid. When an order is placed, the SendGrid plugin sends an email to the customer. -### How it is Created +### How Notification Provider is Created -A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a service file in your Medusa server. +A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a Service file in your Medusa server. As a developer, you mainly work with the Notification Provider when integrating a third-party service that handles notifications in Medusa. When you run your Medusa server, the Notification Provider is registered on your server if it isn’t already. This means that it will be inserted into the `notification_provider` table in your database. -### Entity Overview +### NotificationProvider Entity Overview The `NotificationProvider` entity only has 2 attributes: `id` and `is_installed`. -`id` is the value of the static property `identifier` defined inside the notification service class. +`id` is the value of the static property `identifier` defined inside the notification Service class. `is_installed` indicates whether the Notification Provider is installed or not. When you install a Notification Provider, the value of this attribute is `true`. -If you installed a Notification provider and then removed the service files or plugin that registered the Notification Provider, the Notification Provider remains in your database, but the value of the `is_installed` field changes to `false`. +If you installed a Notification provider and then removed the Service files or plugin that registered the Notification Provider, the Notification Provider remains in your database, but the value of the `is_installed` field changes to `false`. ## Notification -### Overview - A notification is a form of an alert sent to the customers or users to inform them of an action that has occurred. For example, if an order is placed, the notification, in this case, can be an email that confirms their order and lists the order details. Notifications can take on other forms such as an SMS or a Slack message. -### How it is Created +### How Notification is Created Notifications are created in the `NotificationService` class in Medusa’s core after the Notification has been handled by the Notification Provider. @@ -50,11 +46,11 @@ The data and additional details that the Notification Provider returns to the `N A Notification also represents a resent notification. So, when a notification is resent, a new one is created that references the original Notification as a parent. This Notification is also created by the `NotificationService` class. -### Entity Overview +### Notification Entity Overview The 2 most important properties in the `Notification` entity are the `to` and `data` properties. -The `to` property is a string that represents the receiver of the Notification. For example, if the Notification was sent to an email address, the `to` property holds the email address the Notification was sent to. +The `to` property is a string that represents the receiver of the Notification. For example, if the Notification was sent to an email address, the `to` property holds the email address the Notification was sent to. The `to` property can alternatively be a phone number or a chat username. It depends on the Notification Provider and how it sends the Notification. @@ -86,7 +82,7 @@ An example of a flow that can be implemented using Medusa's Notification API is ## What’s Next 🚀 - Learn how to create your own Notification Provider. -- [Check out the list of events in Medusa.](../subscribers/events-list.md) -- [Check the `NotificationService` API reference for more details on how it works.](../../../references/services/classes/NotificationService.md) -- [Check out the SendGrid Notification plugin.](../../../add-plugins/sendgrid.mdx) +- Check out the [list of events](../subscribers/events-list.md) in Medusa. +- Check the [`NotificationService`](../../../references/services/classes/NotificationService.md) API reference for more details on how it works. +- Check out the [SendGrid](../../../add-plugins/sendgrid.mdx) Notification plugin. - Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md) in Medusa. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index f2208b538d..0e9fc6de61 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -193,6 +193,11 @@ module.exports = { { type: "doc", id: "advanced/backend/notification/overview" + }, + { + type: "doc", + id: "advanced/backend/notification/how-to-create-notification-provider", + label: "Create a Notification Provider" } ] }, From ef344bb2556021c003339c3c9c97fbc504b67981 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 6 Jun 2022 19:12:40 +0300 Subject: [PATCH 12/34] Use npm2yarn where missing --- docs/content/add-plugins/minio.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/add-plugins/minio.md b/docs/content/add-plugins/minio.md index 77a1f16ceb..336484e410 100644 --- a/docs/content/add-plugins/minio.md +++ b/docs/content/add-plugins/minio.md @@ -76,7 +76,7 @@ You will not be able to access the Secret Key after closing the pop-up. So, make In the directory of your Medusa server, run the following command to install the MinIO plugin: -```bash +```bash npm2yarn npm install medusa-file-minio ``` From 8a3e4ba355f2f213d57de1388e6ca6f7e9ca063a Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 6 May 2022 15:45:05 +0300 Subject: [PATCH 13/34] added integration --- www/docs/docusaurus.config.js | 6 ++++++ www/docs/package.json | 1 + www/docs/yarn.lock | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/www/docs/docusaurus.config.js b/www/docs/docusaurus.config.js index ce307ea1b1..bafacec1c6 100644 --- a/www/docs/docusaurus.config.js +++ b/www/docs/docusaurus.config.js @@ -23,6 +23,12 @@ module.exports = { systemvars: true, // Set to true if you would rather load all system variables as well (useful for CI purposes) }, ], + [ + "docusaurus-plugin-segment", + { + apiKey: process.env.SEGMENT_API_KEY + } + ] ], themeConfig: { colorMode: { diff --git a/www/docs/package.json b/www/docs/package.json index b5d7c5e27a..f0de8815fd 100644 --- a/www/docs/package.json +++ b/www/docs/package.json @@ -23,6 +23,7 @@ "@svgr/webpack": "6.2.1", "algoliasearch-helper": "^3.8.2", "clsx": "^1.1.1", + "docusaurus-plugin-segment": "^1.0.3", "docusaurus2-dotenv": "^1.4.0", "file-loader": "^6.2.0", "lodash": "^4.17.21", diff --git a/www/docs/yarn.lock b/www/docs/yarn.lock index 2558b23f9c..6f63e596e0 100644 --- a/www/docs/yarn.lock +++ b/www/docs/yarn.lock @@ -1798,6 +1798,25 @@ resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== +"@ndhoule/each@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@ndhoule/each/-/each-2.0.1.tgz#bbed372a603e0713a3193c706a73ddebc5b426a9" + integrity sha1-u+03KmA+BxOjGTxwanPd68W0Jqk= + dependencies: + "@ndhoule/keys" "^2.0.0" + +"@ndhoule/keys@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@ndhoule/keys/-/keys-2.0.0.tgz#3d64ae677c65a261747bf3a457c62eb292a4e0ce" + integrity sha1-PWSuZ3xlomF0e/OkV8YuspKk4M4= + +"@ndhoule/map@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@ndhoule/map/-/map-2.0.1.tgz#f5ca0a47424ea67f46e2a6d499b9e9bc886aefa8" + integrity sha1-9coKR0JOpn9G4qbUmbnpvIhq76g= + dependencies: + "@ndhoule/each" "^2.0.1" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1824,6 +1843,13 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== +"@segment/snippet@^4.13.2": + version "4.15.3" + resolved "https://registry.yarnpkg.com/@segment/snippet/-/snippet-4.15.3.tgz#ac829ec4570b249f559756293f4736e434885de7" + integrity sha512-75kVTYaQGYMkwVjJvCLLOlzxV8jCDxvKG68U88joo/rBx95SIXETcjUmIXF6A7SFRCgz83B+zrZbo+JYsmHkig== + dependencies: + "@ndhoule/map" "^2.0.1" + "@sideway/address@^4.1.3": version "4.1.3" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" @@ -3628,6 +3654,13 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +docusaurus-plugin-segment@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/docusaurus-plugin-segment/-/docusaurus-plugin-segment-1.0.3.tgz#d32ec8ace8625837dee650f853bc89ae2221206a" + integrity sha512-9DqebTx9TqjujCnB22qEeCm8NGJUAH7VAKLAa20/CyfSSrs+khTQI0FmzEALtiCqKNO1D3GWm3VvE4gqbuGqnw== + dependencies: + "@segment/snippet" "^4.13.2" + docusaurus2-dotenv@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/docusaurus2-dotenv/-/docusaurus2-dotenv-1.4.0.tgz#9ab900e29de9081f9f1f28f7224ff63760385641" From 1af5a83e199114700151999fd91e70739ed3957c Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 6 May 2022 15:53:48 +0300 Subject: [PATCH 14/34] add segment for API reference --- www/reference/gatsby-config.js | 10 +++++++++- www/reference/package.json | 1 + www/reference/yarn.lock | 5 +++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/www/reference/gatsby-config.js b/www/reference/gatsby-config.js index 570d1dcc7e..a6bea57867 100644 --- a/www/reference/gatsby-config.js +++ b/www/reference/gatsby-config.js @@ -71,7 +71,15 @@ module.exports = { options: { output: '/api/sitemap' } - } + }, + { + resolve: `gatsby-plugin-segment-js`, + options: { + prodKey: process.env.SEGMENT_API_KEY, + devKey: process.env.SEGMENT_API_KEY_DEV, + trackPage: true, + } + }, // `gatsby-plugin-preact`, // { // resolve: `gatsby-source-openapi-aggregate`, diff --git a/www/reference/package.json b/www/reference/package.json index 32aca47836..bf9e72b95e 100644 --- a/www/reference/package.json +++ b/www/reference/package.json @@ -29,6 +29,7 @@ "gatsby-plugin-preact": "^5.9.0", "gatsby-plugin-react-helmet": "^3.3.12", "gatsby-plugin-sitemap": "^5.15.0", + "gatsby-plugin-segment-js": "^3.7.1", "gatsby-plugin-theme-ui": "^0.10.1", "gatsby-remark-autolink-headers": "^4.6.0", "gatsby-source-filesystem": "^3.9.0", diff --git a/www/reference/yarn.lock b/www/reference/yarn.lock index aa55232e5b..58e938ef33 100644 --- a/www/reference/yarn.lock +++ b/www/reference/yarn.lock @@ -5452,6 +5452,11 @@ gatsby-plugin-sitemap@^5.15.0: minimatch "^3.1.2" sitemap "^7.0.0" +gatsby-plugin-segment-js@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/gatsby-plugin-segment-js/-/gatsby-plugin-segment-js-3.7.1.tgz#3432d59be0e45ee82f36a42cff060af220a0dd68" + integrity sha512-zAsjRrF77Kih7YRUJVp84thnODbzjDE44H6ePtdQfLVyPWiJj3IpS/WAwyRg9Cu3+FciFAT8WEjfJ2I02V0sUw== + gatsby-plugin-theme-ui@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/gatsby-plugin-theme-ui/-/gatsby-plugin-theme-ui-0.10.1.tgz#d1ac7f4f1c4bf187694110a8670f0bb3ff470ad2" From c6b857251a3dcfe28e9b04876979296857fd37de Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 16 Jun 2022 16:00:07 +0300 Subject: [PATCH 15/34] fix double segment --- www/reference/gatsby-config.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/www/reference/gatsby-config.js b/www/reference/gatsby-config.js index bbfbf8da5b..7438986f8a 100644 --- a/www/reference/gatsby-config.js +++ b/www/reference/gatsby-config.js @@ -80,14 +80,6 @@ module.exports = { output: '/api/sitemap' } }, - { - resolve: `gatsby-plugin-segment-js`, - options: { - prodKey: process.env.SEGMENT_API_KEY, - devKey: process.env.SEGMENT_API_KEY_DEV, - trackPage: true, - } - }, // `gatsby-plugin-preact`, // { // resolve: `gatsby-source-openapi-aggregate`, From b3abf02a219a615dbaf771a5237af96a1269429f Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 11 May 2022 18:55:39 +0300 Subject: [PATCH 16/34] updated frontend checkout flow --- .../frontend-payment-flow-in-checkout.md | 117 ------- .../payment/how-to-create-payment-provider.md | 2 +- .../advanced/backend/payment/overview.md | 2 +- .../how-to-implement-checkout-flow.mdx | 329 ++++++++++++++++++ www/docs/sidebars.js | 15 +- 5 files changed, 342 insertions(+), 123 deletions(-) delete mode 100644 docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md create mode 100644 docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx diff --git a/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md b/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md deleted file mode 100644 index eeb1ba83a9..0000000000 --- a/docs/content/advanced/backend/payment/frontend-payment-flow-in-checkout.md +++ /dev/null @@ -1,117 +0,0 @@ -# Frontend Payment Flow in Checkout - -## Introduction -The purpose of this guide is to describe a checkout flow in Medusa. It is assumed that you've completed our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or [Tutorial](https://docs.medusajs.com/tutorial/set-up-your-development-environment) and are familiar with the technologies we use in our stack. Additionally, having an understanding of the [core API](https://docs.medusajs.com/api/store/auth) would serve as a great foundation for this walkthrough. - -:::note - -All code snippets in the following guide, use the JS SDK distributed through **npm**. To install it, run: - -```bash npm2yarn -npm install @medusajs/medusa-js -``` - -::: - -## Glossary -- **Cart**: The Cart contains all the information needed for customers to complete an Order. In the Cart customers gather the items they wish to purchase, they add shipping and billing details and complete payment information. -- **LineItem**: Line Items represent an expense added to a Cart. Typically this will be a Product Variant and a certain quantity of the same variant. Line Items hold descriptive fields that help communicate its contents and price. -- **PaymentSession**: A Payment Session is a Medusa abstraction that unifies the APIs of multiple payment gateways. Payment Sessions are _initialized_ when the customer begins a checkout and are _authorized_ prior to an Order being placed. Payment Sessions are created based on the available Payment Providers configured in a Cart's region. -- **ShippingOption**: A Shipping Option represents a way in which an Order can be fulfilled. Shipping Options have a price and are associated with a Fulfillment Provider that will handle the shipment later in the Order flow. Once a customer selects a Shipping Option it becomes a Shipping Method. -- **ShippingMethod**: Shipping Methods are unique to each Cart and can thereby hold either overwrites for fields in a Shipping Option (e.g. price) or additional details (e.g. an id representing a parcel pickup location). - -## Checkout flow -To create an order from a cart, we go through the following flow. - -:::note - -At this point, it assumed that the customer has created a cart, added items and is now at the initial step of the checkout flow. - -::: - -### Initializing the checkout -The first step in the flow is to _initialize_ the configured Payment Sessions for the Cart. If you are using the `medusa-starter-default` starter, this call will result in the `cart.payment_sessions` array being filled with one Payment Session for the manual payment provider. - -```javascript -const { cart } = await medusa.carts.createPaymentSessions("cart_id") -``` - -To give a more real life example, it is assumed that `medusa-payment-stripe` is installed in your project in which case the call will result in a [Stripe PaymentIntent](https://stripe.com/docs/api/payment_intents) being created. The unique provider data for each Payment Session can be found in the Payment Session's `data` field; this data can be used in front end implementations e.g. if using Stripe Elements the `client_secret` can be retrieved through `session.data.client_secret`. - -### Adding customer information -After initializing the checkout flow, you would typically have one big step or several smaller steps for gathering user information; email, address, country, and more. To store this data you may update the cart with each of field or all fields at the same time. - -```javascript -const { cart } = await medusa.carts.update("cart_id", { - email: "lebron@james.com", - shipping_address: { - first_name: "", - last_name: "", - ... - } -}) -``` - -### Selecting payment provider -This step is only applicable if you have multiple Payment Sessions installed in your project. In cases where only one Payment Provider is configured the Payment Session will be preselected. In all other cases your implementations should call: - -```javascript -const { cart } = await medusa.carts.setPaymentSession("cart_id", { - provider_id: "stripe" -}) -``` - -### Choosing a shipping method -Before reaching the payment step, you would typically require the customer to choose a Shipping Method from a number of options. In Medusa you can set rules that must be met for a Shipping Option to be available for a Cart. To get the available shipping options for a Cart you should call: -```javascript -const { shipping_options } = await medusa.carts.listCartOptions("cart_id") -``` - -Choosing a Shipping Option, will create a Shipping Method and attach it to the Cart. The second argument to the function in the snippet below holds the id of the selected option. -```javascript= -const { cart } = await medusa.carts.addShippingMethod("cart_id", { option_id: "option_id"}) -``` - -### Collecting payment details -The following snippet shows how we use Stripe to collect payment details from the customer. Note that we are using the `client_secret` from the Stripe PaymentIntent in `data` on the payment session as this is required by Stripe Elements. -```jsx -import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js"; - -... - -const stripe = useStripe(); -const elements = useElements(); - - -const handleSubmit = () => { - ... - const { paymentIntent, error } = await stripe.confirmCardPayment( - cart.payment_session.data.client_secret, - { - payment_method: { - card: elements.getElement(CardElement), - }, - } - ); - ... -} - -return -``` -After collecting the payment details, the customer can complete the checkout flow. - -### Completing the cart -When all relevant customer information has been captured, your implementation should proceed to the final step: completing the cart. -```javascript -const { order } = await medusa.carts.complete("cart_id") -``` -If all information is collected correctly throughout the checkout flow, the call will place an Order based on the details gathered in the Cart. - -## Summary -You now have a solid foundation for creating your own checkout flows using Medusa. Throughout this guide, we've used Stripe as a Payment Provider. Stripe is one of the most popular providers and we have an official plugin that you can easily install in your project. - -## What's next? -See the checkout flow, explained in the previous sections, in one of our frontend starters: -- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa) -- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa) - diff --git a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md index 8037f3374f..304446068e 100644 --- a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md +++ b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md @@ -384,4 +384,4 @@ async retrieveSavedMethods(customer) { ## What’s Next 🚀 - Check out the Payment Providers for [Stripe](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-stripe) and [PayPal](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-payment-paypal) for implementation examples. -- Learn more about the [frontend checkout flow](./frontend-payment-flow-in-checkout.md). +- Learn more about the [frontend checkout flow](./../../storefront/how-to-implement-checkout-flow.mdx). diff --git a/docs/content/advanced/backend/payment/overview.md b/docs/content/advanced/backend/payment/overview.md index a34c19e4e3..2320bc342c 100644 --- a/docs/content/advanced/backend/payment/overview.md +++ b/docs/content/advanced/backend/payment/overview.md @@ -126,5 +126,5 @@ This prevents any payment issues from occurring with the customers and allows fo ## What’s Next 🚀 -- [Check out how the checkout flow is implemented on the frontend.](./frontend-payment-flow-in-checkout.md) +- [Check out how the checkout flow is implemented on the frontend.](./../../storefront/how-to-implement-checkout-flow.mdx) - Check out payment plugins like [Stripe](../../../add-plugins/stripe.md), [Paypal](/add-plugins/paypal), and [Klarna](../../../add-plugins/klarna.md). diff --git a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx new file mode 100644 index 0000000000..724fa3c7bf --- /dev/null +++ b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx @@ -0,0 +1,329 @@ +# How to Implement Checkout Flow + +This document will guide you through the steps needed to implement the checkout flow in a Medusa storefront, including steps related to adding a custom payment provider. + +## Overview + +A checkout flow is composed of the necessary steps to allow a customer to perform a successful checkout. It’s generally made up of 2 primary steps: the shipping and payment steps. + +This document will take you through the general process of a checkout flow. You should follow along with this document if you’re creating a custom storefront, if you’re adding a custom payment provider, or if you’re just interested in learning more about how checkout works in Medusa. + +:::note + +It’s recommended to go through the [Shipping Architecture Overview](../backend/shipping/overview.md) and [Payment Architecture Overview](../backend/payment/overview.md) first to have a better understanding of Medusa’s architecture. + +::: + +## Prerequisites + +This document assumes you’ve already taken care of the add-to-cart flow. So, you should have a [cart created](https://docs.medusajs.com/api/store/cart/create-a-cart) for the customer with at least [one product in it](https://docs.medusajs.com/api/store/cart/add-a-line-item). + +To follow along with this tutorial, you can make use of the [Medusa JS Client](https://www.npmjs.com/package/@medusajs/medusa-js). You can install it with this command: + +```bash npm2yarn +npm install @medusajs/medusa-js +``` + +There’s also an alternative approach in this document using [JavaScript’s Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) in case you’re unable to use Medusa’s JS Client. Make sure to replace `` in those examples with your server URL. + +## Shipping Step + +In this step, the customer generally enters their shipping info, then chooses the available shipping option based on the entered info. + +### Add Shipping Address + +After the customer enters their shipping address information, you must send a `POST` request to the [Update a Cart](https://docs.medusajs.com/api/store/cart/update-a-cart) API endpoint passing it the new shipping address: + + + + +```jsx +medusa.carts.update(cart.id, { + shipping_address: { + company, + first_name, + last_name, + address_1, + address_2, + city, + country_code, + province, + postal_code, + phone + }, +}).then((response) => { + //updated cart is in response.cart +}) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}`, { + method: 'POST', + body: JSON.stringify({ + shipping_address: { + company, + first_name, + last_name, + address_1, + address_2, + city, + country_code, + province, + postal_code, + phone + }, + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can have access to the updated cart in `response.cart`, which now has the shipping address you added in `response.cart.shipping_address`. + +### List Shipping Options + +After updating the cart with the customer’s address, the list of available [shipping options](../backend/shipping/overview.md#shipping-option) for that cart might change. So, you should retrieve the updated list of options by sending a `GET` request to the [Retrieve Shipping Options for Cart API](https://docs.medusajs.com/api/store/shipping-option/retrieve-shipping-options-for-cart) endpoint: + + + + +```jsx +medusa.shippingOptions.listCartOptions(cart.id) + .then((response) => { + //shipping options available in response.shipping_options + }) +``` + + + + +```jsx +fetch(`/store/shipping-options/${cart.id}`) + .then((response) => response.json()) + .then((response) => { + //shipping options available in response.shipping_options + }) +``` + + + + +You can access all shipping options available with their info in `response.shipping_options` which is an array of [shipping options](https://docs.medusajs.com/api/store/shipping-option). Typically you would display those options to the customer to choose from. + +### Choose Shipping Option + +Once the customer chooses one of the available shipping options, send a `POST` request to the [Add a Shipping Method](https://docs.medusajs.com/api/store/cart/add-a-shipping-method) API endpoint. This will create a [shipping method](../backend/shipping/overview.md#shipping-method) based on the shipping option chosen and will associate it with the customer’s cart: + + + + +```jsx +medusa.carts.addShippingMethod(cart.id, { + option_id: shipping_option.id //shipping_option is the select option +}).then((response) => { + //updated cart is in response.cart + }) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/shipping-methods`, { + method: 'POST', + body: JSON.stringify({ + option_id: shipping_option.id //shipping_option is the select option + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can have access to the updated cart in `response.cart`, which now has one item in the array value of the property `shipping_methods`. + +## Payment Step + +In this step, the customer generally chooses a payment method to complete their purchase. The implementation of payment providers is done differently for each provider, so this section will just show the general steps you should follow when implementing this step. + +### Initialize Payment Sessions + +When the page opens and before the payment providers are displayed to the customer to choose from, you must initialize the [payment sessions](./../backend/payment/overview.md#payment-session) for the current cart. Each payment provider will have a payment session associated with it. These payment sessions will be used later when the customer chooses the payment provider they want to complete their purchase with. + +To initialize the payment sessions, send a `POST` request to the [Initialize Payment Sessions](https://docs.medusajs.com/api/store/cart/initialize-payment-sessions) API endpoint: + + + + +```jsx +medusa.carts.createPaymentSessions(cart.id) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/payment-sessions`, { + method: 'POST' +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can then access the initialized payment sessions under the `payment_sessions` array in `response.cart`. + +### Select Payment Session + +When the customer chooses the payment provider they want to complete purchase with, you should select the payment session associated with that payment provider. To do that, send a `POST` request to the [Select a Payment Session](https://docs.medusajs.com/api/store/cart/select-a-payment-session) API endpoint: + + + + +```jsx +medusa.carts.setPaymentSession(cart.id, { + provider_id: payment_session.provider_id //payment_session is the session chosen by the customer +}).then((response) => { + //updated cart is in response.cart +}) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/payment-session`, { + method: 'POST', + body: JSON.stringify({ + provider_id: payment_session.provider_id //payment_session is the session chosen by the customer + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can then access the selected payment session in `response.cart.payment_session`. + +:::tip + +If you have one payment provider or if only one payment provider is available for the current cart, its payment session will be automatically selected in the “[Initialize Payment Session](#initialize-payment-sessions)” step and this step becomes unnecessary. You can check whether there is a payment session selected or not by checking whether `cart.payment_session` is `null` or not. + +::: + +### Update Payment Session + +This step is optional and is only necessary for some payment providers. As mentioned in the [Payment Architecture](../backend/payment/overview.md#overview) documentation, the `PaymentSession` model has a `data` attribute that holds any data required for the Payment Provider to perform payment operations such as capturing payment. + +If you need to update that data at any point before the purchase is made, send a request to [Update a Payment Session](https://docs.medusajs.com/api/store/cart/update-a-payment-session) API endpoint passing it the updated data object: + + + + +```jsx +medusa.carts.updatePaymentSession(cart.id, cart.payment_session.provider_id, { + data: { + //pass any data you want to add in the `data` attribute + //for example: + "test": true + } +}).then((response) => { + //updated cart is in response.cart +}) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/payment-sessions/${cart.payment_session.provider_id}`, { + method: 'POST', + body: JSON.stringify({ + data: { + //pass any data you want to add in the `data` attribute + //for example: + "test": true + } + }), + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //updated cart is in response.cart + }) +``` + + + + +You can have access to the updated data in the payment session in `response.cart.payment_session.data`. + +### Complete Cart + +The last step is to place the order by completing the cart. When you complete the cart, your Medusa server will try to authorize the payment first, then place the order if the authorization is successful. So, you should perform any necessary action with your payment provider first to make sure the authorization is successful when you send the request to complete the cart. + +To complete a cart, send a `POST` request to the [Complete a Cart](https://docs.medusajs.com/api/store/cart/complete-a-cart) API endpoint: + + + + +```jsx +medusa.carts.complete(cart.id) + .then((response) => { + //order details is in response.data + }) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/complete`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } +}).then((response) => response.json()) + .then((response) => { + //order details is in response.data + }) +``` + + + + +If the order is placed successfully, you can access the order data in `response.data` and the value for `response.type` is `order`. Otherwise, `response.data` holds the cart details and `response.type` is `cart`. + +## What’s Next 🚀 + +- Check out available plugins for popular payment providers such as [Stripe](../../add-plugins/stripe.md) and [PayPal](/add-plugins/paypal.md). +- Learn more about the [Payment](../backend/payment/overview.md) and [Shipping](../backend/shipping/overview.md) Architectures. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 7e2009c5cc..85783792dd 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -174,10 +174,6 @@ module.exports = { type: "doc", id: "advanced/backend/payment/how-to-create-payment-provider", }, - { - type: "doc", - id: "advanced/backend/payment/frontend-payment-flow-in-checkout", - }, ] }, { @@ -210,6 +206,17 @@ module.exports = { ] }, ] + }, + { + type: "category", + label: "Storefront", + collapsed: true, + items: [ + { + type: "doc", + id: "advanced/storefront/how-to-implement-checkout-flow", + }, + ] } ] }, From 4ae0aca827c48cfebf7947ebd22ad2eb3d5ad973 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 2 Jun 2022 10:36:04 +0300 Subject: [PATCH 17/34] added documentation for entities --- docs/content/advanced/backend/entities.md | 160 ++++++++++++++++++++++ www/docs/sidebars.js | 5 + 2 files changed, 165 insertions(+) create mode 100644 docs/content/advanced/backend/entities.md diff --git a/docs/content/advanced/backend/entities.md b/docs/content/advanced/backend/entities.md new file mode 100644 index 0000000000..95b45dea02 --- /dev/null +++ b/docs/content/advanced/backend/entities.md @@ -0,0 +1,160 @@ +# How to Create Entities + +In this document, you’ll learn about entities in Medusa and how you can create your own entity. + +## Overview + +Entities in medusa represent tables in the database as classes. An example of this would be the `Order` entity which represents the `order` table in the database. Entities provide a uniform way of defining and interacting with data retrieved from the database. + +Aside from Medusa’s core entities, you can also create your own entities to use in your Medusa server. Custom entities must reside in the `src/models` directory of your Medusa server. + +Entities are TypeScript files and they are based on [Typeorm’s Entities](https://typeorm.io/entities) and use Typeorm decorators. + +All entities must extend either the `BaseEntity` or `SoftDeletableEntity` classes. The `BaseEntity` class holds common columns including the `id`, `created_at`, and `updated_at` columns. + +The `SoftDeletableEntity` class extends the `BaseEntity` class and adds another column `deleted_at`. If an entity can be soft deleted, meaning that a row in it can appear to the user as deleted but still be available in the database, it should extend `SoftDeletableEntity`. + +## How to Create a Custom Entity + +### Prerequisites + +It’s recommended to create a `tsconfig.json` file in the root of your Medusa server with the following content: + +```jsx +{ + "compilerOptions": { + "experimentalDecorators": true + } +} +``` + +This will remove any errors that show up in your IDE related to experimental decorators. + +### Create the Entity + +To create an entity, create a TypeScript file in `src/models`. For example, here’s a `Post` entity defined in the file `src/models/post.ts`: + +```tsx +import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm"; +import { BaseEntity} from "@medusajs/medusa"; +import { generateEntityId } from "@medusajs/medusa/dist/utils" + +@Entity() +export class Post extends BaseEntity { + @Column({type: 'varchar'}) + title: string | null; + + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "post") + } +} +``` + +This entity has one column `title` defined. However, since it extends `BaseEntity` it will also have the `id`, `created_at`, and `updated_at` columns. + +Medusa’s core entities all have the following format for IDs: `_`. For example, an order might have the ID `order_01G35WVGY4D1JCA4TPGVXPGCQM`. + +To generate an ID for your entity that matches the IDs generated for Medusa’s core entities, you should add a `BeforeInsert` event handler. Then, inside that handler use Medusa’s utility function `generateEntityId` to generate the ID. It accepts the ID as a first parameter and the prefix as a second parameter. The `Post` entity IDs will be of the format `post_`. + +If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead: + +```tsx +import { SoftDeletableEntity } from "@medusajs/medusa"; + +@Entity() +export class Post extends SoftDeletableEntity { + //... +} +``` + +You can learn more about what decorators and column types you can use in [Typeorm’s documentation](https://typeorm.io/entities). + +### Create the Migration + +Additionally, you must create a migration for your entity. Migrations are used to update the database schema with new tables or changes to existing tables. + +You can learn more about Migrations, how to create them, and how to run them in the [Migration documentation](migrations.md). + +### Create a Repository + +Entities data can be easily accessed and modified using Typeorm [Repositories](https://typeorm.io/working-with-repository). To create a repository, create a file in `src/repositories`. For example, here’s a repository `PostRepository` that resides in `src/repositories/post.ts`: + +```tsx +import { EntityRepository, Repository } from "typeorm" + +import { Post } from "../models/post" + +@EntityRepository(Post) +export class PostRepository extends Repository { } +``` + +This repository is created for the `Post` and that is indicated using the decorator `@EntityRepository`. + +:::tip + +Be careful with your file names as it can cause unclear errors in Typeorm. Make sure all your file names are small letters for both entities and repositories to avoid any issues with file names. + +::: + +## Access Your Custom Entity + +:::note + +Before trying this step make sure that you’ve created and run your migrations. You also need to re-build your code using: + +```bash npm2yarn +npm run build +``` + +::: + +You can access your custom entity data in the database in services or subscribers using the repository. For example, here’s a service that lists all posts: + +```tsx +import { TransactionBaseService } from "medusa-interfaces"; + +class PostService extends TransactionBaseService { + constructor({ postRepository, manager }) { + super({ postRepository, manager }); + + this.postRepository = postRepository; + this.manager_ = manager; + } + + async list() { + const postRepository = this.manager_.getCustomRepository(this.postRepository); + return await postRepository.find(); + } +} + +export default PostService; +``` + +In the constructor, you can use dependency injection to get access to instances of services and repositories. Here, you initialize class fields `postRepository` and `manager`. The `manager` is a [Typeorm Entity Manager](https://typeorm.io/working-with-entity-manager). + +Then, in the method `list`, you can obtain an instance of the `PostRepository` using `this.manager_.getCustomRepository` passing it `this.postRepository` as a parameter. This lets you use [Custom Repositories with Typeorm](https://typeorm.io/custom-repository) to create custom methods in your repository that work with the data in your database. + +After getting an instance of the repository, you can then use [Typeorm’s Repository methods](https://typeorm.io/repository-api) to perform CRUD (Create, Read, Update, Delete) operations on your entity. + +If you need access to your entity in endpoints, you can then use the methods you define in the service. + +:::note + +This same usage of repositories can be done in subscribers as well. + +::: + +### Deleting Soft-Deletable Entities + +To delete soft-deletable entities that extend the `SoftDeletableEntity` class, you can use the repository method `softDelete` method: + +```tsx +await postRepository.softDelete(post.id); +``` + +## What’s Next 🚀 + +- Learn more about [Services](services/create-service.md) and how to use them. +- Learn how to create an endpoint for [storefront](endpoints/add-storefront.md) and [admin](endpoints/add-admin.md). +- Learn about [migrations](migrations.md). \ No newline at end of file diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 85783792dd..043f19b320 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -143,6 +143,11 @@ module.exports = { }, ] }, + { + type: "doc", + id: "advanced/backend/entities", + label: "Entities" + }, { type: "category", label: 'Shipping', From dcbc1e9f5a0caebbb182c7f9f28374559cda73ab Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 2 Jun 2022 19:05:04 +0300 Subject: [PATCH 18/34] added docs contribution guidelines --- CONTRIBUTING.md | 2 + docs/content/contribution-guidelines.md | 112 ++++++++++++++++++++++++ www/docs/sidebars.js | 5 ++ 3 files changed, 119 insertions(+) create mode 100644 docs/content/contribution-guidelines.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e3019cf472..17d405ccba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,8 @@ Thank you for considering contributing to Medusa! This document will outline how to submit changes to this repository and which conventions to follow. If you are ever in doubt about anything we encourage you to reach out either by submitting an issue here or reaching out [via Discord](https://discord.gg/xpCwq3Kfn8). +If you're contributing to our documentation, make sure to also check out the [contribution guidelines on our documentation website](https://docs.medusajs.com/contribution-guidelines). + ## Prerequisites - **You're familiar with GitHub Issues and Pull Requests** diff --git a/docs/content/contribution-guidelines.md b/docs/content/contribution-guidelines.md new file mode 100644 index 0000000000..9c1688b872 --- /dev/null +++ b/docs/content/contribution-guidelines.md @@ -0,0 +1,112 @@ +# Contribution Guidelines + +Thank you for your interest in contributing to the documentation! You will be helping the open source community and other developers interested in learning more about Medusa and using it. + +:::tip + +This guide is specific to contributing to the documentation. If you’re interested in contributing to Medusa’s codebase, check out the [contributing guidelines in the Medusa GitHub repository](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +::: + +## Site Setup + +The documentation website is built with [Docusaurus](https://docusaurus.io/), a framework that optimizes documentation creation. If you’re not familiar with Docusaurus, it’s recommended to check out the [Installation documentation](https://docusaurus.io/docs/installation) on their website to better understand Docusaurus, how it works, its structure, and more details. + +The documentation codebase is hosted as part of the [medusa repository](https://github.com/medusajs/medusa) on GitHub. You’ll find the code that runs the docusaurus website under the [www/docs](https://github.com/medusajs/medusa/tree/master/www/docs) directory. + +## Documentation Content + +The documentation content is written in Markdown format and is located in the [docs/content](https://github.com/medusajs/medusa/tree/master/docs/content) directory of the same repository. If you’re not familiar with Markdown, check out [this cheat sheet](https://www.markdownguide.org/cheat-sheet/) for a quick start. + +You’ll also find MDX files. MDX files combine the power of Markdown with React. So, the content of the file can contain JSX components and import statements, among other features. You can learn more about [MDX in docusaurus’s guide.](https://docusaurus.io/docs/markdown-features/react) + +## What You Can Contribute To + +- You can contribute to the Docusaurus codebase to add a new feature or fix a bug in the documentation website. +- You can contribute to the documentation content either by fixing errors you find or adding documentation pages. + +## What You Can’t Contribute To + +The [Services Reference](/references/services/classes/AuthService) is an automatically generated API reference using Typedoc. So, you can’t contribute to it by making changes to its markdown files. + +You can, however, contribute to the script generating it if you find any issues in it. + +## Style Guide + +When you contribute to the documentation content, make sure to follow the [documentation style guide](https://www.notion.so/Style-Guide-Docs-fad86dd1c5f84b48b145e959f36628e0). + +## How to Contribute + +If you’re fixing errors in an existing documentation page, you can scroll down to the end of the page and click on the “Edit this page” link. You’ll be redirected to the GitHub edit form of that page and you can make edits directly and submit a pull request (PR). + +If you’re adding a new page or contributing to the codebase, fork the repository, create a new branch, and make all changes necessary in your repository. Then, once you’re done creating a PR in the Medusa repository. + +For more details on how to contribute, check out [the contribution guidelines on our repository](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +### Branch Name + +When you make edit to an existing documentation page or fork the repository to make changes to the documentation, you have to create a new branch. + +Make sure that the branch name starts with `docs/`. For example, `docs/fix-services`. + +### Pull Request Conventions + +When you create a pull request, prefix the title with “docs:”. Make sure to keep “docs” in small letters. + +In the body of the PR, explain clearly what the PR does. If the PR solves an issue, use [closing keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) with the issue number. For example, “Closes #1333”. + +## Sidebar + +When you add a new page to the documentation, you must add the new page in `www/docs/sidebars.js` under the `tutorialSidebar`. You can learn more about the syntax used [here](https://docusaurus.io/docs/sidebar/items). + +## Notes and Additional Information + +When displaying notes and additional information in a documentation page, use [Admonitions](https://docusaurus.io/docs/markdown-features/admonitions). Make sure the type of admonition used matches the note’s importance to the current document. + +If the note is something developers have to be careful of doing or not doing, use the `caution` or `danger` admonitions based on how critical it is. + +If the note is defining something to the developer in case they’re not familiar with it, use the `info` admonition. + +If the note displays helpful information and tips use the `tip` admonition. + +If the admonition does not match any of the mentioned criteria, always default to the `note` admonition. + +## Images + +If you are adding images to a documentation page, you can host the image on [Imgur](https://imgur.com) for free. + +## NPM and Yarn Code Blocks + +If you’re adding code blocks that use NPM and Yarn, you must use the [npm2yarn syntax](https://docusaurus.io/docs/markdown-features/code-blocks#npm2yarn-remark-plugin). + +For example: + +~~~md +```bash npm2yarn +npm run start +``` +~~~ + +The code snippet must be written using NPM, and the `npm2yarn` plugin will automatically transform it to Yarn. + +### Expand Commands + +Don't use commands in their abbrivated terms. For example, instead of `npm i` use `npm install`. + +### Run Command + +Make sure to always use the `run` command when the command runs a script. + +For example, even though you can run the `start` script using NPM with `npm start`, however, to make sure it’s transformed properly to a Yarn command, you must add the `run` keyword before `start`. + +### Global Option + +When a command uses the global option `-g`, add it at the end of the NPM command to ensure that it’s transformed to a Yarn command properly. For example: + +```bash +npm install @medusajs/medusa-cli -g +``` + +## Need Additional Help? + +If you need any additional help while contributing, you can join our [Discord server](https://discord.gg/medusajs) and ask Medusa’s core team as well as the community any questions. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 85783792dd..a51d824894 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -394,6 +394,11 @@ module.exports = { }, ], }, + { + type: "doc", + id: "contribution-guidelines", + label: "Contribution Guidelines", + }, ], servicesSidebar: [ { From 9c2511a86d8d87bd179223007e3ca31b1936605c Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 9 Jun 2022 11:06:34 +0300 Subject: [PATCH 19/34] Added guidelines for sidebar labels --- docs/content/contribution-guidelines.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/content/contribution-guidelines.md b/docs/content/contribution-guidelines.md index 9c1688b872..17d7f232c8 100644 --- a/docs/content/contribution-guidelines.md +++ b/docs/content/contribution-guidelines.md @@ -59,6 +59,12 @@ In the body of the PR, explain clearly what the PR does. If the PR solves an iss When you add a new page to the documentation, you must add the new page in `www/docs/sidebars.js` under the `tutorialSidebar`. You can learn more about the syntax used [here](https://docusaurus.io/docs/sidebar/items). +### Terminology + +When the documentation page is a conceptual or overview documentation, the label in the sidebar should start with a noun. + +When the documentation page is a tutorial documentation, the label in the sidebar should start with a verb. An exception of this rule are integration documentations and upgrade guides. + ## Notes and Additional Information When displaying notes and additional information in a documentation page, use [Admonitions](https://docusaurus.io/docs/markdown-features/admonitions). Make sure the type of admonition used matches the note’s importance to the current document. From 1594111cbfafd056b93e5d2a4160fc0b6e097c3c Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 8 Jun 2022 15:35:57 +0300 Subject: [PATCH 20/34] added additional steps section --- docs/content/quickstart/quick-start.md | 52 ++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/content/quickstart/quick-start.md b/docs/content/quickstart/quick-start.md index 603bcdf765..288e941610 100644 --- a/docs/content/quickstart/quick-start.md +++ b/docs/content/quickstart/quick-start.md @@ -18,27 +18,29 @@ node -v You can install Node from the [official website](https://nodejs.org/en/). -## Getting started +## Create a Medusa Server -1. **Install Medusa CLI** +### 1. Install Medusa CLI ```bash npm2yarn npm install -g @medusajs/medusa-cli ``` -2. **Create a new Medusa project** +### 2. Create a new Medusa project ```bash medusa new my-medusa-store --seed ``` -3. **Start your Medusa engine** +### 3. Start your Medusa server ```bash cd my-medusa-store medusa develop ``` +### Test Your Server + After these 3 steps and in only a couple of minutes, you now have a complete commerce engine running locally. You can test it out by sending a request using a tool like Postman or through the command line: ```bash @@ -55,6 +57,48 @@ curl localhost:9000/store/products ::: +## Additional Steps + +### File Service Plugin + +To upload product images to your Medusa server, you must install and configure one of the following file service plugins: + +- [MinIO](../add-plugins/minio.md) (Recommended for local development) +- [S3](../add-plugins/s3.md) +- [DigitalOcean Spaces](../add-plugins/spaces.md) + +### Environment Variables + +Medusa allows you to choose how to load your environment variables. By default, it will only load environment variables on your system. + +If you want to load environment variables from a `.env` file add the following at the top of `medusa-config.js`: + +```js +const dotenv = require('dotenv') + + let ENV_FILE_NAME = ''; + switch (process.env.NODE_ENV) { + case 'production': + ENV_FILE_NAME = '.env.production'; + break; + case 'staging': + ENV_FILE_NAME = '.env.staging'; + break; + case 'test': + ENV_FILE_NAME = '.env.test'; + break; + case 'development': + default: + ENV_FILE_NAME = '.env'; + break; + } + + try { + dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME }); + } catch (e) { + } +``` + ## What's next :rocket: - Install our [Next.js](http://localhost:3000/starters/nextjs-medusa-starter) or [Gatsby](http://localhost:3000/starters/gatsby-medusa-starter) storefronts to set up your ecommerce storefront quickly. From 444ef1ea3f7f1f05b778a88c631661103e4798ec Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 8 Jun 2022 18:55:01 +0300 Subject: [PATCH 21/34] added notification overview --- docs/content/add-plugins/sendgrid.mdx | 2 +- .../advanced/backend/notification/overview.md | 92 ++++++++++++++++ .../backend/subscribers/events-list.md | 2 +- docs/content/how-to/notification-api.md | 103 ------------------ www/docs/sidebars.js | 11 +- 5 files changed, 103 insertions(+), 107 deletions(-) create mode 100644 docs/content/advanced/backend/notification/overview.md delete mode 100644 docs/content/how-to/notification-api.md diff --git a/docs/content/add-plugins/sendgrid.mdx b/docs/content/add-plugins/sendgrid.mdx index 9f602f1601..4fcc04f60c 100644 --- a/docs/content/add-plugins/sendgrid.mdx +++ b/docs/content/add-plugins/sendgrid.mdx @@ -3963,5 +3963,5 @@ You can also track analytics related to emails sent from the SendGrid dashboard. ## What’s Next 🚀 -- Learn more about how [Notifications work in Medusa](../how-to/notification-api.md). +- Learn more about how [Notifications work in Medusa](../advanced/backend/notification/overview.md). - Install the [Medusa admin](https://github.com/medusajs/admin#-setting-up-admin) for functionalities like Gift Cards creation, swaps, claims, order return requests, and more. \ No newline at end of file diff --git a/docs/content/advanced/backend/notification/overview.md b/docs/content/advanced/backend/notification/overview.md new file mode 100644 index 0000000000..68426e450e --- /dev/null +++ b/docs/content/advanced/backend/notification/overview.md @@ -0,0 +1,92 @@ +# Architecture Overview + +This document gives an overview of the notification architecture and how it works. + +## Introduction + +Medusa provides a Notification API to mainly handle sending and resending notifications when an event occurs. For example, sending an email to the customer when they place an order. + +The Notification architecture is made up of 2 main components: the Notification Provider and the Notification. Simply put, the Notification Provider handles the sending and resending of a Notification. + +## Notification Provider + +### Overview + +A Notification Provider is a provider that handles sending and resending of notifications. You can either create and integrate your own provider or install a Notification Provider through a third-party plugin. + +An example of a notification provider is SendGrid. When an order is placed, the SendGrid plugin sends an email to the customer. + +### How it is Created + +A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a service file in your Medusa server. + +As a developer, you mainly work with the Notification Provider when integrating a third-party service that handles notifications in Medusa. + +When you run your Medusa server, the Notification Provider is registered on your server if it isn’t already. This means that it will be inserted into the `notification_provider` table in your database. + +### Entity Overview + +The `NotificationProvider` entity only has 2 attributes: `id` and `is_installed`. + +`id` is the value of the static property `identifier` defined inside the notification service class. + +`is_installed` indicates whether the Notification Provider is installed or not. When you install a Notification Provider, the value of this attribute is `true`. + +If you installed a Notification provider and then removed the service files or plugin that registered the Notification Provider, the Notification Provider remains in your database, but the value of the `is_installed` field changes to `false`. + +## Notification + +### Overview + +A notification is a form of an alert sent to the customers or users to inform them of an action that has occurred. For example, if an order is placed, the notification, in this case, can be an email that confirms their order and lists the order details. + +Notifications can take on other forms such as an SMS or a Slack message. + +### How it is Created + +Notifications are created in the `NotificationService` class in Medusa’s core after the Notification has been handled by the Notification Provider. + +The data and additional details that the Notification Provider returns to the `NotificationService` is used to fill some of the attributes of the Notification in the database. + +A Notification also represents a resent notification. So, when a notification is resent, a new one is created that references the original Notification as a parent. This Notification is also created by the `NotificationService` class. + +### Entity Overview + +The 2 most important properties in the `Notification` entity are the `to` and `data` properties. + +The `to` property is a string that represents the receiver of the Notification. For example, if the Notification was sent to an email address, the `to` property holds the email address the Notification was sent to. + +The `to` property can alternatively be a phone number or a chat username. It depends on the Notification Provider and how it sends the Notification. + +The `data` property is an object that holds all the data necessary to send the Notification. For example, in the case of an order confirmation Notification, it can hold data related to the order. + +The `data` property is useful when a notification is resent later. The same `data` can be used to resend the notification. + +In the case of resent notifications, the resent notification has a `parent_id` set to the ID of the original Notification. The value of the `parent_id` property in the original Notification is `null`. + +The `Notification` entity has some properties that determine the context of this Notification. This includes the `event_name` property which is the event that triggered the sending of this notification. + +Additionally, the `resource_type` property is used to determine what resource this event is associated with. For example, if the `event_name` is `order.placed`, the `resource_type` is `order`. + +You can also access the specific resource using the `resource_id` property, which is the ID of the resource. So, in case of the `order.placed` event, the `resource_id` is the ID of the order that was created. + +The `Notification` entity also includes properties related to the receiver of the Notification. In case the receiver is a customer, the `customer_id` property is used to identify which customer. + +## Automating Flows with Notifications + +With Medusa you can create notifications as a reaction to a wide spectrum of events, allowing you to automate communication and processes. + +An example of a flow that can be implemented using Medusa's Notification API is automated return flows: + +- A customer requests a return by sending a `POST` request to the `/store/returns` endpoint. +- The Notification Provider listens to the `order.return_requested` event and sends an email to the customer with a return invoice and return label generated by the Fulfillment Provider. +- The customer returns the items triggering the `return.recieved` event. +- The Notification Provider listens to the `return.received` event and sends an email to the customer with confirmation that their items have been received and that a refund has been issued. + +## What’s Next 🚀 + +- Learn how to create your own Notification Provider. +- [Check out the list of events in Medusa.](../subscribers/events-list.md) +- [Check the `NotificationService` API reference for more details on how it works.](../../../references/services/classes/NotificationService.md) +- [Check out the SendGrid Notification plugin.](../../../add-plugins/sendgrid.mdx) +- Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md) in Medusa. diff --git a/docs/content/advanced/backend/subscribers/events-list.md b/docs/content/advanced/backend/subscribers/events-list.md index 1f76d6fa2d..21b917d10f 100644 --- a/docs/content/advanced/backend/subscribers/events-list.md +++ b/docs/content/advanced/backend/subscribers/events-list.md @@ -1862,4 +1862,4 @@ Object of the following format: ## What’s Next 🚀 - Learn how you can [use services in subscribers](create-subscriber.md#using-services-in-subscribers). -- Learn how to [create notifications](../../../how-to/notification-api.md) in Medusa. +- Learn how to [create notifications](../notification/overview.md) in Medusa. diff --git a/docs/content/how-to/notification-api.md b/docs/content/how-to/notification-api.md deleted file mode 100644 index 2e39c2523a..0000000000 --- a/docs/content/how-to/notification-api.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Notifications and automated flows ---- - -# Notification API and how to structure email flows - -### Introduction - -Plugins offer a way to extend and integrate the core functionality of Medusa. For a walkthrough of the implementation details behind these, please see [Plugins in Medusa](https://docs.medusajs.com/guides/plugins). - -Medusa makes it possible for plugins to implement the Notification API. The API allows for different types of implementations of notifications (emails, text messages, Slack messages, etc), that are sent as a reaction to events in Medusa. All Notifications are stored in the database with information about the receiver of the notification and what plugin was in charge of sending it. This allows merchants to resend notifications, but also gives an overview of what communication has been sent to customers. - -### How it works - -The Notification API works by subscribing to all events that are emitted to the Event Bus and channeling them through to notification plugins that listen to the events. In a plugin you can subscribe to a notification event by exporting a subscriber class that calls `notificationService.subscribe`: - -```jsx -// src/subscribers/my-notification.js - -class MyNotification { - constructor({ notificationService }) { - // Subscribe to order.placed events - notificationService.subscribe("order.placed", "my-service"); - } -} - -export default MyNotification; -``` - -The above code tells the notification service to send `order.placed` events to the `my-service` notification service implemented in your plugin. - -For a plugin to work with the Notification API you must implement 2 methods `sendNotification` and `resendNotification`; - -```jsx -// src/services/my-notification.js - -class MyService extends NotificationService { - static identifier = "my-service"; - - constructor({ orderService }, options) { - super(); - - this.options_ = options; - this.orderService_ = orderService; - } - - async sendNotification(eventName, eventData, attachmentGenerator) { - let sendData; - switch (eventName) { - case "order.placed": - sendData = await this.orderService_.retrieve(eventData.id); - break; - default: - // If the return value is undefined no notification will be stored - return; - } - - await CoolEmailSender.send({ - email: sendData.email, - templateData: sendData, - }); - - return { to: sendData.email, data: sendData }; - } - - async resendNotification(notification, config, attachmentGenerator) { - const recipient = config.to || notification.to; - - await CoolEmailSender.send({ - email: recipient, - templateData: notification.data, - }); - - return { to: sendOptions.to, data: notification.data }; - } -} - -export default MyService; -``` - -:::note - - A notification service must have a static property called `identifier` this is used to determine which classes are called when subscribing to different events. In this case the service identifier is `my-service` so to subscribe to notifications you must use: - `notificationService.subscribe([eventname], "my-service")` - -::: - -The above class is an example implementation of a NotificationService. It uses a fictional email service called `CoolEmailSender` to send emails to a customer whenever an order is placed. The `sendNotification` implementation gets the event name and fetches relevant data based on what event is being processed; in this case it retrieves an order, which is later used when requesting `CoolEmailSender` to dispatch an email. The address to send the email to is likewise fetched from the order. - -The return type of `sendNotification` and `resendNotification` is an object with `to` and `data`. The `to` prop should identify the receiver of the notification, in this case an email, but it could also be a phone number, an ID, a channel name or something similar depending on the type of notification provider. The `data` prop contains the data as it was gathered when the notification was sent; the same data will be provided if the notification is resent at a later point. - -When `resendNotification` is called the original Notification is provided along with a config object. The config object may contain a `to` property that can be used to overwrite the original `to`. - -## Creating automated notification flows - -When running an ecommerce store you typically want to send communication to your customers when different events occur, these include messages like order confirmations and shipping updates. With Medusa you can create transactional notifications as a reaction to a wide spectrum of events, allowing you to automate communication and processes. An example of a flow that can be implemented using Medusa's Notification API is automated return flows. Below is an outline of how an automated return flow might work. - -- Customer requests a return with `POST /store/returns` -- Notification Service listens for `order.return_requested` and sends email to the customer with a return invoice and return label generated by fulfillment provider -- Customer returns items triggering `return.recieved` -- Notification Service listens for `return.received` and sends email to the customer with confirmation that their items have been received and that a refund has been issued. - -Check out `medusa-plugin-sendgrid` for an Notification API implementation that works with Sendgrid. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index a0a6e20f6d..52742fcbac 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -182,8 +182,15 @@ module.exports = { ] }, { - type: "doc", - id: "how-to/notification-api", + type: "category", + label: "Notification", + collapsed: true, + items: [ + { + type: "doc", + id: "advanced/backend/notification/overview" + } + ] }, { type: "doc", From 1af7a9d1ebd3ef0b9918a042e2f71b43f43b2aed Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 9 Jun 2022 16:35:06 +0300 Subject: [PATCH 22/34] added how to create notification provider --- .../how-to-create-notification-provider.md | 272 ++++++++++++++++++ .../advanced/backend/notification/overview.md | 26 +- www/docs/sidebars.js | 5 + 3 files changed, 288 insertions(+), 15 deletions(-) create mode 100644 docs/content/advanced/backend/notification/how-to-create-notification-provider.md diff --git a/docs/content/advanced/backend/notification/how-to-create-notification-provider.md b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md new file mode 100644 index 0000000000..73ec0e949c --- /dev/null +++ b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md @@ -0,0 +1,272 @@ +# How to Create a Notification Provider + +In this document, you’ll learn how to add a Notification Provider to your Medusa server. If you’re unfamiliar with the Notification architecture in Medusa, it is recommended to check out the [architecture overview](overview.md) first. + +## Overview + +A Notification Provider is the custom or third-party service used to handle sending alerts to customers or users when an event occurs. + +For example, you can use SendGrid to send a confirmation email to a customer after they place an order. SendGrid in this example is a Notification Provider. + +:::tip + +If you’re interested in using SendGrid to send Notifications, you can use the [SendGrid](../../../add-plugins/sendgrid.mdx) plugin instead of using your own. + +::: + +Adding a Notification Provider is as simple as creating a [Service](../services/create-service.md) file in `src/services`. A Notification Provider is essentially a Service that extends the `NotificationService` from `medusa-interfaces`. + +:::info + +Notification Providers are loaded and installed at the server startup. + +::: + +After creating the Notification Provider Service, you must create a [Subscriber](../subscribers/create-subscriber.md) that subscribes the Notification Provider to specific events. + +## Prerequisites + +Before you start creating a Notification Provider, you need to install a [Medusa server](../../../quickstart/quick-start.md). + +You also need to install and configure Redis. You can check out the documentation “[Set Up Your Development Environment](../../../tutorial/0-set-up-your-development-environment.mdx)” for help. + +## Create a Notification Provider + +The first step to creating a Notification Provider is to create a file in `src/services` with the following content: + +```jsx +import { NotificationService } from "medusa-interfaces"; + +class EmailSenderService extends NotificationService { + +} + +export default EmailSenderService; +``` + +Where `EmailSenderService` is the name of your Notification Provider Service. + +Notification Providers must extend `NotificationService` from `medusa-interfaces`. + +:::info + +Following the naming convention of Services, the name of the file should be the slug name of the Notification Provider, and the name of the class should be the camel case name of the Notification Provider suffixed with “Service”. In the example above, the name of the file should be `email-sender.js`. You can learn more in the [service documentation](../services/create-service.md). + +::: + +### identifier + +Notification Provider Services must have a static property `identifier`. + +The `NotificationProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the Service class is used when the Notification Provider is created in the database. + +The value of this property is also used later when you want to subscribe the Notification Provider to events in a Subscriber. + +For example, in the class you created in the previous code snippet you can add the following property: + +```jsx +static identifier = "email-sender"; +``` + +### constructor + +You can use the `constructor` of your Notification Provider to have access to different Services in Medusa through dependency injection. + +You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the Service. + +Additionally, if you’re creating your Notification Provider as an external plugin to be installed on any Medusa server and you want to access the options added for the plugin, you can access it in the constructor. The options are passed as a second parameter. + +:::info + +You can learn more about plugins and how to create them in the [Plugins](../../../guides/plugins.md) documentation. + +::: + +Continuing on with the previous example, if you want to use the [`OrderService`](../../../references/services/classes/OrderService.md) later when sending notifications, you can inject it into the constructor: + +```jsx +constructor({ orderService }, options) { + //you can access options here in case you're + //using a plugin + super(); + + this.orderService = orderService; +} +``` + +### sendNotification + +When an event is triggered that your Notification Provider is registered as a handler for, the [`NotificationService`](../../../references/services/classes/NotificationService.md) in Medusa’s core will execute the `sendNotification` method of your Notification Provider. + +In this method, you can perform the necessary operation to send the Notification. Following the example above, you can send an email to the customer when they place an order. + +This method receives 3 parameters: + +1. `eventName`: This is the name of the event that was triggered. For example, `order.placed`. +2. `eventData`: This is the data payload of the event that was triggered. For example, if the `order.placed` event is triggered, the `eventData` object contains the property `id` which is the ID of the order that was placed. +3. `attachmentGenerator`: If you’ve previously attached a generator to the `NotificationService` using the [`registerAttachmentGenerator`](../../../references/services/classes/NotificationService.md#registerattachmentgenerator) method, you have access to it here. You can use the `attachmentGenerator` to generate on-demand invoices or other documents. The default value of this parameter is null. + +:::info + +You can learn more about what events are triggered in Medusa and their data payload in the [Events List](../subscribers/events-list.md) documentation. + +::: + +This method must return an object containing two properties: + +1. `to`: a string that represents the receiver of the Notification. For example, if you sent an email to the customer then `to` is the email address of the customer. In other cases, it might be a phone number or a username. +2. `data`: an object that contains the data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object might include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data. + +Continuing with the previous example you can have the following implementation of the `sendNotification` method: + +```jsx +async sendNotification(eventName, eventData, attachmentGenerator) { + if (eventName === 'order.placed') { + //retrieve order + const order = await this.orderService.retrieve(eventData.id); + //TODO send email + + console.log('Notification sent'); + return { + to: order.email, + data: { + //any data necessary to send the email + //for example: + subject: 'You placed a new order!', + items: order.items + } + }; + } +} +``` + +In this code snippet, you check first if the event is `order.placed`. This can be helpful if you’re handling multiple events using the same Notification Provider. + +You then retrieve the order using the ID and send the email. Here, the logic related to sending the email is not implemented as it is generally specific to your Notification Provider. + +Finally, you return an object with the `to` property set to the customer email and the `data` property is an object that contains data necessary to send the email such as a `subject` or `items`. + +:::note + +The `to` and `data` properties are used in the `NotificationService` in Medusa’s core to create a new `Notification` record in the database. You can learn more about the `Notification` entity in the [Architecture Overview](overview.md#notification-entity-overview) documentation. + +::: + +### resendNotification + +Using the [Resend Notification endpoint](https://docs.medusajs.com/api/admin/notification/resend-notification), an admin user can resend a Notification to the customer. The [`NotificationService`](../../../references/services/classes/NotificationService.md) in Medusa’s core then executes the `resendNotification` method in your Notification Provider. + +This method receives 3 parameters: + +1. `notification`: This is the original Notification record that was created after you sent the notification with `sendNotification`. You can get an overview of the entity and its attributes in the [architecture overview](overview.md#notification-entity-overview), but most notably it includes the `to` and `data` attributes which are populated originally using the `to` and `data` properties of the object you return in `sendNotification`. +2. `config`: In the Resend Notification endpoint you may specify an alternative receiver of the notification using the `to` request body parameter. For example, you may want to resend the order confirmation email to a different email. If that’s the case, you have access to it in the `config` parameter object. Otherwise, `config` will be an empty object. +3. `attachmentGenerator`: If you’ve previously attached a generator to the Notification Service using the [`registerAttachmentGenerator`](../../../references/services/classes/NotificationService.md#registerattachmentgenerator) method, you have access to it here. You can use the `attachmentGenerator` to generate on-demand invoices or other documents. The default value of this parameter is null. + +Similarly to the `sendNotification` method, this method must return an object containing two properties: + +1. `to`: a string that represents the receiver of the Notification. You can either return the same `to` available in the `notification` parameter or the updated one in the `config` parameter. +2. `data`: an object that contains the data used to send the Notification. You can either return the same `data` in the `notification` parameter or make any necessary updates to it. + +Continuing with the previous example you can have the following implementation of the `resendNotification` method: + +```jsx +resendNotification(notification, config, attachmentGenerator) { + //check if the receiver of the notification should be changed + const to = config.to ? config.to : notification.to; + + //TODO resend the notification using the same data that is saved under notification.data + + console.log('Notification resent'); + return { + to, + data: notification.data //you can also make changes to the data + } +} +``` + +In the above snippet, you check if the `to` should be changed by checking if the `config` parameter has a `to` property. Otherwise, you keep the same `to` address stored in the `notification` parameter. + +You then resend the email. Here, the logic related to sending the email is not implemented as it is generally specific to your Notification Provider. + +Finally, you return an object with the `to` property set to the email (either new or old) and the `data` property is the same data used before to send the original notification. you can alternatively make any changes to the data. + +:::note + +The `to` and `data` properties are used in the `NotificationService` in Medusa’s core to create a new `Notification` record in the database. No changes are made to the original `Notification` record created after the `sendNotification` method. This new record is associated with the original `Notification` record using the `parent_id` attribute in the entity. You can learn more about the `Notification` entity in the [Architecture Overview](overview.md#notification-entity-overview) documentation. + +::: + +## Create a Subscriber + +After creating your Notification Provider Service, you must create a Subscriber that registers this Service as a notification handler of events. + +:::note + +This section will not cover the basics of Subscribers. You can read the [Subscribers](../subscribers/create-subscriber.md) documentation to learn more about them and how to create them. + +::: + +Following the previous example, to make sure the `email-sender` Notification Provider handles the `order.placed` event, create the file `src/subscribers/notification.js` with the following content: + +```jsx +class NotificationSubscriber { + constructor({ notificationService }) { + notificationService.subscribe('order.placed', 'email-sender'); + } +} + +export default NotificationSubscriber; +``` + +This subscriber accesses the `notificationService` using dependency injection. The `notificationService` contains a `subscribe` method that accepts 2 parameters. The first one is the name of the event to subscribe to, and the second is the identifier of the Notification Provider that is subscribing to that event. + +:::tip + +Notice that the value of the `identifier` static property defined in the `EmailSenderService` is used to register the Notification Provider to handle the `order.placed` event. + +::: + +## Test Sending Notifications with your Notification Provider + +Make sure you've configured Redis with your Medusa server as explained in the Prerequisites section and that the Redis service is running. + +Then, start by running your Medusa server: + +```bash +npm run start +``` + +Then, place an order either using the [REST APIs](https://docs.medusajs.com/api/store/auth) or using the storefront. + +:::tip + +If you don’t have a storefront installed you can get started with either our [Next.js](../../../starters/nextjs-medusa-starter.md) or [Gatsby](../../../starters/gatsby-medusa-starter.md) starter storefronts in minutes. + +::: + +After placing an order, you can see in your console the message “Notification Sent”. If you added your own notification sending logic, you should receive an email or alternatively the type of notification you’ve set up. + +## Test Resending Notifications with your Notification Provider + +To test resending a notification, first, retrieve the ID of the notification you just sent using the [List Notifications admin endpoint](https://docs.medusajs.com/api/admin/notification/list-notifications). You can pass as a body parameter the `to` or `event_name` parameters to filter out the notification you just sent. + +:::tip + +You must be authenticated as an admin user before sending this request. You can use the [Authenticate a User](https://docs.medusajs.com/api/admin/auth/) endpoint to get authenticated. + +::: + +![List Notifications Request](https://i.imgur.com/iF1rZX1.png) + +Then, send a request to the [Resend Notification](https://docs.medusajs.com/api/admin/notification/resend-notification) endpoint using the ID retrieved from the previous request. You can pass the `to` parameter in the body to change the receiver of the notification. You should see the message “Notification Resent” in your console and if you implemented your own logic for resending the notification it will be resent. + +![Resend Notifications Request](https://i.imgur.com/0zFfPed.png) + +This request returns the same notification object as the List Notifications endpoint, but it now has a new object in the `resends` array. This is the resent notification. If you supplied a `to` parameter in the request body, you should see its value in the `to` property of the resent notification object. + +## What’s Next 🚀 + +- Check out the [list of events](../subscribers/events-list.md) you can listen to. +- Check out the [SendGrid](../../../add-plugins/sendgrid.mdx) plugin for easy integration of email notifications. +- Learn how to [create your own plugin](../../../guides/plugins.md). +- Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md). diff --git a/docs/content/advanced/backend/notification/overview.md b/docs/content/advanced/backend/notification/overview.md index 68426e450e..b2ed328272 100644 --- a/docs/content/advanced/backend/notification/overview.md +++ b/docs/content/advanced/backend/notification/overview.md @@ -10,39 +10,35 @@ The Notification architecture is made up of 2 main components: the Notification ## Notification Provider -### Overview - A Notification Provider is a provider that handles sending and resending of notifications. You can either create and integrate your own provider or install a Notification Provider through a third-party plugin. An example of a notification provider is SendGrid. When an order is placed, the SendGrid plugin sends an email to the customer. -### How it is Created +### How Notification Provider is Created -A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a service file in your Medusa server. +A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a Service file in your Medusa server. As a developer, you mainly work with the Notification Provider when integrating a third-party service that handles notifications in Medusa. When you run your Medusa server, the Notification Provider is registered on your server if it isn’t already. This means that it will be inserted into the `notification_provider` table in your database. -### Entity Overview +### NotificationProvider Entity Overview The `NotificationProvider` entity only has 2 attributes: `id` and `is_installed`. -`id` is the value of the static property `identifier` defined inside the notification service class. +`id` is the value of the static property `identifier` defined inside the notification Service class. `is_installed` indicates whether the Notification Provider is installed or not. When you install a Notification Provider, the value of this attribute is `true`. -If you installed a Notification provider and then removed the service files or plugin that registered the Notification Provider, the Notification Provider remains in your database, but the value of the `is_installed` field changes to `false`. +If you installed a Notification provider and then removed the Service files or plugin that registered the Notification Provider, the Notification Provider remains in your database, but the value of the `is_installed` field changes to `false`. ## Notification -### Overview - A notification is a form of an alert sent to the customers or users to inform them of an action that has occurred. For example, if an order is placed, the notification, in this case, can be an email that confirms their order and lists the order details. Notifications can take on other forms such as an SMS or a Slack message. -### How it is Created +### How Notification is Created Notifications are created in the `NotificationService` class in Medusa’s core after the Notification has been handled by the Notification Provider. @@ -50,11 +46,11 @@ The data and additional details that the Notification Provider returns to the `N A Notification also represents a resent notification. So, when a notification is resent, a new one is created that references the original Notification as a parent. This Notification is also created by the `NotificationService` class. -### Entity Overview +### Notification Entity Overview The 2 most important properties in the `Notification` entity are the `to` and `data` properties. -The `to` property is a string that represents the receiver of the Notification. For example, if the Notification was sent to an email address, the `to` property holds the email address the Notification was sent to. +The `to` property is a string that represents the receiver of the Notification. For example, if the Notification was sent to an email address, the `to` property holds the email address the Notification was sent to. The `to` property can alternatively be a phone number or a chat username. It depends on the Notification Provider and how it sends the Notification. @@ -86,7 +82,7 @@ An example of a flow that can be implemented using Medusa's Notification API is ## What’s Next 🚀 - Learn how to create your own Notification Provider. -- [Check out the list of events in Medusa.](../subscribers/events-list.md) -- [Check the `NotificationService` API reference for more details on how it works.](../../../references/services/classes/NotificationService.md) -- [Check out the SendGrid Notification plugin.](../../../add-plugins/sendgrid.mdx) +- Check out the [list of events](../subscribers/events-list.md) in Medusa. +- Check the [`NotificationService`](../../../references/services/classes/NotificationService.md) API reference for more details on how it works. +- Check out the [SendGrid](../../../add-plugins/sendgrid.mdx) Notification plugin. - Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md) in Medusa. diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 52742fcbac..84ca07f9f0 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -189,6 +189,11 @@ module.exports = { { type: "doc", id: "advanced/backend/notification/overview" + }, + { + type: "doc", + id: "advanced/backend/notification/how-to-create-notification-provider", + label: "Create a Notification Provider" } ] }, From 35a17330733d0e3da9e02f772b3f48978f560780 Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Fri, 17 Jun 2022 09:50:23 +0200 Subject: [PATCH 23/34] chore: Add issue template for bug reports (#1676) --- .github/ISSUE_TEMPLATE/bug_report.md | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..aa3fbb0892 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,54 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'type: bug' +assignees: '' + +--- + + + +## Bug report + +### Describe the bug + +A clear and concise description of what the bug is. + +### System information + +Medusa version (including plugins): +Node.js version: +Database: +Operating system: +Browser (if relevant): + +### Steps to reproduce the behavior + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +### Expected behavior + +A clear and concise description of what you expected to happen + +### Screenshots + +If applicable, add screenshots to help explain your problem + +### Code snippets + +If applicable, add code samples to help explain your problem + +### Additional context + +Add any other context about the problem here From 2c266302c8df3015e8317531aa951fc8f0ebad86 Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Fri, 17 Jun 2022 09:50:40 +0200 Subject: [PATCH 24/34] chore: Add issue template for feature requests (#1679) --- .github/ISSUE_TEMPLATE/feature_request.md | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..e5c8042f2d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,29 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: 'type: feature or enhancement' +assignees: '' + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 0bfdaab34e2325d859f947f24efad58ab500ba88 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 11:31:05 +0300 Subject: [PATCH 25/34] docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> --- .../advanced/backend/endpoints/add-admin.md | 6 +- .../backend/endpoints/add-storefront.md | 6 +- .../payment/how-to-create-payment-provider.md | 2 +- .../advanced/backend/payment/overview.md | 28 +++---- .../shipping/add-fulfillment-provider.md | 4 +- .../advanced/backend/shipping/overview.md | 81 ++++++++++--------- .../backend/subscribers/events-list.md | 8 +- .../advanced/backend/upgrade-guides/1-3-0.md | 4 +- www/docs/sidebars.js | 9 ++- 9 files changed, 71 insertions(+), 77 deletions(-) diff --git a/docs/content/advanced/backend/endpoints/add-admin.md b/docs/content/advanced/backend/endpoints/add-admin.md index 65d9ff7117..64d7be803e 100644 --- a/docs/content/advanced/backend/endpoints/add-admin.md +++ b/docs/content/advanced/backend/endpoints/add-admin.md @@ -1,8 +1,4 @@ ---- -title: Add Endpoint for Admin ---- - -# Add Endpoint for Admin +# Create Endpoint for Admin In this document, you’ll learn how to add a custom endpoint in the Backend that you can use from the Admin. diff --git a/docs/content/advanced/backend/endpoints/add-storefront.md b/docs/content/advanced/backend/endpoints/add-storefront.md index adb738edbe..d4cca97b5c 100644 --- a/docs/content/advanced/backend/endpoints/add-storefront.md +++ b/docs/content/advanced/backend/endpoints/add-storefront.md @@ -1,8 +1,4 @@ ---- -title: Add Endpoint for Storefront ---- - -# Add Endpoint for Storefront +# Create Endpoint for Storefront In this document, you’ll learn how to add a custom endpoint in the Backend that you can use from the Storefront. diff --git a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md index 304446068e..e867ffe91c 100644 --- a/docs/content/advanced/backend/payment/how-to-create-payment-provider.md +++ b/docs/content/advanced/backend/payment/how-to-create-payment-provider.md @@ -70,7 +70,7 @@ Following the naming convention of Services, the name of the file should be the As mentioned in the overview, Payment Providers should have a static `identifier` property. -The `PaymentProvider` model has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the class will be used when the Payment Provider is created in the database. +The `PaymentProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the class will be used when the Payment Provider is created in the database. The value of this property will also be used to reference the Payment Provider throughout the Medusa server. For example, the identifier is used when a [Payment Session in a cart is selected on checkout](https://docs.medusajs.com/api/store/cart/select-a-payment-session). diff --git a/docs/content/advanced/backend/payment/overview.md b/docs/content/advanced/backend/payment/overview.md index 2320bc342c..1c3e68ff78 100644 --- a/docs/content/advanced/backend/payment/overview.md +++ b/docs/content/advanced/backend/payment/overview.md @@ -1,4 +1,4 @@ -# Architecture Overview +# Payment Architecture Overview In this document, you’ll learn about the payment architecture in Medusa, specifically its 3 main components and the idempotency key. @@ -16,15 +16,13 @@ An important part in the Payment architecture to understand is the **Idempotency ## Payment Provider -### Overview - A Payment Provider in Medusa is a method to handle payments in selected regions. It is not associated with a cart, customer, or order in particular. It provides the necessary implementation to create Payment Sessions and Payments, as well as authorize and capture payments, among other functionalities. Payment Providers can be integrated with third-party services that handle payment operations such as capturing a payment. An example of a Payment Provider is Stripe. Payment Providers can also be related to a custom way of handling payment operations. An example of that is cash on delivery (COD) payment methods or Medusa’s [manual payment provider plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-payment-manual) which provides a minimal implementation of a payment provider and allows store operators to manually handle order payments. -### How it is Created +### How Payment Provider is Created A Payment Provider is essentially a Medusa [service](../services/create-service.md) with a unique identifier, and it extends the `PaymentService` provided by the `medusa-interfaces` package. It can be created as part of a [plugin](../../../guides/plugins.md), or it can be created just as a service file in your Medusa server. @@ -40,21 +38,19 @@ It’s important to choose a payment provider in the list of payment providers i ::: -### Model Overview +### PaymentProvider Entity Overview -The `PaymentProvider` model only has 2 attributes: `is_installed` to indicate if the payment provider is installed and its value is a boolean; and `id` which is the unique identifier that you define in the Payment Provider service. +The `PaymentProvider` entity only has 2 attributes: `is_installed` to indicate if the payment provider is installed and its value is a boolean; and `id` which is the unique identifier that you define in the Payment Provider service. ## Payment Session -### Overview - Payment Sessions are linked to a customer’s cart. Each Payment Session is associated with a payment provider that is available in the customer cart’s region. They hold the status of the payment flow throughout the checkout process which can be used to indicate different statuses such as an authorized payment or payment that requires more actions from the customer. After the checkout process is completed and the Payment Session has been authorized successfully, a Payment instance will be created to be associated with the customer’s order and will be used for further actions related to that order. -### How it is Created +### How Payment Session is Created After the customer adds products to the cart, proceeds with the checkout flow, and reaches the payment method section, Payment Sessions are created for each Payment Provider available in that region. @@ -64,15 +60,15 @@ Payment Sessions can hold data that is necessary for the customer to complete th Among the Payment Sessions available only one will be selected based on the customer’s payment provider choice. For example, if the customer sees that they can pay with Stripe or PayPal and chooses Stripe, Stripe’s Payment Session will be the selected Payment Session of that cart. -### Model Overview +### PaymentSession Entity Overview -The `PaymentSession` model belongs to a `Cart`. This is the customer‘s cart that was used for checkout which lead to the creation of the Payment Session. +The `PaymentSession` entity belongs to a `Cart`. This is the customer‘s cart that was used for checkout which lead to the creation of the Payment Session. The `PaymentSession` also belongs to a `PaymentProvider`. This is the Payment Provider that was used to create the Payment Session and that controls it for further actions like authorizing the payment. The `data` attribute is an object that holds any data required for the Payment Provider to perform payment operations like authorizing or capturing payment. For example, when a Stripe payment session is initialized, the `data` object will hold the payment intent among other data necessary to authorize the payment. -The `is_selected` attribute in the `PaymentSession` model is a boolean value that indicates whether this Payment Session was selected by the customer to pay for their purchase. Going back to the previous example of having Stripe and PayPal as the available Payment Providers, when the customer chooses Stripe, Stripe’s Payment Session will have `is_selected` set to true whereas PayPal’s Payment Session will have `is_selected` set to false. +The `is_selected` attribute in the `PaymentSession` entity is a boolean value that indicates whether this Payment Session was selected by the customer to pay for their purchase. Going back to the previous example of having Stripe and PayPal as the available Payment Providers, when the customer chooses Stripe, Stripe’s Payment Session will have `is_selected` set to true whereas PayPal’s Payment Session will have `is_selected` set to false. The `status` attributes indicates the current status of the Payment Session. It can be one of the following values: @@ -86,21 +82,19 @@ These statuses are important in the checkout flow to determine the current step ## Payment -### Overview - A Payment is used to represent the amount authorized for a customer’s purchase. It is associated with the order placed by the customer and will be used after that for all operations related to the order’s payment such as capturing or refunding the payment. Payments are generally created using data from the Payment Session and it holds any data that can be necessary to perform later payment operations. -### How it is Created +### How Payment is Created Once the customer completes their purchase and the payment has been authorized, a Payment instance will be created from the Payment Session. The Payment is associated first with the cart and then with the order once it’s created and placed. When the store operator then chooses to capture the order from the Medusa Admin, the Payment is used by the Payment Provider to capture the payment. This is the same case for refunding the amount, canceling the order, or creating a swap. -### Model Overview +### Payment Entity Overview -The `Payment` model belongs to the `Cart` that it was originally created from when the customer’s payment was authorized. It also belongs to an `Order` once it’s placed. Additionally, it belongs to a `PaymentProvider` which is the payment provider that the customer chose on checkout. +The `Payment` entity belongs to the `Cart` that it was originally created from when the customer’s payment was authorized. It also belongs to an `Order` once it’s placed. Additionally, it belongs to a `PaymentProvider` which is the payment provider that the customer chose on checkout. In case a `Swap` is created for an order, `Payment` will be associated with that swap to handle payment operations related to it. diff --git a/docs/content/advanced/backend/shipping/add-fulfillment-provider.md b/docs/content/advanced/backend/shipping/add-fulfillment-provider.md index 8523ea1f54..08af0cebbf 100644 --- a/docs/content/advanced/backend/shipping/add-fulfillment-provider.md +++ b/docs/content/advanced/backend/shipping/add-fulfillment-provider.md @@ -1,6 +1,6 @@ # How to Add a Fulfillment Provider -In this document, you’ll learn how to add a fulfillment provider to a Medusa server. If you’re unfamiliar with the Shipping architecture in Medusa, make sure to [check out the overview first](https://docs.medusajs.com/advanced/backend/shipping/overview/). +In this document, you’ll learn how to add a fulfillment provider to a Medusa server. If you’re unfamiliar with the Shipping architecture in Medusa, make sure to [check out the overview first](overview.md). ## Overview @@ -45,7 +45,7 @@ Following the naming convention of Services, the name of the file should be the As mentioned in the overview, fulfillment providers should have a static `identifier` property. -The `FulfillmentProvider` model has 2 properties: `identifier` and `is_installed`. The `identifier` property in the class will be used when the fulfillment provider is created in the database. +The `FulfillmentProvider` entity has 2 properties: `identifier` and `is_installed`. The `identifier` property in the class will be used when the fulfillment provider is created in the database. The value of this property will also be used to reference the fulfillment provider throughout Medusa. For example, it is used to [add a fulfillment provider](https://docs.medusajs.com/api/admin/region/add-fulfillment-provider) to a region. diff --git a/docs/content/advanced/backend/shipping/overview.md b/docs/content/advanced/backend/shipping/overview.md index f40e453c74..6c217e7414 100644 --- a/docs/content/advanced/backend/shipping/overview.md +++ b/docs/content/advanced/backend/shipping/overview.md @@ -1,46 +1,57 @@ ---- +# Shipping Architecture Overview -title: Shipping Architecture Overview - ---- - -# Architecture Overview - -This document gives an overview of the shipping architecture and its 3 most important components. +This document gives an overview of the shipping architecture and its 4 most important components. ## Introduction -In Medusa, the Shipping architecture relies on 3 components: **Shipping Profiles**, **Shipping Options**, and **Shipping Methods**. +In Medusa, the Shipping architecture relies on 4 components: **Fulfillment Provider**, **Shipping Profiles**, **Shipping Options**, and **Shipping Methods**. -The distinction between the 3 is important. It has been carefully planned and put together to support all the different ecommerce use cases and shipping providers that can be integrated. +The distinction between the 4 is important. It has been carefully planned and put together to support all the different ecommerce use cases and shipping providers that can be integrated. It’s also constructed to support multiple regions, provide different shipment configurations and options for different product types, provide promotional shipments for your customers, and much more. ## Summary -- **Shipping Profiles:** created by the admin. They are used to group products that should be shipped in a different manner than the default. Shipping profiles can have multiple shipping options. -- S**hipping Options:** created by the admin and belong to a shipping profile. They are specific to certain regions and can have cart conditions. They use an underlying fulfillment provider. Once a customer checks out, they can choose the shipping option that’s available and most relevant to them. -- **Shipping Method:** created when the customer chooses a shipping option on checkout. The shipping method is basically a copy of the shipping option, but with values specific to the customer and the cart it’s associated with. When the order is placed, the shipping method will then be associated with the order and fulfilled based on the integration with the fulfillment provider. +- **Fulfillment Provider:** Fulfillment providers are plugins or [Services](../services/create-service.md) used to ship the products to your customers, whether physically or virtually. An example of a fulfillment provider would be FedEx. +- **Shipping Profiles:** created by the admin. They are used to group products that should be shipped in a different manner than the default. Shipping profiles can have multiple shipping options. +- **Shipping Options:** created by the admin and belong to a shipping profile. They are specific to certain regions and can have cart conditions. They use an underlying fulfillment provider. Once a customer checks out, they can choose the shipping option that’s available and most relevant to them. +- **Shipping Method:** created when the customer chooses a shipping option on checkout. The shipping method is basically a copy of the shipping option, but with values specific to the customer and the cart it’s associated with. When the order is placed, the shipping method will then be associated with the order and fulfilled based on the integration with the fulfillment provider. -:::note +![Shipping Architecture](https://i.imgur.com/QII2Hvn.png) -Fulfillment providers are used to ship the products to your customers, whether physically or virtually. An example of a fulfillment provider would be FedEx. +## Fulfillment Provider -::: +A Fulfillment Provider in Medusa is a method to handle shipping products in selected regions. It is not associated with a cart, customer, or order in particular. -![Shipping.png](https://i.imgur.com/RnC2esy.png) +It provides the necessary implementation to create Fulfillments for orders and ship items to customers. They can also be used for order returns and swaps. + +Fulfillment Providers can be integrated with third-party services that handle the actual shipment of products. An example of a Fulfillment Provider is FedEx. + +Fulfillment Providers can also be related to a custom way of handling fulfillment operations. An example of that is Medusa’s [manual fulfillment provider plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-fulfillment-manual) which provides a minimal implementation of a fulfillment provider and allows store operators to manually handle order fulfillments. + +### How Fulfillment Provider is Created + +A Fulfillment Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the `FulfillmentService` provided by the `medusa-interfaces` package. It can be created as part of a [plugin](../../../guides/plugins.md), or it can be created just as a Service file in your Medusa server. + +As a developer, you will mainly work with the Fulfillment Provider when integrating a fulfillment method in Medusa. + +When you run your Medusa server, the Fulfillment Provider will be registered on your server if it hasn’t been already. + +Once the Fulfillment Provider is added to the server, the store operator will be able to associate on the [Medusa Admin](../../../quickstart/quick-start.md) the Fulfillment Provider with shipping options. + +### FulfillmentProvider Entity Overview + +The `FulfillmentProvider` entity only has 2 attributes: `is_installed` to indicate if the fulfillment provider is installed and its value is a boolean; and `id` which is the unique identifier that you define in the Fulfillment Provider Service. ## Shipping Profile -### Overview - Shipping profiles are the highest in the hierarchy in the shipping architecture. Shipping profiles are created by the admin. The admin can specify the name of the shipping profile which will be a name that the customer can see. A shipping profile is not associated with any fulfillment providers. It has multiple shipping options that can be associated with different providers. -### Purpose +### Purpose of Shipping Profile Shipping profiles are used to group products that can be shipped in the same manner. @@ -50,18 +61,16 @@ Although this might be the general case, there are still some use cases where yo For example, shipping heavy items might be more expensive than others, which would enforce different price rates. In that case, you can create a new shipping profile that groups together heavy products. This would allow you to give these products more suitable price rates when creating their shipping options. -### Model Overview +### ShippingProfile Entity Overview -The `ShippingProfile` model can have a set of `Product` instances. These would be the products the shipping profile is providing shipping options for. +The `ShippingProfile` entity can have a set of `Product` instances. These would be the products the shipping profile is providing shipping options for. The `ShippingProfile` has a `type` attribute that can be `default`, `gift_card`, or `custom`. -The `ShippingProfile` model also has an array of `ShippingOption` instances. +The `ShippingProfile` entity also has an array of `ShippingOption` instances. ## Shipping Option -### Overview - After the admin adds a shipping profile, they can add shipping options that belong to that shipping profile from the admin dashboard. Shipping options have a set of conditions like the region they’re available in or cart-specific conditions. For example, if your company operates in the United States as well as Germany, you might use a different shipping option for each of the two countries. @@ -70,7 +79,7 @@ Among the configurations that the admin has to set when creating a shipping opti Shipping options are only shown to a customer during checkout if their cart satisfies the option’s conditions. Also, as they belong to a shipping profile, they’re only shown when products that belong to the same shipping profile are in the cart. -### Purpose +### Purpose of Shipping Option The first purpose that a shipping option has is showing the customer during checkout what shipping options are available for them. @@ -78,17 +87,17 @@ Then, once the customer chooses a shipping option, that shipping option is used Think of a shipping option as a template defined by the admin that indicates what data and values the shipping method should have when it’s chosen by the customer during checkout. -### Model Overview +### ShippingOption Entity Overview -The `ShippingOption` model belongs to the `ShippingProfile` model. +The `ShippingOption` entity belongs to the `ShippingProfile` entity. -The `ShippingOption` model also belongs to a `FulfillmentProvider`. This can be either a custom third-party provider or one of Medusa’s default fulfillment providers. +The `ShippingOption` entity also belongs to a `FulfillmentProvider`. This can be either a custom third-party provider or one of Medusa’s default fulfillment providers. It has the `price_type` attribute to indicate whether the shipping option’s rate is `calculated` by the provider or a fixed `flat_rate` price. It also has the `amount` attribute to set an amount for the shipping option if the `price_type` is `flat_rate`. `ShippingOption` also belongs to a `Region`, which resembles one or more countries. This defines where the shipping option is available. -`ShippingOption` has a set of `ShippingOptionRequirement` instances. The `ShippingOptionRequirement` model allows defining cart rules which determine whether the shipping option will be available or not for a customer during checkout. For example, you can set a minimum subtotal amount for a shipping option to be available for a customer’s cart. +`ShippingOption` has a set of `ShippingOptionRequirement` instances. The `ShippingOptionRequirement` entity allows defining cart rules which determine whether the shipping option will be available or not for a customer during checkout. For example, you can set a minimum subtotal amount for a shipping option to be available for a customer’s cart. The `is_return` attribute is used to indicate whether the shipping option is used for shipping orders or returning orders. Shipping options can only be used for one or the other. @@ -98,15 +107,13 @@ The `data` attribute does not have any specific format. It’s up to you to choo ## Shipping Method -### Overview - Unlike the previous two components, a shipping method is not created by the admin. It’s created when a `POST` request is sent to `/store/carts/:id/shipping-methods` after the customer chooses a shipping option. The shipping method will be created based on the chosen shipping option and it’ll be associated with the customer’s cart. Then, when the order is placed, the shipping method is associated with the order. A shipping method can be fulfilled automatically or manually through the admin dashboard. This is based on the fulfillment provider associated with the shipping option the shipping method is based on. -### Purpose +### Shipping Method Purpose It’s important to understand the distinction between shipping methods and shipping options. Shipping options are templates created by the admin to indicate what shipping options should be shown to a customer. This provides customization capabilities in a store, as an admin is free to specify configurations for that option such as what fulfillment provider it uses or what are its rates. @@ -114,17 +121,17 @@ When handling the order and fulfilling it, you, as a developer, will be mostly i This separation allows for developers to implement the custom integration with third-party fulfillment providers as necessary while also ensuring that the admin has full control of their store. -## Model Overview +## ShippingMethod Entity Overview A lot of the shipping method’s attributes are similar to the shipping option’s attribute. -The `ShippingMethod` model belongs to a `ShippingOption`. +The `ShippingMethod` entity belongs to a `ShippingOption`. -Similar to the `data` attribute explained for the `ShippingOption` model, a `ShippingMethod` has a similar `data` attribute that includes all the data to be sent to the fulfillment provider when fulfilling the order. +Similar to the `data` attribute explained for the `ShippingOption` entity, a `ShippingMethod` has a similar `data` attribute that includes all the data to be sent to the fulfillment provider when fulfilling the order. The `ShippingMethod` belongs to a `Cart`. This is the cart the customer is checking out with. -The `ShippingMethod` also belongs to the `Order` model. This association is accomplished when the order is placed. +The `ShippingMethod` also belongs to the `Order` entity. This association is accomplished when the order is placed. The `ShippingMethod` instance holds a `price` attribute, which will either be the flat rate price or the calculated price. diff --git a/docs/content/advanced/backend/subscribers/events-list.md b/docs/content/advanced/backend/subscribers/events-list.md index 21b917d10f..333e5c428a 100644 --- a/docs/content/advanced/backend/subscribers/events-list.md +++ b/docs/content/advanced/backend/subscribers/events-list.md @@ -167,7 +167,7 @@ Triggered when a cart and data associated with it (payment sessions, shipping me -The entire cart as an object. You can refer to the [Cart model](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/cart.ts) for an idea of what fields to expect. +The entire cart as an object. You can refer to the [Cart entity](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/cart.ts) for an idea of what fields to expect. @@ -476,7 +476,7 @@ Triggered when a customer is created. -The entire customer passed as an object. You can refer to the [Customer model](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/customer.ts) for an idea of what fields to expect. +The entire customer passed as an object. You can refer to the [Customer entity](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/customer.ts) for an idea of what fields to expect. @@ -494,7 +494,7 @@ Triggered when a customer is updated including their information or password, or -The entire customer passed as an object. You can refer to the [Customer model](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/customer.ts) for an idea of what fields to expect. +The entire customer passed as an object. You can refer to the [Customer entity](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/customer.ts) for an idea of what fields to expect. @@ -1338,7 +1338,7 @@ Triggered when a product and data associated with it (options, variant orders, e -The entire product passed as an object. You can refer to the [Product model](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/product.ts) for an idea of what fields to expect. +The entire product passed as an object. You can refer to the [Product entity](https://github.com/medusajs/medusa/blob/master/packages/medusa/src/models/product.ts) for an idea of what fields to expect. diff --git a/docs/content/advanced/backend/upgrade-guides/1-3-0.md b/docs/content/advanced/backend/upgrade-guides/1-3-0.md index 8c34f81a2b..74148cfeda 100644 --- a/docs/content/advanced/backend/upgrade-guides/1-3-0.md +++ b/docs/content/advanced/backend/upgrade-guides/1-3-0.md @@ -58,7 +58,7 @@ const dotenv = require('dotenv') This new version of Medusa allows store operators to adjust line items in an order or a swap which provides more customization capabilities. -It introduces a new model `LineItemAdjustment` which gives more flexibility to adjust the pricing of line items in a cart, order, or swap. A discount can be added, removed, or modified and the price will reflect on the total calculation of the cart, order, or swap. +It introduces a new entity `LineItemAdjustment` which gives more flexibility to adjust the pricing of line items in a cart, order, or swap. A discount can be added, removed, or modified and the price will reflect on the total calculation of the cart, order, or swap. This also introduces an optimization to the calculation of totals, as it is no longer necessary to calculate the discounts every time the totals are retrieved. @@ -76,7 +76,7 @@ node ./node_modules/@medusajs/medusa/dist/scripts/line-item-adjustment-migration This new version of Medusa holds advanced promotions functionalities to provide store operators with even more customization capabilities when creating discounts. You can now add even more conditions to your discounts to make them specific for a set of products, collections, customer groups, and more. -This change required creating a new model `DiscountCondition` which belongs to `DiscountRule` and includes a few relationships with other models to make the aforementioned feature possible. +This change required creating a new entity `DiscountCondition` which belongs to `DiscountRule` and includes a few relationships with other entities to make the aforementioned feature possible. ### Actions Required diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 84ca07f9f0..5d0ebc2202 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -112,12 +112,12 @@ module.exports = { { type: "doc", id: "advanced/backend/endpoints/add-storefront", - label: "Add Endpoint for Storefront" + label: "Create Endpoint for Storefront" }, { type: "doc", id: "advanced/backend/endpoints/add-admin", - label: "Add Endpoint for Admin" + label: "Create Endpoint for Admin" }, ] }, @@ -129,7 +129,7 @@ module.exports = { { type: "category", label: 'Subscribers', - collapsed: false, + collapsed: true, items: [ { type: "doc", @@ -161,7 +161,7 @@ module.exports = { { type: "doc", id: "advanced/backend/shipping/add-fulfillment-provider", - label: "Add Fulfillment Provider" + label: "Create a Fulfillment Provider" } ] }, @@ -178,6 +178,7 @@ module.exports = { { type: "doc", id: "advanced/backend/payment/how-to-create-payment-provider", + label: "Create a Payment Provider" }, ] }, From 6e96c7fccba8f69b69658df285c7acd889a8eb9b Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 13:13:01 +0300 Subject: [PATCH 26/34] chore: Added issue template for docs (#1665) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * added issue template for docs * added emoji * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * added issue template for docs * added emoji Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/docs.yml | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/docs.yml diff --git a/.github/ISSUE_TEMPLATE/docs.yml b/.github/ISSUE_TEMPLATE/docs.yml new file mode 100644 index 0000000000..b83874e43e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs.yml @@ -0,0 +1,48 @@ +name: 📚 Documentation +description: Report errors you find in our documentation or ideas for enhancing our documentation +labels: ["type: docs"] +body: + - type: markdown + attributes: + value: | + # Hello 👋 + + Thanks for taking the time to fill out this issue. + Please fill out each section below. This info helps Medusa maintainers understand the issue better and fix it in a short time. + + Useful links: + + - Contribution Guidelines: https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md + - Documentation: https://docs.medusajs.com/ + - type: checkboxes + attributes: + label: Preliminary Checks + description: Please make sure that you verify each checkbox and follow the instructions for them. + options: + - label: "This issue is not a duplicate. Before opening a new issue, please search existing issues: https://github.com/medusajs/medusa/issues" + required: true + - type: textarea + validations: + required: true + attributes: + label: Issue Summary + description: | + What is the error you found in our documentation or what do you think should be enhanced? + - type: textarea + validations: + required: false + attributes: + label: How can this issue be resolved? + description: If you have an idea of how the issue can be resolved, please details the steps below. + value: | + 1. + 2. + 3. + ... + - type: checkboxes + attributes: + label: Are you interested in working on this issue? + description: If you're interested in not only reporting this issue but also fix it, check the box below. + options: + - label: "I would like to fix this issue" + required: false \ No newline at end of file From 53163169d028b2d567c7331e4741e7ed9d4f39c2 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 13:36:43 +0300 Subject: [PATCH 27/34] docs: add details regarding the file path of migrations (#1666) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * docs: add details regarding the file path of migrations * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * chore: Added issue template for docs (#1665) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * added issue template for docs * added emoji * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * added issue template for docs * added emoji Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * docs: add details regarding the file path of migrations Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> --- docs/content/advanced/backend/migrations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/advanced/backend/migrations.md b/docs/content/advanced/backend/migrations.md index 6fec10cb73..6d5635bec3 100644 --- a/docs/content/advanced/backend/migrations.md +++ b/docs/content/advanced/backend/migrations.md @@ -57,12 +57,12 @@ In this section, you’ll learn how to create your own migrations using [Typeorm To create a migration that makes changes to your Medusa schema, run the following command: ```bash -npx typeorm migration:create -n UserChanged --dir src/path +npx typeorm migration:create -n UserChanged --dir src/migrations ``` :::tip -The migration file should be inside the src directory to make sure it is built when the build command is run next. +The migration file must be inside the `src/migrations` directory. When the build command is run, it will be transpiled into the directory `dist/migrations`. The `migrations run` command can only pick up migrations under the `dist/migrations` directory. ::: From da1c6558976df8ee8b9646f1a0fd45f77be51728 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 13:52:57 +0300 Subject: [PATCH 28/34] docs: add upgrade guides index page (#1670) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * add upgrade guides index page * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * chore: Added issue template for docs (#1665) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * added issue template for docs * added emoji * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * added issue template for docs * added emoji Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * docs: add details regarding the file path of migrations (#1666) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * docs: add details regarding the file path of migrations * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * chore: Added issue template for docs (#1665) * added integration * add segment for API reference * updated frontend checkout flow * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * added issue template for docs * added emoji * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * docs: fixes in shipping, payment, and other documentations * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * fixes * fixes for payment provider * fixes * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * chore: Add issue template for bug reports (#1676) * chore: Add issue template for feature requests (#1679) * fixes * fixes for payment provider * fixes Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * added issue template for docs * added emoji Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * docs: add details regarding the file path of migrations Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * add upgrade guides index page Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/content/advanced/backend/upgrade-guides/index.mdx | 8 ++++++++ www/docs/sidebars.js | 4 ++++ www/docs/src/css/custom.css | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 docs/content/advanced/backend/upgrade-guides/index.mdx diff --git a/docs/content/advanced/backend/upgrade-guides/index.mdx b/docs/content/advanced/backend/upgrade-guides/index.mdx new file mode 100644 index 0000000000..7c2c8cb261 --- /dev/null +++ b/docs/content/advanced/backend/upgrade-guides/index.mdx @@ -0,0 +1,8 @@ +import DocCardList from '@theme/DocCardList'; +import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; + +# Upgrade Guides + +Find in this page the upgrade guides that require necessary steps when upgrading to a new version. + + \ No newline at end of file diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 5d0ebc2202..17c8971519 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -215,6 +215,10 @@ module.exports = { type: "category", label: 'Upgrade Guides', collapsed: true, + link: { + type: 'doc', + id: 'advanced/backend/upgrade-guides/index' + }, items: [ { type: "doc", diff --git a/www/docs/src/css/custom.css b/www/docs/src/css/custom.css index 9a0128dc2c..4fe42e05f1 100644 --- a/www/docs/src/css/custom.css +++ b/www/docs/src/css/custom.css @@ -259,7 +259,7 @@ html:not([data-theme="dark"]) footer { /* Cards */ html:not([data-theme=dark]) .card { - border: 1px solid #1f1f1f; + border: 1px solid #cbcbcb; border-radius: 8px; } From 86601e8130fe19d9db1ec483a640acd1602aec0b Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 13:53:19 +0300 Subject: [PATCH 29/34] docs: added usage documentation (#1639) * added integration * add segment for API reference * updated frontend checkout flow * added paypal documentation * Improve storefront quickstart documents * added documentation for entities * docs: disable running tests for docs * added docs contribution guidelines * Use npm2yarn where missing * added additional steps section * added notification overview * Added guidelines for sidebar labels * added how to create notification provider * added usage documentation * chore(deps): bump sqlite3 from 5.0.2 to 5.0.3 (#1453) Bumps [sqlite3](https://github.com/TryGhost/node-sqlite3) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/TryGhost/node-sqlite3/releases) - [Changelog](https://github.com/TryGhost/node-sqlite3/blob/master/CHANGELOG.md) - [Commits](https://github.com/TryGhost/node-sqlite3/compare/v5.0.2...v5.0.3) * fix: Issue with cache in CI pipeline * Use npm2yarn where missing * added integration * add segment for API reference * fix double segment * updated frontend checkout flow * added documentation for entities * added docs contribution guidelines * Added guidelines for sidebar labels * added additional steps section * added notification overview * added how to create notification provider * added usage documentation Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> --- docs/content/usage.md | 50 +++++++++++++++++++++++++++++++++++++++++++ www/docs/sidebars.js | 4 ++++ 2 files changed, 54 insertions(+) create mode 100644 docs/content/usage.md diff --git a/docs/content/usage.md b/docs/content/usage.md new file mode 100644 index 0000000000..27b18f84f4 --- /dev/null +++ b/docs/content/usage.md @@ -0,0 +1,50 @@ +# Collected Usage Information + +This document gives an overview of Medusa’s optional collected usage information, how it helps Medusa become a better platform, and how developers can opt out of this feature. + +## Overview + +At Medusa, we strive to provide the best experience for developers using our platform. For that reason, Medusa collects anonymous and non-sensitive data that provides a global understanding of how users are using Medusa on a live server. + +## Purpose + +As an open source solution, we work closely and constantly interact with our community to ensure that we provide the best experience for everyone using Medusa. + +We are capable of getting a general understanding of how developers use Medusa and what general issues they run into through different means such as our Discord server, GitHub issues and discussions, and occasional one-on-one sessions. + +However, although these methods can be insightful, they’re not enough to get a full and global understanding of how developers are using Medusa, especially in production. + +Collecting this data allows us to understand certain details such as: + +- What operating system do most Medusa developers use? +- What version of Medusa is widely used? +- What Node version is globally used? Should we focus our efforts on providing support for versions that we don’t currently support? + +## Collected Data + +The following data is being collected on your server: + +- Unique project ID generated with UUID. +- Unique machine ID generated with UUID. +- Operating system information including Node version or operating system platform used. +- The version of the Medusa server and Medusa CLI used. + +:::info + +Data is only collected when the server is run with the command `medusa start`. + +::: + +## How to Opt-Out + +If you prefer to disable data collection, you can do it either by setting the following environment variable to true: + +```bash +MEDUSA_DISABLE_TELEMETRY=true +``` + +Or, you can run the following command in the root of your Medusa server project to disable it: + +```bash +medusa telemetry --disable +``` diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 17c8971519..57d9b3289f 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -26,6 +26,10 @@ module.exports = { id: "quickstart/quick-start", label: "Quickstart Guide", }, + { + type: "doc", + id: "usage", + }, { type: "category", collapsed: false, From 8a4a7125b86776b9bc5f9c06b1bee594f64a6d73 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 13:53:49 +0300 Subject: [PATCH 30/34] docs: updated homepage (#1687) --- docs/content/homepage.md | 81 ++++++++++++++++++++++++++++++++ docs/content/homepage.mdx | 97 --------------------------------------- 2 files changed, 81 insertions(+), 97 deletions(-) create mode 100644 docs/content/homepage.md delete mode 100644 docs/content/homepage.mdx diff --git a/docs/content/homepage.md b/docs/content/homepage.md new file mode 100644 index 0000000000..d103a31d89 --- /dev/null +++ b/docs/content/homepage.md @@ -0,0 +1,81 @@ +--- +id: homepage +title: Overview +description: 'What is Medusa?' +slug: / +hide_table_of_contents: true +--- + +Welcome to Medusa, the open source Shopify alternative! + +Medusa is an open-source headless commerce engine that enables developers to create amazing digital commerce experiences. + +:::tip + +Get started with Medusa in a few minutes with our [Quickstart guide](./quickstart/quick-start.md)! + +::: + +## Features + +Medusa comes with a set of building blocks that allow you to create unique digital commerce experiences, below is a list of some of the features that Medusa comes with out of the box: + +- **Headless**: Medusa is a highly customizable commerce API which means that you may use any presentation layer such as a website, app, chatbots, etc. +- **Regions** allow you to specify currencies, payment providers, shipping providers, tax rates, and more for one or more countries for truly international sales. +- **Orders** come with all the functionality necessary to perform powerful customer service operations with ease. +- **Carts** allow customers to collect products for purchase, add shipping details, and complete payments. +- **Products** come with relevant fields for customs, stock keeping, and sales. Medusa supports multiple options and unlimited variants. +- **Swaps** allow customers to exchange products after purchase (e.g. for incorrect sizes). Accounting, payment, and fulfillment plugins handle all the tedious work for you for automated customer service. +- **Claims** can be created if customers experience problems with one of their products. Plugins make sure to automate sending out replacements, handling refunds, and collecting valuable data for analysis. +- **Returns** allow customers to send back products and can be configured to function in 100% automated flow-through accounting and payment plugins. +- **Fulfillment API** makes it easy to integrate with any fulfillment provider by creating fulfillment plugins. +- **Payments API** makes it easy to integrate with any payment provider by creating payment plugins, we already support Stripe, Paypal, and Klarna. +- **Notification API** allows integrations with email providers, chatbots, Slack channels, etc. +- **Customer Login** gives customers a way of managing their data, viewing their orders, and saving payment details. +- **Shipping Options & Profiles** enable powerful rules for free shipping limits, multiple fulfillment methods, and more. +- **Medusa's Plugin Architecture** makes it intuitive and easy to manage your integrations, switch providers and grow with ease. +- **Customization** is supported for those special use cases that all the other e-commerce platforms can't accommodate. + +## Where to Get Started + +### The Medusa Server + +The first step is to [set up your development environment](tutorial/set-up-your-development-environment) with the requirements necessary to run a Medusa server. + +Then, you can follow our [quickstart guide](quickstart/quick-start.md) to install and run a Medusa server. + +### The Medusa Admin + +The Medusa Admin provides you with a lot of functionalities and configurations such as Product Management, Order Management, Discounts and Promotions, and more. + +You can install the Medusa admin in 2 steps by following our [Medusa Admin quickstart guide](admin/quickstart.md). + +### The Storefront + +The final step is to set up a storefront to sell your products. + +Medusa provides 2 starter storefronts, one built with [Next.js](./starters/nextjs-medusa-starter.md) and one with [Gatsby](./starters/gatsby-medusa-starter.md), that you can use to quickly set up your store and start selling. + +Alternatively, you can build your own storefront with any frontend framework of your choice just by connecting to your server with the [Storefront REST APIs](https://docs.medusajs.com/api/store/collection). + +## What’s Next 🚀 + +- Customize your Medusa server by creating your own [endpoints](./advanced/backend/endpoints/add-storefront.md), [services](./advanced/backend/services/create-service.md), and [subscribers](./advanced/backend/subscribers/create-subscriber.md). +- Check out guides under the Integrations section to install plugins for [CMS](./add-plugins/strapi.md), [Payment](./add-plugins/stripe.md), [Search Engines](./add-plugins/algolia.md), and more. +- Deploy your Medusa server in seconds on [Heroku](./how-to/deploying-on-heroku.md), [Qovery](./how-to/deploying-on-qovery.md), or [Digital Ocean](./how-to/deploying-on-digital-ocean.md). + +## Open Source Contribution + +As Medusa is an open source platform, contributions to improve it and its documentation are welcome. In the GitHub repository here’s where you’ll find the different components you can contribute to: + +- The core of the Medusa server resides in [`packages/medusa`](https://github.com/medusajs/medusa/tree/master/packages/medusa). +- You can also find all existing plugins under [the `packages` directory](https://github.com/medusajs/medusa/tree/master/packages). +- The documentation content resides in [`docs/content`](https://github.com/medusajs/medusa/tree/master/docs/content). The code for the documentation website is in [`www/docs`](https://github.com/medusajs/medusa/tree/master/www/docs). + +You can find more details about contributing in [CONTRIBUTING.md](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +## Community & Support + +If you need any support during your development with Medusa, you can join our [Discord Server](https://discord.gg/medusajs). You will get help directly from our core team as well as our community. + +By joining our Discord Server, you’ll also have the chance to participate in many events such as Bug Hunts and showcase your work with Medusa. \ No newline at end of file diff --git a/docs/content/homepage.mdx b/docs/content/homepage.mdx deleted file mode 100644 index 63a7c8740d..0000000000 --- a/docs/content/homepage.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: homepage -title: Overview -description: 'What is Medusa?' -slug: / -hide_table_of_contents: true ---- - -import useBaseUrl from '@docusaurus/useBaseUrl' -import Link from '@docusaurus/Link' -import Tabs from '@theme/Tabs' -import TabItem from '@theme/TabItem' - -Medusa is an open-source Shopify alternative. - -It provides you with the primitives to create amazing digital commerce experiences. - -## Architecture overview - -Medusa is composed of 3 components: The headless backend, the admin dashboard, and the storefront. - -You can learn more about Medusa's architecture in [our introduction](/introduction). - -![Medusa's Architecture](https://i.imgur.com/ZHvM2bu.png) - -
-
-
- -
-

Tutorial

-

Set up your local development environment

-
- -
-
- -
-

Make it your own

-

Create custom endpoints, services, or subscribers.

-
- -
-
- -
-

Plugins

-

Add or build a plugin to make your engine more powerful.

-
- -
-
- -
-

Deploy in seconds

-

Use one of our guides to deploy your Medusa project in seconds.

-
- -
-
-
- -## Quickstart - -Visit our [Quickstart](https://github.com/medusajs/medusa#-quickstart) to get up and running in minutes with only a couple of commands. - -## What you'll find here - -
-
-
- -
-

Quickstart

-

A short guide to get you quickly started.

-
- -
-
- -
-

How-to and guides

-

Guides and walkthroughs of concepts, tools, deployment and APIs.

-
- -
- {/* Ref */} - -
-
From a4e0c074f0a5322e532b6853c6f290872bc0483b Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 14:13:05 +0300 Subject: [PATCH 31/34] docs: improved plugin documentation (#1686) * added plugin documentation * replace incorrect plugin links * small fixes --- docs/content/add-plugins/mailchimp.md | 2 +- .../how-to-create-notification-provider.md | 4 +- .../advanced/backend/notification/overview.md | 2 +- .../advanced/backend/payment/overview.md | 2 +- .../advanced/backend/plugins/create.md | 371 ++++++++++++++++++ .../advanced/backend/plugins/overview.md | 54 +++ .../advanced/backend/shipping/overview.md | 2 +- docs/content/guides/file-plugin.md | 2 +- docs/content/guides/fulfillment-api.md | 4 +- docs/content/guides/plugins.md | 150 ------- docs/content/how-to/create-medusa-app.md | 2 +- www/docs/docusaurus.config.js | 2 +- www/docs/sidebars.js | 16 +- 13 files changed, 450 insertions(+), 163 deletions(-) create mode 100644 docs/content/advanced/backend/plugins/create.md create mode 100644 docs/content/advanced/backend/plugins/overview.md delete mode 100644 docs/content/guides/plugins.md diff --git a/docs/content/add-plugins/mailchimp.md b/docs/content/add-plugins/mailchimp.md index 6dd4f94ffd..abaae99f58 100644 --- a/docs/content/add-plugins/mailchimp.md +++ b/docs/content/add-plugins/mailchimp.md @@ -180,4 +180,4 @@ If you try entering an email and clicking Subscribe, the email will be subscribe ## What’s Next 🚀 - Check out SendGrid plugin for more Email functionalities. -- [Learn more about plugins.](https://docs.medusajs.com/guides/plugins) \ No newline at end of file +- [Learn more about plugins.](../advanced/backend/plugins/overview.md) \ No newline at end of file diff --git a/docs/content/advanced/backend/notification/how-to-create-notification-provider.md b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md index 73ec0e949c..bc5dcd7786 100644 --- a/docs/content/advanced/backend/notification/how-to-create-notification-provider.md +++ b/docs/content/advanced/backend/notification/how-to-create-notification-provider.md @@ -78,7 +78,7 @@ Additionally, if you’re creating your Notification Provider as an external plu :::info -You can learn more about plugins and how to create them in the [Plugins](../../../guides/plugins.md) documentation. +You can learn more about plugins and how to create them in the [Plugins](../plugins/overview.md) documentation. ::: @@ -268,5 +268,5 @@ This request returns the same notification object as the List Notifications endp - Check out the [list of events](../subscribers/events-list.md) you can listen to. - Check out the [SendGrid](../../../add-plugins/sendgrid.mdx) plugin for easy integration of email notifications. -- Learn how to [create your own plugin](../../../guides/plugins.md). +- Learn how to [create your own plugin](../plugins/create.md). - Learn more about [Subscribers](../subscribers/create-subscriber.md) and [Services](../services/create-service.md). diff --git a/docs/content/advanced/backend/notification/overview.md b/docs/content/advanced/backend/notification/overview.md index b2ed328272..e22d5b9a94 100644 --- a/docs/content/advanced/backend/notification/overview.md +++ b/docs/content/advanced/backend/notification/overview.md @@ -16,7 +16,7 @@ An example of a notification provider is SendGrid. When an order is placed, the ### How Notification Provider is Created -A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../../../guides/plugins.md), or it can be created just as a Service file in your Medusa server. +A Notification Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the [`NotificationService`](../../../references/services/classes/NotificationService.md) provided by the `medusa-interfaces` package. It can be created as part of a [Plugin](../plugins/overview.md), or it can be created just as a Service file in your Medusa server. As a developer, you mainly work with the Notification Provider when integrating a third-party service that handles notifications in Medusa. diff --git a/docs/content/advanced/backend/payment/overview.md b/docs/content/advanced/backend/payment/overview.md index 1c3e68ff78..b5650ae9e0 100644 --- a/docs/content/advanced/backend/payment/overview.md +++ b/docs/content/advanced/backend/payment/overview.md @@ -24,7 +24,7 @@ Payment Providers can also be related to a custom way of handling payment operat ### How Payment Provider is Created -A Payment Provider is essentially a Medusa [service](../services/create-service.md) with a unique identifier, and it extends the `PaymentService` provided by the `medusa-interfaces` package. It can be created as part of a [plugin](../../../guides/plugins.md), or it can be created just as a service file in your Medusa server. +A Payment Provider is essentially a Medusa [service](../services/create-service.md) with a unique identifier, and it extends the `PaymentService` provided by the `medusa-interfaces` package. It can be created as part of a [plugin](../plugins/overview.md), or it can be created just as a service file in your Medusa server. As a developer, you will mainly work with the Payment Provider when integrating a payment method in Medusa. diff --git a/docs/content/advanced/backend/plugins/create.md b/docs/content/advanced/backend/plugins/create.md new file mode 100644 index 0000000000..5a956ecd9a --- /dev/null +++ b/docs/content/advanced/backend/plugins/create.md @@ -0,0 +1,371 @@ +# Create a Plugin + +In this document, you’ll learn how to create a plugin and publish it. If you’re interested to learn more about what plugins are and where to find available official and community plugins, check out the [overview document](overview.md). + +## Prerequisites + +This guide uses the Medusa CLI throughout different steps. If you don’t have the Medusa CLI installed you can install it with the following command: + +```bash npm2yarn +npm install @medusajs/medusa-cli -g +``` + +## Initialize Project + +The recommended way to create a plugin is using the Medusa CLI. Run the following command to create a new Medusa project: + +```bash +medusa new medusa-plugin-custom +``` + +Where `medusa-plugin-custom` is the name of the plugin you’re creating. In Medusa, plugins are named based on their functionalities. + +By convention, all plugin names start with `medusa` followed by a descriptive name of what the plugin does. For example, the Stripe plugin is named `medusa-payment-stripe`. + +### Project Structure + +The command above creates a new directory `medusa-plugin-custom` that holds essentially the same codebase you would have for a Medusa server. This is because a plugin has the same directory structure as a Medusa server. + +Under the `src` directory is where the code of your plugin resides. After running the previous command, you should have at least 3 directories inside the `src` directory: + +- `api` is where you can add custom endpoints. +- `services` is where you can add custom services. +- `subscribers` is where you can add custom subscribers. + +You can also add more directories and files to your plugin including: + +- `src/models` for adding custom entities or extending existing entities. +- `src/migrations` for migrations that make changes to the database schema. + +## Change Dependencies in package.json + +A basic Medusa server installed with the `medusa new` command has dependencies similar to this: + +```json +"dependencies": { + "@medusajs/medusa": "^1.3.1", + "@medusajs/medusa-cli": "^1.3.0", + "medusa-fulfillment-manual": "^1.1.31", + "medusa-interfaces": "^1.3.0", + "medusa-payment-manual": "^1.0.16", + "medusa-payment-stripe": "^1.1.38", + "mongoose": "^5.13.3", + "typeorm": "^0.2.36" +}, +"devDependencies": { + "@babel/cli": "^7.14.3", + "@babel/core": "^7.14.3", + "@babel/preset-typescript": "^7.14.5", + "babel-preset-medusa-package": "^1.1.19" +} +``` + +For a plugin, a lot of these dependencies are not necessary or should be labeled as [peer dependencies](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies). Therefore, it’s important to make changes to the dependencies of your plugin. + +The recommended change is the following: + +```json +"peerDependencies": { + "@medusajs/medusa": "^1.3.1", + "medusa-interfaces": "^1.3.0", + "typeorm": "^0.2.36" +}, +"devDependencies": { + "@babel/cli": "^7.14.3", + "@babel/core": "^7.14.3", + "@babel/preset-typescript": "^7.14.5", + "babel-preset-medusa-package": "^1.1.19", +} +``` + +The packages `@medusajs/medusa` and `medusa-interfaces` act as peer dependencies. They’ll be installed while you develop your package, and they are required when your plugin is installed in another NPM project. + +You remove the packages `medusa-fulfillment-manual`, `medusa-payment-manual`, and `medusa-payment-stripe` as they are fulfillment and payment plugins necessary for a Medusa server, but not for a plugin. + +Additionally, you remove `@medusajs/medusa-cli` as you don’t need to use the Medusa CLI while developing a plugin. + +Once you’re done making these changes, re-run the install command to update your `node_modules` directory: + +```bash npm2yarn +npm install +``` + +## Recommended Changes in package.json + +This section includes recommended changes to your `package.json`. You can skip any of these changes if you don’t find them necessary to your plugin. + +### Change Basic Info + +`package.json` holds information that further describes the package or the author that created the package. It is recommended to make the following changes: + +- `description`: Change this to a sentence that describes what your plugin does. +- `author`: Your name and email. +- `repository`: The repository that holds your plugin’s codebase. +- `keywords`: This should hold the keywords that are related to your plugin. It’s recommended that all plugins use the keywords `medusa-plugin` or `medusa`. + +### Change scripts + +A basic Medusa installation comes with the following scripts: + +```json +"scripts": { + "seed": "medusa seed -f ./data/seed.json", + "build": "babel src -d dist --extensions \".ts,.js\"", + "start": "medusa develop" +} +``` + +The `seed` and `start` scripts are not necessary for plugin development so you can remove them. + +It’s also recommended to add the `watch` script that automatically compiles your files if they are changed: + +```json +"watch": "babel -w src --out-dir . --ignore **/__tests__" +``` + +This is helpful when testing the plugin. + +:::note + +Testing the plugin is covered in a later section. + +::: + +Another recommended script is the `prepare` script that builds your files under a “production” environment: + +```json +"prepare": "cross-env NODE_ENV=production npm run build" +``` + +You would typically run this script before publishing your plugin. + +This script requires installing the package `cross-env` as a development dependency: + +```bash npm2yarn +npm install --save-dev cross-env +``` + +## Develop your Plugin + +Now, You can start developing your plugin. This can include adding services, endpoints, entities, or anything that is relevant to your plugin. + +This guide does not cover how to create each of those files or components. If you’re interested in learning how to do that, you can check out these guides: + +- How to create endpoints for [storefront](../endpoints/add-storefront.md) and [admin](../endpoints/add-admin.md) +- How to [create a service](../services/create-service.md) +- How to [create a subscriber](../subscribers/create-subscriber.md) +- How to create an entity +- How to [create a migration](../migrations.md) + +## Add Plugin Configuration + +Plugins often allow developers that will later use them to enter their own configuration. For example, you can allow developers to specify the API key of a service you’re integrating. + +To pass a plugin its configurations on a Medusa server, you have to add it to the `plugins` array in `medusa-config.js`: + +```jsx +const plugins = [ + //... + { + resolve: `medusa-plugin-custom`, + options: { + name: 'My Store' + } + } +]; +``` + +Then, you can have access to your plugin configuration in the constructor of services in your plugin: + +```jsx +//In a service in your plugin +constructor({}, options) { + //options contains plugin configurations + this.name = options.name +} +``` + +You can also have access to the configurations in endpoints in your plugin: + +```jsx +//in an endpoint in your plugin +export default (rootDirectory, options) => { + //options contain the plugin configurations + const router = Router() + + router.get("/hello-world", (req, res) => { + res.json({ + message: `Welcome to ${options.name ? options.name : 'Medusa'}!` + }) + }) + + return router; +} +``` + +:::tip + +Make sure to include in the README of your plugin the configurations that can be passed to a plugin. + +::: + +## Test Your Plugin + +While you develop your plugin, you’ll need to test it on an actual Medusa server. This can be done by using the [npm link](https://docs.npmjs.com/cli/v8/commands/npm-link) command. + +In the root of your plugin directory, run the following command: + +```bash npm2yarn +npm link +``` + +Then, change to the directory of the Medusa server you want to test the plugin on and run the following command: + +```bash npm2yarn +npm link medusa-plugin-custom +``` + +Where `medusa-plugin-custom` is the package name of your plugin. + +After linking to your plugin in a local Medusa server, either run the `build` or `watch` commands in your plugin directory: + +```bash npm2yarn +# in the directory of the plugin +npm run watch +``` + +:::tip + +If you’re running the `watch` command, you don’t need to run the `build` command every time you make a change to your plugin. + +::: + +Then, add your plugin into the array of plugins in `medusa-config.js`: + +```jsx +const plugins = [ + //... + { + resolve: `medusa-plugin-custom`, + //if your plugin has configurations + options: { + name: 'My Store' + } + } +]; +``` + +:::note + +If your plugin has migrations, you must run them before you start the server. Check out the [Migrations guide](../migrations.md#run-migration) for more details. + +::: + +Finally, start your server and test your plugin’s functionalities: + +```bash npm2yarn +npm run start +``` + +## NPM Ignore File + +Not all files that you use while developing your plugin are necessary to be published. + +For example, the files you add in the `src` directory are compiled to a `dist` directory before publishing. Then, when a developer installs your plugin, they’ll just be using the files under the `dist` directory. + +So, you can ignore files and directories like `src` from the final published NPM package. + +To do that, create the file `.npmignore` with the following content: + +```bash +/lib +node_modules +.DS_store +.env* +/*.js +!index.js +yarn.lock +src +.gitignore +.eslintrc +.babelrc +.prettierrc + +#These are files that are included in a +#Medusa project and can be removed from a +#plugin project +medusa-config.js +Dockerfile +medusa-db.sql +develop.sh +``` + +## Publish Plugin + +Once you’re done developing your plugin you can publish the package on NPM’s registry so that other developers can benefit from it and use it. + +Before you publish a plugin, you must [create an account on NPM](https://www.npmjs.com/signup). + +### Login + +In your terminal, log in with your NPM account: + +```bash +npm login +``` + +You’ll be asked to enter your NPM email and password. + +### Publish Plugin Package + +Once you’re logged in, you can publish your package with the following command: + +```bash +npm publish +``` + +Your package is then published on NPM and everyone can use it and install it. + +### Update Plugin + +To update your plugin at a later point, you can run the following command to change the NPM version: + +```bash +npm version +``` + +Where `` indicates the type of version update you’re publishing. For example, it can be `major` or `minor`. + +You can see the [full list of types in NPM’s documentation](https://docs.npmjs.com/cli/v8/commands/npm-version). + +Then, publish the new update: + +```bash +npm publish +``` + +## Add Plugin to Medusa’s Repository + +All officially-supported plugins are available in the [`packages` directory of the Medusa GitHub repository](https://github.com/medusajs/medusa/tree/master/packages). + +If you’re interested in adding your plugin, you need to create a new pull request (PR) where you add your plugin inside the `packages` directory. Our team will then review your plugin, and if it’s approved the PR will be merged and your plugin will be available on Medusa’s repository. + +:::note + +Before contributing to the Medusa repository, please check out the [contribution guidelines](https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md). + +::: + +## Install a Plugin + +To install any published plugin, you can run the following command on any Medusa server project: + +```bash npm2yarn +npm install medusa-plugin-custom +``` + +## What’s Next 🚀 + +- Check out [available Services in Medusa](references/services/../../../../../references/services/classes/AuthService.md) that you can use in your plugin. +- Check out [available events](../subscribers/events-list.md) that you can listen to in Subscribers. +- Check out [available official plugins](https://github.com/medusajs/medusa/tree/master/packages). diff --git a/docs/content/advanced/backend/plugins/overview.md b/docs/content/advanced/backend/plugins/overview.md new file mode 100644 index 0000000000..d8b51f7de6 --- /dev/null +++ b/docs/content/advanced/backend/plugins/overview.md @@ -0,0 +1,54 @@ +# Plugins + +In this document, you’ll get an overview of plugins in Medusa, where to find them, and how to install them. If you want to learn how to create a plugin, check out [this guide](create.md) instead. + +## Overview + +Medusa was built with flexibility and extendibility in mind. All different components and functionalities in Medusa are built with an abstraction layer that gives developers the freedom to choose what services they want to use or how to implement a certain component in their ecommerce store. + +Developers can use plugins to take advantage of this abstraction, flexibility, and extendibility. Plugins allow developers to implement custom features or integrate third-party services into Medusa. + +For example, if you want to use Stripe as a payment provider in your store, then you can install the Stripe plugin on your server and use it. + +An alternative approach is developing a custom way of handling payment on your ecommerce store. Both approaches are achievable by either creating a plugin or using an existing plugin. + +Plugins run within the same process as the core Medusa server eliminating the need for extra server capacity, infrastructure, and maintenance. As a result, plugins can use all other services as dependencies and access the database. + +## Using Existing Plugins + +### Official Plugins + +Medusa has official plugins that cover different aspects and functionalities such as payment, CMS, fulfillment, and notifications. You can check out the available plugins under the [packages directory in the Medusa repository on GitHub](https://github.com/medusajs/medusa/tree/master/packages). + +:::tip + +To feature your plugin in our repository, you can send a pull request that adds your plugin into the `packages` directory. Our team will review your plugin and, if approved, will merge the pull request and add your plugin in the repository. + +::: + +### Community Plugins + +You can find community plugins by [searching NPM for the `medusa` or `medusa-plugin` keywords](https://www.npmjs.com/search?q=keywords%3Amedusa%2Cmedusa-plugin). + +You can also check the [Awesome Medusa repository](https://github.com/adrien2p/awesome-medusajs#plugins) for a list of community plugins among other resources. + +## How to Install a Plugin + +To install an existing plugin, in your Medusa server run the following command: + +```bash npm2yarn +npm install +``` + +Where `` is the package name of the plugin. For example, if you’re installing the Stripe plugin `` is `medusa-payment-stripe`. + +### Plugin Configuration + +If you’re installing an official plugin from the Medusa repository, you can find in its `README.md` file a list of configurations that are either required or optional. You can also refer to the documentation related to that plugin for more details on how to install, configure, and use it. + +For community plugins, please refer to the installation instructions of that plugin to learn about any required configurations. + +## What’s Next 🚀 + +- Learn how to [create your own plugin](create.md). +- Learn how to [create a fulfillment provider](../shipping/add-fulfillment-provider.md) or a [payment provider](../payment/how-to-create-payment-provider.md). diff --git a/docs/content/advanced/backend/shipping/overview.md b/docs/content/advanced/backend/shipping/overview.md index 6c217e7414..60acadef38 100644 --- a/docs/content/advanced/backend/shipping/overview.md +++ b/docs/content/advanced/backend/shipping/overview.md @@ -31,7 +31,7 @@ Fulfillment Providers can also be related to a custom way of handling fulfillmen ### How Fulfillment Provider is Created -A Fulfillment Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the `FulfillmentService` provided by the `medusa-interfaces` package. It can be created as part of a [plugin](../../../guides/plugins.md), or it can be created just as a Service file in your Medusa server. +A Fulfillment Provider is essentially a Medusa [Service](../services/create-service.md) with a unique identifier, and it extends the `FulfillmentService` provided by the `medusa-interfaces` package. It can be created as part of a [plugin](../plugins/overview.md), or it can be created just as a Service file in your Medusa server. As a developer, you will mainly work with the Fulfillment Provider when integrating a fulfillment method in Medusa. diff --git a/docs/content/guides/file-plugin.md b/docs/content/guides/file-plugin.md index 0112bdd8ed..c7b841240e 100644 --- a/docs/content/guides/file-plugin.md +++ b/docs/content/guides/file-plugin.md @@ -4,7 +4,7 @@ title: Create a file plugin # File Plugin -This guide will give an introduction about the File Service and steps required to create a custom file uploader plugin for Medusa. It build on article about [creating custom plugins](https://docs.medusajs.com/guides/plugins). +This guide will give an introduction about the File Service and steps required to create a custom file uploader plugin for Medusa. It build on article about [creating custom plugins](../advanced/backend/payment/overview.md). As an example, we will create a File plugin that uploads the product images to Cloudinary. diff --git a/docs/content/guides/fulfillment-api.md b/docs/content/guides/fulfillment-api.md index 47e3d3c385..d52fa8b8c0 100644 --- a/docs/content/guides/fulfillment-api.md +++ b/docs/content/guides/fulfillment-api.md @@ -6,7 +6,7 @@ title: Fulfillment API This guide will give an overview of Medusa's Fulfillment API and how it can be implemented to work with different fulfillment providers. Before digging deeper into the API it should be clarified what is meant by a fulfillment provider; in Medusa a fulfillment provider is typically a 3rd party service that can handle order data for the purpose of shipping the items in the order to a customer. Examples of fulfillment providers are: a carrier like UPS, a logistics platform like ShipBob or a 3PL solution. -Implementations of the Fulfillment API can be distributed as npm packages for easy installation through the plugin system, there are already a couple of examples of fulfillment plugins in the Medusa monorepo, you can identify these by looking for `medusa-fulfillment-*`. For further details on building and publishing plugins [please check this guide](https://docs.medusajs.com/guides/plugins). +Implementations of the Fulfillment API can be distributed as npm packages for easy installation through the plugin system, there are already a couple of examples of fulfillment plugins in the Medusa monorepo, you can identify these by looking for `medusa-fulfillment-*`. For further details on building and publishing plugins [please check this guide](../advanced/backend/payment/overview.md). ## Fulfillment Service Interface @@ -68,4 +68,4 @@ If the shipping option is configured to dynamically calculate the price of the t ## What's next? -Now that you have an overview of the Fulfillment API you can start developing your own fulfillment plugin. For a guide on how to create plugins [check this guide](https://docs.medusajs.com/how-to/plugins). If you have questions or issues please feel free to [join our Discord server](https://discord.gg/medusajs) for direct access to the engineering team. +Now that you have an overview of the Fulfillment API you can start developing your own fulfillment plugin. For a guide on how to create plugins [check this guide](../advanced/backend/payment/overview.md). If you have questions or issues please feel free to [join our Discord server](https://discord.gg/medusajs) for direct access to the engineering team. diff --git a/docs/content/guides/plugins.md b/docs/content/guides/plugins.md deleted file mode 100644 index 07fcf5e36d..0000000000 --- a/docs/content/guides/plugins.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: Plugins ---- - -# Plugins - -The purpose of this guide is to give an introduction to the structure of a plugin and the steps required to create one. It builds upon our article describing the process of [adding custom functionality](https://docs.medusajs.com/tutorial/adding-custom-functionality). It can be seen as the proceeding steps for extracting your custom functionality to a reusable package for other developers to use. - -## What is a plugin? - -Plugins offer a way to extend and integrate the core functionality of Medusa. - -In most commerce solutions, you can extend the basic features but it often comes with the expense of having to build standalone web applications. Our architecture is built such that plugins run within the same process as the core eliminating the need for extra server capacity, infrastructure and maintenance. As a result, the plugins can use all other services as dependencies and access the database. - -:::note - -You will notice that plugins vary in naming. The name should signal what functionality they provide. - -::: - -In the following sections, we will go through the basics of implementing a generic plugin. And finally, how to use it as part of your commerce setup. - -## Building a plugin - -A plugin is essentially a Node.js project of their own. They contain a file in root, `package.json`, that holds all metadata and dependencies of the project. - -The first step in creating a plugin is to initialize the Node.js project: - -```bash npm2yarn -npm init -``` - -This command will ask you to fill out your project's metadata, which will eventually be used when publishing the package to NPM. After this command completes, you are ready to start implementing the functionality. - -### Implementation - -We've already gone through the process of building custom services, endpoints, and subscribers in another tutorial, so this will not be repeated. The process is the same for the logic within a plugin, meaning that the functionality is loaded as part of the core if the correct naming convention is followed. - -To quickly get started with the implementation, we advise you to copy `/services/welcome.js`, `/api/index.js`, `/subscribers/welcome.js` and the config files from the tutorial and add them in `/src`. As a result, you should have the following folder structure: - -:::note - -Since the container resolution paths are automatically generated from the used directories and filenames you should avoid pre- or suffixing your file (e.g. `services/welcomeService.js` would result in the service being registered as `WelcomeServiceService`). - -::: - -```js -. -├── src -│ ├── api -│ └── index.js -│ └── services -│ └── welcome.js -│ └── subscribers -│ └── welcome.js -├── .babelrc -├── .gitignore -├── medusa-config.js -├── README.md -└── package.json -``` -Please note that you will need some build step before being able to properly load your plugin, since Medusa expects to find the directories (`api`, `services`, `subscribers`, `loaders`…) within the npm package root. In the simplest case, this could be you manually copying the folders from `src`. - -It is worth mentioning the difference between building a generic and a non-generic plugin. A non-generic plugin has a specific purpose such as processing payments or creating fulfillments. Medusa core depends on a specific implementation from such plugins, which is why we've created interfaces that enforce this. These can be found in `medusa-interfaces`. - -:::note - -Non-generic plugins are required to extend the correct interface, otherwise they will not be loaded correctly as part of your Medusa setup. - -::: - -For a more comprehensive walkthrough of the implementation of such plugins, see our guides: - -- How to build a fulfillment provider (Coming soon!) -- How to build a payment provider (Coming soon!) - -### Publishing - -In order for your plugin to become a part of the Medusa plugin ecosystem, you need to publish it to NPM. Make sure that you've included the `package.json` file. NPM uses the details of this file to configure the publishing. Please include `medusa` and `medusa-plugin` and possibly more in the `keywords` field of the `package.json`. - -```bash -{ - "name": "medusa-payment-stripe", - ... - "keywords": [ - "medusa", - "medusa-payment", - "medusa-plugin" - ], - "description": "Stripe Payment provider for Medusa Commerce", - ... -} -``` - -Finally, you should add a README for the plugin, such that the community understands the purpose of the plugin and how to install it. - -## Installation and configuration - -Official Medusa plugins can be found within the [mono repo](https://github.com/medusajs/medusa/tree/master/packages) and community plugins can be found by searching NPM for keywords such as `medusa` or `medusa-plugin`. - -Note: For plugins to become a part of the mono repo, we require you to submit a PR request. If approved, we will publish it under the Medusa organisation on Github. - -Plugins are distributed as NPM packages making it possible for developers to simply install and use a plugin via: - -```bash npm2yarn -npm install -``` - -After installing a plugin using your preferred package manager, it should be added to `medusa-config.js`. We allow you to provide options for plugins. These options can be used for anything ranging from provider requirements such as API keys or custom configuration used in the plugin's logic. These options are injected into the services, subscribers, and APIs of the plugin. - -The following steps will install the official Contentful plugin for your Medusa engine: - -### Step 1: Installation - -First, we add the plugin as a dependency to your project: - -```bash npm2yarn -npm install medusa-plugin-contentful -``` - -### Step 2: Configuration - -In the README of the plugin, you will see the options for the plugin. Some are required and some are optional. - -In your `medusa-config.js`, add the plugin and the required options: - -```js -const plugins = [ - ... - { - resolve: `medusa-plugin-contentful`, - options: { - space_id: "some_space_id", - access_token: "some_access_token", - environment: "some_environment", - }, - }, - ... -] -``` - -### Step 3: Usage - -Depending on the purpose of the plugin, you will now be able to use the extended functionality as part of your commerce setup. - -In this case, you will need to add a content type in Contentful with the fields described in the README. Products created in Medusa Admin will now be synced to Contentful, such that you can enrich them with more details enabling you to enhance the customer experience of your webshop. - -## Summary - -As a result of following this guide, you should now be able to both implement and install plugins for you Medusa project. diff --git a/docs/content/how-to/create-medusa-app.md b/docs/content/how-to/create-medusa-app.md index 27c78a2267..bd4a208aca 100644 --- a/docs/content/how-to/create-medusa-app.md +++ b/docs/content/how-to/create-medusa-app.md @@ -116,6 +116,6 @@ To learn more about Medusa, go through our docs to get some inspiration and guid - [Find out how to set up a Medusa project with Gatsby and Contentful](https://docs.medusajs.com/how-to/headless-ecommerce-store-with-gatsby-contentful-medusa) - [Move your Medusa setup to the next level with some custom functionality](https://docs.medusajs.com/tutorial/adding-custom-functionality) -- [Create your own Medusa plugin](https://docs.medusajs.com/guides/plugins) +- [Create your own Medusa plugin](../advanced/backend/payment/overview.md) If you have any follow-up questions or want to chat directly with our engineering team, we are always happy to meet you at our [Discord](https://discord.gg/DSHySyMu). diff --git a/www/docs/docusaurus.config.js b/www/docs/docusaurus.config.js index bafacec1c6..e5b7caf835 100644 --- a/www/docs/docusaurus.config.js +++ b/www/docs/docusaurus.config.js @@ -26,7 +26,7 @@ module.exports = { [ "docusaurus-plugin-segment", { - apiKey: process.env.SEGMENT_API_KEY + apiKey: process.env.SEGMENT_API_KEY || "temp" } ] ], diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 57d9b3289f..cda315899a 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -203,8 +203,20 @@ module.exports = { ] }, { - type: "doc", - id: "guides/plugins", + type: "category", + label: "Plugins", + collapsed: true, + items: [ + { + type: "doc", + id: "advanced/backend/plugins/overview", + label: "Overview" + }, + { + type: "doc", + id: "advanced/backend/plugins/create", + } + ] }, { type: "doc", From 88e83801f9586e8e762e8daba4ec875975c1a716 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 14:51:27 +0300 Subject: [PATCH 32/34] docs: fix broken link (#1694) --- docs/content/add-plugins/twilio-sms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/add-plugins/twilio-sms.md b/docs/content/add-plugins/twilio-sms.md index 44b09d9436..7d8a00bcc6 100644 --- a/docs/content/add-plugins/twilio-sms.md +++ b/docs/content/add-plugins/twilio-sms.md @@ -124,5 +124,5 @@ If you’re on a Twilio trial make sure that the phone number you entered on che ## What’s Next 🚀 -- Learn more about how [Notifications work in Medusa](../how-to/notification-api). +- Learn more about how [Notifications work in Medusa](../advanced/backend/notification/overview.md). - Install the [Medusa admin](../admin/quickstart.md) for functionalities like Gift Cards creation, swaps, claims, order return requests, and more. From 4be7d40771dc86c19a030437c02677e60bf56c7d Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Fri, 17 Jun 2022 17:03:12 +0300 Subject: [PATCH 33/34] added configurations documentation (#1696) --- docs/content/add-plugins/slack.md | 2 +- docs/content/admin/quickstart.md | 6 + docs/content/homepage.md | 4 +- docs/content/quickstart/quick-start.md | 32 +- .../content/starters/gatsby-medusa-starter.md | 6 + .../content/starters/nextjs-medusa-starter.md | 6 + .../0-set-up-your-development-environment.mdx | 81 +---- docs/content/usage/configurations.md | 286 ++++++++++++++++++ www/docs/sidebars.js | 5 + 9 files changed, 328 insertions(+), 100 deletions(-) create mode 100644 docs/content/usage/configurations.md diff --git a/docs/content/add-plugins/slack.md b/docs/content/add-plugins/slack.md index de9de6d45a..166d4d0513 100644 --- a/docs/content/add-plugins/slack.md +++ b/docs/content/add-plugins/slack.md @@ -33,7 +33,7 @@ Medusa's event system works by pushing data into a queue that is based on [Redis As the Slack plugin will listen to the `order.placed` event to know when to send notifications, you'll need to have Redis installed and configured with your Medusa server. -You can read the [Set up your development enviornment guideline](https://docs.medusajs.com/tutorial/set-up-your-development-environment) to learn more about how you can install and setup Redis. +You can read the [Set up your development enviornment guideline](../tutorial/0-set-up-your-development-environment.mdx#redis) to learn more about how you can install and setup Redis. ## Create Slack App diff --git a/docs/content/admin/quickstart.md b/docs/content/admin/quickstart.md index a8fe6c2d28..eba14beb8b 100644 --- a/docs/content/admin/quickstart.md +++ b/docs/content/admin/quickstart.md @@ -101,6 +101,12 @@ ADMIN_CORS= Make sure to replace `` with your URL. +:::info + +For more details about the Admin CORS configuration, check out the [Configure your Server documentation](../usage/configurations.md#admin-cors). + +::: + ## Admin Features Overview ### Order Management diff --git a/docs/content/homepage.md b/docs/content/homepage.md index d103a31d89..935c0c0229 100644 --- a/docs/content/homepage.md +++ b/docs/content/homepage.md @@ -40,9 +40,9 @@ Medusa comes with a set of building blocks that allow you to create unique digit ### The Medusa Server -The first step is to [set up your development environment](tutorial/set-up-your-development-environment) with the requirements necessary to run a Medusa server. +You can follow our [quickstart guide](quickstart/quick-start.md) to install and run a Medusa server. -Then, you can follow our [quickstart guide](quickstart/quick-start.md) to install and run a Medusa server. +It's also recommended to learn how to [set up your development environment](tutorial/set-up-your-development-environment) with the requirements tools and services to run a Medusa server, then [configure your Medusa server](usage/configurations.md). ### The Medusa Admin diff --git a/docs/content/quickstart/quick-start.md b/docs/content/quickstart/quick-start.md index 288e941610..378b5e1cdc 100644 --- a/docs/content/quickstart/quick-start.md +++ b/docs/content/quickstart/quick-start.md @@ -67,37 +67,11 @@ To upload product images to your Medusa server, you must install and configure o - [S3](../add-plugins/s3.md) - [DigitalOcean Spaces](../add-plugins/spaces.md) -### Environment Variables +### Server Configurations -Medusa allows you to choose how to load your environment variables. By default, it will only load environment variables on your system. +It's important to configure your Medusa server properly and learn how environment variables are loaded. -If you want to load environment variables from a `.env` file add the following at the top of `medusa-config.js`: - -```js -const dotenv = require('dotenv') - - let ENV_FILE_NAME = ''; - switch (process.env.NODE_ENV) { - case 'production': - ENV_FILE_NAME = '.env.production'; - break; - case 'staging': - ENV_FILE_NAME = '.env.staging'; - break; - case 'test': - ENV_FILE_NAME = '.env.test'; - break; - case 'development': - default: - ENV_FILE_NAME = '.env'; - break; - } - - try { - dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME }); - } catch (e) { - } -``` +You can learn more about configuring your server and loading environment variables in the [Configure your Server documentation](../usage/configurations.md). ## What's next :rocket: diff --git a/docs/content/starters/gatsby-medusa-starter.md b/docs/content/starters/gatsby-medusa-starter.md index f9effb6880..aa6b6f67fa 100644 --- a/docs/content/starters/gatsby-medusa-starter.md +++ b/docs/content/starters/gatsby-medusa-starter.md @@ -69,6 +69,12 @@ Then, on your server, update the environment variable `STORE_CORS` to the URL wi STORE_CORS=http://localhost: ``` +:::info + +For more details about the Store CORS configuration, check out the [Configure your Server documentation](../usage/configurations.md#storefront-cors). + +::: + ### Development Resources If you’re not familiar with Gatsby, you can learn more about it through the following resources: diff --git a/docs/content/starters/nextjs-medusa-starter.md b/docs/content/starters/nextjs-medusa-starter.md index 6894070c5b..e430c111d1 100644 --- a/docs/content/starters/nextjs-medusa-starter.md +++ b/docs/content/starters/nextjs-medusa-starter.md @@ -67,6 +67,12 @@ Then, on your server, update the environment variable `STORE_CORS` to the URL STORE_CORS=http://localhost: ``` +:::info + +For more details about the Store CORS configuration, check out the [Configure your Server documentation](../usage/configurations.md#storefront-cors). + +::: + ### Development Resources You can learn more about development with Next.js through [their documentation](https://nextjs.org/docs/getting-started). diff --git a/docs/content/tutorial/0-set-up-your-development-environment.mdx b/docs/content/tutorial/0-set-up-your-development-environment.mdx index 6f67bf99a2..395acde205 100644 --- a/docs/content/tutorial/0-set-up-your-development-environment.mdx +++ b/docs/content/tutorial/0-set-up-your-development-environment.mdx @@ -177,6 +177,12 @@ PostgreSQL is an open-source relational database system with more than 30 years Although you can use an SQLite database with Medusa which would require no necessary database installations, it is recommended to use a PostgreSQL database for your server. +:::tip + +After installing PostgreSQL, check out the [Configure your Server documentation](../usage/configurations.md#postgresql-configurations) to learn how to configure PostgreSQL to work with Medusa. + +::: + @@ -216,6 +222,12 @@ Medusa uses Redis as the event queue in the server. If you want to use subscribe If you don’t install and configure Redis with your Medusa server, then it will work without any events-related features. +:::tip + +After installing Redis, check out the [Configure your Server documentation](../usage/configurations.md#redis) to learn how to configure Redis to work with Medusa. + +::: + @@ -290,75 +302,8 @@ Here are some other options: It is not important which editor you use as long as you feel comfortable working with it. -## Configuring Your Server - -After installing all the requirements mentioned above and following along with our [quickstart guide](../quickstart/quick-start.md), you need to configure some information on your server to connect it to some of the requirements you installed. - -### PostgreSQL - -After creating a new database schema in PostgreSQL, you need to add the URL to connect to it on your Medusa server. - -To do that, add the following environment variable to the `.env` file on the root of your Medusa server: - -```bash -DATABASE_URL=postgres://:@:/ -``` - -Notice that there are some details in the URL above you need to fill in yourself: - -- ``: the username of the user that has access to the database schema you created. -- ``: the password of the user that has access to the database schema you created. -- ``: the hostname where the PostgreSQL database is hosted. In local development, you can use `localhost`. -- ``: the port where the PostgreSQL database can be contacted on the host. By default, it’s 5432**.** -- ``: the name of the database schema you created. - -Then, in `medusa-config.js`, change the following properties in the object `projecConfig`: - -```jsx -module.exports = { - projectConfig: { - ..., - database_url: DATABASE_URL, - database_type: "postgres", - // comment out or remove these lines: - // database_database: "./medusa-db.sql", - // database_type: "sqlite", - }, - plugins, -}; -``` - -The last recommended step is running the following command to migrate Medusa’s database schema into your database and seed the database with dummy data: - -```bash npm2yarn -npm run seed -``` - -### Redis - -After installing Redis and running the Redis server, you must configure Medusa to use it. - -In `.env` add a new environment variable: - -```bash -REDIS_URL=redis://localhost:6379 -``` - -This is the default Redis URL to connect to, especially in development. However, if you’re deploying your server, have configured your Redis installation differently, or just need to check the format of the connection URL, you can check [this guide](https://github.com/lettuce-io/lettuce-core/wiki/Redis-URI-and-connection-details) for more details. - -:::tip - -If you use the default connection string mentioned here then you can skip over adding the environment variable. - -::: - -Then, in `medusa-config.js`, comment out the following line in the object `projectConfig`: - -```jsx -redis_url: REDIS_URL, -``` - ## What’s Next 🚀 +- Learn how to [configure your Medusa server](../usage/configurations.md). - Learn how to install a storefront with [Next.js](../starters/nextjs-medusa-starter.md) or [Gatsby](./../starters/gatsby-medusa-starter.md). - Learn how to install the [Medusa Admin](../admin/quickstart.md). diff --git a/docs/content/usage/configurations.md b/docs/content/usage/configurations.md new file mode 100644 index 0000000000..b51027d614 --- /dev/null +++ b/docs/content/usage/configurations.md @@ -0,0 +1,286 @@ +# Configure your Server + +In this document, you’ll learn what configurations you can add to your Medusa server and how to add them. + +## Prerequisites + +This document assumes you already followed along with the [“Set up your development environment” documentation](../tutorial/0-set-up-your-development-environment.mdx) and have installed a Medusa server. + +## Medusa Configurations File + +The configurations for your Medusa server are in `medusa-config.js`. This includes database, Redis, and plugin configurations, among other configurations. + +Some of the configurations mentioned in this document are already defined in `medusa-config.js` with default values. It’s important that you know what these configurations are used for and how to set them. + +## Environment Variables + +In your configurations, you’ll often use environment variables. For example, when using API keys or setting your database URL. + +By default, Medusa loads environment variables from the system’s environment variables. Any different method you prefer to use or other location you’d prefer to load environment variables from you need to manually implement. + +:::info + +This change in how environment variables are loaded was introduced in version 1.3.0. You can learn more in the [upgrade guide for version 1.3.0](../advanced/backend/upgrade-guides/1-3-0.md). + +::: + +### Load from .env + +A common way to use environment variables during development or in production is using `.env` files. + +To load environment variables from a `.env` file, add the following at the top of `medusa-config.js`: + +```jsx +const dotenv = require('dotenv') + + let ENV_FILE_NAME = ''; + switch (process.env.NODE_ENV) { + case 'production': + ENV_FILE_NAME = '.env.production'; + break; + case 'staging': + ENV_FILE_NAME = '.env.staging'; + break; + case 'test': + ENV_FILE_NAME = '.env.test'; + break; + case 'development': + default: + ENV_FILE_NAME = '.env'; + break; + } + + try { + dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME }); + } catch (e) { + //handle error + } +``` + +This code snippet uses the [dotenv](https://www.npmjs.com/package/dotenv) library to load environment variables from a local file. The file chosen to be loaded will be loaded based on the current environment. + +:::note + +`dotenv` should be available to use in your Medusa server project without the need to install it. However, if it’s not available you can install it with the following command: + +```npm2yarn +npm install dotenv --save +``` + +::: + +## Database Configuration + +Medusa supports 2 database types: SQLite and PostgreSQL. + +:::tip + +You can use SQLite for development purposes, however, it’s recommended to use PostgreSQL. + +::: + +### SQLite Configurations + +For SQLite you mainly need 2 configurations: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + database_type: "sqlite", + database_database: "./medusa-db.sql", + }, +}; +``` + +Where `database_type` is `sqlite` and `database_database` is the location you want the SQLite database to be created in. + +### PostgreSQL Configurations + +For PostgreSQL you mainly need 2 configurations: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + database_type: "postgres", + database_url: DATABASE_URL, + }, +}; +``` + +Where `database_type` is `postgres` and `DATABASE_URL` is the URL connection string to your PostgreSQL database. You can check out how to format it in [PostgreSQL’s documentation](https://www.postgresql.org/docs/current/libpq-connect.html). + +### Common Configuration + +As Medusa internally uses [Typeorm](https://typeorm.io/) to connect to the database, the following configurations are also available: + +1. `database_logging`: enable or disable logging. +2. `database_extra`: extra options that you can pass to the underlying database driver. + +These configurations are not required and can be omitted. + +```jsx +module.exports = { + projectConfig: { + //...other configurations + database_logging: true, + database_extra: {} + }, +}; +``` + +## Redis + +Medusa uses Redis to handle the event queue, among other usages. You need to set Redis URL in the configurations: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + redis_url: REDIS_URL + }, +}; +``` + +Where `REDIS_URL` is the URL used to connect to Redis. The format of the connection string is `redis[s]://[[username][:password]@][host][:port][/db-number]`. + +:::tip + +By default, the Redis connection string should be `redis://localhost:6379` unless you made any changes to the default configurations during the installation. + +::: + +If you omit this configuration, events will not be emitted and subscribers will not work. + +:::info + +You can learn more about Subscribers and events in the [Subscriber documentation](../advanced/backend/subscribers/create-subscriber.md). + +::: + +## JSON Web Token (JWT) Secret + +Medusa uses JWT to handle user authentication. To set the JWT secret: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + jwt_secret: "very secure string", + }, +}; +``` + +Where `jwt_secret` is the secret used to create the tokens. The more secure it is the better. + +:::caution + +In a development environment, if this option is not set the default secret is “supersecret”. However, in production, if this option is not set an error will be thrown and your server will crash. + +::: + +## Cookie Secret + +This configuration is used to sign the session ID cookie. To set the cookie secret: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + cookie_secret: "very secure string", + }, +}; +``` + +Where `cookie_secret` is the secret used to create the tokens. The more secure it is the better. + +:::caution + +In a development environment, if this option is not set the default secret is “supersecret”. However, in production, if this option is not set an error will be thrown and your server will crash. + +::: + +## Admin CORS + +Medusa uses Cross-Origin Resource Sharing (CORS) to only allow specific origins to access the server. To make sure your Admin dashboard can access the Medusa server’s admin endpoints, set this configuration: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + admin_cors: ADMIN_CORS, + }, +}; +``` + +Where `ADMIN_CORS` is the URL of your admin dashboard. By default, it’s `http://localhost:7000,http://localhost:7001`. + +## Storefront CORS + +Medusa uses CORS to only allow specific origins to access the server. To make sure your Storefront dashboard can access the Medusa server, set this configuration: + +```jsx +module.exports = { + projectConfig: { + //...other configurations + store_cors: STORE_CORS, + }, +}; +``` + +Where `STORE_CORS` is the URL of your storefront. By default, it’s `http://localhost:8000`. + +## Plugins + +On your Medusa server, you can use Plugins to add custom features or integrate third-party services. For example, installing a plugin to use Stripe as a payment provider. + +:::info + +You can learn more about plugins in the [Plugins Overview documentation](../advanced/backend/plugins/overview.md). + +::: + +Aside from installing the plugin with NPM, you need to pass the plugin you installed into the `plugins` array defined in `medusa-config.js`. This array is then exported along with other configurations you’ve added: + +```jsx +module.exports = { + projectConfig: { + //previous configurations mentioned... + }, + plugins, +}; +``` + +### Add a Plugin Without Configuration + +To add a plugin that doesn’t need any configurations, you can simply add its name to the `plugins` array: + +```jsx +const plugins = [ + //other plugins... + `medusa-my-plugin`, +]; +``` + +### Add a Plugin With Configuration + +To add a plugin with configurations, you need to add an object to the `plugins` array with the plugin’s name and configurations: + +```jsx +const plugins = [ + //other plugins... + { + resolve: `medusa-my-plugin`, + options: { + apiKey: `test` + } + } +]; +``` + +## What’s Next 🚀 + +- Check out our [Next.js](../starters/nextjs-medusa-starter.md) and [Gatsby](../starters/gatsby-medusa-starter.md) starter storefronts. +- Install the [Medusa admin](../admin/quickstart.md). +- Learn about [deploying the Medusa server on Heroku](../how-to/deploying-on-heroku.md). diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index cda315899a..ec0e634050 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -40,6 +40,11 @@ module.exports = { id: "tutorial/set-up-your-development-environment", label: "Set Up your Development Environment" }, + { + type: "doc", + id: "usage/configurations", + label: "Configure your Server" + }, { type: "category", collapsed: true, From 6b23208d63c6928a0587176bc3a6e40091922151 Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Sun, 19 Jun 2022 12:58:47 +0200 Subject: [PATCH 34/34] fix(medusa): Include adjustments when authorizing payment (#1697) --- integration-tests/api/__tests__/store/cart.js | 63 +++++++++++++++---- integration-tests/api/helpers/cart-seeder.js | 20 +++++- .../src/api/routes/store/carts/update-cart.ts | 6 +- .../__tests__/line-item-adjustment.js | 20 +++--- packages/medusa/src/services/cart.ts | 3 +- .../src/services/line-item-adjustment.ts | 14 ++--- 6 files changed, 92 insertions(+), 34 deletions(-) diff --git a/integration-tests/api/__tests__/store/cart.js b/integration-tests/api/__tests__/store/cart.js index 4edc9a8baa..3503bf5d7a 100644 --- a/integration-tests/api/__tests__/store/cart.js +++ b/integration-tests/api/__tests__/store/cart.js @@ -486,7 +486,8 @@ describe("/store/carts", () => { regions: ["test-region"], } - let discountCart, discount + let discountCart + let discount beforeEach(async () => { try { discount = await simpleDiscountFactory( @@ -718,15 +719,17 @@ describe("/store/carts", () => { ) .catch((err) => console.log(err)) - expect(response.data.cart.items).toEqual([ - expect.objectContaining({ - cart_id: "test-cart-3", - unit_price: 8000, - variant_id: "test-variant-sale-cg", - quantity: 3, - adjustments: [], - }), - ]) + expect(response.data.cart.items).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + cart_id: "test-cart-3", + unit_price: 8000, + variant_id: "test-variant-sale-cg", + quantity: 3, + adjustments: [], + }), + ]) + ) }) it("updates line item of a cart containing a total fixed discount", async () => { @@ -1363,7 +1366,14 @@ describe("/store/carts", () => { .catch((error) => console.log(error)) expect(response.status).toEqual(200) - expect(response.data.cart.items[0].unit_price).toEqual(500) + expect(response.data.cart.items).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + variant_id: "test-variant-sale-cg", + unit_price: 500, + }), + ]) + ) }) it("updates prices when cart region id is updated", async () => { @@ -1479,11 +1489,38 @@ describe("/store/carts", () => { const getRes = await api.post(`/store/carts/test-cart-2/complete-cart`) expect(getRes.status).toEqual(200) + expect(getRes.data.type).toEqual("order") const variantRes = await api.get("/store/variants/test-variant") expect(variantRes.data.variant.inventory_quantity).toEqual(0) }) + it("calculates correct payment totals on cart completion taking into account line item adjustments", async () => { + const api = useApi() + + await api.post("/store/carts/test-cart-3", { + discounts: [{ code: "CREATED" }], + }) + + const createdOrder = await api.post( + `/store/carts/test-cart-3/complete-cart` + ) + + expect(createdOrder.data.type).toEqual("order") + expect(createdOrder.data.data.discount_total).toEqual(10000) + expect(createdOrder.data.data.subtotal).toEqual(16000) + expect(createdOrder.data.data.total).toEqual(6000) + expect(createdOrder.data.data.payments).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + amount: 6000, + }), + ]) + ) + + expect(createdOrder.status).toEqual(200) + }) + it("returns early, if cart is already completed", async () => { const manager = dbConnection.manager const api = useApi() @@ -1739,7 +1776,9 @@ describe("/store/carts", () => { .catch((err) => console.log(err)) // Ensure that the discount is only applied to the standard item - const itemId = cartWithGiftcard.data.cart.items.find(item => !item.is_giftcard).id + const itemId = cartWithGiftcard.data.cart.items.find( + (item) => !item.is_giftcard + ).id expect(cartWithGiftcard.data.cart.items).toEqual( expect.arrayContaining([ expect.objectContaining({ diff --git a/integration-tests/api/helpers/cart-seeder.js b/integration-tests/api/helpers/cart-seeder.js index b3dee44d51..4514956f2c 100644 --- a/integration-tests/api/helpers/cart-seeder.js +++ b/integration-tests/api/helpers/cart-seeder.js @@ -50,6 +50,7 @@ module.exports = async (connection, data = {}) => { const r = manager.create(Region, { id: "test-region", name: "Test Region", + payment_providers: [{ id: "test-pay" }], currency_code: "usd", tax_rate: 0, }) @@ -819,6 +820,23 @@ module.exports = async (connection, data = {}) => { completed_at: null, items: [], }) + + await manager.save(cart3) + + const ps = manager.create(PaymentSession, { + id: "test-cart-session", + cart_id: "test-cart-3", + provider_id: "test-pay", + is_selected: true, + data: {}, + status: "authorized", + }) + + await manager.save(ps) + + cart3.payment_sessions = [ps] + cart3.payment_session = ps + await manager.save(cart3) await manager.insert(ShippingMethod, { @@ -842,7 +860,7 @@ module.exports = async (connection, data = {}) => { await manager.save(li2) const cart4 = manager.create(Cart, { - id: "test-cart-3", + id: "test-cart-4", email: "some-customer@email.com", shipping_address: { id: "test-shipping-address", diff --git a/packages/medusa/src/api/routes/store/carts/update-cart.ts b/packages/medusa/src/api/routes/store/carts/update-cart.ts index 6fc264f1a8..1874c6b398 100644 --- a/packages/medusa/src/api/routes/store/carts/update-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/update-cart.ts @@ -8,10 +8,10 @@ import { } from "class-validator" import { defaultStoreCartFields, defaultStoreCartRelations } from "." import { CartService } from "../../../../services" -import { AddressPayload } from "../../../../types/common" import { CartUpdateProps } from "../../../../types/cart" -import { IsType } from "../../../../utils/validators/is-type" +import { AddressPayload } from "../../../../types/common" import { validator } from "../../../../utils/validator" +import { IsType } from "../../../../utils/validators/is-type" /** * @oas [post] /store/carts/{id} @@ -90,7 +90,7 @@ export default async (req, res) => { // Update the cart const { shipping_address, billing_address, ...rest } = validated - const cartDataToUpdate: CartUpdateProps = { ...rest }; + const cartDataToUpdate: CartUpdateProps = { ...rest } if (typeof shipping_address === "string") { cartDataToUpdate.shipping_address_id = shipping_address } else { diff --git a/packages/medusa/src/services/__tests__/line-item-adjustment.js b/packages/medusa/src/services/__tests__/line-item-adjustment.js index a57dd6b7b1..279643c28d 100644 --- a/packages/medusa/src/services/__tests__/line-item-adjustment.js +++ b/packages/medusa/src/services/__tests__/line-item-adjustment.js @@ -1,8 +1,8 @@ -import LineItemAdjustmentService from "../line-item-adjustment" -import { MockManager, MockRepository, IdMap } from "medusa-test-utils" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import { DiscountServiceMock } from "../__mocks__/discount" +import { MockManager, MockRepository } from "medusa-test-utils" import { In } from "typeorm" +import LineItemAdjustmentService from "../line-item-adjustment" +import { DiscountServiceMock } from "../__mocks__/discount" +import { EventBusServiceMock } from "../__mocks__/event-bus" describe("LineItemAdjustmentService", () => { describe("list", () => { @@ -101,7 +101,7 @@ describe("LineItemAdjustmentService", () => { } const lineItemAdjustmentRepo = MockRepository({ - create: (f) => Promise.resolve(lineItemAdjustment), + create: (f) => lineItemAdjustment, save: (f) => Promise.resolve(lineItemAdjustment), }) @@ -270,11 +270,11 @@ describe("LineItemAdjustmentService", () => { it("calls createAdjustmentForLineItem once when given a line item", () => { const cart = { - id: "cart1", - discounts: ["disc-1"], - items: [{ id: "li-1" }], - }, - lineItem = { id: "li-1" } + id: "cart1", + discounts: ["disc-1"], + items: [{ id: "li-1" }], + } + const lineItem = { id: "li-1" } lineItemAdjustmentService.createAdjustments(cart, lineItem) expect( diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index e05e2b6310..55b9fd9261 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -3,6 +3,7 @@ import { MedusaError, Validator } from "medusa-core-utils" import { DeepPartial, EntityManager, In } from "typeorm" import { TransactionBaseService } from "../interfaces" import { IPriceSelectionStrategy } from "../interfaces/price-selection-strategy" +import { DiscountRuleType } from "../models" import { Address } from "../models/address" import { Cart } from "../models/cart" import { CustomShippingOption } from "../models/custom-shipping-option" @@ -1221,7 +1222,7 @@ class CartService extends TransactionBaseService { const freshCart = await this.retrieve(cart.id, { select: ["total"], - relations: ["payment_sessions"], + relations: ["payment_sessions", "items", "items.adjustments"], }) if (session.status === "authorized") { diff --git a/packages/medusa/src/services/line-item-adjustment.ts b/packages/medusa/src/services/line-item-adjustment.ts index 8ce03c7229..4331a1835b 100644 --- a/packages/medusa/src/services/line-item-adjustment.ts +++ b/packages/medusa/src/services/line-item-adjustment.ts @@ -1,14 +1,14 @@ -import { EntityManager } from "typeorm" -import { BaseService } from "medusa-interfaces" import { MedusaError } from "medusa-core-utils" +import { BaseService } from "medusa-interfaces" +import { EntityManager } from "typeorm" +import { Cart } from "../models/cart" +import { LineItem } from "../models/line-item" +import { LineItemAdjustment } from "../models/line-item-adjustment" +import { ProductVariant } from "../models/product-variant" import { LineItemAdjustmentRepository } from "../repositories/line-item-adjustment" import { FindConfig } from "../types/common" -import { LineItemAdjustment } from "../models/line-item-adjustment" import { FilterableLineItemAdjustmentProps } from "../types/line-item-adjustment" -import { LineItem } from "../models/line-item" -import { Cart } from "../models/cart" import DiscountService from "./discount" -import { ProductVariant } from "../models/product-variant" type LineItemAdjustmentServiceProps = { manager: EntityManager @@ -96,7 +96,7 @@ class LineItemAdjustmentService extends BaseService { const lineItemAdjustmentRepo: LineItemAdjustmentRepository = manager.getCustomRepository(this.lineItemAdjustmentRepo_) - const lineItemAdjustment = await lineItemAdjustmentRepo.create(data) + const lineItemAdjustment = lineItemAdjustmentRepo.create(data) return await lineItemAdjustmentRepo.save(lineItemAdjustment) })