@medusajs/core-flows
Version:
Set of workflow definitions for Medusa
225 lines • 9.75 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCartWorkflow = exports.createCartWorkflowId = void 0;
const utils_1 = require("@medusajs/framework/utils");
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
const emit_event_1 = require("../../common/steps/emit-event");
const use_remote_query_1 = require("../../common/steps/use-remote-query");
const steps_1 = require("../steps");
const validate_line_item_prices_1 = require("../steps/validate-line-item-prices");
const validate_variant_prices_1 = require("../steps/validate-variant-prices");
const fields_1 = require("../utils/fields");
const prepare_line_item_data_1 = require("../utils/prepare-line-item-data");
const confirm_variant_inventory_1 = require("./confirm-variant-inventory");
const refresh_payment_collection_1 = require("./refresh-payment-collection");
const update_cart_promotions_1 = require("./update-cart-promotions");
const update_tax_lines_1 = require("./update-tax-lines");
const validate_sales_channel_1 = require("../steps/validate-sales-channel");
const schemas_1 = require("../utils/schemas");
exports.createCartWorkflowId = "create-cart";
/**
* This workflow creates and returns a cart. You can set the cart's items, region, customer, and other details. This workflow is executed by the
* [Create Cart Store API Route](https://docs.medusajs.com/api/store#carts_postcarts).
*
* This workflow has a hook that allows you to perform custom actions on the created cart. You can see an example in [this guide](https://docs.medusajs.com/resources/commerce-modules/cart/extend#step-4-consume-cartcreated-workflow-hook).
*
* You can also use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around cart creation.
*
* @example
* const { result } = await createCartWorkflow(container)
* .run({
* input: {
* region_id: "reg_123",
* items: [
* {
* variant_id: "var_123",
* quantity: 1,
* }
* ],
* customer_id: "cus_123",
* additional_data: {
* external_id: "123"
* }
* }
* })
*
* @summary
*
* Create a cart specifying region, items, and more.
*
* @property hooks.validate - This hook is executed before all operations. You can consume this hook to perform any custom validation. If validation fails, you can throw an error to stop the workflow execution.
* @property hooks.cartCreated - This hook is executed after a cart is created. You can consume this hook to perform custom actions on the created cart.
* @property hooks.setPricingContext - This hook is executed after the cart is retrieved and before the line items are created. You can consume this hook to return any custom context useful for the prices retrieval of the variants to be added to the cart.
*
* For example, assuming you have the following custom pricing rule:
*
* ```json
* {
* "attribute": "location_id",
* "operator": "eq",
* "value": "sloc_123",
* }
* ```
*
* You can consume the `setPricingContext` hook to add the `location_id` context to the prices calculation:
*
* ```ts
* import { createCartWorkflow } from "@medusajs/medusa/core-flows";
* import { StepResponse } from "@medusajs/workflows-sdk";
*
* createCartWorkflow.hooks.setPricingContext((
* { region, variantIds, salesChannel, customerData, additional_data }, { container }
* ) => {
* return new StepResponse({
* location_id: "sloc_123", // Special price for in-store purchases
* });
* });
* ```
*
* The variants' prices will now be retrieved using the context you return.
*
* :::note
*
* Learn more about prices calculation context in the [Prices Calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation) documentation.
*
* :::
*/
exports.createCartWorkflow = (0, workflows_sdk_1.createWorkflow)(exports.createCartWorkflowId, (input) => {
const variantIds = (0, workflows_sdk_1.transform)({ input }, (data) => {
return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean);
});
const [salesChannel, region, customerData] = (0, workflows_sdk_1.parallelize)((0, steps_1.findSalesChannelStep)({
salesChannelId: input.sales_channel_id,
}), (0, steps_1.findOneOrAnyRegionStep)({
regionId: input.region_id,
}), (0, steps_1.findOrCreateCustomerStep)({
customerId: input.customer_id,
email: input.email,
}));
(0, validate_sales_channel_1.validateSalesChannelStep)({ salesChannel });
const setPricingContext = (0, workflows_sdk_1.createHook)("setPricingContext", {
region,
variantIds,
salesChannel,
customerData,
additional_data: input.additional_data,
}, {
resultValidator: schemas_1.pricingContextResult,
});
const setPricingContextResult = setPricingContext.getResult();
// TODO: This is on par with the context used in v1.*, but we can be more flexible.
const pricingContext = (0, workflows_sdk_1.transform)({ input, region, customerData, setPricingContextResult }, (data) => {
if (!data.region) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "No regions found");
}
return {
...(data.setPricingContextResult ? data.setPricingContextResult : {}),
currency_code: data.input.currency_code ?? data.region.currency_code,
region_id: data.region.id,
customer_id: data.customerData.customer?.id,
};
});
const variants = (0, workflows_sdk_1.when)({ variantIds }, ({ variantIds }) => {
return !!variantIds.length;
}).then(() => {
return (0, use_remote_query_1.useRemoteQueryStep)({
entry_point: "variants",
fields: fields_1.productVariantsFields,
variables: {
id: variantIds,
calculated_price: {
context: pricingContext,
},
},
});
});
(0, validate_variant_prices_1.validateVariantPricesStep)({ variants });
confirm_variant_inventory_1.confirmVariantInventoryWorkflow.runAsStep({
input: {
sales_channel_id: salesChannel.id,
variants,
items: input.items,
},
});
const cartInput = (0, workflows_sdk_1.transform)({ input, region, customerData, salesChannel }, (data) => {
if (!data.region) {
throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "No regions found");
}
const data_ = {
...data.input,
currency_code: data.input.currency_code ?? data.region.currency_code,
region_id: data.region.id,
};
if (data.customerData.customer?.id) {
data_.customer_id = data.customerData.customer.id;
data_.email = data.input?.email ?? data.customerData.customer.email;
}
data_.sales_channel_id = data.salesChannel.id;
// If there is only one country in the region, we prepare a shipping address with that country's code.
if (!data.input.shipping_address &&
data.region.countries.length === 1) {
data_.shipping_address = {
country_code: data.region.countries[0].iso_2,
};
}
return data_;
});
const lineItems = (0, workflows_sdk_1.transform)({ input, variants }, (data) => {
const items = (data.input.items ?? []).map((item) => {
const variant = (data.variants ?? []).find((v) => v.id === item.variant_id);
const input = {
item,
variant: variant,
unitPrice: item.unit_price,
isTaxInclusive: item.is_tax_inclusive ??
variant?.calculated_price?.is_calculated_price_tax_inclusive,
isCustomPrice: (0, utils_1.isDefined)(item?.unit_price),
};
if (variant && !input.unitPrice) {
input.unitPrice = variant.calculated_price?.calculated_amount;
}
return (0, prepare_line_item_data_1.prepareLineItemData)(input);
});
return items;
});
(0, validate_line_item_prices_1.validateLineItemPricesStep)({ items: lineItems });
const cartToCreate = (0, workflows_sdk_1.transform)({ lineItems, cartInput }, (data) => {
return {
...data.cartInput,
items: data.lineItems,
};
});
const validate = (0, workflows_sdk_1.createHook)("validate", {
input: cartInput,
cart: cartToCreate,
});
const carts = (0, steps_1.createCartsStep)([cartToCreate]);
const cart = (0, workflows_sdk_1.transform)({ carts }, (data) => data.carts?.[0]);
update_tax_lines_1.updateTaxLinesWorkflow.runAsStep({
input: {
cart_id: cart.id,
},
});
update_cart_promotions_1.updateCartPromotionsWorkflow.runAsStep({
input: {
cart_id: cart.id,
promo_codes: input.promo_codes,
},
});
(0, workflows_sdk_1.parallelize)(refresh_payment_collection_1.refreshPaymentCollectionForCartWorkflow.runAsStep({
input: {
cart_id: cart.id,
},
}), (0, emit_event_1.emitEventStep)({
eventName: utils_1.CartWorkflowEvents.CREATED,
data: { id: cart.id },
}));
const cartCreated = (0, workflows_sdk_1.createHook)("cartCreated", {
cart,
additional_data: input.additional_data,
});
return new workflows_sdk_1.WorkflowResponse(cart, {
hooks: [validate, cartCreated, setPricingContext],
});
});
//# sourceMappingURL=create-carts.js.map
;