feat(medusa,workflows) Create cart workflow (#4685)
* chore: add baseline test for create cart * chore: add basic paths into handlers + make first tests pass * chore: move input alias to cart specific workflow * chore: move data around into buckets * chore: normalize handlers and introduce types * chore: move aliases to handlers concern * chore: add compensation step for create cart * chore: merge with latest develop * chore: handle error manually + type inputs * chore: handle error manually * chore: added types for each handler * chore: remove addresses * chore: added changset * chore: undo package changes * chore: added config settings to retreieve, cleanup of types * chore: capitalize cart handlers * chore: rename todo * chore: add feature flag for workflow * chore: reorder handlers * chore: add logger to route handler * chore: removed weird vscode moving around things * chore: refactor handlers * chore: refactor compensate step * chore: changed poistion * chore: aggregate config data * chore: moved handlers to their own domain + pr review addressing * chore: address pr reviews * chore: move types to type package * chore: update type to include config * chore: remove error scoping
This commit is contained in:
238
packages/workflows/src/definition/cart/create-cart.ts
Normal file
238
packages/workflows/src/definition/cart/create-cart.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import {
|
||||
TransactionStepsDefinition,
|
||||
WorkflowManager,
|
||||
} from "@medusajs/orchestration"
|
||||
import { CartWorkflow } from "@medusajs/types"
|
||||
|
||||
import { Workflows } from "../../definitions"
|
||||
import {
|
||||
AddressHandlers,
|
||||
CartHandlers,
|
||||
CommonHandlers,
|
||||
CustomerHandlers,
|
||||
RegionHandlers,
|
||||
SalesChannelHandlers,
|
||||
} from "../../handlers"
|
||||
import { aggregateData, exportWorkflow, pipe } from "../../helper"
|
||||
|
||||
enum CreateCartActions {
|
||||
setConfig = "setConfig",
|
||||
setContext = "setContext",
|
||||
attachLineItems = "attachLineItems",
|
||||
findRegion = "findRegion",
|
||||
findSalesChannel = "findSalesChannel",
|
||||
createCart = "createCart",
|
||||
findOrCreateAddresses = "findOrCreateAddresses",
|
||||
findOrCreateCustomer = "findOrCreateCustomer",
|
||||
removeCart = "removeCart",
|
||||
removeAddresses = "removeAddresses",
|
||||
retrieveCart = "retrieveCart",
|
||||
}
|
||||
|
||||
const workflowAlias = "cart"
|
||||
const getWorkflowInput = (alias = workflowAlias) => ({
|
||||
inputAlias: workflowAlias,
|
||||
invoke: {
|
||||
from: workflowAlias,
|
||||
alias,
|
||||
},
|
||||
})
|
||||
|
||||
const workflowSteps: TransactionStepsDefinition = {
|
||||
next: [
|
||||
{
|
||||
action: CreateCartActions.setConfig,
|
||||
noCompensation: true,
|
||||
},
|
||||
{
|
||||
action: CreateCartActions.findOrCreateCustomer,
|
||||
noCompensation: true,
|
||||
},
|
||||
{
|
||||
action: CreateCartActions.findSalesChannel,
|
||||
noCompensation: true,
|
||||
},
|
||||
{
|
||||
action: CreateCartActions.setContext,
|
||||
noCompensation: true,
|
||||
},
|
||||
{
|
||||
action: CreateCartActions.findRegion,
|
||||
noCompensation: true,
|
||||
next: {
|
||||
action: CreateCartActions.findOrCreateAddresses,
|
||||
noCompensation: true,
|
||||
next: {
|
||||
action: CreateCartActions.createCart,
|
||||
next: {
|
||||
action: CreateCartActions.attachLineItems,
|
||||
noCompensation: true,
|
||||
next: {
|
||||
action: CreateCartActions.retrieveCart,
|
||||
noCompensation: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const handlers = new Map([
|
||||
[
|
||||
CreateCartActions.setConfig,
|
||||
{
|
||||
invoke: pipe(
|
||||
getWorkflowInput(CommonHandlers.setConfig.aliases.Config),
|
||||
aggregateData(),
|
||||
CommonHandlers.setConfig
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.findOrCreateCustomer,
|
||||
{
|
||||
invoke: pipe(
|
||||
getWorkflowInput(
|
||||
CustomerHandlers.findOrCreateCustomer.aliases.Customer
|
||||
),
|
||||
CustomerHandlers.findOrCreateCustomer
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.findSalesChannel,
|
||||
{
|
||||
invoke: pipe(
|
||||
getWorkflowInput(
|
||||
SalesChannelHandlers.findSalesChannel.aliases.SalesChannel
|
||||
),
|
||||
SalesChannelHandlers.findSalesChannel
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.setContext,
|
||||
{
|
||||
invoke: pipe(
|
||||
getWorkflowInput(CommonHandlers.setContext.aliases.Context),
|
||||
CommonHandlers.setContext
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.findRegion,
|
||||
{
|
||||
invoke: pipe(
|
||||
getWorkflowInput(RegionHandlers.findRegion.aliases.Region),
|
||||
RegionHandlers.findRegion
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.findOrCreateAddresses,
|
||||
{
|
||||
invoke: pipe(
|
||||
{
|
||||
invoke: [
|
||||
getWorkflowInput(
|
||||
AddressHandlers.findOrCreateAddresses.aliases.Addresses
|
||||
).invoke,
|
||||
{
|
||||
from: CreateCartActions.findRegion,
|
||||
alias: AddressHandlers.findOrCreateAddresses.aliases.Region,
|
||||
},
|
||||
],
|
||||
},
|
||||
AddressHandlers.findOrCreateAddresses
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.createCart,
|
||||
{
|
||||
invoke: pipe(
|
||||
{
|
||||
invoke: [
|
||||
{
|
||||
from: CreateCartActions.findRegion,
|
||||
alias: CartHandlers.createCart.aliases.Region,
|
||||
},
|
||||
{
|
||||
from: CreateCartActions.setContext,
|
||||
alias: CartHandlers.createCart.aliases.Context,
|
||||
},
|
||||
{
|
||||
from: CreateCartActions.findOrCreateCustomer,
|
||||
alias: CartHandlers.createCart.aliases.Customer,
|
||||
},
|
||||
{
|
||||
from: CreateCartActions.findOrCreateAddresses,
|
||||
alias: CartHandlers.createCart.aliases.Addresses,
|
||||
},
|
||||
],
|
||||
},
|
||||
CartHandlers.createCart
|
||||
),
|
||||
compensate: pipe(
|
||||
{
|
||||
invoke: [
|
||||
{
|
||||
from: CreateCartActions.createCart,
|
||||
alias: CartHandlers.removeCart.aliases.Cart,
|
||||
},
|
||||
],
|
||||
},
|
||||
CartHandlers.removeCart
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.attachLineItems,
|
||||
{
|
||||
invoke: pipe(
|
||||
{
|
||||
invoke: [
|
||||
getWorkflowInput(
|
||||
CartHandlers.attachLineItemsToCart.aliases.LineItems
|
||||
).invoke,
|
||||
{
|
||||
from: CreateCartActions.createCart,
|
||||
alias: CartHandlers.attachLineItemsToCart.aliases.Cart,
|
||||
},
|
||||
],
|
||||
},
|
||||
CartHandlers.attachLineItemsToCart
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
CreateCartActions.retrieveCart,
|
||||
{
|
||||
invoke: pipe(
|
||||
{
|
||||
invoke: [
|
||||
{
|
||||
from: CreateCartActions.setConfig,
|
||||
alias: CommonHandlers.setConfig.aliases.Config,
|
||||
},
|
||||
{
|
||||
from: CreateCartActions.createCart,
|
||||
alias: CartHandlers.retrieveCart.aliases.Cart,
|
||||
},
|
||||
],
|
||||
},
|
||||
CartHandlers.retrieveCart
|
||||
),
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
WorkflowManager.register(Workflows.CreateCart, workflowSteps, handlers)
|
||||
|
||||
type CreateCartWorkflowOutput = Record<any, any>
|
||||
|
||||
export const createCart = exportWorkflow<
|
||||
CartWorkflow.CreateCartWorkflowInputDTO,
|
||||
CreateCartWorkflowOutput
|
||||
>(Workflows.CreateCart, CreateCartActions.retrieveCart)
|
||||
1
packages/workflows/src/definition/cart/index.ts
Normal file
1
packages/workflows/src/definition/cart/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./create-cart"
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./create-products"
|
||||
export * from "./cart"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export enum Workflows {
|
||||
// Product workflows
|
||||
CreateProducts = "create-products",
|
||||
|
||||
// Cart workflows
|
||||
CreateCart = "create-cart",
|
||||
}
|
||||
|
||||
export enum InputAlias {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import { AddressDTO } from "@medusajs/types"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type AddressesDTO = {
|
||||
shipping_address_id?: string
|
||||
billing_address_id?: string
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
addresses: AddressesDTO & {
|
||||
billing_address?: AddressDTO
|
||||
shipping_address?: AddressDTO
|
||||
}
|
||||
region: {
|
||||
region_id?: string
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
Addresses = "addresses",
|
||||
Region = "region",
|
||||
}
|
||||
|
||||
export async function findOrCreateAddresses({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<AddressesDTO> {
|
||||
const regionService = container.resolve("regionService")
|
||||
const addressRepository = container.resolve("addressRepository")
|
||||
|
||||
const shippingAddress = data[Aliases.Addresses].shipping_address
|
||||
const shippingAddressId = data[Aliases.Addresses].shipping_address_id
|
||||
const billingAddress = data[Aliases.Addresses].billing_address
|
||||
const billingAddressId = data[Aliases.Addresses].billing_address_id
|
||||
const addressesDTO: AddressesDTO = {}
|
||||
|
||||
const region = await regionService.retrieve(data[Aliases.Region].region_id, {
|
||||
relations: ["countries"],
|
||||
})
|
||||
|
||||
const regionCountries = region.countries.map(({ iso_2 }) => iso_2)
|
||||
|
||||
if (!shippingAddress && !shippingAddressId) {
|
||||
if (region.countries.length === 1) {
|
||||
const shippingAddress = addressRepository.create({
|
||||
country_code: regionCountries[0],
|
||||
})
|
||||
|
||||
addressesDTO.shipping_address_id = shippingAddress?.id
|
||||
}
|
||||
} else {
|
||||
if (shippingAddress) {
|
||||
if (!regionCountries.includes(shippingAddress.country_code!)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Shipping country not in region"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (shippingAddressId) {
|
||||
const address = await regionService.findOne({
|
||||
where: { id: shippingAddressId },
|
||||
})
|
||||
|
||||
if (
|
||||
address?.country_code &&
|
||||
!regionCountries.includes(address.country_code)
|
||||
) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Shipping country not in region"
|
||||
)
|
||||
}
|
||||
|
||||
addressesDTO.shipping_address_id = address.id
|
||||
}
|
||||
}
|
||||
|
||||
if (billingAddress) {
|
||||
if (!regionCountries.includes(billingAddress.country_code!)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Billing country not in region"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (billingAddressId) {
|
||||
const address = await regionService.findOne({
|
||||
where: { id: billingAddressId },
|
||||
})
|
||||
|
||||
if (
|
||||
address?.country_code &&
|
||||
!regionCountries.includes(address.country_code)
|
||||
) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Billing country not in region"
|
||||
)
|
||||
}
|
||||
|
||||
addressesDTO.billing_address_id = billingAddressId
|
||||
}
|
||||
|
||||
return addressesDTO
|
||||
}
|
||||
|
||||
findOrCreateAddresses.aliases = Aliases
|
||||
1
packages/workflows/src/handlers/address/index.ts
Normal file
1
packages/workflows/src/handlers/address/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./find-or-create-addresses"
|
||||
@@ -0,0 +1,57 @@
|
||||
import { CartWorkflow } from "@medusajs/types"
|
||||
import { SalesChannelFeatureFlag } from "@medusajs/utils"
|
||||
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type HandlerInputData = {
|
||||
line_items: {
|
||||
items?: CartWorkflow.CreateLineItemInputDTO[]
|
||||
}
|
||||
cart: {
|
||||
id: string
|
||||
customer_id: string
|
||||
region_id: string
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
LineItems = "line_items",
|
||||
Cart = "cart",
|
||||
}
|
||||
|
||||
export async function attachLineItemsToCart({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<void> {
|
||||
const { manager } = context
|
||||
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const lineItemService = container.resolve("lineItemService")
|
||||
const cartService = container.resolve("cartService")
|
||||
|
||||
const lineItemServiceTx = lineItemService.withTransaction(manager)
|
||||
const cartServiceTx = cartService.withTransaction(manager)
|
||||
let lineItems = data[Aliases.LineItems].items
|
||||
const cart = data[Aliases.Cart]
|
||||
|
||||
if (lineItems?.length) {
|
||||
const generateInputData = lineItems.map((item) => ({
|
||||
variantId: item.variant_id,
|
||||
quantity: item.quantity,
|
||||
}))
|
||||
|
||||
lineItems = await lineItemServiceTx.generate(generateInputData, {
|
||||
region_id: cart.region_id,
|
||||
customer_id: cart.customer_id,
|
||||
})
|
||||
|
||||
await cartServiceTx.addOrUpdateLineItems(cart.id, lineItems, {
|
||||
validateSalesChannels: featureFlagRouter.isFeatureEnabled(
|
||||
SalesChannelFeatureFlag.key
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
attachLineItemsToCart.aliases = Aliases
|
||||
57
packages/workflows/src/handlers/cart/create-cart.ts
Normal file
57
packages/workflows/src/handlers/cart/create-cart.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { CartDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
enum Aliases {
|
||||
SalesChannel = "SalesChannel",
|
||||
Addresses = "addresses",
|
||||
Customer = "customer",
|
||||
Region = "region",
|
||||
Context = "context",
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
sales_channel: {
|
||||
sales_channel_id?: string
|
||||
}
|
||||
addresses: {
|
||||
shipping_address_id: string
|
||||
billing_address_id: string
|
||||
}
|
||||
customer: {
|
||||
customer_id?: string
|
||||
email?: string
|
||||
}
|
||||
region: {
|
||||
region_id: string
|
||||
}
|
||||
context: {
|
||||
context: Record<any, any>
|
||||
}
|
||||
}
|
||||
|
||||
type HandlerOutputData = {
|
||||
cart: CartDTO
|
||||
}
|
||||
|
||||
export async function createCart({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<HandlerOutputData> {
|
||||
const { manager } = context
|
||||
|
||||
const cartService = container.resolve("cartService")
|
||||
const cartServiceTx = cartService.withTransaction(manager)
|
||||
|
||||
const cart = await cartServiceTx.create({
|
||||
...data[Aliases.SalesChannel],
|
||||
...data[Aliases.Addresses],
|
||||
...data[Aliases.Customer],
|
||||
...data[Aliases.Region],
|
||||
...data[Aliases.Context],
|
||||
})
|
||||
|
||||
return cart
|
||||
}
|
||||
|
||||
createCart.aliases = Aliases
|
||||
4
packages/workflows/src/handlers/cart/index.ts
Normal file
4
packages/workflows/src/handlers/cart/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./attach-line-items-to-cart"
|
||||
export * from "./create-cart"
|
||||
export * from "./remove-cart"
|
||||
export * from "./retrieve-cart"
|
||||
28
packages/workflows/src/handlers/cart/remove-cart.ts
Normal file
28
packages/workflows/src/handlers/cart/remove-cart.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
enum Aliases {
|
||||
Cart = "cart",
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
cart: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeCart({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<void> {
|
||||
const { manager } = context
|
||||
|
||||
const cartService = container.resolve("cartService")
|
||||
|
||||
const cartServiceTx = cartService.withTransaction(manager)
|
||||
const cart = data[Aliases.Cart]
|
||||
|
||||
await cartServiceTx.delete(cart.id)
|
||||
}
|
||||
|
||||
removeCart.aliases = Aliases
|
||||
40
packages/workflows/src/handlers/cart/retrieve-cart.ts
Normal file
40
packages/workflows/src/handlers/cart/retrieve-cart.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { CartDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type HandlerInputData = {
|
||||
cart: {
|
||||
id: string
|
||||
}
|
||||
config: {
|
||||
retrieveConfig: {
|
||||
select: string[]
|
||||
relations: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
Cart = "cart",
|
||||
Config = "config",
|
||||
}
|
||||
|
||||
export async function retrieveCart({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<CartDTO> {
|
||||
const { manager } = context
|
||||
|
||||
const cartService = container.resolve("cartService")
|
||||
|
||||
const cartServiceTx = cartService.withTransaction(manager)
|
||||
|
||||
const retrieved = await cartServiceTx.retrieve(
|
||||
data[Aliases.Cart].id,
|
||||
data[Aliases.Config].retrieveConfig
|
||||
)
|
||||
|
||||
return retrieved
|
||||
}
|
||||
|
||||
retrieveCart.aliases = Aliases
|
||||
2
packages/workflows/src/handlers/common/index.ts
Normal file
2
packages/workflows/src/handlers/common/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./set-config"
|
||||
export * from "./set-context"
|
||||
31
packages/workflows/src/handlers/common/set-config.ts
Normal file
31
packages/workflows/src/handlers/common/set-config.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type ConfigDTO = {
|
||||
retrieveConfig?: {
|
||||
select?: string[]
|
||||
relations?: string[]
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
Config = "config",
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
config: {
|
||||
retrieveConfig?: {
|
||||
select?: string[]
|
||||
relations?: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function setConfig({
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<ConfigDTO> {
|
||||
return {
|
||||
retrieveConfig: data[Aliases.Config].retrieveConfig,
|
||||
}
|
||||
}
|
||||
|
||||
setConfig.aliases = Aliases
|
||||
27
packages/workflows/src/handlers/common/set-context.ts
Normal file
27
packages/workflows/src/handlers/common/set-context.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type ContextDTO = {
|
||||
context?: Record<any, any>
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
Context = "context",
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
context: {
|
||||
context?: Record<any, any>
|
||||
}
|
||||
}
|
||||
|
||||
export async function setContext({
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<ContextDTO> {
|
||||
const contextDTO: ContextDTO = {
|
||||
context: data[Aliases.Context].context,
|
||||
}
|
||||
|
||||
return contextDTO
|
||||
}
|
||||
|
||||
setContext.aliases = Aliases
|
||||
@@ -0,0 +1,63 @@
|
||||
import { validateEmail } from "@medusajs/utils"
|
||||
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type CustomerDTO = {
|
||||
customer_id?: string
|
||||
email?: string
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
customer: {
|
||||
customer_id?: string
|
||||
email?: string
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
Customer = "customer",
|
||||
}
|
||||
|
||||
export async function findOrCreateCustomer({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<CustomerDTO> {
|
||||
const { manager } = context
|
||||
|
||||
const customerService = container.resolve("customerService")
|
||||
|
||||
const customerDTO: CustomerDTO = {}
|
||||
const customerId = data[Aliases.Customer].customer_id
|
||||
const customerServiceTx = customerService.withTransaction(manager)
|
||||
|
||||
if (customerId) {
|
||||
const customer = await customerServiceTx
|
||||
.retrieve(customerId)
|
||||
.catch(() => undefined)
|
||||
|
||||
customerDTO.customer_id = customer?.id
|
||||
customerDTO.email = customer?.email
|
||||
}
|
||||
|
||||
const customerEmail = data[Aliases.Customer].email
|
||||
|
||||
if (customerEmail) {
|
||||
const validatedEmail = validateEmail(customerEmail)
|
||||
|
||||
let customer = await customerServiceTx
|
||||
.retrieveUnregisteredByEmail(validatedEmail)
|
||||
.catch(() => undefined)
|
||||
|
||||
if (!customer) {
|
||||
customer = await customerServiceTx.create({ email: validatedEmail })
|
||||
}
|
||||
|
||||
customerDTO.customer_id = customer.id
|
||||
customerDTO.email = customer.email
|
||||
}
|
||||
|
||||
return customerDTO
|
||||
}
|
||||
|
||||
findOrCreateCustomer.aliases = Aliases
|
||||
1
packages/workflows/src/handlers/customer/index.ts
Normal file
1
packages/workflows/src/handlers/customer/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./find-or-create-customer"
|
||||
@@ -1,3 +1,9 @@
|
||||
export * as ProductHandlers from "./product"
|
||||
export * as AddressHandlers from "./address"
|
||||
export * as CartHandlers from "./cart"
|
||||
export * as CommonHandlers from "./common"
|
||||
export * as CustomerHandlers from "./customer"
|
||||
export * as InventoryHandlers from "./inventory"
|
||||
export * as MiddlewaresHandlers from "./middlewares"
|
||||
export * as ProductHandlers from "./product"
|
||||
export * as RegionHandlers from "./region"
|
||||
export * as SalesChannelHandlers from "./sales-channel"
|
||||
|
||||
49
packages/workflows/src/handlers/region/find-region.ts
Normal file
49
packages/workflows/src/handlers/region/find-region.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { isDefined } from "medusa-core-utils"
|
||||
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type RegionDTO = {
|
||||
region_id?: string
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
region: {
|
||||
region_id: string
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
Region = "region",
|
||||
}
|
||||
|
||||
export async function findRegion({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<RegionDTO> {
|
||||
const regionService = container.resolve("regionService")
|
||||
|
||||
let regionId: string
|
||||
const regionDTO: RegionDTO = {}
|
||||
|
||||
if (isDefined(data[Aliases.Region].region_id)) {
|
||||
regionId = data[Aliases.Region].region_id
|
||||
} else {
|
||||
const regions = await regionService.list({}, {})
|
||||
|
||||
if (!regions?.length) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`A region is required to create a cart`
|
||||
)
|
||||
}
|
||||
|
||||
regionId = regions[0].id
|
||||
}
|
||||
|
||||
regionDTO.region_id = regionId
|
||||
|
||||
return regionDTO
|
||||
}
|
||||
|
||||
findRegion.aliases = Aliases
|
||||
1
packages/workflows/src/handlers/region/index.ts
Normal file
1
packages/workflows/src/handlers/region/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./find-region"
|
||||
@@ -0,0 +1,74 @@
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { isDefined } from "medusa-core-utils"
|
||||
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type AttachSalesChannelDTO = {
|
||||
sales_channel_id?: string
|
||||
}
|
||||
|
||||
type HandlerInputData = {
|
||||
sales_channel: {
|
||||
sales_channel_id?: string
|
||||
publishableApiKeyScopes?: {
|
||||
sales_channel_ids?: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Aliases {
|
||||
SalesChannel = "sales_channel",
|
||||
}
|
||||
|
||||
export async function findSalesChannel({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInputData>): Promise<AttachSalesChannelDTO> {
|
||||
const salesChannelService = container.resolve("salesChannelService")
|
||||
const storeService = container.resolve("storeService")
|
||||
|
||||
let salesChannelId = data[Aliases.SalesChannel].sales_channel_id
|
||||
let salesChannel
|
||||
const salesChannelDTO: AttachSalesChannelDTO = {}
|
||||
const publishableApiKeyScopes =
|
||||
data[Aliases.SalesChannel].publishableApiKeyScopes || {}
|
||||
|
||||
delete data[Aliases.SalesChannel].publishableApiKeyScopes
|
||||
|
||||
if (
|
||||
!isDefined(salesChannelId) &&
|
||||
publishableApiKeyScopes?.sales_channel_ids?.length
|
||||
) {
|
||||
if (publishableApiKeyScopes.sales_channel_ids.length > 1) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNEXPECTED_STATE,
|
||||
"The provided PublishableApiKey has multiple associated sales channels."
|
||||
)
|
||||
}
|
||||
|
||||
salesChannelId = publishableApiKeyScopes.sales_channel_ids[0]
|
||||
}
|
||||
|
||||
if (isDefined(salesChannelId)) {
|
||||
salesChannel = await salesChannelService.retrieve(salesChannelId)
|
||||
} else {
|
||||
salesChannel = (
|
||||
await storeService.retrieve({
|
||||
relations: ["default_sales_channel"],
|
||||
})
|
||||
).default_sales_channel
|
||||
}
|
||||
|
||||
if (salesChannel.is_disabled) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Unable to assign the cart to a disabled Sales Channel "${salesChannel.name}"`
|
||||
)
|
||||
}
|
||||
|
||||
salesChannelDTO.sales_channel_id = salesChannel?.id
|
||||
|
||||
return salesChannelDTO
|
||||
}
|
||||
|
||||
findSalesChannel.aliases = Aliases
|
||||
1
packages/workflows/src/handlers/sales-channel/index.ts
Normal file
1
packages/workflows/src/handlers/sales-channel/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./find-sales-channel"
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./aggregate"
|
||||
export * from "./empty-handler"
|
||||
export * from "./pipe"
|
||||
export * from "./workflow-export"
|
||||
|
||||
Reference in New Issue
Block a user