Return Reason (#205)
* feat: add return reasons * feat: add return reasons * feat: adds return reason entity * fix: endpoint tag * fix: endpoint tag * fix: do not require label * fix: PR
This commit is contained in:
1 parent
695b1fd0a5
commit
192237b335
27 files changed
+1032
-38
No files matched your search
@@ -1,5 +1,6 @@
|
||||
const { dropDatabase } = require("pg-god");
|
||||
const path = require("path");
|
||||
const { ReturnReason } = require("@medusajs/medusa");
|
||||
|
||||
const setupServer = require("../../../helpers/setup-server");
|
||||
const { useApi } = require("../../../helpers/use-api");
|
||||
@@ -468,6 +469,91 @@ describe("/admin/orders", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("POST /admin/orders/:id/return", () => {
|
||||
let rrId;
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
await adminSeeder(dbConnection);
|
||||
await orderSeeder(dbConnection);
|
||||
|
||||
const created = dbConnection.manager.create(ReturnReason, {
|
||||
value: "too_big",
|
||||
label: "Too Big",
|
||||
});
|
||||
const result = await dbConnection.manager.save(created);
|
||||
|
||||
rrId = result.id;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const manager = dbConnection.manager;
|
||||
await manager.query(`DELETE FROM "cart"`);
|
||||
await manager.query(`DELETE FROM "fulfillment_item"`);
|
||||
await manager.query(`DELETE FROM "fulfillment"`);
|
||||
await manager.query(`DELETE FROM "swap"`);
|
||||
await manager.query(`DELETE FROM "return_item"`);
|
||||
await manager.query(`DELETE FROM "return_reason"`);
|
||||
await manager.query(`DELETE FROM "return"`);
|
||||
await manager.query(`DELETE FROM "claim_image"`);
|
||||
await manager.query(`DELETE FROM "claim_tag"`);
|
||||
await manager.query(`DELETE FROM "claim_item"`);
|
||||
await manager.query(`DELETE FROM "shipping_method"`);
|
||||
await manager.query(`DELETE FROM "line_item"`);
|
||||
await manager.query(`DELETE FROM "claim_order"`);
|
||||
await manager.query(`DELETE FROM "money_amount"`);
|
||||
await manager.query(`DELETE FROM "product_variant"`);
|
||||
await manager.query(`DELETE FROM "product"`);
|
||||
await manager.query(`DELETE FROM "shipping_option"`);
|
||||
await manager.query(`DELETE FROM "discount"`);
|
||||
await manager.query(`DELETE FROM "payment"`);
|
||||
await manager.query(`DELETE FROM "order"`);
|
||||
await manager.query(`DELETE FROM "customer"`);
|
||||
await manager.query(
|
||||
`UPDATE "country" SET region_id=NULL WHERE iso_2 = 'us'`
|
||||
);
|
||||
await manager.query(`DELETE FROM "region"`);
|
||||
await manager.query(`DELETE FROM "user"`);
|
||||
});
|
||||
|
||||
it("creates a return", async () => {
|
||||
const api = useApi();
|
||||
|
||||
const response = await api.post(
|
||||
"/admin/orders/test-order/return",
|
||||
{
|
||||
items: [
|
||||
{
|
||||
item_id: "test-item",
|
||||
quantity: 1,
|
||||
reason_id: rrId,
|
||||
note: "TOO SMALL",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
authorization: "Bearer test_token",
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
expect(response.data.order.returns[0].refund_amount).toEqual(7200);
|
||||
expect(response.data.order.returns[0].items).toEqual([
|
||||
expect.objectContaining({
|
||||
item_id: "test-item",
|
||||
quantity: 1,
|
||||
reason_id: rrId,
|
||||
note: "TOO SMALL",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /admin/orders", () => {
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
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 adminSeeder = require("../../helpers/admin-seeder");
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
describe("/admin/return-reasons", () => {
|
||||
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("POST /admin/return-reasons", () => {
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
await adminSeeder(dbConnection);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const manager = dbConnection.manager;
|
||||
await manager.query(`DELETE FROM "return_reason"`);
|
||||
await manager.query(`DELETE FROM "user"`);
|
||||
});
|
||||
|
||||
it("creates a return_reason", async () => {
|
||||
const api = useApi();
|
||||
|
||||
const payload = {
|
||||
label: "Too Big",
|
||||
description: "Use this if the size was too big",
|
||||
value: "too_big",
|
||||
};
|
||||
|
||||
const response = await api
|
||||
.post("/admin/return-reasons", payload, {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
expect(response.data.return_reason).toEqual(
|
||||
expect.objectContaining({
|
||||
label: "Too Big",
|
||||
description: "Use this if the size was too big",
|
||||
value: "too_big",
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("update a return reason", async () => {
|
||||
const api = useApi();
|
||||
|
||||
const payload = {
|
||||
label: "Too Big Typo",
|
||||
description: "Use this if the size was too big",
|
||||
value: "too_big",
|
||||
};
|
||||
|
||||
const response = await api
|
||||
.post("/admin/return-reasons", payload, {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
expect(response.data.return_reason).toEqual(
|
||||
expect.objectContaining({
|
||||
label: "Too Big Typo",
|
||||
description: "Use this if the size was too big",
|
||||
value: "too_big",
|
||||
})
|
||||
);
|
||||
|
||||
const newResponse = await api
|
||||
.post(
|
||||
`/admin/return-reasons/${response.data.return_reason.id}`,
|
||||
{
|
||||
label: "Too Big",
|
||||
description: "new desc",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
expect(newResponse.data.return_reason).toEqual(
|
||||
expect.objectContaining({
|
||||
label: "Too Big",
|
||||
description: "new desc",
|
||||
value: "too_big",
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("list return reasons", async () => {
|
||||
const api = useApi();
|
||||
|
||||
const payload = {
|
||||
label: "Too Big Typo",
|
||||
description: "Use this if the size was too big",
|
||||
value: "too_big",
|
||||
};
|
||||
|
||||
await api
|
||||
.post("/admin/return-reasons", payload, {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
const response = await api
|
||||
.get("/admin/return-reasons", {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
console.log(response.data);
|
||||
|
||||
expect(response.data.return_reasons).toEqual([
|
||||
expect.objectContaining({
|
||||
value: "too_big",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
const { dropDatabase } = require("pg-god");
|
||||
const path = require("path");
|
||||
|
||||
const { ReturnReason } = require("@medusajs/medusa");
|
||||
|
||||
const setupServer = require("../../../helpers/setup-server");
|
||||
const { useApi } = require("../../../helpers/use-api");
|
||||
const { initDb } = require("../../../helpers/use-db");
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
describe("/store/return-reasons", () => {
|
||||
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 /store/return-reasons", () => {
|
||||
let rrId;
|
||||
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
const created = dbConnection.manager.create(ReturnReason, {
|
||||
value: "too_big",
|
||||
label: "Too Big",
|
||||
});
|
||||
|
||||
const result = await dbConnection.manager.save(created);
|
||||
rrId = result.id;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
const manager = dbConnection.manager;
|
||||
await manager.query(`DELETE FROM "return_reason"`);
|
||||
});
|
||||
|
||||
it("list return reasons", async () => {
|
||||
const api = useApi();
|
||||
|
||||
const response = await api.get("/store/return-reasons").catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
expect(response.data.return_reasons).toEqual([
|
||||
expect.objectContaining({
|
||||
id: rrId,
|
||||
value: "too_big",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ const { dropDatabase } = require("pg-god");
|
||||
const path = require("path");
|
||||
const {
|
||||
Region,
|
||||
ReturnReason,
|
||||
Order,
|
||||
Customer,
|
||||
ShippingProfile,
|
||||
@@ -35,6 +36,8 @@ describe("/store/carts", () => {
|
||||
});
|
||||
|
||||
describe("POST /store/returns", () => {
|
||||
let rrId;
|
||||
|
||||
beforeEach(async () => {
|
||||
const manager = dbConnection.manager;
|
||||
await manager.query(
|
||||
@@ -110,6 +113,14 @@ describe("/store/carts", () => {
|
||||
amount: 1000,
|
||||
is_return: true,
|
||||
});
|
||||
|
||||
const created = dbConnection.manager.create(ReturnReason, {
|
||||
value: "too_big",
|
||||
label: "Too Big",
|
||||
});
|
||||
const result = await dbConnection.manager.save(created);
|
||||
|
||||
rrId = result.id;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -117,6 +128,7 @@ describe("/store/carts", () => {
|
||||
await manager.query(`DELETE FROM "shipping_method"`);
|
||||
await manager.query(`DELETE FROM "shipping_option"`);
|
||||
await manager.query(`DELETE FROM "return_item"`);
|
||||
await manager.query(`DELETE FROM "return_reason"`);
|
||||
await manager.query(`DELETE FROM "return"`);
|
||||
await manager.query(`DELETE FROM "line_item"`);
|
||||
await manager.query(`DELETE FROM "order"`);
|
||||
@@ -174,5 +186,33 @@ describe("/store/carts", () => {
|
||||
|
||||
expect(response.data.return.refund_amount).toEqual(7000);
|
||||
});
|
||||
|
||||
it("creates a return with reasons", async () => {
|
||||
const api = useApi();
|
||||
|
||||
const response = await api
|
||||
.post("/store/returns", {
|
||||
order_id: "order_test",
|
||||
items: [
|
||||
{
|
||||
reason_id: rrId,
|
||||
note: "TOO small",
|
||||
item_id: "test-item",
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
.catch((err) => {
|
||||
return err.response;
|
||||
});
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
expect(response.data.return.items).toEqual([
|
||||
expect.objectContaining({
|
||||
reason_id: rrId,
|
||||
note: "TOO small",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,15 +8,15 @@
|
||||
"build": "babel src -d dist --extensions \".ts,.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/medusa": "1.1.11-dev-1615546159319",
|
||||
"medusa-interfaces": "1.1.1-dev-1615546159319",
|
||||
"@medusajs/medusa": "1.1.11-dev-1615882960610",
|
||||
"medusa-interfaces": "1.1.1-dev-1615882960610",
|
||||
"typeorm": "^0.2.31"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.12.10",
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/node": "^7.12.10",
|
||||
"babel-preset-medusa-package": "1.1.0-dev-1615546159319",
|
||||
"babel-preset-medusa-package": "1.1.0-dev-1615882960610",
|
||||
"jest": "^26.6.3"
|
||||
}
|
||||
}
|
||||
@@ -1369,10 +1369,10 @@
|
||||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@medusajs/medusa@1.1.11-dev-1615546159319":
|
||||
version "1.1.11-dev-1615546159319"
|
||||
resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.11-dev-1615546159319.tgz#88d494cd9f765d69cfa8450aad1c459e3f358c2c"
|
||||
integrity sha512-0REuafQjwykR6zbjjuIq151S3nLWdHBIFcy7fzKcR7Yhs2XkHMDFToUD01/uY2d/GqmKGvn/HsDLPx2a7Sj4SQ==
|
||||
"@medusajs/medusa@1.1.11-dev-1615882960610":
|
||||
version "1.1.11-dev-1615882960610"
|
||||
resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.11-dev-1615882960610.tgz#805c66ace0750f63ce8d49d89af2b08588455a1b"
|
||||
integrity sha512-dvkCGMt/lM51ZW6HJoAV70uy6wuuhGS6PAiRvmuofRf331yvHO95KBGMxKbGLtsyL1SAt9Bf1V8Wm4zPYL/BNQ==
|
||||
dependencies:
|
||||
"@babel/plugin-transform-classes" "^7.9.5"
|
||||
"@hapi/joi" "^16.1.8"
|
||||
@@ -1394,8 +1394,8 @@
|
||||
joi "^17.3.0"
|
||||
joi-objectid "^3.0.1"
|
||||
jsonwebtoken "^8.5.1"
|
||||
medusa-core-utils "1.1.0-dev-1615546159319"
|
||||
medusa-test-utils "1.1.3-dev-1615546159319"
|
||||
medusa-core-utils "1.1.0-dev-1615882960610"
|
||||
medusa-test-utils "1.1.3-dev-1615882960610"
|
||||
morgan "^1.9.1"
|
||||
multer "^1.4.2"
|
||||
passport "^0.4.0"
|
||||
@@ -1884,10 +1884,10 @@ babel-preset-jest@^26.6.2:
|
||||
babel-plugin-jest-hoist "^26.6.2"
|
||||
babel-preset-current-node-syntax "^1.0.0"
|
||||
|
||||
babel-preset-medusa-package@1.1.0-dev-1615546159319:
|
||||
version "1.1.0-dev-1615546159319"
|
||||
resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.0-dev-1615546159319.tgz#eaaa8908d9b04487cbfbd90cd5422c8ade611506"
|
||||
integrity sha512-IS60RphbSYg+PQA5ywdjba2eL+pyHaHAUm93658fAMezSKnRaDEvtle42DK63EifQC35K1pQc0j7YUbgg8ZODg==
|
||||
babel-preset-medusa-package@1.1.0-dev-1615882960610:
|
||||
version "1.1.0-dev-1615882960610"
|
||||
resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.0-dev-1615882960610.tgz#1cb3b658a6114759b33bb022a19865d8d5751a9a"
|
||||
integrity sha512-PF+RAij3oCoXtU7/WbyJVCvassselnk4I4u2NXo7sxqg0Z6V1N9IwEVxTsg7G2PfiXmT2EYaJPPsq9st8lOvuQ==
|
||||
dependencies:
|
||||
"@babel/plugin-proposal-class-properties" "^7.12.1"
|
||||
"@babel/plugin-proposal-decorators" "^7.12.1"
|
||||
@@ -4493,28 +4493,28 @@ media-typer@0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||
|
||||
medusa-core-utils@1.1.0-dev-1615546159319:
|
||||
version "1.1.0-dev-1615546159319"
|
||||
resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.0-dev-1615546159319.tgz#34147e32463b002c51b815f7329e88881a0fbec2"
|
||||
integrity sha512-t/QeZmHaFdBmn1wC+StZDq+tJescILybCSNIOFLSUlOaUaOPGwZ0UhYN/MNeMrBwAoQq9ZO5QjJsNNbQK33gWA==
|
||||
medusa-core-utils@1.1.0-dev-1615882960610:
|
||||
version "1.1.0-dev-1615882960610"
|
||||
resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.0-dev-1615882960610.tgz#5358b5edc3cd571071ed5bf6c3781b397f2674f9"
|
||||
integrity sha512-v6zvSdkJn97jY7JwEebIpHy5SZzj2KO+m5duIRmRTnBQUI7DWVxOOO7DRqc24W0shwCz/H51PdKjhDwdtSgFwQ==
|
||||
dependencies:
|
||||
joi "^17.3.0"
|
||||
joi-objectid "^3.0.1"
|
||||
|
||||
medusa-interfaces@1.1.1-dev-1615546159319:
|
||||
version "1.1.1-dev-1615546159319"
|
||||
resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.1-dev-1615546159319.tgz#a75e2841a9c68b26bc688706d59fccfd655c8f41"
|
||||
integrity sha512-BqE+ARKvJgmLHABuAGfCSquNa1XPF8+ll/dB6XMMjPAPzlGF9kV/GhQIsjq8fzoZ8ZvrLBD0ak5ndOK/BH/NEA==
|
||||
medusa-interfaces@1.1.1-dev-1615882960610:
|
||||
version "1.1.1-dev-1615882960610"
|
||||
resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.1-dev-1615882960610.tgz#6062b8c6fadb33e89e7ed53b5627a182af1c4511"
|
||||
integrity sha512-WdyYK1yqSUIXIJSjLpOCRotVAEIVeggnqNh+AtNuxddmMBJrS0tFUhj2RetkyMkoVsjTuEkSOI/LY9V8fK9xCA==
|
||||
dependencies:
|
||||
medusa-core-utils "1.1.0-dev-1615546159319"
|
||||
medusa-core-utils "1.1.0-dev-1615882960610"
|
||||
|
||||
medusa-test-utils@1.1.3-dev-1615546159319:
|
||||
version "1.1.3-dev-1615546159319"
|
||||
resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.3-dev-1615546159319.tgz#912b4bf83e03c247bc189ebc315c9db4200f3a71"
|
||||
integrity sha512-hW8xwrf52a5PAzZDL/kOk9Mlv4Jdpgfx+IPUz/F2D3D8ky3OwikwonXKvPvaRC5JaCdjI/xipPaSWUkJeb1dzg==
|
||||
medusa-test-utils@1.1.3-dev-1615882960610:
|
||||
version "1.1.3-dev-1615882960610"
|
||||
resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.3-dev-1615882960610.tgz#55326f1884469e5a41221e1a029e792ed3035129"
|
||||
integrity sha512-cnRbzR4I+R1NkZw1w6e8NwKPDqXodhaK7vAbIc3ogRHt8iXTYIVaU9RJTBCYnmZQ7Y/0zQCSd7NplB+PQ75ssw==
|
||||
dependencies:
|
||||
"@babel/plugin-transform-classes" "^7.9.5"
|
||||
medusa-core-utils "1.1.0-dev-1615546159319"
|
||||
medusa-core-utils "1.1.0-dev-1615882960610"
|
||||
randomatic "^3.1.1"
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
|
||||
@@ -11,6 +11,7 @@ import shippingProfileRoutes from "./shipping-profiles"
|
||||
import discountRoutes from "./discounts"
|
||||
import giftCardRoutes from "./gift-cards"
|
||||
import orderRoutes from "./orders"
|
||||
import returnReasonRoutes from "./return-reasons"
|
||||
import storeRoutes from "./store"
|
||||
import uploadRoutes from "./uploads"
|
||||
import customerRoutes from "./customers"
|
||||
@@ -64,6 +65,7 @@ export default (app, container, config) => {
|
||||
variantRoutes(route)
|
||||
collectionRoutes(route)
|
||||
notificationRoutes(route)
|
||||
returnReasonRoutes(route)
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -13,6 +13,8 @@ const defaultRelations = [
|
||||
"fulfillments.tracking_links",
|
||||
"fulfillments.items",
|
||||
"returns",
|
||||
"returns.items",
|
||||
"returns.items.reason",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
"claims",
|
||||
|
||||
@@ -195,6 +195,8 @@ export const defaultRelations = [
|
||||
"fulfillments.tracking_links",
|
||||
"fulfillments.items",
|
||||
"returns",
|
||||
"returns.items",
|
||||
"returns.items.reason",
|
||||
"gift_cards",
|
||||
"gift_card_transactions",
|
||||
"claims",
|
||||
|
||||
@@ -21,6 +21,12 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* item_id:
|
||||
* description: The id of the Line Item.
|
||||
* type: string
|
||||
* reason_id:
|
||||
* description: The id of the Return Reason to use.
|
||||
* type: string
|
||||
* note:
|
||||
* description: An optional note with information about the Return.
|
||||
* type: string
|
||||
* quantity:
|
||||
* description: The quantity of the Line Item.
|
||||
* type: integer
|
||||
@@ -60,6 +66,8 @@ export default async (req, res) => {
|
||||
.items({
|
||||
item_id: Validator.string().required(),
|
||||
quantity: Validator.number().required(),
|
||||
reason_id: Validator.string().optional(),
|
||||
note: Validator.string().optional(),
|
||||
})
|
||||
.required(),
|
||||
return_shipping: Validator.object()
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /return-reasons
|
||||
* operationId: "PostReturnReasons"
|
||||
* summary: "Create a Return Reason"
|
||||
* description: "Creates a Return Reason"
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* label:
|
||||
* description: "The label to display to the Customer."
|
||||
* type: string
|
||||
* value:
|
||||
* description: "The value that the Return Reason will be identified by. Must be unique."
|
||||
* type: string
|
||||
* description:
|
||||
* description: "An optional description to for the Reason."
|
||||
* type: string
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs with additional information.
|
||||
* type: object
|
||||
* tags:
|
||||
* - Return Reason
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* return_reason:
|
||||
* $ref: "#/components/schemas/return_reason"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const schema = Validator.object().keys({
|
||||
value: Validator.string().required(),
|
||||
label: Validator.string().required(),
|
||||
description: Validator.string()
|
||||
.optional()
|
||||
.allow(""),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
|
||||
try {
|
||||
const returnReasonService = req.scope.resolve("returnReasonService")
|
||||
const result = await returnReasonService.create(value)
|
||||
|
||||
const reason = await returnReasonService.retrieve(result.id, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ return_reason: reason })
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [get] /return-reasons/{id}
|
||||
* operationId: "GetReturnReasonsReason"
|
||||
* summary: "Retrieve a Return Reason"
|
||||
* description: "Retrieves a Return Reason."
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Return Reason.
|
||||
* tags:
|
||||
* - Return Reason
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* return_reason:
|
||||
* $ref: "#/components/schemas/return_reason"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { id } = req.params
|
||||
try {
|
||||
const returnReasonService = req.scope.resolve("returnReasonService")
|
||||
|
||||
const data = await returnReasonService.retrieve(id, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ return_reason: data })
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Router } from "express"
|
||||
import middlewares from "../../../middlewares"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default app => {
|
||||
app.use("/return-reasons", route)
|
||||
|
||||
/**
|
||||
* List reasons
|
||||
*/
|
||||
route.get("/", middlewares.wrap(require("./list-reasons").default))
|
||||
|
||||
/**
|
||||
* Retrieve reason
|
||||
*/
|
||||
route.get("/:id", middlewares.wrap(require("./get-reason").default))
|
||||
|
||||
/**
|
||||
* Create a reason
|
||||
*/
|
||||
route.post("/", middlewares.wrap(require("./create-reason").default))
|
||||
|
||||
/**
|
||||
* Update a reason
|
||||
*/
|
||||
route.post("/:id", middlewares.wrap(require("./update-reason").default))
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export const defaultFields = [
|
||||
"id",
|
||||
"value",
|
||||
"label",
|
||||
"description",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
]
|
||||
|
||||
export const defaultRelations = []
|
||||
@@ -0,0 +1,37 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [get] /return-reasons
|
||||
* operationId: "GetReturnReasons"
|
||||
* summary: "List Return Reasons"
|
||||
* description: "Retrieves a list of Return Reasons."
|
||||
* tags:
|
||||
* - Return Reason
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* return_reasons:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/return_reason"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
try {
|
||||
const returnReasonService = req.scope.resolve("returnReasonService")
|
||||
|
||||
const query = {}
|
||||
const data = await returnReasonService.list(query, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ return_reasons: data })
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /return-reasons/:id
|
||||
* operationId: "PostReturnReasonsReason"
|
||||
* summary: "Update a Return Reason"
|
||||
* description: "Updates a Return Reason"
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Return Reason.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* label:
|
||||
* description: "The label to display to the Customer."
|
||||
* type: string
|
||||
* value:
|
||||
* description: "The value that the Return Reason will be identified by. Must be unique."
|
||||
* type: string
|
||||
* description:
|
||||
* description: "An optional description to for the Reason."
|
||||
* type: string
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs with additional information.
|
||||
* type: object
|
||||
* tags:
|
||||
* - Return Reason
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* return_reason:
|
||||
* $ref: "#/components/schemas/return_reason"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { id } = req.params
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
label: Validator.string().optional(),
|
||||
description: Validator.string()
|
||||
.optional()
|
||||
.allow(""),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
|
||||
try {
|
||||
const returnReasonService = req.scope.resolve("returnReasonService")
|
||||
|
||||
await returnReasonService.update(id, value)
|
||||
|
||||
const reason = await returnReasonService.retrieve(id, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ return_reason: reason })
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import customerRoutes from "./customers"
|
||||
import shippingOptionRoutes from "./shipping-options"
|
||||
import regionRoutes from "./regions"
|
||||
import returnRoutes from "./returns"
|
||||
import returnReasonRoutes from "./return-reasons"
|
||||
import swapRoutes from "./swaps"
|
||||
import variantRoutes from "./variants"
|
||||
import giftCardRoutes from "./gift-cards"
|
||||
@@ -41,6 +42,7 @@ export default (app, container, config) => {
|
||||
variantRoutes(route)
|
||||
returnRoutes(route)
|
||||
giftCardRoutes(route)
|
||||
returnReasonRoutes(route)
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [get] /return-reasons/{id}
|
||||
* operationId: "GetReturnReasonsReason"
|
||||
* summary: "Retrieve a Return Reason"
|
||||
* description: "Retrieves a Return Reason."
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Return Reason.
|
||||
* tags:
|
||||
* - Return Reason
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* return_reason:
|
||||
* $ref: "#/components/schemas/return_reason"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { id } = req.params
|
||||
try {
|
||||
const returnReasonService = req.scope.resolve("returnReasonService")
|
||||
|
||||
const data = await returnReasonService.retrieve(id, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ return_reason: data })
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Router } from "express"
|
||||
import middlewares from "../../../middlewares"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default app => {
|
||||
app.use("/return-reasons", route)
|
||||
|
||||
/**
|
||||
* List reasons
|
||||
*/
|
||||
route.get("/", middlewares.wrap(require("./list-reasons").default))
|
||||
|
||||
/**
|
||||
* Retrieve reason
|
||||
*/
|
||||
route.get("/:id", middlewares.wrap(require("./get-reason").default))
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export const defaultFields = [
|
||||
"id",
|
||||
"value",
|
||||
"label",
|
||||
"description",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
]
|
||||
|
||||
export const defaultRelations = []
|
||||
@@ -0,0 +1,37 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [get] /return-reasons
|
||||
* operationId: "GetReturnReasons"
|
||||
* summary: "List Return Reasons"
|
||||
* description: "Retrieves a list of Return Reasons."
|
||||
* tags:
|
||||
* - Return Reason
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* return_reasons:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/return_reason"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
try {
|
||||
const returnReasonService = req.scope.resolve("returnReasonService")
|
||||
|
||||
const query = {}
|
||||
const data = await returnReasonService.list(query, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ return_reasons: data })
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ export default async (req, res) => {
|
||||
.items({
|
||||
item_id: Validator.string().required(),
|
||||
quantity: Validator.number().required(),
|
||||
reason_id: Validator.string().optional(),
|
||||
note: Validator.string().optional(),
|
||||
})
|
||||
.required(),
|
||||
return_shipping: Validator.object()
|
||||
@@ -109,13 +111,14 @@ export default async (req, res) => {
|
||||
const { key, error } = await idempotencyKeyService.workStage(
|
||||
idempotencyKey.idempotency_key,
|
||||
async manager => {
|
||||
let order = await orderService
|
||||
.withTransaction(manager)
|
||||
.retrieve(value.order_id, { relations: ["returns"] })
|
||||
|
||||
let ret = await returnService.withTransaction(manager).list({
|
||||
let ret = await returnService.withTransaction(manager).list(
|
||||
{
|
||||
idempotency_key: idempotencyKey.idempotency_key,
|
||||
})
|
||||
},
|
||||
{
|
||||
relations: ["items", "items.reason"],
|
||||
}
|
||||
)
|
||||
if (!ret.length) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
|
||||
@@ -41,3 +41,4 @@ export { StagedJob } from "./models/staged-job"
|
||||
export { Store } from "./models/store"
|
||||
export { Swap } from "./models/swap"
|
||||
export { User } from "./models/user"
|
||||
export { ReturnReason } from "./models/return-reason"
|
||||
@@ -0,0 +1,33 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
|
||||
export class returnReason1615891636559 implements MigrationInterface {
|
||||
name = "returnReason1615891636559"
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "return_reason" ("id" character varying NOT NULL, "value" character varying NOT NULL, "label" character varying NOT NULL, "description" character varying, "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, CONSTRAINT "PK_95fd1172973165790903e65660a" PRIMARY KEY ("id"))`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`CREATE UNIQUE INDEX "IDX_00605f9d662c06b81c1b60ce24" ON "return_reason" ("value") `
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "return_item" ADD "reason_id" character varying`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "return_item" ADD "note" character varying`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "return_item" ADD CONSTRAINT "FK_d742532378a65022e7ceb328828" FOREIGN KEY ("reason_id") REFERENCES "return_reason"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "return_item" DROP CONSTRAINT "FK_d742532378a65022e7ceb328828"`
|
||||
)
|
||||
await queryRunner.query(`ALTER TABLE "return_item" DROP COLUMN "note"`)
|
||||
await queryRunner.query(`ALTER TABLE "return_item" DROP COLUMN "reason_id"`)
|
||||
await queryRunner.query(`DROP INDEX "IDX_00605f9d662c06b81c1b60ce24"`)
|
||||
await queryRunner.query(`DROP TABLE "return_reason"`)
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
JoinTable,
|
||||
} from "typeorm"
|
||||
|
||||
import { ReturnReason } from "./return-reason"
|
||||
import { Return } from "./return"
|
||||
import { LineItem } from "./line-item"
|
||||
|
||||
@@ -47,6 +48,16 @@ export class ReturnItem {
|
||||
@Column({ type: "int", nullable: true })
|
||||
received_quantity: number
|
||||
|
||||
@Column({ nullable: true })
|
||||
reason_id: string
|
||||
|
||||
@ManyToOne(() => ReturnReason, { eager: true })
|
||||
@JoinColumn({ name: "reason_id" })
|
||||
reason: ReturnReason
|
||||
|
||||
@Column({ nullable: true })
|
||||
note: string
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
}
|
||||
@@ -79,6 +90,13 @@ export class ReturnItem {
|
||||
* recieved_quantity:
|
||||
* description: "The quantity that was received in the warehouse."
|
||||
* type: integer
|
||||
* reason:
|
||||
* description: "The reason for returning the item."
|
||||
* anyOf:
|
||||
* - $ref: "#/components/schemas/return_reason"
|
||||
* note:
|
||||
* description: "An optional note with additional details about the Return."
|
||||
* type: string
|
||||
* metadata:
|
||||
* description: "An optional key-value map with additional information."
|
||||
* type: object
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
Entity,
|
||||
Index,
|
||||
BeforeInsert,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
PrimaryColumn,
|
||||
} from "typeorm"
|
||||
import { ulid } from "ulid"
|
||||
|
||||
@Entity()
|
||||
export class ReturnReason {
|
||||
@PrimaryColumn()
|
||||
id: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column()
|
||||
value: string
|
||||
|
||||
@Column()
|
||||
label: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
description: string
|
||||
|
||||
@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
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert() {
|
||||
if (this.id) return
|
||||
const id = ulid()
|
||||
this.id = `rr_${id}`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema return_reason
|
||||
* title: "Return Reason"
|
||||
* description: "A Reason for why a given product is returned. A Return Reason can be used on Return Items in order to indicate why a Line Item was returned."
|
||||
* x-resourceId: return_reason
|
||||
* properties:
|
||||
* id:
|
||||
* description: "The id of the Return Reason will start with `rr_`."
|
||||
* type: string
|
||||
* description:
|
||||
* description: "A description of the Reason."
|
||||
* type: string
|
||||
* label:
|
||||
* description: "A text that can be displayed to the Customer as a reason."
|
||||
* type: string
|
||||
* value:
|
||||
* description: "The value to identify the reason by."
|
||||
* type: string
|
||||
* created_at:
|
||||
* description: "The date with timezone at which the resource was created."
|
||||
* type: string
|
||||
* format: date-time
|
||||
* updated_at:
|
||||
* description: "The date with timezone at which the resource was last updated."
|
||||
* type: string
|
||||
* format: date-time
|
||||
* deleted_at:
|
||||
* description: "The date with timezone at which the resource was deleted."
|
||||
* type: string
|
||||
* format: date-time
|
||||
* metadata:
|
||||
* description: "An optional key-value map with additional information."
|
||||
* type: object
|
||||
*/
|
||||
@@ -0,0 +1,5 @@
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
import { ReturnReason } from "../models/return-reason"
|
||||
|
||||
@EntityRepository(ReturnReason)
|
||||
export class ReturnReasonRepository extends Repository<ReturnReason> {}
|
||||
@@ -0,0 +1,97 @@
|
||||
import _ from "lodash"
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
|
||||
class ReturnReasonService extends BaseService {
|
||||
constructor({ manager, returnReasonRepository }) {
|
||||
super()
|
||||
|
||||
/** @private @constant {EntityManager} */
|
||||
this.manager_ = manager
|
||||
|
||||
/** @private @constant {ReturnReasonRepository} */
|
||||
this.retReasonRepo_ = returnReasonRepository
|
||||
}
|
||||
|
||||
withTransaction(manager) {
|
||||
if (!manager) {
|
||||
return this
|
||||
}
|
||||
|
||||
const cloned = new ReturnReasonService({
|
||||
manager,
|
||||
returnReasonRepository: this.retReasonRepo_,
|
||||
})
|
||||
|
||||
cloned.transactionManager_ = manager
|
||||
|
||||
return cloned
|
||||
}
|
||||
|
||||
create(data) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const rrRepo = manager.getCustomRepository(this.retReasonRepo_)
|
||||
|
||||
const created = rrRepo.create(data)
|
||||
|
||||
const result = await rrRepo.save(created)
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
update(id, data) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const rrRepo = manager.getCustomRepository(this.retReasonRepo_)
|
||||
const reason = await this.retrieve(id)
|
||||
|
||||
if ("description" in data) {
|
||||
reason.description = data.description
|
||||
}
|
||||
|
||||
if ("label" in data) {
|
||||
reason.label = data.label
|
||||
}
|
||||
|
||||
await rrRepo.save(reason)
|
||||
|
||||
return reason
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} selector - the query object for find
|
||||
* @return {Promise} the result of the find operation
|
||||
*/
|
||||
async list(
|
||||
selector,
|
||||
config = { skip: 0, take: 50, order: { created_at: "DESC" } }
|
||||
) {
|
||||
const rrRepo = this.manager_.getCustomRepository(this.retReasonRepo_)
|
||||
const query = this.buildQuery_(selector, config)
|
||||
return rrRepo.find(query)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an order by id.
|
||||
* @param {string} orderId - id of order to retrieve
|
||||
* @return {Promise<Order>} the order document
|
||||
*/
|
||||
async retrieve(id, config = {}) {
|
||||
const rrRepo = this.manager_.getCustomRepository(this.retReasonRepo_)
|
||||
const validatedId = this.validateId_(id)
|
||||
|
||||
const query = this.buildQuery_({ id: validatedId }, config)
|
||||
const item = await rrRepo.findOne(query)
|
||||
|
||||
if (!item) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Return Reason with id: ${id} was not found.`
|
||||
)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
export default ReturnReasonService
|
||||
@@ -14,6 +14,7 @@ class ReturnService extends BaseService {
|
||||
returnRepository,
|
||||
returnItemRepository,
|
||||
shippingOptionService,
|
||||
returnReasonService,
|
||||
fulfillmentProviderService,
|
||||
}) {
|
||||
super()
|
||||
@@ -38,6 +39,8 @@ class ReturnService extends BaseService {
|
||||
|
||||
/** @private @const {FulfillmentProviderService} */
|
||||
this.fulfillmentProviderService_ = fulfillmentProviderService
|
||||
|
||||
this.returnReasonService_ = returnReasonService
|
||||
}
|
||||
|
||||
withTransaction(transactionManager) {
|
||||
@@ -53,6 +56,7 @@ class ReturnService extends BaseService {
|
||||
returnItemRepository: this.returnItemRepository_,
|
||||
shippingOptionService: this.shippingOptionService_,
|
||||
fulfillmentProviderService: this.fulfillmentProviderService_,
|
||||
returnReasonService: this.returnReasonService_,
|
||||
})
|
||||
|
||||
cloned.transactionManager_ = transactionManager
|
||||
@@ -72,9 +76,9 @@ class ReturnService extends BaseService {
|
||||
*/
|
||||
async getFulfillmentItems_(order, items, transformer) {
|
||||
const toReturn = await Promise.all(
|
||||
items.map(async ({ item_id, quantity }) => {
|
||||
const item = order.items.find(i => i.id === item_id)
|
||||
return transformer(item, quantity)
|
||||
items.map(async data => {
|
||||
const item = order.items.find(i => i.id === data.item_id)
|
||||
return transformer(item, data.quantity, data)
|
||||
})
|
||||
)
|
||||
|
||||
@@ -127,10 +131,11 @@ class ReturnService extends BaseService {
|
||||
* @param {LineItem?} item - the line item to check has sufficient returnable
|
||||
* quantity.
|
||||
* @param {number} quantity - the quantity that is requested to be returned.
|
||||
* @param {object} additional - the quantity that is requested to be returned.
|
||||
* @return {LineItem} a line item where the quantity is set to the requested
|
||||
* return quantity.
|
||||
*/
|
||||
validateReturnLineItem_(item, quantity) {
|
||||
validateReturnLineItem_(item, quantity, additional) {
|
||||
if (!item) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
@@ -146,10 +151,20 @@ class ReturnService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
const toReturn = {
|
||||
...item,
|
||||
quantity,
|
||||
}
|
||||
|
||||
if ("reason_id" in additional) {
|
||||
toReturn.reason_id = additional.reason_id
|
||||
}
|
||||
|
||||
if ("note" in additional) {
|
||||
toReturn.note = additional.note
|
||||
}
|
||||
|
||||
return toReturn
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,6 +303,8 @@ class ReturnService extends BaseService {
|
||||
item_id: i.id,
|
||||
quantity: i.quantity,
|
||||
requested_quantity: i.quantity,
|
||||
reason_id: i.reason_id,
|
||||
note: i.note,
|
||||
metadata: i.metadata,
|
||||
})
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user