Feat: Bulk add customers to customer group (#1095)

* fix babel transform-runtime regenerator required for migrations

* add customer group model

* add migration for customer group

* add customer group model export

* add customer group repository

* add customer group service

* add CustomerGroupRepository to "withTransaction" in CustomerGroupService

* remove unnecessary argument to runtime plugin

* service export ordering

* add create customer group endpoint

* add customergroup to route index in admin

* add customer group service

* add customer groups test

* cleanup

* add customers batch initial

* batch creation of customer groups

* integration testing batch creation

* integration tests

* chaining existing customers creation in repo

* remove commented test

* update unit tests to reflect change in idempotent behavior

* ensure that exceptions are expected

* update idempotency behavior

* update formatting

* update format

* Update packages/medusa/src/repositories/customer-group.ts

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* pr feedback

* add In import

* add seperate model dto

* add integration test

* error handling in repository

* remove unused import

* jsdoc

* Update packages/medusa/src/api/routes/admin/customer-groups/add-customers-batch.ts

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* Update packages/medusa/src/api/routes/admin/customer-groups/add-customers-batch.ts

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* pr review comments

* rename variable

* fix: adds atomic phase clean up callback

* fix: call error handler in new transaction block too

* restore

* error handling

* fix: error handler in no isolation case

* add integration test for missing group on update

* final adjustments to test

* fix pr feedback

* cleanup core for pr

* remove console.log

* remove customergroupservice test from customers

* Apply suggestions from code review

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>

* add end bracket to customer tests

* remove comments

* change model decorator

* fix integration test merge

* onDelete cascade instead of cascade:true

* remove verbose flag

* fix: dedupe type

* add save to customer groups

* customer model delete cascade

* add await to asyncronous save operations

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>
This commit is contained in:
Philip Korsholm
2022-02-28 10:03:26 +01:00
committed by GitHub
parent 562a1b427a
commit 4b4463f0e2
21 changed files with 638 additions and 251 deletions

View File

@@ -130,7 +130,7 @@ describe("/admin/customer-groups", () => {
.catch((error) => {
expect(error.response.data.type).toEqual("not_found")
expect(error.response.data.message).toEqual(
`CustomerGroup with ${id} was not found`
`CustomerGroup with id ${id} was not found`
)
})
})
@@ -193,6 +193,182 @@ describe("/admin/customer-groups", () => {
})
})
describe("POST /admin/customer-groups/{id}/customers/batch", () => {
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("adds multiple customers to a group", async () => {
const api = useApi()
const payload = {
customer_ids: [{ id: "test-customer-1" }, { id: "test-customer-2" }],
}
const batchAddResponse = await api.post(
"/admin/customer-groups/customer-group-1/customers/batch",
payload,
{
headers: {
Authorization: "Bearer test_token",
},
}
)
expect(batchAddResponse.status).toEqual(200)
expect(batchAddResponse.data.customer_group).toEqual(
expect.objectContaining({
name: "vip-customers",
})
)
const getCustomerResponse = await api.get(
"/admin/customers?expand=groups",
{
headers: { Authorization: "Bearer test_token" },
}
)
expect(getCustomerResponse.data.customers).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "test-customer-1",
groups: [
expect.objectContaining({
name: "vip-customers",
id: "customer-group-1",
}),
],
}),
expect.objectContaining({
id: "test-customer-2",
groups: [
expect.objectContaining({
name: "vip-customers",
id: "customer-group-1",
}),
],
}),
])
)
})
it("presents a descriptive error when presented with a non-existing group", async () => {
expect.assertions(2)
const api = useApi()
const payload = {
customer_ids: [{ id: "test-customer-1" }, { id: "test-customer-2" }],
}
await api
.post(
"/admin/customer-groups/non-existing-customer-group-1/customers/batch",
payload,
{
headers: {
Authorization: "Bearer test_token",
},
}
)
.catch((err) => {
expect(err.response.data.type).toEqual("not_found")
expect(err.response.data.message).toEqual(
"CustomerGroup with id non-existing-customer-group-1 was not found"
)
})
})
it("adds customers to a group idempotently", async () => {
expect.assertions(3)
const api = useApi()
// add customer-1 to the customer group
const payload_1 = {
customer_ids: [{ id: "test-customer-1" }],
}
await api
.post(
"/admin/customer-groups/customer-group-1/customers/batch",
payload_1,
{
headers: {
Authorization: "Bearer test_token",
},
}
)
.catch((err) => console.log(err))
// re-adding customer-1 to the customer group along with new addintion:
// customer-2 and some non-existing customers should cause the request to fail
const payload_2 = {
customer_ids: [
{ id: "test-customer-1" },
{ id: "test-customer-27" },
{ id: "test-customer-28" },
{ id: "test-customer-2" },
],
}
await api
.post(
"/admin/customer-groups/customer-group-1/customers/batch",
payload_2,
{
headers: {
Authorization: "Bearer test_token",
},
}
)
.catch((err) => {
expect(err.response.data.type).toEqual("not_found")
expect(err.response.data.message).toEqual(
'The following customer ids do not exist: "test-customer-27, test-customer-28"'
)
})
// check that customer-1 is only added once and that customer-2 is added correctly
const getCustomerResponse = await api.get(
"/admin/customers?expand=groups",
{
headers: { Authorization: "Bearer test_token" },
}
)
expect(getCustomerResponse.data.customers).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: "test-customer-1",
groups: [
expect.objectContaining({
name: "vip-customers",
id: "customer-group-1",
}),
],
}),
expect.objectContaining({
id: "test-customer-2",
groups: [],
}),
])
)
})
})
describe("POST /admin/customer-groups/:id", () => {
beforeEach(async () => {
try {
@@ -336,8 +512,6 @@ describe("/admin/customer-groups", () => {
})
it("throws error when a customer group doesn't exist", async () => {
expect.assertions(3)
const api = useApi()
const id = "test-group-000"
@@ -352,7 +526,7 @@ describe("/admin/customer-groups", () => {
expect(err.response.status).toEqual(404)
expect(err.response.data.type).toEqual("not_found")
expect(err.response.data.message).toEqual(
`CustomerGroup with ${id} was not found`
`CustomerGroup with id ${id} was not found`
)
})
})

View File

@@ -229,6 +229,32 @@ describe("/admin/customers", () => {
)
})
it("fails when adding a customer group which doesn't exist", async () => {
expect.assertions(3)
// Try adding a non existing group
const api = useApi()
await api
.post(
"/admin/customers/test-customer-3?expand=groups",
{
groups: [{ id: "fake-group-0" }],
},
{
headers: {
Authorization: "Bearer test_token",
},
}
)
.catch((error) => {
expect(error.response.status).toEqual(404)
expect(error.response.data.type).toEqual("not_found")
expect(error.response.data.message).toEqual(
"Customer_group with customer_group_id fake-group-0 does not exist."
)
})
})
it("Correctly updates customer groups", async () => {
const api = useApi()
let response = await api
@@ -254,32 +280,6 @@ describe("/admin/customers", () => {
])
)
// Try adding a non existing group
response = await api
.post(
"/admin/customers/test-customer-3?expand=groups",
{
groups: [{ id: "test-group-4" }, { id: "fake-group-0" }],
},
{
headers: {
Authorization: "Bearer test_token",
},
}
)
.catch((err) => {
console.log(err)
})
expect(response.status).toEqual(200)
expect(response.data.customer.groups.length).toEqual(1)
expect(response.data.customer.groups).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: "test-group-4", name: "test-group-4" }),
])
)
// Delete all groups
response = await api

View File

@@ -882,8 +882,8 @@ describe("/admin/discounts", () => {
}
)
} catch (error) {
expect(error.response.data.message).toMatch(
/duplicate key value violates unique constraint/i
expect(error.response.data.message).toEqual(
"Discount with code TESTING already exists."
)
}
})

View File

@@ -1627,7 +1627,7 @@ describe("/admin/products", () => {
})
} catch (error) {
expect(error.response.data.message).toMatch(
/duplicate key value violates unique constraint/i
"Product with handle test-product already exists."
)
}
})
@@ -1699,7 +1699,7 @@ describe("/admin/products", () => {
})
} catch (error) {
expect(error.response.data.message).toMatch(
/duplicate key value violates unique constraint/i
"Product_collection with handle test-collection already exists."
)
}
})