committed by
GitHub
parent
cb727c8689
commit
cc2e87754d
37
packages/medusa/src/models/__mocks__/customer.js
Normal file
37
packages/medusa/src/models/__mocks__/customer.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { IdMap } from "medusa-test-utils"
|
||||||
|
|
||||||
|
export const customers = {
|
||||||
|
testCustomer: {
|
||||||
|
_id: IdMap.getId("testCustomer"),
|
||||||
|
email: "oliver@medusa.com",
|
||||||
|
first_name: "Oliver",
|
||||||
|
last_name: "Juhl",
|
||||||
|
billingAddress: {},
|
||||||
|
password_hash: "123456789",
|
||||||
|
},
|
||||||
|
deleteCustomer: {
|
||||||
|
_id: IdMap.getId("deleteId"),
|
||||||
|
email: "oliver@medusa.com",
|
||||||
|
first_name: "Oliver",
|
||||||
|
last_name: "Juhl",
|
||||||
|
billingAddress: {},
|
||||||
|
password_hash: "123456789",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CustomerModelMock = {
|
||||||
|
create: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
updateOne: jest.fn().mockImplementation((query, update) => {
|
||||||
|
return Promise.resolve()
|
||||||
|
}),
|
||||||
|
deleteOne: jest.fn().mockReturnValue(Promise.resolve()),
|
||||||
|
findOne: jest.fn().mockImplementation(query => {
|
||||||
|
if (query._id === IdMap.getId("testCustomer")) {
|
||||||
|
return Promise.resolve(customers.testCustomer)
|
||||||
|
}
|
||||||
|
if (query._id === IdMap.getId("deleteId")) {
|
||||||
|
return Promise.resolve(customers.deleteCustomer)
|
||||||
|
}
|
||||||
|
return Promise.resolve(undefined)
|
||||||
|
}),
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ class CustomerModel extends BaseModel {
|
|||||||
first_name: { type: String, required: true },
|
first_name: { type: String, required: true },
|
||||||
last_name: { type: String, required: true },
|
last_name: { type: String, required: true },
|
||||||
billing_address: { type: AddressSchema },
|
billing_address: { type: AddressSchema },
|
||||||
password_hash: { type: String },
|
|
||||||
metadata: { type: mongoose.Schema.Types.Mixed, default: {} },
|
metadata: { type: mongoose.Schema.Types.Mixed, default: {} },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
277
packages/medusa/src/services/__tests__/customer.js
Normal file
277
packages/medusa/src/services/__tests__/customer.js
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
import mongoose from "mongoose"
|
||||||
|
import { IdMap } from "medusa-test-utils"
|
||||||
|
import CustomerService from "../customer"
|
||||||
|
import { CustomerModelMock, customers } from "../../models/__mocks__/customer"
|
||||||
|
|
||||||
|
describe("CustomerService", () => {
|
||||||
|
describe("retrieve", () => {
|
||||||
|
let result
|
||||||
|
beforeAll(async () => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
result = await customerService.retrieve(IdMap.getId("testCustomer"))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calls customer model functions", () => {
|
||||||
|
expect(CustomerModelMock.findOne).toHaveBeenCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.findOne).toHaveBeenCalledWith({
|
||||||
|
_id: IdMap.getId("testCustomer"),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns the customer", () => {
|
||||||
|
expect(result).toEqual(customers.testCustomer)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("setMetadata", () => {
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calls updateOne with correct params", async () => {
|
||||||
|
const id = mongoose.Types.ObjectId()
|
||||||
|
await customerService.setMetadata(`${id}`, "metadata", "testMetadata")
|
||||||
|
|
||||||
|
expect(CustomerModelMock.updateOne).toBeCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.updateOne).toBeCalledWith(
|
||||||
|
{ _id: `${id}` },
|
||||||
|
{ $set: { "metadata.metadata": "testMetadata" } }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("throw error on invalid key type", async () => {
|
||||||
|
const id = mongoose.Types.ObjectId()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await customerService.setMetadata(`${id}`, 1234, "nono")
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.message).toEqual(
|
||||||
|
"Key type is invalid. Metadata keys must be strings"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("create", () => {
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calls model layer create", () => {
|
||||||
|
customerService.create({
|
||||||
|
email: "oliver@medusa.com",
|
||||||
|
first_name: "Oliver",
|
||||||
|
last_name: "Juhl",
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(CustomerModelMock.create).toBeCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.create).toBeCalledWith({
|
||||||
|
email: "oliver@medusa.com",
|
||||||
|
first_name: "Oliver",
|
||||||
|
last_name: "Juhl",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails if email is in incorrect format", () => {
|
||||||
|
try {
|
||||||
|
customerService.create({
|
||||||
|
email: "olivermedusa.com",
|
||||||
|
first_name: "Oliver",
|
||||||
|
last_name: "Juhl",
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.message).toEqual("The email is not valid")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails if billing address is in incorrect format", () => {
|
||||||
|
try {
|
||||||
|
customerService.create({
|
||||||
|
email: "oliver@medusa.com",
|
||||||
|
first_name: "Oliver",
|
||||||
|
last_name: "Juhl",
|
||||||
|
billing_address: {
|
||||||
|
first_name: 1234,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.message).toEqual("The address is not valid")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("update", () => {
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("successfully updates a customer", async () => {
|
||||||
|
await customerService.update(IdMap.getId("testCustomer"), {
|
||||||
|
first_name: "Olli",
|
||||||
|
last_name: "Test",
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(CustomerModelMock.updateOne).toBeCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.updateOne).toBeCalledWith(
|
||||||
|
{ _id: IdMap.getId("testCustomer") },
|
||||||
|
{ $set: { first_name: "Olli", last_name: "Test" } },
|
||||||
|
{ runValidators: true }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails if metadata updates are attempted", async () => {
|
||||||
|
try {
|
||||||
|
await customerService.update(IdMap.getId("testCustomer"), {
|
||||||
|
metadata: "Nononono",
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.message).toEqual("Use setMetadata to update metadata fields")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fails if billing address updates are attempted", async () => {
|
||||||
|
try {
|
||||||
|
await customerService.update(IdMap.getId("testCustomer"), {
|
||||||
|
billing_address: {
|
||||||
|
last_name: "nnonono",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.message).toEqual(
|
||||||
|
"Use updateBillingAddress to update billing address"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("updateEmail", () => {
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("successfully updates an email", async () => {
|
||||||
|
await customerService.updateEmail(
|
||||||
|
IdMap.getId("testCustomer"),
|
||||||
|
"oliver@medusa2.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(CustomerModelMock.updateOne).toHaveBeenCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.updateOne).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
_id: IdMap.getId("testCustomer"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: { email: "oliver@medusa2.com" },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("throws on invalid email", async () => {
|
||||||
|
try {
|
||||||
|
await customerService.updateEmail(
|
||||||
|
IdMap.getId("testCustomer"),
|
||||||
|
"olivermedusa"
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.message).toEqual("The email is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(CustomerModelMock.updateOne).toHaveBeenCalledTimes(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("updateBillingAddress", () => {
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("successfully updates billing address", async () => {
|
||||||
|
await customerService.updateBillingAddress(
|
||||||
|
IdMap.getId("testCustomer"),
|
||||||
|
{
|
||||||
|
first_name: "Olli",
|
||||||
|
last_name: "Juhl",
|
||||||
|
address_1: "Laksegade",
|
||||||
|
city: "Copenhagen",
|
||||||
|
country_code: "DK",
|
||||||
|
postal_code: "2100",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(CustomerModelMock.updateOne).toHaveBeenCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.updateOne).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
_id: IdMap.getId("testCustomer"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
billing_address: {
|
||||||
|
first_name: "Olli",
|
||||||
|
last_name: "Juhl",
|
||||||
|
address_1: "Laksegade",
|
||||||
|
city: "Copenhagen",
|
||||||
|
country_code: "DK",
|
||||||
|
postal_code: "2100",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("throws on invalid address", async () => {
|
||||||
|
try {
|
||||||
|
await customerService.updateBillingAddress(
|
||||||
|
IdMap.getId("testCustomer"),
|
||||||
|
{
|
||||||
|
first_name: 1234,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.message).toEqual("The address is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(CustomerModelMock.updateOne).toHaveBeenCalledTimes(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe("delete", () => {
|
||||||
|
const customerService = new CustomerService({
|
||||||
|
customerModel: CustomerModelMock,
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("deletes customer successfully", async () => {
|
||||||
|
await customerService.delete(IdMap.getId("deleteId"))
|
||||||
|
|
||||||
|
expect(CustomerModelMock.deleteOne).toBeCalledTimes(1)
|
||||||
|
expect(CustomerModelMock.deleteOne).toBeCalledWith({
|
||||||
|
_id: IdMap.getId("deleteId"),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -167,7 +167,7 @@ class CartService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async decorate(cart, fields, expandFields = []) {
|
async decorate(cart, fields, expandFields = []) {
|
||||||
const requiredFields = ["_id", "metadata"]
|
const requiredFields = ["_id", "metadata"]
|
||||||
const decorated = _.pick(product, fields.concat(requiredFields))
|
const decorated = _.pick(cart, fields.concat(requiredFields))
|
||||||
return decorated
|
return decorated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
260
packages/medusa/src/services/customer.js
Normal file
260
packages/medusa/src/services/customer.js
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import mongoose from "mongoose"
|
||||||
|
import _ from "lodash"
|
||||||
|
import { Validator, MedusaError } from "medusa-core-utils"
|
||||||
|
import { BaseService } from "medusa-interfaces"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides layer to manipulate customers.
|
||||||
|
* @implements BaseService
|
||||||
|
*/
|
||||||
|
class CustomerService extends BaseService {
|
||||||
|
constructor({ customerModel, eventBusService }) {
|
||||||
|
super()
|
||||||
|
|
||||||
|
/** @private @const {CustomerModel} */
|
||||||
|
this.customerModel_ = customerModel
|
||||||
|
|
||||||
|
/** @private @const {EventBus} */
|
||||||
|
this.eventBus_ = eventBusService
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to validate customer ids. Throws an error if the cast fails
|
||||||
|
* @param {string} rawId - the raw customer id to validate.
|
||||||
|
* @return {string} the validated id
|
||||||
|
*/
|
||||||
|
validateId_(rawId) {
|
||||||
|
const schema = Validator.objectId()
|
||||||
|
const { value, error } = schema.validate(rawId)
|
||||||
|
if (error) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_ARGUMENT,
|
||||||
|
"The customerId could not be casted to an ObjectId"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to validate customer email.
|
||||||
|
* @param {string} email - email to validate
|
||||||
|
* @return {string} the validated email
|
||||||
|
*/
|
||||||
|
validateEmail_(email) {
|
||||||
|
const schema = Validator.string()
|
||||||
|
.email()
|
||||||
|
.required()
|
||||||
|
const { value, error } = schema.validate(email)
|
||||||
|
if (error) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
"The email is not valid"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
validateBillingAddress_(address) {
|
||||||
|
const { value, error } = Validator.address().validate(address)
|
||||||
|
if (error) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
"The address is not valid"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} selector - the query object for find
|
||||||
|
* @return {Promise} the result of the find operation
|
||||||
|
*/
|
||||||
|
list(selector) {
|
||||||
|
return this.customerModel_.find(selector)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a customer by id.
|
||||||
|
* @param {string} customerId - the id of the customer to get.
|
||||||
|
* @return {Promise<Customer>} the customer document.
|
||||||
|
*/
|
||||||
|
retrieve(customerId) {
|
||||||
|
const validatedId = this.validateId_(customerId)
|
||||||
|
return this.customerModel_.findOne({ _id: validatedId }).catch(err => {
|
||||||
|
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a customer with email and billing address
|
||||||
|
* (if provided) being validated.
|
||||||
|
* @param {object} customer - the customer to create
|
||||||
|
* @return {Promise} the result of create
|
||||||
|
*/
|
||||||
|
create(customer) {
|
||||||
|
const { email, billing_address } = customer
|
||||||
|
this.validateEmail_(email)
|
||||||
|
if (billing_address) {
|
||||||
|
this.validateBillingAddress_(billing_address)
|
||||||
|
}
|
||||||
|
this.customerModel_.create(customer).catch(err => {
|
||||||
|
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email of a customer
|
||||||
|
* @param {string} customerId - the id of the customer to update
|
||||||
|
* @param {string} email - the email to add to customer
|
||||||
|
* @return {Promise} the result of the update operation
|
||||||
|
*/
|
||||||
|
async updateEmail(customerId, email) {
|
||||||
|
const customer = await this.retrieve(customerId)
|
||||||
|
if (!customer) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Customer with ${customerId} was not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.validateEmail_(email)
|
||||||
|
|
||||||
|
return this.customerModel_.updateOne(
|
||||||
|
{
|
||||||
|
_id: customerId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: { email },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the billing address of a customer
|
||||||
|
* @param {*} customerId - the customer to update address on
|
||||||
|
* @param {*} address - the new address to replace the current one
|
||||||
|
* @return {Promise} the result of the update operation
|
||||||
|
*/
|
||||||
|
async updateBillingAddress(customerId, address) {
|
||||||
|
const customer = await this.retrieve(customerId)
|
||||||
|
if (!customer) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Customer with ${customerId} was not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.validateBillingAddress_(address)
|
||||||
|
|
||||||
|
return this.customerModel_.updateOne(
|
||||||
|
{
|
||||||
|
_id: customerId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: { billing_address: address },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a customer. Metadata updates and address updates should
|
||||||
|
* use dedicated methods, e.g. `setMetadata`, etc. The function
|
||||||
|
* will throw errors if metadata updates and address updates are attempted.
|
||||||
|
* @param {string} variantId - the id of the variant. Must be a string that
|
||||||
|
* can be casted to an ObjectId
|
||||||
|
* @param {object} update - an object with the update values.
|
||||||
|
* @return {Promise} resolves to the update result.
|
||||||
|
*/
|
||||||
|
async update(customerId, update) {
|
||||||
|
const customer = await this.retrieve(customerId)
|
||||||
|
if (!customer) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Customer with ${customerId} was not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update.metadata) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
"Use setMetadata to update metadata fields"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update.billing_address) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
"Use updateBillingAddress to update billing address"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.customerModel_
|
||||||
|
.updateOne({ _id: customerId }, { $set: update }, { runValidators: true })
|
||||||
|
.catch(err => {
|
||||||
|
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a customer from a given customer id.
|
||||||
|
* @param {string} customerId - the id of the customer to delete. Must be
|
||||||
|
* castable as an ObjectId
|
||||||
|
* @return {Promise} the result of the delete operation.
|
||||||
|
*/
|
||||||
|
async delete(customerId) {
|
||||||
|
const customer = await this.retrieve(customerId)
|
||||||
|
// Delete is idempotent, but we return a promise to allow then-chaining
|
||||||
|
if (!customer) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.customerModel_.deleteOne({ _id: customer._id }).catch(err => {
|
||||||
|
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates a customer.
|
||||||
|
* @param {Customer} customer - the cart to decorate.
|
||||||
|
* @param {string[]} fields - the fields to include.
|
||||||
|
* @param {string[]} expandFields - fields to expand.
|
||||||
|
* @return {Customer} return the decorated customer.
|
||||||
|
*/
|
||||||
|
async decorate(customer, fields, expandFields = []) {
|
||||||
|
const requiredFields = ["_id", "metadata"]
|
||||||
|
const decorated = _.pick(customer, fields.concat(requiredFields))
|
||||||
|
return decorated
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dedicated method to set metadata for a customer.
|
||||||
|
* To ensure that plugins does not overwrite each
|
||||||
|
* others metadata fields, setMetadata is provided.
|
||||||
|
* @param {string} customerId - the customer to apply metadata to.
|
||||||
|
* @param {string} key - key for metadata field
|
||||||
|
* @param {string} value - value for metadata field.
|
||||||
|
* @return {Promise} resolves to the updated result.
|
||||||
|
*/
|
||||||
|
setMetadata(customerId, key, value) {
|
||||||
|
const validatedId = this.validateId_(customerId)
|
||||||
|
|
||||||
|
if (typeof key !== "string") {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_ARGUMENT,
|
||||||
|
"Key type is invalid. Metadata keys must be strings"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyPath = `metadata.${key}`
|
||||||
|
return this.customerModel_
|
||||||
|
.updateOne({ _id: validatedId }, { $set: { [keyPath]: value } })
|
||||||
|
.catch(err => {
|
||||||
|
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomerService
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user