From b80124d32d950790c2a01b49e8c34d562b1d57f4 Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Thu, 12 Jan 2023 15:47:18 +0100 Subject: [PATCH] feat(medusa): Allow custom created_by on order edits (#3007) --- .changeset/sixty-turkeys-deliver.md | 5 +++ .../__tests__/cancel-order-edit.ts | 2 +- .../__tests__/confirm-order-edit.ts | 2 +- .../__tests__/create-order-edit.ts | 4 +- .../__tests__/request-confirmation.ts | 2 +- .../admin/order-edits/cancel-order-edit.ts | 6 +-- .../admin/order-edits/confirm-order-edit.ts | 6 +-- .../admin/order-edits/create-order-edit.ts | 14 +++--- .../admin/order-edits/request-confirmation.ts | 10 ++--- .../store/order-edits/complete-order-edit.ts | 8 ++-- .../store/order-edits/decline-order-edit.ts | 4 +- packages/medusa/src/models/order-edit.ts | 10 ++--- .../src/services/__tests__/order-edit.ts | 34 +++++++------- packages/medusa/src/services/order-edit.ts | 44 +++++++++---------- 14 files changed, 80 insertions(+), 71 deletions(-) create mode 100644 .changeset/sixty-turkeys-deliver.md diff --git a/.changeset/sixty-turkeys-deliver.md b/.changeset/sixty-turkeys-deliver.md new file mode 100644 index 0000000000..873261101d --- /dev/null +++ b/.changeset/sixty-turkeys-deliver.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +feat(medusa): Allow custom created_by on order edits diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts index f9336fee66..d1686d5220 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts @@ -30,7 +30,7 @@ describe("POST /admin/order-edits/:id/cancel", () => { it("calls orderService cancel", () => { expect(orderEditServiceMock.cancel).toHaveBeenCalledTimes(1) expect(orderEditServiceMock.cancel).toHaveBeenCalledWith(orderEditId, { - loggedInUserId: IdMap.getId("admin_user"), + canceledBy: IdMap.getId("admin_user"), }) }) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts index 12d253398e..4dff0fb902 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts @@ -30,7 +30,7 @@ describe("POST /admin/order-edits/:id/confirm", () => { it("calls orderService confirm", () => { expect(orderEditServiceMock.confirm).toHaveBeenCalledTimes(1) expect(orderEditServiceMock.confirm).toHaveBeenCalledWith(orderEditId, { - loggedInUserId: "admin_user", + confirmedBy: "admin_user", }) }) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts index f6ff218874..49bd87c35b 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts @@ -1,7 +1,7 @@ import { IdMap } from "medusa-test-utils" import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" import OrderEditingFeatureFlag from "../../../../../loaders/feature-flags/order-editing" +import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" describe("POST /admin/order-edits", () => { describe("successfully create an order edit", () => { @@ -41,7 +41,7 @@ describe("POST /admin/order-edits", () => { internal_note: internalNote, }, { - loggedInUserId: IdMap.getId("admin_user"), + createdBy: IdMap.getId("admin_user"), } ) }) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts index 6d93bdef5d..19a5858201 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts @@ -35,7 +35,7 @@ describe("GET /admin/order-edits/:id", () => { expect(orderEditServiceMock.requestConfirmation).toHaveBeenCalledTimes(1) expect(orderEditServiceMock.requestConfirmation).toHaveBeenCalledWith( orderEditId, - { loggedInUserId: IdMap.getId("admin_user") } + { requestedBy: IdMap.getId("admin_user") } ) expect(orderEditServiceMock.update).toHaveBeenCalledTimes(1) diff --git a/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts index b6a917cf00..7c15d6f25c 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts @@ -1,9 +1,9 @@ import { Request, Response } from "express" -import { OrderEditService } from "../../../../services" import { EntityManager } from "typeorm" +import { OrderEditService } from "../../../../services" import { defaultOrderEditFields, - defaultOrderEditRelations, + defaultOrderEditRelations } from "../../../../types/order-edit" /** @@ -68,7 +68,7 @@ export default async (req: Request, res: Response) => { await manager.transaction(async (transactionManager) => { await orderEditService .withTransaction(transactionManager) - .cancel(id, { loggedInUserId: userId }) + .cancel(id, { canceledBy: userId }) }) const orderEdit = await orderEditService.retrieve(id, { diff --git a/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts index dda908f0e5..3a396705f9 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts @@ -1,9 +1,9 @@ import { Request, Response } from "express" -import { OrderEditService } from "../../../../services" import { EntityManager } from "typeorm" +import { OrderEditService } from "../../../../services" import { defaultOrderEditFields, - defaultOrderEditRelations, + defaultOrderEditRelations } from "../../../../types/order-edit" /** @@ -68,7 +68,7 @@ export default async (req: Request, res: Response) => { await manager.transaction(async (transactionManager) => { await orderEditService .withTransaction(transactionManager) - .confirm(id, { loggedInUserId: userId }) + .confirm(id, { confirmedBy: userId }) }) let orderEdit = await orderEditService.retrieve(id, { diff --git a/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts index adc9a58af1..4dec310bc8 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts @@ -1,10 +1,10 @@ -import { Request, Response } from "express" -import { OrderEditService } from "../../../../services" import { IsOptional, IsString } from "class-validator" +import { Request, Response } from "express" import { EntityManager } from "typeorm" +import { OrderEditService } from "../../../../services" import { defaultOrderEditFields, - defaultOrderEditRelations, + defaultOrderEditRelations } from "../../../../types/order-edit" /** @@ -71,13 +71,13 @@ export default async (req: Request, res: Response) => { const manager = req.scope.resolve("manager") as EntityManager const data = req.validatedBody as AdminPostOrderEditsReq - const loggedInUserId = (req.user?.id ?? req.user?.userId) as string + const createdBy = (req.user?.id ?? req.user?.userId) as string const createdOrderEdit = await manager.transaction( async (transactionManager) => { return await orderEditService .withTransaction(transactionManager) - .create(data, { loggedInUserId }) + .create(data, { createdBy }) } ) @@ -110,4 +110,8 @@ export class AdminPostOrderEditsReq { @IsOptional() @IsString() internal_note?: string + + @IsOptional() + @IsString() + created_by?: string } diff --git a/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts b/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts index d6179150ee..5d23872dc9 100644 --- a/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts +++ b/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts @@ -1,15 +1,15 @@ -import { EntityManager } from "typeorm" import { IsOptional, IsString } from "class-validator" +import { EntityManager } from "typeorm" +import { PaymentCollectionType } from "../../../../models" import { OrderEditService, OrderService, - PaymentCollectionService, + PaymentCollectionService } from "../../../../services" import { defaultOrderEditFields, - defaultOrderEditRelations, + defaultOrderEditRelations } from "../../../../types/order-edit" -import { PaymentCollectionType } from "../../../../models" /** * @oas [post] /order-edits/{id}/request @@ -82,7 +82,7 @@ export default async (req, res) => { orderEditService.withTransaction(transactionManager) const orderEdit = await orderEditServiceTx.requestConfirmation(id, { - loggedInUserId: loggedInUser, + requestedBy: loggedInUser, }) const total = await orderEditServiceTx.getTotals(orderEdit.id) diff --git a/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts index 3c8f723d4b..4711e1ef61 100644 --- a/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts +++ b/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts @@ -1,12 +1,12 @@ import { Request, Response } from "express" +import { MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" +import { OrderEditStatus, PaymentCollectionStatus } from "../../../../models" import { OrderEditService, PaymentProviderService } from "../../../../services" import { defaultStoreOrderEditFields, - defaultStoreOrderEditRelations, + defaultStoreOrderEditRelations } from "../../../../types/order-edit" -import { OrderEditStatus, PaymentCollectionStatus } from "../../../../models" -import { MedusaError } from "medusa-core-utils" /** * @oas [post] /order-edits/{id}/complete @@ -111,7 +111,7 @@ export default async (req: Request, res: Response) => { } const returned = await orderEditServiceTx.confirm(id, { - loggedInUserId: userId, + confirmedBy: userId, }) return returned diff --git a/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts index 7dc4d689ec..878155e810 100644 --- a/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts +++ b/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts @@ -4,7 +4,7 @@ import { EntityManager } from "typeorm" import { OrderEditService } from "../../../../services" import { defaultStoreOrderEditFields, - defaultStoreOrderEditRelations, + defaultStoreOrderEditRelations } from "../../../../types/order-edit" /** @@ -70,7 +70,7 @@ export default async (req: Request, res: Response) => { await manager.transaction(async (manager) => { await orderEditService.withTransaction(manager).decline(id, { declinedReason: validatedBody.declined_reason, - loggedInUserId: userId, + declinedBy: userId, }) }) diff --git a/packages/medusa/src/models/order-edit.ts b/packages/medusa/src/models/order-edit.ts index 5a05006a87..3cc3dea8d2 100644 --- a/packages/medusa/src/models/order-edit.ts +++ b/packages/medusa/src/models/order-edit.ts @@ -6,14 +6,14 @@ import { JoinColumn, ManyToOne, OneToMany, - OneToOne, + OneToOne } from "typeorm" -import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing" -import { FeatureFlagEntity } from "../utils/feature-flag-decorators" -import { resolveDbType } from "../utils/db-aware-column" import { BaseEntity } from "../interfaces" +import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing" import { generateEntityId } from "../utils" +import { resolveDbType } from "../utils/db-aware-column" +import { FeatureFlagEntity } from "../utils/feature-flag-decorators" import { LineItem, Order, OrderItemChange, PaymentCollection } from "." @@ -44,7 +44,7 @@ export class OrderEdit extends BaseEntity { internal_note?: string @Column() - created_by: string // customer or user ID + created_by: string // customer, user, third party, etc. @Column({ nullable: true }) requested_by?: string // customer or user ID diff --git a/packages/medusa/src/services/__tests__/order-edit.ts b/packages/medusa/src/services/__tests__/order-edit.ts index 34dd0f523d..ea0d0ca6c3 100644 --- a/packages/medusa/src/services/__tests__/order-edit.ts +++ b/packages/medusa/src/services/__tests__/order-edit.ts @@ -1,4 +1,5 @@ import { IdMap, MockManager, MockRepository } from "medusa-test-utils" +import { OrderEditItemChangeType, OrderEditStatus } from "../../models" import { EventBusService, LineItemService, @@ -6,17 +7,16 @@ import { OrderEditService, OrderService, TaxProviderService, - TotalsService, + TotalsService } from "../index" -import { OrderEditItemChangeType, OrderEditStatus } from "../../models" -import { OrderServiceMock } from "../__mocks__/order" +import LineItemAdjustmentService from "../line-item-adjustment" import { EventBusServiceMock } from "../__mocks__/event-bus" import { LineItemServiceMock } from "../__mocks__/line-item" -import { TotalsServiceMock } from "../__mocks__/totals" +import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" +import { OrderServiceMock } from "../__mocks__/order" import { orderEditItemChangeServiceMock } from "../__mocks__/order-edit-item-change" import { taxProviderServiceMock } from "../__mocks__/tax-provider" -import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" -import LineItemAdjustmentService from "../line-item-adjustment" +import { TotalsServiceMock } from "../__mocks__/totals" const orderEditToUpdate = { id: IdMap.getId("order-edit-to-update"), @@ -223,7 +223,7 @@ describe("OrderEditService", () => { internal_note: "internal note", } await orderEditService.create(data, { - loggedInUserId: IdMap.getId("admin_user"), + createdBy: IdMap.getId("admin_user"), }) expect(orderEditRepository.create).toHaveBeenCalledTimes(1) @@ -261,7 +261,7 @@ describe("OrderEditService", () => { IdMap.getId("requested-order-edit"), { declinedReason: "I requested a different color for the new product", - loggedInUserId: "admin_user", + declinedBy: "admin_user", } ) @@ -279,7 +279,7 @@ describe("OrderEditService", () => { await expect( orderEditService.decline(IdMap.getId("confirmed-order-edit"), { declinedReason: "I requested a different color for the new product", - loggedInUserId: "admin_user", + declinedBy: "admin_user", }) ).rejects.toThrowError( "Cannot decline an order edit with status confirmed." @@ -291,7 +291,7 @@ describe("OrderEditService", () => { IdMap.getId("declined-order-edit"), { declinedReason: "I requested a different color for the new product", - loggedInUserId: "admin_user", + declinedBy: "admin_user", } ) @@ -335,7 +335,7 @@ describe("OrderEditService", () => { } as any) result = await orderEditService.requestConfirmation(orderEditId, { - loggedInUserId: userId, + requestedBy: userId, }) }) @@ -367,7 +367,7 @@ describe("OrderEditService", () => { beforeEach(async () => { result = await orderEditService.requestConfirmation(orderEditId, { - loggedInUserId: userId, + requestedBy: userId, }) }) @@ -381,7 +381,7 @@ describe("OrderEditService", () => { const id = IdMap.getId("order-edit-with-changes") const userId = IdMap.getId("user-id") - await orderEditService.cancel(id, { loggedInUserId: userId }) + await orderEditService.cancel(id, { canceledBy: userId }) expect(orderEditRepository.save).toHaveBeenCalledWith({ ...orderEditWithChanges, @@ -401,7 +401,7 @@ describe("OrderEditService", () => { const userId = IdMap.getId("user-id") const result = await orderEditService.cancel(id, { - loggedInUserId: userId, + canceledBy: userId, }) expect(result).toEqual(expect.objectContaining({ status: "canceled" })) @@ -418,7 +418,7 @@ describe("OrderEditService", () => { const userId = IdMap.getId("user-id") try { - await orderEditService.cancel(id, { loggedInUserId: userId }) + await orderEditService.cancel(id, { canceledBy: userId }) } catch (err) { expect(err.message).toEqual( `Cannot cancel order edit with status ${status}` @@ -433,7 +433,7 @@ describe("OrderEditService", () => { const id = IdMap.getId("order-edit-with-changes") const userId = IdMap.getId("user-id") - await orderEditService.confirm(id, { loggedInUserId: userId }) + await orderEditService.confirm(id, { confirmedBy: userId }) expect(orderEditRepository.save).toHaveBeenCalledWith({ ...orderEditWithChanges, @@ -453,7 +453,7 @@ describe("OrderEditService", () => { const userId = IdMap.getId("user-id") const result = await orderEditService.confirm(id, { - loggedInUserId: userId, + confirmedBy: userId, }) expect(result).toEqual(expect.objectContaining({ status: "confirmed" })) diff --git a/packages/medusa/src/services/order-edit.ts b/packages/medusa/src/services/order-edit.ts index f72be7682f..34da0fc6f6 100644 --- a/packages/medusa/src/services/order-edit.ts +++ b/packages/medusa/src/services/order-edit.ts @@ -1,17 +1,21 @@ -import { DeepPartial, EntityManager, ILike, IsNull } from "typeorm" import { isDefined, MedusaError } from "medusa-core-utils" +import { DeepPartial, EntityManager, ILike, IsNull } from "typeorm" -import { FindConfig, Selector } from "../types/common" -import { buildQuery, isString } from "../utils" -import { OrderEditRepository } from "../repositories/order-edit" +import { TransactionBaseService } from "../interfaces" import { Cart, Order, OrderEdit, OrderEditItemChangeType, - OrderEditStatus, + OrderEditStatus } from "../models" -import { TransactionBaseService } from "../interfaces" +import { OrderEditRepository } from "../repositories/order-edit" +import { FindConfig, Selector } from "../types/common" +import { + AddOrderEditLineItemInput, + CreateOrderEditInput +} from "../types/order-edit" +import { buildQuery, isString } from "../utils" import { EventBusService, LineItemAdjustmentService, @@ -19,12 +23,8 @@ import { OrderEditItemChangeService, OrderService, TaxProviderService, - TotalsService, + TotalsService } from "./index" -import { - AddOrderEditLineItemInput, - CreateOrderEditInput, -} from "../types/order-edit" type InjectedDependencies = { manager: EntityManager @@ -213,7 +213,7 @@ export default class OrderEditService extends TransactionBaseService { async create( data: CreateOrderEditInput, - context: { loggedInUserId: string } + context: { createdBy: string } ): Promise { return await this.atomicPhase_(async (transactionManager) => { const activeOrderEdit = await this.retrieveActive(data.order_id) @@ -231,7 +231,7 @@ export default class OrderEditService extends TransactionBaseService { const orderEditToCreate = orderEditRepository.create({ order_id: data.order_id, internal_note: data.internal_note, - created_by: context.loggedInUserId, + created_by: context.createdBy, }) const orderEdit = await orderEditRepository.save(orderEditToCreate) @@ -317,7 +317,7 @@ export default class OrderEditService extends TransactionBaseService { orderEditId: string, context: { declinedReason?: string - loggedInUserId?: string + declinedBy?: string } ): Promise { return await this.atomicPhase_(async (manager) => { @@ -325,7 +325,7 @@ export default class OrderEditService extends TransactionBaseService { this.orderEditRepository_ ) - const { loggedInUserId, declinedReason } = context + const { declinedBy, declinedReason } = context const orderEdit = await this.retrieve(orderEditId) @@ -341,7 +341,7 @@ export default class OrderEditService extends TransactionBaseService { } orderEdit.declined_at = new Date() - orderEdit.declined_by = loggedInUserId + orderEdit.declined_by = declinedBy orderEdit.declined_reason = declinedReason const result = await orderEditRepo.save(orderEdit) @@ -658,7 +658,7 @@ export default class OrderEditService extends TransactionBaseService { async requestConfirmation( orderEditId: string, context: { - loggedInUserId?: string + requestedBy?: string } = {} ): Promise { return await this.atomicPhase_(async (manager) => { @@ -683,7 +683,7 @@ export default class OrderEditService extends TransactionBaseService { } orderEdit.requested_at = new Date() - orderEdit.requested_by = context.loggedInUserId + orderEdit.requested_by = context.requestedBy orderEdit = await orderEditRepo.save(orderEdit) @@ -697,7 +697,7 @@ export default class OrderEditService extends TransactionBaseService { async cancel( orderEditId: string, - context: { loggedInUserId?: string } = {} + context: { canceledBy?: string } = {} ): Promise { return await this.atomicPhase_(async (manager) => { const orderEditRepository = manager.getCustomRepository( @@ -722,7 +722,7 @@ export default class OrderEditService extends TransactionBaseService { } orderEdit.canceled_at = new Date() - orderEdit.canceled_by = context.loggedInUserId + orderEdit.canceled_by = context.canceledBy const saved = await orderEditRepository.save(orderEdit) @@ -736,7 +736,7 @@ export default class OrderEditService extends TransactionBaseService { async confirm( orderEditId: string, - context: { loggedInUserId?: string } = {} + context: { confirmedBy?: string } = {} ): Promise { return await this.atomicPhase_(async (manager) => { const orderEditRepository = manager.getCustomRepository( @@ -774,7 +774,7 @@ export default class OrderEditService extends TransactionBaseService { ]) orderEdit.confirmed_at = new Date() - orderEdit.confirmed_by = context.loggedInUserId + orderEdit.confirmed_by = context.confirmedBy orderEdit = await orderEditRepository.save(orderEdit)