chore(docs): added eslint to lint documentation code blocks (#2920)
* docs: added rule for code length * chore: fixes based on vale errors * changed to use eslint * fixes using eslint * added github action for documentation eslint * changed allowed max-length * fixed incorrect heading level * removed comment
This commit is contained in:
1 parent
99add15fc3
commit
d1b4b11ff6
67 files changed
+2611
-1735
No files matched your search
@@ -97,7 +97,7 @@ Finally, in `medusa-config.js` add the following item into the `plugins` arr
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-algolia`,
|
||||
options: {
|
||||
@@ -123,7 +123,7 @@ const plugins = [
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
The `searchableAttributes` are the attributes in a product that are searchable, and `attributesToRetrieve` are the attributes to retrieve for each product result. You’re free to make changes to these attributes as you see fit, but these are the recommended attributes.
|
||||
@@ -207,7 +207,7 @@ Finally, change the code in `src/lib/search-client.ts` to the following:
|
||||
```jsx title=src/lib/search-client.ts
|
||||
import algoliasearch from "algoliasearch/lite"
|
||||
|
||||
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || "" // You should add this to your environment variables
|
||||
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || ""
|
||||
|
||||
const apiKey = process.env.NEXT_PUBLIC_SEARCH_API_KEY || "test_key"
|
||||
|
||||
@@ -227,9 +227,7 @@ To make sure the Next.js storefront properly displays the products in the search
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Add to Gatsby and React-Based Storefronts
|
||||
### Add to Gatsby and React-Based Storefronts
|
||||
|
||||
This section covers adding the search UI to React-based storefronts. It uses the Gatsby storefront as an example, but you can use the same steps on any React-based framework.
|
||||
|
||||
@@ -269,11 +267,11 @@ import {
|
||||
Hits,
|
||||
InstantSearch,
|
||||
SearchBox,
|
||||
connectStateResults
|
||||
connectStateResults,
|
||||
} from "react-instantsearch-dom"
|
||||
|
||||
import React from "react"
|
||||
import algoliasearch from 'algoliasearch/lite';
|
||||
import algoliasearch from "algoliasearch/lite"
|
||||
|
||||
const searchClient = algoliasearch(
|
||||
process.env.GATSBY_ALGOLIA_APP_ID,
|
||||
@@ -281,19 +279,28 @@ const searchClient = algoliasearch(
|
||||
)
|
||||
|
||||
const Search = () => {
|
||||
const Results = connectStateResults(({ searchState, searchResults, children }) =>
|
||||
searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? (
|
||||
<div className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
|
||||
{children}
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
)
|
||||
);
|
||||
const Results = connectStateResults(
|
||||
({ searchState, searchResults, children }) => {
|
||||
return (
|
||||
searchState && searchState.query &&
|
||||
searchResults && searchResults.nbHits !== 0 ?
|
||||
(
|
||||
<div
|
||||
className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
|
||||
{children}
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<InstantSearch indexName={process.env.GATSBY_SEARCH_INDEX_NAME} searchClient={searchClient}>
|
||||
<InstantSearch
|
||||
indexName={process.env.GATSBY_SEARCH_INDEX_NAME}
|
||||
searchClient={searchClient}>
|
||||
<SearchBox submit={null} reset={null} />
|
||||
<Results>
|
||||
<Hits hitComponent={Hit} />
|
||||
@@ -313,7 +320,7 @@ const Hit = ({ hit }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default Search;
|
||||
export default Search
|
||||
```
|
||||
|
||||
This file uses the dependencies you installed to show the search results. It also initializes Algolia using the environment variables you added.
|
||||
@@ -333,10 +340,12 @@ import Search from "./search"
|
||||
And add the `Search` component in the returned JSX before `RegionPopover`:
|
||||
|
||||
```jsx title=src/components/header/index.jsx
|
||||
//...
|
||||
<Search />
|
||||
<RegionPopover regions={mockData.regions} />
|
||||
//...
|
||||
// ...
|
||||
<div className="...">
|
||||
<Search />
|
||||
<RegionPopover regions={mockData.regions} />
|
||||
</div>
|
||||
// ...
|
||||
```
|
||||
|
||||
If you run your Gatsby storefront while the Medusa server is running, you should find a search bar in the header of the page. Try entering a query to search through the products in your store.
|
||||
|
||||
@@ -29,32 +29,32 @@ Here’s an example of a migration created in a new file `contentful-migrations/
|
||||
```jsx title=contentful-migrations/rich-text.js
|
||||
#! /usr/bin/env node
|
||||
|
||||
require("dotenv").config();
|
||||
require("dotenv").config()
|
||||
|
||||
const { runMigration } = require("contentful-migration");
|
||||
const { runMigration } = require("contentful-migration")
|
||||
|
||||
const options = {
|
||||
spaceId: process.env.CONTENTFUL_SPACE_ID,
|
||||
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
|
||||
environment: process.env.CONTENTFUL_ENVIRONMENT,
|
||||
yes: true,
|
||||
};
|
||||
}
|
||||
|
||||
const migration = async () => {
|
||||
await runMigration({
|
||||
...options,
|
||||
migrationFunction: function (migration, context) {
|
||||
|
||||
//create Rich Text content model
|
||||
// create Rich Text content model
|
||||
const richText = migration
|
||||
.createContentType("richText")
|
||||
.name("Rich Text")
|
||||
.displayField("title");
|
||||
.displayField("title")
|
||||
|
||||
richText.createField("title").name("Title (Internal)").type("Symbol");
|
||||
richText.createField("body").name("Body").type("RichText");
|
||||
richText.createField("title").name("Title (Internal)").type("Symbol")
|
||||
richText.createField("body").name("Body").type("RichText")
|
||||
|
||||
//edit Page content model
|
||||
// edit Page content model
|
||||
const page = migration.editContentType("page")
|
||||
|
||||
page.editField("contentModules").items({
|
||||
@@ -67,7 +67,7 @@ const migration = async () => {
|
||||
],
|
||||
})
|
||||
|
||||
//edit Product content model
|
||||
// edit Product content model
|
||||
const product = migration.editContentType("product")
|
||||
|
||||
product
|
||||
@@ -83,11 +83,11 @@ const migration = async () => {
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
migration();
|
||||
migration()
|
||||
```
|
||||
|
||||
This example creates a new content model Rich Text that has two fields: title and body. It also edits the Page content model to allow using Rich Text content models on the page.
|
||||
@@ -97,7 +97,19 @@ In addition, it edits the Product content model by adding a new field `contentMo
|
||||
You can also add other types of content models the `contentModules` should accept. For example, to accept `tileSection` add it to the `linkContentType` option:
|
||||
|
||||
```jsx
|
||||
linkContentType: ["tileSection", "richText"],
|
||||
product
|
||||
.createField("contentModules")
|
||||
.name("Content Modules")
|
||||
.type("Array")
|
||||
.items({
|
||||
type: "Link",
|
||||
linkType: "Entry",
|
||||
validations: [
|
||||
{
|
||||
linkContentType: ["richText", "tileSection"],
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### Run a Contentful Migration
|
||||
@@ -165,10 +177,10 @@ import { renderRichText } from "gatsby-source-contentful/rich-text"
|
||||
const RichText = ({ data }) => {
|
||||
return (
|
||||
<div style={{
|
||||
maxWidth: '870px',
|
||||
margin: '0 auto',
|
||||
paddingTop: '20px',
|
||||
paddingBottom: '20px'
|
||||
maxWidth: "870px",
|
||||
margin: "0 auto",
|
||||
paddingTop: "20px",
|
||||
paddingBottom: "20px",
|
||||
}}>
|
||||
{data.body ? renderRichText(data.body) : ""}
|
||||
</div>
|
||||
@@ -194,7 +206,7 @@ Then, in the returned JSX add a new case to the switch statement:
|
||||
|
||||
```jsx title=src/pages/{ContentfulPage.slug}.js
|
||||
switch (cm.internal.type) {
|
||||
//...
|
||||
// ...
|
||||
case "ContentfulRichText":
|
||||
return <RichText key={cm.id} data={cm} />
|
||||
default:
|
||||
|
||||
@@ -123,14 +123,14 @@ Then, in `medusa-config.js` in the exported object, comment out or remove the SQ
|
||||
```jsx title=medusa-config.js
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...
|
||||
// ...
|
||||
database_url: DATABASE_URL,
|
||||
database_type: "postgres",
|
||||
//REMOVE OR COMMENT OUT THE BELOW:
|
||||
// REMOVE OR COMMENT OUT THE BELOW:
|
||||
// database_database: "./medusa-db.sql",
|
||||
// database_type: "sqlite",
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Migrate Content Types to Contentful
|
||||
|
||||
@@ -55,22 +55,22 @@ Finally, in `medusa-config.js`, add the Klarna plugin to the `plugins` array wit
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//other plugins...
|
||||
// other plugins...
|
||||
{
|
||||
resolve: `medusa-payment-klarnal`,
|
||||
options: {
|
||||
backend_url: process.env.KLARNA_BACKEND_URL
|
||||
backend_url: process.env.KLARNA_BACKEND_URL,
|
||||
url: process.env.KLARNA_URL,
|
||||
user: process.env.KLARNA_USER,
|
||||
password: process.env.KLARNA_PASSWORD,
|
||||
merchant_urls: {
|
||||
terms: process.env.KLARNA_TERMS_URL,
|
||||
checkout: process.env.KLARNA_CHECKOUT_URL,
|
||||
confirmation: process.env.KLARNA_CONFIRMATION_URL
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
confirmation: process.env.KLARNA_CONFIRMATION_URL,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -59,15 +59,15 @@ Open `medusa-config.js` and add the new plugin into the `plugins` array:
|
||||
|
||||
```js title=medusa-config.js
|
||||
const plugins = [
|
||||
...,
|
||||
// ...,
|
||||
{
|
||||
resolve: `medusa-plugin-mailchimp`,
|
||||
options: {
|
||||
api_key: process.env.MAILCHIMP_API_KEY,
|
||||
newsletter_list_id: process.env.MAILCHIMP_NEWSLETTER_LIST_ID
|
||||
}
|
||||
}
|
||||
];
|
||||
newsletter_list_id: process.env.MAILCHIMP_NEWSLETTER_LIST_ID,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
@@ -147,35 +147,37 @@ npm install axios
|
||||
Then, in the component you want to add the subscription form add the following code:
|
||||
|
||||
```jsx
|
||||
import axios from 'axios'
|
||||
import { useState } from "react";
|
||||
import axios from "axios"
|
||||
import { useState } from "react"
|
||||
|
||||
export default function NewsletterForm() {
|
||||
const [email, setEmail] = useState("")
|
||||
|
||||
function subscribe(e) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
if (!email) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
axios.post('http://localhost:9000/mailchimp/subscribe', {
|
||||
email
|
||||
axios.post("http://localhost:9000/mailchimp/subscribe", {
|
||||
email,
|
||||
})
|
||||
.then((e) => {
|
||||
alert("Subscribed sucessfully!")
|
||||
setEmail("")
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
alert("An error occurred");
|
||||
console.error(e)
|
||||
alert("An error occurred")
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={subscribe}>
|
||||
<h2>Sign Up for our newsletter</h2>
|
||||
<input type="email" name="email" id="email" placeholder="example@gmail.com"
|
||||
<input
|
||||
type="email" name="email" id="email"
|
||||
placeholder="example@gmail.com"
|
||||
value={email} onChange={(e) => setEmail(e.target.value)} />
|
||||
<button type="submit">Subscribe</button>
|
||||
</form>
|
||||
|
||||
@@ -57,11 +57,12 @@ Finally, in `medusa-config.js` add the following item into the `plugins` array:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-meilisearch`,
|
||||
options: {
|
||||
// config object passed when creating an instance of the MeiliSearch client
|
||||
// config object passed when creating an instance
|
||||
// of the MeiliSearch client
|
||||
config: {
|
||||
host: process.env.MEILISEARCH_HOST,
|
||||
apiKey: process.env.MEILISEARCH_API_KEY,
|
||||
@@ -71,12 +72,18 @@ const plugins = [
|
||||
products: {
|
||||
// MeiliSearch's setting options to be set on a particular index
|
||||
searchableAttributes: ["title", "description", "variant_sku"],
|
||||
displayedAttributes: ["title", "description", "variant_sku", "thumbnail", "handle"],
|
||||
displayedAttributes: [
|
||||
"title",
|
||||
"description",
|
||||
"variant_sku",
|
||||
"thumbnail",
|
||||
"handle",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
You can change the `searchableAttributes` and `displayedAttributes` as you see fit. However, the attributes included are the recommended attributes.
|
||||
@@ -220,7 +227,7 @@ import {
|
||||
Hits,
|
||||
InstantSearch,
|
||||
SearchBox,
|
||||
connectStateResults
|
||||
connectStateResults,
|
||||
} from "react-instantsearch-dom"
|
||||
|
||||
import React from "react"
|
||||
@@ -232,19 +239,28 @@ const searchClient = instantMeiliSearch(
|
||||
)
|
||||
|
||||
const Search = () => {
|
||||
const Results = connectStateResults(({ searchState, searchResults, children }) =>
|
||||
searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? (
|
||||
<div className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
|
||||
{children}
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
)
|
||||
);
|
||||
const Results = connectStateResults(
|
||||
({ searchState, searchResults, children }) => {
|
||||
return (
|
||||
searchState && searchState.query &&
|
||||
searchResults && searchResults.nbHits !== 0 ?
|
||||
(
|
||||
<div
|
||||
className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
|
||||
{children}
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<InstantSearch indexName={process.env.GATSBY_SEARCH_INDEX_NAME} searchClient={searchClient}>
|
||||
<InstantSearch
|
||||
indexName={process.env.GATSBY_SEARCH_INDEX_NAME}
|
||||
searchClient={searchClient}>
|
||||
<SearchBox submit={null} reset={null} />
|
||||
<Results>
|
||||
<Hits hitComponent={Hit} />
|
||||
@@ -264,7 +280,7 @@ const Hit = ({ hit }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default Search;
|
||||
export default Search
|
||||
```
|
||||
|
||||
This file uses the dependencies you installed to show the search results. It also initializes MeiliSearch using the environment variables you added.
|
||||
@@ -284,10 +300,12 @@ import Search from "./search"
|
||||
And add the `Search` component in the returned JSX before `RegionPopover`:
|
||||
|
||||
```jsx title=src/components/header/index.jsx
|
||||
//...
|
||||
<Search />
|
||||
<RegionPopover regions={mockData.regions} />
|
||||
//...
|
||||
// ...
|
||||
<div className="...">
|
||||
<Search />
|
||||
<RegionPopover regions={mockData.regions} />
|
||||
</div>
|
||||
// ...
|
||||
```
|
||||
|
||||
If you run your Gatsby storefront while the Medusa server and the MeiliSearch instance are running, you should find a search bar in the header of the page. Try entering a query to search through the products in your store.
|
||||
|
||||
@@ -104,7 +104,9 @@ Where `<ENDPOINT>` is the URL of your MinIO server, `<BUCKET>` is the name of th
|
||||
Finally, configure your `medusa-config.js` to include the plugin with the required options:
|
||||
|
||||
```js title=medusa-config.js
|
||||
{
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-file-minio`,
|
||||
options: {
|
||||
endpoint: process.env.MINIO_ENDPOINT,
|
||||
@@ -112,7 +114,8 @@ Finally, configure your `medusa-config.js` to include the plugin with the requ
|
||||
access_key_id: process.env.MINIO_ACCESS_KEY,
|
||||
secret_access_key: process.env.MINIO_SECRET_KEY,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
:::caution
|
||||
@@ -156,13 +159,16 @@ MINIO_PRIVATE_BUCKET=exports
|
||||
Then, add a new option to the plugin’s options in `medusa-config.js`:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
{
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-file-minio`,
|
||||
options: {
|
||||
//...
|
||||
private_bucket: process.env.MINIO_PRIVATE_BUCKET
|
||||
// ...
|
||||
private_bucket: process.env.MINIO_PRIVATE_BUCKET,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### Use Different Secret and Access Keys
|
||||
@@ -181,14 +187,17 @@ Where `<YOUR_PRIVATE_ACCESS_KEY>` and `<YOUR_PRIVATE_SECRET_KEY>` are the access
|
||||
Then, add two new options to the plugin’s options in `medusa-config.js`:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
{
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-file-minio`,
|
||||
options: {
|
||||
//...
|
||||
// ...
|
||||
private_access_key_id: process.env.MINIO_PRIVATE_ACCESS_KEY,
|
||||
private_secret_access_key: process.env.MINIO_PRIVATE_SECRET_KEY
|
||||
private_secret_access_key: process.env.MINIO_PRIVATE_SECRET_KEY,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
@@ -204,13 +213,13 @@ In `next.config.js` add the following option in the exported object:
|
||||
```jsx title=next.config.js
|
||||
const { withStoreConfig } = require("./store-config")
|
||||
|
||||
//...
|
||||
// ...
|
||||
|
||||
module.exports = withStoreConfig({
|
||||
//...
|
||||
// ...
|
||||
images: {
|
||||
domains: [
|
||||
//...
|
||||
// ...
|
||||
"127.0.0.1",
|
||||
],
|
||||
},
|
||||
|
||||
@@ -57,17 +57,17 @@ Then, in `medusa-config.js`, add the PayPal plugin to the `plugins` array with t
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//other plugins...
|
||||
// other plugins...
|
||||
{
|
||||
resolve: `medusa-payment-paypal`,
|
||||
options: {
|
||||
sandbox: process.env.PAYPAL_SANDBOX,
|
||||
client_id: process.env.PAYPAL_CLIENT_ID,
|
||||
client_secret: process.env.PAYPAL_CLIENT_SECRET,
|
||||
auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID
|
||||
}
|
||||
}
|
||||
];
|
||||
auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
That’s all you need to install PayPal on your Medusa server!
|
||||
@@ -158,12 +158,15 @@ npm install @paypal/react-paypal-js
|
||||
Next, create a new file `src/components/payment/paypal-payment/index.jsx` with the following content:
|
||||
|
||||
```jsx title=src/components/payment/paypal-payment/index.jsx
|
||||
import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import {
|
||||
PayPalButtons,
|
||||
PayPalScriptProvider,
|
||||
} from "@paypal/react-paypal-js"
|
||||
import React, { useMemo, useState } from "react"
|
||||
|
||||
import { navigate } from "gatsby"
|
||||
import { useCart } from "../../../hooks/use-cart"
|
||||
import { useMedusa } from "../../../hooks/use-medusa";
|
||||
import { useMedusa } from "../../../hooks/use-medusa"
|
||||
|
||||
const paypalClientId = process.env.GATSBY_PAYPAL_CLIENT_ID || ""
|
||||
|
||||
@@ -179,7 +182,7 @@ const PaypalPayment = () => {
|
||||
|
||||
const paypalSession = useMemo(() => {
|
||||
if (cart.payment_sessions) {
|
||||
return cart.payment_sessions.find(s => s.provider_id === "paypal")
|
||||
return cart.payment_sessions.find((s) => s.provider_id === "paypal")
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -200,10 +203,10 @@ const PaypalPayment = () => {
|
||||
await client.carts.updatePaymentSession(cart.id, "paypal", {
|
||||
data: {
|
||||
data: {
|
||||
...authorizationOrder
|
||||
}
|
||||
}
|
||||
});
|
||||
...authorizationOrder,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const order = await completeCart(cart.id)
|
||||
|
||||
@@ -218,10 +221,12 @@ const PaypalPayment = () => {
|
||||
|
||||
const handlePayment = (data, actions) => {
|
||||
actions.order.authorize().then((authorization) => {
|
||||
if (authorization.status !== 'COMPLETED') {
|
||||
setErrorMessage(`An error occurred, status: ${authorization.status}`);
|
||||
setProcessing(false);
|
||||
return;
|
||||
if (authorization.status !== "COMPLETED") {
|
||||
setErrorMessage(
|
||||
`An error occurred, status: ${authorization.status}`
|
||||
)
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
completeOrder(authorization)
|
||||
@@ -232,7 +237,7 @@ const PaypalPayment = () => {
|
||||
<PayPalScriptProvider options={{
|
||||
"client-id": paypalClientId,
|
||||
"currency": cart.region.currency_code.toUpperCase(),
|
||||
"intent": "authorize"
|
||||
"intent": "authorize",
|
||||
}}>
|
||||
{errorMessage && (
|
||||
<span className="text-rose-500 mt-4">{errorMessage}</span>
|
||||
@@ -246,7 +251,7 @@ const PaypalPayment = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default PaypalPayment;
|
||||
export default PaypalPayment
|
||||
```
|
||||
|
||||
Here’s briefly what this code snippet does:
|
||||
@@ -264,9 +269,11 @@ In `src/components/payment/index.js` you’ll find in the return statement a swi
|
||||
```jsx title=src/components/payment/index.js
|
||||
switch (ps.provider_id) {
|
||||
case "stripe":
|
||||
//...
|
||||
// ...
|
||||
break
|
||||
case "manual":
|
||||
//...
|
||||
// ...
|
||||
break
|
||||
case "paypal":
|
||||
return <PaypalPayment />
|
||||
default:
|
||||
@@ -303,28 +310,33 @@ Then, add the Client ID as an environment variable based on the framework you’
|
||||
Next, create the file that will hold the PayPal component with the following content:
|
||||
|
||||
```jsx
|
||||
import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
|
||||
import {
|
||||
PayPalButtons,
|
||||
PayPalScriptProvider,
|
||||
} from "@paypal/react-paypal-js"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
function Paypal() {
|
||||
const client = new Medusa();
|
||||
const client = new Medusa()
|
||||
const [errorMessage, setErrorMessage] = useState(undefined)
|
||||
const [processing, setProcessing] = useState(false)
|
||||
const cart //TODO retrieve the cart here
|
||||
const cart = "..." // TODO retrieve the cart here
|
||||
|
||||
const handlePayment = (data, actions) => {
|
||||
actions.order.authorize().then(async (authorization) => {
|
||||
if (authorization.status !== 'COMPLETED') {
|
||||
setErrorMessage(`An error occurred, status: ${authorization.status}`);
|
||||
setProcessing(false);
|
||||
return;
|
||||
if (authorization.status !== "COMPLETED") {
|
||||
setErrorMessage(
|
||||
`An error occurred, status: ${authorization.status}`
|
||||
)
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
const response = await client.carts.setPaymentSession(cart.id, {
|
||||
"provider_id": "paypal"
|
||||
});
|
||||
"provider_id": "paypal",
|
||||
})
|
||||
|
||||
if (!response.cart) {
|
||||
setProcessing(false)
|
||||
@@ -334,30 +346,30 @@ function Paypal() {
|
||||
await client.carts.updatePaymentSession(cart.id, "paypal", {
|
||||
data: {
|
||||
data: {
|
||||
...authorization
|
||||
}
|
||||
}
|
||||
});
|
||||
...authorization,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const {data} = await client.carts.complete(cart.id)
|
||||
const { data } = await client.carts.complete(cart.id)
|
||||
|
||||
if (!data || data.object !== "order") {
|
||||
setProcessing(false)
|
||||
return
|
||||
}
|
||||
|
||||
//order successful
|
||||
// order successful
|
||||
alert("success")
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{marginTop: "10px", marginLeft: "10px"}}>
|
||||
<div style={{ marginTop: "10px", marginLeft: "10px" }}>
|
||||
{cart !== undefined && (
|
||||
<PayPalScriptProvider options={{
|
||||
"client-id": <CLIENT_ID>,
|
||||
"client-id": "<CLIENT_ID>",
|
||||
"currency": "EUR",
|
||||
"intent": "authorize"
|
||||
"intent": "authorize",
|
||||
}}>
|
||||
{errorMessage && (
|
||||
<span className="text-rose-500 mt-4">{errorMessage}</span>
|
||||
@@ -370,10 +382,10 @@ function Paypal() {
|
||||
</PayPalScriptProvider>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
export default Paypal;
|
||||
export default Paypal
|
||||
```
|
||||
|
||||
Here’s briefly what this code snippet does:
|
||||
|
||||
@@ -118,7 +118,7 @@ Finally, in `medusa-config.js`, add to the `plugins` array the following new ite
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-file-s3`,
|
||||
options: {
|
||||
@@ -129,7 +129,7 @@ const plugins = [
|
||||
secret_access_key: process.env.S3_SECRET_ACCESS_KEY,
|
||||
},
|
||||
},
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
### Add AWS Configurations
|
||||
@@ -140,7 +140,7 @@ For example, you can pass the `region`, `access_key_id` and `secret_access_key`
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-file-s3`,
|
||||
options: {
|
||||
@@ -150,10 +150,10 @@ const plugins = [
|
||||
region: process.env.S3_REGION,
|
||||
access_key_id: process.env.S3_ACCESS_KEY_ID,
|
||||
secret_access_key: process.env.S3_SECRET_ACCESS_KEY,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
Make sure to define `S3_REGION`, `S3_ACCESS_KEY_ID`, and `S3_SECRET_ACCESS_KEY` in your environment variables first.
|
||||
@@ -198,14 +198,14 @@ In `next.config.js` add the following option in the exported object:
|
||||
```jsx title=next.config.js
|
||||
const { withStoreConfig } = require("./store-config")
|
||||
|
||||
//...
|
||||
// ...
|
||||
|
||||
module.exports = withStoreConfig({
|
||||
//...
|
||||
// ...
|
||||
images: {
|
||||
domains: [
|
||||
//...
|
||||
"<BUCKET_NAME>.s3.amazonaws.com"
|
||||
// ...
|
||||
"<BUCKET_NAME>.s3.amazonaws.com",
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -110,14 +110,14 @@ Finally, in `medusa-config.js`, add the following new item to the `plugins` arra
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-segment`,
|
||||
options: {
|
||||
write_key: process.env.SEGMENT_WRITE_KEY,
|
||||
}
|
||||
}
|
||||
];
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
@@ -155,24 +155,24 @@ For example, you can add the following subscriber to listen to the `customer.cre
|
||||
```jsx title=src/subscribers/customer.ts
|
||||
class CustomerSubscriber {
|
||||
constructor({ segmentService, eventBusService }) {
|
||||
this.segmentService = segmentService;
|
||||
this.segmentService = segmentService
|
||||
|
||||
eventBusService.subscribe("customer.created", this.handleCustomer);
|
||||
eventBusService.subscribe("customer.created", this.handleCustomer)
|
||||
}
|
||||
|
||||
handleCustomer = async (data) => {
|
||||
const customerData = data;
|
||||
delete customerData['password_hash'];
|
||||
const customerData = data
|
||||
delete customerData["password_hash"]
|
||||
|
||||
this.segmentService.track({
|
||||
event: 'Customer Created',
|
||||
event: "Customer Created",
|
||||
userId: data.id,
|
||||
properties: customerData
|
||||
properties: customerData,
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default CustomerSubscriber;
|
||||
export default CustomerSubscriber
|
||||
```
|
||||
|
||||
You resolve the `SegmentService` using dependency injection. Then, when the `customer.created` event is triggered, you use the `track` method available in the `SegmentService` to send tracking data to Segment.
|
||||
|
||||
@@ -3928,7 +3928,7 @@ Finally, in your `medusa-config.js` file, add the SendGrid plugin into the array
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
...,
|
||||
// ...,
|
||||
{
|
||||
resolve: `medusa-plugin-sendgrid`,
|
||||
options: {
|
||||
@@ -3937,12 +3937,13 @@ const plugins = [
|
||||
order_placed_template: process.env.SENDGRID_ORDER_PLACED_ID,
|
||||
localization: {
|
||||
"de-DE": { // locale key
|
||||
order_placed_template: process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
order_placed_template:
|
||||
process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
The `api_key` and `from` options are required. Then, use the key of each template you create (from the [reference](#template-reference)) as the option name with the template ID as the value.
|
||||
|
||||
@@ -83,16 +83,16 @@ After that, open `medusa-config.js` and add the new plugin with its configuratio
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
...,
|
||||
// ...,
|
||||
{
|
||||
resolve: `medusa-plugin-slack-notification`,
|
||||
options: {
|
||||
show_discount_code: false,
|
||||
slack_url: `<WEBHOOK_URL>`,
|
||||
admin_orders_url: `http://localhost:7001/a/orders`
|
||||
}
|
||||
}
|
||||
];
|
||||
admin_orders_url: `http://localhost:7001/a/orders`,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
- Make sure to change `<WEBHOOK_URL>` with the Webhook URL you copied after creating the Slack app.
|
||||
|
||||
@@ -105,7 +105,7 @@ Finally, in `medusa-config.js` add a new item to the `plugins` array:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-file-spaces`,
|
||||
options: {
|
||||
@@ -116,7 +116,7 @@ const plugins = [
|
||||
secret_access_key: process.env.SPACE_SECRET_ACCESS_KEY,
|
||||
},
|
||||
},
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
:::caution
|
||||
@@ -158,14 +158,14 @@ In `next.config.js` add the following option in the exported object:
|
||||
```jsx title=next.config.js
|
||||
const { withStoreConfig } = require("./store-config")
|
||||
|
||||
//...
|
||||
// ...
|
||||
|
||||
module.exports = withStoreConfig({
|
||||
//...
|
||||
// ...
|
||||
images: {
|
||||
domains: [
|
||||
//...
|
||||
"<YOUR_SPACE_DOMAIN>"
|
||||
// ...
|
||||
"<YOUR_SPACE_DOMAIN>",
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -94,10 +94,10 @@ Once the command is done executing, change to the newly created `medusa-server`
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
redis_url: REDIS_URL,
|
||||
//...
|
||||
}
|
||||
//...
|
||||
};
|
||||
// ...
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This uses the default Redis configurations. If you want to learn more about configuring Redis, [check out this documentation](../usage/configurations.md#redis).
|
||||
@@ -140,18 +140,18 @@ Finally, open `medusa-config.js` and add the following new item to the `plugins`
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-strapi`,
|
||||
options: {
|
||||
strapi_medusa_user: process.env.STRAPI_USER,
|
||||
strapi_medusa_password: process.env.STRAPI_PASSWORD,
|
||||
strapi_url: process.env.STRAPI_URL, //optional
|
||||
strapi_port: process.env.STRAPI_PORT, //optional
|
||||
strapi_protocol: process.env.STRAPI_PROTOCOL //optional
|
||||
}
|
||||
}
|
||||
];
|
||||
strapi_url: process.env.STRAPI_URL, // optional
|
||||
strapi_port: process.env.STRAPI_PORT, // optional
|
||||
strapi_protocol: process.env.STRAPI_PROTOCOL, // optional
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -48,7 +48,7 @@ In `medusa-config.js` add the following at the end of the `plugins` array:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
...,
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-payment-stripe`,
|
||||
options: {
|
||||
@@ -56,7 +56,7 @@ const plugins = [
|
||||
webhook_secret: process.env.STRIPE_WEBHOOK_SECRET,
|
||||
},
|
||||
},
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
:::note
|
||||
@@ -75,7 +75,7 @@ You’ll first retrieve the API key. You can find it by choosing API Keys from t
|
||||
|
||||
Next, you need to add the key to your environment variables. In your Medusa server, create `.env` if it doesn’t already exist and add the Stripe key:
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
STRIPE_API_KEY=sk_...
|
||||
```
|
||||
|
||||
@@ -95,7 +95,7 @@ Then, you can add a description. You must select at least one event to listen to
|
||||
|
||||
After the Webhook is created, you’ll see "Signing secret" in the Webhook details. Click on "Reveal" to reveal the secret key. Copy that key and in your Medusa server add the Webhook secret environment variable:
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
STRIPE_WEBHOOK_SECRET=whsec_...
|
||||
```
|
||||
|
||||
@@ -195,30 +195,30 @@ In this section, you’ll initialize Stripe without Medusa’s checkout workflow
|
||||
Create a container component that will hold the payment card component:
|
||||
|
||||
```jsx
|
||||
import { useState } from 'react';
|
||||
import { useState } from "react"
|
||||
|
||||
import {Elements} from '@stripe/react-stripe-js';
|
||||
import Form from './Form';
|
||||
import {loadStripe} from '@stripe/stripe-js';
|
||||
import { Elements } from "@stripe/react-stripe-js"
|
||||
import Form from "./Form"
|
||||
import { loadStripe } from "@stripe/stripe-js"
|
||||
|
||||
const stripePromise = loadStripe('pk_...');
|
||||
const stripePromise = loadStripe("pk_...")
|
||||
|
||||
export default function Container() {
|
||||
const [clientSecret, setClientSecret] = useState()
|
||||
|
||||
//TODO set clientSecret
|
||||
// TODO set clientSecret
|
||||
|
||||
return (
|
||||
<div>
|
||||
{clientSecret && (
|
||||
<Elements stripe={stripePromise} options={{
|
||||
clientSecret
|
||||
clientSecret,
|
||||
}}>
|
||||
<Form clientSecret={clientSecret} cartId={cartId} />
|
||||
</Elements>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
@@ -237,15 +237,19 @@ Once the clientSecret is set, the `Elements` Stripe component will wrap a `Form`
|
||||
Create a new file for the `Form` component with the following content:
|
||||
|
||||
```jsx
|
||||
import {CardElement, useElements, useStripe} from '@stripe/react-stripe-js';
|
||||
import {
|
||||
CardElement,
|
||||
useElements,
|
||||
useStripe,
|
||||
} from "@stripe/react-stripe-js"
|
||||
|
||||
export default function Form({clientSecret, cartId}) {
|
||||
const stripe = useStripe();
|
||||
const elements = useElements();
|
||||
export default function Form({ clientSecret, cartId }) {
|
||||
const stripe = useStripe()
|
||||
const elements = useElements()
|
||||
|
||||
async function handlePayment(e) {
|
||||
e.preventDefault()
|
||||
//TODO handle payment
|
||||
// TODO handle payment
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -253,7 +257,7 @@ export default function Form({clientSecret, cartId}) {
|
||||
<CardElement />
|
||||
<button onClick={handlePayment}>Submit</button>
|
||||
</form>
|
||||
);
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
@@ -267,8 +271,8 @@ You’ll now implement the workflow explained earlier. You’ll use Medusa’s J
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
export default function Container() {
|
||||
const client = new Medusa();
|
||||
...
|
||||
const client = new Medusa()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -282,19 +286,21 @@ Then, in the place of the `//TODO` inside the `Container` element, initialize th
|
||||
|
||||
```jsx
|
||||
client.carts.createPaymentSessions(cart.id)
|
||||
.then(({cart}) => {
|
||||
//check if stripe is selected
|
||||
const isStripeAvailable = cart.payment_sessions?.some((session) => session.provider_id === 'stripe');
|
||||
.then(({ cart }) => {
|
||||
// check if stripe is selected
|
||||
const isStripeAvailable = cart.payment_sessions?.some((session) => (
|
||||
session.provider_id === "stripe"
|
||||
))
|
||||
if (!isStripeAvailable) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
//select stripe payment session
|
||||
// select stripe payment session
|
||||
client.carts.setPaymentSession(cart.id, {
|
||||
provider_id: 'stripe'
|
||||
}).then(({cart}) => {
|
||||
setClientSecret(cart.payment_session.data.client_secret);
|
||||
});
|
||||
provider_id: "stripe",
|
||||
}).then(({ cart }) => {
|
||||
setClientSecret(cart.payment_session.data.client_secret)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
@@ -314,8 +320,8 @@ As you’ll use Medusa’s client again make sure to import it and initialize it
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
export default function Form() {
|
||||
const client = new Medusa();
|
||||
...
|
||||
const client = new Medusa()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -335,12 +341,12 @@ return stripe.confirmCardPayment(clientSecret, {
|
||||
line1,
|
||||
line2,
|
||||
postal_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}).then(({ error, paymentIntent }) => {
|
||||
//TODO handle errors
|
||||
client.carts.complete(cartId).then(resp => console.log(resp))
|
||||
// TODO handle errors
|
||||
client.carts.complete(cartId).then((resp) => console.log(resp))
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -52,16 +52,16 @@ Finally, add the plugin and its options in the `medusa-config.js` file to the `p
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
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
|
||||
}
|
||||
}
|
||||
];
|
||||
from_number: process.env.TWILIO_SMS_FROM_NUMBER,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
@@ -83,27 +83,27 @@ Create the file `src/services/sms.js` in your Medusa server with the following c
|
||||
```jsx title=src/services/sms.js
|
||||
class SmsSubscriber {
|
||||
constructor({ twilioSmsService, orderService, eventBusService }) {
|
||||
this.twilioSmsService_ = twilioSmsService;
|
||||
this.orderService = orderService;
|
||||
this.twilioSmsService_ = twilioSmsService
|
||||
this.orderService = orderService
|
||||
|
||||
eventBusService.subscribe("order.placed", this.sendSMS);
|
||||
eventBusService.subscribe("order.placed", this.sendSMS)
|
||||
}
|
||||
|
||||
sendSMS = async (data) => {
|
||||
const order = await this.orderService.retrieve(data.id, {
|
||||
relations: ['shipping_address']
|
||||
});
|
||||
relations: ["shipping_address"],
|
||||
})
|
||||
|
||||
if (order.shipping_address.phone) {
|
||||
this.twilioSmsService_.sendSms({
|
||||
to: order.shipping_address.phone,
|
||||
body: 'We have received your order #' + data.id,
|
||||
body: "We have received your order #" + data.id,
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default SmsSubscriber;
|
||||
export default SmsSubscriber
|
||||
```
|
||||
|
||||
In the `constructor`, you resolve the `twilioSmsService` and `orderService` using dependency injection to use it later in the `sendSMS` method.
|
||||
|
||||
@@ -68,31 +68,31 @@ You can do that by sending the following request to the [Upload Files](https://d
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
medusa.admin.uploads.create(file) //file is an instance of File
|
||||
medusa.admin.uploads.create(file) // file is an instance of File
|
||||
.then(({ uploads }) => {
|
||||
const key = uploads[0].key;
|
||||
});
|
||||
const key = uploads[0].key
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
const formData = new FormData();
|
||||
formData.append('files', file); //file is an instance of File
|
||||
const formData = new FormData()
|
||||
formData.append("files", file) // file is an instance of File
|
||||
|
||||
fetch(`<YOUR_SERVER>/admin/uploads`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
body: formData
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ uploads }) => {
|
||||
const key = uploads[0].key;
|
||||
});
|
||||
const key = uploads[0].key
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -123,16 +123,16 @@ You can do that by sending the following request to the [Create a Batch Job](htt
|
||||
|
||||
```jsx
|
||||
medusa.admin.batchJobs.create({
|
||||
type: 'price-list-import',
|
||||
type: "price-list-import",
|
||||
context: {
|
||||
fileKey: key, //obtained from previous step
|
||||
price_list_id
|
||||
fileKey: key, // obtained from previous step
|
||||
price_list_id,
|
||||
},
|
||||
dry_run: true
|
||||
dry_run: true,
|
||||
})
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -140,24 +140,24 @@ medusa.admin.batchJobs.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'price-list-import',
|
||||
type: "price-list-import",
|
||||
context: {
|
||||
fileKey: key, //obtained from previous step
|
||||
price_list_id
|
||||
fileKey: key, // obtained from previous step
|
||||
price_list_id,
|
||||
},
|
||||
dry_run: true
|
||||
})
|
||||
dry_run: true,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -212,8 +212,8 @@ You can retrieve all the details of the batch job, including its status and the
|
||||
```jsx
|
||||
medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -221,12 +221,12 @@ medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -257,7 +257,7 @@ Here’s an example of the `result` property:
|
||||
"message": "5 prices will be added"
|
||||
}
|
||||
],
|
||||
"advancement_count": 0 //number of prices processed so far. Will be 0 before the import is confirmed.
|
||||
"advancement_count": 0 //number of prices processed so far.
|
||||
},
|
||||
```
|
||||
|
||||
@@ -275,8 +275,8 @@ To confirm a batch job send the following request:
|
||||
```jsx
|
||||
medusa.admin.batchJobs.confirm(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -284,13 +284,13 @@ medusa.admin.batchJobs.confirm(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -62,31 +62,31 @@ You can do that by sending the following request to the [Upload Files](https://d
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
medusa.admin.uploads.create(file) //file is an instance of File
|
||||
medusa.admin.uploads.create(file) // file is an instance of File
|
||||
.then(({ uploads }) => {
|
||||
const key = uploads[0].key;
|
||||
});
|
||||
const key = uploads[0].key
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
const formData = new FormData();
|
||||
formData.append('files', file); //file is an instance of File
|
||||
const formData = new FormData()
|
||||
formData.append("files", file) // file is an instance of File
|
||||
|
||||
fetch(`<YOUR_SERVER>/admin/uploads`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
body: formData
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ uploads }) => {
|
||||
const key = uploads[0].key;
|
||||
});
|
||||
const key = uploads[0].key
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -117,15 +117,15 @@ You can do that by sending the following request to the [Create a Batch Job](htt
|
||||
|
||||
```jsx
|
||||
medusa.admin.batchJobs.create({
|
||||
type: 'product-import',
|
||||
type: "product-import",
|
||||
context: {
|
||||
fileKey: key //obtained from previous step
|
||||
fileKey: key, // obtained from previous step
|
||||
},
|
||||
dry_run: true
|
||||
dry_run: true,
|
||||
})
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -133,23 +133,23 @@ medusa.admin.batchJobs.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'product-import',
|
||||
type: "product-import",
|
||||
context: {
|
||||
fileKey: key //obtained from previous step
|
||||
fileKey: key, // obtained from previous step
|
||||
},
|
||||
dry_run: true
|
||||
})
|
||||
dry_run: true,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -200,8 +200,8 @@ You can retrieve all the details of the batch job, including its status and the
|
||||
```jsx
|
||||
medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -209,12 +209,12 @@ medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -242,10 +242,10 @@ Here’s an example of the `result` property:
|
||||
{
|
||||
"key": "product-import-count",
|
||||
"name": "Products/variants to import",
|
||||
"message": "There will be 2 products created (0 updated).\n 3 variants will be created and 0 updated"
|
||||
"message": "There will be 2 products created..."
|
||||
}
|
||||
],
|
||||
"advancement_count": 0 //number of products processed so far. Will be 0 before the import is confirmed.
|
||||
"advancement_count": 0 //number of products processed so far.
|
||||
},
|
||||
```
|
||||
|
||||
@@ -263,8 +263,8 @@ To confirm a batch job send the following request:
|
||||
```jsx
|
||||
medusa.admin.batchJobs.confirm(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -272,13 +272,13 @@ medusa.admin.batchJobs.confirm(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -49,8 +49,8 @@ You can show a list of customers by sending a request to the [List Customers](/a
|
||||
```ts
|
||||
medusa.admin.customers.list()
|
||||
.then(({ customers, limit, offset, count }) => {
|
||||
console.log(customers.length);
|
||||
});
|
||||
console.log(customers.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -58,12 +58,12 @@ medusa.admin.customers.list()
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/admin/customers`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customers, limit, offset, count }) => {
|
||||
console.log(customers.length);
|
||||
});
|
||||
console.log(customers.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -108,11 +108,11 @@ medusa.admin.customers.create({
|
||||
email,
|
||||
password,
|
||||
first_name,
|
||||
last_name
|
||||
last_name,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -120,19 +120,19 @@ medusa.admin.customers.create({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/admin/customers`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password,
|
||||
first_name,
|
||||
last_name
|
||||
})
|
||||
last_name,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -177,11 +177,11 @@ You can edit a customer’s information by sending a request to the [Update a Cu
|
||||
|
||||
```ts
|
||||
medusa.admin.customers.update(customerId, {
|
||||
first_name
|
||||
first_name,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -189,16 +189,16 @@ medusa.admin.customers.update(customerId, {
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/admin/customers/${customerId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
first_name
|
||||
})
|
||||
first_name,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -60,21 +60,21 @@ You can create a discount by sending a request to the [Create Discount](/api/adm
|
||||
|
||||
```jsx
|
||||
import { AllocationType, DiscountRuleType } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
medusa.admin.discounts.create({
|
||||
code,
|
||||
rule: {
|
||||
type: DiscountRuleType.FIXED,
|
||||
value: 10,
|
||||
allocation: AllocationType.ITEM
|
||||
allocation: AllocationType.ITEM,
|
||||
},
|
||||
regions: [
|
||||
regionId
|
||||
]
|
||||
regionId,
|
||||
],
|
||||
})
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -82,27 +82,27 @@ medusa.admin.discounts.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
code,
|
||||
rule: {
|
||||
type: 'fixed',
|
||||
type: "fixed",
|
||||
value: 10,
|
||||
allocation: 'item'
|
||||
allocation: "item",
|
||||
},
|
||||
regions: [
|
||||
regionId
|
||||
]
|
||||
})
|
||||
regionId,
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -153,11 +153,11 @@ For example, you can update the discount’s description and status by sending t
|
||||
```jsx
|
||||
medusa.admin.discounts.update(discountId, {
|
||||
description: "New description",
|
||||
is_disabled: true
|
||||
is_disabled: true,
|
||||
})
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -165,20 +165,20 @@ medusa.admin.discounts.update(discountId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts/${discountId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
description: "New description",
|
||||
is_disabled: true
|
||||
})
|
||||
is_disabled: true,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -222,16 +222,16 @@ You can send a request to the [Create Condition](/api/admin/#tag/Discount-Condit
|
||||
|
||||
```jsx
|
||||
import { DiscountConditionOperator } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
medusa.admin.discounts.createCondition(discount_id, {
|
||||
operator: DiscountConditionOperator.IN,
|
||||
products: [
|
||||
productId
|
||||
]
|
||||
productId,
|
||||
],
|
||||
})
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -239,22 +239,22 @@ medusa.admin.discounts.createCondition(discount_id, {
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts/${discountId}/conditions`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
operator: 'in',
|
||||
operator: "in",
|
||||
products: [
|
||||
productId
|
||||
]
|
||||
})
|
||||
productId,
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -301,24 +301,28 @@ You can retrieve a condition and its resources by sending a request to the [Get
|
||||
|
||||
```jsx
|
||||
medusa.admin.discounts.getCondition(discountId, conditionId, {
|
||||
expand: 'products'
|
||||
expand: "products",
|
||||
})
|
||||
.then(({ discount_condition }) => {
|
||||
console.log(discount_condition.id, discount_condition.products);
|
||||
});
|
||||
console.log(discount_condition.id, discount_condition.products)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts/${discountId}/conditions/${conditionId}&expand=products`, {
|
||||
credentials: 'include'
|
||||
})
|
||||
fetch(
|
||||
`<YOUR_SERVER>/admin/discounts/${discountId}` +
|
||||
`/conditions/${conditionId}&expand=products`,
|
||||
{
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ discount_condition }) => {
|
||||
console.log(discount_condition.id, discount_condition.products);
|
||||
});
|
||||
console.log(discount_condition.id, discount_condition.products)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -351,35 +355,38 @@ For example, to update the products in a condition:
|
||||
medusa.admin.discounts.updateCondition(discountId, conditionId, {
|
||||
products: [
|
||||
productId1,
|
||||
productId2
|
||||
]
|
||||
productId2,
|
||||
],
|
||||
})
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts/${discountId}/conditions/${conditionId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
products: [
|
||||
productId1,
|
||||
productId2
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<YOUR_SERVER>/admin/discounts/${discountId}/conditions/${conditionId}`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
products: [
|
||||
productId1,
|
||||
productId2,
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -416,22 +423,25 @@ You can delete a condition by sending a request to the [Delete Condition](/api/a
|
||||
```jsx
|
||||
medusa.admin.discounts.deleteCondition(discountId, conditionId)
|
||||
.then(({ discount }) => {
|
||||
console.log(discount);
|
||||
});
|
||||
console.log(discount)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts/${discountId}/conditions/${conditionId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
})
|
||||
fetch(
|
||||
`<YOUR_SERVER>/admin/discounts/${discountId}/conditions/${conditionId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ discount }) => {
|
||||
console.log(discount.id);
|
||||
});
|
||||
console.log(discount.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -461,8 +471,8 @@ You can delete a discount by sending a request to the [Delete Discount](/api/adm
|
||||
```jsx
|
||||
medusa.admin.discounts.delete(discount_id)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -470,13 +480,13 @@ medusa.admin.discounts.delete(discount_id)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/discounts/${discountId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -57,9 +57,9 @@ You can retrieve regions available on your server using the [List Regions](/api/
|
||||
```tsx
|
||||
medusa.admin.regions.list()
|
||||
.then(({ regions, limit, offset, count }) => {
|
||||
console.log(regions.length);
|
||||
//display regions
|
||||
});
|
||||
console.log(regions.length)
|
||||
// display regions
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -67,13 +67,13 @@ medusa.admin.regions.list()
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/admin/regions`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ regions, limit, offset, count }) => {
|
||||
console.log(regions.length);
|
||||
//display regions
|
||||
});
|
||||
console.log(regions.length)
|
||||
// display regions
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -102,22 +102,22 @@ You can create a region by sending a request to the [Create a Region](/api/admin
|
||||
|
||||
```tsx
|
||||
medusa.admin.regions.create({
|
||||
name: 'Europe',
|
||||
currency_code: 'eur',
|
||||
name: "Europe",
|
||||
currency_code: "eur",
|
||||
tax_rate: 0,
|
||||
payment_providers: [
|
||||
'manual'
|
||||
"manual",
|
||||
],
|
||||
fulfillment_providers: [
|
||||
'manual'
|
||||
"manual",
|
||||
],
|
||||
countries: [
|
||||
'DK'
|
||||
]
|
||||
"DK",
|
||||
],
|
||||
})
|
||||
.then(({ region }) => {
|
||||
console.log(region.id);
|
||||
});
|
||||
console.log(region.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -125,27 +125,27 @@ medusa.admin.regions.create({
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/admin/regions`, {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
name: 'Europe',
|
||||
currency_code: 'eur',
|
||||
name: "Europe",
|
||||
currency_code: "eur",
|
||||
tax_rate: 0,
|
||||
payment_providers: [
|
||||
'manual'
|
||||
"manual",
|
||||
],
|
||||
fulfillment_providers: [
|
||||
'manual'
|
||||
"manual",
|
||||
],
|
||||
countries: [
|
||||
'DK'
|
||||
]
|
||||
})
|
||||
"DK",
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ region }) => {
|
||||
console.log(region.id);
|
||||
});
|
||||
console.log(region.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -202,12 +202,12 @@ Alternatively, you can update the details of a region using the [Update a Region
|
||||
medusa.admin.regions.update(regionId, {
|
||||
countries: [
|
||||
"DK",
|
||||
"DE"
|
||||
]
|
||||
"DE",
|
||||
],
|
||||
})
|
||||
.then(({ region }) => {
|
||||
console.log(region.id);
|
||||
});
|
||||
console.log(region.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -215,25 +215,25 @@ medusa.admin.regions.update(regionId, {
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/admin/regions/${regionId}`, {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
countries: [
|
||||
'DK',
|
||||
'DE'
|
||||
]
|
||||
})
|
||||
"DK",
|
||||
"DE",
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ region }) => {
|
||||
console.log(region.id);
|
||||
});
|
||||
console.log(region.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```tsx
|
||||
```bash
|
||||
curl -L -X POST '<SERVER_URL>/admin/regions/<REGION_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
@@ -271,17 +271,17 @@ You can add a shipping option to a region by sending a request to the [Create Sh
|
||||
|
||||
```tsx
|
||||
medusa.admin.shippingOptions.create({
|
||||
name: 'PostFake',
|
||||
name: "PostFake",
|
||||
region_id: regionId,
|
||||
provider_id: "manual",
|
||||
data: {
|
||||
},
|
||||
price_type: 'flat_rate',
|
||||
amount: 1000
|
||||
price_type: "flat_rate",
|
||||
amount: 1000,
|
||||
})
|
||||
.then(({ shipping_option }) => {
|
||||
console.log(shipping_option.id);
|
||||
});
|
||||
console.log(shipping_option.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -289,28 +289,28 @@ medusa.admin.shippingOptions.create({
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/admin/shipping-options`, {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
name: 'PostFake',
|
||||
name: "PostFake",
|
||||
region_id: regionId,
|
||||
provider_id: "manual",
|
||||
price_type: 'flat_rate',
|
||||
price_type: "flat_rate",
|
||||
data: {
|
||||
},
|
||||
amount: 1000
|
||||
})
|
||||
amount: 1000,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ shipping_option }) => {
|
||||
console.log(shipping_option.id);
|
||||
});
|
||||
console.log(shipping_option.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```tsx
|
||||
```bash
|
||||
curl -L -X POST '<SERVER_URL>/admin/shipping-options' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
@@ -360,8 +360,8 @@ You can delete a region by sending a request to the [Delete a Region](/api/admin
|
||||
```tsx
|
||||
medusa.admin.regions.delete(regionId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -369,19 +369,19 @@ medusa.admin.regions.delete(regionId)
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/admin/regions/${regionId}`, {
|
||||
credentials: 'include',
|
||||
method: 'DELETE'
|
||||
credentials: "include",
|
||||
method: "DELETE",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```tsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/regions/<REGION_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
@@ -87,11 +87,11 @@ To do that, send a request to the [Create an OrderEdit](/api/admin/#tag/OrderEdi
|
||||
|
||||
```ts
|
||||
medusa.admin.orderEdits.create({
|
||||
order_id, //required
|
||||
order_id, // required
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.id);
|
||||
});
|
||||
console.log(order_edit.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -99,19 +99,19 @@ medusa.admin.orderEdits.create({
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
order_id
|
||||
})
|
||||
order_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.id);
|
||||
});
|
||||
console.log(order_edit.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -161,11 +161,11 @@ To add a new item to the original order, send a request to the [Add Line Item](/
|
||||
```ts
|
||||
medusa.admin.orderEdits.addLineItem(orderEditId, {
|
||||
quantity: 1,
|
||||
variant_id
|
||||
variant_id,
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -173,20 +173,20 @@ medusa.admin.orderEdits.addLineItem(orderEditId, {
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits/${orderEditId}/items`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 1,
|
||||
variant_id
|
||||
})
|
||||
variant_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -225,8 +225,8 @@ medusa.admin.orderEdits.updateLineItem(orderEditId, itemId, {
|
||||
quantity: 2,
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -234,19 +234,19 @@ medusa.admin.orderEdits.updateLineItem(orderEditId, itemId, {
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits/${orderEditId}/items/${itemId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 2
|
||||
})
|
||||
quantity: 2,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -280,8 +280,8 @@ You can remove an item from the original order by sending a request to the [Remo
|
||||
```ts
|
||||
medusa.admin.orderEdits.removeLineItem(orderEditId, itemId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -289,13 +289,13 @@ medusa.admin.orderEdits.removeLineItem(orderEditId, itemId)
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits/${orderEditId}/items/${itemId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -327,22 +327,25 @@ To revert an item change, send a request to the [Delete Item Change](/api/admin/
|
||||
```ts
|
||||
medusa.admin.orderEdits.deleteItemChange(orderEditId, changeId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits/${orderEditId}/changes/${changeId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
})
|
||||
fetch(
|
||||
`<YOUR_SERVER>/admin/order-edits/${orderEditId}/changes/${changeId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id, object, deleted);
|
||||
});
|
||||
console.log(id, object, deleted)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -378,7 +381,7 @@ To move an Order Edit into the request state, send a request to the [Request Con
|
||||
```ts
|
||||
medusa.admin.orderEdits.requestConfirmation(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.requested_at, order_edit.requested_by);
|
||||
console.log(order_edit.requested_at, order_edit.requested_by)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -387,12 +390,12 @@ medusa.admin.orderEdits.requestConfirmation(orderEditId)
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits/${orderEditId}/request`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.requested_at, order_edit.requested_by);
|
||||
console.log(order_edit.requested_at, order_edit.requested_by)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -445,7 +448,7 @@ To confirm an Order Edit, send a request to the [Confirm Order Edit](/api/admin/
|
||||
```ts
|
||||
medusa.admin.orderEdits.confirm(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at, order_edit.confirmed_by);
|
||||
console.log(order_edit.confirmed_at, order_edit.confirmed_by)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -454,12 +457,12 @@ medusa.admin.orderEdits.confirm(orderEditId)
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/order-edits/${orderEditId}/confirm`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at, order_edit.confirmed_by);
|
||||
console.log(order_edit.confirmed_at, order_edit.confirmed_by)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -507,7 +510,7 @@ If the payment is authorized by the customer, it can be captured by sending a re
|
||||
```ts
|
||||
medusa.admin.payments.capturePayment(paymentId)
|
||||
.then(({ payment }) => {
|
||||
console.log(payment.captured_at);
|
||||
console.log(payment.captured_at)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -516,12 +519,12 @@ medusa.admin.payments.capturePayment(paymentId)
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/payments/${paymentId}/capture`, {
|
||||
method: 'POST',
|
||||
credentials: 'include'
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ payment }) => {
|
||||
console.log(payment.captured_at);
|
||||
console.log(payment.captured_at)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -551,10 +554,10 @@ To refund the difference to the customer, send a request to the [Refund Payment]
|
||||
|
||||
```ts
|
||||
medusa.admin.payments.refundPayment(paymentId, {
|
||||
amount
|
||||
amount,
|
||||
})
|
||||
.then(({ refund }) => {
|
||||
console.log(refund.id);
|
||||
console.log(refund.id)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -563,18 +566,18 @@ medusa.admin.payments.refundPayment(paymentId, {
|
||||
|
||||
```ts
|
||||
fetch(`<YOUR_SERVER>/admin/payments/${paymentId}/refund`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
amount
|
||||
})
|
||||
amount,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ refund }) => {
|
||||
console.log(refund.id);
|
||||
console.log(refund.id)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -44,11 +44,11 @@ You can create a customer group by sending a request to the Create Customer Grou
|
||||
|
||||
```jsx
|
||||
medusa.admin.customerGroups.create({
|
||||
name: 'VIP'
|
||||
name: "VIP",
|
||||
})
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id);
|
||||
});
|
||||
console.log(customer_group.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -56,19 +56,19 @@ medusa.admin.customerGroups.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: 'VIP'
|
||||
})
|
||||
name: "VIP",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -100,8 +100,8 @@ You can get a list of all customer groups by sending a request to the List Custo
|
||||
```jsx
|
||||
medusa.admin.customerGroups.list()
|
||||
.then(({ customer_groups, limit, offset, count }) => {
|
||||
console.log(customer_groups.length);
|
||||
});
|
||||
console.log(customer_groups.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -109,12 +109,12 @@ medusa.admin.customerGroups.list()
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer_groups, limit, offset, count }) => {
|
||||
console.log(customer_groups.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -144,8 +144,8 @@ You can retrieve a single customer group by sending a request to the Get a Custo
|
||||
```jsx
|
||||
medusa.admin.customerGroups.retrieve(customerGroupId)
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id);
|
||||
});
|
||||
console.log(customer_group.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -153,12 +153,12 @@ medusa.admin.customerGroups.retrieve(customerGroupId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups/${customerGroupId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -186,12 +186,12 @@ You can update a customer group’s data by sending a request to the Update Cust
|
||||
```jsx
|
||||
medusa.admin.customerGroups.update(customerGroupId, {
|
||||
metadata: {
|
||||
is_seller: true
|
||||
}
|
||||
is_seller: true,
|
||||
},
|
||||
})
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id);
|
||||
});
|
||||
console.log(customer_group.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -199,21 +199,21 @@ medusa.admin.customerGroups.update(customerGroupId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups/${customerGroupId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
metadata: {
|
||||
is_seller: true
|
||||
}
|
||||
})
|
||||
is_seller: true,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -247,8 +247,8 @@ You can delete a customer group by sending a request to the Delete a Customer Gr
|
||||
```jsx
|
||||
medusa.admin.customerGroups.delete(customerGroupId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -256,13 +256,13 @@ medusa.admin.customerGroups.delete(customerGroupId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups/${customerGroupId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -293,37 +293,40 @@ You can add a customer to a group by sending a request to the Customer Group’s
|
||||
medusa.admin.customerGroups.addCustomers(customerGroupId, {
|
||||
customer_ids: [
|
||||
{
|
||||
id: customerId
|
||||
}
|
||||
]
|
||||
id: customerId,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id);
|
||||
});
|
||||
console.log(customer_group.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups/${customerGroupId}/customers/batch`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_ids: [
|
||||
{
|
||||
id: customerId
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/customer-groups/${customerGroupId}/customers/batch`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_ids: [
|
||||
{
|
||||
id: customerId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -357,8 +360,8 @@ You can retrieve a list of all customers in a customer group using the List Cust
|
||||
```jsx
|
||||
medusa.admin.customerGroups.listCustomers(customerGroupId)
|
||||
.then(({ customers, count, offset, limit }) => {
|
||||
console.log(customers.length);
|
||||
});
|
||||
console.log(customers.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -366,12 +369,12 @@ medusa.admin.customerGroups.listCustomers(customerGroupId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups/${customerGroupId}/customers`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customers, count, offset, limit }) => {
|
||||
console.log(customers.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -404,37 +407,40 @@ You can remove customers from a customer group by sending a request to the Remov
|
||||
medusa.admin.customerGroups.removeCustomers(customer_group_id, {
|
||||
customer_ids: [
|
||||
{
|
||||
id: customer_id
|
||||
}
|
||||
]
|
||||
id: customer_id,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id);
|
||||
});
|
||||
console.log(customer_group.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/customer-groups/${customerGroupId}/customers/batch`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_ids: [
|
||||
{
|
||||
id: customerId
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/customer-groups/${customerGroupId}/customers/batch`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_ids: [
|
||||
{
|
||||
id: customerId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ customer_group }) => {
|
||||
console.log(customer_group.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -49,17 +49,20 @@ Batch job strategies must extend the abstract class `AbstractBatchJobStrategy` a
|
||||
|
||||
Add the following content to the file you created:
|
||||
|
||||
```tsx title=src/strategies/publish.ts
|
||||
import { AbstractBatchJobStrategy, BatchJobService } from '@medusajs/medusa'
|
||||
import { EntityManager } from 'typeorm'
|
||||
```ts title=src/strategies/publish.ts
|
||||
import {
|
||||
AbstractBatchJobStrategy,
|
||||
BatchJobService,
|
||||
} from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
protected batchJobService_: BatchJobService
|
||||
processJob(batchJobId: string): Promise<void> {
|
||||
throw new Error('Method not implemented.')
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
buildTemplate(): Promise<string> {
|
||||
throw new Error('Method not implemented.')
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
@@ -79,12 +82,12 @@ You will use the `batchType` later when you [interact with the Batch Job APIs](#
|
||||
|
||||
Following the same example, add the following properties to the `PublishStrategy` class:
|
||||
|
||||
```tsx
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
static identifier = 'publish-products-strategy'
|
||||
static batchType = 'publish-products'
|
||||
static identifier = "publish-products-strategy"
|
||||
static batchType = "publish-products"
|
||||
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -98,10 +101,16 @@ Medusa runs this method before it creates the batch job to prepare the content o
|
||||
|
||||
Implementing this method is optional. For example:
|
||||
|
||||
```tsx
|
||||
async prepareBatchJobForProcessing(batchJob: CreateBatchJobInput, req: Express.Request): Promise<CreateBatchJobInput> {
|
||||
//make changes to the batch job's fields...
|
||||
return batchJob
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async prepareBatchJobForProcessing(
|
||||
batchJob: CreateBatchJobInput,
|
||||
req: Express.Request
|
||||
): Promise<CreateBatchJobInput> {
|
||||
// make changes to the batch job's fields...
|
||||
return batchJob
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -111,35 +120,38 @@ Medusa runs this method after it creates the batch job, but before it is confirm
|
||||
|
||||
For example, this implementation of the `preProcessBatchJob` method calculates how many draft products it will published and adds it to the `result` attribute of the batch job:
|
||||
|
||||
```tsx
|
||||
async preProcessBatchJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const batchJob = (await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.retrieve(batchJobId))
|
||||
|
||||
const count = await this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
.count({
|
||||
status: ProductStatus.DRAFT
|
||||
});
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async preProcessBatchJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const batchJob = (await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.retrieve(batchJobId))
|
||||
|
||||
const count = await this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
.count({
|
||||
status: ProductStatus.DRAFT,
|
||||
})
|
||||
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJob, {
|
||||
result: {
|
||||
advancement_count: 0,
|
||||
count,
|
||||
stat_descriptors: [
|
||||
{
|
||||
key: 'product-publish-count',
|
||||
name: 'Number of products to publish',
|
||||
message: `${count} product(s) will be published.`
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJob, {
|
||||
result: {
|
||||
advancement_count: 0,
|
||||
count,
|
||||
stat_descriptors: [
|
||||
{
|
||||
key: "product-publish-count",
|
||||
name: "Number of products to publish",
|
||||
message: `${count} product(s) will be published.`,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -155,34 +167,37 @@ Medusa runs this method to process the batch job once it is confirmed.
|
||||
|
||||
For example, this implementation of the `processJob` method retrieves all draft products and changes their status to published:
|
||||
|
||||
```tsx
|
||||
async processJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager) => {
|
||||
const productServiceTx = this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async processJob(batchJobId: string): Promise<void> {
|
||||
return await this.atomicPhase_(
|
||||
async (transactionManager) => {
|
||||
const productServiceTx = this.productService_
|
||||
.withTransaction(transactionManager)
|
||||
|
||||
const productList = await productServiceTx
|
||||
.list({
|
||||
status: [ProductStatus.DRAFT]
|
||||
})
|
||||
|
||||
productList.forEach(async (product: Product) => {
|
||||
await productServiceTx
|
||||
.update(product.id, {
|
||||
status: ProductStatus.PUBLISHED
|
||||
const productList = await productServiceTx
|
||||
.list({
|
||||
status: [ProductStatus.DRAFT],
|
||||
})
|
||||
})
|
||||
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJobId, {
|
||||
result: {
|
||||
advancement_count: productList.length
|
||||
}
|
||||
|
||||
productList.forEach(async (product: Product) => {
|
||||
await productServiceTx
|
||||
.update(product.id, {
|
||||
status: ProductStatus.PUBLISHED,
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await this.batchJobService_
|
||||
.withTransaction(transactionManager)
|
||||
.update(batchJobId, {
|
||||
result: {
|
||||
advancement_count: productList.length,
|
||||
},
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -198,9 +213,12 @@ This method can be used in cases where you provide a template file to download,
|
||||
|
||||
If not necessary to your use case, you can simply return an empty string:
|
||||
|
||||
```tsx
|
||||
async buildTemplate(): Promise<string> {
|
||||
return ''
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
async buildTemplate(): Promise<string> {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -212,9 +230,15 @@ By default, the `AbstractBatchJobStrategy` class implements this method and retu
|
||||
|
||||
If you would like to change that behavior, you can override this method to return a different value:
|
||||
|
||||
```tsx
|
||||
protected async shouldRetryOnProcessingError(batchJob: BatchJob, err: unknown): Promise<boolean> {
|
||||
return true
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
protected async shouldRetryOnProcessingError(
|
||||
batchJob: BatchJob,
|
||||
err: unknown
|
||||
): Promise<boolean> {
|
||||
return true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -226,9 +250,16 @@ You can use this method as implemented in `AbstractBatchJobStrategy` at any poin
|
||||
|
||||
You can also override this method in your batch job strategy and change how it works:
|
||||
|
||||
```tsx
|
||||
protected async handleProcessingError<T>(batchJobId: string, err: unknown, result: T): Promise<void> {
|
||||
//different implementation...
|
||||
```ts
|
||||
class PublishStrategy extends AbstractBatchJobStrategy {
|
||||
// ...
|
||||
protected async handleProcessingError<T>(
|
||||
batchJobId: string,
|
||||
err: unknown,
|
||||
result: T
|
||||
): Promise<void> {
|
||||
// different implementation...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -273,13 +304,13 @@ For example, this creates a batch job of the type `publish-products`:
|
||||
|
||||
```jsx
|
||||
medusa.admin.batchJobs.create({
|
||||
type: 'publish-products',
|
||||
type: "publish-products",
|
||||
context: { },
|
||||
dry_run: true
|
||||
dry_run: true,
|
||||
})
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -287,21 +318,21 @@ medusa.admin.batchJobs.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'publish-products',
|
||||
type: "publish-products",
|
||||
context: { },
|
||||
dry_run: true
|
||||
})
|
||||
dry_run: true,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -335,8 +366,8 @@ You can retrieve the batch job afterward to get its status and view details abou
|
||||
```jsx
|
||||
medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -344,12 +375,12 @@ medusa.admin.batchJobs.retrieve(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status, batch_job.result);
|
||||
});
|
||||
console.log(batch_job.status, batch_job.result)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -390,8 +421,8 @@ To process the batch job, send a request to [confirm the batch job](https://docs
|
||||
```jsx
|
||||
medusa.admin.batchJobs.confirm(batchJobId)
|
||||
.then(( batch_job ) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -399,13 +430,13 @@ medusa.admin.batchJobs.confirm(batchJobId)
|
||||
|
||||
```jsx
|
||||
fetch(`<YOUR_SERVER>/admin/batch-jobs/${batchJobId}/confirm`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ batch_job }) => {
|
||||
console.log(batch_job.status);
|
||||
});
|
||||
console.log(batch_job.status)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -565,7 +565,7 @@ To load resources, such as services, in endpoints, use the `req.scope.resolve` f
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const logger = req.scope.resolve('logger');
|
||||
const logger = req.scope.resolve("logger")
|
||||
```
|
||||
|
||||
Please note that in endpoints some resources, such as repositories, are not available.
|
||||
@@ -577,13 +577,13 @@ In classes such as services, strategies, or subscribers, you can load resources
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import { OrderService } from '@medusajs/medusa';
|
||||
import { OrderService } from "@medusajs/medusa"
|
||||
|
||||
class OrderSubscriber {
|
||||
protected orderService: OrderService;
|
||||
protected orderService: OrderService
|
||||
|
||||
constructor({ orderService }) {
|
||||
this.orderService = orderService;
|
||||
this.orderService = orderService
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -62,12 +62,13 @@ Next, in the exported function, retrieve the CORS configurations of your server
|
||||
|
||||
```ts
|
||||
export default (rootDirectory) => {
|
||||
//...
|
||||
// ...
|
||||
|
||||
const { configModule } = getConfigFile<ConfigModule>(rootDirectory, "medusa-config")
|
||||
const { configModule } =
|
||||
getConfigFile<ConfigModule>(rootDirectory, "medusa-config")
|
||||
const { projectConfig } = configModule
|
||||
|
||||
//....
|
||||
// ....
|
||||
}
|
||||
```
|
||||
|
||||
@@ -94,7 +95,7 @@ Finally, for each route you add, create an `OPTIONS` request and add `cors`
|
||||
```ts
|
||||
router.options("/admin/hello", cors(corsOptions))
|
||||
router.get("/admin/hello", cors(corsOptions), (req, res) => {
|
||||
//...
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
@@ -202,20 +203,24 @@ Protected routes are routes that should be accessible by logged-in customers or
|
||||
To make a storefront route protected, first, import the `authenticate-customer` middleware:
|
||||
|
||||
```ts
|
||||
import authenticate from "@medusajs/medusa/dist/api/middlewares/authenticate-customer"
|
||||
import
|
||||
authenticate
|
||||
from "@medusajs/medusa/dist/api/middlewares/authenticate-customer"
|
||||
```
|
||||
|
||||
Then, add the middleware to your route:
|
||||
|
||||
```ts
|
||||
router.options("/store/hello", cors(corsOptions))
|
||||
router.get("/store/hello", cors(corsOptions), authenticate(), async (req, res) => {
|
||||
if (req.user) {
|
||||
//user is logged in
|
||||
//to get customer id: req.user.customer_id
|
||||
router.get("/store/hello", cors(corsOptions), authenticate(),
|
||||
async (req, res) => {
|
||||
if (req.user) {
|
||||
// user is logged in
|
||||
// to get customer id: req.user.customer_id
|
||||
}
|
||||
// ...
|
||||
}
|
||||
//...
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
Please note that the endpoint is still accessible by all users, however, you’ll be able to access the current logged-in customer if there’s any.
|
||||
@@ -227,21 +232,25 @@ To disallow guest customers from accessing the endpoint, you can throw an error
|
||||
To make an admin route protected, first, import the `authenticate` middleware:
|
||||
|
||||
```ts
|
||||
import authenticate from "@medusajs/medusa/dist/api/middlewares/authenticate"
|
||||
import
|
||||
authenticate
|
||||
from "@medusajs/medusa/dist/api/middlewares/authenticate"
|
||||
```
|
||||
|
||||
Then, add the middleware to your route:
|
||||
|
||||
```ts
|
||||
router.options("/admin/products/count", cors(corsOptions))
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(), async (req, res) => {
|
||||
//access current user
|
||||
const id = req.user.userId
|
||||
const userService = req.scope.resolve("userService")
|
||||
|
||||
const user = await userService.retrieve(id)
|
||||
//...
|
||||
})
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(),
|
||||
async (req, res) => {
|
||||
// access current user
|
||||
const id = req.user.userId
|
||||
const userService = req.scope.resolve("userService")
|
||||
|
||||
const user = await userService.retrieve(id)
|
||||
// ...
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Now, only authenticated users can access this endpoint.
|
||||
@@ -257,15 +266,17 @@ You can retrieve any registered service in your endpoint using `req.scope.resol
|
||||
Here’s an example of an endpoint that retrieves the count of products in your store:
|
||||
|
||||
```ts
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(), (req, res) => {
|
||||
const productService = req.scope.resolve("productService")
|
||||
router.get("/admin/products/count", cors(corsOptions), authenticate(),
|
||||
(req, res) => {
|
||||
const productService = req.scope.resolve("productService")
|
||||
|
||||
productService.count().then((count) => {
|
||||
res.json({
|
||||
count,
|
||||
productService.count().then((count) => {
|
||||
res.json({
|
||||
count,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
The `productService` has a `count` method that returns a Promise. This Promise resolves to the count of the products. You return a JSON of the product count.
|
||||
|
||||
@@ -6,15 +6,15 @@ In this document, you’ll learn how you can create an [Entity](overview.md).
|
||||
|
||||
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 title=src/models/post.ts
|
||||
import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm";
|
||||
import { BaseEntity} from "@medusajs/medusa";
|
||||
```ts title=src/models/post.ts
|
||||
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;
|
||||
@Column({ type: "varchar" })
|
||||
title: string | null
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
@@ -31,12 +31,12 @@ To generate an ID for your entity that matches the IDs generated for Medusa’s
|
||||
|
||||
If you want the entity to also be soft deletable then it should extend `SoftDeletableEntity` instead:
|
||||
|
||||
```tsx
|
||||
import { SoftDeletableEntity } from "@medusajs/medusa";
|
||||
```ts
|
||||
import { SoftDeletableEntity } from "@medusajs/medusa"
|
||||
|
||||
@Entity()
|
||||
export class Post extends SoftDeletableEntity {
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ You can learn more about Migrations, how to create them, and how to run them in
|
||||
|
||||
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` created in `src/repositories/post.ts`:
|
||||
|
||||
```tsx title=src/repositories/post.ts
|
||||
```ts title=src/repositories/post.ts
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
|
||||
import { Post } from "../models/post"
|
||||
@@ -85,24 +85,25 @@ 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 '@medusajs/medusa';
|
||||
```ts
|
||||
import { TransactionBaseService } from "@medusajs/medusa"
|
||||
|
||||
class PostService extends TransactionBaseService {
|
||||
constructor({ postRepository, manager }) {
|
||||
super({ postRepository, manager });
|
||||
super({ postRepository, manager })
|
||||
|
||||
this.postRepository = postRepository;
|
||||
this.manager_ = manager;
|
||||
this.postRepository = postRepository
|
||||
this.manager_ = manager
|
||||
}
|
||||
|
||||
async list() {
|
||||
const postRepository = this.manager_.getCustomRepository(this.postRepository);
|
||||
return await postRepository.find();
|
||||
const postRepository = this.manager_
|
||||
.getCustomRepository(this.postRepository)
|
||||
return await postRepository.find()
|
||||
}
|
||||
}
|
||||
|
||||
export default PostService;
|
||||
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).
|
||||
@@ -123,8 +124,8 @@ This same usage of repositories can be done in subscribers as well.
|
||||
|
||||
To delete soft-deletable entities that extend the `SoftDeletableEntity` class, you can use the repository method `softDelete` method:
|
||||
|
||||
```tsx
|
||||
await postRepository.softDelete(post.id);
|
||||
```ts
|
||||
await postRepository.softDelete(post.id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -51,9 +51,9 @@ For example, to enable the Tax-Inclusive Pricing beta feature, add the following
|
||||
```jsx title=medusa-config.js
|
||||
module.exports = {
|
||||
featureFlags: {
|
||||
tax_inclusive_pricing: true
|
||||
tax_inclusive_pricing: true,
|
||||
},
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -23,23 +23,39 @@ Creating a Notification Provider is as simple as creating a TypeScript or JavaS
|
||||
For example, create the file `src/services/email-sender.ts` with the following content:
|
||||
|
||||
```ts title=src/services/email-sender.ts
|
||||
import { AbstractNotificationService } from "@medusajs/medusa";
|
||||
import { EntityManager } from "typeorm";
|
||||
import { AbstractNotificationService } from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
|
||||
sendNotification(event: string, data: unknown, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
throw new Error("Method not implemented.");
|
||||
sendNotification(
|
||||
event: string,
|
||||
data: unknown,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
resendNotification(notification: unknown, config: unknown, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
throw new Error("Method not implemented.");
|
||||
resendNotification(
|
||||
notification: unknown,
|
||||
config: unknown,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EmailSenderService;
|
||||
export default EmailSenderService
|
||||
```
|
||||
|
||||
Where `EmailSenderService` is the name of your Notification Provider Service.
|
||||
@@ -63,7 +79,10 @@ The value of this property is also used later when you want to subscribe the Not
|
||||
For example, in the class you created in the previous code snippet you can add the following property:
|
||||
|
||||
```ts
|
||||
static identifier = "email-sender";
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
static identifier = "email-sender"
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### constructor
|
||||
@@ -83,23 +102,26 @@ You can learn more about plugins and how to create them in the [Plugins](../plug
|
||||
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:
|
||||
|
||||
```ts
|
||||
import { AbstractNotificationService, OrderService } from "@medusajs/medusa";
|
||||
import {
|
||||
AbstractNotificationService,
|
||||
OrderService,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
static identifier = "email-sender";
|
||||
protected orderService: OrderService;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
static identifier = "email-sender"
|
||||
protected orderService: OrderService
|
||||
|
||||
constructor(container, options) {
|
||||
super(container);
|
||||
//you can access options here in case you're
|
||||
//using a plugin
|
||||
super(container)
|
||||
// you can access options here in case you're
|
||||
// using a plugin
|
||||
|
||||
this.orderService = container.orderService;
|
||||
this.orderService = container.orderService
|
||||
}
|
||||
|
||||
//...
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -129,23 +151,34 @@ This method must return an object containing two properties:
|
||||
Continuing with the previous example you can have the following implementation of the `sendNotification` method:
|
||||
|
||||
```ts
|
||||
async sendNotification(event: string, data: any, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
if (event === 'order.placed') {
|
||||
//retrieve order
|
||||
const order = await this.orderService.retrieve(data.id);
|
||||
//TODO send email
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
// ...
|
||||
async sendNotification(
|
||||
event: string,
|
||||
data: any,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
if (event === "order.placed") {
|
||||
// retrieve order
|
||||
const order = await this.orderService.retrieve(data.id)
|
||||
// TODO send email
|
||||
|
||||
console.log('Notification sent');
|
||||
return {
|
||||
to: order.email,
|
||||
status: 'done',
|
||||
data: {
|
||||
//any data necessary to send the email
|
||||
//for example:
|
||||
subject: 'You placed a new order!',
|
||||
items: order.items
|
||||
console.log("Notification sent")
|
||||
return {
|
||||
to: order.email,
|
||||
status: "done",
|
||||
data: {
|
||||
// any data necessary to send the email
|
||||
// for example:
|
||||
subject: "You placed a new order!",
|
||||
items: order.items,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -180,17 +213,29 @@ Similarly to the `sendNotification` method, this method must return an object co
|
||||
Continuing with the previous example you can have the following implementation of the `resendNotification` method:
|
||||
|
||||
```ts
|
||||
async resendNotification(notification: any, config: any, attachmentGenerator: unknown): Promise<{ to: string; status: string; data: Record<string, unknown>; }> {
|
||||
//check if the receiver of the notification should be changed
|
||||
const to: string = config.to ? config.to : notification.to;
|
||||
class EmailSenderService extends AbstractNotificationService {
|
||||
// ...
|
||||
async resendNotification(
|
||||
notification: any,
|
||||
config: any,
|
||||
attachmentGenerator: unknown
|
||||
): Promise<{
|
||||
to: string;
|
||||
status: string;
|
||||
data: Record<string, unknown>;
|
||||
}> {
|
||||
// check if the receiver of the notification should be changed
|
||||
const to: string = config.to ? config.to : notification.to
|
||||
|
||||
//TODO resend the notification using the same data that is saved under notification.data
|
||||
// TODO resend the notification using the same data
|
||||
// that is saved under notification.data
|
||||
|
||||
console.log('Notification resent');
|
||||
return {
|
||||
to,
|
||||
status: 'done',
|
||||
data: notification.data //you can also make changes to the data
|
||||
console.log("Notification resent")
|
||||
return {
|
||||
to,
|
||||
status: "done",
|
||||
data: notification.data, // you can also make changes to the data
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -224,11 +269,12 @@ Following the previous example, to make sure the `email-sender` Notification Pro
|
||||
```ts title=src/subscribers/notification.js
|
||||
class NotificationSubscriber {
|
||||
constructor({ notificationService }) {
|
||||
notificationService.subscribe('order.placed', 'email-sender');
|
||||
notificationService.subscribe("order.placed", "email-sender")
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
export default NotificationSubscriber;
|
||||
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.
|
||||
@@ -288,5 +334,5 @@ This request returns the same notification object as the List Notifications endp
|
||||
- [Events reference](../subscribers/events-list.md)
|
||||
- [SendGrid Plugin](../../../add-plugins/sendgrid.mdx)
|
||||
- [Create a Subscriber](../subscribers/create-subscriber.md)
|
||||
- [Create a Service](../services/create-service.md).
|
||||
- [Create a Plugin](../plugins/create.md).
|
||||
- [Create a Service](../services/create-service.md)
|
||||
- [Create a Plugin](../plugins/create.md)
|
||||
@@ -50,51 +50,60 @@ The first step to create a payment provider is to create a JavaScript or TypeScr
|
||||
|
||||
For example, create the file `src/services/my-payment.ts` with the following content:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts title=src/services/my-payment.ts
|
||||
import { AbstractPaymentService, Cart, Data, Payment, PaymentSession, PaymentSessionStatus, TransactionBaseService } from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm";
|
||||
import {
|
||||
AbstractPaymentService,
|
||||
Cart, Data, Payment, PaymentSession,
|
||||
PaymentSessionStatus, TransactionBaseService,
|
||||
} from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
|
||||
getPaymentData(paymentSession: PaymentSession): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
updatePaymentData(paymentSessionData: Data, data: Data): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
createPayment(cart: Cart): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
retrievePayment(paymentData: Data): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
updatePayment(paymentSessionData: Data, cart: Cart): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
authorizePayment(paymentSession: PaymentSession, context: Data): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
throw new Error("Method not implemented.");
|
||||
authorizePayment(
|
||||
paymentSession: PaymentSession,
|
||||
context: Data
|
||||
): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
capturePayment(payment: Payment): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
refundPayment(payment: Payment, refundAmount: number): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
cancelPayment(payment: Payment): Promise<Data> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
deletePayment(paymentSession: PaymentSession): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
getStatus(data: Data): Promise<PaymentSessionStatus> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default MyPaymentService;
|
||||
export default MyPaymentService
|
||||
```
|
||||
|
||||
Where `MyPaymentService` is the name of your Payment Provider service. For example, Stripe’s Payment Provider Service is called `StripeProviderService`.
|
||||
@@ -123,10 +132,16 @@ You can also use the constructor to initialize your integration with the third-p
|
||||
|
||||
Additionally, if you’re 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:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
constructor({ productService }, options) {
|
||||
super();
|
||||
//you can access options here
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
constructor({ productService }, options) {
|
||||
super()
|
||||
// you can access options here
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -140,15 +155,20 @@ This method must return an object that is going to be stored in the `data` field
|
||||
|
||||
An example of a minimal implementation of `createPayment` that does not interact with any third-party providers:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Cart, Data } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
async createPayment(cart: Cart): Promise<Data> {
|
||||
return {
|
||||
id: 'test-payment',
|
||||
status: 'pending'
|
||||
};
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async createPayment(cart: Cart): Promise<Data> {
|
||||
return {
|
||||
id: "test-payment",
|
||||
status: "pending",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -162,12 +182,17 @@ This method must return an object containing the data from the third-party provi
|
||||
|
||||
An example of a minimal implementation of `retrievePayment` where you don’t need to interact with the third-party provider:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Data } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
async retrievePayment(paymentData: Data): Promise<Data> {
|
||||
return {};
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async retrievePayment(paymentData: Data): Promise<Data> {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -189,12 +214,17 @@ This method returns a string that represents the status. The status must be one
|
||||
|
||||
An example of a minimal implementation of `getStatus` where you don’t need to interact with the third-party provider:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Data, PaymentSessionStatus } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
async getStatus(data: Data): Promise<PaymentSessionStatus> {
|
||||
return PaymentSessionStatus.AUTHORIZED;
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async getStatus(data: Data): Promise<PaymentSessionStatus> {
|
||||
return PaymentSessionStatus.AUTHORIZED
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -222,12 +252,17 @@ This method must return an object that will be stored in the `data` field of the
|
||||
|
||||
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:
|
||||
|
||||
```ts
|
||||
import { Cart, Data } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async updatePayment(paymentSessionData: Data, cart: Cart): Promise<Data> {
|
||||
return paymentSessionData;
|
||||
```ts
|
||||
import { Cart, Data } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async updatePayment(paymentSessionData: Data, cart: Cart): Promise<Data> {
|
||||
return paymentSessionData
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -243,12 +278,20 @@ This method must return an object that will be stored in the `data` field of the
|
||||
|
||||
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.
|
||||
|
||||
```ts
|
||||
import { Data } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async updatePaymentData(paymentSessionData: Data, updatedData: Data): Promise<Data> {
|
||||
return updatedData;
|
||||
```ts
|
||||
import { Data } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async updatePaymentData(
|
||||
paymentSessionData: Data,
|
||||
updatedData: Data
|
||||
): Promise<Data> {
|
||||
return updatedData
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -267,12 +310,17 @@ You can use this method to interact with the third-party provider to delete data
|
||||
|
||||
An example of a minimal implementation of `deletePayment` where no interaction with a third-party provider is required:
|
||||
|
||||
```ts
|
||||
import { PaymentSession } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async deletePayment(paymentSession: PaymentSession): Promise<void> {
|
||||
return;
|
||||
```ts
|
||||
import { PaymentSession } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async deletePayment(paymentSession: PaymentSession): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -305,17 +353,29 @@ You can utilize this method to interact with the third-party provider and perfor
|
||||
|
||||
An example of a minimal implementation of `authorizePayment` that doesn’t need to interact with any third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, PaymentSession, PaymentSessionStatus } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async authorizePayment(paymentSession: PaymentSession, context: Data): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
return {
|
||||
status: PaymentSessionStatus.AUTHORIZED,
|
||||
data: {
|
||||
id: 'test'
|
||||
```ts
|
||||
import {
|
||||
Data,
|
||||
PaymentSession,
|
||||
PaymentSessionStatus,
|
||||
} from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async authorizePayment(
|
||||
paymentSession: PaymentSession,
|
||||
context: Data
|
||||
): Promise<{ data: Data; status: PaymentSessionStatus; }> {
|
||||
return {
|
||||
status: PaymentSessionStatus.AUTHORIZED,
|
||||
data: {
|
||||
id: "test",
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -329,12 +389,17 @@ This method must return an object to be stored in the `data` field of the Paymen
|
||||
|
||||
An example of a minimal implementation of `getPaymentData`:
|
||||
|
||||
```ts
|
||||
import { Data, PaymentSession } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async getPaymentData(paymentSession: PaymentSession): Promise<Data> {
|
||||
return paymentSession.data;
|
||||
```ts
|
||||
import { Data, PaymentSession } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async getPaymentData(paymentSession: PaymentSession): Promise<Data> {
|
||||
return paymentSession.data
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -352,14 +417,19 @@ This method must return an object that will be stored in the `data` field of the
|
||||
|
||||
An example of a minimal implementation of `capturePayment` that doesn’t need to interact with a third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async capturePayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
status: 'captured'
|
||||
};
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async capturePayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
status: "captured",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -377,13 +447,21 @@ This method must return an object that is stored in the `data` field of the Paym
|
||||
|
||||
An example of a minimal implementation of `refundPayment` that doesn’t need to interact with a third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async refundPayment(payment: Payment, refundAmount: number): Promise<Data> {
|
||||
return {
|
||||
id: 'test'
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async refundPayment(
|
||||
payment: Payment,
|
||||
refundAmount: number
|
||||
): Promise<Data> {
|
||||
return {
|
||||
id: "test",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -405,13 +483,18 @@ This method must return an object that is stored in the `data` field of the Paym
|
||||
|
||||
An example of a minimal implementation of `cancelPayment` that doesn’t need to interact with a third-party provider:
|
||||
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa";
|
||||
//...
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
async cancelPayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
id: 'test'
|
||||
```ts
|
||||
import { Data, Payment } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async cancelPayment(payment: Payment): Promise<Data> {
|
||||
return {
|
||||
id: "test",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -438,26 +521,31 @@ If you’re using Medusa’s [Next.js](../../../starters/nextjs-medusa-starter.m
|
||||
|
||||
An example of the implementation of `retrieveSavedMethods` taken from Stripe’s Payment Provider:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { Customer, Data } from "@medusajs/medusa"
|
||||
//...
|
||||
// ...
|
||||
|
||||
/**
|
||||
* 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: Customer): Promise<Data[]> {
|
||||
if (customer.metadata && customer.metadata.stripe_id) {
|
||||
const methods = await this.stripe_.paymentMethods.list({
|
||||
customer: customer.metadata.stripe_id,
|
||||
type: "card",
|
||||
})
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
/**
|
||||
* Fetches a customers saved payment methods if registered in Stripe.
|
||||
* @param {object} customer - customer to fetch saved cards for
|
||||
* @return {Promise<Array<object>>} saved payments methods
|
||||
*/
|
||||
async retrieveSavedMethods(customer: Customer): Promise<Data[]> {
|
||||
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 methods.data
|
||||
}
|
||||
|
||||
return Promise.resolve([])
|
||||
}
|
||||
|
||||
return Promise.resolve([])
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ To pass a plugin its configurations on a Medusa server, you have to add it to th
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-custom`,
|
||||
options: {
|
||||
@@ -225,19 +225,23 @@ const plugins = [
|
||||
Then, you can have access to your plugin configuration in the constructor of services in your plugin:
|
||||
|
||||
```jsx title=src/service/test.ts
|
||||
//In a service in your plugin
|
||||
constructor({}, options) {
|
||||
//options contains plugin configurations
|
||||
this.name = options.name
|
||||
// In a service in your plugin
|
||||
class MyService extends TransactionBaseService {
|
||||
constructor(container, options) {
|
||||
super(container)
|
||||
// options contains plugin configurations
|
||||
this.name = options.name
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
You can also have access to the configurations in endpoints in your plugin:
|
||||
|
||||
```jsx title=src/api/index.ts
|
||||
//in an endpoint in your plugin
|
||||
// in an endpoint in your plugin
|
||||
export default (rootDirectory, options) => {
|
||||
//options contain the plugin configurations
|
||||
// options contain the plugin configurations
|
||||
const router = Router()
|
||||
|
||||
router.get("/hello-world", (req, res) => {
|
||||
@@ -293,10 +297,10 @@ Then, add your plugin into the array of plugins in `medusa-config.js`:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
const plugins = [
|
||||
//...
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-custom`,
|
||||
//if your plugin has configurations
|
||||
// if your plugin has configurations
|
||||
options: {
|
||||
name: "My Store",
|
||||
},
|
||||
|
||||
@@ -37,6 +37,8 @@ When you create a price list, you can specify different conditions to control wh
|
||||
|
||||
In the body of your request, aside from the required fields, you can send the following fields to apply different conditions:
|
||||
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```js noReport
|
||||
{
|
||||
prices: [
|
||||
@@ -70,28 +72,28 @@ For example, sending the following request creates a price list with two prices:
|
||||
import { PriceListType } from "@medusajs/medusa"
|
||||
|
||||
medusa.admin.priceLists.create({
|
||||
name: 'New Price List',
|
||||
description: 'A new price list',
|
||||
name: "New Price List",
|
||||
description: "A new price list",
|
||||
type: PriceListType.SALE,
|
||||
status: 'active',
|
||||
status: "active",
|
||||
prices: [
|
||||
{
|
||||
amount: 1000,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
max_quantity: 3
|
||||
currency_code: "eur",
|
||||
max_quantity: 3,
|
||||
},
|
||||
{
|
||||
amount: 1500,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
min_quantity: 4
|
||||
}
|
||||
]
|
||||
currency_code: "eur",
|
||||
min_quantity: 4,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -99,31 +101,31 @@ medusa.admin.priceLists.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: 'New Price List',
|
||||
description: 'A new price list',
|
||||
type: 'sale',
|
||||
status: 'active',
|
||||
name: "New Price List",
|
||||
description: "A new price list",
|
||||
type: "sale",
|
||||
status: "active",
|
||||
prices: [
|
||||
{
|
||||
amount: 1000,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
max_quantity: 3
|
||||
currency_code: "eur",
|
||||
max_quantity: 3,
|
||||
},
|
||||
{
|
||||
amount: 1500,
|
||||
variant_id,
|
||||
currency_code: 'eur',
|
||||
min_quantity: 4
|
||||
}
|
||||
]
|
||||
})
|
||||
currency_code: "eur",
|
||||
min_quantity: 4,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -179,8 +181,8 @@ You can retrieve all of a price list’s details using the Get a Price List endp
|
||||
```jsx
|
||||
medusa.admin.priceLists.retrieve(priceListId)
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -188,7 +190,7 @@ medusa.admin.priceLists.retrieve(priceListId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -199,7 +201,7 @@ fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X GET '<SERVER_URL>/admin/price-lists/{id}' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
@@ -220,11 +222,11 @@ For example, by sending the following request the end date of the price list wil
|
||||
|
||||
```jsx
|
||||
medusa.admin.priceLists.update(priceListId, {
|
||||
ends_at: '2022-10-11'
|
||||
ends_at: "2022-10-11",
|
||||
})
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -232,14 +234,14 @@ medusa.admin.priceLists.update(priceListId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ends_at: '2022-10-11'
|
||||
})
|
||||
ends_at: "2022-10-11",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -287,13 +289,13 @@ medusa.admin.priceLists.addPrices(priceListId, {
|
||||
{
|
||||
amount: 1200,
|
||||
variant_id,
|
||||
currency_code: 'eur'
|
||||
}
|
||||
]
|
||||
currency_code: "eur",
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ price_list }) => {
|
||||
console.log(price_list.id);
|
||||
});
|
||||
console.log(price_list.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -301,20 +303,20 @@ medusa.admin.priceLists.addPrices(priceListId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/prices/batch`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prices: [
|
||||
{
|
||||
amount: 1200,
|
||||
variant_id,
|
||||
currency_code: 'eur'
|
||||
}
|
||||
]
|
||||
})
|
||||
currency_code: "eur",
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ price_list }) => {
|
||||
@@ -357,18 +359,23 @@ You can delete all the prices of a product’s variants using the [Delete Produc
|
||||
```jsx
|
||||
medusa.admin.priceLists.deleteProductPrices(priceListId, productId)
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids.length);
|
||||
});
|
||||
console.log(ids.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/products/${productId}/prices`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/price-lists/${priceListId}/products/${productId}/prices`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids.length)
|
||||
@@ -398,18 +405,23 @@ You can delete all the prices of a variant using the [Delete Variant Prices](htt
|
||||
```jsx
|
||||
medusa.admin.priceLists.deleteVariantPrices(priceListId, variantId)
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids);
|
||||
});
|
||||
console.log(ids)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/variants/${variantId}/prices`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/price-lists/${priceListId}/variants/${variantId}/prices`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ ids, object, deleted }) => {
|
||||
console.log(ids.length)
|
||||
@@ -419,7 +431,7 @@ fetch(`<SERVER_URL>/admin/price-lists/${priceListId}/variants/${variantId}/price
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/price-lists/<PRICE_LIST_ID>/variants/<VARIANT_ID>/prices' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
@@ -441,8 +453,8 @@ You can delete a price list, and subsequently all prices defined in it, using th
|
||||
```jsx
|
||||
medusa.admin.priceLists.delete(priceListId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -450,8 +462,8 @@ medusa.admin.priceLists.delete(priceListId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
@@ -462,7 +474,7 @@ fetch(`<SERVER_URL>/admin/price-lists/${priceListId}`, {
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/price-lists/<PRICE_LIST_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
@@ -57,12 +57,12 @@ You can create a sales channel by sending a request to the Create a Sales Channe
|
||||
|
||||
```jsx
|
||||
medusa.admin.salesChannels.create({
|
||||
name: 'App',
|
||||
description: 'Mobile app'
|
||||
name: "App",
|
||||
description: "Mobile app",
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -70,20 +70,20 @@ medusa.admin.salesChannels.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: 'App',
|
||||
description: 'Mobile app'
|
||||
})
|
||||
name: "App",
|
||||
description: "Mobile app",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -118,8 +118,8 @@ You can list all sales channels by sending a request to the List Sales Channels
|
||||
```jsx
|
||||
medusa.admin.salesChannels.list()
|
||||
.then(({ sales_channels, limit, offset, count }) => {
|
||||
console.log(sales_channels.length);
|
||||
});
|
||||
console.log(sales_channels.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -127,12 +127,12 @@ medusa.admin.salesChannels.list()
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channels, limit, offset, count }) => {
|
||||
console.log(sales_channels.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -160,8 +160,8 @@ You can retrieve a sales channel’s details by its ID using the Get Sales Chann
|
||||
```jsx
|
||||
medusa.admin.salesChannels.retrieve(salesChannelId)
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -169,12 +169,12 @@ medusa.admin.salesChannels.retrieve(salesChannelId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channels, limit, offset, count }) => {
|
||||
console.log(sales_channels.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -201,11 +201,11 @@ You can update a Sales Channel’s details and attributes by sending a request t
|
||||
|
||||
```jsx
|
||||
medusa.admin.salesChannels.update(salesChannelId, {
|
||||
is_disabled: false
|
||||
is_disabled: false,
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -213,19 +213,19 @@ medusa.admin.salesChannels.update(salesChannelId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is_disabled: false
|
||||
})
|
||||
is_disabled: false,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -261,8 +261,8 @@ You can delete a sales channel by sending a request to the Delete Sales Channel
|
||||
```jsx
|
||||
medusa.admin.salesChannels.delete(salesChannelId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id);
|
||||
});
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -270,13 +270,13 @@ medusa.admin.salesChannels.delete(salesChannelId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -307,37 +307,40 @@ To add a product to a sales channel, send a request to the Sales Channel’s Add
|
||||
medusa.admin.salesChannels.addProducts(salesChannelId, {
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -373,25 +376,28 @@ You can list the products available in a sales channel by sending a request to t
|
||||
```jsx
|
||||
medusa.admin.products.list({
|
||||
sales_channel_id: [
|
||||
salesChannelId
|
||||
]
|
||||
salesChannelId,
|
||||
],
|
||||
})
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length);
|
||||
});
|
||||
console.log(products.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/products?sales_channel_id[0]=${salesChannelId}`, {
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/products?sales_channel_id[0]=${salesChannelId}`,
|
||||
{
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -424,43 +430,46 @@ You can delete a product from a sales channel by sending a request to the Sales
|
||||
medusa.admin.salesChannels.removeProducts(salesChannelId, {
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id);
|
||||
});
|
||||
console.log(sales_channel.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/admin/sales-channels/${salesChannelId}/products/batch`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_ids: [
|
||||
{
|
||||
id: productId,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ sales_channel }) => {
|
||||
console.log(sales_channel.id)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X DELETE '<SERVER_URL>/admin/sales-channels/<SALES_CHANNEL_ID>/products/batch' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
@@ -492,14 +501,14 @@ You can filter orders by a specific sales channel by sending a request to the Li
|
||||
```jsx
|
||||
medusa.admin.orders.list({
|
||||
sales_channel_id: [
|
||||
salesChannelId
|
||||
salesChannelId,
|
||||
],
|
||||
limit: 50,
|
||||
offset: 0
|
||||
offset: 0,
|
||||
})
|
||||
.then(({ orders, limit, offset, count }) => {
|
||||
console.log(orders.length);
|
||||
});
|
||||
console.log(orders.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -507,18 +516,18 @@ medusa.admin.orders.list({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/admin/orders?sales_channel_id[0]=${salesChannelId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ orders, limit, offset, count }) => {
|
||||
console.log(orders.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
curl -L -X GET '<SERVER_URL>/admin/orders?sales_channel_id[0]=<SALES_CHANNEL_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
@@ -38,23 +38,25 @@ To create a scheduled job, add the following code in the file you created, which
|
||||
|
||||
```ts title=src/loaders/publish.ts
|
||||
const publishJob = async (container, options) => {
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService");
|
||||
jobSchedulerService.create("publish-products", {}, "0 0 * * *", async () => {
|
||||
//job to execute
|
||||
const productService = container.resolve("productService");
|
||||
const draftProducts = await productService.list({
|
||||
status: 'draft'
|
||||
});
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService")
|
||||
jobSchedulerService.create("publish-products", {}, "0 0 * * *",
|
||||
async () => {
|
||||
// job to execute
|
||||
const productService = container.resolve("productService")
|
||||
const draftProducts = await productService.list({
|
||||
status: "draft",
|
||||
})
|
||||
|
||||
for (const product of draftProducts) {
|
||||
await productService.update(product.id, {
|
||||
status: 'published'
|
||||
});
|
||||
for (const product of draftProducts) {
|
||||
await productService.update(product.id, {
|
||||
status: "published",
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export default publishJob;
|
||||
export default publishJob
|
||||
```
|
||||
|
||||
:::info
|
||||
@@ -87,12 +89,12 @@ For example:
|
||||
```ts
|
||||
jobSchedulerService.create("publish-products", {
|
||||
data: {
|
||||
productId
|
||||
}
|
||||
productId,
|
||||
},
|
||||
}, "0 0 * * *", async (job) => {
|
||||
console.log(job.data); // {productId: 'prod_124...'}
|
||||
//...
|
||||
});
|
||||
console.log(job.data) // {productId: 'prod_124...'}
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -9,12 +9,12 @@ To create a service, create a TypeScript or JavaScript file in `src/services` to
|
||||
For example, if you want to create a service `helloService`, create the file `hello.ts` in `src/services` with the following content:
|
||||
|
||||
```ts title=/src/services/hello.ts
|
||||
import { TransactionBaseService } from '@medusajs/medusa';
|
||||
import { EntityManager } from 'typeorm';
|
||||
import { TransactionBaseService } from "@medusajs/medusa"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
class HelloService extends TransactionBaseService {
|
||||
protected manager_: EntityManager;
|
||||
protected transactionManager_: EntityManager;
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager
|
||||
getMessage() {
|
||||
return `Welcome to My Store!`
|
||||
}
|
||||
@@ -32,19 +32,25 @@ As the service extends the `TransactionBaseService` class, all services in Medus
|
||||
So, if you want your service to use another service, simply add it as part of your constructor’s dependencies and set it to a field inside your service’s class:
|
||||
|
||||
```ts
|
||||
private productService: ProductService;
|
||||
class HelloService extends TransactionBaseService {
|
||||
private productService: ProductService
|
||||
|
||||
constructor(container) {
|
||||
super(container);
|
||||
this.productService = container.productService;
|
||||
constructor(container) {
|
||||
super(container)
|
||||
this.productService = container.productService
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Then, you can use that service anywhere in your custom service:
|
||||
|
||||
```ts
|
||||
async getProductCount() {
|
||||
return await this.productService.count();
|
||||
class HelloService extends TransactionBaseService {
|
||||
// ...
|
||||
async getProductCount() {
|
||||
return await this.productService.count()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -69,9 +75,12 @@ npm run build
|
||||
To use your custom service in another custom service, you can have easy access to it in the dependencies injected to the constructor of your service:
|
||||
|
||||
```ts
|
||||
constructor(container) {
|
||||
super(container);
|
||||
this.helloService = container.helloService;
|
||||
class MyService extends TransactionBaseService {
|
||||
constructor(container) {
|
||||
super(container)
|
||||
this.helloService = container.helloService
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -92,8 +101,11 @@ res.json({
|
||||
To use your custom service in a subscriber, you can have easy access to it in the subscriber’s dependencies injected to the constructor of your subscriber:
|
||||
|
||||
```ts
|
||||
constructor({ helloService, eventBusService }) {
|
||||
this.helloService = helloService;
|
||||
class MySubscriber {
|
||||
constructor({ helloService, eventBusService }) {
|
||||
this.helloService = helloService
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class MyFulfillmentService extends FulfillmentService {
|
||||
|
||||
}
|
||||
|
||||
export default MyFulfillmentService;
|
||||
export default MyFulfillmentService
|
||||
```
|
||||
|
||||
Fulfillment provider services must extend the `FulfillmentService` class imported from `medusa-interfaces`.
|
||||
@@ -55,10 +55,10 @@ The value of this property will also be used to reference the fulfillment provid
|
||||
import { FulfillmentService } from "medusa-interfaces"
|
||||
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
static identifier = 'my-fulfillment';
|
||||
static identifier = "my-fulfillment"
|
||||
}
|
||||
|
||||
export default MyFulfillmentService;
|
||||
export default MyFulfillmentService
|
||||
```
|
||||
|
||||
### constructor
|
||||
@@ -72,9 +72,12 @@ Additionally, if you’re creating your fulfillment provider as an external plug
|
||||
For example:
|
||||
|
||||
```ts
|
||||
constructor({ productService }, options) {
|
||||
super();
|
||||
//you can access options here
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
constructor(container, options) {
|
||||
super(container)
|
||||
// you can access options here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -89,15 +92,18 @@ These fulfillment options are defined in the `getFulfillmentOptions` method. Thi
|
||||
For example:
|
||||
|
||||
```ts
|
||||
async getFulfillmentOptions () {
|
||||
return [
|
||||
{
|
||||
id: 'my-fulfillment'
|
||||
},
|
||||
{
|
||||
id: 'my-fulfillment-dynamic'
|
||||
}
|
||||
];
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
async getFulfillmentOptions() {
|
||||
return [
|
||||
{
|
||||
id: "my-fulfillment",
|
||||
},
|
||||
{
|
||||
id: "my-fulfillment-dynamic",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -116,8 +122,11 @@ This method returns a boolean. If the result is false, an error is thrown and th
|
||||
For example, you can use this method to ensure that the `id` in the `data` object is correct:
|
||||
|
||||
```ts
|
||||
async validateOption (data) {
|
||||
return data.id == 'my-fulfillment';
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
async validateOption(data) {
|
||||
return data.id == "my-fulfillment"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -144,13 +153,16 @@ If everything is valid, this method must return a value that will be stored in t
|
||||
For example:
|
||||
|
||||
```ts
|
||||
async validateFulfillmentData(optionData, data, cart) {
|
||||
if (data.id !== "my-fulfillment") {
|
||||
throw new Error("invalid data");
|
||||
}
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
async validateFulfillmentData(optionData, data, cart) {
|
||||
if (data.id !== "my-fulfillment") {
|
||||
throw new Error("invalid data")
|
||||
}
|
||||
|
||||
return {
|
||||
...data
|
||||
return {
|
||||
...data,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -173,14 +185,17 @@ You can use the `data` property in the shipping method (first parameter) to acce
|
||||
Here is a basic implementation of `createFulfillment` for a fulfillment provider that does not interact with any third-party provider to create the fulfillment:
|
||||
|
||||
```ts
|
||||
createFulfillment(
|
||||
methodData,
|
||||
fulfillmentItems,
|
||||
fromOrder,
|
||||
fulfillment
|
||||
) {
|
||||
// No data is being sent anywhere
|
||||
return Promise.resolve({})
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
createFulfillment(
|
||||
methodData,
|
||||
fulfillmentItems,
|
||||
fromOrder,
|
||||
fulfillment
|
||||
) {
|
||||
// No data is being sent anywhere
|
||||
return Promise.resolve({})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -206,8 +221,11 @@ This method receives as a parameter the `data` object sent with the request that
|
||||
For example:
|
||||
|
||||
```ts
|
||||
canCalculate(data) {
|
||||
return data.id === 'my-fulfillment-dynamic';
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
canCalculate(data) {
|
||||
return data.id === "my-fulfillment-dynamic"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -224,16 +242,22 @@ This method receives three parameters:
|
||||
If your fulfillment provider does not provide any dynamically calculated rates you can keep the function empty:
|
||||
|
||||
```ts
|
||||
calculatePrice() {
|
||||
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
calculatePrice() {
|
||||
// leave empty
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Otherwise, you can use it to calculate the price with a custom logic. For example:
|
||||
|
||||
```ts
|
||||
calculatePrice (optionData, data, cart) {
|
||||
return cart.items.length * 1000;
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
calculatePrice(optionData, data, cart) {
|
||||
return cart.items.length * 1000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -250,8 +274,11 @@ It receives the return created as a parameter. The value it returns is set to th
|
||||
This is the basic implementation of the method for a fulfillment provider that does not contact with a third-party provider to fulfill the return:
|
||||
|
||||
```ts
|
||||
createReturn(returnOrder) {
|
||||
return Promise.resolve({})
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
createReturn(returnOrder) {
|
||||
return Promise.resolve({})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -266,8 +293,11 @@ This method receives the fulfillment being cancelled as a parameter.
|
||||
This is the basic implementation of the method for a fulfillment provider that does not interact with a third-party provider to cancel the fulfillment:
|
||||
|
||||
```ts
|
||||
cancelFulfillment(fulfillment) {
|
||||
return Promise.resolve({})
|
||||
class MyFulfillmentService extends FulfillmentService {
|
||||
// ...
|
||||
cancelFulfillment(fulfillment) {
|
||||
return Promise.resolve({})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -18,20 +18,20 @@ After creating the file under `src/subscribers`, in the constructor of your subs
|
||||
|
||||
The `eventBusService.subscribe` method receives the name of the event as a first parameter and as a second parameter a method in your subscriber that will handle this event.
|
||||
|
||||
For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/orderNotifier.js`:
|
||||
For example, here is the `OrderNotifierSubscriber` class created in `src/subscribers/orderNotifier.ts`:
|
||||
|
||||
```ts title=src/subscribers/orderNotifier.js
|
||||
```ts title=src/subscribers/orderNotifier.ts
|
||||
class OrderNotifierSubscriber {
|
||||
constructor({ eventBusService }) {
|
||||
eventBusService.subscribe("order.placed", this.handleOrder);
|
||||
eventBusService.subscribe("order.placed", this.handleOrder)
|
||||
}
|
||||
|
||||
handleOrder = async (data) => {
|
||||
console.log("New Order: " + data.id)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderNotifierSubscriber;
|
||||
export default OrderNotifierSubscriber
|
||||
```
|
||||
|
||||
This subscriber registers 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. It receives the order ID in the `data` parameter. You can then use the order’s details to perform any kind of task you need.
|
||||
@@ -51,19 +51,25 @@ You can access any service through the dependencies injected to your subscriber
|
||||
For example:
|
||||
|
||||
```ts
|
||||
constructor({ productService, eventBusService }) {
|
||||
this.productService = productService;
|
||||
class OrderNotifierSubscriber {
|
||||
constructor({ productService, eventBusService }) {
|
||||
this.productService = productService
|
||||
|
||||
eventBusService.subscribe("order.placed", this.handleOrder);
|
||||
eventBusService.subscribe("order.placed", this.handleOrder)
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
You can then use `this.productService` anywhere in your subscriber’s methods. For example:
|
||||
|
||||
```ts
|
||||
handleOrder = async (data) => {
|
||||
//...
|
||||
const product = this.productService.list()
|
||||
class OrderNotifierSubscriber {
|
||||
// ...
|
||||
handleOrder = async (data) => {
|
||||
// ...
|
||||
const product = this.productService.list()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -72,7 +72,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -93,7 +93,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -116,7 +116,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -139,7 +139,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -160,7 +160,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -181,7 +181,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -202,7 +202,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of batch job
|
||||
id // string ID of batch job
|
||||
}
|
||||
```
|
||||
|
||||
@@ -262,7 +262,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of cart
|
||||
id // string ID of cart
|
||||
}
|
||||
```
|
||||
|
||||
@@ -329,8 +329,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -354,8 +354,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -379,8 +379,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -404,9 +404,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
fulfillment_id, //string ID of the fulfillment created
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
fulfillment_id, // string ID of the fulfillment created
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -430,9 +430,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
fulfillment_id, //string ID of the fulfillment created
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
fulfillment_id, // string ID of the fulfillment created
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -456,8 +456,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of claim
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of claim
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -505,7 +505,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of claim item
|
||||
id // string ID of claim item
|
||||
}
|
||||
```
|
||||
|
||||
@@ -529,7 +529,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of claim item
|
||||
id // string ID of claim item
|
||||
}
|
||||
```
|
||||
|
||||
@@ -553,7 +553,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of claim item
|
||||
id // string ID of claim item
|
||||
}
|
||||
```
|
||||
|
||||
@@ -601,7 +601,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
code //string 3 character ISO code of the updated currency.
|
||||
code // string 3 character ISO code of the updated currency.
|
||||
}
|
||||
```
|
||||
|
||||
@@ -685,11 +685,11 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of customer
|
||||
email, //string email of the customer
|
||||
first_name, //string first name of the customer
|
||||
last_name, //string last name of the customer
|
||||
token //string reset password token
|
||||
id, // string ID of customer
|
||||
email, // string email of the customer
|
||||
first_name, // string first name of the customer
|
||||
last_name, // string last name of the customer
|
||||
token // string reset password token
|
||||
}
|
||||
```
|
||||
|
||||
@@ -737,7 +737,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of draft order
|
||||
id // string ID of draft order
|
||||
}
|
||||
```
|
||||
|
||||
@@ -761,7 +761,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of draft order
|
||||
id // string ID of draft order
|
||||
}
|
||||
```
|
||||
|
||||
@@ -858,9 +858,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of invite
|
||||
token, //string token generated to validate the invited user
|
||||
user_email //string email of invited user
|
||||
id // string ID of invite
|
||||
token, // string token generated to validate the invited user
|
||||
user_email // string email of invited user
|
||||
}
|
||||
```
|
||||
|
||||
@@ -907,7 +907,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of note
|
||||
id // string ID of note
|
||||
}
|
||||
```
|
||||
|
||||
@@ -931,7 +931,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of note
|
||||
id // string ID of note
|
||||
}
|
||||
```
|
||||
|
||||
@@ -955,7 +955,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of note
|
||||
id // string ID of note
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1070,8 +1070,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1095,8 +1095,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //(optional) boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // (optional) boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1120,8 +1120,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1145,8 +1145,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1194,7 +1194,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of order
|
||||
id // string ID of order
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1218,8 +1218,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1243,10 +1243,10 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
payment_id, //string ID of Payment
|
||||
error, //string error message
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
payment_id, // string ID of Payment
|
||||
error, // string error message
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1270,9 +1270,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1296,9 +1296,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1322,9 +1322,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1348,9 +1348,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
return_id, //string ID of return
|
||||
no_notification //(optional) boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
return_id, // string ID of return
|
||||
no_notification // (optional) boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1374,9 +1374,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
return_id, //string ID of return
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
return_id, // string ID of return
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1400,9 +1400,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
return_id, //string ID of return
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
return_id, // string ID of return
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1426,9 +1426,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of order
|
||||
refund_id, //string ID of refund
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of order
|
||||
refund_id, // string ID of refund
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1631,7 +1631,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of order edit
|
||||
id // string ID of order edit
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1712,7 +1712,7 @@ Triggered when an order edit item change is created.
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of item change
|
||||
id // string ID of item change
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1734,7 +1734,7 @@ Triggered when an order edit item change is deleted.
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of item change
|
||||
id // string ID of item change
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2027,7 +2027,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of product
|
||||
id // string ID of product
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2053,8 +2053,8 @@ In one case, when the `/admin/products/{id}` endpoint is used to update the prod
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //id of product
|
||||
fields //an array of field names that were updated
|
||||
id, // id of product
|
||||
fields // an array of field names that were updated
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2078,7 +2078,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of product
|
||||
id // string ID of product
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2126,8 +2126,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of variant
|
||||
product_id //string ID of product
|
||||
id, // string ID of variant
|
||||
product_id // string ID of product
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2151,9 +2151,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of variant
|
||||
product_id, //string ID of product
|
||||
fields //array of names of updated fields
|
||||
id, // string ID of variant
|
||||
product_id, // string ID of product
|
||||
fields // array of names of updated fields
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2177,9 +2177,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of variant
|
||||
product_id, //string ID of product
|
||||
metadata //object of the `metadata` field of the variant
|
||||
id, // string ID of variant
|
||||
product_id, // string ID of product
|
||||
metadata // object of the `metadata` field of the variant
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2239,7 +2239,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of publishable API key
|
||||
id // string ID of publishable API key
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2263,7 +2263,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of publishable API key
|
||||
id // string ID of publishable API key
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2311,7 +2311,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of region
|
||||
id // string ID of region
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2335,8 +2335,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of region
|
||||
fields //array of names of updated fields
|
||||
id, // string ID of region
|
||||
fields // array of names of updated fields
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2360,7 +2360,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of region
|
||||
id // string ID of region
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2418,7 +2418,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of sales channel
|
||||
id // string ID of sales channel
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2466,7 +2466,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of sales channel
|
||||
id // string ID of sales channel
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2513,8 +2513,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2538,9 +2538,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
order_id, //string ID of order
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
order_id, // string ID of order
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2564,9 +2564,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2590,9 +2590,9 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
fulfillment_id, //string ID of fulfillment
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
fulfillment_id, // string ID of fulfillment
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2616,8 +2616,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2641,8 +2641,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2666,8 +2666,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2691,8 +2691,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2716,8 +2716,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id, //string ID of swap
|
||||
no_notification //boolean indicating whether a notification should be sent or not
|
||||
id, // string ID of swap
|
||||
no_notification // boolean indicating whether a notification should be sent
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2816,7 +2816,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of user
|
||||
id // string ID of user
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2840,7 +2840,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of user
|
||||
id // string ID of user
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2864,8 +2864,8 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
email, //string email of user requesting to reset their password
|
||||
token //token create to reset the password
|
||||
email, // string email of user requesting to reset their password
|
||||
token // token create to reset the password
|
||||
}
|
||||
```
|
||||
|
||||
@@ -2889,7 +2889,7 @@ Object of the following format:
|
||||
|
||||
```js noReport noCopy
|
||||
{
|
||||
id //string ID of user
|
||||
id // string ID of user
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -126,7 +126,9 @@ Where `amount` is the amount of the variant’s price in the price list, `taxRat
|
||||
|
||||
Here is an example of these fields when tax inclusivity is enabled for both the currency and the price list:
|
||||
|
||||
```jsx noReport
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```js noReport
|
||||
{
|
||||
original_price: 110,
|
||||
calculated_price: 100,
|
||||
|
||||
@@ -29,7 +29,7 @@ You can, however, force calculating the taxes of the cart by passing in the thir
|
||||
For example:
|
||||
|
||||
```jsx
|
||||
cartService.retrieve('cart_01G8Z...', { }, { force_taxes: true });
|
||||
cartService.retrieve("cart_01G8Z...", { }, { force_taxes: true })
|
||||
```
|
||||
|
||||
:::tip
|
||||
@@ -45,20 +45,20 @@ Another way you can use the `CartService` to calculate taxes is using the method
|
||||
```jsx
|
||||
|
||||
export default () => {
|
||||
//...
|
||||
// ...
|
||||
|
||||
router.get("/store/line-taxes", async (req, res) => {
|
||||
//example of retrieving cart
|
||||
const cartService = req.scope.resolve("cartService");
|
||||
// example of retrieving cart
|
||||
const cartService = req.scope.resolve("cartService")
|
||||
const cart = await cartService.retrieve(cart_id)
|
||||
|
||||
//...
|
||||
//retrieve taxes of line items
|
||||
// ...
|
||||
// retrieve taxes of line items
|
||||
const data = await decorateTotals(cart, {
|
||||
force_taxes: true
|
||||
force_taxes: true,
|
||||
})
|
||||
|
||||
return res.status(200).json({ cart: data });
|
||||
return res.status(200).json({ cart: data })
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -72,7 +72,7 @@ You can calculate and retrieve taxes of line items using the `getLineItemTotals`
|
||||
```jsx
|
||||
const itemTotals = await totalsService
|
||||
.getLineItemTotals(item, cart, {
|
||||
include_tax: true
|
||||
include_tax: true,
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -35,28 +35,29 @@ If you use a `.env` file to load environment variables on your server, you need
|
||||
You can add the following code snippet at the top of the file which uses the [dotenv](https://www.npmjs.com/package/dotenv) package to load the environment variables based on the current Node environment:
|
||||
|
||||
```jsx
|
||||
const dotenv = require('dotenv')
|
||||
const dotenv = require("dotenv")
|
||||
|
||||
let ENV_FILE_NAME = '';
|
||||
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':
|
||||
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;
|
||||
ENV_FILE_NAME = ".env"
|
||||
break
|
||||
}
|
||||
|
||||
try {
|
||||
dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME });
|
||||
dotenv.config({ path: process.cwd() + "/" + ENV_FILE_NAME })
|
||||
} catch (e) {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,19 +31,19 @@ Instead of using `customerService.retrieveByEmail`, you should now use the metho
|
||||
The `customerService.retrieveRegisteredByEmail` method allows you to retrieve a registered customer by email:
|
||||
|
||||
```ts
|
||||
customerService.retrieveRegisteredByEmail("example@gmail.com");
|
||||
customerService.retrieveRegisteredByEmail("example@gmail.com")
|
||||
```
|
||||
|
||||
On the other hand, the `retrieveUnregisteredByEmail` method allows to retrieve guest customers by email:
|
||||
|
||||
```jsx
|
||||
customerService.retrieveUnregisteredByEmail("example@gmail.com");
|
||||
customerService.retrieveUnregisteredByEmail("example@gmail.com")
|
||||
```
|
||||
|
||||
To retrieve a customer by email regardless of whether they are registered or not, you can use the `customerService.list` method instead:
|
||||
|
||||
```ts
|
||||
customerService.list({
|
||||
email: "example@gmail.com"
|
||||
email: "example@gmail.com",
|
||||
})
|
||||
```
|
||||
@@ -56,13 +56,13 @@ In your loader file that creates a cron job, replace the use of `eventBus` to `j
|
||||
|
||||
```ts
|
||||
const myJob = async (container, options) => {
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService");
|
||||
const jobSchedulerService = container.resolve("jobSchedulerService")
|
||||
jobSchedulerService.create("my-job", {}, "0 0 * * *", async () => {
|
||||
//...
|
||||
});
|
||||
// ...
|
||||
})
|
||||
}
|
||||
|
||||
export default myJob;
|
||||
export default myJob
|
||||
```
|
||||
|
||||
You can learn more in the [How to Create a Scheduled Job](../scheduled-jobs/create.md) documentation.
|
||||
@@ -73,15 +73,26 @@ This version of Medusa introduces a change in how payment providers are implemen
|
||||
|
||||
Although this change is currently backwards compatible, it is recommended to change the signature of these methods to the following:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```ts
|
||||
import { PaymentContext, PaymentSessionResponse } from '@medusajs/medusa'
|
||||
import { PaymentContext, PaymentSessionResponse } from "@medusajs/medusa"
|
||||
// ...
|
||||
|
||||
async createPayment(context: PaymentContext): Promise<PaymentSessionResponse> {
|
||||
//...
|
||||
}
|
||||
class MyPaymentService extends AbstractPaymentService<TransactionBaseService> {
|
||||
// ...
|
||||
async createPayment(
|
||||
context: PaymentContext
|
||||
): Promise<PaymentSessionResponse> {
|
||||
// ...
|
||||
}
|
||||
|
||||
async updatePayment(paymentSessionData: PaymentSessionData, context: PaymentContext): Promise<PaymentSessionResponse> {
|
||||
//...
|
||||
async updatePayment(
|
||||
paymentSessionData: PaymentSessionData,
|
||||
context: PaymentContext
|
||||
): Promise<PaymentSessionResponse> {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ You can learn more about subscribers in the [Subscribers](../backend/subscribers
|
||||
Create the file `src/subscribers/claim-order.ts` with the following content:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
import { EventBusService } from "@medusajs/medusa";
|
||||
import { EventBusService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService,
|
||||
@@ -59,7 +59,7 @@ class ClaimOrderSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber;
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
If you want to add any other dependencies, you can add them to the `InjectedDependencies` type.
|
||||
@@ -77,8 +77,14 @@ You can learn more about dependency injection in [this documentation](../backend
|
||||
In the subscriber you created, add the following in the `constructor`:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
constructor({ eventBusService }: InjectedDependencies) {
|
||||
eventBusService.subscribe("order-update-token.created", this.handleRequestClaimOrder);
|
||||
class ClaimOrderSubscriber {
|
||||
constructor({ eventBusService }: InjectedDependencies) {
|
||||
eventBusService.subscribe(
|
||||
"order-update-token.created",
|
||||
this.handleRequestClaimOrder
|
||||
)
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -90,14 +96,14 @@ In the subscriber, add a new method `handleRequestClaimOrder`:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
class ClaimOrderSubscriber {
|
||||
//...
|
||||
// ...
|
||||
|
||||
handleRequestClaimOrder = async (data) {
|
||||
//TODO: handle event
|
||||
handleRequestClaimOrder = async (data) => {
|
||||
// TODO: handle event
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber;
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
The `handleRequestClaimOrder` event receives a `data` object as a parameter. This object holds the following properties:
|
||||
@@ -118,7 +124,7 @@ The page would then send a request to the server to verify that the `token` is v
|
||||
For example, you can implement this subscriber to send emails using SendGrid:
|
||||
|
||||
```ts title=src/subscribers/claim-order.ts
|
||||
import { EventBusService } from "@medusajs/medusa";
|
||||
import { EventBusService } from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService,
|
||||
@@ -126,28 +132,31 @@ type InjectedDependencies = {
|
||||
}
|
||||
|
||||
class ClaimOrderSubscriber {
|
||||
protected sendGridService: any;
|
||||
protected sendGridService: any
|
||||
|
||||
constructor({ eventBusService, sendgridService }: InjectedDependencies) {
|
||||
this.sendGridService = sendgridService;
|
||||
eventBusService.subscribe("order-update-token.created", this.handleRequestClaimOrder);
|
||||
this.sendGridService = sendgridService
|
||||
eventBusService.subscribe(
|
||||
"order-update-token.created",
|
||||
this.handleRequestClaimOrder
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
handleRequestClaimOrder = async (data) => {
|
||||
this.sendGridService.sendEmail({
|
||||
templateId: 'order-claim-confirmation',
|
||||
from: 'hello@medusajs.com',
|
||||
templateId: "order-claim-confirmation",
|
||||
from: "hello@medusajs.com",
|
||||
to: data.old_email,
|
||||
data: {
|
||||
link: `http://example-storefront.com/confirm-order-claim/${data.token}`,
|
||||
//other data...
|
||||
}
|
||||
link: `http://example.com/confirm-order-claim/${data.token}`,
|
||||
// other data...
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default ClaimOrderSubscriber;
|
||||
export default ClaimOrderSubscriber
|
||||
```
|
||||
|
||||
Notice how the `token` is passed to the storefront link as a parameter.
|
||||
|
||||
@@ -60,8 +60,8 @@ medusa.customers.create({
|
||||
last_name,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -69,19 +69,19 @@ medusa.customers.create({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password,
|
||||
first_name,
|
||||
last_name,
|
||||
})
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -112,11 +112,11 @@ You can log in a customer into your store by sending a request to the [Customer
|
||||
```ts
|
||||
medusa.auth.authenticate({
|
||||
email,
|
||||
password
|
||||
password,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -124,17 +124,17 @@ medusa.auth.authenticate({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/auth`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password
|
||||
})
|
||||
password,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -158,8 +158,8 @@ You can log out a customer by sending a request to the [Customer Logout](/api/st
|
||||
```ts
|
||||
medusa.auth.deleteSession()
|
||||
.then(() => {
|
||||
//success
|
||||
});
|
||||
// success
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -167,12 +167,12 @@ medusa.auth.deleteSession()
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/auth`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then(() => {
|
||||
//success
|
||||
});
|
||||
// success
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -197,7 +197,7 @@ You can request to reset a customer’s password by sending a request to the [Re
|
||||
|
||||
```ts
|
||||
medusa.customers.generatePasswordToken({
|
||||
email
|
||||
email,
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
@@ -212,11 +212,11 @@ medusa.customers.generatePasswordToken({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/password-token`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
email
|
||||
})
|
||||
email,
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
@@ -252,11 +252,11 @@ You can then reset the customer’s password to the new password they enter by s
|
||||
medusa.customers.resetPassword({
|
||||
email,
|
||||
password,
|
||||
token
|
||||
token,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -264,18 +264,18 @@ medusa.customers.resetPassword({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/password-reset`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password,
|
||||
token
|
||||
})
|
||||
token,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -302,11 +302,11 @@ You can edit a customer’s info using the [Update Customer](/api/store/#tag/Cus
|
||||
|
||||
```ts
|
||||
medusa.customers.update({
|
||||
first_name
|
||||
first_name,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -314,16 +314,16 @@ medusa.customers.update({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/me`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
first_name
|
||||
})
|
||||
first_name,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -365,12 +365,12 @@ medusa.customers.addresses.addAddress({
|
||||
company,
|
||||
address_2,
|
||||
province,
|
||||
metadata
|
||||
}
|
||||
metadata,
|
||||
},
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -378,8 +378,8 @@ medusa.customers.addresses.addAddress({
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/me/addresses`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
address: {
|
||||
first_name,
|
||||
@@ -392,14 +392,14 @@ fetch(`<SERVER_URL>/store/customers/me/addresses`, {
|
||||
company,
|
||||
address_2,
|
||||
province,
|
||||
metadata
|
||||
}
|
||||
})
|
||||
metadata,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -427,11 +427,11 @@ You can edit a customer’s shipping address using the [Update a Shipping Addres
|
||||
|
||||
```ts
|
||||
medusa.customers.addresses.updateAddress(addressId, {
|
||||
first_name
|
||||
first_name,
|
||||
})
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -439,16 +439,16 @@ medusa.customers.addresses.updateAddress(addressId, {
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/me/addresses/${addressId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
first_name
|
||||
})
|
||||
first_name,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -468,8 +468,8 @@ You can delete a shipping address by sending a request to the [Delete an Address
|
||||
```ts
|
||||
medusa.customers.addresses.deleteAddress(addressId)
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -477,13 +477,13 @@ medusa.customers.addresses.deleteAddress(addressId)
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/me/addresses/${addressId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ customer }) => {
|
||||
console.log(customer.id);
|
||||
});
|
||||
console.log(customer.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -505,8 +505,8 @@ You can retrieve a customer’s orders by sending a request to the [List Orders]
|
||||
```ts
|
||||
medusa.customers.listOrders()
|
||||
.then(({ orders, limit, offset, count }) => {
|
||||
console.log(orders);
|
||||
});
|
||||
console.log(orders)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -514,12 +514,12 @@ medusa.customers.listOrders()
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/customers/me/orders`, {
|
||||
credentials: 'include'
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ orders, limit, offset, count }) => {
|
||||
console.log(orders);
|
||||
});
|
||||
console.log(orders)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -78,9 +78,9 @@ You can retrieve a single order edit by its ID by sending a request to the [Get
|
||||
```ts
|
||||
medusa.orderEdits.retrieve(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
//show changed items to the customer
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
// show changed items to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -90,9 +90,9 @@ medusa.orderEdits.retrieve(orderEditId)
|
||||
fetch(`<SERVER_URL>/store/order-edits/${orderEditId}`)
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.changes);
|
||||
//show changed items to the customer
|
||||
});
|
||||
console.log(order_edit.changes)
|
||||
// show changed items to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -116,6 +116,8 @@ You can learn more about what fields to expect in the [API reference](/api/store
|
||||
|
||||
All data about changes to the original order’s items can be found in `order_edit.changes`. `changes` is an array of item changes. Each item change includes the following fields:
|
||||
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```ts
|
||||
{
|
||||
type: string,
|
||||
@@ -134,14 +136,22 @@ Here’s an example of how you can use this data to show the customer the reques
|
||||
|
||||
```jsx
|
||||
<ul>
|
||||
{orderEdit.changes.map(itemChange => (
|
||||
{orderEdit.changes.map((itemChange) => (
|
||||
<li key={itemChange.id}>
|
||||
<strong>{itemChange.line_item ? itemChange.line_item.title : itemChange.original_line_item.title}</strong>
|
||||
{itemChange.type === 'added' && <span>New Item</span>}
|
||||
{itemChange.type === 'removed' && <span>Removed Item</span>}
|
||||
{itemChange.type === 'edited' &&
|
||||
<strong>
|
||||
{
|
||||
itemChange.line_item ?
|
||||
itemChange.line_item.title :
|
||||
itemChange.original_line_item.title
|
||||
}
|
||||
</strong>
|
||||
{itemChange.type === "added" && <span>New Item</span>}
|
||||
{itemChange.type === "removed" && <span>Removed Item</span>}
|
||||
{itemChange.type === "edited" &&
|
||||
<span>
|
||||
Edited Item. Old Quantity: {itemChange.original_line_item.quantity}. New Quantity: {itemChange.line_item.quantity}
|
||||
Edited Item
|
||||
Old Quantity: {itemChange.original_line_item.quantity}
|
||||
New Quantity: {itemChange.line_item.quantity}
|
||||
</span>}
|
||||
</li>
|
||||
))}
|
||||
@@ -178,31 +188,34 @@ If `difference_due` is greater than 0, then additional payment from the customer
|
||||
|
||||
```ts
|
||||
medusa.paymentCollections.managePaymentSession(paymentCollectionId, {
|
||||
provider_id
|
||||
provider_id,
|
||||
})
|
||||
.then(({ payment_collection }) => {
|
||||
console.log(payment_collection.payment_sessions);
|
||||
});
|
||||
console.log(payment_collection.payment_sessions)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/payment-collections/${paymentCollectionId}/sessions`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
provider_id
|
||||
})
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/store/payment-collections/${paymentCollectionId}/sessions`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
provider_id,
|
||||
}),
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ payment_collection }) => {
|
||||
console.log(payment_collection.payment_sessions);
|
||||
});
|
||||
console.log(payment_collection.payment_sessions)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -215,24 +228,29 @@ fetch(`<SERVER_URL>/store/payment-collections/${paymentCollectionId}/sessions`,
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.paymentCollection.authorizePaymentSession(paymentCollectionId, paymentSessionId)
|
||||
medusa.paymentCollection
|
||||
.authorizePaymentSession(paymentCollectionId, paymentSessionId)
|
||||
.then(({ payment_session }) => {
|
||||
console.log(payment_session.id);
|
||||
});
|
||||
console.log(payment_session.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/payment-collection/${paymentCollectionId}/sessions/${paymentSessionId}/authorize`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
})
|
||||
fetch(
|
||||
`<SERVER_URL>/store/payment-collection/${paymentCollectionId}` +
|
||||
`/sessions/${paymentSessionId}/authorize`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
}
|
||||
)
|
||||
.then((response) => response.json())
|
||||
.then(({ payment_session }) => {
|
||||
console.log(payment_session.id);
|
||||
});
|
||||
console.log(payment_session.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -252,8 +270,8 @@ To confirm and complete the order edit, send a request to the [Complete Order Ed
|
||||
```ts
|
||||
medusa.orderEdits.complete(orderEditId)
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at);
|
||||
});
|
||||
console.log(order_edit.confirmed_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -261,13 +279,13 @@ medusa.orderEdits.complete(orderEditId)
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/order-edits/${orderEditId}/complete`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.confirmed_at);
|
||||
});
|
||||
console.log(order_edit.confirmed_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -296,11 +314,11 @@ If the customer wants to decline the Order Edit, you can do that by sending a re
|
||||
|
||||
```ts
|
||||
medusa.orderEdits.decline(orderEditId, {
|
||||
decline_reason: 'I am not satisfied'
|
||||
decline_reason: "I am not satisfied",
|
||||
})
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.declined_at);
|
||||
});
|
||||
console.log(order_edit.declined_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -308,19 +326,19 @@ medusa.orderEdits.decline(orderEditId, {
|
||||
|
||||
```ts
|
||||
fetch(`<SERVER_URL>/store/order-edits/${orderEditId}/decline`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
decline_reason: 'I am not satisfied'
|
||||
})
|
||||
decline_reason: "I am not satisfied",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ order_edit }) => {
|
||||
console.log(order_edit.declined_at);
|
||||
});
|
||||
console.log(order_edit.declined_at)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -64,11 +64,11 @@ medusa.carts.update(cartId, {
|
||||
country_code,
|
||||
province,
|
||||
postal_code,
|
||||
phone
|
||||
phone,
|
||||
},
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.shipping_address);
|
||||
console.log(cart.shipping_address)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -77,8 +77,8 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
shipping_address: {
|
||||
company,
|
||||
@@ -90,17 +90,17 @@ fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
country_code,
|
||||
province,
|
||||
postal_code,
|
||||
phone
|
||||
phone,
|
||||
},
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.shipping_address);
|
||||
});
|
||||
console.log(cart.shipping_address)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -124,7 +124,7 @@ You can retrieve the list of shipping options by sending a `GET` request to the
|
||||
```jsx
|
||||
medusa.shippingOptions.listCartOptions(cartId)
|
||||
.then(({ shipping_options }) => {
|
||||
console.log(shipping_options.length);
|
||||
console.log(shipping_options.length)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -133,11 +133,11 @@ medusa.shippingOptions.listCartOptions(cartId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/shipping-options/${cartId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ shipping_options }) => {
|
||||
console.log(shipping_options.length);
|
||||
console.log(shipping_options.length)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -155,7 +155,7 @@ Once the customer chooses one of the available shipping options, send a `POST` r
|
||||
|
||||
```jsx
|
||||
medusa.carts.addShippingMethod(cartId, {
|
||||
option_id: shippingOptionId //the ID of the selected option
|
||||
option_id: shippingOptionId, // the ID of the selected option
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.shipping_methods)
|
||||
@@ -167,14 +167,14 @@ medusa.carts.addShippingMethod(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/shipping-methods`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
option_id: shippingOptionId //the ID of the selected option
|
||||
option_id: shippingOptionId, // the ID of the selected option
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
@@ -216,8 +216,8 @@ medusa.carts.createPaymentSessions(cartId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/payment-sessions`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
@@ -239,7 +239,8 @@ When the customer chooses the payment provider they want to complete purchase wi
|
||||
|
||||
```jsx
|
||||
medusa.carts.setPaymentSession(cartId, {
|
||||
provider_id: paymentProviderId // retrieved from the payment session selected by the customer
|
||||
// retrieved from the payment session selected by the customer
|
||||
provider_id: paymentProviderId,
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.payment_session)
|
||||
@@ -251,14 +252,15 @@ medusa.carts.setPaymentSession(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/payment-session`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
provider_id: paymentProviderId // retrieved from the payment session selected by the customer
|
||||
// retrieved from the payment session selected by the customer
|
||||
provider_id: paymentProviderId,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
@@ -291,10 +293,10 @@ If you need to update that data at any point before the purchase is made, send a
|
||||
```jsx
|
||||
medusa.carts.updatePaymentSession(cartId, paymentProviderId, {
|
||||
data: {
|
||||
//pass any data you want to add in the `data` attribute
|
||||
//for example:
|
||||
"test": true
|
||||
}
|
||||
// pass any data you want to add in the `data` attribute
|
||||
// for example:
|
||||
"test": true,
|
||||
},
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.payment_session.data)
|
||||
@@ -304,21 +306,26 @@ medusa.carts.updatePaymentSession(cartId, paymentProviderId, {
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/payment-sessions/${paymentProviderId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
data: {
|
||||
//pass any data you want to add in the `data` attribute
|
||||
//for example:
|
||||
"test": true
|
||||
}
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
fetch(
|
||||
`<SERVER_URL>/store/carts/${cartId}/payment-sessions/${paymentProviderId}`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
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(({ cart }) => {
|
||||
console.log(cart.payment_session.data)
|
||||
@@ -344,7 +351,7 @@ To complete a cart, send a `POST` request to the [Complete a Cart](/api/store/#t
|
||||
```jsx
|
||||
medusa.carts.complete(cartId)
|
||||
.then(({ type, data }) => {
|
||||
console.log(type, data);
|
||||
console.log(type, data)
|
||||
})
|
||||
```
|
||||
|
||||
@@ -353,15 +360,15 @@ medusa.carts.complete(cartId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/complete`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ type, data }) => {
|
||||
console.log(type, data);
|
||||
console.log(type, data)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ medusa.orders.claimOrders({
|
||||
})
|
||||
.catch(() => {
|
||||
// an error occurred
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -90,23 +90,23 @@ medusa.orders.claimOrders({
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/store/orders/batch/customer/token`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
order_ids: [
|
||||
order_id,
|
||||
],
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
//successful
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
//display an error to the customer
|
||||
});
|
||||
// display an error to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -131,14 +131,14 @@ Then, you send a request to the Verify Claim Order endpoint:
|
||||
|
||||
```tsx
|
||||
medusa.orders.confirmRequest({
|
||||
token
|
||||
token,
|
||||
})
|
||||
.then(() => {
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
// an error occurred
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -146,21 +146,21 @@ medusa.orders.confirmRequest({
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/store/orders/customer/confirm`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
token
|
||||
token,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
//successful
|
||||
// successful
|
||||
})
|
||||
.catch(() => {
|
||||
//display an error to the customer
|
||||
});
|
||||
// display an error to the customer
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -58,17 +58,17 @@ You can add a discount to a customer’s cart by sending the [Update Cart reques
|
||||
medusa.carts.update(cartId, {
|
||||
discounts: [
|
||||
{
|
||||
code
|
||||
}
|
||||
]
|
||||
code,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.discounts)
|
||||
})
|
||||
.catch((e) => {
|
||||
//display an error to the customer
|
||||
alert('Discount is invalid')
|
||||
});
|
||||
// display an error to the customer
|
||||
alert("Discount is invalid")
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -76,27 +76,27 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
discounts: [
|
||||
{
|
||||
code
|
||||
}
|
||||
code,
|
||||
},
|
||||
],
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.discounts);
|
||||
console.log(cart.discounts)
|
||||
})
|
||||
.catch((e) => {
|
||||
//display an error to the customer
|
||||
alert('Discount is invalid')
|
||||
});
|
||||
// display an error to the customer
|
||||
alert("Discount is invalid")
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -222,7 +222,7 @@ You can remove a discount from a customer’s cart using the [Remove Discount re
|
||||
medusa.carts.deleteDiscount(cartId, code)
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.discounts)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -230,13 +230,13 @@ medusa.carts.deleteDiscount(cartId, code)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/discounts/${code}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include'
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.discounts);
|
||||
});
|
||||
console.log(cart.discounts)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -47,9 +47,9 @@ You can retrieve available regions by sending a request to the [List Regions](/a
|
||||
```tsx
|
||||
medusa.regions.list()
|
||||
.then(({ regions }) => {
|
||||
console.log(regions.length);
|
||||
//show customers available regions
|
||||
});
|
||||
console.log(regions.length)
|
||||
// show customers available regions
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -57,13 +57,13 @@ medusa.regions.list()
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/store/regions`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ regions }) => {
|
||||
console.log(regions.length);
|
||||
//show customers available regions
|
||||
});
|
||||
console.log(regions.length)
|
||||
// show customers available regions
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -86,12 +86,12 @@ For example:
|
||||
|
||||
```tsx
|
||||
medusa.products.list({
|
||||
region_id: regionId
|
||||
region_id: regionId,
|
||||
})
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length);
|
||||
//show customer the products
|
||||
});
|
||||
console.log(products.length)
|
||||
// show customer the products
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -99,13 +99,13 @@ medusa.products.list({
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/store/products?region_id=${regionId}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length);
|
||||
//show customer the products
|
||||
});
|
||||
console.log(products.length)
|
||||
// show customer the products
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -136,11 +136,11 @@ For example:
|
||||
|
||||
```tsx
|
||||
medusa.carts.update(cartId, {
|
||||
region_id: regionId
|
||||
region_id: regionId,
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.id);
|
||||
});
|
||||
console.log(cart.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -148,16 +148,16 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```tsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
region_id: regionId
|
||||
})
|
||||
region_id: regionId,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.id);
|
||||
});
|
||||
console.log(cart.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -39,12 +39,12 @@ To filter products by a specific sales channel, pass the `sales_channel_id` quer
|
||||
```jsx
|
||||
medusa.products.list({
|
||||
sales_channel_id: [
|
||||
salesChannelId
|
||||
]
|
||||
salesChannelId,
|
||||
],
|
||||
})
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length);
|
||||
});
|
||||
console.log(products.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -55,7 +55,7 @@ fetch(`<SERVER_URL>/store/products?sales_channel_id[0]=${salesChannelId}`)
|
||||
.then((response) => response.json())
|
||||
.then(({ products, limit, offset, count }) => {
|
||||
console.log(products.length)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -79,11 +79,11 @@ To associate a sales channel with a cart while creating it, you can pass the `sa
|
||||
|
||||
```jsx
|
||||
medusa.carts.create({
|
||||
sales_channel_id: salesChannelId
|
||||
sales_channel_id: salesChannelId,
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.id)
|
||||
})
|
||||
.then(({cart}) => {
|
||||
console.log(cart.id);
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -91,18 +91,18 @@ medusa.carts.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
sales_channel_id: salesChannelId
|
||||
})
|
||||
sales_channel_id: salesChannelId,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({cart}) => {
|
||||
console.log(cart.id);
|
||||
});
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -119,11 +119,11 @@ You can update the sales channel of an existing cart by passing the `sales_chann
|
||||
|
||||
```jsx
|
||||
medusa.carts.update(cartId, {
|
||||
sales_channel_id: salesChannelId
|
||||
sales_channel_id: salesChannelId,
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
console.log(cart.id)
|
||||
})
|
||||
.then(({cart}) => {
|
||||
console.log(cart.id);
|
||||
});
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -131,16 +131,16 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
sales_channel_id: salesChannelId
|
||||
})
|
||||
sales_channel_id: salesChannelId,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({cart}) => console.log(cart.id));
|
||||
.then(({ cart }) => console.log(cart.id))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -130,10 +130,10 @@ import TabItem from '@theme/TabItem';
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
medusa.admin.uploads.create(file) //file is an instance of File
|
||||
medusa.admin.uploads.create(file) // file is an instance of File
|
||||
.then(({ uploads }) => {
|
||||
const key = uploads[0].key;
|
||||
});
|
||||
const key = uploads[0].key
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -157,7 +157,10 @@ If you want to add a title to a code block with tabs, add the `codeTitle` prop t
|
||||
For example:
|
||||
|
||||
```md
|
||||
<Tabs groupId="request-type" wrapperClassName="code-tabs" codeTitle="/src/services/hello.ts">
|
||||
<Tabs
|
||||
groupId="request-type"
|
||||
wrapperClassName="code-tabs"
|
||||
codeTitle="/src/services/hello.ts">
|
||||
```
|
||||
|
||||
### Add Title to Code Block without Tabs
|
||||
@@ -242,7 +245,7 @@ npm install @medusajs/medusa-cli -g
|
||||
|
||||
Medusa uses Vale to lint documentation pages and perform checks on incoming PRs into the repository.
|
||||
|
||||
### Result of PR Checks
|
||||
### Result of Vale PR Checks
|
||||
|
||||
You can check the result of running the "lint" action on your PR by clicking the Details link next to it. You can find there all errors that you need to fix.
|
||||
|
||||
@@ -293,6 +296,64 @@ If you use this in your PR, you must justify its usage.
|
||||
|
||||
---
|
||||
|
||||
## Linting with ESLint
|
||||
|
||||
Medusa uses Eslint to lint code blocks in the documentation and perform checks on incoming PRs into the repository.
|
||||
|
||||
### Result of ESLint PR Checks
|
||||
|
||||
You can check the result of running the "eslint" action on your PR by clicking the Details link next to it. You can find there all errors that you need to fix.
|
||||
|
||||
### Running ESLint locally
|
||||
|
||||
If you want to check your work locally, you can do that by:
|
||||
|
||||
1. Installing the dependencies in the root directory:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
2\. Run the lint command:
|
||||
|
||||
```bash
|
||||
yarn lint:docs
|
||||
```
|
||||
|
||||
You can also pass the `--fix` option to automatically fix errors.
|
||||
|
||||
### ESLint Exceptions
|
||||
|
||||
If some code blocks have errors that can't or shouldn't be fixed, you can add the following command before the code block:
|
||||
|
||||
~~~md
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```js
|
||||
console.log("This block isn't linted")
|
||||
```
|
||||
|
||||
```js
|
||||
console.log("This block is linted")
|
||||
```
|
||||
~~~
|
||||
|
||||
You can also disable specific rules. For example:
|
||||
|
||||
~~~md
|
||||
<!-- eslint-disable semi -->
|
||||
|
||||
```js
|
||||
console.log("This block can use semicolons");
|
||||
```
|
||||
|
||||
```js
|
||||
console.log("This block can't use semi colons")
|
||||
```
|
||||
~~~
|
||||
|
||||
---
|
||||
|
||||
## Need Additional Help
|
||||
|
||||
If you need any additional help while contributing, you can join Medusa's [Discord server](https://discord.gg/medusajs) and ask Medusa’s core team as well as the community any questions.
|
||||
@@ -52,13 +52,15 @@ In `medusa-config.js`, the `DATABASE_URL` variable is set to the environment var
|
||||
Replace the previous declaration of `DATABASE_URL` in `medusa-config.js` with the following:
|
||||
|
||||
```js
|
||||
const DB_USERNAME = process.env.DB_USERNAME;
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD;
|
||||
const DB_HOST = process.env.DB_HOST;
|
||||
const DB_PORT = process.env.DB_PORT;
|
||||
const DB_DATABASE = process.env.DB_DATABASE;
|
||||
const DB_USERNAME = process.env.DB_USERNAME
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
||||
const DB_HOST = process.env.DB_HOST
|
||||
const DB_PORT = process.env.DB_PORT
|
||||
const DB_DATABASE = process.env.DB_DATABASE
|
||||
|
||||
const DATABASE_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE}`;
|
||||
const DATABASE_URL =
|
||||
`postgres://${DB_USERNAME}:${DB_PASSWORD}` +
|
||||
`@${DB_HOST}:${DB_PORT}/${DB_DATABASE}`
|
||||
```
|
||||
|
||||
In addition, you must add to `projectConfig` in the exported object a new property `database_extra`:
|
||||
@@ -66,10 +68,10 @@ In addition, you must add to `projectConfig` in the exported object a new proper
|
||||
```js
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...
|
||||
database_extra: { ssl: { rejectUnauthorized: false } }
|
||||
// ...
|
||||
database_extra: { ssl: { rejectUnauthorized: false } },
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -187,7 +187,7 @@ module.exports = {
|
||||
: {},
|
||||
},
|
||||
plugins,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### package.json
|
||||
|
||||
@@ -49,10 +49,10 @@ You can create a cart with the following code snippet:
|
||||
```jsx
|
||||
medusa.carts.create()
|
||||
.then(({ cart }) => {
|
||||
localStorage.setItem('cart_id', cart.id);
|
||||
//assuming you have a state variable to store the cart
|
||||
setCart(cart);
|
||||
});
|
||||
localStorage.setItem("cart_id", cart.id)
|
||||
// assuming you have a state variable to store the cart
|
||||
setCart(cart)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -60,15 +60,15 @@ medusa.carts.create()
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
localStorage.setItem('cart_id', cart.id);
|
||||
//assuming you have a state variable to store the cart
|
||||
localStorage.setItem("cart_id", cart.id)
|
||||
// assuming you have a state variable to store the cart
|
||||
setCart(cart)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -85,13 +85,13 @@ Otherwise, you can assign it a specific region during creation:
|
||||
|
||||
```jsx
|
||||
medusa.carts.create({
|
||||
region_id
|
||||
region_id,
|
||||
})
|
||||
.then(({ cart }) => {
|
||||
localStorage.setItem('cart_id', cart.id);
|
||||
//assuming you have a state variable to store the cart
|
||||
setCart(cart);
|
||||
});
|
||||
localStorage.setItem("cart_id", cart.id)
|
||||
// assuming you have a state variable to store the cart
|
||||
setCart(cart)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -99,21 +99,21 @@ medusa.carts.create({
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
region_id
|
||||
})
|
||||
region_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => {
|
||||
localStorage.setItem('cart_id', cart.id);
|
||||
//assuming you have a state variable to store the cart
|
||||
localStorage.setItem("cart_id", cart.id)
|
||||
// assuming you have a state variable to store the cart
|
||||
setCart(cart)
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -139,11 +139,11 @@ You can retrieve the cart at any given point using its ID with the following cod
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```jsx
|
||||
const id = localStorage.getItem('cart_id');
|
||||
const id = localStorage.getItem("cart_id")
|
||||
|
||||
if (id) {
|
||||
medusa.carts.retrieve(id)
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -151,14 +151,14 @@ if (id) {
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```jsx
|
||||
const id = localStorage.getItem('cart_id');
|
||||
const id = localStorage.getItem("cart_id")
|
||||
|
||||
if (id) {
|
||||
fetch(`<SERVER_URL>/store/carts/${id}`, {
|
||||
credentials: 'include',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -188,9 +188,9 @@ You can use the following snippet to update any of the cart’s data:
|
||||
|
||||
```jsx
|
||||
medusa.carts.update(cartId, {
|
||||
region_id
|
||||
region_id,
|
||||
})
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -198,17 +198,17 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
region_id
|
||||
})
|
||||
region_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -231,9 +231,9 @@ You can do that using the same update operation:
|
||||
|
||||
```jsx
|
||||
medusa.carts.update(cartId, {
|
||||
customer_id
|
||||
customer_id,
|
||||
})
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -241,17 +241,17 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
customer_id
|
||||
})
|
||||
customer_id,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -270,9 +270,9 @@ You can do that using the same update operation:
|
||||
|
||||
```jsx
|
||||
medusa.carts.update(cartId, {
|
||||
email: 'user@example.com'
|
||||
email: "user@example.com",
|
||||
})
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -280,17 +280,17 @@ medusa.carts.update(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: 'user@example.com'
|
||||
})
|
||||
email: "user@example.com",
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -308,9 +308,9 @@ To create a line item of a product and add it to a cart, you can use the followi
|
||||
```jsx
|
||||
medusa.carts.lineItems.create(cartId, {
|
||||
variant_id,
|
||||
quantity: 1
|
||||
quantity: 1,
|
||||
})
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -318,18 +318,18 @@ medusa.carts.lineItems.create(cartId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/line-items`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
variant_id,
|
||||
quantity: 1
|
||||
})
|
||||
quantity: 1,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -358,7 +358,7 @@ To update a line item's quantity in the cart, you can use the following code sni
|
||||
|
||||
```jsx
|
||||
medusa.carts.lineItems.update(cartId, lineItemId, {
|
||||
quantity: 3
|
||||
quantity: 3,
|
||||
})
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
@@ -368,17 +368,17 @@ medusa.carts.lineItems.update(cartId, lineItemId, {
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/line-items/${lineItemId}`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity: 3
|
||||
})
|
||||
quantity: 3,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -407,11 +407,11 @@ medusa.carts.lineItems.delete(cartId, lineItemId)
|
||||
|
||||
```jsx
|
||||
fetch(`<SERVER_URL>/store/carts/${cartId}/line-items/${lineItemId}`, {
|
||||
method: 'DELETE',
|
||||
credentials: 'include',
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ cart }) => setCart(cart));
|
||||
.then(({ cart }) => setCart(cart))
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -37,9 +37,9 @@ import Medusa from "@medusajs/medusa-js"
|
||||
|
||||
const medusa = new Medusa()
|
||||
|
||||
//use method
|
||||
// use method
|
||||
medusa.customers.create({
|
||||
//data
|
||||
// data
|
||||
})
|
||||
```
|
||||
|
||||
@@ -47,7 +47,7 @@ The `customers` resource also has another resource `addresses` nested inside it
|
||||
|
||||
```js
|
||||
medusa.customers.addresses.addAddress({
|
||||
//data
|
||||
// data
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@ In your `medusa-config.js` , you should ensure that you've configured your CORS
|
||||
|
||||
The default configuration uses the following CORS settings:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
```js title=medusa-config.js
|
||||
// CORS when consuming Medusa from admin
|
||||
const ADMIN_CORS = process.env.ADMIN_CORS || "http://localhost:7000,http://localhost:7001"
|
||||
const ADMIN_CORS = process.env.ADMIN_CORS ||
|
||||
"http://localhost:7000,http://localhost:7001"
|
||||
|
||||
// CORS to avoid issues when consuming Medusa from a client
|
||||
const STORE_CORS = process.env.STORE_CORS || "http://localhost:8000"
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
You add payment providers to your Medusa instance by adding them as plugins in `medusa-config.js`:
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
```js title=medusa-config.js
|
||||
const plugins = [
|
||||
...
|
||||
// ...
|
||||
// You can create a Stripe account via: https://stripe.com
|
||||
{
|
||||
resolve: `medusa-payment-stripe`,
|
||||
@@ -13,8 +13,7 @@ const plugins = [
|
||||
webhook_secret: STRIPE_WEBHOOK_SECRET,
|
||||
},
|
||||
},
|
||||
...
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
And installing them with your favourite package manager:
|
||||
|
||||
@@ -11,7 +11,7 @@ After installing it, make sure to configure your Medusa server to use Redis:
|
||||
```jsx title=medusa-config.js
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...
|
||||
// ...
|
||||
redis_url: REDIS_URL,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ Then in your `medusa-config.js`, you should change the project configuration to
|
||||
```jsx title=medusa-config.js
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...
|
||||
// ...
|
||||
database_url: DATABASE_URL,
|
||||
database_type: "postgres",
|
||||
},
|
||||
@@ -31,6 +31,8 @@ Where `DATABASE_URL` is the connection string to your PostgreSQL database. You c
|
||||
|
||||
Make sure to also remove the following lines that are used to configure an SQLite database:
|
||||
|
||||
<!-- eslint-skip -->
|
||||
|
||||
```jsx title=medusa-config.js
|
||||
database_type: "sqlite",
|
||||
database_database: "./medusa-db.sql",
|
||||
|
||||
@@ -47,11 +47,11 @@ For SQLite you mainly need two configurations:
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...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.
|
||||
@@ -69,12 +69,12 @@ For PostgreSQL you mainly need two configurations:
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...other configurations
|
||||
database_type: "postgres",
|
||||
database_url: DATABASE_URL,
|
||||
database_schema: process.env.DATABASE_SCHEMA //optional
|
||||
database_schema: process.env.DATABASE_SCHEMA, // optional
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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).
|
||||
@@ -109,11 +109,11 @@ These configurations are not required and can be omitted.
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...other configurations
|
||||
database_logging: true,
|
||||
database_extra: {}
|
||||
database_extra: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
@@ -125,10 +125,10 @@ Medusa uses Redis to handle the event queue, among other usages. You need to set
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
redis_url: REDIS_URL
|
||||
// ...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]`.
|
||||
@@ -164,10 +164,10 @@ Medusa uses JSON Web Token (JWT) to handle user authentication. To set the JWT s
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...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.
|
||||
@@ -195,10 +195,10 @@ This configuration is used to sign the session ID cookie. To set the cookie secr
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...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.
|
||||
@@ -239,10 +239,10 @@ To make sure your Admin dashboard can access the Medusa server’s admin endpoin
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...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`.
|
||||
@@ -268,10 +268,10 @@ To make sure your Storefront dashboard can access the Medusa server, set this co
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//...other configurations
|
||||
// ...other configurations
|
||||
store_cors: STORE_CORS,
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Where `STORE_CORS` is the URL of your storefront. By default, it’s `http://localhost:8000`.
|
||||
@@ -307,10 +307,10 @@ Aside from installing the plugin with NPM, you need to pass the plugin you insta
|
||||
```jsx
|
||||
module.exports = {
|
||||
projectConfig: {
|
||||
//previous configurations mentioned...
|
||||
// previous configurations mentioned...
|
||||
},
|
||||
plugins,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Add a Plugin Without Configuration
|
||||
@@ -319,9 +319,9 @@ To add a plugin that doesn’t need any configurations, you can simply add its n
|
||||
|
||||
```jsx
|
||||
const plugins = [
|
||||
//other plugins...
|
||||
// other plugins...
|
||||
`medusa-my-plugin`,
|
||||
];
|
||||
]
|
||||
```
|
||||
|
||||
### Add a Plugin With Configuration
|
||||
@@ -330,14 +330,14 @@ To add a plugin with configurations, you need to add an object to the `plugins`
|
||||
|
||||
```jsx
|
||||
const plugins = [
|
||||
//other plugins...
|
||||
// other plugins...
|
||||
{
|
||||
resolve: `medusa-my-plugin`,
|
||||
options: {
|
||||
apiKey: `test`
|
||||
}
|
||||
}
|
||||
];
|
||||
apiKey: `test`,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Reference in new issue
Block a user