Merge branch 'master' into docs/dark-mode

This commit is contained in:
Shahed Nasser
2022-04-29 13:27:59 +03:00
committed by GitHub
32 changed files with 791 additions and 73 deletions

View File

@@ -46,7 +46,11 @@ Then configure your `medusa-config.js` to include the plugin alongside the requi
The two access keys in the options are the ones created in the previous section.
> Make sure to use an environment variable for the secret key in a live environment.
:::tip
Make sure to use an environment variable for the secret key in a live environment.
:::
### Try it out

View File

@@ -78,7 +78,11 @@ https://[bucket].s3.[region].amazonaws.com
The two access keys in the options are the ones created in the previous section.
> Make sure to use an environment variable for the secret key in a live environment.
:::tip
Make sure to use an environment variable for the secret key in a live environment.
:::
### Try it out

View File

@@ -21,7 +21,11 @@ Common integration use cases that can be implemented with Segment include:
## Adding Segment to your Medusa store
> Note: you should create a [Node.js source in Segment](https://segment.com/docs/connections/sources/catalog/libraries/server/node/quickstart/) in order to obtain the write key that will be provided in the plugin options.
:::note
You should create a [Node.js source in Segment](https://segment.com/docs/connections/sources/catalog/libraries/server/node/quickstart/) in order to obtain the write key that will be provided in the plugin options.
:::
Plugins in Medusa's ecosystem come as separate npm packages, that can be installed from the npm registry.

View File

@@ -47,7 +47,11 @@ Then configure your `medusa-config.js` to include the plugin alongside the requi
In the above options, a `spaces_url` is included. This can be found in your Space overview. The `bucket` should point to the name you gave your Space. The `endpoint` identifies the region in which you created the Space. And finally the two keys are the ones created in the previous section.
> Make sure to use an environment variable for the secret key in a live environment.
:::tip
Make sure to use an environment variable for the secret key in a live environment.
:::
### Try it out!

View File

@@ -37,7 +37,11 @@ Alternatively, using Yarn:
yarn create medusa-app
```
> When choosing `npx` you are shown different store engine options as part of the setup. For this Strapi tutorial, you should choose `medusa-starter-default`. Optionally, pick a storefront.
:::note
When choosing `npx` you are shown different store engine options as part of the setup. For this Strapi tutorial, you should choose `medusa-starter-default`. Optionally, pick a storefront.
:::
**Use `medusa-cli`**
`@medusajs/medusa-cli` is our Command Line Tool for creating the Medusa store engine (alongside many other powerful commands). First, install it:
@@ -116,13 +120,19 @@ Alternatively, using Yarn:
yarn global add create-strapi-app@3.6.8
create-strapi-app strapi-medusa --template https://github.com/Deathwish98/strapi-medusa-template.git
```
:::note
> Note: The plugin expects node version to be '>= 10.16.0 and <=14.x.x', otherwise it will throw an error.
The plugin expects node version to be '>= 10.16.0 and <=14.x.x', otherwise it will throw an error.
:::
After running the command, you have a full Strapi project configured to synchronize with Medusa. Upon the initial start of the Strapi server, all the required models will be created. They will correlate with models from Medusa to allow for two-way synchronization.
> Note: The Strapi template starter uses SQLite as the default database. There is a known bug related to `knex.js` that comes from multiple write connections. Restarting the Strapi server should make the error disappear.
:::caution
The Strapi template starter uses SQLite as the default database. There is a known bug related to `knex.js` that comes from multiple write connections. Restarting the Strapi server should make the error disappear.
:::
**Synchronization**
@@ -134,7 +144,11 @@ When products are created in Medusa, the two-way communication ensures that data
**Variants**: title
**Region**: name
> Further down the road, the support for synchronizing more entities is expected to be introduced
:::note
Further down the road, the support for synchronizing more entities is expected to be introduced
:::
**Using Postgres in Medusa (optional)**
@@ -158,7 +172,11 @@ projectConfig: {
},
```
> Note: the `DATABASE_URL` variable should use the Postgres database created in the previous step
:::tip
The `DATABASE_URL` variable should use the Postgres database created in the previous step
:::
## Summary and next steps

View File

@@ -0,0 +1,128 @@
# Twilio SMS
In this document, youll learn about the Twilio SMS Plugin, what it does, and how to use it in Medusa.
## Overview
[Twilios SMS API](https://www.twilio.com/sms) can be used to send users SMS messages instantly. It has a lot of additional features such as Whatsapp messaging and conversations.
By integrating Twilio SMS into Medusa, youll have easy access to Twilios SMS API to send SMS messages to your users and customers. You can use it to send Order confirmations, verification codes, reset password messages, and more.
:::note
This plugin only gives you access to the Twilio SMS API but does not implement sending messages at any given point. Youll have to add this yourself where you need it. You can look at the [example later in this tutorial](#example-usage-of-the-plugin) to check how you can send an SMS for a new order.
:::
## Prerequisites
Before going further with this guide make sure you have a Medusa server set up. You can follow our [Quickstart guide](../quickstart/quick-start.md) if you dont.
You also must have a [Twilio account created](https://www.twilio.com/sms) so if you dont already please go ahead and create one.
## Retrieve Credentials
For the [Twilio SMS plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-plugin-twilio-sms), you need three credentials from your Twilio account: Account SID, Auth Token, and a Twilio phone number to send from. You can find these 3 from your [Twilio Consoles homepage](https://console.twilio.com).
## Install Plugin
In the directory of your Medusa server, run the following command to install [Twilio SMS plugin](https://github.com/medusajs/medusa/tree/master/packages/medusa-plugin-twilio-sms):
```bash npm2yarn
npm install medusa-plugin-twilio-sms
```
Then, youll need to add your credentials in `.env`:
```bash
TWILIO_SMS_ACCOUNT_SID=<YOUR_ACCOUNT_SID>
TWILIO_SMS_AUTH_TOKEN=<YOUR_AUTH_TOKEN>
TWILIO_SMS_FROM_NUMBER=<YOUR_TWILIO_NUMBER>
```
Make sure to replace `<YOUR_ACCOUNT_SID>`, `<YOUR_AUTH_TOKEN>`, and `<YOUR_TWILIO_NUMBER>` with the credentials you obtained from your Twilio Console.
Finally, add the plugin and its options in the `medusa-config.js` file to the `plugins` array:
```jsx
const plugins = [
...,
{
resolve: `medusa-plugin-twilio-sms`,
options: {
account_sid: process.env.TWILIO_SMS_ACCOUNT_SID,
auth_token: process.env.TWILIO_SMS_AUTH_TOKEN,
from_number: process.env.TWILIO_SMS_FROM_NUMBER
}
}
];
```
## Example Usage of the Plugin
This plugin adds the service `twilioSmsService` to your Medusa server. To send SMS using it, all you have to do is resolve it in your file as explained in the [Services](../advanced/backend/services/create-service.md#using-your-custom-service) documentation.
In this example, youll create a subscriber that listens to the `order.placed` event and sends an SMS to the customer to confirm their order.
:::tip
For this example to work, youll need to install and configure Redis on your server. You can refer to the [development guide](../tutorial/0-set-up-your-development-environment.md#redis) to learn how to do that.
:::
Create the file `src/services/sms.js` in your Medusa server with the following content:
```jsx
class SmsSubscriber {
constructor({ twilioSmsService, orderService, eventBusService }) {
this.twilioSmsService_ = twilioSmsService;
this.orderService = orderService;
eventBusService.subscribe("order.placed", this.sendSMS);
}
sendSMS = async (data) => {
const order = await this.orderService.retrieve(data.id, {
relations: ['shipping_address']
});
if (order.shipping_address.phone) {
this.twilioSmsService_.sendSms({
to: order.shipping_address.phone,
body: 'We have received your order #' + data.id,
})
}
};
}
export default SmsSubscriber;
```
In the `constructor`, you resolve the `twilioSmsService` and `orderService` using dependency injection to use it later in the `sendSMS` method.
You also subscribe to the event `order.placed` and sets the event handler to be `sendSMS`.
In `sendSMS`, you first retrieve the order with its relation to `shipping_address` which contains a `phone` field. If the phone is set, you send an SMS to the customer using the method `sendSms` in the `twilioSmsService`.
This method accepts an object of parameters. These parameters are based on Twilios SMS APIs. You can check their [API documentation](https://www.twilio.com/docs/sms/api/message-resource#create-a-message-resource) for more fields that you can add.
If you create an order now on your storefront, you should receive a message from Twilio on the phone number you entered in the shipping address.
:::tip
If you dont have a storefront set up yet, you can install one of our [Next.js](../starters/nextjs-medusa-starter.md) or [Gatsby](../starters/gatsby-medusa-starter.md) storefronts.
:::
:::caution
If youre on a Twilio trial make sure that the phone number you entered on checkout is a [verified Twilio number on your console](https://console.twilio.com/us1/develop/phone-numbers/manage/verified).
:::
![Twilio Dashboard](https://i.imgur.com/MXtQMiL.png)
## Whats Next 🚀
- Learn more about how [Notifications work in Medusa](../how-to/notification-api).
- Install the [Medusa admin](../admin/quickstart.md) for functionalities like Gift Cards creation, swaps, claims, order return requests, and more.

View File

@@ -1,17 +1,18 @@
---
title: Checkouts
---
# Checkouts
# 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.
> All code snippets in the following guide, use the JS SDK distributed through **npm**. To install it, run:
:::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.
@@ -21,7 +22,12 @@ npm install @medusajs/medusa-js
## Checkout flow
To create an order from a cart, we go through the following flow.
> 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.
:::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.

View File

@@ -0,0 +1,387 @@
# How to Create a Payment Provider
In this document, youll learn how to add a Payment Provider to your Medusa server. If youre unfamiliar with the Payment architecture in Medusa, make sure to check out the [overview](./overview.md) first.
## Overview
A Payment Provider is the payment method used to authorize, capture, and refund payment, among other actions. An example of a Payment Provider is Stripe.
By default, Medusa has a [manual payment provider](https://github.com/medusajs/medusa/tree/2e6622ec5d0ae19d1782e583e099000f0a93b051/packages/medusa-fulfillment-manual) that has minimal implementation. It can be synonymous with a Cash on Delivery payment method. It allows store operators to manage the payment themselves but still keep track of its different stages on Medusa.
Adding a Payment Provider is as simple as creating a [service](../services/create-service.md) file in `src/services`. A Payment Provider is essentially a service that extends `PaymentService` from `medusa-interfaces`.
Payment Provider Services must have a static property `identifier`. It is the name that will be used to install and refer to the Payment Provider in the Medusa server.
:::tip
Payment Providers are loaded and installed at the server startup.
:::
The Payment Provider service is also required to implement the following methods:
1. `createPayment`: Called when a Payment Session for the Payment Provider is to be created.
2. `retrievePayment`: Used to retrieve payment data from the third-party provider, if theres any.
3. `getStatus`: Used to get the status of a Payment or Payment Session.
4. `updatePayment`: Used to update the Payment Session whenever the cart and its related data are updated.
5. `updatePaymentData`: Used to update the `data` field of Payment Sessions. Specifically called when a request is sent to the [Update Payment Session](https://docs.medusajs.com/api/store/cart/update-a-payment-session) endpoint.
6. `deletePayment`: Used to perform any action necessary before a Payment Session is deleted.
7. `authorizePayment`: Used to authorize the payment amount of the cart before the order or swap is created.
8. `getPaymentData`: Used to retrieve the data that should be stored in the `data` field of a new Payment instance after the payment amount has been authorized.
9. `capturePayment`: Used to capture the payment amount of an order or swap.
10. `refundPayment`: Used to refund a payment amount of an order or swap.
11. `cancelPayment`: Used to perform any necessary action with the third-party payment provider when an order or swap is canceled.
:::note
All these methods must be declared async in the Payment Provider Service.
:::
These methods are used at different points in the Checkout flow as well as when processing the order after its placed.
![Payment Flows.jpg](https://i.imgur.com/WeDr0ph.jpg)
## Create a Fulfillment Provider
The first step to create a fulfillment provider is to create a file in `src/services` with the following content:
```jsx
import { PaymentService } from "medusa-interfaces"
class MyPaymentService extends PaymentService {
}
export default MyPaymentService;
```
Where `MyPaymentService` is the name of your Payment Provider service. For example, Stripes Payment Provider Service is called `StripeProviderService`.
Payment Providers must extend `PaymentService` from `medusa-interfaces`.
:::tip
Following the naming convention of Services, the name of the file should be the slug name of the Payment Provider, and the name of the class should be the camel case name of the Payment Provider suffixed with “Service”. In the example above, the name of the file should be `my-payment.js`. You can learn more in the [service documentation](../services/create-service.md).
:::
### Identifier
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 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).
### constructor
You can use the `constructor` of your Payment 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 providers APIs, you can initialize it in the constructor and use it in other methods in the service.
Additionally, if youre creating your Payment 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:
```jsx
constructor({}, options) {
//you can access options here
}
```
### createPayment
This method is called during checkout when [Payment Sessions are initialized](https://docs.medusajs.com/api/store/cart/initialize-payment-sessions) to present payment options to the customer. It is used to allow you to make any necessary calls to the third-party provider to initialize the payment. For example, in Stripe this method is used to initialize a Payment Intent for the customer.
The method receives the cart as an object for its first parameter. It holds all the necessary information you need to know about the cart and the customer that owns this cart.
This method must return an object that is going to be stored in the `data` field of the Payment Session to be created. As mentioned in the [Architecture Overview](./overview.md), the `data` field is useful to hold any data required by the third-party provider to process the payment or retrieve its details at a later point.
An example of a minimal implementation of `createPayment` that does not interact with any third-party providers:
```jsx
async createPayment(cart) {
return {
id: 'test-payment',
status: 'pending'
};
}
```
### retrievePayment
This method is used to provide a uniform way of retrieving the payment information from the third-party provider. For example, in Stripes Payment Provider Service this method is used to retrieve the payment intent details from Stripe.
This method accepts the `data` field of a Payment Session or a Payment. So, you should make sure to store in the `data` field any necessary data that would allow you to retrieve the payment data from the third-party provider.
This method must return an object containing the data from the third-party provider.
An example of a minimal implementation of `retrievePayment` where you dont need to interact with the third-party provider:
```jsx
async retrievePayment(cart) {
return {};
}
```
### getStatus
This method is used to get the status of a Payment or a Payment Session.
Its main usage is in the place order workflow. If the status returned is not `authorized`, then the payment is considered failed, an error will be thrown, and the order will not be placed.
This method accepts the `data` field of the Payment or Payment Session as a parameter. You can use this data to interact with the third-party provider to check the status of the payment if necessary.
This method returns a string that represents the status. The status must be one of the following values:
1. `authorized`: The payment was successfully authorized.
2. `pending`: The payment is still pending. This is the default status of a Payment Session.
3. `requires_more`: The payment requires more actions from the customer. For example, if the customer must complete a 3DS check before the payment is authorized.
4. `error`: If an error occurred with the payment.
5. `canceled`: If the payment was canceled.
An example of a minimal implementation of `getStatus` where you dont need to interact with the third-party provider:
```jsx
async getStatus (data) {
return data.status;
}
```
:::note
This code block assumes the status is stored in the `data` field as demonstrated in the `createPayment` method.
:::
### updatePayment
This method is used to perform any necessary updates on the payment. This method is called whenever the cart or any of its related data is updated. For example, when a [line item is added to the cart](https://docs.medusajs.com/api/store/cart/add-a-line-item) or when a [shipping method is selected](https://docs.medusajs.com/api/store/cart/add-a-shipping-method).
:::tip
A line item refers to a product in the cart.
:::
It accepts the `data` field of the Payment Session as the first parameter and the cart as an object for the second parameter.
You can utilize this method to interact with the third-party provider and update any details regarding the payment if necessary.
This method must return an object that will be stored in the `data` field of the Payment Session.
An example of a minimal implementation of `updatePayment` that does not need to make any updates on the third-party provider or the `data` field of the Payment Session:
```jsx
async updatePayment(sessionData, cart) {
return sessionData;
}
```
### updatePaymentData
This method is used to update the `data` field of a Payment Session. Particularly, it is called when a request is sent to the [Update Payment Session](https://docs.medusajs.com/api/store/cart/update-a-payment-session) endpoint. This endpoint receives a `data` object in the body of the request that should be used to update the existing `data` field of the Payment Session.
This method accepts the current `data` field of the Payment Session as the first parameter, and the new `data` field sent in the body request as the second parameter.
You can utilize this method to interact with the third-party provider and make any necessary updates based on the `data` field passed in the body of the request.
This method must return an object that will be stored in the `data` field of the Payment Session.
An example of a minimal implementation of `updatePaymentData` that returns the `updatedData` passed in the body of the request as-is to update the `data` field of the Payment Session.
```jsx
async updatePaymentData(sessionData, updatedData) {
return updatedData;
}
```
### deletePayment
This method is used to perform any actions necessary before a Payment Session is deleted. The Payment Session is deleted in one of the following cases:
1. When a request is sent to [delete the Payment Session](https://docs.medusajs.com/api/store/cart/delete-a-payment-session).
2. When the [Payment Session is refreshed](https://docs.medusajs.com/api/store/cart/refresh-a-payment-session). The Payment Session is deleted so that a newer one is initialized instead.
3. When the Payment Provider is no longer available. This generally happens when the store operator removes it from the available Payment Provider in the admin.
4. When the region of the store is changed based on the cart information and the Payment Provider is not available in the new region.
It accepts the Payment Session as an object for its first parameter.
You can use this method to interact with the third-party provider to delete data related to the Payment Session if necessary.
An example of a minimal implementation of `deletePayment` where no interaction with a third-party provider is required:
```jsx
async deletePayment(paymentSession) {
return;
}
```
### authorizePayment
This method is used to authorize payment using the Payment Session for an order. This is called when the [cart is completed](https://docs.medusajs.com/api/store/cart/complete-a-cart) and before the order is created.
This method is also used for authorizing payments of a swap of an order.
The payment authorization might require additional action from the customer before it is declared authorized. Once that additional action is performed, the `authorizePayment` method will be called again to validate that the payment is now fully authorized. So, you should make sure to implement it for this case as well, if necessary.
Once the payment is authorized successfully and the Payment Session status is set to `authorized`, the order can then be placed.
If the payment authorization fails, then an error will be thrown and the order will not be created.
:::note
The payment authorization status is determined using the `getStatus` method as mentioned earlier. If the status is `requires_more` then it means additional actions are required from the customer. If the workflow process reaches the “Start Create Order” step and the status is not `authorized`, then the payment is considered failed.
:::
This method accepts the Payment Session as an object for its first parameter, and a `context` object as a second parameter. The `context` object contains the following properties:
1. `ip`: The customers IP.
2. `idempotency_key`: The [Idempotency Key](./overview.md#idempotency-key) that is associated with the current cart. It is useful when retrying payments, retrying checkout at a failed point, or for payments that require additional actions from the customer.
This method must return an object containing the property `status` which is a string that indicates the current status of the payment, and the property `data` which is an object containing any additional information required to perform additional payment processing such as capturing the payment. The values of both of these properties are stored in the Payment Sessions `status` and `data` fields respectively.
You can utilize this method to interact with the third-party provider and perform any actions necessary to authorize the payment.
An example of a minimal implementation of `authorizePayment` that doesnt need to interact with any third-party provider:
```jsx
async authorizePayment(paymentSession, context) {
return {
status: 'authorized',
data: {
id: 'test'
}
};
}
```
### getPaymentData
After the payment is authorized using `authorizePayment`, a Payment instance will be created. The `data` field of the Payment instance will be set to the value returned from the `getPaymentData` method in the Payment Provider.
This method accepts the Payment Session as an object for its first parameter.
This method must return an object to be stored in the `data` field of the Payment instance. You can either use it as-is or make any changes to it if necessary.
An example of a minimal implementation of `getPaymentData`:
```jsx
async getPaymentData(paymentSession) {
return paymentSession.data;
}
```
### capturePayment
This method is used to capture the payment amount of an order. This is typically triggered manually by the store operator from the admin.
This method is also used for capturing payments of a swap of an order.
You can utilize this method to interact with the third-party provider and perform any actions necessary to capture the payment.
This method accepts the Payment as an object for its first parameter.
This method must return an object that will be stored in the `data` field of the Payment.
An example of a minimal implementation of `capturePayment` that doesnt need to interact with a third-party provider:
```jsx
async capturePayment(payment) {
return {
status: 'captured'
};
}
```
### refundPayment
This method is used to refund an orders payment. This is typically triggered manually by the store operator from the admin. The refund amount might be the total order amount or part of it.
This method is also used for refunding payments of a swap of an order.
You can utilize this method to interact with the third-party provider and perform any actions necessary to refund the payment.
This method accepts the Payment as an object for its first parameter, and the amount to refund as a second parameter.
This method must return an object that is stored in the `data` field of the Payment.
An example of a minimal implementation of `refundPayment` that doesnt need to interact with a third-party provider:
```jsx
async refundPayment(payment, amount) {
return {
id: 'test'
}
}
```
### cancelPayment
This method is used to cancel an orders payment. This method is typically triggered by one of the following situations:
1. Before an order is placed and after the payment is authorized, an inventory check is done on products to ensure that products are still available for purchase. If the inventory check fails for any of the products, the payment is canceled.
2. If the store operator cancels the order from the admin.
This method is also used for canceling payments of a swap of an order.
You can utilize this method to interact with the third-party provider and perform any actions necessary to cancel the payment.
This method accepts the Payment as an object for its first parameter.
This method must return an object that is stored in the `data` field of the Payment.
An example of a minimal implementation of `cancelPayment` that doesnt need to interact with a third-party provider:
```jsx
async cancelPayment(payment) {
return {
id: 'test'
}
}
```
## Optional Methods
### retrieveSavedMethods
This method can be added to your Payment Provider service if your third-party provider supports saving the customers payment methods. Please note that in Medusa there is no way to save payment methods.
This method is called when a request is sent to [Retrieve Saved Payment Methods](https://docs.medusajs.com/api/store/customer/retrieve-saved-payment-methods).
This method accepts the customer as an object for its first parameter.
This method returns an array of saved payment methods retrieved from the third-party provider. You have the freedom to shape the items in the array as you see fit since they will be returned as-is for the response to the request.
:::note
If youre using Medusas [Next.js](../../../starters/nextjs-medusa-starter.md) or [Gatsby](../../../starters/gatsby-medusa-starter.md) storefront starters, note that the presentation of this method is not implemented. Youll need to implement the UI and pages for this method based on your implementation and the provider you are using.
:::
An example of the implementation of `retrieveSavedMethods` taken from Stripes Payment Provider:
```jsx
/**
* Fetches a customers saved payment methods if registered in Stripe.
* @param {object} customer - customer to fetch saved cards for
* @returns {Promise<Array<object>>} saved payments methods
*/
async retrieveSavedMethods(customer) {
if (customer.metadata && customer.metadata.stripe_id) {
const methods = await this.stripe_.paymentMethods.list({
customer: customer.metadata.stripe_id,
type: "card",
})
return methods.data
}
return Promise.resolve([])
}
```
## Whats 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).

View File

@@ -126,5 +126,5 @@ This prevents any payment issues from occurring with the customers and allows fo
## Whats Next 🚀
- [Check out how the checkout flow is implemented on the frontend.](../../../guides/checkouts.md)
- [Check out how the checkout flow is implemented on the frontend.](./frontend-payment-flow-in-checkout.md)
- Check out payment plugins like [Stripe](../../../add-plugins/stripe.md), [Paypal](../../../add-plugins/paypal.md), and [Klarna](../../../add-plugins/klarna.md).

View File

@@ -1,6 +1,6 @@
# How to Add a Fulfillment Provider
In this document, youll learn how to add a fulfillment provider to a Medusa server. If youre unfamiliar with the Shipping architecture in Medusa, make sure to check out the overview first.
In this document, youll learn how to add a fulfillment provider to a Medusa server. If youre unfamiliar with the Shipping architecture in Medusa, make sure to [check out the overview first](https://docs.medusajs.com/advanced/backend/shipping/overview/).
## Overview
@@ -59,7 +59,7 @@ class MyFulfillmentService extends FulfillmentService {
export default MyFulfillmentService;
```
## constructor
### constructor
You can use the `constructor` of your fulfillment provider to have access to different services in Medusa through dependency injection.

View File

@@ -69,7 +69,11 @@ export default OrderNotifierSubscriber;
This subscriber will register the method `handleOrder` as one of the handlers of the `order.placed` event. The method `handleOrder` will be executed every time an order is placed, and it will receive the order ID in the `data` parameter. You can then use the orders details to perform any kind of task you need.
> The `data` object will not contain other order data. Only the ID of the order. You can retrieve the order information using the `orderService`.
:::note
The `data` object will not contain other order data. Only the ID of the order. You can retrieve the order information using the `orderService`.
:::
## Using Services in Subscribers

View File

@@ -12,7 +12,11 @@ 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.
> You will notice that plugins vary in naming. The name should signal what functionality they provide.
:::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.
@@ -34,7 +38,11 @@ We've already gone through the process of building custom services, endpoints, a
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:
> Please 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`).
:::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
.
@@ -55,7 +63,11 @@ Please note that you will need some build step before being able to properly loa
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.
:::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:

View File

@@ -6,7 +6,11 @@ title: "Deploying Admin on Netlify"
This is a guide for deploying Medusa Admin on Netlify. Netlify is a platform that offers hosting and backend services for applications and static websites.
> At this point, you should have a running instance of Medusa Admin. If not, check out [these steps](https://github.com/medusajs/admin#-setting-up-admin) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::note
At this point, you should have a running instance of Medusa Admin. If not, check out [these steps](https://github.com/medusajs/admin#-setting-up-admin) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::
### 1. Install the Netlify CLI
@@ -62,7 +66,11 @@ git push origin main
Within a couple of minutes, your Medusa Admin is live and running on Netlify.
> If you experience CORS issues in your new setup, you might need to add your admin url as part of the ADMIN_CORS environment variable in your server setup.
:::tip
If you experience CORS issues in your new setup, you might need to add your admin url as part of the ADMIN_CORS environment variable in your server setup.
:::
### What's next?

View File

@@ -2,7 +2,11 @@
This is a guide for deploying a Medusa project on DigitalOcean App Platform.
> It is assumed, that you are currently running a local instance of Medusa. If not, check out our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::note
It is assumed, that you are currently running a local instance of Medusa. If not, check out our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::
### 1. Configure Medusa
@@ -83,7 +87,11 @@ Navigate to the top-right dropdown **Create** and select **Apps**.
Choose **GitHub** or **GitLab** and select the repository that holds your Medusa project. Check **Autodeploy code changes**, if you want DigitalOcean to deploy on every push to your repository.
> It's important, that DigitalOcean is pointing to the directory holding the Medusa store engine as it is only this which that will be deployed (If you followed the quickstart guide this will simply be the created project, and if you used the npx command this will be the backend folder inside of the newly created project).
:::tip
It's important, that DigitalOcean is pointing to the directory holding the Medusa store engine as it is only this which that will be deployed (If you followed the quickstart guide this will simply be the created project, and if you used the npx command this will be the backend folder inside of the newly created project).
:::
### 5. Configure environment variables
@@ -100,7 +108,11 @@ JWT_SECRET=your-jwt-secret
COOKIE_SECRET=your-cookie-secret
```
> Make sure to use actual secrets in a production environment
:::tip
Make sure to use actual secrets in a production environment
:::
### 6. Set up a Database

View File

@@ -12,7 +12,11 @@ This is a guide for deploying a Medusa project on Heroku. Heroku is at PaaS that
</video>
</div>
> We assume, that you are currently running a local instance of Medusa. If not, check out our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::note
We assume, that you are currently running a local instance of Medusa. If not, check out our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::
### 1. Install the Heroku CLI
@@ -45,7 +49,11 @@ Connect to your Heroku account from your terminal:
heroku login
```
> Follow the instructions on your terminal
:::note
Follow the instructions on your terminal
:::
### 3. Create an app on Heroku
@@ -60,7 +68,11 @@ heroku git:remote -a medusa-test-app
Medusa requires a Postgres database and a Redis instance to work. These are added through the Heroku CLI using the following commands.
> In this below example, we initialize the resources on free plans. This is not a valid configuration for a production environment.
:::tip
In this below example, we initialize the resources on free plans. This is not a valid configuration for a production environment.
:::
#### Postgresql
@@ -76,7 +88,11 @@ You can find more informations, plans and pricing about Heroku Postgres [here](h
Add a Redis instance to your Heroku app
> The addon `redistogo:nano` is free, but Heroku requires you to add a payment method to proceed.
:::note
The addon `redistogo:nano` is free, but Heroku requires you to add a payment method to proceed.
:::
```bash
heroku addons:create redistogo:nano
@@ -94,8 +110,11 @@ heroku config:set JWT_SECRET=your-super-secret
heroku config:set COOKIE_SECRET=your-super-secret-pt2
heroku config:set NPM_CONFIG_PRODUCTION=false
```
:::tip
> Make sure to use actual secrets in a production environment.
Make sure to use actual secrets in a production environment.
:::
Additionally, we need to set the buildpack to Node.js

View File

@@ -2,7 +2,11 @@
This is a guide for deploying a Medusa project to Qovery. Qovery is a Continuous Deployment Platform, that provides you with the developer experience of Heroku on top of your cloud provider (e.g. AWS, DigitalOcean).
> We assume, that you are currently running a local instance of Medusa. If not, check out our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::note
We assume, that you are currently running a local instance of Medusa. If not, check out our [Quickstart](https://docs.medusajs.com/quickstart/quick-start) or use `npx create-medusa-app` to set up your application in a matter of minutes. For the latter, see [this guide](https://docs.medusajs.com/how-to/create-medusa-app) for a small walkthrough.
:::
### 1. Qovery Console
@@ -16,7 +20,11 @@ Create a project and an environment.
Add a new app to your Qovery environment and connect the Git repository that holds your Medusa project. In your application settings, set the port to 9000 unless something else is specified in your setup.
> If you used our `npx` starter, your repository will most likely hold all components; storefront, admin and backend. Ensure that **Root application path** in Qovery is pointing to your Medusa project (`/backend`).
:::note
If you used our `npx` starter, your repository will most likely hold all components; storefront, admin and backend. Ensure that **Root application path** in Qovery is pointing to your Medusa project (`/backend`).
:::
### 4. Add a database
@@ -61,10 +69,14 @@ module.exports = {
};
```
> **IMPORTANT**: We are using the Qovery community plan, that does not allow SSL connections for the database, so this is disabled.
>
> In a production environment, you would need the following in the config:
> `database_extra: { ssl: { rejectUnauthorized: false } }`
:::caution IMPORTANT
We are using the Qovery community plan, that does not allow SSL connections for the database, so this is disabled.
In a production environment, you would need the following in the config:
`database_extra: { ssl: { rejectUnauthorized: false } }`
:::
#### Add some extra variables
@@ -75,7 +87,11 @@ JTW_SECRET=something_secret_jwt
COOKIE_SECRET=something_secret_cookie
```
> Make sure to use actual secrets in a production environment.
:::tip
Make sure to use actual secrets in a production environment.
:::
#### Update `package.json`

View File

@@ -4,7 +4,11 @@ title: Create a headless ecommerce store with Gatsby, Contentful & Medusa
# Creating a headless ecommerce store with Gatsby, Contentful and Medusa
> Medusa is an open source headless commerce engine that allow you to create amazing digital commerce experiences. Medusa is highly customizable, allowing you to extend the core to fit your needs.
:::info About Medusa
Medusa is an open source headless commerce engine that allow you to create amazing digital commerce experiences. Medusa is highly customizable, allowing you to extend the core to fit your needs.
:::
## Introduction
@@ -33,7 +37,11 @@ If you want to jump straight to the code for this series you can checkout:
## Prerequisites
> For a full guide to how to set up your development environment for Medusa please see [the tutorial](https://docs.medusajs.com/tutorials/set-up-your-development-environment)
:::note
For a full guide to how to set up your development environment for Medusa please see [the tutorial](https://docs.medusajs.com/tutorials/set-up-your-development-environment)
:::
In order to get you started with your Gatsby, Contentful, Medusa store you must complete a couple of installations:

View File

@@ -76,11 +76,13 @@ npm run migrate:contentful --file contentful-migrations/update-page-module-valid
To use your new Rich Text module **Content > Page > About**, and click **Add Content > Page**. You will now make use of the new Rich Text module to add some more details about your store. You can write your own text or use the text provided below if you just want to copy/paste.
> ### About Medusa
>
> Medusa is an open-source headless commerce engine for fast-growing businesses. Getting started with Medusa is very easy and you will be able to start selling online with a basic setup in no time, however, the real power of Medusa starts showing up when you add custom functionality and extend your core to fit your needs.
>
> The core Medusa package and all the official Medusa plugins ship as individual NPM packages that you install into a Node project. You store and plugins are configured in your medusa-config.js file making it very easy to manage your store as your business grows. Custom functionality doesn't have to come from plugins, you can also add project-level functionality by simply adding files in your `src/` folder. Medusa will automatically register your custom functionalities in the bootstrap phase.
:::info About Medusa
Medusa is an open-source headless commerce engine for fast-growing businesses. Getting started with Medusa is very easy and you will be able to start selling online with a basic setup in no time, however, the real power of Medusa starts showing up when you add custom functionality and extend your core to fit your needs.
The core Medusa package and all the official Medusa plugins ship as individual NPM packages that you install into a Node project. You store and plugins are configured in your medusa-config.js file making it very easy to manage your store as your business grows. Custom functionality doesn't have to come from plugins, you can also add project-level functionality by simply adding files in your `src/` folder. Medusa will automatically register your custom functionalities in the bootstrap phase.
:::
![](https://i.imgur.com/hqiaoFq.png)
@@ -88,7 +90,11 @@ When you have added your text you can click **Publish changes** (make sure the A
## Updating the storefront to support the Rich Text module
> If you want to jump straight to the final frontend code visit [medusajs/medusa-contentful-storefront@part-2](https://github.com/medusajs/medusa-contentful-storefront/tree/part-2).
:::note
If you want to jump straight to the final frontend code visit [medusajs/medusa-contentful-storefront@part-2](https://github.com/medusajs/medusa-contentful-storefront/tree/part-2).
:::
To display your newly created Rich Text module open up the storefront code and create a new file at `src/components/rich-text/rich-text.jsx`.

View File

@@ -78,8 +78,12 @@ class MyService extends NotificationService {
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")`
:::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.

View File

@@ -4,8 +4,12 @@ title: Setting up a Next.js storefront for your Medusa project
# Setting up a Next.js storefront for your Medusa project
> Medusa is a headless open source commerce platform giving engineers the foundation for building unique and scalable digital commerce projects through our API-first engine.
> Being headless, our starters serve as a good foundation for you to get coupled with a frontend in a matter of minutes.
:::note
Medusa is a headless open source commerce platform giving engineers the foundation for building unique and scalable digital commerce projects through our API-first engine.
Being headless, our starters serve as a good foundation for you to get coupled with a frontend in a matter of minutes.
:::
This article assumes you already have the Medusa project created and ready to be linked to your Next.js starter.

View File

@@ -46,7 +46,11 @@ Then configure your `medusa-config.js` to include the plugin alongside the requi
The two access keys in the options are the ones created in the previous section.
> Make sure to use an environment variable for the secret key in a live environment.
:::tip
Make sure to use an environment variable for the secret key in a live environment.
:::
### Try it out

View File

@@ -78,7 +78,11 @@ https://[bucket].s3.[region].amazonaws.com
The two access keys in the options are the ones created in the previous section.
> Make sure to use an environment variable for the secret key in a live environment.
:::tip
Make sure to use an environment variable for the secret key in a live environment.
:::
### Try it out

View File

@@ -41,7 +41,11 @@ Then configure your `medusa-config.js` to include the plugin alongside the requi
In the above options, a `spaces_url` is included. This can be found in your Space overview. The `bucket` should point to the name you gave your Space. The `endpoint` identifies the region in which you created the Space. And finally the two keys are the ones created in the previous section.
> Make sure to use an environment variable for the secret key in a live environment.
:::tip
Make sure to use an environment variable for the secret key in a live environment.
:::
### Try it out!

View File

@@ -50,7 +50,11 @@ We have created two starters for you that can help you lay a foundation for your
- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa)
- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa)
> Note: Medusa runs on port 9000 by default and the storefront starters are both configured to run on port 8000. If you wish to run your storefront starter on another port you should update your CORS settings in your project's `medusa-config.js`.
:::tip
Medusa runs on port 9000 by default and the storefront starters are both configured to run on port 8000. If you wish to run your storefront starter on another port you should update your CORS settings in your project's `medusa-config.js`.
:::
<!-- ### Link you local development to Medusa Cloud (Coming soon!)

