From 7c31acb064b5b9db180bc10e85d5ab6217389f05 Mon Sep 17 00:00:00 2001 From: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Wed, 16 Feb 2022 23:41:30 +0100 Subject: [PATCH] Add expand to /admin/customers/:id (#1070) * fix: 1055 add expand to /admin/customers/:id * fix tests * fix tests --- .../admin/__snapshots__/customer.js.snap | 72 +++++++++++++++++++ .../api/__tests__/admin/customer.js | 71 ++++++++++++++++++ .../api/helpers/customer-seeder.js | 21 +++--- .../routes/admin/customers/get-customer.ts | 22 +++++- .../src/api/routes/admin/customers/index.ts | 2 + packages/medusa/src/types/common.ts | 15 +++- 6 files changed, 189 insertions(+), 14 deletions(-) create mode 100644 integration-tests/api/__tests__/admin/__snapshots__/customer.js.snap diff --git a/integration-tests/api/__tests__/admin/__snapshots__/customer.js.snap b/integration-tests/api/__tests__/admin/__snapshots__/customer.js.snap new file mode 100644 index 0000000000..2c77349148 --- /dev/null +++ b/integration-tests/api/__tests__/admin/__snapshots__/customer.js.snap @@ -0,0 +1,72 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`/admin/customers GET /admin/customers/:id fetches a customer 1`] = ` +Object { + "billing_address_id": "test-address", + "created_at": Any, + "deleted_at": null, + "email": "test1@email.com", + "first_name": null, + "has_account": false, + "id": Any, + "last_name": null, + "metadata": null, + "orders": Array [], + "phone": null, + "shipping_addresses": Array [ + Object { + "address_1": null, + "address_2": null, + "city": null, + "company": null, + "country_code": null, + "created_at": Any, + "customer_id": "test-customer-1", + "deleted_at": null, + "first_name": "Lebron", + "id": "test-address", + "last_name": "James", + "metadata": null, + "phone": null, + "postal_code": null, + "province": null, + "updated_at": Any, + }, + ], + "updated_at": Any, +} +`; + +exports[`/admin/customers GET /admin/customers/:id fetches a customer with expand query 1`] = ` +Object { + "billing_address": Object { + "address_1": null, + "address_2": null, + "city": null, + "company": null, + "country_code": null, + "created_at": Any, + "customer_id": "test-customer-1", + "deleted_at": null, + "first_name": "Lebron", + "id": "test-address", + "last_name": "James", + "metadata": null, + "phone": null, + "postal_code": null, + "province": null, + "updated_at": Any, + }, + "billing_address_id": "test-address", + "created_at": Any, + "deleted_at": null, + "email": "test1@email.com", + "first_name": null, + "has_account": false, + "id": "test-customer-1", + "last_name": null, + "metadata": null, + "phone": null, + "updated_at": Any, +} +`; diff --git a/integration-tests/api/__tests__/admin/customer.js b/integration-tests/api/__tests__/admin/customer.js index 8661c1780c..283d716894 100644 --- a/integration-tests/api/__tests__/admin/customer.js +++ b/integration-tests/api/__tests__/admin/customer.js @@ -229,4 +229,75 @@ describe("/admin/customers", () => { ) }) }) + + describe("GET /admin/customers/:id", () => { + beforeEach(async () => { + try { + await adminSeeder(dbConnection) + await customerSeeder(dbConnection) + } catch (err) { + console.log(err) + throw err + } + }) + + afterEach(async () => { + const db = useDb() + await db.teardown() + }) + + it("fetches a customer", async () => { + const api = useApi() + + const response = await api + .get("/admin/customers/test-customer-1", { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.log(err) + }) + + expect(response.status).toEqual(200) + expect(response.data.customer).toMatchSnapshot({ + id: expect.any(String), + shipping_addresses: [ + { + id: "test-address", + created_at: expect.any(String), + updated_at: expect.any(String), + }, + ], + created_at: expect.any(String), + updated_at: expect.any(String), + }) + }) + + it("fetches a customer with expand query", async () => { + const api = useApi() + + const response = await api + .get("/admin/customers/test-customer-1?expand=billing_address", { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.log(err) + }) + + expect(response.status).toEqual(200) + expect(response.data.customer).toMatchSnapshot({ + id: "test-customer-1", + billing_address: { + id: "test-address", + created_at: expect.any(String), + updated_at: expect.any(String), + }, + created_at: expect.any(String), + updated_at: expect.any(String), + }) + }) + }) }) diff --git a/integration-tests/api/helpers/customer-seeder.js b/integration-tests/api/helpers/customer-seeder.js index acef948bbd..ff27341312 100644 --- a/integration-tests/api/helpers/customer-seeder.js +++ b/integration-tests/api/helpers/customer-seeder.js @@ -3,11 +3,23 @@ const { Customer, Address } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { const manager = connection.manager - await manager.insert(Customer, { + const testAddr = await manager.create(Address, { + id: "test-address", + first_name: "Lebron", + last_name: "James", + }) + + await manager.save(testAddr) + + const customer = await manager.create(Customer, { id: "test-customer-1", email: "test1@email.com", }) + customer.billing_address = testAddr + customer.shipping_addresses = [testAddr] + await manager.save(customer) + await manager.insert(Customer, { id: "test-customer-2", email: "test2@email.com", @@ -23,11 +35,4 @@ module.exports = async (connection, data = {}) => { email: "test4@email.com", has_account: true, }) - - await manager.insert(Address, { - id: "test-address", - first_name: "Lebron", - last_name: "James", - customer_id: "test-customer-1", - }) } diff --git a/packages/medusa/src/api/routes/admin/customers/get-customer.ts b/packages/medusa/src/api/routes/admin/customers/get-customer.ts index f7914e66b5..fe6eb0c085 100644 --- a/packages/medusa/src/api/routes/admin/customers/get-customer.ts +++ b/packages/medusa/src/api/routes/admin/customers/get-customer.ts @@ -1,4 +1,7 @@ +import { defaultAdminCustomersRelations } from "." import CustomerService from "../../../../services/customer" +import { FindParams } from "../../../../types/common" +import { validator } from "../../../../utils/validator" /** * @oas [get] /customers/{id} @@ -22,10 +25,23 @@ import CustomerService from "../../../../services/customer" */ export default async (req, res) => { const { id } = req.params + + const validated = await validator(FindParams, req.query) + const customerService: CustomerService = req.scope.resolve("customerService") - const customer = await customerService.retrieve(id, { - relations: ["orders", "shipping_addresses"], - }) + + let expandFields: string[] = [] + if (validated.expand) { + expandFields = validated.expand.split(",") + } + + const findConfig = { + relations: expandFields.length + ? expandFields + : defaultAdminCustomersRelations, + } + + const customer = await customerService.retrieve(id, findConfig) res.json({ customer }) } diff --git a/packages/medusa/src/api/routes/admin/customers/index.ts b/packages/medusa/src/api/routes/admin/customers/index.ts index 310d944332..d6bbd32ef7 100644 --- a/packages/medusa/src/api/routes/admin/customers/index.ts +++ b/packages/medusa/src/api/routes/admin/customers/index.ts @@ -26,6 +26,8 @@ export type AdminCustomersListRes = PaginatedResponse & { customers: Customer[] } +export const defaultAdminCustomersRelations = ["orders", "shipping_addresses"] + export * from "./create-customer" export * from "./get-customer" export * from "./list-customers" diff --git a/packages/medusa/src/types/common.ts b/packages/medusa/src/types/common.ts index a8d88a2939..f2f6d41b70 100644 --- a/packages/medusa/src/types/common.ts +++ b/packages/medusa/src/types/common.ts @@ -1,8 +1,7 @@ -import { Transform } from "class-transformer" -import { transformDate } from "../utils/validators/date-transform" -import { Type } from "class-transformer" +import { Transform, Type } from "class-transformer" import { IsDate, IsNumber, IsOptional, IsString } from "class-validator" import "reflect-metadata" +import { transformDate } from "../utils/validators/date-transform" export type PartialPick = { [P in K]?: T[P] @@ -169,3 +168,13 @@ export class AddressCreatePayload { @IsString() postal_code: string } + +export class FindParams { + @IsString() + @IsOptional() + expand?: string + + @IsString() + @IsOptional() + fields?: string +}