Merge remote-tracking branch 'origin/develop' into release/next
This commit is contained in:
commit
63e7ce765e
7 files changed
+397
-40
No files matched your search
@@ -0,0 +1,135 @@
|
|||||||
|
const { dropDatabase } = require("pg-god");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const setupServer = require("../../../helpers/setup-server");
|
||||||
|
const { useApi } = require("../../../helpers/use-api");
|
||||||
|
const { initDb } = require("../../../helpers/use-db");
|
||||||
|
|
||||||
|
const customerSeeder = require("../../helpers/customer-seeder");
|
||||||
|
const adminSeeder = require("../../helpers/admin-seeder");
|
||||||
|
|
||||||
|
jest.setTimeout(30000);
|
||||||
|
|
||||||
|
describe("/admin/customers", () => {
|
||||||
|
let medusaProcess;
|
||||||
|
let dbConnection;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", ".."));
|
||||||
|
dbConnection = await initDb({ cwd });
|
||||||
|
medusaProcess = await setupServer({ cwd });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await dbConnection.close();
|
||||||
|
await dropDatabase({ databaseName: "medusa-integration" });
|
||||||
|
|
||||||
|
medusaProcess.kill();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("GET /admin/customers", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await adminSeeder(dbConnection);
|
||||||
|
await customerSeeder(dbConnection);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const manager = dbConnection.manager;
|
||||||
|
await manager.query(`DELETE FROM "address"`);
|
||||||
|
await manager.query(`DELETE FROM "customer"`);
|
||||||
|
await manager.query(`DELETE FROM "user"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("lists customers and query count", async () => {
|
||||||
|
const api = useApi();
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/customers", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.data.count).toEqual(3);
|
||||||
|
expect(response.data.customers).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-customer-1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-customer-2",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-customer-3",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("lists customers with specific query", async () => {
|
||||||
|
const api = useApi();
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/customers?q=test2@email.com", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.data.count).toEqual(1);
|
||||||
|
expect(response.data.customers).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-customer-2",
|
||||||
|
email: "test2@email.com",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("lists customers with expand query", async () => {
|
||||||
|
const api = useApi();
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/customers?q=test1@email.com&expand=shipping_addresses", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.data.count).toEqual(1);
|
||||||
|
console.log(response.data.customers);
|
||||||
|
expect(response.data.customers).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-customer-1",
|
||||||
|
shipping_addresses: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-address",
|
||||||
|
first_name: "Lebron",
|
||||||
|
last_name: "James",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
const { Customer, Address } = require("@medusajs/medusa");
|
||||||
|
|
||||||
|
module.exports = async (connection, data = {}) => {
|
||||||
|
const manager = connection.manager;
|
||||||
|
|
||||||
|
await manager.insert(Customer, {
|
||||||
|
id: "test-customer-1",
|
||||||
|
email: "test1@email.com",
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.insert(Customer, {
|
||||||
|
id: "test-customer-2",
|
||||||
|
email: "test2@email.com",
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.insert(Customer, {
|
||||||
|
id: "test-customer-3",
|
||||||
|
email: "test3@email.com",
|
||||||
|
});
|
||||||
|
|
||||||
|
await manager.insert(Address, {
|
||||||
|
id: "test-address",
|
||||||
|
first_name: "Lebron",
|
||||||
|
last_name: "James",
|
||||||
|
customer_id: "test-customer-1",
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ import Brightpearl from "../utils/brightpearl"
|
|||||||
class BrightpearlService extends BaseService {
|
class BrightpearlService extends BaseService {
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
|
manager,
|
||||||
oauthService,
|
oauthService,
|
||||||
totalsService,
|
totalsService,
|
||||||
productVariantService,
|
productVariantService,
|
||||||
@@ -18,6 +19,7 @@ class BrightpearlService extends BaseService {
|
|||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
this.manager_ = manager
|
||||||
this.options = options
|
this.options = options
|
||||||
this.productVariantService_ = productVariantService
|
this.productVariantService_ = productVariantService
|
||||||
this.regionService_ = regionService
|
this.regionService_ = regionService
|
||||||
@@ -189,8 +191,12 @@ class BrightpearlService extends BaseService {
|
|||||||
.retrieveBySKU(sku)
|
.retrieveBySKU(sku)
|
||||||
.catch((_) => undefined)
|
.catch((_) => undefined)
|
||||||
if (variant && variant.manage_inventory) {
|
if (variant && variant.manage_inventory) {
|
||||||
await this.productVariantService_.update(variant.id, {
|
await this.manager_.transaction((m) => {
|
||||||
inventory_quantity: onHand,
|
return this.productVariantService_
|
||||||
|
.withTransaction(m)
|
||||||
|
.update(variant.id, {
|
||||||
|
inventory_quantity: onHand,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,16 @@ const checkContentTypes = async (container) => {
|
|||||||
if (product && product.fields) {
|
if (product && product.fields) {
|
||||||
const productFields = product.fields
|
const productFields = product.fields
|
||||||
|
|
||||||
|
const customProductFields = Object.keys(
|
||||||
|
contentfulService.options_.custom_product_fields || {}
|
||||||
|
)
|
||||||
const keys = Object.values(productFields).map((f) => f.id)
|
const keys = Object.values(productFields).map((f) => f.id)
|
||||||
if (!requiredProductFields.every((f) => keys.includes(f))) {
|
|
||||||
|
const missingKeys = requiredProductFields.filter(
|
||||||
|
(rpf) => !keys.includes(rpf) && !customProductFields.includes(rpf)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (missingKeys.length) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`Contentful: Content type ${`product`} is missing some required key(s). Required: ${requiredProductFields.join(
|
`Contentful: Content type ${`product`} is missing some required key(s). Required: ${requiredProductFields.join(
|
||||||
", "
|
", "
|
||||||
@@ -32,8 +40,16 @@ const checkContentTypes = async (container) => {
|
|||||||
if (variant && variant.fields) {
|
if (variant && variant.fields) {
|
||||||
const variantFields = variant.fields
|
const variantFields = variant.fields
|
||||||
|
|
||||||
|
const customVariantFields = Object.keys(
|
||||||
|
contentfulService.options_.custom_variant_fields || {}
|
||||||
|
)
|
||||||
const keys = Object.values(variantFields).map((f) => f.id)
|
const keys = Object.values(variantFields).map((f) => f.id)
|
||||||
if (!requiredVariantFields.every((f) => keys.includes(f))) {
|
|
||||||
|
const missingKeys = requiredVariantFields.filter(
|
||||||
|
(rpf) => !keys.includes(rpf) && !customVariantFields.includes(rpf)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (missingKeys.length) {
|
||||||
throw Error(
|
throw Error(
|
||||||
`Contentful: Content type ${`productVariant`} is missing some required key(s). Required: ${requiredVariantFields.join(
|
`Contentful: Content type ${`productVariant`} is missing some required key(s). Required: ${requiredVariantFields.join(
|
||||||
", "
|
", "
|
||||||
@@ -47,13 +63,13 @@ const requiredProductFields = [
|
|||||||
"title",
|
"title",
|
||||||
"variants",
|
"variants",
|
||||||
"options",
|
"options",
|
||||||
"objectId",
|
"medusaId",
|
||||||
"type",
|
"type",
|
||||||
"collection",
|
"collection",
|
||||||
"tags",
|
"tags",
|
||||||
"handle",
|
"handle",
|
||||||
]
|
]
|
||||||
|
|
||||||
const requiredVariantFields = ["title", "sku", "prices", "options", "objectId"]
|
const requiredVariantFields = ["title", "sku", "prices", "options", "medusaId"]
|
||||||
|
|
||||||
export default checkContentTypes
|
export default checkContentTypes
|
||||||
@@ -111,10 +111,27 @@ class ContentfulService extends BaseService {
|
|||||||
return assets
|
return assets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCustomField(field, type) {
|
||||||
|
const customOptions = this.options_[`custom_${type}_fields`]
|
||||||
|
|
||||||
|
if (customOptions) {
|
||||||
|
return customOptions[field] || field
|
||||||
|
} else {
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async createProductInContentful(product) {
|
async createProductInContentful(product) {
|
||||||
try {
|
try {
|
||||||
const p = await this.productService_.retrieve(product.id, {
|
const p = await this.productService_.retrieve(product.id, {
|
||||||
relations: ["variants", "options", "tags", "type", "collection"],
|
relations: [
|
||||||
|
"variants",
|
||||||
|
"options",
|
||||||
|
"tags",
|
||||||
|
"type",
|
||||||
|
"collection",
|
||||||
|
"images",
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const environment = await this.getContentfulEnvironment_()
|
const environment = await this.getContentfulEnvironment_()
|
||||||
@@ -122,46 +139,92 @@ class ContentfulService extends BaseService {
|
|||||||
const variantLinks = this.getVariantLinks_(variantEntries)
|
const variantLinks = this.getVariantLinks_(variantEntries)
|
||||||
|
|
||||||
const fields = {
|
const fields = {
|
||||||
title: {
|
[this.getCustomField("title", "product")]: {
|
||||||
"en-US": p.title,
|
"en-US": p.title,
|
||||||
},
|
},
|
||||||
variants: {
|
[this.getCustomField("variants", "product")]: {
|
||||||
"en-US": variantLinks,
|
"en-US": variantLinks,
|
||||||
},
|
},
|
||||||
options: {
|
[this.getCustomField("options", "product")]: {
|
||||||
"en-US": p.options,
|
"en-US": p.options,
|
||||||
},
|
},
|
||||||
objectId: {
|
[this.getCustomField("medusaId", "product")]: {
|
||||||
"en-US": p.id,
|
"en-US": p.id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p.images.length > 0) {
|
||||||
|
const imageLinks = await this.createImageAssets(product)
|
||||||
|
|
||||||
|
const thumbnailAsset = await environment.createAsset({
|
||||||
|
fields: {
|
||||||
|
title: {
|
||||||
|
"en-US": `${p.title}`,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
"en-US": "",
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
"en-US": {
|
||||||
|
contentType: "image/xyz",
|
||||||
|
fileName: p.thumbnail,
|
||||||
|
upload: p.thumbnail,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await thumbnailAsset.processForAllLocales()
|
||||||
|
|
||||||
|
const thumbnailLink = {
|
||||||
|
sys: {
|
||||||
|
type: "Link",
|
||||||
|
linkType: "Asset",
|
||||||
|
id: thumbnailAsset.sys.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.thumbnail = {
|
||||||
|
"en-US": thumbnailLink,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageLinks) {
|
||||||
|
fields.images = {
|
||||||
|
"en-US": imageLinks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (p.type) {
|
if (p.type) {
|
||||||
const type = {
|
const type = {
|
||||||
"en-US": p.type.value,
|
"en-US": p.type.value,
|
||||||
}
|
}
|
||||||
fields.type = type
|
|
||||||
|
fields[this.getCustomField("type", "product")] = type
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.collection) {
|
if (p.collection) {
|
||||||
const collection = {
|
const collection = {
|
||||||
"en-US": p.collection.title,
|
"en-US": p.collection.title,
|
||||||
}
|
}
|
||||||
fields.collection = collection
|
|
||||||
|
fields[this.getCustomField("collection", "product")] = collection
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.tags) {
|
if (p.tags) {
|
||||||
const tags = {
|
const tags = {
|
||||||
"en-US": p.tags,
|
"en-US": p.tags,
|
||||||
}
|
}
|
||||||
fields.tags = tags
|
|
||||||
|
fields[this.getCustomField("tags", "product")] = tags
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.handle) {
|
if (p.handle) {
|
||||||
const handle = {
|
const handle = {
|
||||||
"en-US": p.handle,
|
"en-US": p.handle,
|
||||||
}
|
}
|
||||||
fields.handle = handle
|
|
||||||
|
fields[this.getCustomField("handle", "product")] = handle
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await environment.createEntryWithId("product", p.id, {
|
const result = await environment.createEntryWithId("product", p.id, {
|
||||||
@@ -189,19 +252,19 @@ class ContentfulService extends BaseService {
|
|||||||
v.id,
|
v.id,
|
||||||
{
|
{
|
||||||
fields: {
|
fields: {
|
||||||
title: {
|
[this.getCustomField("title", "variant")]: {
|
||||||
"en-US": v.title,
|
"en-US": v.title,
|
||||||
},
|
},
|
||||||
sku: {
|
[this.getCustomField("sku", "variant")]: {
|
||||||
"en-US": v.sku,
|
"en-US": v.sku,
|
||||||
},
|
},
|
||||||
prices: {
|
[this.getCustomField("prices", "variant")]: {
|
||||||
"en-US": v.prices,
|
"en-US": v.prices,
|
||||||
},
|
},
|
||||||
options: {
|
[this.getCustomField("options", "variant")]: {
|
||||||
"en-US": v.options,
|
"en-US": v.options,
|
||||||
},
|
},
|
||||||
objectId: {
|
[this.getCustomField("medusaId", "variant")]: {
|
||||||
"en-US": v.id,
|
"en-US": v.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -240,7 +303,14 @@ class ContentfulService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const p = await this.productService_.retrieve(product.id, {
|
const p = await this.productService_.retrieve(product.id, {
|
||||||
relations: ["options", "variants", "type", "collection", "tags"],
|
relations: [
|
||||||
|
"options",
|
||||||
|
"variants",
|
||||||
|
"type",
|
||||||
|
"collection",
|
||||||
|
"tags",
|
||||||
|
"images",
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const variantEntries = await this.getVariantEntries_(p.variants)
|
const variantEntries = await this.getVariantEntries_(p.variants)
|
||||||
@@ -248,46 +318,86 @@ class ContentfulService extends BaseService {
|
|||||||
|
|
||||||
const productEntryFields = {
|
const productEntryFields = {
|
||||||
...productEntry.fields,
|
...productEntry.fields,
|
||||||
title: {
|
[this.getCustomField("title", "product")]: {
|
||||||
"en-US": p.title,
|
"en-US": p.title,
|
||||||
},
|
},
|
||||||
options: {
|
[this.getCustomField("options", "product")]: {
|
||||||
"en-US": p.options,
|
"en-US": p.options,
|
||||||
},
|
},
|
||||||
variants: {
|
[this.getCustomField("variants", "product")]: {
|
||||||
"en-US": variantLinks,
|
"en-US": variantLinks,
|
||||||
},
|
},
|
||||||
objectId: {
|
[this.getCustomField("medusaId", "product")]: {
|
||||||
"en-US": p.id,
|
"en-US": p.id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p.thumbnail) {
|
||||||
|
const thumbnailAsset = await environment.createAsset({
|
||||||
|
fields: {
|
||||||
|
title: {
|
||||||
|
"en-US": `${p.title}`,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
"en-US": "",
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
"en-US": {
|
||||||
|
contentType: "image/xyz",
|
||||||
|
fileName: p.thumbnail,
|
||||||
|
upload: p.thumbnail,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await thumbnailAsset.processForAllLocales()
|
||||||
|
|
||||||
|
const thumbnailLink = {
|
||||||
|
sys: {
|
||||||
|
type: "Link",
|
||||||
|
linkType: "Asset",
|
||||||
|
id: thumbnailAsset.sys.id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
productEntryFields.thumbnail = {
|
||||||
|
"en-US": thumbnailLink,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (p.type) {
|
if (p.type) {
|
||||||
const type = {
|
const type = {
|
||||||
"en-US": p.type.value,
|
"en-US": p.type.value,
|
||||||
}
|
}
|
||||||
productEntryFields.type = type
|
|
||||||
|
productEntryFields[this.getCustomField("type", "product")] = type
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.collection) {
|
if (p.collection) {
|
||||||
const collection = {
|
const collection = {
|
||||||
"en-US": p.collection.title,
|
"en-US": p.collection.title,
|
||||||
}
|
}
|
||||||
productEntryFields.collection = collection
|
|
||||||
|
productEntryFields[
|
||||||
|
this.getCustomField("collection", "product")
|
||||||
|
] = collection
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.tags) {
|
if (p.tags) {
|
||||||
const tags = {
|
const tags = {
|
||||||
"en-US": p.tags,
|
"en-US": p.tags,
|
||||||
}
|
}
|
||||||
productEntryFields.tags = tags
|
|
||||||
|
productEntryFields[this.getCustomField("tags", "product")] = tags
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.handle) {
|
if (p.handle) {
|
||||||
const handle = {
|
const handle = {
|
||||||
"en-US": p.handle,
|
"en-US": p.handle,
|
||||||
}
|
}
|
||||||
productEntryFields.handle = handle
|
|
||||||
|
productEntryFields[this.getCustomField("handle", "product")] = handle
|
||||||
}
|
}
|
||||||
|
|
||||||
productEntry.fields = productEntryFields
|
productEntry.fields = productEntryFields
|
||||||
@@ -333,19 +443,19 @@ class ContentfulService extends BaseService {
|
|||||||
|
|
||||||
const variantEntryFields = {
|
const variantEntryFields = {
|
||||||
...variantEntry.fields,
|
...variantEntry.fields,
|
||||||
title: {
|
[this.getCustomField("title", "variant")]: {
|
||||||
"en-US": v.title,
|
"en-US": v.title,
|
||||||
},
|
},
|
||||||
sku: {
|
[this.getCustomField("sku", "variant")]: {
|
||||||
"en-US": v.sku,
|
"en-US": v.sku,
|
||||||
},
|
},
|
||||||
options: {
|
[this.getCustomField("options", "variant")]: {
|
||||||
"en-US": v.options,
|
"en-US": v.options,
|
||||||
},
|
},
|
||||||
prices: {
|
[this.getCustomField("prices", "variant")]: {
|
||||||
"en-US": v.prices,
|
"en-US": v.prices,
|
||||||
},
|
},
|
||||||
objectId: {
|
[this.getCustomField("medusaId", "variant")]: {
|
||||||
"en-US": v.id,
|
"en-US": v.id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -377,7 +487,8 @@ class ContentfulService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let update = {
|
let update = {
|
||||||
title: productEntry.fields.title["en-US"],
|
title:
|
||||||
|
productEntry.fields[this.getCustomField("title", "product")]["en-US"],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the thumbnail, if present
|
// Get the thumbnail, if present
|
||||||
@@ -421,7 +532,10 @@ class ContentfulService extends BaseService {
|
|||||||
const updatedVariant = await this.productVariantService_.update(
|
const updatedVariant = await this.productVariantService_.update(
|
||||||
variantId,
|
variantId,
|
||||||
{
|
{
|
||||||
title: variantEntry.fields.title["en-US"],
|
title:
|
||||||
|
variantEntry.fields[this.getCustomField("title", "variant")][
|
||||||
|
"en-US"
|
||||||
|
],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,32 @@ export default async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const customerService = req.scope.resolve("customerService")
|
const customerService = req.scope.resolve("customerService")
|
||||||
|
|
||||||
const limit = parseInt(req.query.limit) || 10
|
const limit = parseInt(req.query.limit) || 50
|
||||||
const offset = parseInt(req.query.offset) || 0
|
const offset = parseInt(req.query.offset) || 0
|
||||||
|
|
||||||
|
const selector = {}
|
||||||
|
|
||||||
|
if ("q" in req.query) {
|
||||||
|
selector.q = req.query.q
|
||||||
|
}
|
||||||
|
|
||||||
|
let expandFields = []
|
||||||
|
if ("expand" in req.query) {
|
||||||
|
expandFields = req.query.expand.split(",")
|
||||||
|
}
|
||||||
|
|
||||||
const listConfig = {
|
const listConfig = {
|
||||||
relations: [],
|
relations: expandFields.length ? expandFields : [],
|
||||||
skip: offset,
|
skip: offset,
|
||||||
take: limit,
|
take: limit,
|
||||||
}
|
}
|
||||||
|
|
||||||
const customers = await customerService.list({}, listConfig)
|
const [customers, count] = await customerService.listAndCount(
|
||||||
|
selector,
|
||||||
|
listConfig
|
||||||
|
)
|
||||||
|
|
||||||
res.json({ customers, count: customers.length, offset, limit })
|
res.json({ customers, count, offset, limit })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Scrypt from "scrypt-kdf"
|
|||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import { Validator, MedusaError } from "medusa-core-utils"
|
import { Validator, MedusaError } from "medusa-core-utils"
|
||||||
import { BaseService } from "medusa-interfaces"
|
import { BaseService } from "medusa-interfaces"
|
||||||
|
import { Brackets } from "typeorm"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides layer to manipulate customers.
|
* Provides layer to manipulate customers.
|
||||||
@@ -132,6 +133,50 @@ class CustomerService extends BaseService {
|
|||||||
return customerRepo.find(query)
|
return customerRepo.find(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listAndCount(
|
||||||
|
selector,
|
||||||
|
config = { relations: [], skip: 0, take: 50, order: { created_at: "DESC" } }
|
||||||
|
) {
|
||||||
|
const customerRepo = this.manager_.getCustomRepository(
|
||||||
|
this.customerRepository_
|
||||||
|
)
|
||||||
|
|
||||||
|
let q
|
||||||
|
if ("q" in selector) {
|
||||||
|
q = selector.q
|
||||||
|
delete selector.q
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = this.buildQuery_(selector, config)
|
||||||
|
|
||||||
|
if (q) {
|
||||||
|
const where = query.where
|
||||||
|
|
||||||
|
delete where.email
|
||||||
|
delete where.first_name
|
||||||
|
delete where.last_name
|
||||||
|
|
||||||
|
query.join = {
|
||||||
|
alias: "customer",
|
||||||
|
}
|
||||||
|
|
||||||
|
query.where = qb => {
|
||||||
|
qb.where(where)
|
||||||
|
|
||||||
|
qb.andWhere(
|
||||||
|
new Brackets(qb => {
|
||||||
|
qb.where(`customer.first_name ILIKE :q`, { q: `%${q}%` })
|
||||||
|
.orWhere(`customer.last_name ILIKE :q`, { q: `%${q}%` })
|
||||||
|
.orWhere(`customer.email ILIKE :q`, { q: `%${q}%` })
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [customers, count] = await customerRepo.findAndCount(query)
|
||||||
|
return [customers, count]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the total number of documents in database
|
* Return the total number of documents in database
|
||||||
* @return {Promise} the result of the count operation
|
* @return {Promise} the result of the count operation
|
||||||
|
|||||||
Reference in new issue
Block a user