feat(medusa, medusa-js, medusa-react): Implement Sales Channel update (#1797)

This commit is contained in:
Philip Korsholm
2022-07-06 15:44:09 +02:00
committed by GitHub
parent 263a661031
commit 9d19cc0818
19 changed files with 395 additions and 89 deletions
@@ -20,8 +20,8 @@ import productTypesRoutes from "./product-types"
import productRoutes from "./products"
import regionRoutes from "./regions"
import returnReasonRoutes from "./return-reasons"
import salesChannelRoutes from "./sales-channels"
import returnRoutes from "./returns"
import salesChannelRoutes from "./sales-channels"
import shippingOptionRoutes from "./shipping-options"
import shippingProfileRoutes from "./shipping-profiles"
import storeRoutes from "./store"
@@ -0,0 +1,48 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel"
describe("POST /admin/regions/:region_id/countries", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("test_sales_channel")
subject = await request("POST", `/admin/sales-channels/${id}`, {
payload: {
name: "amazon",
description: "This is our amazon sales channel",
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
flags: ["sales_channels"],
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("returns updated sales channel", () => {
expect(subject.body.sales_channel).toEqual({
id: IdMap.getId("test_sales_channel"),
name: "amazon",
description: "This is our amazon sales channel",
})
})
it("calls service update", () => {
expect(SalesChannelServiceMock.update).toHaveBeenCalledTimes(1)
expect(SalesChannelServiceMock.update).toHaveBeenCalledWith(
IdMap.getId("test_sales_channel"),
{
name: "amazon",
description: "This is our amazon sales channel",
}
)
})
})
})
@@ -10,7 +10,7 @@ import SalesChannelService from "../../../../services/sales-channel"
* parameters:
* - (path) id=* {string} The id of the Sales channel.
* tags:
* - Sales channel
* - Sales Channel
* responses:
* 200:
* description: OK
@@ -3,7 +3,8 @@ import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
import "reflect-metadata"
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
import { SalesChannel } from "../../../../models"
import middlewares from "../../../middlewares"
import middlewares, { transformBody } from "../../../middlewares"
import { AdminPostSalesChannelsSalesChannelReq } from "./update-sales-channel"
const route = Router()
@@ -22,14 +23,18 @@ export default (app) => {
route.post("/", (req, res) => {})
route.post("/:id", (req, res) => {})
route.post(
"/:id",
transformBody(AdminPostSalesChannelsSalesChannelReq),
middlewares.wrap(require("./update-sales-channel").default)
)
route.delete("/:id", (req, res) => {})
return app
}
export type AdminSalesChannelRes = {
export type AdminSalesChannelsRes = {
sales_channel: SalesChannel
}
@@ -42,5 +47,5 @@ export type AdminSalesChannelListRes = PaginatedResponse & {
export * from "./get-sales-channel"
// export * from './'
// export * from './'
// export * from './'
export * from "./update-sales-channel"
// export * from './'
@@ -0,0 +1,64 @@
import { IsBoolean, IsOptional, IsString } from "class-validator"
import { Request, Response } from "express"
import { SalesChannelService } from "../../../../services"
/**
* @oas [post] /sales-channels/{id}
* operationId: "PostSalesChannelsSalesChannel"
* summary: "Update a Sales Channel"
* description: "Updates a Sales Channel."
* x-authenticated: true
* parameters:
* - (path) id=* {string} The id of the Sales Channel.
* requestBody:
* content:
* application/json:
* schema:
* properties:
* name:
* type: string
* description: Name of the sales channel.
* description:
* type: string
* description: Sales Channel description.
* is_disabled:
* type: boolean
* description: Indication of if the sales channel is active.
* tags:
* - Sales Channel
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* customer:
* $ref: "#/components/schemas/sales-channel"
*/
export default async (req: Request, res: Response) => {
const { id } = req.params
const { validatedBody } = req as {
validatedBody: AdminPostSalesChannelsSalesChannelReq
}
const salesChannelService: SalesChannelService = req.scope.resolve(
"salesChannelService"
)
const sales_channel = await salesChannelService.update(id, validatedBody)
res.status(200).json({ sales_channel })
}
export class AdminPostSalesChannelsSalesChannelReq {
@IsOptional()
@IsString()
name?: string
@IsOptional()
@IsString()
description?: string
@IsBoolean()
@IsOptional()
is_disabled?: boolean
}
@@ -16,9 +16,6 @@ export class SalesChannel extends SoftDeletableEntity {
@Column({ default: false })
is_disabled: boolean
// @Column({ type: resolveDbType("timestamptz"), nullable: true })
// disabled_at: Date | null
@BeforeInsert()
private beforeInsert(): void {
this.id = generateEntityId(this.id, "sc")
@@ -11,6 +11,15 @@ export const SalesChannelServiceMock = {
is_disabled: false,
})
}),
update: jest.fn().mockImplementation((id, data) => {
return Promise.resolve({ id, ...data })
}),
listAndCount: jest.fn().mockImplementation(() => {}),
create: jest.fn().mockImplementation(() => {}),
delete: jest.fn().mockImplementation(() => {}),
}
const mock = jest.fn().mockImplementation(() => {
@@ -5,53 +5,91 @@ import { EventBusService } from "../index"
import { FindConditions, FindOneOptions } from "typeorm"
import { SalesChannel } from "../../models"
describe('SalesChannelService', () => {
describe("SalesChannelService", () => {
const salesChannelData = {
name: "sales channel 1 name",
description: "sales channel 1 description",
is_disabled: false,
}
const salesChannelRepositoryMock = MockRepository({
findOne: jest
.fn()
.mockImplementation(
(queryOrId: string | FindOneOptions<SalesChannel>): any => {
return Promise.resolve({
id:
typeof queryOrId === "string"
? queryOrId
: (queryOrId?.where as FindConditions<SalesChannel>)?.id ??
IdMap.getId("sc_adjhlukiaeswhfae"),
...salesChannelData,
})
}
),
save: (salesChannel) => Promise.resolve(salesChannel),
})
describe("retrieve", () => {
const salesChannelData = {
name: "sales channel 1 name",
description: "sales channel 1 description",
is_disabled: false,
}
const salesChannelRepositoryMock = MockRepository({
findOne: jest.fn().mockImplementation((queryOrId: string | FindOneOptions<SalesChannel>): any => {
return Promise.resolve({
id:
typeof queryOrId === "string"
? queryOrId
: ((queryOrId?.where as FindConditions<SalesChannel>)?.id ?? IdMap.getId("sc_adjhlukiaeswhfae")),
...salesChannelData
})
}),
})
const salesChannelService = new SalesChannelService({
manager: MockManager,
eventBusService: EventBusServiceMock as unknown as EventBusService,
salesChannelRepository: salesChannelRepositoryMock
salesChannelRepository: salesChannelRepositoryMock,
})
afterEach(() => {
jest.clearAllMocks()
})
it('should retrieve a sales channel', async () => {
it("should retrieve a sales channel", async () => {
const salesChannel = await salesChannelService.retrieve(
IdMap.getId("sales_channel_1")
)
expect(salesChannel).toBeTruthy()
expect(salesChannel).toEqual({
id: IdMap.getId("sales_channel_1"),
...salesChannelData
id: IdMap.getId("sales_channel_1"),
...salesChannelData,
})
expect(salesChannelRepositoryMock.findOne)
.toHaveBeenCalledTimes(1)
expect(salesChannelRepositoryMock.findOne)
.toHaveBeenLastCalledWith(
{ where: { id: IdMap.getId("sales_channel_1") } },
)
expect(salesChannelRepositoryMock.findOne).toHaveBeenCalledTimes(1)
expect(salesChannelRepositoryMock.findOne).toHaveBeenLastCalledWith({
where: { id: IdMap.getId("sales_channel_1") },
})
})
})
describe("update", () => {
const salesChannelService = new SalesChannelService({
manager: MockManager,
eventBusService: EventBusServiceMock as unknown as EventBusService,
salesChannelRepository: salesChannelRepositoryMock,
})
const update = {
name: "updated name",
description: "updated description",
is_disabled: true,
}
beforeAll(async () => {
jest.clearAllMocks()
})
it("calls save with the updated sales channel", async () => {
await salesChannelService.update(IdMap.getId("sc"), update)
expect(salesChannelRepositoryMock.save).toHaveBeenCalledWith({
id: IdMap.getId("sc"),
...update,
})
})
it("returns the saved sales channel", async () => {
const res = await salesChannelService.update(IdMap.getId("sc"), update)
expect(res).toEqual({
id: IdMap.getId("sc"),
...update,
})
})
})
})
+1
View File
@@ -30,6 +30,7 @@ export { default as QueryBuilderService } from "./query-builder"
export { default as RegionService } from "./region"
export { default as ReturnReasonService } from "./return-reason"
export { default as ReturnService } from "./return"
export { default as SalesChannelService } from "./sales-channel"
export { default as SearchService } from "./search"
export { default as ShippingOptionService } from "./shipping-option"
export { default as ShippingProfileService } from "./shipping-profile"
+29 -4
View File
@@ -1,4 +1,5 @@
import { EntityManager } from "typeorm"
import { MedusaError } from "medusa-core-utils"
import { TransactionBaseService } from "../interfaces"
import { SalesChannel } from "../models"
import { SalesChannelRepository } from "../repositories/sales-channel"
@@ -9,7 +10,6 @@ import {
} from "../types/sales-channels"
import EventBusService from "./event-bus"
import { buildQuery } from "../utils"
import { MedusaError } from "medusa-core-utils"
type InjectedDependencies = {
salesChannelRepository: typeof SalesChannelRepository
@@ -18,6 +18,10 @@ type InjectedDependencies = {
}
class SalesChannelService extends TransactionBaseService<SalesChannelService> {
static Events = {
UPDATED: "sales_channel.updated",
}
protected manager_: EntityManager
protected transactionManager_: EntityManager | undefined
@@ -78,10 +82,31 @@ class SalesChannelService extends TransactionBaseService<SalesChannelService> {
}
async update(
id: string,
salesChannelId: string,
data: UpdateSalesChannelInput
): Promise<SalesChannel> {
throw new Error("Method not implemented.")
): Promise<SalesChannel | never> {
return await this.atomicPhase_(async (transactionManager) => {
const salesChannelRepo: SalesChannelRepository =
transactionManager.getCustomRepository(this.salesChannelRepository_)
const salesChannel = await this.retrieve(salesChannelId)
for (const key of Object.keys(data)) {
if (typeof data[key] !== `undefined`) {
salesChannel[key] = data[key]
}
}
const result = await salesChannelRepo.save(salesChannel)
await this.eventBusService_
.withTransaction(transactionManager)
.emit(SalesChannelService.Events.UPDATED, {
id: result.id,
})
return result
})
}
async delete(id: string): Promise<void> {