feat(medusa-fulfillment-webshipper): Create webshipper return order (#4846)
Adds option to create a webshipper return order if return_portal is defined through webshipper options. Return order allows additional features in webshipper, such as marking the return as "Arrived" or "Processed" which enables us to create a webhook and automatically mark return as received in medusa. Note: Return portal is a "required" relationship in webshipper when doing a return order POST request, hence it should be defined in options prior to using this feature. Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"medusa-fulfillment-webshipper": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa-fulfillment-webshipper): Create webshipper return order
|
||||||
@@ -97,6 +97,75 @@ class WebshipperFulfillmentService extends AbstractFulfillmentService {
|
|||||||
// Calculate prices
|
// Calculate prices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a return order in webshipper and links it to an existing shipment.
|
||||||
|
*/
|
||||||
|
async createReturnOrder(shipment, fromOrder) {
|
||||||
|
const fulfillmentData = fromOrder.fulfillments[0]?.data
|
||||||
|
|
||||||
|
if (!shipment?.id || !fulfillmentData?.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const customsLines = shipment.attributes?.packages?.[0]?.customs_lines
|
||||||
|
|
||||||
|
if (!customsLines?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const returnOrderData = {
|
||||||
|
type: "returns",
|
||||||
|
attributes: {
|
||||||
|
status: "pending",
|
||||||
|
return_lines: customsLines.map(({ ext_ref, quantity }) => ({
|
||||||
|
order_line_id: fulfillmentData.attributes?.order_lines?.find(
|
||||||
|
(order_line) => order_line.ext_ref === ext_ref
|
||||||
|
)?.id,
|
||||||
|
cause_id: this.options_.return_portal?.cause_id || "1",
|
||||||
|
quantity: quantity,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
relationships: {
|
||||||
|
order: {
|
||||||
|
data: {
|
||||||
|
id: fulfillmentData.id,
|
||||||
|
type: "orders",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
portal: {
|
||||||
|
data: {
|
||||||
|
id: this.options_.return_portal.id || "1",
|
||||||
|
type: "return_portals",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
refund_method: {
|
||||||
|
data: {
|
||||||
|
id: this.options_.return_portal.refund_method_id || "1",
|
||||||
|
type: "return_refund_methods",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shipping_method: {
|
||||||
|
data: {
|
||||||
|
id: shipment.shipping_method?.data?.webshipper_id || "1",
|
||||||
|
type: "return_shipping_methods",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shipment: {
|
||||||
|
data: {
|
||||||
|
id: shipment.id,
|
||||||
|
type: "shipments",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client_.returns.create(returnOrderData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a return shipment in webshipper using the given method data, and
|
||||||
|
* return lines.
|
||||||
|
*/
|
||||||
async createReturn(returnOrder) {
|
async createReturn(returnOrder) {
|
||||||
let orderId
|
let orderId
|
||||||
if (returnOrder.order_id) {
|
if (returnOrder.order_id) {
|
||||||
@@ -109,7 +178,13 @@ class WebshipperFulfillmentService extends AbstractFulfillmentService {
|
|||||||
|
|
||||||
const fromOrder = await this.orderService_.retrieve(orderId, {
|
const fromOrder = await this.orderService_.retrieve(orderId, {
|
||||||
select: ["total"],
|
select: ["total"],
|
||||||
relations: ["discounts", "discounts.rule", "shipping_address", "returns"],
|
relations: [
|
||||||
|
"discounts",
|
||||||
|
"discounts.rule",
|
||||||
|
"shipping_address",
|
||||||
|
"returns",
|
||||||
|
"fulfillments",
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
const methodData = returnOrder.shipping_method.data
|
const methodData = returnOrder.shipping_method.data
|
||||||
@@ -204,6 +279,10 @@ class WebshipperFulfillmentService extends AbstractFulfillmentService {
|
|||||||
return this.client_.shipments
|
return this.client_.shipments
|
||||||
.create(returnShipment)
|
.create(returnShipment)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
if (this.options_.return_portal?.id) {
|
||||||
|
this.createReturnOrder(result.data, fromOrder)
|
||||||
|
}
|
||||||
|
|
||||||
return result.data
|
return result.data
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class Webshipper {
|
|||||||
this.shippingRates = this.buildShippingRateEndpoints_()
|
this.shippingRates = this.buildShippingRateEndpoints_()
|
||||||
this.orders = this.buildOrderEndpoints_()
|
this.orders = this.buildOrderEndpoints_()
|
||||||
this.shipments = this.buildShipmentEndpoints_()
|
this.shipments = this.buildShipmentEndpoints_()
|
||||||
|
this.returns = this.buildReturnEndpoints_()
|
||||||
}
|
}
|
||||||
|
|
||||||
async request(data) {
|
async request(data) {
|
||||||
@@ -124,6 +125,21 @@ class Webshipper {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildReturnEndpoints_ = () => {
|
||||||
|
return {
|
||||||
|
create: async (data) => {
|
||||||
|
const path = `/v2/returns`
|
||||||
|
return this.client_({
|
||||||
|
method: "POST",
|
||||||
|
url: path,
|
||||||
|
data: {
|
||||||
|
data,
|
||||||
|
},
|
||||||
|
}).then(({ data }) => data)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Webshipper
|
export default Webshipper
|
||||||
|
|||||||
Reference in New Issue
Block a user