View File

@@ -34,8 +34,12 @@ module.exports = {
}
```
> When changing from SQLite to Postgres, you should seed the database again using:
:::tip
When changing from SQLite to Postgres, you should seed the database again using:
```bash npm2yarn
npm run seed
```
:::

View File

@@ -58,7 +58,11 @@ If you prefer using something like homebrew you can also run:
brew install node
```
> **Mac users**: Make sure that you have Xcode command line tools installed; if not run `xcode-select --install`
:::tip
**Mac users**: Make sure that you have Xcode command line tools installed; if not run `xcode-select --install`
:::
### Git

View File

@@ -51,7 +51,11 @@ For customizations that are more particular to your project you can extend your
## Starting your Medusa server
> Note: For your server to run correctly you should configure your `COOKIE_SECRET` and `JWT_SECRET` environment variables by adding a `.env` file to the root of your Medusa project.
:::note
For your server to run correctly you should configure your `COOKIE_SECRET` and `JWT_SECRET` environment variables by adding a `.env` file to the root of your Medusa project.
:::
After your project has been set up with `medusa new`, you can run the following commands to start your server:

View File

@@ -52,7 +52,11 @@ constructor({ cartService, orderService }) {
In the constructor we specify that our `WelcomeService` will depend upon the `cartService` and `orderService` and Medusa will make sure to provide those as the first argument to the constructor when starting up Medusa. We then keep a reference to these services within the `WelcomeService` so that we can use them later on.
> Note: Just like we can depend on the `cartService` and `orderService` other services will be able to depend on our newly created `WelcomeService`. The registration name of our service is the camelCased version of our file name with the registration type appended. I.e. `/src/services/welcome.js` -> `welcomeService`.
:::note
Just like we can depend on the `cartService` and `orderService` other services will be able to depend on our newly created `WelcomeService`. The registration name of our service is the camelCased version of our file name with the registration type appended. I.e. `/src/services/welcome.js` -> `welcomeService`.
:::
### `registerOptin`
@@ -72,7 +76,12 @@ async registerOptin(cartId, optin) {
The `registerOptin` implementation simply validates that the provided argument is of the correct type and calls the CartService function `update`. `update` takes two arguments: the first is the id of the cart to update and the second is an object that with the key/value pairs that we want to update. In this case we are updating the metadata on the cart. The `metadata` field on the cart is itself an object so we need to pass an object when updating this field.
> Note: Most entities in Medusa have a `metadata` field that can be used for customizations or integrations when it is necessary to persist some data relating to the entity. Metadata cannot be overridden by other plugins.
:::note
Most entities in Medusa have a `metadata` field that can be used for customizations or integrations when it is necessary to persist some data relating to the entity. Metadata cannot be overridden by other
plugins.
:::
### `sendWelcome`
@@ -115,7 +124,11 @@ We then check if the number of previous orders is greater than 1, indicating tha
The final part of the implementation checks if the `welcome_optin` metadata has been set to true. If the customer has opted in we use `someEmailService.send` to trigger and email dispatch to the email stored on the order. In this case `someEmailSender` could be any email service for example Sendgrid, SES, Mailgun, etc.
> Note: If you have `medusa-plugin-sendgrid` installed you can use `sendgridService` in your constructor to use it later in `sendWelcome`. You will then be able to do `sendgridService.send({ ... })`.
:::note
If you have `medusa-plugin-sendgrid` installed you can use `sendgridService` in your constructor to use it later in `sendWelcome`. You will then be able to do `sendgridService.send({ ... })`.
:::
We have completed the implementation of our custom service and we will now be able to call it from elsewhere in our project.

View File

@@ -40,9 +40,17 @@ The `link` command will first check that you have authenticated your CLI which w
You should note that the `--develop` flag is optional for the `link` command. If provided it tells the CLI to start up your server after linking is completed; you may leave it out if you'd rather start your server separately.
> Note: For local linking to work you must make sure to have your CORS settings configured correctly. This is done by adding `https://app.medusajs.com` to your `cors_admin` config in `medusa-config.js`.
:::note
> Note: If you change the port that your local server is running on you will have to run `medusa link` again. `medusa link` uses your `PORT` environment variable to specify where Medusa Cloud should look for your local server.
For local linking to work you must make sure to have your CORS settings configured correctly. This is done by adding `https://app.medusajs.com` to your `cors_admin` config in `medusa-config.js`.
:::
:::note
If you change the port that your local server is running on you will have to run `medusa link` again. `medusa link` uses your `PORT` environment variable to specify where Medusa Cloud should look for your local server.
:::
## Summary

View File

@@ -39,11 +39,14 @@ update the line item.
Deleting line items happens with `DELETE /cart/line-items/[line-id]`. Endpoint
removes the line item with the given line id by calling `removeLineItem`.
> ### Custom add to cart
> It is possible to make custom endpoints to add to cart. For example if you are
> creating a gift card plugin you may want to create a custom endpoint that
> accepts values like `amount` which can be set by the customer. As long as the
> controller compiles a valid `LineItem` it can safely call `addLineItem`
:::note Custom add to cart
It is possible to make custom endpoints to add to cart. For example if you are
creating a gift card plugin you may want to create a custom endpoint that
accepts values like `amount` which can be set by the customer. As long as the
controller compiles a valid `LineItem` it can safely call `addLineItem`
:::
## Checking out