Merge branch 'release/next'
This commit is contained in:
135
integration-tests/api/__tests__/admin/customer.js
Normal file
135
integration-tests/api/__tests__/admin/customer.js
Normal file
@@ -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",
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
27
integration-tests/api/helpers/customer-seeder.js
Normal file
27
integration-tests/api/helpers/customer-seeder.js
Normal file
@@ -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",
|
||||
});
|
||||
};
|
||||
19
integration-tests/api/src/services/test-not.js
Normal file
19
integration-tests/api/src/services/test-not.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { NotificationService } from "medusa-interfaces";
|
||||
|
||||
class TestNotiService extends NotificationService {
|
||||
static identifier = "test-not";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async sendNotification() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async resendNotification() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export default TestNotiService;
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.3](https://github.com/medusajs/medusa/compare/medusa-fulfillment-webshipper@1.1.3-next.0...medusa-fulfillment-webshipper@1.1.3) (2021-02-25)
|
||||
|
||||
**Note:** Version bump only for package medusa-fulfillment-webshipper
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.3-next.0](https://github.com/medusajs/medusa/compare/medusa-fulfillment-webshipper@1.1.2...medusa-fulfillment-webshipper@1.1.3-next.0) (2021-02-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **medusa:** tracking links ([#177](https://github.com/medusajs/medusa/issues/177)) ([99ad43b](https://github.com/medusajs/medusa/commit/99ad43bf47c3922f391d433448b1c4affd88f457))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.2](https://github.com/medusajs/medusa/compare/medusa-fulfillment-webshipper@1.1.1...medusa-fulfillment-webshipper@1.1.2) (2021-02-17)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "medusa-fulfillment-webshipper",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.3",
|
||||
"description": "Webshipper Fulfillment provider for Medusa",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
import WebshipperFulfillmentService from "../webshipper-fulfillment"
|
||||
|
||||
describe("WebshipperFulfillmentService", () => {
|
||||
const orderService = {
|
||||
createShipment: jest.fn(),
|
||||
}
|
||||
const swapService = {
|
||||
createShipment: jest.fn(),
|
||||
}
|
||||
const claimService = {
|
||||
createShipment: jest.fn(),
|
||||
}
|
||||
|
||||
describe("handleWebhook", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("creates an order shipment", async () => {
|
||||
const webshipper = new WebshipperFulfillmentService(
|
||||
{
|
||||
orderService,
|
||||
claimService,
|
||||
swapService,
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
||||
webshipper.retrieveRelationship = () => {
|
||||
return {
|
||||
data: {
|
||||
attributes: {
|
||||
ext_ref: "order_test.ful_test",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
attributes: {
|
||||
tracking_links: [
|
||||
{
|
||||
url: "https://test/1134",
|
||||
number: "12324245345",
|
||||
},
|
||||
{
|
||||
url: "https://test/1234",
|
||||
number: "12324245345",
|
||||
},
|
||||
],
|
||||
},
|
||||
relationships: {
|
||||
order: {
|
||||
id: "order",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
await webshipper.handleWebhook("", body)
|
||||
|
||||
expect(claimService.createShipment).toHaveBeenCalledTimes(0)
|
||||
expect(swapService.createShipment).toHaveBeenCalledTimes(0)
|
||||
|
||||
expect(orderService.createShipment).toHaveBeenCalledTimes(1)
|
||||
expect(orderService.createShipment).toHaveBeenCalledWith(
|
||||
"order_test",
|
||||
"ful_test",
|
||||
[
|
||||
{
|
||||
url: "https://test/1134",
|
||||
tracking_number: "12324245345",
|
||||
},
|
||||
{
|
||||
url: "https://test/1234",
|
||||
tracking_number: "12324245345",
|
||||
},
|
||||
]
|
||||
)
|
||||
})
|
||||
|
||||
it("creates a claim shipment", async () => {
|
||||
const webshipper = new WebshipperFulfillmentService(
|
||||
{
|
||||
orderService,
|
||||
claimService,
|
||||
swapService,
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
||||
webshipper.retrieveRelationship = () => {
|
||||
return {
|
||||
data: {
|
||||
attributes: {
|
||||
ext_ref: "claim_test.ful_test",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
attributes: {
|
||||
tracking_links: [
|
||||
{
|
||||
url: "https://test/1134",
|
||||
number: "12324245345",
|
||||
},
|
||||
{
|
||||
url: "https://test/1234",
|
||||
number: "12324245345",
|
||||
},
|
||||
],
|
||||
},
|
||||
relationships: {
|
||||
order: {
|
||||
id: "order",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
await webshipper.handleWebhook("", body)
|
||||
|
||||
expect(orderService.createShipment).toHaveBeenCalledTimes(0)
|
||||
expect(swapService.createShipment).toHaveBeenCalledTimes(0)
|
||||
|
||||
expect(claimService.createShipment).toHaveBeenCalledTimes(1)
|
||||
expect(claimService.createShipment).toHaveBeenCalledWith(
|
||||
"claim_test",
|
||||
"ful_test",
|
||||
[
|
||||
{
|
||||
url: "https://test/1134",
|
||||
tracking_number: "12324245345",
|
||||
},
|
||||
{
|
||||
url: "https://test/1234",
|
||||
tracking_number: "12324245345",
|
||||
},
|
||||
]
|
||||
)
|
||||
})
|
||||
|
||||
it("creates a swap shipment", async () => {
|
||||
const webshipper = new WebshipperFulfillmentService(
|
||||
{
|
||||
orderService,
|
||||
claimService,
|
||||
swapService,
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
||||
webshipper.retrieveRelationship = () => {
|
||||
return {
|
||||
data: {
|
||||
attributes: {
|
||||
ext_ref: "swap_test.ful_test",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
attributes: {
|
||||
tracking_links: [
|
||||
{
|
||||
url: "https://test/1134",
|
||||
number: "12324245345",
|
||||
},
|
||||
{
|
||||
url: "https://test/1234",
|
||||
number: "12324245345",
|
||||
},
|
||||
],
|
||||
},
|
||||
relationships: {
|
||||
order: {
|
||||
id: "order",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
await webshipper.handleWebhook("", body)
|
||||
|
||||
expect(orderService.createShipment).toHaveBeenCalledTimes(0)
|
||||
expect(claimService.createShipment).toHaveBeenCalledTimes(0)
|
||||
|
||||
expect(swapService.createShipment).toHaveBeenCalledTimes(1)
|
||||
expect(swapService.createShipment).toHaveBeenCalledWith(
|
||||
"swap_test",
|
||||
"ful_test",
|
||||
[
|
||||
{
|
||||
url: "https://test/1134",
|
||||
tracking_number: "12324245345",
|
||||
},
|
||||
{
|
||||
url: "https://test/1234",
|
||||
tracking_number: "12324245345",
|
||||
},
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -363,9 +363,10 @@ class WebshipperFulfillmentService extends FulfillmentService {
|
||||
body.data.relationships.order
|
||||
)
|
||||
if (wsOrder.data && wsOrder.data.attributes.ext_ref) {
|
||||
const trackingNumbers = body.data.attributes.tracking_links.map(
|
||||
(l) => l.number
|
||||
)
|
||||
const trackingLinks = body.data.attributes.tracking_links.map((l) => ({
|
||||
url: l.url,
|
||||
tracking_number: l.number,
|
||||
}))
|
||||
const [orderId, fulfillmentIndex] = wsOrder.data.attributes.ext_ref.split(
|
||||
"."
|
||||
)
|
||||
@@ -375,7 +376,7 @@ class WebshipperFulfillmentService extends FulfillmentService {
|
||||
return this.swapService_.createShipment(
|
||||
orderId,
|
||||
fulfillmentIndex,
|
||||
trackingNumbers
|
||||
trackingLinks
|
||||
)
|
||||
} else {
|
||||
const swap = await this.swapService_.retrieve(orderId.substring(1), {
|
||||
@@ -385,21 +386,21 @@ class WebshipperFulfillmentService extends FulfillmentService {
|
||||
return this.swapService_.createShipment(
|
||||
swap.id,
|
||||
fulfillment.id,
|
||||
trackingNumbers
|
||||
trackingLinks
|
||||
)
|
||||
}
|
||||
} else if (orderId.charAt(0).toLowerCase() === "c") {
|
||||
return this.claimService_.createShipment(
|
||||
orderId,
|
||||
fulfillmentIndex,
|
||||
trackingNumbers
|
||||
trackingLinks
|
||||
)
|
||||
} else {
|
||||
if (fulfillmentIndex.startsWith("ful")) {
|
||||
return this.orderService_.createShipment(
|
||||
orderId,
|
||||
fulfillmentIndex,
|
||||
trackingNumbers
|
||||
trackingLinks
|
||||
)
|
||||
} else {
|
||||
const order = await this.orderService_.retrieve(orderId, {
|
||||
@@ -411,7 +412,7 @@ class WebshipperFulfillmentService extends FulfillmentService {
|
||||
return this.orderService_.createShipment(
|
||||
order.id,
|
||||
fulfillment.id,
|
||||
trackingNumbers
|
||||
trackingLinks
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/medusajs/medusa/compare/medusa-plugin-brightpearl@1.1.4...medusa-plugin-brightpearl@1.1.5) (2021-02-25)
|
||||
|
||||
**Note:** Version bump only for package medusa-plugin-brightpearl
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.4](https://github.com/medusajs/medusa/compare/medusa-plugin-brightpearl@1.1.3...medusa-plugin-brightpearl@1.1.4) (2021-02-17)
|
||||
|
||||
**Note:** Version bump only for package medusa-plugin-brightpearl
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "medusa-plugin-brightpearl",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"description": "Brightpearl plugin for Medusa Commerce",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.4](https://github.com/medusajs/medusa/compare/medusa-plugin-contentful@1.1.3...medusa-plugin-contentful@1.1.4) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **medusa-plugin-contentful:** Allow custom fields in plugin options ([#180](https://github.com/medusajs/medusa/issues/180)) ([587a464](https://github.com/medusajs/medusa/commit/587a464e83576833ff616bde7bb26b1bb48472fe))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.3](https://github.com/medusajs/medusa/compare/medusa-plugin-contentful@1.1.2...medusa-plugin-contentful@1.1.3) (2021-02-17)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "medusa-plugin-contentful",
|
||||
"version": "1.1.3",
|
||||
"version": "1.1.4",
|
||||
"description": "Contentful plugin for Medusa Commerce",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
||||
@@ -19,8 +19,16 @@ const checkContentTypes = async (container) => {
|
||||
if (product && product.fields) {
|
||||
const productFields = product.fields
|
||||
|
||||
const customProductFields = Object.keys(
|
||||
contentfulService.options_.custom_product_fields || {}
|
||||
)
|
||||
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(
|
||||
`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) {
|
||||
const variantFields = variant.fields
|
||||
|
||||
const customVariantFields = Object.keys(
|
||||
contentfulService.options_.custom_variant_fields || {}
|
||||
)
|
||||
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(
|
||||
`Contentful: Content type ${`productVariant`} is missing some required key(s). Required: ${requiredVariantFields.join(
|
||||
", "
|
||||
@@ -47,13 +63,13 @@ const requiredProductFields = [
|
||||
"title",
|
||||
"variants",
|
||||
"options",
|
||||
"objectId",
|
||||
"medusaId",
|
||||
"type",
|
||||
"collection",
|
||||
"tags",
|
||||
"handle",
|
||||
]
|
||||
|
||||
const requiredVariantFields = ["title", "sku", "prices", "options", "objectId"]
|
||||
const requiredVariantFields = ["title", "sku", "prices", "options", "medusaId"]
|
||||
|
||||
export default checkContentTypes
|
||||
|
||||
@@ -111,10 +111,27 @@ class ContentfulService extends BaseService {
|
||||
return assets
|
||||
}
|
||||
|
||||
getCustomField(field, type) {
|
||||
const customOptions = this.options_[`custom_${type}_fields`]
|
||||
|
||||
if (customOptions) {
|
||||
return customOptions[field] || field
|
||||
} else {
|
||||
return field
|
||||
}
|
||||
}
|
||||
|
||||
async createProductInContentful(product) {
|
||||
try {
|
||||
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_()
|
||||
@@ -122,46 +139,92 @@ class ContentfulService extends BaseService {
|
||||
const variantLinks = this.getVariantLinks_(variantEntries)
|
||||
|
||||
const fields = {
|
||||
title: {
|
||||
[this.getCustomField("title", "product")]: {
|
||||
"en-US": p.title,
|
||||
},
|
||||
variants: {
|
||||
[this.getCustomField("variants", "product")]: {
|
||||
"en-US": variantLinks,
|
||||
},
|
||||
options: {
|
||||
[this.getCustomField("options", "product")]: {
|
||||
"en-US": p.options,
|
||||
},
|
||||
objectId: {
|
||||
[this.getCustomField("medusaId", "product")]: {
|
||||
"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) {
|
||||
const type = {
|
||||
"en-US": p.type.value,
|
||||
}
|
||||
fields.type = type
|
||||
|
||||
fields[this.getCustomField("type", "product")] = type
|
||||
}
|
||||
|
||||
if (p.collection) {
|
||||
const collection = {
|
||||
"en-US": p.collection.title,
|
||||
}
|
||||
fields.collection = collection
|
||||
|
||||
fields[this.getCustomField("collection", "product")] = collection
|
||||
}
|
||||
|
||||
if (p.tags) {
|
||||
const tags = {
|
||||
"en-US": p.tags,
|
||||
}
|
||||
fields.tags = tags
|
||||
|
||||
fields[this.getCustomField("tags", "product")] = tags
|
||||
}
|
||||
|
||||
if (p.handle) {
|
||||
const handle = {
|
||||
"en-US": p.handle,
|
||||
}
|
||||
fields.handle = handle
|
||||
|
||||
fields[this.getCustomField("handle", "product")] = handle
|
||||
}
|
||||
|
||||
const result = await environment.createEntryWithId("product", p.id, {
|
||||
@@ -189,19 +252,19 @@ class ContentfulService extends BaseService {
|
||||
v.id,
|
||||
{
|
||||
fields: {
|
||||
title: {
|
||||
[this.getCustomField("title", "variant")]: {
|
||||
"en-US": v.title,
|
||||
},
|
||||
sku: {
|
||||
[this.getCustomField("sku", "variant")]: {
|
||||
"en-US": v.sku,
|
||||
},
|
||||
prices: {
|
||||
[this.getCustomField("prices", "variant")]: {
|
||||
"en-US": v.prices,
|
||||
},
|
||||
options: {
|
||||
[this.getCustomField("options", "variant")]: {
|
||||
"en-US": v.options,
|
||||
},
|
||||
objectId: {
|
||||
[this.getCustomField("medusaId", "variant")]: {
|
||||
"en-US": v.id,
|
||||
},
|
||||
},
|
||||
@@ -240,7 +303,14 @@ class ContentfulService extends BaseService {
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -248,46 +318,86 @@ class ContentfulService extends BaseService {
|
||||
|
||||
const productEntryFields = {
|
||||
...productEntry.fields,
|
||||
title: {
|
||||
[this.getCustomField("title", "product")]: {
|
||||
"en-US": p.title,
|
||||
},
|
||||
options: {
|
||||
[this.getCustomField("options", "product")]: {
|
||||
"en-US": p.options,
|
||||
},
|
||||
variants: {
|
||||
[this.getCustomField("variants", "product")]: {
|
||||
"en-US": variantLinks,
|
||||
},
|
||||
objectId: {
|
||||
[this.getCustomField("medusaId", "product")]: {
|
||||
"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) {
|
||||
const type = {
|
||||
"en-US": p.type.value,
|
||||
}
|
||||
productEntryFields.type = type
|
||||
|
||||
productEntryFields[this.getCustomField("type", "product")] = type
|
||||
}
|
||||
|
||||
if (p.collection) {
|
||||
const collection = {
|
||||
"en-US": p.collection.title,
|
||||
}
|
||||
productEntryFields.collection = collection
|
||||
|
||||
productEntryFields[
|
||||
this.getCustomField("collection", "product")
|
||||
] = collection
|
||||
}
|
||||
|
||||
if (p.tags) {
|
||||
const tags = {
|
||||
"en-US": p.tags,
|
||||
}
|
||||
productEntryFields.tags = tags
|
||||
|
||||
productEntryFields[this.getCustomField("tags", "product")] = tags
|
||||
}
|
||||
|
||||
if (p.handle) {
|
||||
const handle = {
|
||||
"en-US": p.handle,
|
||||
}
|
||||
productEntryFields.handle = handle
|
||||
|
||||
productEntryFields[this.getCustomField("handle", "product")] = handle
|
||||
}
|
||||
|
||||
productEntry.fields = productEntryFields
|
||||
@@ -333,19 +443,19 @@ class ContentfulService extends BaseService {
|
||||
|
||||
const variantEntryFields = {
|
||||
...variantEntry.fields,
|
||||
title: {
|
||||
[this.getCustomField("title", "variant")]: {
|
||||
"en-US": v.title,
|
||||
},
|
||||
sku: {
|
||||
[this.getCustomField("sku", "variant")]: {
|
||||
"en-US": v.sku,
|
||||
},
|
||||
options: {
|
||||
[this.getCustomField("options", "variant")]: {
|
||||
"en-US": v.options,
|
||||
},
|
||||
prices: {
|
||||
[this.getCustomField("prices", "variant")]: {
|
||||
"en-US": v.prices,
|
||||
},
|
||||
objectId: {
|
||||
[this.getCustomField("medusaId", "variant")]: {
|
||||
"en-US": v.id,
|
||||
},
|
||||
}
|
||||
@@ -377,7 +487,8 @@ class ContentfulService extends BaseService {
|
||||
}
|
||||
|
||||
let update = {
|
||||
title: productEntry.fields.title["en-US"],
|
||||
title:
|
||||
productEntry.fields[this.getCustomField("title", "product")]["en-US"],
|
||||
}
|
||||
|
||||
// Get the thumbnail, if present
|
||||
@@ -421,7 +532,10 @@ class ContentfulService extends BaseService {
|
||||
const updatedVariant = await this.productVariantService_.update(
|
||||
variantId,
|
||||
{
|
||||
title: variantEntry.fields.title["en-US"],
|
||||
title:
|
||||
variantEntry.fields[this.getCustomField("title", "variant")][
|
||||
"en-US"
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,59 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/medusajs/medusa/compare/medusa-plugin-segment@1.1.5-next.3...medusa-plugin-segment@1.1.5) (2021-02-25)
|
||||
|
||||
**Note:** Version bump only for package medusa-plugin-segment
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.5-next.3](https://github.com/medusajs/medusa/compare/medusa-plugin-segment@1.1.5-next.2...medusa-plugin-segment@1.1.5-next.3) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* normalize currency code ([98aa404](https://github.com/medusajs/medusa/commit/98aa404306d55f0818d48e56c51146351ebfe306))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.5-next.2](https://github.com/medusajs/medusa/compare/medusa-plugin-segment@1.1.5-next.1...medusa-plugin-segment@1.1.5-next.2) (2021-02-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **segment:** track shipments ([d156911](https://github.com/medusajs/medusa/commit/d15691188348c19fc22806d8cf7584fc5f249ce9))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.5-next.1](https://github.com/medusajs/medusa/compare/medusa-plugin-segment@1.1.5-next.0...medusa-plugin-segment@1.1.5-next.1) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add subtitle to tracks ([0c294b7](https://github.com/medusajs/medusa/commit/0c294b7b3acbc1b873aab7e90a8e596bdac48899))
|
||||
* versioning ([262af34](https://github.com/medusajs/medusa/commit/262af34125543d9a80bf469b5d380019b9bc8d3f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.5-next.0](https://github.com/medusajs/medusa/compare/medusa-plugin-segment@1.1.4...medusa-plugin-segment@1.1.5-next.0) (2021-02-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **medusa-plugin-segment:** adds category and type to segment events ([#179](https://github.com/medusajs/medusa/issues/179)) ([e27cf72](https://github.com/medusajs/medusa/commit/e27cf72a8ca49a6586a82dde964d559c40a4415f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.4](https://github.com/medusajs/medusa/compare/medusa-plugin-segment@1.1.3...medusa-plugin-segment@1.1.4) (2021-02-17)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "medusa-plugin-segment",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"description": "Segment Analytics",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -42,5 +42,5 @@
|
||||
"medusa-core-utils": "^1.1.0",
|
||||
"medusa-test-utils": "^1.1.3"
|
||||
},
|
||||
"gitHead": "0646bd395a6056657cb0aa93c13699c4a9dbbcdd"
|
||||
"gitHead": "0c294b7b3acbc1b873aab7e90a8e596bdac48899"
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@ class SegmentService extends BaseService {
|
||||
* write_key: Segment write key given in Segment dashboard
|
||||
* }
|
||||
*/
|
||||
constructor({ totalsService }, options) {
|
||||
constructor({ totalsService, productService }, options) {
|
||||
super()
|
||||
|
||||
this.totalsService_ = totalsService
|
||||
this.options_ = options
|
||||
this.productService_ = productService
|
||||
|
||||
this.analytics_ = new Analytics(options.write_key)
|
||||
}
|
||||
@@ -102,7 +103,7 @@ class SegmentService extends BaseService {
|
||||
tax,
|
||||
discount,
|
||||
coupon,
|
||||
currency: order.currency_code,
|
||||
currency: order.currency_code.toUpperCase(),
|
||||
products: await Promise.all(
|
||||
order.items.map(async (item) => {
|
||||
let name = item.title
|
||||
@@ -129,12 +130,20 @@ class SegmentService extends BaseService {
|
||||
variant = item.variant.sku
|
||||
}
|
||||
|
||||
const product = await this.productService_.retrieve(
|
||||
item.variant.product_id,
|
||||
{ relations: ["collection", "type"] }
|
||||
)
|
||||
|
||||
return {
|
||||
name,
|
||||
variant,
|
||||
price: lineTotal / 100 / item.quantity,
|
||||
reporting_revenue: revenue,
|
||||
product_id: item.variant.product_id,
|
||||
category: product.collection?.title,
|
||||
subtitle: product.subtitle,
|
||||
type: product.type?.value,
|
||||
sku,
|
||||
quantity: item.quantity,
|
||||
}
|
||||
|
||||
@@ -5,12 +5,76 @@ class OrderSubscriber {
|
||||
orderService,
|
||||
claimService,
|
||||
returnService,
|
||||
fulfillmentService,
|
||||
}) {
|
||||
this.orderService_ = orderService
|
||||
|
||||
this.returnService_ = returnService
|
||||
|
||||
this.claimService_ = claimService
|
||||
this.fulfillmentService_ = fulfillmentService
|
||||
|
||||
eventBusService.subscribe(
|
||||
"order.shipment_created",
|
||||
async ({ id, fulfillment_id }) => {
|
||||
const order = await this.orderService_.retrieve(id, {
|
||||
select: [
|
||||
"shipping_total",
|
||||
"discount_total",
|
||||
"tax_total",
|
||||
"refunded_total",
|
||||
"gift_card_total",
|
||||
"subtotal",
|
||||
"total",
|
||||
],
|
||||
relations: [
|
||||
"customer",
|
||||
"billing_address",
|
||||
"shipping_address",
|
||||
"discounts",
|
||||
"shipping_methods",
|
||||
"payments",
|
||||
"fulfillments",
|
||||
"returns",
|
||||
"items",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
"swaps",
|
||||
"swaps.return_order",
|
||||
"swaps.payment",
|
||||
"swaps.shipping_methods",
|
||||
"swaps.shipping_address",
|
||||
"swaps.additional_items",
|
||||
"swaps.fulfillments",
|
||||
],
|
||||
})
|
||||
|
||||
const fulfillment = await this.fulfillmentService_.retrieve(
|
||||
fulfillment_id,
|
||||
{
|
||||
relations: ["items"],
|
||||
}
|
||||
)
|
||||
|
||||
const toBuildFrom = {
|
||||
...order,
|
||||
provider_id: fulfillment.provider,
|
||||
items: fulfillment.items.map((i) =>
|
||||
order.items.find((l) => l.id === i.item_id)
|
||||
),
|
||||
}
|
||||
|
||||
const orderData = await segmentService.buildOrder(toBuildFrom)
|
||||
const orderEvent = {
|
||||
event: "Order Shipped",
|
||||
userId: order.customer_id,
|
||||
properties: orderData,
|
||||
timestamp: fulfillment.shipped_at,
|
||||
}
|
||||
|
||||
segmentService.track(orderEvent)
|
||||
}
|
||||
)
|
||||
|
||||
eventBusService.subscribe("claim.created", async ({ id }) => {
|
||||
const claim = await this.claimService_.retrieve(id, {
|
||||
@@ -74,6 +138,7 @@ class OrderSubscriber {
|
||||
"payments",
|
||||
"fulfillments",
|
||||
"returns",
|
||||
"items",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
"swaps",
|
||||
@@ -160,6 +225,7 @@ class OrderSubscriber {
|
||||
"shipping_methods",
|
||||
"payments",
|
||||
"fulfillments",
|
||||
"items",
|
||||
"returns",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.4](https://github.com/medusajs/medusa/compare/medusa-plugin-sendgrid@1.1.3...medusa-plugin-sendgrid@1.1.4) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add tracking links to shipments ([7be4bb5](https://github.com/medusajs/medusa/commit/7be4bb5f2daa0aad805abe0f97278f53cf3af402))
|
||||
* sendgrid tracking links ([5cfc8d8](https://github.com/medusajs/medusa/commit/5cfc8d80bd3eaee93595027d0cc3ce67ae98d275))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.3](https://github.com/medusajs/medusa/compare/medusa-plugin-sendgrid@1.1.2...medusa-plugin-sendgrid@1.1.3) (2021-02-17)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "medusa-plugin-sendgrid",
|
||||
"version": "1.1.3",
|
||||
"version": "1.1.4",
|
||||
"description": "SendGrid transactional emails",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
|
||||
@@ -275,7 +275,7 @@ class SendGridService extends NotificationService {
|
||||
})
|
||||
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id, {
|
||||
relations: ["items"],
|
||||
relations: ["items", "tracking_links"],
|
||||
})
|
||||
|
||||
return {
|
||||
@@ -283,6 +283,7 @@ class SendGridService extends NotificationService {
|
||||
date: shipment.shipped_at.toDateString(),
|
||||
email: order.email,
|
||||
fulfillment: shipment,
|
||||
tracking_links: shipment.tracking_links,
|
||||
tracking_number: shipment.tracking_numbers.join(", "),
|
||||
}
|
||||
}
|
||||
@@ -586,7 +587,9 @@ class SendGridService extends NotificationService {
|
||||
|
||||
const refundAmount = swap.return_order.refund_amount
|
||||
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id)
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id, {
|
||||
relations: ["tracking_links"],
|
||||
})
|
||||
|
||||
return {
|
||||
swap,
|
||||
@@ -602,6 +605,7 @@ class SendGridService extends NotificationService {
|
||||
refund_amount: `${this.humanPrice_(refundAmount)} ${currencyCode}`,
|
||||
additional_total: `${this.humanPrice_(additionalTotal)} ${currencyCode}`,
|
||||
fulfillment: shipment,
|
||||
tracking_links: shipment.tracking_links,
|
||||
tracking_number: shipment.tracking_numbers.join(", "),
|
||||
}
|
||||
}
|
||||
@@ -611,13 +615,16 @@ class SendGridService extends NotificationService {
|
||||
relations: ["order", "order.items", "order.shipping_address"],
|
||||
})
|
||||
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id)
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id, {
|
||||
relations: ["tracking_links"],
|
||||
})
|
||||
|
||||
return {
|
||||
email: claim.order.email,
|
||||
claim,
|
||||
order: claim.order,
|
||||
fulfillment: shipment,
|
||||
tracking_links: shipment.tracking_links,
|
||||
tracking_number: shipment.tracking_numbers.join(", "),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,47 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.11](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.10...@medusajs/medusa@1.1.11) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **medusa:** Add querying func. on customer retrievals ([#181](https://github.com/medusajs/medusa/issues/181)) ([22be418](https://github.com/medusajs/medusa/commit/22be418ec132944afe469106ba4b3b92f634d240))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.10](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.10-next.1...@medusajs/medusa@1.1.10) (2021-02-25)
|
||||
|
||||
**Note:** Version bump only for package @medusajs/medusa
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.10-next.1](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.10-next.0...@medusajs/medusa@1.1.10-next.1) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update-product ([0320788](https://github.com/medusajs/medusa/commit/0320788aacf93da8a8951c6a540656da1772dba4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.10-next.0](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.9...@medusajs/medusa@1.1.10-next.0) (2021-02-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **medusa:** tracking links ([#177](https://github.com/medusajs/medusa/issues/177)) ([99ad43b](https://github.com/medusajs/medusa/commit/99ad43bf47c3922f391d433448b1c4affd88f457))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.9](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.8...@medusajs/medusa@1.1.9) (2021-02-18)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@medusajs/medusa",
|
||||
"version": "1.1.9",
|
||||
"version": "1.1.11",
|
||||
"description": "E-commerce for JAMstack",
|
||||
"main": "dist/index.js",
|
||||
"repository": {
|
||||
|
||||
@@ -2,18 +2,32 @@ export default async (req, res) => {
|
||||
try {
|
||||
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 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 = {
|
||||
relations: [],
|
||||
relations: expandFields.length ? expandFields : [],
|
||||
skip: offset,
|
||||
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) {
|
||||
throw error
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ const defaultRelations = [
|
||||
"shipping_methods",
|
||||
"payments",
|
||||
"fulfillments",
|
||||
"fulfillments.tracking_links",
|
||||
"fulfillments.items",
|
||||
"returns",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
|
||||
@@ -23,7 +23,7 @@ export default async (req, res) => {
|
||||
await claimService.createShipment(
|
||||
claim_id,
|
||||
value.fulfillment_id,
|
||||
value.tracking_numbers
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n }))
|
||||
)
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
|
||||
@@ -22,7 +22,7 @@ export default async (req, res) => {
|
||||
await orderService.createShipment(
|
||||
id,
|
||||
value.fulfillment_id,
|
||||
value.tracking_numbers
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n }))
|
||||
)
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
|
||||
@@ -23,7 +23,7 @@ export default async (req, res) => {
|
||||
await swapService.createShipment(
|
||||
swap_id,
|
||||
value.fulfillment_id,
|
||||
value.tracking_numbers
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n }))
|
||||
)
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
|
||||
@@ -188,6 +188,8 @@ export const defaultRelations = [
|
||||
"shipping_methods",
|
||||
"payments",
|
||||
"fulfillments",
|
||||
"fulfillments.tracking_links",
|
||||
"fulfillments.items",
|
||||
"returns",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
@@ -271,6 +273,7 @@ export const allowedRelations = [
|
||||
"shipping_methods",
|
||||
"payments",
|
||||
"fulfillments",
|
||||
"fulfillments.tracking_links",
|
||||
"returns",
|
||||
"claims",
|
||||
"swaps",
|
||||
|
||||
@@ -6,6 +6,9 @@ export default async (req, res) => {
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
title: Validator.string().optional(),
|
||||
subtitle: Validator.string()
|
||||
.optional()
|
||||
.allow(null, ""),
|
||||
description: Validator.string().optional(),
|
||||
type: Validator.object()
|
||||
.keys({
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class trackingLinks1613656135167 implements MigrationInterface {
|
||||
name = 'trackingLinks1613656135167'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "tracking_link" ("id" character varying NOT NULL, "url" character varying, "tracking_number" character varying NOT NULL, "fulfillment_id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deleted_at" TIMESTAMP WITH TIME ZONE, "metadata" jsonb, "idempotency_key" character varying, CONSTRAINT "PK_fcfd77feb9012ec2126d7c0bfb6" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`ALTER TABLE "tracking_link" ADD CONSTRAINT "FK_471e9e4c96e02ba209a307db32b" FOREIGN KEY ("fulfillment_id") REFERENCES "fulfillment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "tracking_link" DROP CONSTRAINT "FK_471e9e4c96e02ba209a307db32b"`);
|
||||
await queryRunner.query(`DROP TABLE "tracking_link"`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import { FulfillmentProvider } from "./fulfillment-provider"
|
||||
import { FulfillmentItem } from "./fulfillment-item"
|
||||
import { Swap } from "./swap"
|
||||
import { ClaimOrder } from "./claim-order"
|
||||
import { TrackingLink } from "./tracking-link"
|
||||
|
||||
@Entity()
|
||||
export class Fulfillment {
|
||||
@@ -76,6 +77,13 @@ export class Fulfillment {
|
||||
)
|
||||
items: FulfillmentItem[]
|
||||
|
||||
@OneToMany(
|
||||
() => TrackingLink,
|
||||
tl => tl.fulfillment,
|
||||
{ cascade: ["insert"] }
|
||||
)
|
||||
tracking_links: TrackingLink[]
|
||||
|
||||
@Column({ type: "jsonb", default: [] })
|
||||
tracking_numbers: string[]
|
||||
|
||||
|
||||
63
packages/medusa/src/models/tracking-link.ts
Normal file
63
packages/medusa/src/models/tracking-link.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
Entity,
|
||||
Index,
|
||||
BeforeInsert,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
PrimaryColumn,
|
||||
OneToOne,
|
||||
OneToMany,
|
||||
ManyToOne,
|
||||
ManyToMany,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
} from "typeorm"
|
||||
import { ulid } from "ulid"
|
||||
|
||||
import { Fulfillment } from "./fulfillment"
|
||||
|
||||
@Entity()
|
||||
export class TrackingLink {
|
||||
@PrimaryColumn()
|
||||
id: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
url: string
|
||||
|
||||
@Column()
|
||||
tracking_number: string
|
||||
|
||||
@Column()
|
||||
fulfillment_id: string
|
||||
|
||||
@ManyToOne(
|
||||
() => Fulfillment,
|
||||
ful => ful.tracking_links
|
||||
)
|
||||
@JoinColumn({ name: "fulfillment_id" })
|
||||
fulfillment: Fulfillment
|
||||
|
||||
@CreateDateColumn({ type: "timestamptz" })
|
||||
created_at: Date
|
||||
|
||||
@UpdateDateColumn({ type: "timestamptz" })
|
||||
updated_at: Date
|
||||
|
||||
@DeleteDateColumn({ type: "timestamptz" })
|
||||
deleted_at: Date
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
|
||||
@Column({ nullable: true })
|
||||
idempotency_key: string
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert() {
|
||||
if (this.id) return
|
||||
const id = ulid()
|
||||
this.id = `tlink_${id}`
|
||||
}
|
||||
}
|
||||
5
packages/medusa/src/repositories/tracking-link.ts
Normal file
5
packages/medusa/src/repositories/tracking-link.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
import { TrackingLink } from "../models/tracking-link"
|
||||
|
||||
@EntityRepository(TrackingLink)
|
||||
export class TrackingLinkRepository extends Repository<TrackingLink> {}
|
||||
@@ -95,6 +95,7 @@ describe("FulfillmentService", () => {
|
||||
})
|
||||
|
||||
describe("createShipment", () => {
|
||||
const trackingLinkRepository = MockRepository({ create: c => c })
|
||||
const fulfillmentRepository = MockRepository({
|
||||
findOne: () => Promise.resolve({ id: IdMap.getId("fulfillment") }),
|
||||
})
|
||||
@@ -102,6 +103,7 @@ describe("FulfillmentService", () => {
|
||||
const fulfillmentService = new FulfillmentService({
|
||||
manager: MockManager,
|
||||
fulfillmentRepository,
|
||||
trackingLinkRepository,
|
||||
})
|
||||
|
||||
const now = new Date()
|
||||
@@ -113,14 +115,17 @@ describe("FulfillmentService", () => {
|
||||
it("calls order model functions", async () => {
|
||||
await fulfillmentService.createShipment(
|
||||
IdMap.getId("fulfillment"),
|
||||
["1234", "2345"],
|
||||
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
|
||||
{}
|
||||
)
|
||||
|
||||
expect(fulfillmentRepository.save).toHaveBeenCalledTimes(1)
|
||||
expect(fulfillmentRepository.save).toHaveBeenCalledWith({
|
||||
id: IdMap.getId("fulfillment"),
|
||||
tracking_numbers: ["1234", "2345"],
|
||||
tracking_links: [
|
||||
{ tracking_number: "1234" },
|
||||
{ tracking_number: "2345" },
|
||||
],
|
||||
metadata: {},
|
||||
shipped_at: now,
|
||||
})
|
||||
|
||||
@@ -1182,14 +1182,14 @@ describe("OrderService", () => {
|
||||
await orderService.createShipment(
|
||||
IdMap.getId("test"),
|
||||
IdMap.getId("fulfillment"),
|
||||
["1234", "2345"],
|
||||
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
|
||||
{}
|
||||
)
|
||||
|
||||
expect(fulfillmentService.createShipment).toHaveBeenCalledTimes(1)
|
||||
expect(fulfillmentService.createShipment).toHaveBeenCalledWith(
|
||||
IdMap.getId("fulfillment"),
|
||||
["1234", "2345"],
|
||||
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
|
||||
{}
|
||||
)
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ class ClaimService extends BaseService {
|
||||
})
|
||||
}
|
||||
|
||||
async createShipment(id, fulfillmentId, trackingNumbers, metadata = []) {
|
||||
async createShipment(id, fulfillmentId, trackingLinks, metadata = []) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const claim = await this.retrieve(id, {
|
||||
relations: ["additional_items"],
|
||||
@@ -426,7 +426,7 @@ class ClaimService extends BaseService {
|
||||
|
||||
const shipment = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createShipment(fulfillmentId, trackingNumbers, metadata)
|
||||
.createShipment(fulfillmentId, trackingLinks, metadata)
|
||||
|
||||
claim.fulfillment_status = "shipped"
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import Scrypt from "scrypt-kdf"
|
||||
import _ from "lodash"
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
import { Brackets } from "typeorm"
|
||||
|
||||
/**
|
||||
* Provides layer to manipulate customers.
|
||||
@@ -132,6 +133,50 @@ class CustomerService extends BaseService {
|
||||
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 {Promise} the result of the count operation
|
||||
|
||||
@@ -11,6 +11,7 @@ class FulfillmentService extends BaseService {
|
||||
manager,
|
||||
totalsService,
|
||||
fulfillmentRepository,
|
||||
trackingLinkRepository,
|
||||
shippingProfileService,
|
||||
lineItemService,
|
||||
fulfillmentProviderService,
|
||||
@@ -26,6 +27,9 @@ class FulfillmentService extends BaseService {
|
||||
/** @private @const {FulfillmentRepository} */
|
||||
this.fulfillmentRepository_ = fulfillmentRepository
|
||||
|
||||
/** @private @const {TrackingLinkRepository} */
|
||||
this.trackingLinkRepository_ = trackingLinkRepository
|
||||
|
||||
/** @private @const {ShippingProfileService} */
|
||||
this.shippingProfileService_ = shippingProfileService
|
||||
|
||||
@@ -44,6 +48,7 @@ class FulfillmentService extends BaseService {
|
||||
const cloned = new FulfillmentService({
|
||||
manager: transactionManager,
|
||||
totalsService: this.totalsService_,
|
||||
trackingLinkRepository: this.trackingLinkRepository_,
|
||||
fulfillmentRepository: this.fulfillmentRepository_,
|
||||
shippingProfileService: this.shippingProfileService_,
|
||||
lineItemService: this.lineItemService_,
|
||||
@@ -235,15 +240,18 @@ class FulfillmentService extends BaseService {
|
||||
* Creates a shipment by marking a fulfillment as shipped. Adds
|
||||
* tracking numbers and potentially more metadata.
|
||||
* @param {Order} fulfillmentId - the fulfillment to ship
|
||||
* @param {string[]} trackingNumbers - tracking numbers for the shipment
|
||||
* @param {TrackingLink[]} trackingNumbers - tracking numbers for the shipment
|
||||
* @param {object} metadata - potential metadata to add
|
||||
* @return {Fulfillment} the shipped fulfillment
|
||||
*/
|
||||
async createShipment(fulfillmentId, trackingNumbers, metadata) {
|
||||
async createShipment(fulfillmentId, trackingLinks, metadata) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const fulfillmentRepository = manager.getCustomRepository(
|
||||
this.fulfillmentRepository_
|
||||
)
|
||||
const trackingLinkRepo = manager.getCustomRepository(
|
||||
this.trackingLinkRepository_
|
||||
)
|
||||
|
||||
const fulfillment = await this.retrieve(fulfillmentId, {
|
||||
relations: ["items"],
|
||||
@@ -251,7 +259,11 @@ class FulfillmentService extends BaseService {
|
||||
|
||||
const now = new Date()
|
||||
fulfillment.shipped_at = now
|
||||
fulfillment.tracking_numbers = trackingNumbers
|
||||
|
||||
fulfillment.tracking_links = trackingLinks.map(tl =>
|
||||
trackingLinkRepo.create(tl)
|
||||
)
|
||||
|
||||
fulfillment.metadata = {
|
||||
...fulfillment.metadata,
|
||||
...metadata,
|
||||
|
||||
@@ -553,13 +553,13 @@ class OrderService extends BaseService {
|
||||
* have been created in regards to the shipment.
|
||||
* @param {string} orderId - the id of the order that has been shipped
|
||||
* @param {string} fulfillmentId - the fulfillment that has now been shipped
|
||||
* @param {Array<String>} trackingNumbers - array of tracking numebers
|
||||
* @param {TrackingLink[]} trackingLinks - array of tracking numebers
|
||||
* associated with the shipment
|
||||
* @param {Dictionary<String, String>} metadata - optional metadata to add to
|
||||
* the fulfillment
|
||||
* @return {order} the resulting order following the update.
|
||||
*/
|
||||
async createShipment(orderId, fulfillmentId, trackingNumbers, metadata = {}) {
|
||||
async createShipment(orderId, fulfillmentId, trackingLinks, metadata = {}) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const order = await this.retrieve(orderId, { relations: ["items"] })
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillmentId)
|
||||
@@ -573,7 +573,7 @@ class OrderService extends BaseService {
|
||||
|
||||
const shipmentRes = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createShipment(fulfillmentId, trackingNumbers, metadata)
|
||||
.createShipment(fulfillmentId, trackingLinks, metadata)
|
||||
|
||||
order.fulfillment_status = "shipped"
|
||||
for (const item of order.items) {
|
||||
|
||||
@@ -671,12 +671,12 @@ class SwapService extends BaseService {
|
||||
* @param {string} swapId - the id of the swap that has been shipped.
|
||||
* @param {string} fulfillmentId - the id of the specific fulfillment that
|
||||
* has been shipped
|
||||
* @param {Array<string>} trackingNumbers - the tracking numbers associated
|
||||
* @param {TrackingLink[]} trackingLinks - the tracking numbers associated
|
||||
* with the shipment
|
||||
* @param {object} metadata - optional metadata to attach to the shipment.
|
||||
* @returns {Promise<Swap>} the updated swap with new fulfillments and status.
|
||||
*/
|
||||
async createShipment(swapId, fulfillmentId, trackingNumbers, metadata = {}) {
|
||||
async createShipment(swapId, fulfillmentId, trackingLinks, metadata = {}) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const swap = await this.retrieve(swapId, {
|
||||
relations: ["additional_items"],
|
||||
@@ -685,7 +685,7 @@ class SwapService extends BaseService {
|
||||
// Update the fulfillment to register
|
||||
const shipment = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createShipment(fulfillmentId, trackingNumbers, metadata)
|
||||
.createShipment(fulfillmentId, trackingLinks, metadata)
|
||||
|
||||
swap.fulfillment_status = "shipped"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user