Merge branch 'master' of github.com:medusajs/medusa

This commit is contained in:
Sebastian Rindom
2020-11-13 13:54:10 +01:00
6 changed files with 243 additions and 38 deletions

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.0.40](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.0.39...@medusajs/medusa@1.0.40) (2020-11-13)
### Features
* **medusa:** Adds shipped status to line items + Capture fails will give payment_status = requires_action ([6a3c545](https://github.com/medusajs/medusa/commit/6a3c5455371c33e47722c7ab433a48d1d9b5b511))
## [1.0.39](https://github.com/medusajs/medusa/compare/@medusajs/medusa@1.0.38...@medusajs/medusa@1.0.39) (2020-11-05)
**Note:** Version bump only for package @medusajs/medusa

View File

@@ -1,6 +1,6 @@
{
"name": "@medusajs/medusa",
"version": "1.0.39",
"version": "1.0.40",
"description": "E-commerce for JAMstack",
"main": "dist/app.js",
"repository": {

View File

@@ -368,6 +368,97 @@ export const orders = {
],
discounts: [],
},
shippedOrder: {
_id: IdMap.getId("shippedOrder"),
email: "oliver@test.dk",
billing_address: {
first_name: "Oli",
last_name: "Medusa",
address_1: "testaddress",
city: "LA",
country_code: "US",
postal_code: "90002",
},
shipping_address: {
first_name: "Oli",
last_name: "Medusa",
address_1: "testaddress",
city: "LA",
country_code: "US",
postal_code: "90002",
},
items: [
{
_id: IdMap.getId("existingLine"),
title: "merge line",
description: "This is a new line",
thumbnail: "test-img-yeah.com/thumb",
content: {
unit_price: 123,
variant: {
_id: IdMap.getId("can-cover"),
},
product: {
_id: IdMap.getId("validId"),
},
quantity: 1,
},
fulfilled_quantity: 10,
shipped_quantity: 0,
quantity: 10,
},
],
region_id: IdMap.getId("region-france"),
customer_id: IdMap.getId("test-customer"),
payment_method: {
provider_id: "default_provider",
},
shipping_methods: [
{
_id: IdMap.getId("expensiveShipping"),
name: "Expensive Shipping",
price: 100,
provider_id: "default_provider",
profile_id: IdMap.getId("default"),
data: {
extra: "hi",
},
},
],
fulfillments: [
{
_id: IdMap.getId("fulfillment"),
provider_id: "default_provider",
data: {},
items: [
{
_id: IdMap.getId("existingLine"),
content: {
product: {
_id: IdMap.getId("validId"),
},
quantity: 1,
unit_price: 123,
variant: {
_id: IdMap.getId("can-cover"),
},
},
description: "This is a new line",
fulfilled_quantity: 10,
quantity: 10,
thumbnail: "test-img-yeah.com/thumb",
title: "merge line",
},
],
},
],
fulfillment_status: "not_fulfilled",
payment_status: "awaiting",
status: "pending",
metadata: {
cart_id: IdMap.getId("test-cart"),
},
},
}
export const OrderModelMock = {
@@ -420,6 +511,9 @@ export const OrderModelMock = {
if (query.cart_id === IdMap.getId("test-cart")) {
return Promise.resolve(orders.testOrder)
}
if (query._id === IdMap.getId("shippedOrder")) {
return Promise.resolve(orders.shippedOrder)
}
return Promise.resolve(undefined)
}),
}

View File

@@ -4,8 +4,8 @@
import mongoose from "mongoose"
/**
* REMEMBER: When updating this line you must also update the LineItemService's
* validate method too. Otherwise we cannot copy lines directly.
* REMEMBER: When updating this line you must also update the LineItemService's
* validate method too. Otherwise we cannot copy lines directly.
*/
export default new mongoose.Schema(
{
@@ -45,6 +45,7 @@ export default new mongoose.Schema(
fulfilled: { type: Boolean, default: false },
fulfilled_quantity: { type: Number, default: 0 },
returned_quantity: { type: Number, default: 0 },
shipped_quantity: { type: Number, default: 0 },
metadata: { type: mongoose.Schema.Types.Mixed, default: {} },
},
{ minimize: false }

View File

@@ -509,7 +509,8 @@ describe("OrderService", () => {
},
quantity: 1,
},
fulfilled_quantity: 0,
fulfilled_quantity: 10,
fulfilled: true,
quantity: 10,
},
],
@@ -1121,7 +1122,7 @@ describe("OrderService", () => {
it("calls order model functions", async () => {
await orderService.createShipment(
IdMap.getId("test-order"),
IdMap.getId("shippedOrder"),
IdMap.getId("fulfillment"),
["1234", "2345"],
{}
@@ -1130,19 +1131,64 @@ describe("OrderService", () => {
expect(OrderModelMock.updateOne).toHaveBeenCalledTimes(1)
expect(OrderModelMock.updateOne).toHaveBeenCalledWith(
{
_id: IdMap.getId("test-order"),
_id: IdMap.getId("shippedOrder"),
"fulfillments._id": IdMap.getId("fulfillment"),
},
{
$set: {
"fulfillments.$": {
_id: IdMap.getId("fulfillment"),
provider_id: "default_provider",
tracking_numbers: ["1234", "2345"],
data: {},
shipped_at: expect.anything(),
metadata: {},
},
"fulfillments.$": [
{
_id: IdMap.getId("fulfillment"),
provider_id: "default_provider",
tracking_numbers: ["1234", "2345"],
data: {},
items: [
{
_id: IdMap.getId("existingLine"),
content: {
product: {
_id: IdMap.getId("validId"),
},
quantity: 1,
unit_price: 123,
variant: {
_id: IdMap.getId("can-cover"),
},
},
description: "This is a new line",
fulfilled_quantity: 10,
shipped_quantity: 10,
quantity: 10,
thumbnail: "test-img-yeah.com/thumb",
title: "merge line",
},
],
shipped_at: expect.anything(),
metadata: {},
},
],
items: [
{
_id: IdMap.getId("existingLine"),
content: {
product: {
_id: IdMap.getId("validId"),
},
quantity: 1,
unit_price: 123,
variant: {
_id: IdMap.getId("can-cover"),
},
},
description: "This is a new line",
fulfilled_quantity: 10,
shipped_quantity: 10,
quantity: 10,
thumbnail: "test-img-yeah.com/thumb",
title: "merge line",
},
],
fulfillment_status: "shipped",
},
}
)

View File

@@ -6,6 +6,7 @@ class OrderService extends BaseService {
static Events = {
GIFT_CARD_CREATED: "order.gift_card_created",
PAYMENT_CAPTURED: "order.payment_captured",
PAYMENT_CAPTURE_FAILED: "order.payment_capture_failed",
SHIPMENT_CREATED: "order.shipment_created",
FULFILLMENT_CREATED: "order.fulfillment_created",
RETURN_REQUESTED: "order.return_requested",
@@ -418,22 +419,39 @@ class OrderService extends BaseService {
async createShipment(orderId, fulfillmentId, trackingNumbers, metadata = {}) {
const order = await this.retrieve(orderId)
const shipment = order.fulfillments.find(f => f._id.equals(fulfillmentId))
if (!shipment) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Could not find a fulfillment with the provided id`
)
}
let shipment
const updated = order.fulfillments.map(f => {
if (f._id.equals(fulfillmentId)) {
// For each item in the shipment, we set their status to shipped
f.items.map(item => {
const itemIdx = order.items.findIndex(el => el._id.equals(item._id))
// Update item in order.items and in fullfillment.items to
// ensure consistency
if (item !== -1) {
item.shipped_quantity = item.quantity
order.items[itemIdx].shipped_quantity += item.quantity
}
})
shipment = {
...f,
tracking_numbers: trackingNumbers,
shipped_at: Date.now(),
metadata: {
...f.metadata,
...metadata,
},
}
return shipment
}
return f
})
const updated = {
...shipment,
tracking_numbers: trackingNumbers,
shipped_at: Date.now(),
metadata: {
...shipment.metadata,
...metadata,
},
let fulfillmentStatus = "shipped"
for (const item of order.items) {
if (item.quantity !== item.shipped_quantity) {
fulfillmentStatus = "partially_shipped"
break
}
}
// Add the shipment to the order
@@ -441,7 +459,11 @@ class OrderService extends BaseService {
.updateOne(
{ _id: orderId, "fulfillments._id": fulfillmentId },
{
$set: { "fulfillments.$": updated },
$set: {
"fulfillments.$": updated,
items: order.items,
fulfillment_status: fulfillmentStatus,
},
}
)
.then(result => {
@@ -638,7 +660,26 @@ class OrderService extends BaseService {
provider_id
)
await paymentProvider.capturePayment(data)
try {
await paymentProvider.capturePayment(data)
} catch (error) {
return this.orderModel_
.updateOne(
{
_id: orderId,
},
{
$set: { payment_status: "requires_action" },
}
)
.then(result => {
this.eventBus_.emit(
OrderService.Events.PAYMENT_CAPTURE_FAILED,
result
)
return result
})
}
return this.orderModel_
.updateOne(
@@ -705,12 +746,7 @@ class OrderService extends BaseService {
const { shipping_methods } = order
// prepare update object
const updateFields = { fulfillment_status: "fulfilled" }
const completed = order.payment_status !== "awaiting"
if (completed) {
updateFields.status = "completed"
}
const updateFields = {}
// partition order items to their dedicated shipping method
const fulfillments = await this.partitionItems_(shipping_methods, lineItems)
@@ -729,6 +765,14 @@ class OrderService extends BaseService {
return res
})
method.items = method.items.map(el => {
return {
...el,
fulfilled_quantity: el.quantity,
fulfilled: true,
}
})
return {
provider_id: method.provider_id,
items: method.items,
@@ -745,13 +789,22 @@ class OrderService extends BaseService {
return {
...i,
fulfilled: i.quantity === ful.quantity,
fulfilled_quantity: ful.quantity,
fulfilled_quantity: i.fulfilled_quantity + ful.quantity,
}
}
return i
})
updateFields.fulfillment_status = "fulfilled"
for (const el of updateFields.items) {
if (el.quantity !== el.fulfilled_quantity) {
updateFields.fulfillment_status = "partially_fulfilled"
break
}
}
return this.orderModel_
.updateOne(
{