release: next (#315)
Co-authored-by: Sebastian Mateos Nicolajsen <sebastian.m.nicolajsen@gmail.com> Co-authored-by: Abraham Ugbeshe <abrahamugbeshe@gmail.com> Co-authored-by: olivermrbl <oliver@mrbltech.com>
This commit is contained in:
1 parent
44d31b4d83
commit
2585e958de
144 files changed
+2554
-240
No files matched your search
@@ -3,6 +3,21 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.30](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.29...@medusajs/medusa@1.1.30) (2021-07-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adds tracking links to customer orders ([c013270](https://github.com/medusajs/medusa/commit/c0132700b78d171d6c7e29e2604b99129c5a1921))
|
||||
* allow updating billing address on customer ([5a1cbc6](https://github.com/medusajs/medusa/commit/5a1cbc68b721fe80d223e4ff611ebc81346333d7))
|
||||
* better store/customer support ([6342e68](https://github.com/medusajs/medusa/commit/6342e68d069636e5eb4877c7ebf7aac952b5e363))
|
||||
* create fulfillment ([0603a86](https://github.com/medusajs/medusa/commit/0603a86d65a528af86bdbdc46227faa2f48a93bb))
|
||||
* **medusa:** Resolve issue with soft-delete and unique indexes in DB ([#296](https://github.com/medusajs/medusa/issues/296)) ([6358f8f](https://github.com/medusajs/medusa/commit/6358f8fc756291710a82ce39a47d0cbec1395b87))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.1.29](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.1.28...@medusajs/medusa@1.1.29) (2021-07-02)
|
||||
|
||||
**Note:** Version bump only for package @medusajs/medusa
|
||||
|
||||
@@ -36,7 +36,7 @@ The steps can be done in any order. The standard path would probably be:
|
||||
|
||||
Assuming that shipping methods are static within each region we can display all shipping methods at checkout time. If shipping is dynamically calculated the price of the shipping method may change, we will ask the fulfillment provider for new rates.
|
||||
|
||||
Payment details can be entered at any point as long as the final amount is known. If the final amount changes afer the payment details are entered the payment method may therefore be invalidated.
|
||||
Payment details can be entered at any point as long as the final amount is known. If the final amount changes after the payment details are entered the payment method may therefore be invalidated.
|
||||
|
||||
Within the store UI you could imagine each step being taken care of by a single button click, which calls all endpoints.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@medusajs/medusa",
|
||||
"version": "1.1.29",
|
||||
"version": "1.1.30",
|
||||
"description": "E-commerce for JAMstack",
|
||||
"main": "dist/index.js",
|
||||
"repository": {
|
||||
@@ -17,11 +17,11 @@
|
||||
"@babel/cli": "^7.14.3",
|
||||
"@babel/core": "^7.14.3",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"babel-preset-medusa-package": "^1.1.10",
|
||||
"babel-preset-medusa-package": "^1.1.11",
|
||||
"cross-env": "^5.2.1",
|
||||
"eslint": "^6.8.0",
|
||||
"jest": "^25.5.2",
|
||||
"medusa-interfaces": "^1.1.17",
|
||||
"medusa-interfaces": "^1.1.18",
|
||||
"nodemon": "^2.0.1",
|
||||
"prettier": "^1.19.1",
|
||||
"supertest": "^4.0.2"
|
||||
@@ -59,8 +59,8 @@
|
||||
"joi": "^17.3.0",
|
||||
"joi-objectid": "^3.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"medusa-core-utils": "^1.1.16",
|
||||
"medusa-test-utils": "^1.1.19",
|
||||
"medusa-core-utils": "^1.1.17",
|
||||
"medusa-test-utils": "^1.1.20",
|
||||
"morgan": "^1.9.1",
|
||||
"multer": "^1.4.2",
|
||||
"passport": "^0.4.0",
|
||||
|
||||
@@ -9,6 +9,9 @@ export default () => {
|
||||
|
||||
let statusCode = 500
|
||||
switch (err.name) {
|
||||
case MedusaError.Types.DUPLICATE_ERROR:
|
||||
statusCode = 409
|
||||
break
|
||||
case MedusaError.Types.NOT_ALLOWED:
|
||||
case MedusaError.Types.INVALID_DATA:
|
||||
statusCode = 400
|
||||
|
||||
@@ -63,6 +63,9 @@ import { defaultFields, defaultRelations } from "."
|
||||
* customer_id:
|
||||
* description: The id of the customer to add on the draft order
|
||||
* type: string
|
||||
* no_notification_order:
|
||||
* description: An optional flag passed to the resulting order to determine use of notifications.
|
||||
* type: boolean
|
||||
* shipping_methods:
|
||||
* description: The shipping methods for the draft order
|
||||
* type: array
|
||||
@@ -123,6 +126,7 @@ export default async (req, res) => {
|
||||
})
|
||||
.optional(),
|
||||
customer_id: Validator.string().optional(),
|
||||
no_notification_order: Validator.boolean().optional(),
|
||||
shipping_methods: Validator.array()
|
||||
.items({
|
||||
option_id: Validator.string().required(),
|
||||
|
||||
@@ -78,6 +78,7 @@ export const defaultFields = [
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"metadata",
|
||||
"no_notification_order",
|
||||
]
|
||||
|
||||
export const allowedFields = [
|
||||
@@ -89,6 +90,7 @@ export const allowedFields = [
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"metadata",
|
||||
"no_notification_order",
|
||||
]
|
||||
|
||||
export const allowedRelations = ["cart"]
|
||||
@@ -35,6 +35,9 @@ import { defaultCartFields, defaultCartRelations, defaultFields } from "."
|
||||
* code:
|
||||
* description: "The code that a Discount is identifed by."
|
||||
* type: string
|
||||
* no_notification_order:
|
||||
* description: "An optional flag passed to the resulting order to determine use of notifications."
|
||||
* type: boolean
|
||||
* customer_id:
|
||||
* description: "The id of the Customer to associate the Draft Order with."
|
||||
* type: string
|
||||
@@ -68,6 +71,7 @@ export default async (req, res) => {
|
||||
})
|
||||
.optional(),
|
||||
customer_id: Validator.string().optional(),
|
||||
no_notification_order: Validator.boolean().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -88,6 +92,13 @@ export default async (req, res) => {
|
||||
)
|
||||
}
|
||||
|
||||
if ("no_notification_order" in value) {
|
||||
await draftOrderService.update(draftOrder.id, {
|
||||
no_notification_order: value.no_notification_order,
|
||||
})
|
||||
delete value.no_notification_order
|
||||
}
|
||||
|
||||
await cartService.update(draftOrder.cart_id, value)
|
||||
|
||||
draftOrder.cart = await cartService.retrieve(draftOrder.cart_id, {
|
||||
|
||||
@@ -33,7 +33,10 @@ export const defaultFields = [
|
||||
"metadata",
|
||||
]
|
||||
|
||||
export const defaultRelations = ["region"]
|
||||
export const defaultRelations = [
|
||||
"region",
|
||||
"order",
|
||||
]
|
||||
|
||||
export const allowedFields = [
|
||||
"id",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultFields, defaultRelations } from "./"
|
||||
|
||||
/**
|
||||
@@ -21,14 +22,23 @@ import { defaultFields, defaultRelations } from "./"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
try {
|
||||
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
|
||||
}
|
||||
|
||||
const giftCardService = req.scope.resolve("giftCardService")
|
||||
|
||||
const giftCards = await giftCardService.list(selector, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
order: { created_at: "DESC" },
|
||||
limit: limit,
|
||||
skip: offset,
|
||||
})
|
||||
|
||||
res.status(200).json({ gift_cards: giftCards })
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultFields, defaultRelations } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /gift-cards/{id}
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("POST /admin/orders/:id/fulfillment", () => {
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
undefined
|
||||
{ metadata: undefined, no_notification: undefined }
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ const defaultFields = [
|
||||
"total",
|
||||
"paid_total",
|
||||
"refundable_amount",
|
||||
"no_notification",
|
||||
]
|
||||
|
||||
describe("GET /admin/orders", () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IdMap } from "medusa-test-utils"
|
||||
import { request } from "../../../../../helpers/test-request"
|
||||
import { orders } from "../../../../../services/__mocks__/order"
|
||||
import { ReturnService } from "../../../../../services/__mocks__/return"
|
||||
import { EventBusServiceMock } from "../../../../../services/__mocks__/event-bus"
|
||||
|
||||
describe("POST /admin/orders/:id/return", () => {
|
||||
describe("successfully returns full order", () => {
|
||||
@@ -21,6 +21,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund: 10,
|
||||
no_notification: true,
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
@@ -47,6 +48,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund_amount: 10,
|
||||
no_notification: true,
|
||||
shipping_method: undefined,
|
||||
})
|
||||
})
|
||||
@@ -69,6 +71,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund: -1,
|
||||
no_notification: true,
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
@@ -95,6 +98,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund_amount: 0,
|
||||
no_notification: true,
|
||||
shipping_method: undefined,
|
||||
})
|
||||
})
|
||||
@@ -118,6 +122,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
],
|
||||
refund: -1,
|
||||
},
|
||||
no_notification: true,
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: IdMap.getId("admin_user"),
|
||||
@@ -143,6 +148,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund_amount: 0,
|
||||
no_notification: true,
|
||||
shipping_method: undefined,
|
||||
})
|
||||
})
|
||||
@@ -165,6 +171,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund: 100,
|
||||
no_notification: true,
|
||||
return_shipping: {
|
||||
option_id: "opt_1234",
|
||||
price: 12,
|
||||
@@ -195,6 +202,7 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
},
|
||||
],
|
||||
refund_amount: 100,
|
||||
no_notification: true,
|
||||
shipping_method: {
|
||||
option_id: "opt_1234",
|
||||
price: 12,
|
||||
@@ -205,4 +213,82 @@ describe("POST /admin/orders/:id/return", () => {
|
||||
expect(ReturnService.fulfill).toHaveBeenCalledWith("return")
|
||||
})
|
||||
})
|
||||
|
||||
describe("the api call overrides notification settings of order", () => {
|
||||
it("eventBus is called with the proper no notification feature", async () => {
|
||||
jest.clearAllMocks()
|
||||
const subject = await request(
|
||||
"POST",
|
||||
`/admin/orders/${IdMap.getId("test-order")}/return`,
|
||||
{
|
||||
payload: {
|
||||
items: [
|
||||
{
|
||||
item_id: IdMap.getId("existingLine"),
|
||||
quantity: 10,
|
||||
},
|
||||
],
|
||||
refund: 100,
|
||||
return_shipping: {
|
||||
option_id: "opt_1234",
|
||||
price: 12,
|
||||
},
|
||||
no_notification: false,
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: IdMap.getId("admin_user"),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
expect(EventBusServiceMock.emit).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
{
|
||||
id: expect.any(String),
|
||||
no_notification: false,
|
||||
return_id: expect.any(String),
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("the api call inherits notification settings of order", () => {
|
||||
it("eventBus is called with the proper no notification feature", async () => {
|
||||
jest.clearAllMocks()
|
||||
await request(
|
||||
"POST",
|
||||
`/admin/orders/${IdMap.getId("test-order")}/return`,
|
||||
{
|
||||
payload: {
|
||||
items: [
|
||||
{
|
||||
item_id: IdMap.getId("existingLine"),
|
||||
quantity: 10,
|
||||
},
|
||||
],
|
||||
refund: 100,
|
||||
return_shipping: {
|
||||
option_id: "opt_1234",
|
||||
price: 12,
|
||||
},
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: IdMap.getId("admin_user"),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(EventBusServiceMock.emit).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
{
|
||||
id: expect.any(String),
|
||||
no_notification: true,
|
||||
return_id: expect.any(String),
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -91,6 +91,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* refund_amount:
|
||||
* description: The amount to refund the Customer when the Claim type is `refund`.
|
||||
* type: integer
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Claim.
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs to hold additional information.
|
||||
* type: object
|
||||
@@ -108,7 +111,6 @@ import { defaultRelations, defaultFields } from "./"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { id } = req.params
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
type: Validator.string()
|
||||
.valid("replace", "refund")
|
||||
@@ -155,6 +157,7 @@ export default async (req, res) => {
|
||||
.integer()
|
||||
.optional(),
|
||||
shipping_address: Validator.object().optional(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
@@ -162,7 +165,6 @@ export default async (req, res) => {
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
|
||||
const idempotencyKeyService = req.scope.resolve("idempotencyKeyService")
|
||||
|
||||
const headerKey = req.get("Idempotency-Key") || ""
|
||||
@@ -212,6 +214,7 @@ export default async (req, res) => {
|
||||
return_shipping: value.return_shipping,
|
||||
additional_items: value.additional_items,
|
||||
shipping_methods: value.shipping_methods,
|
||||
no_notification: value.no_notification,
|
||||
metadata: value.metadata,
|
||||
})
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* quantity:
|
||||
* description: The quantity of the Line Item to fulfill.
|
||||
* type: integer
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Swap.
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs to hold additional information.
|
||||
* type: object
|
||||
@@ -49,6 +52,7 @@ export default async (req, res) => {
|
||||
quantity: Validator.number().required(),
|
||||
})
|
||||
.required(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
@@ -60,7 +64,10 @@ export default async (req, res) => {
|
||||
try {
|
||||
const orderService = req.scope.resolve("orderService")
|
||||
|
||||
await orderService.createFulfillment(id, value.items, value.metadata)
|
||||
await orderService.createFulfillment(id, value.items, {
|
||||
metadata: value.metadata,
|
||||
no_notification: value.no_notification,
|
||||
})
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
select: defaultFields,
|
||||
|
||||
@@ -27,6 +27,7 @@ export default async (req, res) => {
|
||||
items: Validator.array().optional(),
|
||||
})
|
||||
.required(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Shipment.
|
||||
* type: boolean
|
||||
* tags:
|
||||
* - Order
|
||||
* responses:
|
||||
@@ -41,6 +44,7 @@ export default async (req, res) => {
|
||||
tracking_numbers: Validator.array()
|
||||
.items(Validator.string())
|
||||
.optional(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -54,7 +58,8 @@ export default async (req, res) => {
|
||||
await orderService.createShipment(
|
||||
id,
|
||||
value.fulfillment_id,
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n }))
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n })),
|
||||
{ no_notification: value.no_notification }
|
||||
)
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
|
||||
@@ -22,6 +22,9 @@ import { defaultFields, defaultRelations } from "./"
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Claim.
|
||||
* type: boolean
|
||||
* tags:
|
||||
* - Order
|
||||
* responses:
|
||||
@@ -42,6 +45,7 @@ export default async (req, res) => {
|
||||
tracking_numbers: Validator.array()
|
||||
.items(Validator.string())
|
||||
.optional(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -56,7 +60,8 @@ export default async (req, res) => {
|
||||
await swapService.createShipment(
|
||||
swap_id,
|
||||
value.fulfillment_id,
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n }))
|
||||
value.tracking_numbers.map(n => ({ tracking_number: n })),
|
||||
{ no_notification: value.no_notification }
|
||||
)
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
|
||||
@@ -45,6 +45,9 @@ import { defaultFields, defaultRelations } from "./"
|
||||
* quantity:
|
||||
* description: The quantity of the Product Variant to ship.
|
||||
* type: integer
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Swap.
|
||||
* type: boolean
|
||||
* tags:
|
||||
* - Order
|
||||
* responses:
|
||||
@@ -79,6 +82,7 @@ export default async (req, res) => {
|
||||
variant_id: Validator.string().required(),
|
||||
quantity: Validator.number().required(),
|
||||
}),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -134,7 +138,10 @@ export default async (req, res) => {
|
||||
value.return_items,
|
||||
value.additional_items,
|
||||
value.return_shipping,
|
||||
{ idempotency_key: idempotencyKey.idempotency_key }
|
||||
{
|
||||
idempotency_key: idempotencyKey.idempotency_key,
|
||||
no_notification: value.no_notification,
|
||||
}
|
||||
)
|
||||
|
||||
await swapService.withTransaction(manager).createCart(swap.id)
|
||||
|
||||
@@ -17,6 +17,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs to hold additional information.
|
||||
* type: object
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Claim.
|
||||
* type: boolean
|
||||
* tags:
|
||||
* - Order
|
||||
* responses:
|
||||
@@ -34,6 +37,7 @@ export default async (req, res) => {
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
metadata: Validator.object().optional(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -47,9 +51,10 @@ export default async (req, res) => {
|
||||
const entityManager = req.scope.resolve("manager")
|
||||
|
||||
await entityManager.transaction(async manager => {
|
||||
await claimService
|
||||
.withTransaction(manager)
|
||||
.createFulfillment(claim_id, value.metadata)
|
||||
await claimService.withTransaction(manager).createFulfillment(claim_id, {
|
||||
metadata: value.metadata,
|
||||
no_notification: value.no_notification,
|
||||
})
|
||||
})
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
|
||||
@@ -17,6 +17,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs to hold additional information.
|
||||
* type: object
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Claim.
|
||||
* type: boolean
|
||||
* tags:
|
||||
* - Order
|
||||
* responses:
|
||||
@@ -34,6 +37,7 @@ export default async (req, res) => {
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
metadata: Validator.object().optional(),
|
||||
no_notification: Validator.boolean().optional,
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -47,9 +51,10 @@ export default async (req, res) => {
|
||||
const entityManager = req.scope.resolve("manager")
|
||||
|
||||
await entityManager.transaction(async manager => {
|
||||
await swapService
|
||||
.withTransaction(manager)
|
||||
.createFulfillment(swap_id, value.metadata)
|
||||
await swapService.withTransaction(manager).createFulfillment(swap_id, {
|
||||
metadata: value.metadata,
|
||||
no_notification: value.no_notification,
|
||||
})
|
||||
|
||||
const order = await orderService.withTransaction(manager).retrieve(id, {
|
||||
select: defaultFields,
|
||||
|
||||
@@ -237,6 +237,7 @@ export const defaultFields = [
|
||||
"total",
|
||||
"paid_total",
|
||||
"refundable_amount",
|
||||
"no_notification",
|
||||
]
|
||||
|
||||
export const allowedFields = [
|
||||
@@ -265,6 +266,7 @@ export const allowedFields = [
|
||||
"total",
|
||||
"paid_total",
|
||||
"refundable_amount",
|
||||
"no_notification",
|
||||
]
|
||||
|
||||
export const allowedRelations = [
|
||||
|
||||
@@ -25,6 +25,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* note:
|
||||
* description: A not with additional details about the Refund.
|
||||
* type: string
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Refund.
|
||||
* type: boolean
|
||||
* tags:
|
||||
* - Order
|
||||
* responses:
|
||||
@@ -47,9 +50,11 @@ export default async (req, res) => {
|
||||
note: Validator.string()
|
||||
.allow("")
|
||||
.optional(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
@@ -57,7 +62,13 @@ export default async (req, res) => {
|
||||
try {
|
||||
const orderService = req.scope.resolve("orderService")
|
||||
|
||||
await orderService.createRefund(id, value.amount, value.reason, value.note)
|
||||
await orderService.createRefund(
|
||||
id,
|
||||
value.amount,
|
||||
value.reason,
|
||||
value.note,
|
||||
{ no_notification: value.no_notification }
|
||||
)
|
||||
|
||||
const order = await orderService.retrieve(id, {
|
||||
select: defaultFields,
|
||||
|
||||
@@ -43,6 +43,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* receive_now:
|
||||
* description: A flag to indicate if the Return should be registerd as received immediately.
|
||||
* type: boolean
|
||||
* no_notification:
|
||||
* description: A flag to indicate if no notifications should be emitted related to the requested Return.
|
||||
* type: boolean
|
||||
* refund:
|
||||
* description: The amount to refund.
|
||||
* type: integer
|
||||
@@ -79,6 +82,7 @@ export default async (req, res) => {
|
||||
})
|
||||
.optional(),
|
||||
receive_now: Validator.boolean().default(false),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
refund: Validator.number()
|
||||
.integer()
|
||||
.optional(),
|
||||
@@ -141,6 +145,13 @@ export default async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
let order = await orderService
|
||||
.withTransaction(manager)
|
||||
.retrieve(id)
|
||||
|
||||
const evaluatedNoNotification = value.no_notification !== undefined ? value.no_notification : order.no_notification
|
||||
returnObj.no_notification = evaluatedNoNotification
|
||||
|
||||
const createdReturn = await returnService
|
||||
.withTransaction(manager)
|
||||
.create(returnObj)
|
||||
@@ -150,12 +161,13 @@ export default async (req, res) => {
|
||||
.withTransaction(manager)
|
||||
.fulfill(createdReturn.id)
|
||||
}
|
||||
|
||||
|
||||
await eventBus
|
||||
.withTransaction(manager)
|
||||
.emit("order.return_requested", {
|
||||
id,
|
||||
return_id: createdReturn.id,
|
||||
no_notification: evaluatedNoNotification
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -62,6 +62,9 @@ import { defaultRelations, defaultFields } from "./"
|
||||
* price:
|
||||
* description: The price to charge for the Shipping Method
|
||||
* type: integer
|
||||
* no_notification:
|
||||
* description: If set to true no notification will be send related to this Swap.
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs to hold additional information.
|
||||
* type: object
|
||||
@@ -106,6 +109,7 @@ export default async (req, res) => {
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
no_notification: Validator.boolean().optional(),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ export default async (req, res) => {
|
||||
data: Validator.object(),
|
||||
items: Validator.array(),
|
||||
}),
|
||||
no_notification: Validator.boolean(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
|
||||
@@ -54,6 +54,7 @@ export default async (req, res) => {
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IdMap } from "medusa-test-utils"
|
||||
import { request } from "../../../../../helpers/test-request"
|
||||
import { CustomerServiceMock } from "../../../../../services/__mocks__/customer"
|
||||
import { defaultFields, defaultRelations } from "../"
|
||||
|
||||
describe("POST /store/customers", () => {
|
||||
describe("successfully creates a customer", () => {
|
||||
@@ -34,7 +35,7 @@ describe("POST /store/customers", () => {
|
||||
expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
||||
expect(CustomerServiceMock.retrieve).toHaveBeenCalledWith(
|
||||
IdMap.getId("lebron"),
|
||||
{ relations: ["shipping_addresses"] }
|
||||
{ relations: defaultRelations, select: defaultFields }
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IdMap } from "medusa-test-utils"
|
||||
import { request } from "../../../../../helpers/test-request"
|
||||
import { defaultFields, defaultRelations } from "../"
|
||||
import { CustomerServiceMock } from "../../../../../services/__mocks__/customer"
|
||||
|
||||
describe("POST /store/customers/:id", () => {
|
||||
@@ -42,7 +43,7 @@ describe("POST /store/customers/:id", () => {
|
||||
expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
||||
expect(CustomerServiceMock.retrieve).toHaveBeenCalledWith(
|
||||
IdMap.getId("lebron"),
|
||||
{ relations: ["shipping_addresses"] }
|
||||
{ relations: defaultRelations, select: defaultFields }
|
||||
)
|
||||
})
|
||||
|
||||
@@ -55,6 +56,98 @@ describe("POST /store/customers/:id", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("successfully updates a customer with billing address id", () => {
|
||||
let subject
|
||||
beforeAll(async () => {
|
||||
subject = await request(
|
||||
"POST",
|
||||
`/store/customers/${IdMap.getId("lebron")}`,
|
||||
{
|
||||
payload: {
|
||||
billing_address: "test",
|
||||
},
|
||||
clientSession: {
|
||||
jwt: {
|
||||
customer_id: IdMap.getId("lebron"),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("calls CustomerService update", () => {
|
||||
expect(CustomerServiceMock.update).toHaveBeenCalledTimes(1)
|
||||
expect(CustomerServiceMock.update).toHaveBeenCalledWith(
|
||||
IdMap.getId("lebron"),
|
||||
{
|
||||
billing_address: "test",
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("status code 200", () => {
|
||||
expect(subject.status).toEqual(200)
|
||||
})
|
||||
})
|
||||
|
||||
describe("successfully updates a customer with billing address object", () => {
|
||||
let subject
|
||||
beforeAll(async () => {
|
||||
subject = await request(
|
||||
"POST",
|
||||
`/store/customers/${IdMap.getId("lebron")}`,
|
||||
{
|
||||
payload: {
|
||||
billing_address: {
|
||||
first_name: "Olli",
|
||||
last_name: "Juhl",
|
||||
address_1: "Laksegade",
|
||||
city: "Copenhagen",
|
||||
country_code: "dk",
|
||||
postal_code: "2100",
|
||||
phone: "+1 (222) 333 4444",
|
||||
},
|
||||
},
|
||||
clientSession: {
|
||||
jwt: {
|
||||
customer_id: IdMap.getId("lebron"),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("calls CustomerService update", () => {
|
||||
expect(CustomerServiceMock.update).toHaveBeenCalledTimes(1)
|
||||
expect(CustomerServiceMock.update).toHaveBeenCalledWith(
|
||||
IdMap.getId("lebron"),
|
||||
{
|
||||
billing_address: {
|
||||
first_name: "Olli",
|
||||
last_name: "Juhl",
|
||||
address_1: "Laksegade",
|
||||
city: "Copenhagen",
|
||||
country_code: "dk",
|
||||
postal_code: "2100",
|
||||
phone: "+1 (222) 333 4444",
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("status code 200", () => {
|
||||
expect(subject.status).toEqual(200)
|
||||
})
|
||||
})
|
||||
|
||||
describe("fails if not authenticated", () => {
|
||||
let subject
|
||||
beforeAll(async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /customers/{id}/addresses
|
||||
@@ -45,7 +46,8 @@ export default async (req, res) => {
|
||||
|
||||
let customer = await customerService.addAddress(id, value.address)
|
||||
customer = await customerService.retrieve(id, {
|
||||
relations: ["shipping_addresses"],
|
||||
relations: defaultRelations,
|
||||
select: defaultFields,
|
||||
})
|
||||
|
||||
res.status(200).json({ customer })
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import jwt from "jsonwebtoken"
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import config from "../../../../config"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /customers
|
||||
@@ -40,6 +41,7 @@ export default async (req, res) => {
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
|
||||
try {
|
||||
const customerService = req.scope.resolve("customerService")
|
||||
let customer = await customerService.create(value)
|
||||
@@ -50,7 +52,8 @@ export default async (req, res) => {
|
||||
})
|
||||
|
||||
customer = await customerService.retrieve(customer.id, {
|
||||
relations: ["shipping_addresses"],
|
||||
relations: defaultRelations,
|
||||
select: defaultFields,
|
||||
})
|
||||
|
||||
res.status(200).json({ customer })
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [delete] /customers/{id}/addresses/{address_id}
|
||||
* operationId: DeleteCustomersCustomerAddressesAddress
|
||||
@@ -25,7 +27,8 @@ export default async (req, res) => {
|
||||
try {
|
||||
await customerService.removeAddress(id, address_id)
|
||||
customer = await customerService.retrieve(id, {
|
||||
relations: ["shipping_addresses"],
|
||||
relations: defaultRelations,
|
||||
select: defaultFields,
|
||||
})
|
||||
|
||||
res.json({ customer })
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [get] /customers/{id}
|
||||
* operationId: GetCustomersCustomer
|
||||
@@ -22,7 +24,8 @@ export default async (req, res) => {
|
||||
try {
|
||||
const customerService = req.scope.resolve("customerService")
|
||||
const customer = await customerService.retrieve(id, {
|
||||
relations: ["shipping_addresses"],
|
||||
relations: defaultRelations,
|
||||
select: defaultFields,
|
||||
})
|
||||
res.json({ customer })
|
||||
} catch (err) {
|
||||
|
||||
@@ -57,3 +57,39 @@ export default (app, container) => {
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export const defaultRelations = ["shipping_addresses", "billing_address"]
|
||||
|
||||
export const defaultFields = [
|
||||
"id",
|
||||
"email",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"billing_address_id",
|
||||
"phone",
|
||||
"has_account",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
]
|
||||
|
||||
export const allowedRelations = [
|
||||
"shipping_addresses",
|
||||
"billing_address",
|
||||
"orders",
|
||||
]
|
||||
|
||||
export const allowedFields = [
|
||||
"id",
|
||||
"email",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"billing_address_id",
|
||||
"phone",
|
||||
"has_account",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"deleted_at",
|
||||
"metadata",
|
||||
]
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /customers/{id}/addresses/{address_id}
|
||||
@@ -50,7 +51,8 @@ export default async (req, res) => {
|
||||
)
|
||||
|
||||
customer = await customerService.retrieve(id, {
|
||||
relations: ["shipping_addresses"],
|
||||
relations: defaultRelations,
|
||||
select: defaultFields,
|
||||
})
|
||||
|
||||
res.json({ customer })
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { defaultRelations, defaultFields } from "./"
|
||||
|
||||
/**
|
||||
* @oas [post] /customers/{id}
|
||||
@@ -18,12 +19,19 @@ import { Validator, MedusaError } from "medusa-core-utils"
|
||||
* last_name:
|
||||
* description: "The Customer's last name."
|
||||
* type: string
|
||||
* billing_address:
|
||||
* description: "The Address to be used for billing purposes."
|
||||
* anyOf:
|
||||
* - $ref: "#/components/schemas/address"
|
||||
* password:
|
||||
* description: "The Customer's password."
|
||||
* type: string
|
||||
* phone:
|
||||
* description: "The Customer's phone number."
|
||||
* type: string
|
||||
* metadata:
|
||||
* description: "Metadata about the customer."
|
||||
* type: object
|
||||
* tags:
|
||||
* - Customer
|
||||
* responses:
|
||||
@@ -40,10 +48,12 @@ export default async (req, res) => {
|
||||
const { id } = req.params
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
billing_address: Validator.address().optional(),
|
||||
first_name: Validator.string().optional(),
|
||||
last_name: Validator.string().optional(),
|
||||
password: Validator.string().optional(),
|
||||
phone: Validator.string().optional(),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
@@ -56,7 +66,8 @@ export default async (req, res) => {
|
||||
let customer = await customerService.update(id, value)
|
||||
|
||||
customer = await customerService.retrieve(customer.id, {
|
||||
relations: ["shipping_addresses"],
|
||||
relations: defaultRelations,
|
||||
select: defaultFields,
|
||||
})
|
||||
|
||||
res.status(200).json({ customer })
|
||||
|
||||
@@ -30,6 +30,7 @@ export default app => {
|
||||
export const defaultRelations = [
|
||||
"shipping_address",
|
||||
"fulfillments",
|
||||
"fulfillments.tracking_links",
|
||||
"items",
|
||||
"items.variant",
|
||||
"items.variant.product",
|
||||
@@ -66,6 +67,7 @@ export const defaultFields = [
|
||||
export const allowedRelations = [
|
||||
"shipping_address",
|
||||
"fulfillments",
|
||||
"fulfillments.tracking_links",
|
||||
"billing_address",
|
||||
"items",
|
||||
"items.variant",
|
||||
|
||||
@@ -43,3 +43,4 @@ export { Swap } from "./models/swap"
|
||||
export { User } from "./models/user"
|
||||
export { DraftOrder } from "./models/draft-order"
|
||||
export { ReturnReason } from "./models/return-reason"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class noNotification1623231564533 implements MigrationInterface {
|
||||
name = 'noNotification1623231564533'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "return" ADD "no_notification" boolean`);
|
||||
await queryRunner.query(`ALTER TABLE "claim_order" ADD "no_notification" boolean`);
|
||||
await queryRunner.query(`ALTER TABLE "swap" ADD "no_notification" boolean`);
|
||||
await queryRunner.query(`ALTER TABLE "order" ADD "no_notification" boolean`);
|
||||
await queryRunner.query(`ALTER TABLE "draft_order" ADD "no_notification_order" boolean`);
|
||||
await queryRunner.query(`ALTER TABLE "fulfillment" ADD "no_notification" boolean`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "fulfillment" DROP COLUMN "no_notification"`);
|
||||
await queryRunner.query(`ALTER TABLE "draft_order" DROP COLUMN "no_notification_order"`);
|
||||
await queryRunner.query(`ALTER TABLE "order" DROP COLUMN "no_notification"`);
|
||||
await queryRunner.query(`ALTER TABLE "swap" DROP COLUMN "no_notification"`);
|
||||
await queryRunner.query(`ALTER TABLE "claim_order" DROP COLUMN "no_notification"`);
|
||||
await queryRunner.query(`ALTER TABLE "return" DROP COLUMN "no_notification"`);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,28 +4,16 @@ export class gcRemoveUniqueOrder1624287602631 implements MigrationInterface {
|
||||
name = "gcRemoveUniqueOrder1624287602631"
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "gift_card" DROP CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0"`
|
||||
)
|
||||
await queryRunner.query(`ALTER TABLE "gift_card" DROP CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0"`)
|
||||
await queryRunner.query(`COMMENT ON COLUMN "gift_card"."order_id" IS NULL`)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "gift_card" DROP CONSTRAINT "REL_dfc1f02bb0552e79076aa58dbb"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "gift_card" ADD CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0" FOREIGN KEY ("order_id") REFERENCES "order"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
await queryRunner.query(`ALTER TABLE "gift_card" DROP CONSTRAINT "REL_dfc1f02bb0552e79076aa58dbb"`)
|
||||
await queryRunner.query(`ALTER TABLE "gift_card" ADD CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0" FOREIGN KEY ("order_id") REFERENCES "order"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "gift_card" DROP CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "gift_card" ADD CONSTRAINT "REL_dfc1f02bb0552e79076aa58dbb" UNIQUE ("order_id")`
|
||||
)
|
||||
await queryRunner.query(`ALTER TABLE "gift_card" DROP CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0"`)
|
||||
await queryRunner.query(`ALTER TABLE "gift_card" ADD CONSTRAINT "REL_dfc1f02bb0552e79076aa58dbb" UNIQUE ("order_id")`)
|
||||
await queryRunner.query(`COMMENT ON COLUMN "gift_card"."order_id" IS NULL`)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "gift_card" ADD CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0" FOREIGN KEY ("order_id") REFERENCES "order"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
await queryRunner.query(`ALTER TABLE "gift_card" ADD CONSTRAINT "FK_dfc1f02bb0552e79076aa58dbb0" FOREIGN KEY ("order_id") REFERENCES "order"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||
|
||||
export class softDeletingUniqueConstraints1624610325746 implements MigrationInterface {
|
||||
name = 'softDeletingUniqueConstraints1624610325746'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP INDEX "IDX_6910923cb678fd6e99011a21cc"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_db7355f7bd36c547c8a4f539e5"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_087926f6fec32903be3c8eedfa"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_f4dc2c0888b66d547c175f090e"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_9db95c4b71f632fc93ecbc3d8b"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_7124082c8846a06a857cca386c"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_a0a3f124dc5b167622217fee02"`);
|
||||
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e08af711f3493df1e921c4c9ef" ON "product_collection" ("handle") WHERE deleted_at IS NOT NULL`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_77c4073c30ea7793f484750529" ON "product" ("handle") WHERE deleted_at IS NOT NULL`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ae3e22c67d7c7a969a363533c0" ON "discount" ("code") WHERE deleted_at IS NOT NULL`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0683952543d7d3f4fffc427034" ON "product_variant" ("sku") WHERE deleted_at IS NOT NULL`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_410649600ce31c10c4b667ca10" ON "product_variant" ("barcode") WHERE deleted_at IS NOT NULL`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5248fda27b9f16ef818604bb6f" ON "product_variant" ("ean") WHERE deleted_at IS NOT NULL`);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_832f86daf8103491d634a967da" ON "product_variant" ("upc") WHERE deleted_at IS NOT NULL`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP INDEX "IDX_ae3e22c67d7c7a969a363533c0"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_77c4073c30ea7793f484750529"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_e08af711f3493df1e921c4c9ef"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_832f86daf8103491d634a967da"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_5248fda27b9f16ef818604bb6f"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_410649600ce31c10c4b667ca10"`);
|
||||
await queryRunner.query(`DROP INDEX "IDX_0683952543d7d3f4fffc427034"`);
|
||||
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_087926f6fec32903be3c8eedfa" ON "discount" ("code") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_db7355f7bd36c547c8a4f539e5" ON "product" ("handle") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_6910923cb678fd6e99011a21cc" ON "product_collection" ("handle") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a0a3f124dc5b167622217fee02" ON "product_variant" ("upc") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_7124082c8846a06a857cca386c" ON "product_variant" ("ean") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_9db95c4b71f632fc93ecbc3d8b" ON "product_variant" ("barcode") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_f4dc2c0888b66d547c175f090e" ON "product_variant" ("sku") `);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -246,7 +246,7 @@ export class Cart {
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
context: any
|
||||
|
||||
|
||||
// Total fields
|
||||
shipping_total: number
|
||||
discount_total: number
|
||||
|
||||
@@ -134,6 +134,9 @@ export class ClaimOrder {
|
||||
@DeleteDateColumn({ type: "timestamptz" })
|
||||
deleted_at: Date
|
||||
|
||||
@Column({ type: "boolean", nullable: true})
|
||||
no_notification: Boolean
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
|
||||
@@ -223,6 +226,9 @@ export class ClaimOrder {
|
||||
* deleted_at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* no_notification:
|
||||
* description: "Flag for describing whether or not notifications related to this should be send."
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* type: object
|
||||
*/
|
||||
@@ -23,7 +23,7 @@ export class Discount {
|
||||
@PrimaryColumn()
|
||||
id: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
@Column()
|
||||
code: string
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ export class DraftOrder {
|
||||
@Column({ type: "timestamptz", nullable: true })
|
||||
completed_at: Date
|
||||
|
||||
@Column({ nullable: true})
|
||||
no_notification_order: boolean
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
|
||||
@@ -115,6 +118,8 @@ export class DraftOrder {
|
||||
* completed_at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* no_notification_order:
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* type: object
|
||||
* idempotency_key:
|
||||
|
||||
@@ -62,6 +62,9 @@ export class Fulfillment {
|
||||
@JoinColumn({ name: "order_id" })
|
||||
order: Order
|
||||
|
||||
@Column({ type: "boolean", nullable: true})
|
||||
no_notification: Boolean
|
||||
|
||||
@Index()
|
||||
@Column()
|
||||
provider_id: string
|
||||
@@ -157,6 +160,9 @@ export class Fulfillment {
|
||||
* description: "The date with timezone at which the Fulfillment was shipped."
|
||||
* type: string
|
||||
* format: date-time
|
||||
* no_notification:
|
||||
* description: "Flag for describing whether or not notifications related to this should be send."
|
||||
* type: boolean
|
||||
* canceled_at:
|
||||
* description: "The date with timezone at which the Fulfillment was canceled."
|
||||
* type: string
|
||||
|
||||
@@ -245,6 +245,9 @@ export class Order {
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
|
||||
@Column({ type: "boolean", nullable: true})
|
||||
no_notification: Boolean
|
||||
|
||||
@Column({ nullable: true })
|
||||
idempotency_key: string
|
||||
|
||||
@@ -414,4 +417,7 @@ export class Order {
|
||||
* type: integer
|
||||
* paid_total:
|
||||
* type: integer
|
||||
* no_notification:
|
||||
* description: "Flag for describing whether or not notifications related to this should be send."
|
||||
* type: boolean
|
||||
*/
|
||||
@@ -23,7 +23,7 @@ export class ProductCollection {
|
||||
@Column()
|
||||
title: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
@Column({ nullable: true })
|
||||
handle: string
|
||||
|
||||
|
||||
@@ -47,19 +47,19 @@ export class ProductVariant {
|
||||
prices: MoneyAmount[]
|
||||
|
||||
@Column({ nullable: true })
|
||||
@Index({ unique: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
sku: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column({ nullable: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
barcode: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column({ nullable: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
ean: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Column({ nullable: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
upc: string
|
||||
|
||||
@Column({ type: "int" })
|
||||
|
||||
@@ -39,7 +39,7 @@ export class Product {
|
||||
@Column({ nullable: true })
|
||||
description: string
|
||||
|
||||
@Index({ unique: true })
|
||||
@Index({ unique: true, where: "deleted_at IS NOT NULL" })
|
||||
@Column({ nullable: true })
|
||||
handle: string
|
||||
|
||||
|
||||
@@ -99,6 +99,9 @@ export class Return {
|
||||
@UpdateDateColumn({ type: "timestamptz" })
|
||||
updated_at: Date
|
||||
|
||||
@Column({ type: "boolean", nullable: true})
|
||||
no_notification: Boolean
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
|
||||
@@ -165,6 +168,9 @@ export class Return {
|
||||
* description: "The date with timezone at which the resource was last updated."
|
||||
* type: string
|
||||
* format: date-time
|
||||
* no_notification:
|
||||
* description: "When set to true, no notification will be sent related to this return."
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: "An optional key-value map with additional information."
|
||||
* type: object
|
||||
|
||||
@@ -130,6 +130,9 @@ export class Swap {
|
||||
@DeleteDateColumn({ type: "timestamptz" })
|
||||
deleted_at: Date
|
||||
|
||||
@Column({ type: "boolean", nullable: true})
|
||||
no_notification: Boolean
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: any
|
||||
|
||||
@@ -224,6 +227,9 @@ export class Swap {
|
||||
* description: "The date with timezone at which the resource was last updated."
|
||||
* type: string
|
||||
* format: date-time
|
||||
* no_notification:
|
||||
* description: "If set to true, no notification will be sent related to this swap"
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: "An optional key-value map with additional information."
|
||||
* type: object
|
||||
|
||||
@@ -1,5 +1,61 @@
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
import { flatten, groupBy, map, merge } from "lodash"
|
||||
import { EntityRepository, FindManyOptions, Repository } from "typeorm"
|
||||
import { GiftCard } from "../models/gift-card"
|
||||
|
||||
@EntityRepository(GiftCard)
|
||||
export class GiftCardRepository extends Repository<GiftCard> {}
|
||||
export class GiftCardRepository extends Repository<GiftCard> {
|
||||
public async findWithRelations(
|
||||
relations: Array<keyof GiftCard> = [],
|
||||
idsOrOptionsWithoutRelations: Omit<
|
||||
FindManyOptions<GiftCard>,
|
||||
"relations"
|
||||
> = {}
|
||||
): Promise<GiftCard[]> {
|
||||
let entities
|
||||
if (Array.isArray(idsOrOptionsWithoutRelations)) {
|
||||
entities = await this.findByIds(idsOrOptionsWithoutRelations)
|
||||
} else {
|
||||
entities = await this.find(idsOrOptionsWithoutRelations)
|
||||
}
|
||||
const entitiesIds = entities.map(({ id }) => id)
|
||||
|
||||
const groupedRelations = {}
|
||||
for (const rel of relations) {
|
||||
const [topLevel] = rel.split(".")
|
||||
if (groupedRelations[topLevel]) {
|
||||
groupedRelations[topLevel].push(rel)
|
||||
} else {
|
||||
groupedRelations[topLevel] = [rel]
|
||||
}
|
||||
}
|
||||
|
||||
const entitiesIdsWithRelations = await Promise.all(
|
||||
Object.entries(groupedRelations).map(([_, rels]) => {
|
||||
return this.findByIds(entitiesIds, {
|
||||
select: ["id"],
|
||||
relations: rels as string[],
|
||||
})
|
||||
})
|
||||
).then(flatten)
|
||||
const entitiesAndRelations = entitiesIdsWithRelations.concat(entities)
|
||||
|
||||
const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id")
|
||||
return map(entitiesAndRelationsById, entityAndRelations =>
|
||||
merge({}, ...entityAndRelations)
|
||||
)
|
||||
}
|
||||
|
||||
public async findOneWithRelations(
|
||||
relations: Array<keyof GiftCard> = [],
|
||||
optionsWithoutRelations: Omit<FindManyOptions<GiftCard>, "relations"> = {}
|
||||
): Promise<GiftCard> {
|
||||
// Limit 1
|
||||
optionsWithoutRelations.take = 1
|
||||
|
||||
const result = await this.findWithRelations(
|
||||
relations,
|
||||
optionsWithoutRelations
|
||||
)
|
||||
return result[0]
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ export const orders = {
|
||||
providerid: "default_provider",
|
||||
data: {},
|
||||
},
|
||||
no_notification: true,
|
||||
shipping_method: [
|
||||
{
|
||||
providerid: "default_provider",
|
||||
@@ -99,6 +100,7 @@ export const orders = {
|
||||
payment_method: {
|
||||
providerid: "default_provider",
|
||||
},
|
||||
no_notification: false,
|
||||
shipping_methods: [
|
||||
{
|
||||
id: IdMap.getId("expensiveShipping"),
|
||||
|
||||
@@ -22,6 +22,7 @@ describe("ClaimService", () => {
|
||||
order: {
|
||||
id: "1234",
|
||||
region_id: "order_region",
|
||||
no_notification: true,
|
||||
items: [
|
||||
{
|
||||
id: "itm_1",
|
||||
@@ -113,6 +114,7 @@ describe("ClaimService", () => {
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
no_notification: true,
|
||||
})
|
||||
|
||||
expect(withTransactionMock).toHaveBeenCalledWith("lineItem")
|
||||
@@ -138,6 +140,7 @@ describe("ClaimService", () => {
|
||||
expect(claimRepo.create).toHaveBeenCalledTimes(1)
|
||||
expect(claimRepo.create).toHaveBeenCalledWith({
|
||||
payment_status: "not_refunded",
|
||||
no_notification: true,
|
||||
refund_amount: 1000,
|
||||
type: "refund",
|
||||
order_id: "1234",
|
||||
@@ -156,6 +159,7 @@ describe("ClaimService", () => {
|
||||
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusService.emit).toHaveBeenCalledWith("claim.created", {
|
||||
id: "claim_134",
|
||||
no_notification: true,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -208,6 +212,25 @@ describe("ClaimService", () => {
|
||||
})
|
||||
).rejects.toThrow(`Claims must have at least one claim item.`)
|
||||
})
|
||||
|
||||
it.each(
|
||||
[
|
||||
[false, false],
|
||||
[undefined, true],
|
||||
],
|
||||
"passes correct no_notification status to event bus",
|
||||
async (input, expected) => {
|
||||
await claimService.create({
|
||||
...testClaim,
|
||||
no_notification: input,
|
||||
})
|
||||
|
||||
expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), {
|
||||
id: expect.any(String),
|
||||
no_notification: expected,
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe("retrieve", () => {
|
||||
@@ -294,7 +317,9 @@ describe("ClaimService", () => {
|
||||
})
|
||||
|
||||
it("successfully creates fulfillment", async () => {
|
||||
await claimService.createFulfillment("claim_id", { meta: "data" })
|
||||
await claimService.createFulfillment("claim_id", {
|
||||
metadata: { meta: "data" },
|
||||
})
|
||||
|
||||
expect(withTransactionMock).toHaveBeenCalledTimes(3)
|
||||
expect(withTransactionMock).toHaveBeenCalledWith("eventBus")
|
||||
@@ -414,7 +439,10 @@ describe("ClaimService", () => {
|
||||
)
|
||||
|
||||
await claimService.createShipment("claim", "ful_123", ["track1234"], {
|
||||
meta: "data",
|
||||
metadata: {
|
||||
meta: "data",
|
||||
},
|
||||
no_notification: false,
|
||||
})
|
||||
|
||||
expect(withTransactionMock).toHaveBeenCalledTimes(3)
|
||||
@@ -426,7 +454,12 @@ describe("ClaimService", () => {
|
||||
expect(fulfillmentService.createShipment).toHaveBeenCalledWith(
|
||||
"ful_123",
|
||||
["track1234"],
|
||||
{ meta: "data" }
|
||||
{
|
||||
metadata: {
|
||||
meta: "data",
|
||||
},
|
||||
no_notification: false,
|
||||
}
|
||||
)
|
||||
|
||||
expect(lineItemService.update).toHaveBeenCalledTimes(1)
|
||||
|
||||
@@ -168,8 +168,14 @@ describe("CustomerService", () => {
|
||||
},
|
||||
})
|
||||
|
||||
const addressRepository = MockRepository({
|
||||
create: data => data,
|
||||
save: data => Promise.resolve(data),
|
||||
})
|
||||
|
||||
const customerService = new CustomerService({
|
||||
manager: MockManager,
|
||||
addressRepository,
|
||||
customerRepository,
|
||||
eventBusService,
|
||||
})
|
||||
@@ -233,7 +239,7 @@ describe("CustomerService", () => {
|
||||
last_name: "Juhl",
|
||||
address_1: "Laksegade",
|
||||
city: "Copenhagen",
|
||||
country_code: "DK",
|
||||
country_code: "dk",
|
||||
postal_code: "2100",
|
||||
phone: "+1 (222) 333 4444",
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import _ from "lodash"
|
||||
import { IdMap, MockRepository, MockManager } from "medusa-test-utils"
|
||||
import { MockRepository, MockManager } from "medusa-test-utils"
|
||||
import { EventBusServiceMock } from "../__mocks__/event-bus"
|
||||
import DraftOrderService from "../draft-order"
|
||||
|
||||
const eventBusService = {
|
||||
@@ -205,4 +206,93 @@ describe("DraftOrderService", () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("update", () => {
|
||||
const testOrder = {
|
||||
region_id: "test-region",
|
||||
shipping_address_id: "test-shipping",
|
||||
billing_address_id: "test-billing",
|
||||
customer_id: "test-customer",
|
||||
items: [{ variant_id: "test-variant", quantity: 2, metadata: {} }],
|
||||
shipping_methods: [
|
||||
{
|
||||
option_id: "test-option",
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const completedOrder = {
|
||||
status: "completed",
|
||||
...testOrder,
|
||||
}
|
||||
|
||||
const draftOrderRepository = MockRepository({
|
||||
create: d => ({
|
||||
...d,
|
||||
}),
|
||||
save: d => ({
|
||||
id: "test-draft-order",
|
||||
...d,
|
||||
}),
|
||||
findOne: q => {
|
||||
switch (q.where.id) {
|
||||
case "completed":
|
||||
return Promise.resolve(completedOrder)
|
||||
default:
|
||||
return Promise.resolve(testOrder)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const draftOrderService = new DraftOrderService({
|
||||
manager: MockManager,
|
||||
regionService: undefined,
|
||||
cartService: undefined,
|
||||
shippingOptionService: undefined,
|
||||
lineItemService: undefined,
|
||||
productVariantService: undefined,
|
||||
draftOrderRepository,
|
||||
addressRepository: undefined,
|
||||
eventBusService: EventBusServiceMock,
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("calls draftOrder model functions", async () => {
|
||||
await draftOrderService.update("test-draft-order", {
|
||||
no_notification_order: true,
|
||||
})
|
||||
|
||||
expect(draftOrderRepository.save).toHaveBeenCalledTimes(1)
|
||||
expect(draftOrderRepository.save).toHaveBeenCalledWith({
|
||||
no_notification_order: true,
|
||||
billing_address_id: "test-billing",
|
||||
customer_id: "test-customer",
|
||||
items: [
|
||||
{
|
||||
metadata: {},
|
||||
quantity: 2,
|
||||
variant_id: "test-variant",
|
||||
},
|
||||
],
|
||||
region_id: "test-region",
|
||||
shipping_address_id: "test-shipping",
|
||||
shipping_methods: [
|
||||
{
|
||||
data: {},
|
||||
option_id: "test-option",
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it("fails to update draftOrder when already complete", async () => {
|
||||
await expect(draftOrderService.update("completed", {})).rejects.toThrow(
|
||||
"Can't update a draft order which is complete"
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,256 @@
|
||||
import { IdMap, MockManager, MockRepository } from "medusa-test-utils"
|
||||
|
||||
import GiftCardService from "../gift-card"
|
||||
|
||||
describe("GiftCardService", () => {
|
||||
const eventBusService = {
|
||||
emit: jest.fn(),
|
||||
withTransaction: function() {
|
||||
return this
|
||||
},
|
||||
}
|
||||
|
||||
describe("create", () => {
|
||||
const giftCardRepo = MockRepository({
|
||||
create: s => {
|
||||
return Promise.resolve(s)
|
||||
},
|
||||
save: s => {
|
||||
return Promise.resolve(s)
|
||||
},
|
||||
})
|
||||
|
||||
const regionService = {
|
||||
withTransaction: function() {
|
||||
return this
|
||||
},
|
||||
retrieve: () => {
|
||||
return Promise.resolve({
|
||||
id: IdMap.getId("region-id"),
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
const giftCardService = new GiftCardService({
|
||||
manager: MockManager,
|
||||
giftCardRepository: giftCardRepo,
|
||||
regionService: regionService,
|
||||
eventBusService: eventBusService,
|
||||
})
|
||||
|
||||
const giftCard = {
|
||||
region_id: IdMap.getId("region-id"),
|
||||
order_id: IdMap.getId("order-id"),
|
||||
is_disabled: true,
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("correctly creates a giftcard", async () => {
|
||||
await giftCardService.create(giftCard)
|
||||
|
||||
expect(giftCardRepo.create).toHaveBeenCalledTimes(1)
|
||||
expect(giftCardRepo.create).toHaveBeenCalledWith({
|
||||
region_id: IdMap.getId("region-id"),
|
||||
order_id: IdMap.getId("order-id"),
|
||||
is_disabled: true,
|
||||
code: expect.any(String),
|
||||
})
|
||||
})
|
||||
|
||||
it("fails to create giftcard if no region is provided", async () => {
|
||||
const card = {
|
||||
...giftCard,
|
||||
}
|
||||
|
||||
card.region_id = undefined
|
||||
|
||||
await expect(giftCardService.create(card)).rejects.toThrow(
|
||||
"Gift card is missing region_id"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("retrieve", () => {
|
||||
const giftCardRepo = MockRepository({
|
||||
findOneWithRelations: () => {
|
||||
return Promise.resolve({})
|
||||
},
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
const giftCardService = new GiftCardService({
|
||||
manager: MockManager,
|
||||
giftCardRepository: giftCardRepo,
|
||||
})
|
||||
|
||||
it("it calls order model functions", async () => {
|
||||
await giftCardService.retrieve(IdMap.getId("gift-card"), {
|
||||
relations: ["region"],
|
||||
select: ["id"],
|
||||
})
|
||||
|
||||
expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledTimes(1)
|
||||
expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledWith(
|
||||
["region"],
|
||||
{
|
||||
where: {
|
||||
id: IdMap.getId("gift-card"),
|
||||
},
|
||||
select: ["id"],
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("retrieveByCode", () => {
|
||||
const giftCardRepo = MockRepository({
|
||||
findOneWithRelations: () => {
|
||||
return Promise.resolve({})
|
||||
},
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
const giftCardService = new GiftCardService({
|
||||
manager: MockManager,
|
||||
giftCardRepository: giftCardRepo,
|
||||
})
|
||||
|
||||
it("it calls order model functions", async () => {
|
||||
await giftCardService.retrieveByCode("1234-1234-1234-1234", {
|
||||
relations: ["region"],
|
||||
select: ["id"],
|
||||
})
|
||||
|
||||
expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledTimes(1)
|
||||
expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledWith(
|
||||
["region"],
|
||||
{
|
||||
where: {
|
||||
code: "1234-1234-1234-1234",
|
||||
},
|
||||
select: ["id"],
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("update", () => {
|
||||
const giftCard = {
|
||||
region_id: IdMap.getId("region-id"),
|
||||
order_id: IdMap.getId("order-id"),
|
||||
is_disabled: true,
|
||||
value: 5000,
|
||||
}
|
||||
|
||||
const giftCardRepo = MockRepository({
|
||||
findOneWithRelations: s => {
|
||||
return Promise.resolve(giftCard)
|
||||
},
|
||||
save: s => {
|
||||
return Promise.resolve(s)
|
||||
},
|
||||
})
|
||||
|
||||
const regionService = {
|
||||
withTransaction: function() {
|
||||
return this
|
||||
},
|
||||
retrieve: () => {
|
||||
return Promise.resolve({
|
||||
id: IdMap.getId("other-region"),
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
const giftCardService = new GiftCardService({
|
||||
manager: MockManager,
|
||||
giftCardRepository: giftCardRepo,
|
||||
regionService: regionService,
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("calls order model functions", async () => {
|
||||
await giftCardService.update(IdMap.getId("giftcard-id"), {
|
||||
is_disabled: false,
|
||||
region_id: IdMap.getId("other-region"),
|
||||
})
|
||||
|
||||
expect(giftCardRepo.save).toHaveBeenCalledTimes(1)
|
||||
expect(giftCardRepo.save).toHaveBeenCalledWith({
|
||||
region_id: IdMap.getId("other-region"),
|
||||
order_id: IdMap.getId("order-id"),
|
||||
is_disabled: false,
|
||||
value: 5000,
|
||||
})
|
||||
})
|
||||
|
||||
it.each([[-100], [6000]])(
|
||||
"fails to update balance with illegal input '%s'",
|
||||
async input => {
|
||||
await expect(
|
||||
giftCardService.update(IdMap.getId("giftcard-id"), {
|
||||
balance: input,
|
||||
})
|
||||
).rejects.toThrow("new balance is invalid")
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe("delete", () => {
|
||||
const giftCard = {
|
||||
region_id: IdMap.getId("region-id"),
|
||||
order_id: IdMap.getId("order-id"),
|
||||
}
|
||||
|
||||
const giftCardRepo = MockRepository({
|
||||
findOne: s => {
|
||||
switch (s.where.id) {
|
||||
case IdMap.getId("gift-card"):
|
||||
return Promise.resolve(giftCard)
|
||||
default:
|
||||
return Promise.resolve()
|
||||
}
|
||||
},
|
||||
softRemove: s => {
|
||||
return Promise.resolve()
|
||||
},
|
||||
})
|
||||
|
||||
const giftCardService = new GiftCardService({
|
||||
manager: MockManager,
|
||||
giftCardRepository: giftCardRepo,
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("successfully deletes existing gift-card", async () => {
|
||||
await giftCardService.delete(IdMap.getId("gift-card"))
|
||||
|
||||
expect(giftCardRepo.softRemove).toHaveBeenCalledTimes(1)
|
||||
expect(giftCardRepo.softRemove).toHaveBeenCalledWith({
|
||||
region_id: IdMap.getId("region-id"),
|
||||
order_id: IdMap.getId("order-id"),
|
||||
})
|
||||
})
|
||||
|
||||
it("returns if no gift-card found", async () => {
|
||||
await giftCardService.delete(IdMap.getId("other"))
|
||||
|
||||
expect(giftCardRepo.softRemove).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,30 +1,31 @@
|
||||
import NotificationService from "../notification"
|
||||
import { IdMap, MockManager, MockRepository } from "medusa-test-utils"
|
||||
import { MockManager, MockRepository } from "medusa-test-utils"
|
||||
|
||||
describe("NotificationService", () => {
|
||||
describe("send", () => {
|
||||
const notificationRepository = MockRepository({ create: c => c })
|
||||
const notificationRepository = MockRepository({ create: c => c })
|
||||
|
||||
const container = {
|
||||
manager: MockManager,
|
||||
notificationRepository,
|
||||
noti_test: {
|
||||
sendNotification: jest.fn(() =>
|
||||
Promise.resolve({
|
||||
to: "test@mail.com",
|
||||
data: { id: "something" },
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
const container = {
|
||||
manager: MockManager,
|
||||
notificationRepository,
|
||||
noti_test: {
|
||||
sendNotification: jest.fn(() =>
|
||||
Promise.resolve({
|
||||
to: "test@mail.com",
|
||||
data: { id: "something" },
|
||||
})
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
const notificationService = new NotificationService(container)
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
describe("send", () =>{
|
||||
|
||||
it("successfully calls provider and saves noti", async () => {
|
||||
const notificationService = new NotificationService(container)
|
||||
|
||||
await notificationService.send("event.test", { id: "test" }, "test")
|
||||
|
||||
expect(container.noti_test.sendNotification).toHaveBeenCalledTimes(1)
|
||||
@@ -51,4 +52,30 @@ describe("NotificationService", () => {
|
||||
expect(notificationRepository.save).toHaveBeenCalledWith(constructed)
|
||||
})
|
||||
})
|
||||
|
||||
describe("handleEvent", () => {
|
||||
|
||||
it("cancels notification if no_notification is set", async () => {
|
||||
const notificationService = new NotificationService(container)
|
||||
const event = "event.test"
|
||||
notificationService.subscribe(event, "test")
|
||||
|
||||
await notificationService.handleEvent(event, {id: "id",
|
||||
return_id: "id",
|
||||
no_notification: true})
|
||||
|
||||
expect(container.noti_test.sendNotification).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("if no_notification is not set notification is send", async () => {
|
||||
const notificationService = new NotificationService(container)
|
||||
const event = "event.test"
|
||||
notificationService.subscribe(event, "test")
|
||||
|
||||
await notificationService.handleEvent(event, {id: "id", return_id: "id"})
|
||||
|
||||
expect(container.noti_test.sendNotification).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
@@ -711,6 +711,7 @@ describe("OrderService", () => {
|
||||
const order = {
|
||||
fulfillments: [],
|
||||
shipping_methods: [{ id: "ship" }],
|
||||
no_notification: true,
|
||||
items: [
|
||||
{
|
||||
id: "item_1",
|
||||
@@ -859,6 +860,31 @@ describe("OrderService", () => {
|
||||
fulfillment_status: "partially_fulfilled",
|
||||
})
|
||||
})
|
||||
|
||||
it.each([
|
||||
[true, true],
|
||||
[false, false],
|
||||
[undefined, true],
|
||||
])(
|
||||
"emits correct no_notification option with '%s'",
|
||||
async (input, expected) => {
|
||||
await orderService.createFulfillment(
|
||||
"test-order",
|
||||
[
|
||||
{
|
||||
item_id: "item_1",
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
{ no_notification: input }
|
||||
)
|
||||
|
||||
expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), {
|
||||
id: expect.any(String),
|
||||
no_notification: expected,
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe("registerReturnReceived", () => {
|
||||
@@ -975,6 +1001,7 @@ describe("OrderService", () => {
|
||||
fulfilled_quantity: 0,
|
||||
},
|
||||
],
|
||||
no_notification: true,
|
||||
}
|
||||
|
||||
const orderRepo = MockRepository({
|
||||
@@ -996,7 +1023,11 @@ describe("OrderService", () => {
|
||||
}
|
||||
|
||||
const fulfillmentService = {
|
||||
retrieve: () => Promise.resolve({ order_id: IdMap.getId("test") }),
|
||||
retrieve: () =>
|
||||
Promise.resolve({
|
||||
order_id: IdMap.getId("test"),
|
||||
no_notification: true,
|
||||
}),
|
||||
createShipment: jest
|
||||
.fn()
|
||||
.mockImplementation((shipmentId, tracking, meta) => {
|
||||
@@ -1036,10 +1067,12 @@ describe("OrderService", () => {
|
||||
)
|
||||
|
||||
expect(fulfillmentService.createShipment).toHaveBeenCalledTimes(1)
|
||||
expect(fulfillmentService.createShipment).toHaveBeenCalledWith(
|
||||
expect(
|
||||
fulfillmentService.createShipment
|
||||
).toHaveBeenCalledWith(
|
||||
IdMap.getId("fulfillment"),
|
||||
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
|
||||
{}
|
||||
{ metadata: undefined, no_notification: true }
|
||||
)
|
||||
|
||||
expect(orderRepo.save).toHaveBeenCalledTimes(1)
|
||||
@@ -1048,6 +1081,27 @@ describe("OrderService", () => {
|
||||
fulfillment_status: "shipped",
|
||||
})
|
||||
})
|
||||
|
||||
it.each([
|
||||
[true, true],
|
||||
[false, false],
|
||||
[undefined, true],
|
||||
])(
|
||||
"emits correct no_notification option with '%s'",
|
||||
async (input, expected) => {
|
||||
await orderService.createShipment(
|
||||
IdMap.getId("test"),
|
||||
IdMap.getId("fulfillment"),
|
||||
[{ tracking_number: "1234" }, { tracking_number: "2345" }],
|
||||
{ no_notification: input }
|
||||
)
|
||||
|
||||
expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), {
|
||||
id: expect.any(String),
|
||||
no_notification: expected,
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe("createRefund", () => {
|
||||
@@ -1081,6 +1135,7 @@ describe("OrderService", () => {
|
||||
paid_total: 100,
|
||||
refundable_amount: 100,
|
||||
refunded_total: 0,
|
||||
no_notification: true,
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -1129,5 +1184,27 @@ describe("OrderService", () => {
|
||||
)
|
||||
).rejects.toThrow("Cannot refund more than the original order amount")
|
||||
})
|
||||
|
||||
it.each([
|
||||
[false, false],
|
||||
[undefined, true],
|
||||
])(
|
||||
"emits correct no_notification option with '%s'",
|
||||
async (input, expected) => {
|
||||
await orderService.createRefund(
|
||||
IdMap.getId("order_123"),
|
||||
100,
|
||||
"discount",
|
||||
"note",
|
||||
{ no_notification: input }
|
||||
)
|
||||
|
||||
expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), {
|
||||
id: expect.any(String),
|
||||
no_notification: expected,
|
||||
refund_id: expect.any(String),
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -135,8 +135,8 @@ describe("ProductCollectionService", () => {
|
||||
it("successfully removes a product collection", async () => {
|
||||
await productCollectionService.delete(IdMap.getId("bathrobe"))
|
||||
|
||||
expect(productCollectionRepository.remove).toHaveBeenCalledTimes(1)
|
||||
expect(productCollectionRepository.remove).toHaveBeenCalledWith({
|
||||
expect(productCollectionRepository.softRemove).toHaveBeenCalledTimes(1)
|
||||
expect(productCollectionRepository.softRemove).toHaveBeenCalledWith({
|
||||
id: IdMap.getId("bathrobe"),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -57,6 +57,7 @@ const testOrder = generateOrder(
|
||||
currency_code: "dkk",
|
||||
region_id: IdMap.getId("region"),
|
||||
tax_rate: 0,
|
||||
no_notification: true,
|
||||
shipping_address: {
|
||||
first_name: "test",
|
||||
last_name: "testson",
|
||||
@@ -329,6 +330,7 @@ describe("SwapService", () => {
|
||||
order_id: IdMap.getId("test"),
|
||||
fulfillment_status: "not_fulfilled",
|
||||
payment_status: "not_paid",
|
||||
no_notification: true,
|
||||
additional_items: [
|
||||
{
|
||||
unit_price: 100,
|
||||
@@ -340,6 +342,31 @@ describe("SwapService", () => {
|
||||
|
||||
expect(returnService.create).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it.each([
|
||||
[true, true],
|
||||
[false, false],
|
||||
[undefined, true],
|
||||
])(
|
||||
"passes correct no_notification to eventBus with %s",
|
||||
async (input, expected) => {
|
||||
await swapService.create(
|
||||
testOrder,
|
||||
[{ item_id: IdMap.getId("line"), quantity: 1 }],
|
||||
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
|
||||
{
|
||||
id: IdMap.getId("return-shipping"),
|
||||
price: 20,
|
||||
},
|
||||
{ no_notification: input }
|
||||
)
|
||||
|
||||
expect(eventBusService.emit).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
{ id: undefined, no_notification: expected }
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class ClaimService extends BaseService {
|
||||
const claimRepo = manager.getCustomRepository(this.claimRepository_)
|
||||
const claim = await this.retrieve(id, { relations: ["shipping_methods"] })
|
||||
|
||||
const { claim_items, shipping_methods, metadata } = data
|
||||
const { claim_items, shipping_methods, metadata, no_notification } = data
|
||||
|
||||
if (metadata) {
|
||||
claim.metadata = this.setMetadata_(claim, metadata)
|
||||
@@ -135,6 +135,11 @@ class ClaimService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
if (no_notification !== undefined) {
|
||||
claim.no_notification = no_notification
|
||||
await claimRepo.save(claim)
|
||||
}
|
||||
|
||||
if (claim_items) {
|
||||
for (const i of claim_items) {
|
||||
if (i.id) {
|
||||
@@ -149,6 +154,7 @@ class ClaimService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(ClaimService.Events.UPDATED, {
|
||||
id: claim.id,
|
||||
no_notification: claim.no_notification,
|
||||
})
|
||||
|
||||
return claim
|
||||
@@ -174,6 +180,7 @@ class ClaimService extends BaseService {
|
||||
refund_amount,
|
||||
shipping_address,
|
||||
shipping_address_id,
|
||||
no_notification,
|
||||
...rest
|
||||
} = data
|
||||
|
||||
@@ -233,6 +240,9 @@ class ClaimService extends BaseService {
|
||||
)
|
||||
)
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : order.no_notification
|
||||
|
||||
const created = claimRepo.create({
|
||||
shipping_address_id: addressId,
|
||||
payment_status: type === "refund" ? "not_refunded" : "na",
|
||||
@@ -241,6 +251,7 @@ class ClaimService extends BaseService {
|
||||
type,
|
||||
additional_items: newItems,
|
||||
order_id: order.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
const result = await claimRepo.save(created)
|
||||
@@ -281,6 +292,7 @@ class ClaimService extends BaseService {
|
||||
metadata: ci.metadata,
|
||||
})),
|
||||
shipping_method: return_shipping,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -288,13 +300,22 @@ class ClaimService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(ClaimService.Events.CREATED, {
|
||||
id: result.id,
|
||||
no_notification: result.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
createFulfillment(id, metadata = {}) {
|
||||
createFulfillment(
|
||||
id,
|
||||
config = {
|
||||
metadata: {},
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const claim = await this.retrieve(id, {
|
||||
relations: [
|
||||
@@ -331,6 +352,9 @@ class ClaimService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : claim.no_notification
|
||||
|
||||
const fulfillments = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createFulfillment(
|
||||
@@ -347,6 +371,7 @@ class ClaimService extends BaseService {
|
||||
items: claim.additional_items,
|
||||
shipping_methods: claim.shipping_methods,
|
||||
is_claim: true,
|
||||
no_notification: evaluatedNoNotification,
|
||||
},
|
||||
claim.additional_items.map(i => ({
|
||||
item_id: i.id,
|
||||
@@ -395,6 +420,7 @@ class ClaimService extends BaseService {
|
||||
.emit(ClaimService.Events.FULFILLMENT_CREATED, {
|
||||
id: id,
|
||||
fulfillment_id: fulfillment.id,
|
||||
no_notification: claim.no_notification,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -430,21 +456,38 @@ class ClaimService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(ClaimService.Events.REFUND_PROCESSED, {
|
||||
id,
|
||||
no_notification: result.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
async createShipment(id, fulfillmentId, trackingLinks, metadata = []) {
|
||||
async createShipment(
|
||||
id,
|
||||
fulfillmentId,
|
||||
trackingLinks,
|
||||
config = {
|
||||
metadata: {},
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const claim = await this.retrieve(id, {
|
||||
relations: ["additional_items"],
|
||||
})
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : claim.no_notification
|
||||
|
||||
const shipment = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createShipment(fulfillmentId, trackingLinks, metadata)
|
||||
.createShipment(fulfillmentId, trackingLinks, {
|
||||
metadata,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
claim.fulfillment_status = "shipped"
|
||||
|
||||
@@ -474,6 +517,7 @@ class ClaimService extends BaseService {
|
||||
.emit(ClaimService.Events.SHIPMENT_CREATED, {
|
||||
id,
|
||||
fulfillment_id: shipment.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -524,6 +568,7 @@ class ClaimService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(ClaimService.Events.CANCELED, {
|
||||
id: result.id,
|
||||
no_notification: result.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@@ -318,6 +318,13 @@ class CustomerService extends BaseService {
|
||||
|
||||
const existing = await this.retrieveByEmail(email).catch(err => undefined)
|
||||
|
||||
if (existing && existing.has_account) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.DUPLICATE_ERROR,
|
||||
"A customer with the given email already has an account. Log in instead"
|
||||
)
|
||||
}
|
||||
|
||||
if (existing && password && !existing.has_account) {
|
||||
const hashedPassword = await this.hashPassword_(password)
|
||||
customer.password_hash = hashedPassword
|
||||
@@ -360,6 +367,7 @@ class CustomerService extends BaseService {
|
||||
const customerRepository = manager.getCustomRepository(
|
||||
this.customerRepository_
|
||||
)
|
||||
const addrRepo = manager.getCustomRepository(this.addressRepository_)
|
||||
|
||||
const customer = await this.retrieve(customerId)
|
||||
|
||||
@@ -368,6 +376,7 @@ class CustomerService extends BaseService {
|
||||
password,
|
||||
password_hash,
|
||||
billing_address,
|
||||
billing_address_id,
|
||||
metadata,
|
||||
...rest
|
||||
} = update
|
||||
@@ -380,8 +389,9 @@ class CustomerService extends BaseService {
|
||||
customer.email = this.validateEmail_(email)
|
||||
}
|
||||
|
||||
if (billing_address) {
|
||||
customer.billing_address = this.validateBillingAddress_(billing_address)
|
||||
if ("billing_address_id" in update || "billing_address" in update) {
|
||||
const address = update.billing_address_id || update.billing_address
|
||||
await this.updateBillingAddress_(customer, address, addrRepo)
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(rest)) {
|
||||
@@ -393,6 +403,7 @@ class CustomerService extends BaseService {
|
||||
}
|
||||
|
||||
const updated = await customerRepository.save(customer)
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(CustomerService.Events.UPDATED, updated)
|
||||
@@ -400,6 +411,41 @@ class CustomerService extends BaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the customers's billing address.
|
||||
* @param {Customer} customer - the Customer to update
|
||||
* @param {object} address - the value to set the billing address to
|
||||
* @return {Promise} the result of the update operation
|
||||
*/
|
||||
async updateBillingAddress_(customer, addressOrId, addrRepo) {
|
||||
if (typeof addressOrId === `string`) {
|
||||
addressOrId = await addrRepo.findOne({
|
||||
where: { id: addressOrId },
|
||||
})
|
||||
}
|
||||
|
||||
addressOrId.country_code = addressOrId.country_code.toLowerCase()
|
||||
|
||||
if (addressOrId.id) {
|
||||
customer.billing_address_id = addressOrId.id
|
||||
customer.billing_address = addressOrId
|
||||
} else {
|
||||
if (customer.billing_address_id) {
|
||||
const addr = await addrRepo.findOne({
|
||||
where: { id: customer.billing_address_id },
|
||||
})
|
||||
|
||||
await addrRepo.save({ ...addr, ...addressOrId })
|
||||
} else {
|
||||
const created = addrRepo.create({
|
||||
...addressOrId,
|
||||
})
|
||||
const saved = await addrRepo.save(created)
|
||||
customer.billing_address = saved
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updateAddress(customerId, addressId, address) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const addressRepo = manager.getCustomRepository(this.addressRepository_)
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Brackets } from "typeorm"
|
||||
class DraftOrderService extends BaseService {
|
||||
static Events = {
|
||||
CREATED: "draft_order.created",
|
||||
UPDATED: "draft_order.updated",
|
||||
}
|
||||
|
||||
constructor({
|
||||
@@ -248,7 +249,13 @@ class DraftOrderService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
const { items, shipping_methods, discounts, ...rest } = data
|
||||
const {
|
||||
items,
|
||||
shipping_methods,
|
||||
discounts,
|
||||
no_notification_order,
|
||||
...rest
|
||||
} = data
|
||||
|
||||
if (discounts) {
|
||||
for (const { code } of discounts) {
|
||||
@@ -263,7 +270,10 @@ class DraftOrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.create({ type: "draft_order", ...rest })
|
||||
|
||||
const draftOrder = draftOrderRepo.create({ cart_id: createdCart.id })
|
||||
const draftOrder = draftOrderRepo.create({
|
||||
cart_id: createdCart.id,
|
||||
no_notification_order,
|
||||
})
|
||||
const result = await draftOrderRepo.save(draftOrder)
|
||||
|
||||
await this.eventBus_
|
||||
@@ -335,6 +345,44 @@ class DraftOrderService extends BaseService {
|
||||
await draftOrderRepo.save(draftOrder)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a draft order with the given data
|
||||
* @param {String} doId - id of the draft order
|
||||
* @param {DraftOrder} data - values to update the order with
|
||||
* @returns {Promise<DraftOrder>} the updated draft order
|
||||
*/
|
||||
async update(doId, data) {
|
||||
return this.atomicPhase_(async manager => {
|
||||
const doRepo = manager.getCustomRepository(this.draftOrderRepository_)
|
||||
const draftOrder = await this.retrieve(doId)
|
||||
let touched = false
|
||||
|
||||
if (draftOrder.status === "completed") {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Can't update a draft order which is complete"
|
||||
)
|
||||
}
|
||||
|
||||
if (data.no_notification_order !== undefined) {
|
||||
touched = true
|
||||
draftOrder.no_notification_order = data.no_notification_order
|
||||
}
|
||||
|
||||
if (touched) {
|
||||
doRepo.save(draftOrder)
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(DraftOrderService.Events.UPDATED, {
|
||||
id: draftOrder.id,
|
||||
})
|
||||
}
|
||||
|
||||
return draftOrder
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default DraftOrderService
|
||||
@@ -241,10 +241,19 @@ class FulfillmentService extends BaseService {
|
||||
* tracking numbers and potentially more metadata.
|
||||
* @param {Order} fulfillmentId - the fulfillment to ship
|
||||
* @param {TrackingLink[]} trackingNumbers - tracking numbers for the shipment
|
||||
* @param {object} metadata - potential metadata to add
|
||||
* @param {object} config - potential configuration settings, such as no_notification and metadata
|
||||
* @return {Fulfillment} the shipped fulfillment
|
||||
*/
|
||||
async createShipment(fulfillmentId, trackingLinks, metadata) {
|
||||
async createShipment(
|
||||
fulfillmentId,
|
||||
trackingLinks,
|
||||
config = {
|
||||
metadata: {},
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const fulfillmentRepository = manager.getCustomRepository(
|
||||
this.fulfillmentRepository_
|
||||
@@ -264,6 +273,10 @@ class FulfillmentService extends BaseService {
|
||||
trackingLinkRepo.create(tl)
|
||||
)
|
||||
|
||||
if (no_notification) {
|
||||
fulfillment.no_notification = no_notification
|
||||
}
|
||||
|
||||
fulfillment.metadata = {
|
||||
...fulfillment.metadata,
|
||||
...metadata,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import _ from "lodash"
|
||||
import randomize from "randomatic"
|
||||
import { BaseService } from "medusa-interfaces"
|
||||
import { Validator, MedusaError } from "medusa-core-utils"
|
||||
import { Brackets } from "typeorm"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
|
||||
/**
|
||||
* Provides layer to manipulate gift cards.
|
||||
@@ -72,6 +73,7 @@ class GiftCardService extends BaseService {
|
||||
|
||||
/**
|
||||
* @param {Object} selector - the query object for find
|
||||
* @param {Object} config - the configuration used to find the objects. contains relations, skip, and take.
|
||||
* @return {Promise} the result of the find operation
|
||||
*/
|
||||
async list(selector = {}, config = { relations: [], skip: 0, take: 10 }) {
|
||||
@@ -79,8 +81,41 @@ class GiftCardService extends BaseService {
|
||||
this.giftCardRepository_
|
||||
)
|
||||
|
||||
let q
|
||||
if ("q" in selector) {
|
||||
q = selector.q
|
||||
delete selector.q
|
||||
}
|
||||
|
||||
const query = this.buildQuery_(selector, config)
|
||||
return giftCardRepo.find(query)
|
||||
|
||||
const rels = query.relations
|
||||
delete query.relations
|
||||
|
||||
if (q) {
|
||||
const where = query.where
|
||||
delete where.id
|
||||
|
||||
const raw = await giftCardRepo
|
||||
.createQueryBuilder("gift_card")
|
||||
.leftJoinAndSelect("gift_card.order", "order")
|
||||
.select(["gift_card.id"])
|
||||
.where(where)
|
||||
.andWhere(
|
||||
new Brackets(qb => {
|
||||
return qb
|
||||
.where(`gift_card.code ILIKE :q`, { q: `%${q}%` })
|
||||
.orWhere(`display_id::varchar(255) ILIKE :dId`, { dId: `${q}` })
|
||||
})
|
||||
)
|
||||
.getMany()
|
||||
|
||||
return giftCardRepo.findWithRelations(
|
||||
rels,
|
||||
raw.map(i => i.id)
|
||||
)
|
||||
}
|
||||
return giftCardRepo.findWithRelations(rels, query)
|
||||
}
|
||||
|
||||
async createTransaction(data) {
|
||||
@@ -156,7 +191,10 @@ class GiftCardService extends BaseService {
|
||||
query.relations = config.relations
|
||||
}
|
||||
|
||||
const giftCard = await giftCardRepo.findOne(query)
|
||||
const rels = query.relations
|
||||
delete query.relations
|
||||
|
||||
const giftCard = await giftCardRepo.findOneWithRelations(rels, query)
|
||||
|
||||
if (!giftCard) {
|
||||
throw new MedusaError(
|
||||
@@ -185,7 +223,10 @@ class GiftCardService extends BaseService {
|
||||
query.relations = config.relations
|
||||
}
|
||||
|
||||
const giftCard = await giftCardRepo.findOne(query)
|
||||
const rels = query.relations
|
||||
delete query.relations
|
||||
|
||||
const giftCard = await giftCardRepo.findOneWithRelations(rels, query)
|
||||
|
||||
if (!giftCard) {
|
||||
throw new MedusaError(
|
||||
@@ -209,7 +250,7 @@ class GiftCardService extends BaseService {
|
||||
|
||||
const giftCard = await this.retrieve(giftCardId)
|
||||
|
||||
const { region_id, metadata, ...rest } = update
|
||||
const { region_id, metadata, balance, ...rest } = update
|
||||
|
||||
if (region_id && region_id !== giftCard.region_id) {
|
||||
const region = await this.regionService_.retrieve(region_id)
|
||||
@@ -220,6 +261,16 @@ class GiftCardService extends BaseService {
|
||||
giftCard.metadata = await this.setMetadata_(giftCard.id, metadata)
|
||||
}
|
||||
|
||||
if (balance) {
|
||||
if (balance < 0 || giftCard.value < balance) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_ARGUMENT,
|
||||
"new balance is invalid"
|
||||
)
|
||||
}
|
||||
giftCard.balance = balance
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(rest)) {
|
||||
giftCard[key] = value
|
||||
}
|
||||
|
||||
@@ -164,6 +164,9 @@ class NotificationService extends BaseService {
|
||||
if (!subs) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
if (data["no_notification"] === true) {
|
||||
return
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
subs.map(async providerId => {
|
||||
|
||||
@@ -333,7 +333,6 @@ class OrderService extends BaseService {
|
||||
const rels = query.relations
|
||||
delete query.relations
|
||||
const raw = await orderRepo.findOneWithRelations(rels, query)
|
||||
|
||||
if (!raw) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
@@ -408,6 +407,7 @@ class OrderService extends BaseService {
|
||||
OrderService.Events.COMPLETED,
|
||||
{
|
||||
id: orderId,
|
||||
no_notification: order.no_notification,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -507,6 +507,7 @@ class OrderService extends BaseService {
|
||||
.retrieveByCartId(cart.id)
|
||||
|
||||
toCreate.draft_order_id = draft.id
|
||||
toCreate.no_notification = draft.no_notification_order
|
||||
}
|
||||
|
||||
const o = await orderRepo.create(toCreate)
|
||||
@@ -553,6 +554,7 @@ class OrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(OrderService.Events.PLACED, {
|
||||
id: result.id,
|
||||
no_notification: result.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -571,7 +573,17 @@ class OrderService extends BaseService {
|
||||
* the fulfillment
|
||||
* @return {order} the resulting order following the update.
|
||||
*/
|
||||
async createShipment(orderId, fulfillmentId, trackingLinks, metadata = {}) {
|
||||
async createShipment(
|
||||
orderId,
|
||||
fulfillmentId,
|
||||
trackingLinks,
|
||||
config = {
|
||||
metadata: {},
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const order = await this.retrieve(orderId, { relations: ["items"] })
|
||||
const shipment = await this.fulfillmentService_.retrieve(fulfillmentId)
|
||||
@@ -583,9 +595,17 @@ class OrderService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined
|
||||
? no_notification
|
||||
: shipment.no_notification
|
||||
|
||||
const shipmentRes = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createShipment(fulfillmentId, trackingLinks, metadata)
|
||||
.createShipment(fulfillmentId, trackingLinks, {
|
||||
metadata,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
order.fulfillment_status = "shipped"
|
||||
for (const item of order.items) {
|
||||
@@ -614,6 +634,7 @@ class OrderService extends BaseService {
|
||||
.emit(OrderService.Events.SHIPMENT_CREATED, {
|
||||
id: orderId,
|
||||
fulfillment_id: shipmentRes.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -634,6 +655,7 @@ class OrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(OrderService.Events.PLACED, {
|
||||
id: result.id,
|
||||
no_notification: order.no_notification,
|
||||
})
|
||||
return result
|
||||
})
|
||||
@@ -801,6 +823,10 @@ class OrderService extends BaseService {
|
||||
await this.updateBillingAddress_(order, update.billing_address)
|
||||
}
|
||||
|
||||
if ("no_notification" in update) {
|
||||
order.no_notification = update.no_notification
|
||||
}
|
||||
|
||||
if ("items" in update) {
|
||||
for (const item of update.items) {
|
||||
await this.lineItemService_.withTransaction(manager).create({
|
||||
@@ -821,6 +847,7 @@ class OrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(OrderService.Events.UPDATED, {
|
||||
id: orderId,
|
||||
no_notification: order.no_notification,
|
||||
})
|
||||
return result
|
||||
})
|
||||
@@ -871,6 +898,7 @@ class OrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(OrderService.Events.CANCELED, {
|
||||
id: order.id,
|
||||
no_notification: order.no_notification,
|
||||
})
|
||||
return result
|
||||
})
|
||||
@@ -899,6 +927,7 @@ class OrderService extends BaseService {
|
||||
id: orderId,
|
||||
payment_id: p.id,
|
||||
error: err,
|
||||
no_notification: order.no_notification,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -924,6 +953,7 @@ class OrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(OrderService.Events.PAYMENT_CAPTURED, {
|
||||
id: result.id,
|
||||
no_notification: order.no_notification,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -970,8 +1000,21 @@ class OrderService extends BaseService {
|
||||
* @param {string} orderId - id of order to cancel.
|
||||
* @return {Promise} result of the update operation.
|
||||
*/
|
||||
async createFulfillment(orderId, itemsToFulfill, metadata = {}) {
|
||||
async createFulfillment(
|
||||
orderId,
|
||||
itemsToFulfill,
|
||||
config = {
|
||||
no_notification: undefined,
|
||||
metadata: {},
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
// NOTE: we are telling the service to calculate all totals for us which
|
||||
// will add to what is fetched from the database. We want this to happen
|
||||
// so that we get all order details. These will thereafter be forwarded
|
||||
// to the fulfillment provider.
|
||||
const order = await this.retrieve(orderId, {
|
||||
select: [
|
||||
"subtotal",
|
||||
@@ -1007,6 +1050,7 @@ class OrderService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.createFulfillment(order, itemsToFulfill, {
|
||||
metadata,
|
||||
no_notification: no_notification,
|
||||
order_id: orderId,
|
||||
})
|
||||
let successfullyFulfilled = []
|
||||
@@ -1046,12 +1090,16 @@ class OrderService extends BaseService {
|
||||
order.fulfillments = [...order.fulfillments, ...fulfillments]
|
||||
const result = await orderRepo.save(order)
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : order.no_notification
|
||||
|
||||
for (const fulfillment of fulfillments) {
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(OrderService.Events.FULFILLMENT_CREATED, {
|
||||
id: orderId,
|
||||
fulfillment_id: fulfillment.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1107,7 +1155,17 @@ class OrderService extends BaseService {
|
||||
/**
|
||||
* Refunds a given amount back to the customer.
|
||||
*/
|
||||
async createRefund(orderId, refundAmount, reason, note) {
|
||||
async createRefund(
|
||||
orderId,
|
||||
refundAmount,
|
||||
reason,
|
||||
note,
|
||||
config = {
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const order = await this.retrieve(orderId, {
|
||||
select: ["refundable_amount", "total", "refunded_total"],
|
||||
@@ -1126,9 +1184,14 @@ class OrderService extends BaseService {
|
||||
.refundPayment(order.payments, refundAmount, reason, note)
|
||||
|
||||
const result = await this.retrieve(orderId)
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : order.no_notification
|
||||
|
||||
this.eventBus_.emit(OrderService.Events.REFUND_CREATED, {
|
||||
id: result.id,
|
||||
refund_id: refund.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
return result
|
||||
})
|
||||
@@ -1232,6 +1295,7 @@ class OrderService extends BaseService {
|
||||
.emit(OrderService.Events.RETURN_ACTION_REQUIRED, {
|
||||
id: result.id,
|
||||
return_id: receivedReturn.id,
|
||||
no_notification: receivedReturn.no_notification,
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -1263,6 +1327,7 @@ class OrderService extends BaseService {
|
||||
.emit(OrderService.Events.ITEMS_RETURNED, {
|
||||
id: order.id,
|
||||
return_id: receivedReturn.id,
|
||||
no_notification: receivedReturn.no_notification,
|
||||
})
|
||||
return result
|
||||
})
|
||||
|
||||
@@ -129,7 +129,7 @@ class ProductCollectionService extends BaseService {
|
||||
|
||||
if (!collection) return Promise.resolve()
|
||||
|
||||
await productCollectionRepo.remove(collection)
|
||||
await productCollectionRepo.softRemove(collection)
|
||||
|
||||
return Promise.resolve()
|
||||
})
|
||||
|
||||
@@ -330,6 +330,7 @@ class ReturnService extends BaseService {
|
||||
reason_id: i.reason_id,
|
||||
note: i.note,
|
||||
metadata: i.metadata,
|
||||
no_notification: data.no_notification,
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ class SwapService extends BaseService {
|
||||
PAYMENT_CAPTURE_FAILED: "swap.payment_capture_failed",
|
||||
PROCESS_REFUND_FAILED: "swap.process_refund_failed",
|
||||
REFUND_PROCESSED: "swap.refund_processed",
|
||||
FULFILLMENT_CREATED: "swap.fulfillment_created",
|
||||
}
|
||||
|
||||
constructor({
|
||||
@@ -210,6 +211,9 @@ class SwapService extends BaseService {
|
||||
* the customer.
|
||||
* @param {ReturnShipping?} returnShipping - an optional shipping method for
|
||||
* returning the returnItems.
|
||||
* @param {Object} custom - contains relevant custom information. This object may
|
||||
* include no_notification which will disable sending notification when creating
|
||||
* swap. If set, it overrules the attribute inherited from the order.
|
||||
* @returns {Promise<Swap>} the newly created swap.
|
||||
*/
|
||||
async create(
|
||||
@@ -217,8 +221,11 @@ class SwapService extends BaseService {
|
||||
returnItems,
|
||||
additionalItems,
|
||||
returnShipping,
|
||||
custom = {}
|
||||
custom = {
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { no_notification, ...rest } = custom
|
||||
return this.atomicPhase_(async manager => {
|
||||
if (
|
||||
order.fulfillment_status === "not_fulfilled" ||
|
||||
@@ -240,13 +247,17 @@ class SwapService extends BaseService {
|
||||
})
|
||||
)
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : order.no_notification
|
||||
|
||||
const swapRepo = manager.getCustomRepository(this.swapRepository_)
|
||||
const created = swapRepo.create({
|
||||
...custom,
|
||||
...rest,
|
||||
fulfillment_status: "not_fulfilled",
|
||||
payment_status: "not_paid",
|
||||
order_id: order.id,
|
||||
additional_items: newItems,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
const result = await swapRepo.save(created)
|
||||
@@ -256,12 +267,14 @@ class SwapService extends BaseService {
|
||||
order_id: order.id,
|
||||
items: returnItems,
|
||||
shipping_method: returnShipping,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.CREATED, {
|
||||
id: result.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -298,9 +311,14 @@ class SwapService extends BaseService {
|
||||
} catch (err) {
|
||||
swap.payment_status = "requires_action"
|
||||
const result = await swapRepo.save(swap)
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.PROCESS_REFUND_FAILED, result)
|
||||
.emit(SwapService.Events.PROCESS_REFUND_FAILED, {
|
||||
id: result.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -310,7 +328,11 @@ class SwapService extends BaseService {
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.REFUND_PROCESSED, result)
|
||||
.emit(SwapService.Events.REFUND_PROCESSED, {
|
||||
id: result.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
} else if (swap.difference_due === 0) {
|
||||
if (swap.payment_status === "difference_refunded") {
|
||||
@@ -320,9 +342,14 @@ class SwapService extends BaseService {
|
||||
swap.payment_status = "difference_refunded"
|
||||
|
||||
const result = await swapRepo.save(swap)
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.REFUND_PROCESSED, result)
|
||||
.emit(SwapService.Events.REFUND_PROCESSED, {
|
||||
id: result.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -337,18 +364,28 @@ class SwapService extends BaseService {
|
||||
} catch (err) {
|
||||
swap.payment_status = "requires_action"
|
||||
const result = await swapRepo.save(swap)
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.PAYMENT_CAPTURE_FAILED, result)
|
||||
.emit(SwapService.Events.PAYMENT_CAPTURE_FAILED, {
|
||||
id: swap.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
swap.payment_status = "captured"
|
||||
|
||||
const result = await swapRepo.save(swap)
|
||||
|
||||
await this.eventBus_
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.PAYMENT_CAPTURED, result)
|
||||
.emit(SwapService.Events.PAYMENT_CAPTURED, {
|
||||
id: result.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
@@ -361,6 +398,10 @@ class SwapService extends BaseService {
|
||||
swap.metadata = this.setMetadata_(swap, update.metadata)
|
||||
}
|
||||
|
||||
if ("no_notification" in update) {
|
||||
swap.no_notification = update.no_notification
|
||||
}
|
||||
|
||||
if ("shipping_address" in update) {
|
||||
await this.updateShippingAddress_(swap, update.shipping_address)
|
||||
}
|
||||
@@ -562,6 +603,7 @@ class SwapService extends BaseService {
|
||||
.withTransaction(manager)
|
||||
.emit(SwapService.Events.PAYMENT_COMPLETED, {
|
||||
id: swap.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -609,10 +651,18 @@ class SwapService extends BaseService {
|
||||
* Fulfills the addtional items associated with the swap. Will call the
|
||||
* fulfillment providers associated with the shipping methods.
|
||||
* @param {string} swapId - the id of the swap to fulfill,
|
||||
* @param {object} metadata - optional metadata to attach to the fulfillment.
|
||||
* @param {object} config - optional configurations, includes optional metadata to attach to the shipment, and a no_notification flag.
|
||||
* @returns {Promise<Swap>} the updated swap with new status and fulfillments.
|
||||
*/
|
||||
async createFulfillment(swapId, metadata = {}) {
|
||||
async createFulfillment(
|
||||
swapId,
|
||||
config = {
|
||||
metadata: {},
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const swap = await this.retrieve(swapId, {
|
||||
relations: [
|
||||
@@ -642,6 +692,9 @@ class SwapService extends BaseService {
|
||||
)
|
||||
}
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : swap.no_notification
|
||||
|
||||
swap.fulfillments = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createFulfillment(
|
||||
@@ -658,6 +711,7 @@ class SwapService extends BaseService {
|
||||
items: swap.additional_items,
|
||||
shipping_methods: swap.shipping_methods,
|
||||
is_swap: true,
|
||||
no_notification: evaluatedNoNotification,
|
||||
},
|
||||
swap.additional_items.map(i => ({
|
||||
item_id: i.id,
|
||||
@@ -700,6 +754,17 @@ class SwapService extends BaseService {
|
||||
|
||||
const swapRepo = manager.getCustomRepository(this.swapRepository_)
|
||||
const result = await swapRepo.save(swap)
|
||||
|
||||
await this.eventBus_.withTransaction(manager).emit(
|
||||
SwapService.Events.FULFILLMENT_CREATED,
|
||||
|
||||
{
|
||||
id: swapId,
|
||||
fulfillment_id: result.id,
|
||||
no_notification: evaluatedNoNotification,
|
||||
}
|
||||
)
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
@@ -711,19 +776,35 @@ class SwapService extends BaseService {
|
||||
* has been shipped
|
||||
* @param {TrackingLink[]} trackingLinks - the tracking numbers associated
|
||||
* with the shipment
|
||||
* @param {object} metadata - optional metadata to attach to the shipment.
|
||||
* @param {object} config - optional configurations, includes optional metadata to attach to the shipment, and a noNotification flag.
|
||||
* @returns {Promise<Swap>} the updated swap with new fulfillments and status.
|
||||
*/
|
||||
async createShipment(swapId, fulfillmentId, trackingLinks, metadata = {}) {
|
||||
async createShipment(
|
||||
swapId,
|
||||
fulfillmentId,
|
||||
trackingLinks,
|
||||
config = {
|
||||
metadata: {},
|
||||
no_notification: undefined,
|
||||
}
|
||||
) {
|
||||
const { metadata, no_notification } = config
|
||||
|
||||
return this.atomicPhase_(async manager => {
|
||||
const swap = await this.retrieve(swapId, {
|
||||
relations: ["additional_items"],
|
||||
})
|
||||
|
||||
const evaluatedNoNotification =
|
||||
no_notification !== undefined ? no_notification : swap.no_notification
|
||||
|
||||
// Update the fulfillment to register
|
||||
const shipment = await this.fulfillmentService_
|
||||
.withTransaction(manager)
|
||||
.createShipment(fulfillmentId, trackingLinks, metadata)
|
||||
.createShipment(fulfillmentId, trackingLinks, {
|
||||
metadata,
|
||||
no_notification: evaluatedNoNotification,
|
||||
})
|
||||
|
||||
swap.fulfillment_status = "shipped"
|
||||
|
||||
@@ -753,6 +834,7 @@ class SwapService extends BaseService {
|
||||
.emit(SwapService.Events.SHIPMENT_CREATED, {
|
||||
id: swapId,
|
||||
fulfillment_id: shipment.id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
return result
|
||||
})
|
||||
@@ -809,6 +891,7 @@ class SwapService extends BaseService {
|
||||
.emit(SwapService.Events.RECEIVED, {
|
||||
id: id,
|
||||
order_id: result.order_id,
|
||||
no_notification: swap.no_notification,
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
Reference in new issue
Block a user