@medusajs/order
Version:
Medusa Order module
1,104 lines (1,103 loc) • 107 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("@medusajs/framework/types");
const utils_1 = require("@medusajs/framework/utils");
const core_1 = require("@mikro-orm/core");
const _models_1 = require("../models");
const joiner_config_1 = require("../joiner-config");
const utils_2 = require("../utils");
const BundledActions = __importStar(require("./actions"));
const generateMethodForModels = {
Order: _models_1.Order,
OrderAddress: _models_1.OrderAddress,
OrderLineItem: _models_1.OrderLineItem,
OrderLineItemAdjustment: _models_1.OrderLineItemAdjustment,
OrderLineItemTaxLine: _models_1.OrderLineItemTaxLine,
OrderShippingMethod: _models_1.OrderShippingMethod,
OrderShippingMethodAdjustment: _models_1.OrderShippingMethodAdjustment,
OrderShippingMethodTaxLine: _models_1.OrderShippingMethodTaxLine,
OrderTransaction: _models_1.OrderTransaction,
OrderChange: _models_1.OrderChange,
OrderChangeAction: _models_1.OrderChangeAction,
OrderItem: _models_1.OrderItem,
OrderSummary: _models_1.OrderSummary,
OrderShipping: _models_1.OrderShipping,
ReturnReason: _models_1.ReturnReason,
Return: _models_1.Return,
ReturnItem: _models_1.ReturnItem,
OrderClaim: _models_1.OrderClaim,
OrderClaimItem: _models_1.OrderClaimItem,
OrderClaimItemImage: _models_1.OrderClaimItemImage,
OrderExchange: _models_1.OrderExchange,
OrderExchangeItem: _models_1.OrderExchangeItem,
OrderCreditLine: _models_1.OrderCreditLine,
};
{
const MikroORMEntity = (0, utils_1.toMikroORMEntity)(_models_1.OrderChangeAction);
MikroORMEntity.prototype["onInit_OrderChangeAction"] = function () {
this.version ??= this.order_change?.version ?? null;
this.order_id ??= this.order_change?.order_id ?? null;
this.claim_id ??= this.order_change?.claim_id ?? null;
this.exchange_id ??= this.order_change?.exchange_id ?? null;
if (!this.claim_id && !this.exchange_id) {
this.return_id = this.return?.id ?? this.order_change?.return_id ?? null;
}
};
(0, core_1.OnInit)()(MikroORMEntity.prototype, "onInit_OrderChangeAction");
(0, core_1.BeforeCreate)()(MikroORMEntity.prototype, "onInit_OrderChangeAction");
}
{
const MikroORMEntity = (0, utils_1.toMikroORMEntity)(_models_1.OrderShipping);
MikroORMEntity.prototype["onInit_OrderShipping"] = function () {
this.version ??= this.order?.version ?? null;
this.order ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.Order), this.order?.id ?? null);
this.return ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.Return), this.return?.id ?? null);
this.claim ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.OrderClaim), this.claim?.id ?? null);
this.exchange ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.OrderExchange), this.exchange?.id ?? null);
this.shipping_method ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.OrderShippingMethod), this.shipping_method?.id ?? null);
};
(0, core_1.OnInit)()(MikroORMEntity.prototype, "onInit_OrderShipping");
(0, core_1.BeforeCreate)()(MikroORMEntity.prototype, "onInit_OrderShipping");
}
{
const MikroORMEntity = (0, utils_1.toMikroORMEntity)(_models_1.OrderItem);
MikroORMEntity.prototype["onInit_OrderItem"] = function () {
this.version ??= this.order?.version ?? null;
this.order ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.Order), this.order?.id ?? null);
this.item ??= (0, core_1.rel)((0, utils_1.toMikroORMEntity)(_models_1.OrderLineItem), this.item?.id ?? null);
};
(0, core_1.OnInit)()(MikroORMEntity.prototype, "onInit_OrderItem");
(0, core_1.BeforeCreate)()(MikroORMEntity.prototype, "onInit_OrderItem");
}
// TODO: rm template args here, keep it for later to not collide with carlos work at least as little as possible
class OrderModuleService extends utils_1.ModulesSdkUtils.MedusaService(generateMethodForModels) {
constructor({ baseRepository, orderService, orderAddressService, orderLineItemService, orderShippingMethodAdjustmentService, orderShippingMethodService, orderLineItemAdjustmentService, orderShippingMethodTaxLineService, orderLineItemTaxLineService, orderTransactionService, orderChangeService, orderChangeActionService, orderItemService, orderSummaryService, orderShippingService, returnReasonService, returnService, returnItemService, orderClaimService, orderExchangeService, orderCreditLineService, }, moduleDeclaration) {
// @ts-ignore
super(...arguments);
this.moduleDeclaration = moduleDeclaration;
this.baseRepository_ = baseRepository;
this.orderService_ = orderService;
this.orderAddressService_ = orderAddressService;
this.orderLineItemService_ = orderLineItemService;
this.orderShippingMethodAdjustmentService_ =
orderShippingMethodAdjustmentService;
this.orderShippingMethodService_ = orderShippingMethodService;
this.orderLineItemAdjustmentService_ = orderLineItemAdjustmentService;
this.orderShippingMethodTaxLineService_ = orderShippingMethodTaxLineService;
this.orderLineItemTaxLineService_ = orderLineItemTaxLineService;
this.orderTransactionService_ = orderTransactionService;
this.orderChangeService_ = orderChangeService;
this.orderChangeActionService_ = orderChangeActionService;
this.orderItemService_ = orderItemService;
this.orderSummaryService_ = orderSummaryService;
this.orderShippingService_ = orderShippingService;
this.returnReasonService_ = returnReasonService;
this.returnService_ = returnService;
this.returnItemService_ = returnItemService;
this.orderClaimService_ = orderClaimService;
this.orderExchangeService_ = orderExchangeService;
this.orderCreditLineService_ = orderCreditLineService;
}
__joinerConfig() {
return joiner_config_1.joinerConfig;
}
shouldIncludeTotals(config) {
const totalFields = [
"total",
"subtotal",
"tax_total",
"discount_total",
"discount_tax_total",
"original_total",
"original_tax_total",
"item_total",
"item_subtotal",
"item_tax_total",
"original_item_total",
"original_item_subtotal",
"original_item_tax_total",
"shipping_total",
"shipping_subtotal",
"shipping_tax_total",
"original_shipping_tax_total",
"original_shipping_subtotal",
"original_shipping_total",
"credit_line_total",
"credit_line_tax_total",
"credit_line_subtotal",
];
const includeTotals = (config?.select ?? []).some((field) => totalFields.includes(field));
if (includeTotals) {
this.addRelationsToCalculateTotals(config, totalFields);
}
return includeTotals;
}
addRelationsToCalculateTotals(config, totalFields) {
config.relations ??= [];
config.select ??= [];
const requiredRelationsForTotals = [
"credit_lines",
"items",
"items.tax_lines",
"items.adjustments",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
];
config.relations = (0, utils_1.deduplicate)([
...config.relations,
...requiredRelationsForTotals,
]);
config.select = config.select.filter((field) => {
return (!requiredRelationsForTotals.some((val) => val.startsWith(field)) && !totalFields.includes(field));
});
}
// @ts-expect-error
async retrieveOrder(id, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const order = await super.retrieveOrder(id, config, sharedContext);
const orderChange = await this.getActiveOrderChange_(order.id, false, sharedContext);
order.order_change = orderChange;
return (0, utils_2.formatOrder)(order, {
entity: _models_1.Order,
includeTotals,
});
}
// @ts-expect-error
async listOrders(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const orders = await super.listOrders(filters, config, sharedContext);
return (0, utils_2.formatOrder)(orders, {
entity: _models_1.Order,
includeTotals,
});
}
// @ts-expect-error
async listAndCountOrders(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const [orders, count] = await super.listAndCountOrders(filters, config, sharedContext);
return [
(0, utils_2.formatOrder)(orders, {
entity: _models_1.Order,
includeTotals,
}),
count,
];
}
// @ts-ignore
async retrieveReturn(id, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const returnOrder = await super.retrieveReturn(id, config, sharedContext);
return (0, utils_2.formatOrder)(returnOrder, {
entity: _models_1.Return,
includeTotals,
});
}
// @ts-ignore
async listReturns(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const returnOrders = await super.listReturns(filters, config, sharedContext);
return (0, utils_2.formatOrder)(returnOrders, {
entity: _models_1.Return,
includeTotals,
});
}
// @ts-ignore
async listAndCountReturns(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const [returnOrders, count] = await super.listAndCountReturns(filters, config, sharedContext);
return [
(0, utils_2.formatOrder)(returnOrders, {
entity: _models_1.Return,
includeTotals,
}),
count,
];
}
// @ts-ignore
async retrieveOrderClaim(id, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const returnOrder = await super.retrieveOrderClaim(id, config, sharedContext);
return (0, utils_2.formatOrder)(returnOrder, {
entity: _models_1.OrderClaim,
includeTotals,
});
}
// @ts-ignore
async listOrderClaims(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const returnOrders = await super.listOrderClaims(filters, config, sharedContext);
return (0, utils_2.formatOrder)(returnOrders, {
entity: _models_1.OrderClaim,
includeTotals,
});
}
// @ts-ignore
async listAndCountOrderClaims(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const [returnOrders, count] = await super.listAndCountOrderClaims(filters, config, sharedContext);
return [
(0, utils_2.formatOrder)(returnOrders, {
entity: _models_1.OrderClaim,
includeTotals,
}),
count,
];
}
// @ts-ignore
async retrieveOrderExchange(id, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const returnOrder = await super.retrieveOrderExchange(id, config, sharedContext);
return (0, utils_2.formatOrder)(returnOrder, {
entity: _models_1.OrderExchange,
includeTotals,
});
}
// @ts-ignore
async listOrderExchanges(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const returnOrders = await super.listOrderExchanges(filters, config, sharedContext);
return (0, utils_2.formatOrder)(returnOrders, {
entity: _models_1.OrderExchange,
includeTotals,
});
}
// @ts-ignore
async listAndCountOrderExchanges(filters, config, sharedContext) {
config ??= {};
const includeTotals = this.shouldIncludeTotals(config);
const [returnOrders, count] = await super.listAndCountOrderExchanges(filters, config, sharedContext);
return [
(0, utils_2.formatOrder)(returnOrders, {
entity: _models_1.OrderExchange,
includeTotals,
}),
count,
];
}
// @ts-expect-error
async createOrders(data, sharedContext = {}) {
const input = Array.isArray(data) ? data : [data];
const orders = await this.createOrders_(input, sharedContext);
const result = await this.listOrders({
id: orders.map((p) => p.id),
}, {
relations: [
"shipping_address",
"billing_address",
"summary",
"items",
"credit_lines",
"items.tax_lines",
"items.adjustments",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
"transactions",
],
}, sharedContext);
return (Array.isArray(data) ? result : result[0]);
}
async createOrders_(data, sharedContext = {}) {
await this.createOrderAddresses_(data, sharedContext);
const lineItemsToCreate = [];
const creditLinesToCreate = [];
const createdOrders = [];
for (const { items, shipping_methods, credit_lines, shipping_address, billing_address, ...order } of data) {
const ord = order;
const shippingMethods = shipping_methods?.map((sm) => {
return {
shipping_method: { ...sm },
};
});
ord.shipping_methods = shippingMethods;
const orderWithTotals = (0, utils_1.decorateCartTotals)({
...ord,
shipping_methods,
items,
credit_lines,
});
const calculated = (0, utils_2.calculateOrderChange)({
order: orderWithTotals,
actions: [],
transactions: order.transactions,
});
(0, utils_1.createRawPropertiesFromBigNumber)(calculated);
ord.summary = {
totals: calculated.summary,
};
const created = await this.orderService_.create(ord, sharedContext);
creditLinesToCreate.push(...(credit_lines ?? []).map((creditLine) => ({
amount: utils_1.MathBN.convert(creditLine.amount),
reference: creditLine.reference,
reference_id: creditLine.reference_id,
metadata: creditLine.metadata,
order_id: created.id,
})));
createdOrders.push(created);
if (items?.length) {
const orderItems = items.map((item) => {
return {
...item,
order_id: created.id,
};
});
lineItemsToCreate.push(...orderItems);
}
}
if (lineItemsToCreate.length) {
await this.createOrderLineItemsBulk_(lineItemsToCreate, sharedContext);
}
if (creditLinesToCreate.length) {
await this.orderCreditLineService_.create(creditLinesToCreate, sharedContext);
}
return createdOrders;
}
async createOrderAddresses_(input, sharedContext = {}) {
const allAddresses = [];
input.forEach((inputData) => {
if (inputData.billing_address) {
allAddresses.push({
data: inputData.billing_address,
type: "billing",
source: inputData,
});
}
if (inputData.shipping_address) {
allAddresses.push({
data: inputData.shipping_address,
type: "shipping",
source: inputData,
});
}
});
const createdAddresses = allAddresses.length
? await this.orderAddressService_.create(allAddresses.map((a) => a.data), sharedContext)
: [];
createdAddresses.forEach((createdAddress, index) => {
const { type, source } = allAddresses[index];
if (type === "billing") {
source.billing_address_id = createdAddress.id;
}
else if (type === "shipping") {
source.shipping_address_id = createdAddress.id;
}
});
}
// @ts-expect-error
async deleteOrders(orderIds, sharedContext = {}) {
const ids = Array.isArray(orderIds) ? orderIds : [orderIds];
const orders = await this.orderService_.list({ id: ids }, {
select: ["id", "shipping_address_id", "billing_address_id"],
}, sharedContext);
const orderAddressIds = orders
.map((order) => [order.shipping_address_id, order.billing_address_id])
.flat(1);
const orderChanges = await this.orderChangeService_.list({ order_id: ids }, { select: ["id"] }, sharedContext);
const orderChangeIds = orderChanges.map((orderChange) => orderChange.id);
const orderItems = await this.orderItemService_.list({ order_id: ids }, { select: ["id", "item_id"] }, sharedContext);
const lineItemIds = orderItems.map((orderItem) => orderItem.item_id);
const orderShipping = await this.orderShippingService_.list({ order_id: ids }, { select: ["shipping_method_id"] }, sharedContext);
const orderShippingMethodIds = orderShipping.map((orderShipping) => orderShipping.shipping_method_id);
await (0, utils_1.promiseAll)([
this.orderAddressService_.delete(orderAddressIds, sharedContext),
// Delete order changes & actions
this.orderChangeService_.delete(orderChangeIds, sharedContext),
]);
// Delete order, order items, summary, shipping methods and transactions
await super.deleteOrders(ids, sharedContext);
await (0, utils_1.promiseAll)([
this.orderLineItemService_.delete(lineItemIds, sharedContext),
this.orderShippingMethodService_.delete(orderShippingMethodIds, sharedContext),
]);
}
// @ts-expect-error
async updateOrders(dataOrIdOrSelector, data, sharedContext = {}) {
const result = await this.updateOrders_(dataOrIdOrSelector, data, sharedContext);
const serializedResult = await this.baseRepository_.serialize(result, {
populate: true,
});
return (0, utils_1.isString)(dataOrIdOrSelector) ? serializedResult[0] : serializedResult;
}
async updateOrders_(dataOrIdOrSelector, data, sharedContext = {}) {
let toUpdate = [];
if ((0, utils_1.isString)(dataOrIdOrSelector)) {
toUpdate = [
{
id: dataOrIdOrSelector,
...data,
},
];
}
else if (Array.isArray(dataOrIdOrSelector)) {
toUpdate = dataOrIdOrSelector;
}
else {
const orders = await this.orderService_.list({ ...dataOrIdOrSelector }, { select: ["id"] }, sharedContext);
toUpdate = orders.map((order) => {
return {
...data,
id: order.id,
};
});
}
const result = await this.orderService_.update(toUpdate, sharedContext);
return result;
}
// @ts-expect-error
async createOrderLineItems(orderIdOrData, data, sharedContext = {}) {
let items = [];
if ((0, utils_1.isString)(orderIdOrData)) {
items = await this.createOrderLineItems_(orderIdOrData, data, sharedContext);
}
else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData];
const allOrderIds = data.map((dt) => dt.order_id);
const order = await this.listOrders({ id: allOrderIds }, { select: ["id", "version"] }, sharedContext);
const mapOrderVersion = order.reduce((acc, curr) => {
acc[curr.id] = curr.version;
return acc;
}, {});
const lineItems = data.map((dt) => {
return {
...dt,
version: mapOrderVersion[dt.order_id],
};
});
items = await this.createOrderLineItemsBulk_(lineItems, sharedContext);
}
return await this.baseRepository_.serialize(items, {
populate: true,
});
}
async createOrderLineItems_(orderId, items, sharedContext = {}) {
const order = await this.retrieveOrder(orderId, { select: ["id", "version"] }, sharedContext);
const toUpdate = items.map((item) => {
return {
...item,
order_id: order.id,
version: order.version,
};
});
return await this.createOrderLineItemsBulk_(toUpdate, sharedContext);
}
async createOrderLineItemsBulk_(data, sharedContext = {}) {
const orderItemToCreate = [];
const lineItems = await this.orderLineItemService_.create(data, sharedContext);
for (let i = 0; i < lineItems.length; i++) {
const item = lineItems[i];
const toCreate = data[i];
if (toCreate.order_id) {
orderItemToCreate.push({
order_id: toCreate.order_id,
version: toCreate.version ?? 1,
item_id: item.id,
quantity: toCreate.quantity,
});
}
}
if (orderItemToCreate.length) {
await this.orderItemService_.create(orderItemToCreate, sharedContext);
}
return lineItems;
}
// @ts-expect-error
async updateOrderLineItems(lineItemIdOrDataOrSelector, data, sharedContext = {}) {
let items = [];
if ((0, utils_1.isString)(lineItemIdOrDataOrSelector)) {
const item = await this.updateOrderLineItem_(lineItemIdOrDataOrSelector, data, sharedContext);
return await this.baseRepository_.serialize(item, {
populate: true,
});
}
const toUpdate = Array.isArray(lineItemIdOrDataOrSelector)
? lineItemIdOrDataOrSelector
: [
{
selector: lineItemIdOrDataOrSelector,
data: data,
},
];
items = await this.updateOrderLineItemsWithSelector_(toUpdate, sharedContext);
return await this.baseRepository_.serialize(items, {
populate: true,
});
}
async updateOrderLineItem_(lineItemId, data, sharedContext = {}) {
const [item] = await this.orderLineItemService_.update([{ id: lineItemId, ...data }], sharedContext);
if ("quantity" in data) {
await this.updateOrderItemWithSelector_([
{
selector: { item_id: item.id },
data,
},
], sharedContext);
}
return item;
}
async updateOrderLineItemsWithSelector_(updates, sharedContext = {}) {
let toUpdate = [];
const detailsToUpdate = [];
for (const { selector, data } of updates) {
const items = await this.listOrderLineItems({ ...selector }, {}, sharedContext);
items.forEach((item) => {
toUpdate.push({
...data,
id: item.id,
});
if ("quantity" in data) {
detailsToUpdate.push({
selector: { item_id: item.id },
data,
});
}
});
}
if (detailsToUpdate.length) {
await this.updateOrderItemWithSelector_(detailsToUpdate, sharedContext);
}
return await this.orderLineItemService_.update(toUpdate, sharedContext);
}
async updateOrderItem(orderItemIdOrDataOrSelector, data, sharedContext = {}) {
let items = [];
if ((0, utils_1.isString)(orderItemIdOrDataOrSelector)) {
const item = await this.updateOrderItem_(orderItemIdOrDataOrSelector, data, sharedContext);
return await this.baseRepository_.serialize(item, {
populate: true,
});
}
const toUpdate = Array.isArray(orderItemIdOrDataOrSelector)
? orderItemIdOrDataOrSelector
: [
{
selector: orderItemIdOrDataOrSelector,
data: data,
},
];
items = await this.updateOrderItemWithSelector_(toUpdate, sharedContext);
return await this.baseRepository_.serialize(items, {
populate: true,
});
}
async updateOrderItem_(orderItemId, data, sharedContext = {}) {
const [detail] = await this.orderItemService_.update([{ id: orderItemId, ...data }], sharedContext);
return detail;
}
async updateOrderItemWithSelector_(updates, sharedContext = {}) {
let toUpdate = [];
for (const { selector, data } of updates) {
const details = await this.listOrderItems({ ...selector }, {}, sharedContext);
details.forEach((detail) => {
toUpdate.push({
...data,
id: detail.id,
});
});
}
return await this.orderItemService_.update(toUpdate, sharedContext);
}
// @ts-expect-error
async createOrderShippingMethods(orderIdOrData, data, sharedContext = {}) {
let methods;
if ((0, utils_1.isString)(orderIdOrData)) {
methods = await this.createOrderShippingMethods_(orderIdOrData, data, sharedContext);
}
else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData];
const allOrderIds = data.map((dt) => dt.order_id);
const order = await this.listOrders({ id: allOrderIds }, { select: ["id", "version"] }, sharedContext);
const mapOrderVersion = order.reduce((acc, curr) => {
acc[curr.id] = curr.version;
return acc;
}, {});
const orderShippingMethodData = data.map((dt) => {
return {
shipping_method: dt,
order_id: dt.order_id,
return_id: dt.return_id,
claim_id: dt.claim_id,
exchange_id: dt.exchange_id,
version: dt.version ?? mapOrderVersion[dt.order_id],
};
});
methods = await this.createOrderShippingMethodsBulk_(orderShippingMethodData, sharedContext);
}
return await this.baseRepository_.serialize(methods, { populate: true });
}
async createOrderShippingMethods_(orderId, data, sharedContext = {}) {
const order = await this.retrieveOrder(orderId, { select: ["id", "version"] }, sharedContext);
const methods = data.map((methodData) => {
return {
shipping_method: methodData,
order_id: order.id,
return_id: methodData.return_id,
claim_id: methodData.claim_id,
exchange_id: methodData.exchange_id,
version: methodData.version ?? order.version ?? 1,
};
});
return await this.createOrderShippingMethodsBulk_(methods, sharedContext);
}
async createOrderShippingMethodsBulk_(data, sharedContext = {}) {
const sm = await this.orderShippingService_.create(data, sharedContext);
return sm.map((s) => s.shipping_method);
}
// @ts-ignore
async softDeleteOrderShippingMethods(ids, config, sharedContext) {
const rel = await super.listOrderShippings({
shipping_method_id: ids,
}, {
select: ["id"],
}, sharedContext);
const orderShippingIds = rel.map((r) => r.id);
const [returned] = await (0, utils_1.promiseAll)([
super.softDeleteOrderShippingMethods(ids, config, sharedContext),
super.softDeleteOrderShippings(orderShippingIds, config, sharedContext),
]);
return returned;
}
// @ts-ignore
async restoreOrderShippingMethods(ids, config, sharedContext) {
const rel = await super.listOrderShippings({
shipping_method_id: ids,
}, {
select: ["id"],
}, sharedContext);
const shippingIds = rel.map((r) => r.id);
const [returned] = await (0, utils_1.promiseAll)([
super.restoreOrderShippingMethods(ids, config, sharedContext),
super.restoreOrderShippings(shippingIds, config, sharedContext),
]);
return returned;
}
// @ts-expect-error
async createOrderLineItemAdjustments(orderIdOrData, adjustments, sharedContext = {}) {
let addedAdjustments = [];
if ((0, utils_1.isString)(orderIdOrData)) {
const order = await this.retrieveOrder(orderIdOrData, { select: ["id"], relations: ["items.item"] }, sharedContext);
const lineIds = order.items?.map((item) => item.id);
for (const adj of adjustments || []) {
if (!lineIds?.includes(adj.item_id)) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Line item with id ${adj.item_id} does not exist on order with id ${orderIdOrData}`);
}
}
addedAdjustments = await this.orderLineItemAdjustmentService_.create(adjustments, sharedContext);
}
else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData];
addedAdjustments = await this.orderLineItemAdjustmentService_.create(data, sharedContext);
}
return await this.baseRepository_.serialize(addedAdjustments, {
populate: true,
});
}
async upsertOrderLineItemAdjustments(adjustments, sharedContext = {}) {
let result = await this.orderLineItemAdjustmentService_.upsert(adjustments, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
async setOrderLineItemAdjustments(orderId, adjustments, sharedContext = {}) {
const order = await this.retrieveOrder(orderId, { select: ["id"], relations: ["items.item.adjustments"] }, sharedContext);
const existingAdjustments = (order.items ?? [])
.map((item) => item.adjustments ?? [])
.flat()
.map((adjustment) => adjustment.id);
const adjustmentsSet = new Set(adjustments
.map((a) => a.id)
.filter(Boolean));
const toDelete = [];
// From the existing adjustments, find the ones that are not passed in adjustments
existingAdjustments.forEach((adj) => {
if (!adjustmentsSet.has(adj)) {
toDelete.push(adj);
}
});
if (toDelete.length) {
await this.orderLineItemAdjustmentService_.delete(toDelete, sharedContext);
}
let result = await this.orderLineItemAdjustmentService_.upsert(adjustments, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
async upsertOrderShippingMethodAdjustments(adjustments, sharedContext = {}) {
const result = await this.orderShippingMethodAdjustmentService_.upsert(adjustments, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
async setOrderShippingMethodAdjustments(orderId, adjustments, sharedContext = {}) {
const order = await this.retrieveOrder(orderId, { select: ["id"], relations: ["shipping_methods.adjustments"] }, sharedContext);
const existingAdjustments = (order.shipping_methods ?? [])
.map((shippingMethod) => shippingMethod.adjustments ?? [])
.flat()
.map((adjustment) => adjustment.id);
const adjustmentsSet = new Set(adjustments
.map((a) => a?.id)
.filter(Boolean));
const toDelete = [];
// From the existing adjustments, find the ones that are not passed in adjustments
existingAdjustments.forEach((adj) => {
if (!adjustmentsSet.has(adj)) {
toDelete.push(adj);
}
});
if (toDelete.length) {
await this.orderShippingMethodAdjustmentService_.delete(toDelete, sharedContext);
}
const result = await this.orderShippingMethodAdjustmentService_.upsert(adjustments, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
// @ts-expect-error
async createOrderShippingMethodAdjustments(orderIdOrData, adjustments, sharedContext = {}) {
let addedAdjustments = [];
if ((0, utils_1.isString)(orderIdOrData)) {
const order = await this.retrieveOrder(orderIdOrData, { select: ["id"], relations: ["shipping_methods"] }, sharedContext);
const methodIds = order.shipping_methods?.map((method) => method.id);
for (const adj of adjustments || []) {
if (!methodIds?.includes(adj.shipping_method_id)) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Shipping method with id ${adj.shipping_method_id} does not exist on order with id ${orderIdOrData}`);
}
}
addedAdjustments =
await this.orderShippingMethodAdjustmentService_.create(adjustments, sharedContext);
}
else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData];
addedAdjustments =
await this.orderShippingMethodAdjustmentService_.create(data, sharedContext);
}
if ((0, utils_1.isObject)(orderIdOrData)) {
return await this.baseRepository_.serialize(addedAdjustments[0], {
populate: true,
});
}
return await this.baseRepository_.serialize(addedAdjustments, {
populate: true,
});
}
// @ts-expect-error
async createOrderLineItemTaxLines(orderIdOrData, taxLines, sharedContext = {}) {
let addedTaxLines;
if ((0, utils_1.isString)(orderIdOrData)) {
const lines = Array.isArray(taxLines) ? taxLines : [taxLines];
addedTaxLines = await this.orderLineItemTaxLineService_.create(lines, sharedContext);
}
else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData];
addedTaxLines = await this.orderLineItemTaxLineService_.create(data, sharedContext);
}
const serialized = await this.baseRepository_.serialize(addedTaxLines, {
populate: true,
});
if ((0, utils_1.isObject)(orderIdOrData)) {
return serialized[0];
}
return serialized;
}
async upsertOrderLineItemTaxLines(taxLines, sharedContext = {}) {
const result = await this.orderLineItemTaxLineService_.upsert(taxLines, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
async setOrderLineItemTaxLines(orderId, taxLines, sharedContext = {}) {
const order = await this.retrieveOrder(orderId, { select: ["id"], relations: ["items.item.tax_lines"] }, sharedContext);
const existingTaxLines = (order.items ?? [])
.map((item) => item.tax_lines ?? [])
.flat()
.map((taxLine) => taxLine.id);
const taxLinesSet = new Set(taxLines
.map((taxLine) => taxLine?.id)
.filter(Boolean));
const toDelete = [];
existingTaxLines.forEach((taxLine) => {
if (!taxLinesSet.has(taxLine)) {
toDelete.push(taxLine);
}
});
if (toDelete.length) {
await this.orderLineItemTaxLineService_.delete(toDelete, sharedContext);
}
const result = await this.orderLineItemTaxLineService_.upsert(taxLines, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
// @ts-expect-error
async createOrderShippingMethodTaxLines(orderIdOrData, taxLines, sharedContext = {}) {
let addedTaxLines;
if ((0, utils_1.isString)(orderIdOrData)) {
const lines = Array.isArray(taxLines) ? taxLines : [taxLines];
addedTaxLines = await this.orderShippingMethodTaxLineService_.create(lines, sharedContext);
}
else {
addedTaxLines = await this.orderShippingMethodTaxLineService_.create(taxLines, sharedContext);
}
const serialized = await this.baseRepository_.serialize(addedTaxLines[0], {
populate: true,
});
if ((0, utils_1.isObject)(orderIdOrData)) {
return serialized[0];
}
return serialized;
}
async upsertOrderShippingMethodTaxLines(taxLines, sharedContext = {}) {
const result = await this.orderShippingMethodTaxLineService_.upsert(taxLines, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
async setOrderShippingMethodTaxLines(orderId, taxLines, sharedContext = {}) {
const order = await this.retrieveOrder(orderId, { select: ["id"], relations: ["shipping_methods.tax_lines"] }, sharedContext);
const existingTaxLines = (order.shipping_methods ?? [])
.map((shippingMethod) => shippingMethod.tax_lines ?? [])
.flat()
.map((taxLine) => taxLine.id);
const taxLinesSet = new Set(taxLines
.map((taxLine) => taxLine?.id)
.filter(Boolean));
const toDelete = [];
existingTaxLines.forEach((taxLine) => {
if (!taxLinesSet.has(taxLine)) {
toDelete.push(taxLine);
}
});
if (toDelete.length) {
await this.orderShippingMethodTaxLineService_.delete(toDelete, sharedContext);
}
const result = await this.orderShippingMethodTaxLineService_.upsert(taxLines, sharedContext);
return await this.baseRepository_.serialize(result, {
populate: true,
});
}
// @ts-expect-error
async createReturns(data, sharedContext) {
const created = await this.createOrderRelatedEntity_(data, this.returnService_, sharedContext);
return await this.baseRepository_.serialize(!Array.isArray(data) ? created[0] : created, {
populate: true,
});
}
// @ts-expect-error
async createOrderClaims(data, sharedContext) {
const created = await this.createOrderRelatedEntity_(data, this.orderClaimService_, sharedContext);
return await this.baseRepository_.serialize(!Array.isArray(data) ? created[0] : created, {
populate: true,
});
}
// @ts-expect-error
async createOrderExchanges(data, sharedContext) {
const created = await this.createOrderRelatedEntity_(data, this.orderExchangeService_, sharedContext);
return await this.baseRepository_.serialize(!Array.isArray(data) ? created[0] : created, {
populate: true,
});
}
async createOrderRelatedEntity_(data, service, sharedContext) {
const data_ = Array.isArray(data) ? data : [data];
const inputDataMap = data_.reduce((acc, curr) => {
acc[curr.order_id] = curr;
return acc;
}, {});
const orderIds = data_.map((d) => d.order_id);
const orders = await this.orderService_.list({ id: orderIds }, { select: ["id", "version"] }, sharedContext);
if (orders.length !== orderIds.length) {
const foundOrders = orders.map((o) => o.id);
const missing = orderIds.filter((id) => !foundOrders.includes(id));
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Order could not be found: ${missing.join(", ")}`);
}
for (const order of orders) {
inputDataMap[order.id].order_version = order.version;
}
return await service.create(data_, sharedContext);
}
async createOrderChange(data, sharedContext) {
const changes = await this.createOrderChange_(data, sharedContext);
return await this.baseRepository_.serialize(Array.isArray(data) ? changes : changes[0], {
populate: true,
});
}
async createOrderChange_(data, sharedContext) {
const dataArr = Array.isArray(data) ? data : [data];
const orderIds = [];
const dataMap = {};
const orderChanges = await this.listOrderChanges({
order_id: dataArr.map((data) => data.order_id),
status: [utils_1.OrderChangeStatus.PENDING, utils_1.OrderChangeStatus.REQUESTED],
}, {}, sharedContext);
const orderChangesMap = new Map(orderChanges.map((item) => [item.order_id, item]));
for (const change of dataArr) {
orderIds.push(change.order_id);
dataMap[change.order_id] = change;
}
const orders = await this.orderService_.list({ id: orderIds }, { select: ["id", "version"] }, sharedContext);
if (orders.length !== orderIds.length) {
const foundOrders = orders.map((o) => o.id);
const missing = orderIds.filter((id) => !foundOrders.includes(id));
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Order could not be found: ${missing.join(", ")}`);
}
const input = orders.map((order) => {
const existingOrderChange = orderChangesMap.get(order.id);
if (existingOrderChange) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Order (${order.id}) already has an existing active order change`);
}
return {
...dataMap[order.id],
version: order.version + 1,
};
});
return await this.orderChangeService_.create(input, sharedContext);
}
async previewOrderChange(orderId, sharedContext) {
const order = await this.retrieveOrder(orderId, {
select: ["id", "version", "items.detail", "summary", "total"],
relations: ["transactions", "credit_lines"],
}, sharedContext);
if (!order.order_change) {
return order;
}
const orderChange = await super.retrieveOrderChange(order.order_change.id, { relations: ["actions"] }, sharedContext);
const { itemsToUpsert, shippingMethodsToUpsert, calculatedOrders } = await (0, utils_2.applyChangesToOrder)([order], { [order.id]: orderChange.actions }, { addActionReferenceToObject: true });
const calculated = calculatedOrders[order.id];
await this.includeTaxLinesAndAdjustementsToPreview(calculated.order, itemsToUpsert, shippingMethodsToUpsert, sharedContext);
const calcOrder = calculated.order;
const orderWithTotals = (0, utils_1.decorateCartTotals)(calcOrder);
calcOrder.summary = calculated.getSummaryFromOrder(orderWithTotals);
(0, utils_1.createRawPropertiesFromBigNumber)(calcOrder);
return calcOrder;
}
async includeTaxLinesAndAdjustementsToPreview(order, itemsToUpsert, shippingMethodsToUpsert, sharedContext) {
const addedItems = {};
const addedShippingMethods = {};
for (const item of order.items) {
const isExistingItem = item.id === item.detail?.item_id;
if (!isExistingItem) {
addedItems[item.id] = {
...item,
quantity: item.detail?.quantity ?? item.quantity,
unit_price: item.detail?.unit_price || item.unit_price,
compare_at_unit_price: item.detail?.compare_at_unit_price ||
item.compare_at_unit_price ||
null,
};
}
}
for (const sm of order.shipping_methods) {
if (!(0, utils_1.isDefined)(sm.shipping_option_id)) {
addedShippingMethods[sm.id] = sm;
}
}
if (Object.keys(addedItems).length > 0) {
const addedItemDetails = await this.listOrderLineItems({ id: Object.keys(addedItems) }, {
relations: ["adjustments", "tax_lines"],
}, sharedContext);
order.items.forEach((item, idx) => {
if (!addedItems[item.id]) {
return;
}
const lineItem = addedItemDetails.find((d) => d.id === item.id);
const actions = item.actions;
delete item.actions;
//@ts-ignore
const newItem = itemsToUpsert.find((d) => d.item_id === item.id);
const unitPrice = newItem?.unit_price ?? item.unit_price;
const compareAtUnitPrice = newItem?.compare_at_unit_price ?? item.compare_at_unit_price;
delete lineItem.raw_unit_price;
delete lineItem.raw_compare_at_unit_price;
order.items[idx] = {
...lineItem,
actions,
quantity: newItem.quantity,
unit_price: unitPrice,
compare_at_unit_price: compareAtUnitPrice || null,
detail: {
...newItem,
...item,
},
};
});
}
if (Object.keys(addedShippingMethods).length > 0) {
const addedShippingDetails = await this.listOrderShippingMethods({ id: Object.keys(addedShippingMethods) }, {
relations: ["adjustments", "tax_lines"],
}, sharedContext);
order.shipping_methods.forEach((sm, idx) => {
if (!addedShippingMethods[sm.id]) {
return;
}
const shippingMethod = addedShippingDetails.find((d) => d.id === sm.id);
const actions = sm.actions;
delete sm.actions;
const newItem = shippingMethodsToUpsert.find((d) => d.id === sm.id);
sm.shipping_method_id = sm.id;
delete sm.id;
order.shipping_methods[idx] = {
...shippingMethod,
actions,
detail: {
...sm,
...newItem,
},
};
});
}
}
async cancelOrderChange(orderChangeIdOrData, sharedContext) {