feat(medusa, medusa-js, medusa-react): Implement Sales Channel deletion (#1804)
This commit is contained in:
committed by
GitHub
parent
4d15e01c3e
commit
2d03634cfc
@@ -1,5 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`sales channels DELETE /admin/sales-channels/:id should delete the requested sales channel 1`] = `
|
||||
Object {
|
||||
"deleted": true,
|
||||
"id": Any<String>,
|
||||
"object": "sales-channel",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`sales channels GET /admin/sales-channels/:id should retrieve the requested sales channel 1`] = `
|
||||
Object {
|
||||
"created_at": Any<String>,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const path = require("path")
|
||||
const { SalesChannel } = require("@medusajs/medusa")
|
||||
|
||||
const { useApi } = require("../../../helpers/use-api")
|
||||
const { useDb } = require("../../../helpers/use-db")
|
||||
@@ -15,7 +16,7 @@ const adminReqConfig = {
|
||||
},
|
||||
}
|
||||
|
||||
jest.setTimeout(30000)
|
||||
jest.setTimeout(50000)
|
||||
|
||||
describe("sales channels", () => {
|
||||
let medusaProcess
|
||||
@@ -173,5 +174,109 @@ describe("sales channels", () => {
|
||||
|
||||
describe("GET /admin/sales-channels/:id", () => {})
|
||||
describe("POST /admin/sales-channels/:id", () => {})
|
||||
describe("DELETE /admin/sales-channels/:id", () => {})
|
||||
|
||||
describe("DELETE /admin/sales-channels/:id", () => {
|
||||
let salesChannel
|
||||
|
||||
beforeEach(async() => {
|
||||
try {
|
||||
await adminSeeder(dbConnection)
|
||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
||||
name: "test name",
|
||||
description: "test description",
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("should delete the requested sales channel", async() => {
|
||||
const api = useApi()
|
||||
|
||||
let deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
||||
where: { id: salesChannel.id },
|
||||
withDeleted: true
|
||||
})
|
||||
|
||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
||||
expect(deletedSalesChannel.deleted_at).toEqual(null)
|
||||
|
||||
const response = await api.delete(
|
||||
`/admin/sales-channels/${salesChannel.id}`,
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toMatchSnapshot({
|
||||
deleted: true,
|
||||
id: expect.any(String),
|
||||
object: "sales-channel",
|
||||
})
|
||||
|
||||
deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
||||
where: { id: salesChannel.id },
|
||||
withDeleted: true
|
||||
})
|
||||
|
||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
||||
expect(deletedSalesChannel.deleted_at).not.toEqual(null)
|
||||
})
|
||||
|
||||
it("should delete the requested sales channel idempotently", async() => {
|
||||
const api = useApi()
|
||||
|
||||
let deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
||||
where: { id: salesChannel.id },
|
||||
withDeleted: true
|
||||
})
|
||||
|
||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
||||
expect(deletedSalesChannel.deleted_at).toEqual(null)
|
||||
|
||||
let response = await api.delete(
|
||||
`/admin/sales-channels/${salesChannel.id}`,
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toEqual({
|
||||
id: expect.any(String),
|
||||
object: "sales-channel",
|
||||
deleted: true
|
||||
})
|
||||
|
||||
deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
||||
where: { id: salesChannel.id },
|
||||
withDeleted: true
|
||||
})
|
||||
|
||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
||||
expect(deletedSalesChannel.deleted_at).not.toEqual(null)
|
||||
|
||||
response = await api.delete(
|
||||
`/admin/sales-channels/${salesChannel.id}`,
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toEqual({
|
||||
id: expect.any(String),
|
||||
object: "sales-channel",
|
||||
deleted: true
|
||||
})
|
||||
|
||||
deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
||||
where: { id: salesChannel.id },
|
||||
withDeleted: true
|
||||
})
|
||||
|
||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
||||
expect(deletedSalesChannel.deleted_at).not.toEqual(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
AdminPostSalesChannelsReq,
|
||||
AdminSalesChannelsRes,
|
||||
AdminPostSalesChannelsSalesChannelReq,
|
||||
AdminSalesChannelsDeleteRes,
|
||||
} from "@medusajs/medusa"
|
||||
import { ResponsePromise } from "../../typings"
|
||||
import BaseResource from "../base"
|
||||
@@ -48,17 +49,26 @@ class AdminSalesChannelsResource extends BaseResource {
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
/* delete(
|
||||
id: string,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<any> {
|
||||
}*/
|
||||
|
||||
/* list(
|
||||
query?: any,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<any> {
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Delete a sales channel
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `sales_channels` in your medusa backend project.
|
||||
* @description gets a sales channel
|
||||
* @returns an deletion result
|
||||
*/
|
||||
delete(
|
||||
salesChannelId: string,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminSalesChannelsDeleteRes> {
|
||||
const path = `/admin/sales-channels/${salesChannelId}`
|
||||
return this.client.request("DELETE", path, {}, {}, customHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminSalesChannelsResource
|
||||
|
||||
@@ -869,7 +869,7 @@ export const adminHandlers = [
|
||||
discount_condition: {
|
||||
...fixtures
|
||||
.get("discount")
|
||||
.rule.conditions.find((c) => c.id === req.params.conditionId),
|
||||
.rule.conditions.find(c => c.id === req.params.conditionId),
|
||||
},
|
||||
})
|
||||
)
|
||||
@@ -1703,4 +1703,15 @@ export const adminHandlers = [
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.delete("/admin/sales-channels/:id", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
id: req.params.id,
|
||||
object: "sales-channel",
|
||||
deleted: true,
|
||||
})
|
||||
)
|
||||
}),
|
||||
]
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
AdminPostSalesChannelsReq,
|
||||
AdminSalesChannelsRes,
|
||||
AdminPostSalesChannelsSalesChannelReq,
|
||||
AdminSalesChannelsDeleteRes,
|
||||
} from "@medusajs/medusa"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from "react-query"
|
||||
@@ -59,3 +60,30 @@ export const useAdminUpdateSalesChannel = (
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a sales channel
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `sales_channels` in your medusa backend project.
|
||||
* @param id
|
||||
* @param options
|
||||
*/
|
||||
export const useAdminDeleteSalesChannel = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminSalesChannelsDeleteRes>,
|
||||
Error,
|
||||
void
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation(
|
||||
() => client.admin.salesChannels.delete(id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[adminSalesChannelsKeys.lists(), adminSalesChannelsKeys.detail(id)],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
|
||||
import { useAdminCreateSalesChannel, useAdminUpdateSalesChannel } from "../../../../src"
|
||||
import {
|
||||
useAdminDeleteSalesChannel,
|
||||
useAdminCreateSalesChannel,
|
||||
useAdminUpdateSalesChannel,
|
||||
} from "../../../../src"
|
||||
import { fixtures } from "../../../../mocks/data"
|
||||
import { createWrapper } from "../../../utils"
|
||||
|
||||
@@ -30,7 +34,7 @@ describe("useAdminCreateSalesChannel hook", () => {
|
||||
})
|
||||
|
||||
describe("useAdminUpdateSalesChannel hook", () => {
|
||||
test("updates a store", async () => {
|
||||
test("updates a sales channel", async () => {
|
||||
const salesChannel = {
|
||||
name: "medusa sales channel",
|
||||
description: "main sales channel for medusa",
|
||||
@@ -57,3 +61,26 @@ describe("useAdminUpdateSalesChannel hook", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminDeleteSalesChannel hook", () => {
|
||||
test("deletes a sales channel", async () => {
|
||||
const id = fixtures.get("sales_channel").id
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminDeleteSalesChannel(id),
|
||||
{ wrapper: createWrapper() }
|
||||
)
|
||||
|
||||
result.current.mutate()
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data).toEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
object: "sales-channel",
|
||||
deleted: true,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { IdMap } from "medusa-test-utils"
|
||||
import { request } from "../../../../../helpers/test-request"
|
||||
import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel"
|
||||
|
||||
describe("DELETE /admin/sales-channels/:id", () => {
|
||||
describe("successfully delete a sales channel", () => {
|
||||
let subject
|
||||
|
||||
beforeAll(async () => {
|
||||
subject = await request(
|
||||
"DELETE",
|
||||
`/admin/sales-channels/${IdMap.getId("sales_channel_1")}`,
|
||||
{
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: IdMap.getId("admin_user"),
|
||||
},
|
||||
},
|
||||
flags: ["sales_channels"],
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("calls the delete method from the sales channel service", () => {
|
||||
expect(SalesChannelServiceMock.delete).toHaveBeenCalledTimes(1)
|
||||
expect(SalesChannelServiceMock.delete).toHaveBeenCalledWith(
|
||||
IdMap.getId("sales_channel_1"),
|
||||
)
|
||||
})
|
||||
|
||||
it("returns the expected result", () => {
|
||||
expect(subject.body).toEqual({
|
||||
id: IdMap.getId("sales_channel_1"),
|
||||
object: "sales-channel",
|
||||
deleted: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Request, Response } from "express"
|
||||
import { SalesChannelService } from "../../../../services/"
|
||||
|
||||
/**
|
||||
* @oas [delete] /sales-channels/{id}
|
||||
* operationId: "DeleteSalesChannelsSalesChannel"
|
||||
* summary: "Delete a sales channel"
|
||||
* description: "Deletes the sales channel."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Sales channel.
|
||||
* tags:
|
||||
* - Sales Channel
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: The id of the deleted Sales Channel.
|
||||
* object:
|
||||
* type: string
|
||||
* description: The type of the object that was deleted.
|
||||
* deleted:
|
||||
* type: boolean
|
||||
*/
|
||||
export default async (req: Request, res: Response): Promise<void> => {
|
||||
const { id } = req.params
|
||||
|
||||
const salesChannelService: SalesChannelService = req.scope.resolve(
|
||||
"salesChannelService"
|
||||
)
|
||||
await salesChannelService.delete(id)
|
||||
res.json({
|
||||
id,
|
||||
object: "sales-channel",
|
||||
deleted: true,
|
||||
})
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Request, Response } from "express"
|
||||
import SalesChannelService from "../../../../services/sales-channel"
|
||||
import { SalesChannelService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [get] /sales-channels/{id}
|
||||
|
||||
@@ -19,6 +19,10 @@ export default (app) => {
|
||||
"/",
|
||||
middlewares.wrap(require("./get-sales-channel").default)
|
||||
)
|
||||
salesChannelRouter.delete(
|
||||
"/",
|
||||
middlewares.wrap(require("./delete-sales-channel").default)
|
||||
)
|
||||
|
||||
route.get("/", (req, res) => {})
|
||||
|
||||
@@ -34,7 +38,7 @@ export default (app) => {
|
||||
middlewares.wrap(require("./update-sales-channel").default)
|
||||
)
|
||||
|
||||
route.delete("/:id", (req, res) => {})
|
||||
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -43,7 +47,7 @@ export type AdminSalesChannelsRes = {
|
||||
sales_channel: SalesChannel
|
||||
}
|
||||
|
||||
export type AdminSalesChannelDeleteRes = DeleteResponse
|
||||
export type AdminSalesChannelsDeleteRes = DeleteResponse
|
||||
|
||||
export type AdminSalesChannelListRes = PaginatedResponse & {
|
||||
sales_channels: SalesChannel[]
|
||||
|
||||
@@ -17,14 +17,16 @@ export const SalesChannelServiceMock = {
|
||||
|
||||
listAndCount: jest.fn().mockImplementation(() => {}),
|
||||
|
||||
delete: jest.fn().mockImplementation(() => {}),
|
||||
|
||||
create: jest.fn().mockImplementation((data) => {
|
||||
return Promise.resolve({
|
||||
id: id,
|
||||
...data,
|
||||
})
|
||||
}),
|
||||
|
||||
delete: jest.fn().mockImplementation((id, config) => {
|
||||
return Promise.resolve()
|
||||
}),
|
||||
}
|
||||
|
||||
const mock = jest.fn().mockImplementation(() => {
|
||||
|
||||
@@ -28,6 +28,9 @@ describe("SalesChannelService", () => {
|
||||
}
|
||||
),
|
||||
save: (salesChannel) => Promise.resolve(salesChannel),
|
||||
softRemove: jest.fn().mockImplementation((id: string): any => {
|
||||
return Promise.resolve()
|
||||
}),
|
||||
})
|
||||
|
||||
describe("retrieve", () => {
|
||||
@@ -37,7 +40,7 @@ describe("SalesChannelService", () => {
|
||||
salesChannelRepository: salesChannelRepositoryMock,
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
@@ -92,4 +95,40 @@ describe("SalesChannelService", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("delete", () => {
|
||||
const salesChannelService = new SalesChannelService({
|
||||
manager: MockManager,
|
||||
eventBusService: EventBusServiceMock as unknown as EventBusService,
|
||||
salesChannelRepository: salesChannelRepositoryMock
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should soft remove a sales channel', async () => {
|
||||
const res = await salesChannelService.delete(
|
||||
IdMap.getId("sales_channel_1")
|
||||
)
|
||||
|
||||
expect(res).toBeUndefined()
|
||||
|
||||
expect(salesChannelRepositoryMock.softRemove)
|
||||
.toHaveBeenCalledTimes(1)
|
||||
expect(salesChannelRepositoryMock.softRemove)
|
||||
.toHaveBeenLastCalledWith({
|
||||
id: IdMap.getId("sales_channel_1"),
|
||||
...salesChannelData
|
||||
})
|
||||
|
||||
expect(EventBusServiceMock.emit)
|
||||
.toHaveBeenCalledTimes(1)
|
||||
expect(EventBusServiceMock.emit)
|
||||
.toHaveBeenLastCalledWith(
|
||||
SalesChannelService.Events.DELETED,
|
||||
{ "id": IdMap.getId("sales_channel_1") }
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -23,6 +23,7 @@ class SalesChannelService extends TransactionBaseService<SalesChannelService> {
|
||||
static Events = {
|
||||
UPDATED: "sales_channel.updated",
|
||||
CREATED: "sales_channel.created",
|
||||
DELETED: "sales_channel.deleted",
|
||||
}
|
||||
|
||||
protected manager_: EntityManager
|
||||
@@ -55,8 +56,8 @@ class SalesChannelService extends TransactionBaseService<SalesChannelService> {
|
||||
salesChannelId: string,
|
||||
config: FindConfig<SalesChannel> = {}
|
||||
): Promise<SalesChannel | never> {
|
||||
return await this.atomicPhase_(async (manager) => {
|
||||
const salesChannelRepo = manager.getCustomRepository(
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const salesChannelRepo = transactionManager.getCustomRepository(
|
||||
this.salesChannelRepository_
|
||||
)
|
||||
|
||||
@@ -139,8 +140,35 @@ class SalesChannelService extends TransactionBaseService<SalesChannelService> {
|
||||
})
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
throw new Error("Method not implemented.")
|
||||
/**
|
||||
* Deletes a sales channel from
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable the corresponding feature flag in your medusa backend project.
|
||||
* @param salesChannelId - the id of the sales channel to delete
|
||||
* @return Promise<void>
|
||||
*/
|
||||
async delete(salesChannelId: string): Promise<void> {
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const salesChannelRepo = transactionManager.getCustomRepository(
|
||||
this.salesChannelRepository_
|
||||
)
|
||||
|
||||
const salesChannel = await this.retrieve(salesChannelId).catch(
|
||||
() => void 0
|
||||
)
|
||||
|
||||
if (!salesChannel) {
|
||||
return
|
||||
}
|
||||
|
||||
await salesChannelRepo.softRemove(salesChannel)
|
||||
|
||||
await this.eventBusService_
|
||||
.withTransaction(transactionManager)
|
||||
.emit(SalesChannelService.Events.DELETED, {
|
||||
id: salesChannelId,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user