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:
Shahed Nasser authored and GitHub committed 2022-12-30 18:44:46 +02:00
1 parent 99add15fc3
commit d1b4b11ff6
67 files changed
+2611 -1735

No files matched your search

@@ -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
}
}
```
+38 -27
View File
@@ -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.
+20 -19
View File
@@ -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> {
// ...
}
}
```