chore(workflows, core-flows): Split workflows tooling and definitions (#5705)
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import { AddressDTO } from "@medusajs/types"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -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 "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -0,0 +1,57 @@
|
||||
import { CartDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./attach-line-items-to-cart"
|
||||
export * from "./create-cart"
|
||||
export * from "./remove-cart"
|
||||
export * from "./retrieve-cart"
|
||||
@@ -0,0 +1,28 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -0,0 +1,40 @@
|
||||
import { CartDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./set-context"
|
||||
@@ -0,0 +1,27 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
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 "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./find-or-create-customer"
|
||||
@@ -0,0 +1,10 @@
|
||||
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 PriceListHandlers from "./price-list"
|
||||
export * as ProductHandlers from "./product"
|
||||
export * as RegionHandlers from "./region"
|
||||
export * as SalesChannelHandlers from "./sales-channel"
|
||||
@@ -0,0 +1,35 @@
|
||||
import { InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
export async function attachInventoryItems({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: {
|
||||
tag: string
|
||||
inventoryItem: InventoryItemDTO
|
||||
}[]
|
||||
}>) {
|
||||
const { manager } = context
|
||||
const productVariantInventoryService = container
|
||||
.resolve("productVariantInventoryService")
|
||||
.withTransaction(manager)
|
||||
|
||||
if (!data?.inventoryItems?.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const inventoryData = data.inventoryItems.map(({ tag, inventoryItem }) => ({
|
||||
variantId: tag,
|
||||
inventoryItemId: inventoryItem.id,
|
||||
}))
|
||||
|
||||
await productVariantInventoryService.attachInventoryItem(inventoryData)
|
||||
|
||||
return data.inventoryItems
|
||||
}
|
||||
|
||||
attachInventoryItems.aliases = {
|
||||
inventoryItems: "inventoryItems",
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { IInventoryService, InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
type Result = {
|
||||
tag: string
|
||||
inventoryItem: InventoryItemDTO
|
||||
}[]
|
||||
|
||||
export async function createInventoryItems({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: (InventoryItemDTO & { _associationTag?: string })[]
|
||||
}>): Promise<Result | void> {
|
||||
const inventoryService: IInventoryService =
|
||||
container.resolve("inventoryService")
|
||||
|
||||
if (!inventoryService) {
|
||||
const logger = container.resolve("logger")
|
||||
logger.warn(
|
||||
`Inventory service not found. You should install the @medusajs/inventory package to use inventory. The 'createInventoryItems' will be skipped.`
|
||||
)
|
||||
return void 0
|
||||
}
|
||||
|
||||
return await promiseAll(
|
||||
data.inventoryItems.map(async (item) => {
|
||||
const inventoryItem = await inventoryService!.createInventoryItem({
|
||||
sku: item.sku!,
|
||||
origin_country: item.origin_country!,
|
||||
hs_code: item.hs_code!,
|
||||
mid_code: item.mid_code!,
|
||||
material: item.material!,
|
||||
weight: item.weight!,
|
||||
length: item.length!,
|
||||
height: item.height!,
|
||||
width: item.width!,
|
||||
})
|
||||
|
||||
return { tag: item._associationTag ?? inventoryItem.id, inventoryItem }
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
createInventoryItems.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
export async function detachInventoryItems({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: {
|
||||
tag: string
|
||||
inventoryItem: InventoryItemDTO
|
||||
}[]
|
||||
}>) {
|
||||
const { manager } = context
|
||||
|
||||
const productVariantInventoryService = container
|
||||
.resolve("productVariantInventoryService")
|
||||
.withTransaction(manager)
|
||||
|
||||
if (!data?.inventoryItems?.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
await promiseAll(
|
||||
data.inventoryItems.map(async ({ tag, inventoryItem }) => {
|
||||
return await productVariantInventoryService.detachInventoryItem(
|
||||
inventoryItem.id,
|
||||
tag
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
return data.inventoryItems
|
||||
}
|
||||
|
||||
detachInventoryItems.aliases = {
|
||||
inventoryItems: "inventoryItems",
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./detach-inventory-items"
|
||||
export * from "./attach-inventory-items"
|
||||
export * from "./create-inventory-items"
|
||||
export * from "./remove-inventory-items"
|
||||
export * from "./restore-inventory-items"
|
||||
@@ -0,0 +1,29 @@
|
||||
import { InventoryItemDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
export async function removeInventoryItems({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: { inventoryItem: InventoryItemDTO }[]
|
||||
}>) {
|
||||
const inventoryService = container.resolve("inventoryService")
|
||||
|
||||
if (!inventoryService) {
|
||||
const logger = container.resolve("logger")
|
||||
logger.warn(
|
||||
`Inventory service not found. You should install the @medusajs/inventory package to use inventory. The 'removeInventoryItems' will be skipped.`
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
await inventoryService!.deleteInventoryItem(
|
||||
data.inventoryItems.map(({ inventoryItem }) => inventoryItem.id)
|
||||
)
|
||||
|
||||
return data.inventoryItems
|
||||
}
|
||||
|
||||
removeInventoryItems.aliases = {
|
||||
inventoryItems: "inventoryItems",
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import {
|
||||
IInventoryService,
|
||||
InventoryItemDTO,
|
||||
SharedContext,
|
||||
} from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
export async function restoreInventoryItems({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
inventoryItems: { inventoryItem: InventoryItemDTO }[]
|
||||
}>) {
|
||||
const { manager } = context as SharedContext
|
||||
const inventoryService: IInventoryService =
|
||||
container.resolve("inventoryService")
|
||||
|
||||
if (!inventoryService) {
|
||||
const logger = container.resolve("logger")
|
||||
logger.warn(
|
||||
`Inventory service not found. You should install the @medusajs/inventory package to use inventory. The 'removeInventoryItems' will be skipped.`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
return await inventoryService!.restoreInventoryItem(
|
||||
data.inventoryItems.map(({ inventoryItem }) => inventoryItem.id),
|
||||
{ transactionManager: manager }
|
||||
)
|
||||
}
|
||||
|
||||
restoreInventoryItems.aliases = {
|
||||
inventoryItems: "inventoryItems",
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
import { ProductTypes, WorkflowTypes } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type ProductHandle = string
|
||||
type VariantIndexAndPrices = {
|
||||
index: number
|
||||
prices: WorkflowTypes.ProductWorkflow.CreateProductVariantPricesInputDTO[]
|
||||
}
|
||||
|
||||
export async function createProductsPrepareCreatePricesCompensation({
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
preparedData: {
|
||||
productsHandleVariantsIndexPricesMap: Map<
|
||||
ProductHandle,
|
||||
VariantIndexAndPrices[]
|
||||
>
|
||||
}
|
||||
products: ProductTypes.ProductDTO[]
|
||||
}>) {
|
||||
const productsHandleVariantsIndexPricesMap =
|
||||
data.preparedData.productsHandleVariantsIndexPricesMap
|
||||
const products = data.products
|
||||
|
||||
const updatedProductsHandleVariantsIndexPricesMap = new Map()
|
||||
productsHandleVariantsIndexPricesMap.forEach(
|
||||
(existingItems, productHandle) => {
|
||||
const items =
|
||||
updatedProductsHandleVariantsIndexPricesMap.get(productHandle) ?? []
|
||||
|
||||
existingItems.forEach(({ index }) => {
|
||||
items.push({
|
||||
index,
|
||||
prices: [],
|
||||
})
|
||||
})
|
||||
|
||||
updatedProductsHandleVariantsIndexPricesMap.set(productHandle, items)
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
alias: createProductsPrepareCreatePricesCompensation.aliases.output,
|
||||
value: {
|
||||
productsHandleVariantsIndexPricesMap:
|
||||
updatedProductsHandleVariantsIndexPricesMap,
|
||||
products,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
createProductsPrepareCreatePricesCompensation.aliases = {
|
||||
preparedData: "preparedData",
|
||||
output: "createProductsPrepareCreatePricesCompensationOutput",
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
export async function extractVariants({
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
object: { variants?: ProductTypes.ProductVariantDTO[] }[]
|
||||
}>) {
|
||||
const variants = data.object.reduce((acc, object) => {
|
||||
if (object.variants?.length) {
|
||||
return acc.concat(object.variants)
|
||||
}
|
||||
return acc
|
||||
}, [] as ProductTypes.ProductVariantDTO[])
|
||||
|
||||
return {
|
||||
alias: extractVariants.aliases.output,
|
||||
value: {
|
||||
variants,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
extractVariants.aliases = {
|
||||
output: "extractVariantsFromProductOutput",
|
||||
object: "object",
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from "./create-products-prepare-create-prices-compensation"
|
||||
export * from "./update-products-extract-created-variants"
|
||||
export * from "./update-products-extract-deleted-variants"
|
||||
export * from "./use-variants-inventory-items"
|
||||
export * from "./extract-variants"
|
||||
export * from "./map-data"
|
||||
@@ -0,0 +1,16 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
/**
|
||||
* Middleware for map input data to a key/s.
|
||||
*
|
||||
* @param mapFn - apply function on the input data and return result as the middleware output
|
||||
* @param alias - key to save output under (if `merge === false`)
|
||||
*/
|
||||
export function mapData<T, S>(mapFn: (arg: T) => S, alias = "mapData") {
|
||||
return async function ({ data }: WorkflowArguments<T>) {
|
||||
return {
|
||||
alias,
|
||||
value: mapFn(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import { ProductTypes, ProductVariantDTO } from "@medusajs/types"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { UpdateProductsPreparedData } from "../product"
|
||||
|
||||
export async function updateProductsExtractCreatedVariants({
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
preparedData: UpdateProductsPreparedData // products state before the update
|
||||
products: ProductTypes.ProductDTO[] // updated products
|
||||
}>) {
|
||||
const createdVariants: ProductVariantDTO[] = []
|
||||
|
||||
data.products.forEach((product) => {
|
||||
const addedVariants: ProductVariantDTO[] = []
|
||||
|
||||
const originalProduct = data.preparedData.originalProducts.find(
|
||||
(p) => p.id === product.id
|
||||
)!
|
||||
|
||||
product.variants.forEach((variant) => {
|
||||
if (!originalProduct.variants.find((v) => v.id === variant.id)) {
|
||||
addedVariants.push(variant)
|
||||
}
|
||||
})
|
||||
|
||||
createdVariants.push(...addedVariants)
|
||||
})
|
||||
|
||||
return {
|
||||
alias: updateProductsExtractCreatedVariants.aliases.output,
|
||||
value: [{ variants: createdVariants }],
|
||||
}
|
||||
}
|
||||
|
||||
updateProductsExtractCreatedVariants.aliases = {
|
||||
preparedData: "preparedData",
|
||||
products: "products",
|
||||
output: "products",
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
import { ProductTypes, ProductVariantDTO } from "@medusajs/types"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { UpdateProductsPreparedData } from "../product"
|
||||
|
||||
export async function updateProductsExtractDeletedVariants({
|
||||
data,
|
||||
container,
|
||||
}: WorkflowArguments<{
|
||||
preparedData: UpdateProductsPreparedData // products state before the update
|
||||
products: ProductTypes.ProductDTO[] // updated products
|
||||
}>) {
|
||||
const deletedVariants: ProductVariantDTO[] = []
|
||||
|
||||
data.products.forEach((product) => {
|
||||
const removedVariants: ProductVariantDTO[] = []
|
||||
|
||||
const originalProduct = data.preparedData.originalProducts.find(
|
||||
(p) => p.id === product.id
|
||||
)!
|
||||
|
||||
originalProduct.variants.forEach((variant) => {
|
||||
if (!product.variants.find((v) => v.id === variant.id)) {
|
||||
removedVariants.push(variant)
|
||||
}
|
||||
})
|
||||
|
||||
deletedVariants.push(...removedVariants)
|
||||
})
|
||||
|
||||
return {
|
||||
alias: updateProductsExtractDeletedVariants.aliases.output,
|
||||
value: {
|
||||
variants: deletedVariants,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
updateProductsExtractDeletedVariants.aliases = {
|
||||
preparedData: "preparedData",
|
||||
products: "products",
|
||||
output: "updateProductsExtractDeletedVariantsOutput",
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { IInventoryService, ProductVariantDTO } from "@medusajs/types"
|
||||
|
||||
export async function useVariantsInventoryItems({
|
||||
data,
|
||||
container,
|
||||
}: WorkflowArguments<{
|
||||
updateProductsExtractDeletedVariantsOutput: { variants: ProductVariantDTO[] }
|
||||
}>) {
|
||||
const inventoryService: IInventoryService =
|
||||
container.resolve("inventoryService")
|
||||
|
||||
if (!inventoryService) {
|
||||
const logger = container.resolve("logger")
|
||||
logger.warn(
|
||||
`Inventory service not found. You should install the @medusajs/inventory package to use inventory. The 'useVariantsInventoryItems' will be skipped.`
|
||||
)
|
||||
return {
|
||||
alias: useVariantsInventoryItems.aliases.output,
|
||||
value: null,
|
||||
}
|
||||
}
|
||||
|
||||
const [inventoryItems] = await inventoryService!.listInventoryItems({
|
||||
sku: data.updateProductsExtractDeletedVariantsOutput.variants.map(
|
||||
(v) => v.id
|
||||
),
|
||||
})
|
||||
|
||||
const variantItems = inventoryItems.map((item) => ({
|
||||
inventoryItem: item,
|
||||
tag: data.updateProductsExtractDeletedVariantsOutput.variants.find(
|
||||
(variant) => variant.sku === item.sku
|
||||
)!.id,
|
||||
}))
|
||||
|
||||
return {
|
||||
alias: useVariantsInventoryItems.aliases.output,
|
||||
value: { inventoryItems: variantItems },
|
||||
}
|
||||
}
|
||||
|
||||
useVariantsInventoryItems.aliases = {
|
||||
variants: "variants",
|
||||
output: "useVariantsInventoryItemsOutput",
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
CreatePriceListDTO,
|
||||
IPricingModuleService,
|
||||
PriceListDTO,
|
||||
} from "@medusajs/types"
|
||||
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type Result = {
|
||||
priceList: PriceListDTO
|
||||
}[]
|
||||
|
||||
type Input = {
|
||||
tag?: string
|
||||
priceList: CreatePriceListDTO
|
||||
}[]
|
||||
|
||||
export async function createPriceLists({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
priceLists: Input
|
||||
}>): Promise<Result> {
|
||||
const pricingService: IPricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
return await Promise.all(
|
||||
data.priceLists.map(async (item) => {
|
||||
const [priceList] = await pricingService!.createPriceLists([
|
||||
item.priceList,
|
||||
])
|
||||
|
||||
return { tag: item.tag ?? priceList.id, priceList }
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
createPriceLists.aliases = {
|
||||
priceLists: "priceLists",
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export * from "./create-price-list"
|
||||
export * from "./prepare-create-price-list"
|
||||
export * from "./prepare-update-price-lists"
|
||||
export * from "./remove-price-list"
|
||||
export * from "./update-price-lists"
|
||||
export * from "./prepare-remove-product-prices"
|
||||
export * from "./remove-price-set-price-list-prices"
|
||||
export * from "./prepare-remove-variant-prices"
|
||||
export * from "./prepare-remove-price-list-prices"
|
||||
export * from "./remove-prices"
|
||||
@@ -0,0 +1,87 @@
|
||||
import { CreatePriceListDTO, PriceListWorkflow } from "@medusajs/types"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type Result = {
|
||||
tag?: string
|
||||
priceList: CreatePriceListDTO
|
||||
}[]
|
||||
|
||||
export async function prepareCreatePriceLists({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
price_lists: (PriceListWorkflow.CreatePriceListWorkflowDTO & {
|
||||
_associationTag?: string
|
||||
})[]
|
||||
}>): Promise<Result | void> {
|
||||
const remoteQuery = container.resolve("remoteQuery")
|
||||
|
||||
const { price_lists } = data
|
||||
|
||||
const variantIds = price_lists
|
||||
.map((priceList) => priceList.prices.map((price) => price.variant_id))
|
||||
.flat()
|
||||
|
||||
const variables = {
|
||||
variant_id: variantIds,
|
||||
}
|
||||
|
||||
const query = {
|
||||
product_variant_price_set: {
|
||||
__args: variables,
|
||||
fields: ["variant_id", "price_set_id"],
|
||||
},
|
||||
}
|
||||
|
||||
const variantPriceSets = await remoteQuery(query)
|
||||
|
||||
const variantIdPriceSetIdMap: Map<string, string> = new Map(
|
||||
variantPriceSets.map((variantPriceSet) => [
|
||||
variantPriceSet.variant_id,
|
||||
variantPriceSet.price_set_id,
|
||||
])
|
||||
)
|
||||
|
||||
const variantsWithoutPriceSets: string[] = []
|
||||
|
||||
for (const variantId of variantIds) {
|
||||
if (!variantIdPriceSetIdMap.has(variantId)) {
|
||||
variantsWithoutPriceSets.push(variantId)
|
||||
}
|
||||
}
|
||||
|
||||
if (variantsWithoutPriceSets.length) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`No priceSet exist for variants: ${variantsWithoutPriceSets.join(", ")}`
|
||||
)
|
||||
}
|
||||
|
||||
return price_lists.map((priceListDTO) => {
|
||||
priceListDTO.title ??= priceListDTO.name
|
||||
const { _associationTag, name, prices, ...rest } = priceListDTO
|
||||
|
||||
const priceList = rest as CreatePriceListDTO
|
||||
|
||||
priceList.rules ??= {}
|
||||
priceList.prices =
|
||||
prices?.map((price) => {
|
||||
const price_set_id = variantIdPriceSetIdMap.get(price.variant_id)!
|
||||
|
||||
return {
|
||||
currency_code: price.currency_code,
|
||||
amount: price.amount,
|
||||
min_quantity: price.min_quantity,
|
||||
max_quantity: price.max_quantity,
|
||||
price_set_id,
|
||||
}
|
||||
}) ?? []
|
||||
|
||||
return { priceList, tag: _associationTag }
|
||||
})
|
||||
}
|
||||
|
||||
prepareCreatePriceLists.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type Result = {
|
||||
moneyAmountIds: string[]
|
||||
priceListId: string
|
||||
}
|
||||
|
||||
export async function prepareRemovePriceListPrices({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
money_amount_ids: string[]
|
||||
price_list_id: string
|
||||
}>): Promise<Result | void> {
|
||||
const pricingService: IPricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
const {
|
||||
price_list_id: priceListId,
|
||||
money_amount_ids: moneyAmountIdsToDelete,
|
||||
} = data
|
||||
|
||||
const moneyAmounts = await pricingService.listMoneyAmounts(
|
||||
{ id: moneyAmountIdsToDelete },
|
||||
{
|
||||
relations: [
|
||||
"price_set_money_amount",
|
||||
"price_set_money_amount.price_list",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
const moneyAmountIds = moneyAmounts
|
||||
.filter(
|
||||
(moneyAmount) =>
|
||||
moneyAmount?.price_set_money_amount?.price_list?.id === priceListId
|
||||
)
|
||||
.map((ma) => ma.id)
|
||||
|
||||
return { moneyAmountIds, priceListId }
|
||||
}
|
||||
|
||||
prepareRemovePriceListPrices.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { prepareCreatePriceLists } from "./prepare-create-price-list"
|
||||
|
||||
type Result = {
|
||||
priceSetIds: string[]
|
||||
priceListId: string
|
||||
}
|
||||
|
||||
export async function prepareRemoveProductPrices({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
product_ids: string[]
|
||||
price_list_id: string
|
||||
}>): Promise<Result | void> {
|
||||
const remoteQuery = container.resolve("remoteQuery")
|
||||
|
||||
const { price_list_id, product_ids } = data
|
||||
|
||||
const variables = {
|
||||
id: product_ids,
|
||||
}
|
||||
|
||||
const query = {
|
||||
product: {
|
||||
__args: variables,
|
||||
...defaultAdminProductRemoteQueryObject,
|
||||
},
|
||||
}
|
||||
|
||||
const productsWithVariantPriceSets: QueryResult[] = await remoteQuery(query)
|
||||
|
||||
const priceSetIds = productsWithVariantPriceSets
|
||||
.map(({ variants }) => variants.map(({ price }) => price.price_set_id))
|
||||
.flat()
|
||||
|
||||
return { priceSetIds, priceListId: price_list_id }
|
||||
}
|
||||
|
||||
prepareCreatePriceLists.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
|
||||
type QueryResult = {
|
||||
id: string
|
||||
variants: {
|
||||
id: string
|
||||
price: {
|
||||
price_set_id: string
|
||||
variant_id: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const defaultAdminProductRemoteQueryObject = {
|
||||
fields: ["id"],
|
||||
variants: {
|
||||
price: {
|
||||
fields: ["variant_id", "price_set_id"],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { prepareCreatePriceLists } from "./prepare-create-price-list"
|
||||
|
||||
type Result = {
|
||||
priceSetIds: string[]
|
||||
priceListId: string
|
||||
}
|
||||
|
||||
export async function prepareRemoveVariantPrices({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
variant_ids: string[]
|
||||
price_list_id: string
|
||||
}>): Promise<Result | void> {
|
||||
const remoteQuery = container.resolve("remoteQuery")
|
||||
|
||||
const { price_list_id, variant_ids } = data
|
||||
|
||||
const variables = {
|
||||
variant_id: variant_ids,
|
||||
}
|
||||
|
||||
const query = {
|
||||
product_variant_price_set: {
|
||||
__args: variables,
|
||||
fields: ["variant_id", "price_set_id"],
|
||||
},
|
||||
}
|
||||
|
||||
const productsWithVariantPriceSets: QueryResult[] = await remoteQuery(query)
|
||||
|
||||
const priceSetIds = productsWithVariantPriceSets.map(
|
||||
(variantPriceSet) => variantPriceSet.price_set_id
|
||||
)
|
||||
|
||||
return { priceSetIds, priceListId: price_list_id }
|
||||
}
|
||||
|
||||
prepareCreatePriceLists.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
|
||||
type QueryResult = {
|
||||
price_set_id: string
|
||||
variant_id: string
|
||||
}
|
||||
|
||||
const defaultAdminProductRemoteQueryObject = {
|
||||
fields: ["id"],
|
||||
variants: {
|
||||
price: {
|
||||
fields: ["variant_id", "price_set_id"],
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
PriceListPriceDTO,
|
||||
UpdatePriceListDTO,
|
||||
WorkflowTypes,
|
||||
} from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type Result = {
|
||||
priceLists: UpdatePriceListDTO[]
|
||||
priceListPricesMap: Map<string, PriceListPriceDTO[]>
|
||||
}
|
||||
|
||||
export async function prepareUpdatePriceLists({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
price_lists: WorkflowTypes.PriceListWorkflow.UpdatePriceListWorkflowDTO[]
|
||||
}>): Promise<Result> {
|
||||
const { price_lists: priceListsData } = data
|
||||
const remoteQuery = container.resolve("remoteQuery")
|
||||
|
||||
const variantPriceSetMap = new Map<string, string>()
|
||||
const priceListPricesMap = new Map<string, PriceListPriceDTO[]>()
|
||||
|
||||
const variantIds = priceListsData
|
||||
.map((priceListData) => priceListData.prices?.map((p) => p.variant_id))
|
||||
.flat()
|
||||
|
||||
const variables = {
|
||||
variant_id: variantIds,
|
||||
}
|
||||
|
||||
const query = {
|
||||
product_variant_price_set: {
|
||||
__args: variables,
|
||||
fields: ["variant_id", "price_set_id"],
|
||||
},
|
||||
}
|
||||
|
||||
const variantPriceSets = await remoteQuery(query)
|
||||
|
||||
for (const { variant_id, price_set_id } of variantPriceSets) {
|
||||
variantPriceSetMap.set(variant_id, price_set_id)
|
||||
}
|
||||
|
||||
const priceLists = priceListsData.map((priceListData) => {
|
||||
const priceListPrices: PriceListPriceDTO[] = []
|
||||
|
||||
priceListData.prices?.forEach((price) => {
|
||||
const { variant_id, ...priceData } = price
|
||||
if (!variant_id) {
|
||||
return
|
||||
}
|
||||
|
||||
priceListPrices.push({
|
||||
id: priceData.id,
|
||||
price_set_id: variantPriceSetMap.get(variant_id) as string,
|
||||
currency_code: priceData.currency_code as string,
|
||||
amount: priceData.amount,
|
||||
min_quantity: priceData.min_quantity,
|
||||
max_quantity: priceData.max_quantity,
|
||||
})
|
||||
|
||||
return
|
||||
})
|
||||
|
||||
priceListPricesMap.set(priceListData.id, priceListPrices)
|
||||
|
||||
delete priceListData?.prices
|
||||
|
||||
const priceListDataClone: UpdatePriceListDTO = {
|
||||
...priceListData,
|
||||
}
|
||||
|
||||
if (priceListData.name) {
|
||||
priceListDataClone.title = priceListData.name
|
||||
}
|
||||
|
||||
return priceListDataClone
|
||||
})
|
||||
|
||||
return { priceLists, priceListPricesMap }
|
||||
}
|
||||
|
||||
prepareUpdatePriceLists.aliases = {
|
||||
payload: "prepare",
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { IPricingModuleService, PriceListDTO } from "@medusajs/types"
|
||||
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
export async function removePriceLists({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
price_lists: {
|
||||
price_list: PriceListDTO
|
||||
}[]
|
||||
}>): Promise<
|
||||
{
|
||||
price_list: PriceListDTO
|
||||
}[]
|
||||
> {
|
||||
const pricingService: IPricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
await pricingService!.deletePriceLists(
|
||||
data.price_lists.map(({ price_list }) => price_list.id)
|
||||
)
|
||||
|
||||
return data.price_lists
|
||||
}
|
||||
|
||||
removePriceLists.aliases = {
|
||||
priceLists: "priceLists",
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { prepareCreatePriceLists } from "./prepare-create-price-list"
|
||||
|
||||
export async function removePriceListPriceSetPrices({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
priceSetIds: string[]
|
||||
priceListId: string
|
||||
}>): Promise<string[]> {
|
||||
const { priceSetIds, priceListId } = data
|
||||
const pricingService: IPricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
const priceSetMoneyAmounts = await pricingService.listPriceSetMoneyAmounts(
|
||||
{
|
||||
price_set_id: priceSetIds,
|
||||
price_list_id: [priceListId],
|
||||
},
|
||||
{
|
||||
relations: ["money_amount"],
|
||||
}
|
||||
)
|
||||
|
||||
const moneyAmountIDs = priceSetMoneyAmounts
|
||||
.map((priceSetMoneyAmount) => priceSetMoneyAmount.money_amount?.id)
|
||||
.filter((moneyAmountId): moneyAmountId is string => !!moneyAmountId)
|
||||
|
||||
await pricingService.deleteMoneyAmounts(moneyAmountIDs)
|
||||
|
||||
return moneyAmountIDs
|
||||
}
|
||||
|
||||
prepareCreatePriceLists.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type Result = {
|
||||
deletedPriceIds: string[]
|
||||
}
|
||||
|
||||
export async function removePrices({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
moneyAmountIds: string[]
|
||||
}>): Promise<Result> {
|
||||
const { moneyAmountIds } = data
|
||||
const pricingService: IPricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
await pricingService.deleteMoneyAmounts(moneyAmountIds)
|
||||
|
||||
return {
|
||||
deletedPriceIds: moneyAmountIds,
|
||||
}
|
||||
}
|
||||
|
||||
removePrices.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
AddPriceListPricesDTO,
|
||||
IPricingModuleService,
|
||||
PriceListDTO,
|
||||
PriceListPriceDTO,
|
||||
UpdateMoneyAmountDTO,
|
||||
UpdatePriceListDTO,
|
||||
} from "@medusajs/types"
|
||||
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type Result = {
|
||||
priceLists: PriceListDTO[]
|
||||
}
|
||||
|
||||
export async function updatePriceLists({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<{
|
||||
priceLists: UpdatePriceListDTO[]
|
||||
priceListPricesMap: Map<string, PriceListPriceDTO[]>
|
||||
}>): Promise<Result> {
|
||||
const { priceLists: priceListsData, priceListPricesMap } = data
|
||||
const pricingService: IPricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
const priceLists = await pricingService.updatePriceLists(priceListsData)
|
||||
const addPriceListPricesData: AddPriceListPricesDTO[] = []
|
||||
const moneyAmountsToUpdate: UpdateMoneyAmountDTO[] = []
|
||||
|
||||
for (const [priceListId, prices] of priceListPricesMap.entries()) {
|
||||
const moneyAmountsToCreate: PriceListPriceDTO[] = []
|
||||
|
||||
for (const price of prices) {
|
||||
if (price.id) {
|
||||
moneyAmountsToUpdate.push(price as UpdateMoneyAmountDTO)
|
||||
} else {
|
||||
moneyAmountsToCreate.push(price)
|
||||
}
|
||||
}
|
||||
|
||||
addPriceListPricesData.push({
|
||||
priceListId,
|
||||
prices: moneyAmountsToCreate,
|
||||
})
|
||||
}
|
||||
|
||||
if (addPriceListPricesData.length) {
|
||||
await pricingService.addPriceListPrices(addPriceListPricesData)
|
||||
}
|
||||
|
||||
if (moneyAmountsToUpdate.length) {
|
||||
await pricingService.updateMoneyAmounts(moneyAmountsToUpdate)
|
||||
}
|
||||
|
||||
return { priceLists }
|
||||
}
|
||||
|
||||
updatePriceLists.aliases = {
|
||||
payload: "updatePriceLists",
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
type ProductHandle = string
|
||||
type SalesChannelId = string
|
||||
|
||||
type PartialProduct = { handle: string; id: string }
|
||||
|
||||
type HandlerInput = {
|
||||
productsHandleSalesChannelsMap: Map<ProductHandle, SalesChannelId[]>
|
||||
products: PartialProduct[]
|
||||
}
|
||||
|
||||
export async function attachSalesChannelToProducts({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<void> {
|
||||
const { manager } = context
|
||||
const productsHandleSalesChannelsMap = data.productsHandleSalesChannelsMap
|
||||
const products = data.products
|
||||
|
||||
const salesChannelService = container.resolve("salesChannelService")
|
||||
const salesChannelServiceTx = salesChannelService.withTransaction(manager)
|
||||
|
||||
const salesChannelIdProductIdsMap = new Map<ProductHandle, SalesChannelId[]>()
|
||||
products.forEach((product) => {
|
||||
const salesChannelIds = productsHandleSalesChannelsMap.get(product.handle!)
|
||||
if (salesChannelIds) {
|
||||
salesChannelIds.forEach((salesChannelId) => {
|
||||
const productIds = salesChannelIdProductIdsMap.get(salesChannelId) || []
|
||||
productIds.push(product.id)
|
||||
salesChannelIdProductIdsMap.set(salesChannelId, productIds)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
await promiseAll(
|
||||
Array.from(salesChannelIdProductIdsMap.entries()).map(
|
||||
async ([salesChannelId, productIds]) => {
|
||||
return await salesChannelServiceTx.addProducts(
|
||||
salesChannelId,
|
||||
productIds
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
attachSalesChannelToProducts.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
type ProductHandle = string
|
||||
type ShippingProfileId = string
|
||||
type PartialProduct = { handle: string; id: string }
|
||||
type handlerInput = {
|
||||
productsHandleShippingProfileIdMap: Map<ProductHandle, ShippingProfileId>
|
||||
products: PartialProduct[]
|
||||
}
|
||||
|
||||
export async function attachShippingProfileToProducts({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<handlerInput>): Promise<void> {
|
||||
const { manager } = context
|
||||
|
||||
const productsHandleShippingProfileIdMap =
|
||||
data.productsHandleShippingProfileIdMap
|
||||
const products = data.products
|
||||
|
||||
const shippingProfileService = container.resolve("shippingProfileService")
|
||||
const shippingProfileServiceTx =
|
||||
shippingProfileService.withTransaction(manager)
|
||||
|
||||
const profileIdProductIdsMap = new Map<ShippingProfileId, ProductHandle[]>()
|
||||
products.forEach((product) => {
|
||||
const profileId = productsHandleShippingProfileIdMap.get(product.handle!)
|
||||
if (profileId) {
|
||||
const productIds = profileIdProductIdsMap.get(profileId) || []
|
||||
productIds.push(product.id)
|
||||
profileIdProductIdsMap.set(profileId, productIds)
|
||||
}
|
||||
})
|
||||
|
||||
await promiseAll(
|
||||
Array.from(profileIdProductIdsMap.entries()).map(
|
||||
async ([profileId, productIds]) => {
|
||||
return await shippingProfileServiceTx.addProducts(profileId, productIds)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
attachShippingProfileToProducts.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { ProductWorkflow, WorkflowTypes } from "@medusajs/types"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type VariantPrice = {
|
||||
region_id?: string
|
||||
currency_code?: string
|
||||
amount: number
|
||||
min_quantity?: number
|
||||
max_quantity?: number
|
||||
}
|
||||
|
||||
export type CreateProductVariantsPreparedData = {
|
||||
productVariants: ProductWorkflow.CreateProductVariantsInputDTO[]
|
||||
variantIndexPricesMap: Map<number, VariantPrice[]>
|
||||
productVariantsMap: Map<
|
||||
string,
|
||||
ProductWorkflow.CreateProductVariantsInputDTO[]
|
||||
>
|
||||
}
|
||||
|
||||
export async function createProductVariantsPrepareData({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<WorkflowTypes.ProductWorkflow.CreateProductVariantsWorkflowInputDTO>): Promise<CreateProductVariantsPreparedData> {
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const productVariants: ProductWorkflow.CreateProductVariantsInputDTO[] =
|
||||
data.productVariants || []
|
||||
|
||||
const variantIndexPricesMap = new Map<number, VariantPrice[]>()
|
||||
const productVariantsMap = new Map<
|
||||
string,
|
||||
ProductWorkflow.CreateProductVariantsInputDTO[]
|
||||
>()
|
||||
|
||||
for (const [index, productVariantData] of productVariants.entries()) {
|
||||
if (!productVariantData.product_id) {
|
||||
continue
|
||||
}
|
||||
|
||||
variantIndexPricesMap.set(index, productVariantData.prices || [])
|
||||
|
||||
delete productVariantData.prices
|
||||
|
||||
const productVariants = productVariantsMap.get(
|
||||
productVariantData.product_id
|
||||
)
|
||||
|
||||
if (productVariants) {
|
||||
productVariants.push(productVariantData)
|
||||
} else {
|
||||
productVariantsMap.set(productVariantData.product_id, [
|
||||
productVariantData,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
productVariants,
|
||||
variantIndexPricesMap,
|
||||
productVariantsMap,
|
||||
}
|
||||
}
|
||||
|
||||
createProductVariantsPrepareData.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type VariantPrice = {
|
||||
region_id?: string
|
||||
currency_code?: string
|
||||
amount: number
|
||||
min_quantity?: number
|
||||
max_quantity?: number
|
||||
}
|
||||
|
||||
type HandlerInput = {
|
||||
productVariantsMap: Map<string, ProductTypes.CreateProductVariantDTO[]>
|
||||
variantIndexPricesMap: Map<number, VariantPrice[]>
|
||||
}
|
||||
|
||||
export async function createProductVariants({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<{
|
||||
productVariants: ProductTypes.ProductVariantDTO[]
|
||||
variantPricesMap: Map<string, VariantPrice[]>
|
||||
}> {
|
||||
const { productVariantsMap, variantIndexPricesMap } = data
|
||||
const variantPricesMap = new Map<string, VariantPrice[]>()
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
const productVariants = await productModuleService.createVariants(
|
||||
[...productVariantsMap.values()].flat()
|
||||
)
|
||||
|
||||
productVariants.forEach((variant, index) => {
|
||||
variantPricesMap.set(variant.id, variantIndexPricesMap.get(index) || [])
|
||||
})
|
||||
|
||||
return {
|
||||
productVariants,
|
||||
variantPricesMap,
|
||||
}
|
||||
}
|
||||
|
||||
createProductVariants.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import { ProductTypes, SalesChannelTypes, WorkflowTypes } from "@medusajs/types"
|
||||
import {
|
||||
FeatureFlagUtils,
|
||||
kebabCase,
|
||||
ShippingProfileUtils,
|
||||
} from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type ShippingProfileId = string
|
||||
type SalesChannelId = string
|
||||
type ProductHandle = string
|
||||
type VariantIndexAndPrices = {
|
||||
index: number
|
||||
prices: {
|
||||
region_id?: string
|
||||
currency_code?: string
|
||||
amount: number
|
||||
min_quantity?: number
|
||||
max_quantity?: number
|
||||
}[]
|
||||
}
|
||||
|
||||
export type CreateProductsPreparedData = {
|
||||
products: ProductTypes.CreateProductDTO[]
|
||||
productsHandleShippingProfileIdMap: Map<ProductHandle, ShippingProfileId>
|
||||
productsHandleSalesChannelsMap: Map<ProductHandle, SalesChannelId[]>
|
||||
productsHandleVariantsIndexPricesMap: Map<
|
||||
ProductHandle,
|
||||
VariantIndexAndPrices[]
|
||||
>
|
||||
}
|
||||
|
||||
export async function createProductsPrepareData({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<WorkflowTypes.ProductWorkflow.CreateProductsWorkflowInputDTO>): Promise<CreateProductsPreparedData> {
|
||||
const { manager } = context
|
||||
let products = data.products
|
||||
|
||||
const shippingProfileService = container
|
||||
.resolve("shippingProfileService")
|
||||
.withTransaction(manager)
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const salesChannelService = container
|
||||
.resolve("salesChannelService")
|
||||
.withTransaction(manager)
|
||||
const salesChannelFeatureFlagKey =
|
||||
FeatureFlagUtils.SalesChannelFeatureFlag.key
|
||||
|
||||
const shippingProfileServiceTx =
|
||||
shippingProfileService.withTransaction(manager)
|
||||
|
||||
const shippingProfiles = await shippingProfileServiceTx.list({
|
||||
type: [
|
||||
ShippingProfileUtils.ShippingProfileType.DEFAULT,
|
||||
ShippingProfileUtils.ShippingProfileType.GIFT_CARD,
|
||||
],
|
||||
})
|
||||
const defaultShippingProfile = shippingProfiles.find(
|
||||
(sp) => sp.type === ShippingProfileUtils.ShippingProfileType.DEFAULT
|
||||
)
|
||||
const gitCardShippingProfile = shippingProfiles.find(
|
||||
(sp) => sp.type === ShippingProfileUtils.ShippingProfileType.GIFT_CARD
|
||||
)
|
||||
|
||||
let defaultSalesChannel: SalesChannelTypes.SalesChannelDTO | undefined
|
||||
if (featureFlagRouter.isFeatureEnabled(salesChannelFeatureFlagKey)) {
|
||||
defaultSalesChannel = await salesChannelService
|
||||
.withTransaction(manager)
|
||||
.retrieveDefault()
|
||||
}
|
||||
|
||||
const productsHandleShippingProfileIdMap = new Map<
|
||||
ProductHandle,
|
||||
ShippingProfileId
|
||||
>()
|
||||
const productsHandleSalesChannelsMap = new Map<
|
||||
ProductHandle,
|
||||
SalesChannelId[]
|
||||
>()
|
||||
const productsHandleVariantsIndexPricesMap = new Map<
|
||||
ProductHandle,
|
||||
VariantIndexAndPrices[]
|
||||
>()
|
||||
|
||||
for (const product of products) {
|
||||
product.handle ??= kebabCase(product.title)
|
||||
|
||||
if (product.is_giftcard) {
|
||||
productsHandleShippingProfileIdMap.set(
|
||||
product.handle!,
|
||||
gitCardShippingProfile!.id
|
||||
)
|
||||
} else {
|
||||
productsHandleShippingProfileIdMap.set(
|
||||
product.handle!,
|
||||
defaultShippingProfile!.id
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
featureFlagRouter.isFeatureEnabled(salesChannelFeatureFlagKey) &&
|
||||
!product.sales_channels?.length
|
||||
) {
|
||||
productsHandleSalesChannelsMap.set(product.handle!, [
|
||||
defaultSalesChannel!.id,
|
||||
])
|
||||
} else {
|
||||
productsHandleSalesChannelsMap.set(
|
||||
product.handle!,
|
||||
product.sales_channels!.map((s) => s.id)
|
||||
)
|
||||
}
|
||||
|
||||
if (product.variants) {
|
||||
const items =
|
||||
productsHandleVariantsIndexPricesMap.get(product.handle!) ?? []
|
||||
|
||||
product.variants.forEach((variant, index) => {
|
||||
items.push({
|
||||
index,
|
||||
prices: variant.prices!,
|
||||
})
|
||||
})
|
||||
|
||||
productsHandleVariantsIndexPricesMap.set(product.handle!, items)
|
||||
}
|
||||
}
|
||||
|
||||
products = products.map((productData) => {
|
||||
delete productData.sales_channels
|
||||
return productData
|
||||
})
|
||||
|
||||
return {
|
||||
products: products as ProductTypes.CreateProductDTO[],
|
||||
productsHandleShippingProfileIdMap,
|
||||
productsHandleSalesChannelsMap,
|
||||
productsHandleVariantsIndexPricesMap,
|
||||
}
|
||||
}
|
||||
|
||||
createProductsPrepareData.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
|
||||
type HandlerInput = {
|
||||
products: ProductTypes.CreateProductDTO[]
|
||||
}
|
||||
|
||||
export async function createProducts({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<ProductTypes.ProductDTO[]> {
|
||||
const data_ = data.products
|
||||
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
return await productModuleService.create(data_)
|
||||
}
|
||||
|
||||
createProducts.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
type ProductHandle = string
|
||||
type SalesChannelId = string
|
||||
type PartialProduct = { handle: string; id: string }
|
||||
type HandlerInput = {
|
||||
productsHandleSalesChannelsMap: Map<ProductHandle, SalesChannelId[]>
|
||||
products: PartialProduct[]
|
||||
}
|
||||
|
||||
export async function detachSalesChannelFromProducts({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<void> {
|
||||
const { manager } = context
|
||||
const productsHandleSalesChannelsMap = data.productsHandleSalesChannelsMap
|
||||
const products = data.products
|
||||
|
||||
const salesChannelService = container.resolve("salesChannelService")
|
||||
const salesChannelServiceTx = salesChannelService.withTransaction(manager)
|
||||
|
||||
const salesChannelIdProductIdsMap = new Map<ProductHandle, SalesChannelId[]>()
|
||||
products.forEach((product) => {
|
||||
const salesChannelIds = productsHandleSalesChannelsMap.get(product.handle!)
|
||||
if (salesChannelIds) {
|
||||
salesChannelIds.forEach((salesChannelId) => {
|
||||
const productIds = salesChannelIdProductIdsMap.get(salesChannelId) || []
|
||||
productIds.push(product.id)
|
||||
salesChannelIdProductIdsMap.set(salesChannelId, productIds)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
await promiseAll(
|
||||
Array.from(salesChannelIdProductIdsMap.entries()).map(
|
||||
async ([salesChannelId, productIds]) => {
|
||||
return await salesChannelServiceTx.removeProducts(
|
||||
salesChannelId,
|
||||
productIds
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
detachSalesChannelFromProducts.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
type ProductHandle = string
|
||||
type ShippingProfileId = string
|
||||
type PartialProduct = { handle: string; id: string }
|
||||
type HandlerInput = {
|
||||
productsHandleShippingProfileIdMap: Map<ProductHandle, ShippingProfileId>
|
||||
products: PartialProduct[]
|
||||
}
|
||||
|
||||
export async function detachShippingProfileFromProducts({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<void> {
|
||||
const { manager } = context
|
||||
const productsHandleShippingProfileIdMap =
|
||||
data.productsHandleShippingProfileIdMap
|
||||
const products = data.products
|
||||
|
||||
const shippingProfileService = container.resolve("shippingProfileService")
|
||||
const shippingProfileServiceTx =
|
||||
shippingProfileService.withTransaction(manager)
|
||||
|
||||
const profileIdProductIdsMap = new Map<ShippingProfileId, ProductHandle[]>()
|
||||
products.forEach((product) => {
|
||||
const profileId = productsHandleShippingProfileIdMap.get(product.handle!)
|
||||
if (profileId) {
|
||||
const productIds = profileIdProductIdsMap.get(profileId) || []
|
||||
productIds.push(product.id)
|
||||
profileIdProductIdsMap.set(profileId, productIds)
|
||||
}
|
||||
})
|
||||
|
||||
await promiseAll(
|
||||
Array.from(profileIdProductIdsMap.entries()).map(
|
||||
async ([profileId, productIds]) => {
|
||||
return await shippingProfileServiceTx.removeProducts(
|
||||
profileId,
|
||||
productIds
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
detachShippingProfileFromProducts.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export * from "./attach-sales-channel-to-products"
|
||||
export * from "./attach-shipping-profile-to-products"
|
||||
export * from "./create-product-variants"
|
||||
export * from "./create-product-variants-prepare-data"
|
||||
export * from "./create-products"
|
||||
export * from "./create-products-prepare-data"
|
||||
export * from "./detach-sales-channel-from-products"
|
||||
export * from "./detach-shipping-profile-from-products"
|
||||
export * from "./list-products"
|
||||
export * from "./remove-product-variants"
|
||||
export * from "./remove-products"
|
||||
export * from "./revert-update-products"
|
||||
export * from "./revert-variant-prices"
|
||||
export * from "./update-product-variants"
|
||||
export * from "./update-product-variants-prepare-data"
|
||||
export * from "./update-products"
|
||||
export * from "./update-products-prepare-data"
|
||||
export * from "./update-products-variants-prices"
|
||||
export * from "./upsert-variant-prices"
|
||||
@@ -0,0 +1,47 @@
|
||||
import { ProductTypes, WorkflowTypes } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type HandlerInput = {
|
||||
ids: string[]
|
||||
config?: WorkflowTypes.CommonWorkflow.WorkflowInputConfig
|
||||
}
|
||||
|
||||
export async function listProducts({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: // TODO: should return product DTO or priced product but needs to be created in the types package
|
||||
WorkflowArguments<HandlerInput>): Promise<ProductTypes.ProductDTO[]> {
|
||||
const { manager } = context
|
||||
|
||||
const productIds = data.ids
|
||||
const listConfig = data.config?.listConfig ?? {}
|
||||
|
||||
const productService = container.resolve("productService")
|
||||
const pricingService = container.resolve("pricingService")
|
||||
|
||||
const config = {}
|
||||
let shouldUseConfig = false
|
||||
|
||||
if (listConfig.select) {
|
||||
shouldUseConfig = !!listConfig.select.length
|
||||
Object.assign(config, { select: listConfig.select })
|
||||
}
|
||||
|
||||
if (listConfig.relations) {
|
||||
shouldUseConfig = shouldUseConfig || !!listConfig.relations.length
|
||||
Object.assign(config, { relations: listConfig.relations })
|
||||
}
|
||||
|
||||
const rawProducts = await productService
|
||||
.withTransaction(manager as any)
|
||||
.list({ id: productIds }, shouldUseConfig ? config : undefined)
|
||||
|
||||
return await pricingService
|
||||
.withTransaction(manager as any)
|
||||
.setProductPrices(rawProducts)
|
||||
}
|
||||
|
||||
listProducts.aliases = {
|
||||
ids: "ids",
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { IProductModuleService } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type HandlerInput = { productVariants: { id: string }[] }
|
||||
|
||||
export async function removeProductVariants({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<void> {
|
||||
if (!data.productVariants.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const productModuleService: IProductModuleService = container.resolve(
|
||||
ModulesDefinition[Modules.PRODUCT].registrationName
|
||||
)
|
||||
|
||||
await productModuleService.deleteVariants(
|
||||
data.productVariants.map((p) => p.id)
|
||||
)
|
||||
}
|
||||
|
||||
removeProductVariants.aliases = {
|
||||
productVariants: "productVariants",
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ProductTypes } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
|
||||
type HandlerInput = { products: { id: string }[] }
|
||||
|
||||
export async function removeProducts({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<void> {
|
||||
if (!data.products.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
await productModuleService.softDelete(data.products.map((p) => p.id))
|
||||
}
|
||||
|
||||
removeProducts.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
ProductDTO,
|
||||
ProductTypes,
|
||||
ProductVariantDTO,
|
||||
UpdateProductDTO,
|
||||
} from "@medusajs/types"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
import { UpdateProductsPreparedData } from "./update-products-prepare-data"
|
||||
|
||||
type HandlerInput = UpdateProductsPreparedData & {
|
||||
variants: ProductVariantDTO[]
|
||||
}
|
||||
|
||||
export async function revertUpdateProducts({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<ProductDTO[]> {
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
// restore variants that have been soft deleted during update products step
|
||||
await productModuleService.restoreVariants(data.variants.map((v) => v.id))
|
||||
data.originalProducts.forEach((product) => {
|
||||
// @ts-ignore
|
||||
product.variants = product.variants.map((v) => ({ id: v.id }))
|
||||
})
|
||||
|
||||
return await productModuleService.update(
|
||||
data.originalProducts as unknown as UpdateProductDTO[]
|
||||
)
|
||||
}
|
||||
|
||||
revertUpdateProducts.aliases = {
|
||||
preparedData: "preparedData",
|
||||
variants: "variants",
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { PricingTypes } from "@medusajs/types"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type HandlerInput = {
|
||||
createdLinks: Record<any, any>[]
|
||||
originalMoneyAmounts: PricingTypes.MoneyAmountDTO[]
|
||||
createdPriceSets: PricingTypes.PriceSetDTO[]
|
||||
}
|
||||
|
||||
export async function revertVariantPrices({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<void> {
|
||||
const {
|
||||
createdLinks = [],
|
||||
originalMoneyAmounts = [],
|
||||
createdPriceSets = [],
|
||||
} = data
|
||||
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const isPricingDomainEnabled = featureFlagRouter.isFeatureEnabled(
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
|
||||
if (!isPricingDomainEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
const pricingModuleService = container.resolve("pricingModuleService")
|
||||
const remoteLink = container.resolve("remoteLink")
|
||||
|
||||
await remoteLink.remove(createdLinks)
|
||||
|
||||
if (originalMoneyAmounts.length) {
|
||||
await pricingModuleService.updateMoneyAmounts(originalMoneyAmounts)
|
||||
}
|
||||
|
||||
if (createdPriceSets.length) {
|
||||
await pricingModuleService.delete({
|
||||
id: createdPriceSets.map((cps) => cps.id),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
revertVariantPrices.aliases = {
|
||||
productVariantsPrices: "productVariantsPrices",
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { ProductTypes, ProductWorkflow, WorkflowTypes } from "@medusajs/types"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type VariantPrice = {
|
||||
region_id?: string
|
||||
currency_code?: string
|
||||
amount: number
|
||||
min_quantity?: number
|
||||
max_quantity?: number
|
||||
}
|
||||
|
||||
export type UpdateProductVariantsPreparedData = {
|
||||
productVariants: ProductWorkflow.UpdateProductVariantsInputDTO[]
|
||||
variantPricesMap: Map<string, VariantPrice[]>
|
||||
productVariantsMap: Map<
|
||||
string,
|
||||
ProductWorkflow.UpdateProductVariantsInputDTO[]
|
||||
>
|
||||
}
|
||||
|
||||
export async function updateProductVariantsPrepareData({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<WorkflowTypes.ProductWorkflow.UpdateProductVariantsWorkflowInputDTO>): Promise<UpdateProductVariantsPreparedData> {
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const isPricingDomainEnabled = featureFlagRouter.isFeatureEnabled(
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
let productVariants: ProductWorkflow.UpdateProductVariantsInputDTO[] =
|
||||
data.productVariants || []
|
||||
|
||||
const variantsDataMap = new Map<
|
||||
string,
|
||||
ProductWorkflow.UpdateProductVariantsInputDTO
|
||||
>(
|
||||
productVariants.map((productVariantData) => [
|
||||
productVariantData.id,
|
||||
productVariantData,
|
||||
])
|
||||
)
|
||||
|
||||
const variantIds = productVariants.map((pv) => pv.id) as string[]
|
||||
const productVariantsMap = new Map<
|
||||
string,
|
||||
ProductWorkflow.UpdateProductVariantsInputDTO[]
|
||||
>()
|
||||
const variantPricesMap = new Map<string, VariantPrice[]>()
|
||||
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
const variantsWithProductIds = await productModuleService.listVariants(
|
||||
{
|
||||
id: variantIds,
|
||||
},
|
||||
{
|
||||
select: ["id", "product_id"],
|
||||
}
|
||||
)
|
||||
|
||||
for (const variantWithProductID of variantsWithProductIds) {
|
||||
const variantData = variantsDataMap.get(variantWithProductID.id)
|
||||
|
||||
if (!variantData) {
|
||||
continue
|
||||
}
|
||||
|
||||
variantPricesMap.set(variantWithProductID.id, variantData.prices || [])
|
||||
if (isPricingDomainEnabled) {
|
||||
delete variantData.prices
|
||||
}
|
||||
|
||||
const variantsData: ProductWorkflow.UpdateProductVariantsInputDTO[] =
|
||||
productVariantsMap.get(variantWithProductID.product_id) || []
|
||||
|
||||
if (variantData) {
|
||||
variantsData.push(variantData)
|
||||
}
|
||||
|
||||
productVariantsMap.set(variantWithProductID.product_id, variantsData)
|
||||
}
|
||||
|
||||
return {
|
||||
productVariants,
|
||||
variantPricesMap,
|
||||
productVariantsMap,
|
||||
}
|
||||
}
|
||||
|
||||
updateProductVariantsPrepareData.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { ProductTypes, UpdateProductVariantOnlyDTO } from "@medusajs/types"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type HandlerInput = {
|
||||
productVariantsMap: Map<string, ProductTypes.UpdateProductVariantDTO[]>
|
||||
}
|
||||
|
||||
export async function updateProductVariants({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<
|
||||
ProductTypes.UpdateProductVariantDTO[]
|
||||
> {
|
||||
const { productVariantsMap } = data
|
||||
const productsVariants: ProductTypes.UpdateProductVariantDTO[] = []
|
||||
const updateVariantsData: ProductTypes.UpdateProductVariantOnlyDTO[] = []
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
for (const [product_id, variantsUpdateData = []] of productVariantsMap) {
|
||||
updateVariantsData.push(
|
||||
...(variantsUpdateData as unknown as UpdateProductVariantOnlyDTO[]).map(
|
||||
(update) => ({ ...update, product_id })
|
||||
)
|
||||
)
|
||||
|
||||
productsVariants.push(...variantsUpdateData)
|
||||
}
|
||||
|
||||
if (updateVariantsData.length) {
|
||||
await productModuleService.updateVariants(updateVariantsData)
|
||||
}
|
||||
|
||||
return productsVariants
|
||||
}
|
||||
|
||||
updateProductVariants.aliases = {
|
||||
payload: "payload",
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { ProductDTO, SalesChannelDTO, WorkflowTypes } from "@medusajs/types"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type ProductWithSalesChannelsDTO = ProductDTO & {
|
||||
sales_channels?: SalesChannelDTO[]
|
||||
}
|
||||
|
||||
type VariantPrice = {
|
||||
region_id?: string
|
||||
currency_code?: string
|
||||
amount: number
|
||||
min_quantity?: number
|
||||
max_quantity?: number
|
||||
}
|
||||
|
||||
export type UpdateProductsPreparedData = {
|
||||
originalProducts: ProductWithSalesChannelsDTO[]
|
||||
productHandleAddedChannelsMap: Map<string, string[]>
|
||||
productHandleRemovedChannelsMap: Map<string, string[]>
|
||||
variantPricesMap: Map<string, VariantPrice[]>
|
||||
}
|
||||
|
||||
export async function updateProductsPrepareData({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<WorkflowTypes.ProductWorkflow.UpdateProductsWorkflowInputDTO>): Promise<UpdateProductsPreparedData> {
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const isPricingDomainEnabled = featureFlagRouter.isFeatureEnabled(
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
|
||||
const variantPricesMap = new Map<string, VariantPrice[]>()
|
||||
const ids = data.products.map((product) => product.id)
|
||||
|
||||
const productHandleAddedChannelsMap = new Map<string, string[]>()
|
||||
const productHandleRemovedChannelsMap = new Map<string, string[]>()
|
||||
|
||||
const productService = container.resolve("productService")
|
||||
const productServiceTx = productService.withTransaction(context.manager)
|
||||
|
||||
const products = await productServiceTx.list(
|
||||
// TODO: use RemoteQuery - sales_channels needs to be added to the joiner config
|
||||
{ id: ids },
|
||||
{
|
||||
relations: [
|
||||
"variants",
|
||||
"variants.options",
|
||||
"images",
|
||||
"options",
|
||||
"tags",
|
||||
"collection",
|
||||
"sales_channels",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
data.products.forEach((productInput) => {
|
||||
const removedChannels: string[] = []
|
||||
const addedChannels: string[] = []
|
||||
|
||||
const currentProduct = products.find(
|
||||
(p) => p.id === productInput.id
|
||||
) as unknown as ProductWithSalesChannelsDTO
|
||||
|
||||
if (productInput.sales_channels) {
|
||||
productInput.sales_channels.forEach((channel) => {
|
||||
if (
|
||||
!currentProduct.sales_channels?.find((sc) => sc.id === channel.id)
|
||||
) {
|
||||
addedChannels.push(channel.id)
|
||||
}
|
||||
})
|
||||
|
||||
currentProduct.sales_channels?.forEach((channel) => {
|
||||
if (!productInput.sales_channels!.find((sc) => sc.id === channel.id)) {
|
||||
removedChannels.push(channel.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for (const variantInput of productInput.variants || []) {
|
||||
if (variantInput.id) {
|
||||
variantPricesMap.set(variantInput.id, variantInput.prices || [])
|
||||
}
|
||||
|
||||
if (isPricingDomainEnabled) {
|
||||
delete variantInput.prices
|
||||
}
|
||||
}
|
||||
|
||||
productHandleAddedChannelsMap.set(currentProduct.handle!, addedChannels)
|
||||
productHandleRemovedChannelsMap.set(currentProduct.handle!, removedChannels)
|
||||
})
|
||||
|
||||
return {
|
||||
originalProducts: products,
|
||||
productHandleAddedChannelsMap,
|
||||
productHandleRemovedChannelsMap,
|
||||
variantPricesMap,
|
||||
}
|
||||
}
|
||||
|
||||
updateProductsPrepareData.aliases = {
|
||||
preparedData: "preparedData",
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { ProductTypes, WorkflowTypes } from "@medusajs/types"
|
||||
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { MedusaError, MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type ProductHandle = string
|
||||
type VariantIndexAndPrices = {
|
||||
index: number
|
||||
prices: WorkflowTypes.ProductWorkflow.CreateProductVariantPricesInputDTO[]
|
||||
}
|
||||
type HandlerInput = {
|
||||
productsHandleVariantsIndexPricesMap: Map<
|
||||
ProductHandle,
|
||||
VariantIndexAndPrices[]
|
||||
>
|
||||
products: ProductTypes.ProductDTO[]
|
||||
}
|
||||
|
||||
export async function updateProductsVariantsPrices({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>) {
|
||||
const { manager } = context
|
||||
const products = data.products
|
||||
const productsHandleVariantsIndexPricesMap =
|
||||
data.productsHandleVariantsIndexPricesMap
|
||||
|
||||
const productVariantService = container.resolve("productVariantService")
|
||||
const regionService = container.resolve("regionService")
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const productVariantServiceTx = productVariantService.withTransaction(manager)
|
||||
const variantIdsPricesData: any[] = []
|
||||
const variantPricesMap = new Map<string, any[]>()
|
||||
|
||||
const productsMap = new Map<string, ProductTypes.ProductDTO>(
|
||||
products.map((p) => [p.handle!, p])
|
||||
)
|
||||
|
||||
const regionIds = new Set()
|
||||
|
||||
for (const mapData of productsHandleVariantsIndexPricesMap.entries()) {
|
||||
const [handle, variantData] = mapData
|
||||
|
||||
const product = productsMap.get(handle)
|
||||
if (!product) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Product with handle ${handle} not found`
|
||||
)
|
||||
}
|
||||
|
||||
variantData.forEach((item, index) => {
|
||||
const variant = product.variants[index]
|
||||
variantIdsPricesData.push({
|
||||
variantId: variant.id,
|
||||
prices: item.prices,
|
||||
})
|
||||
|
||||
const prices: any[] = []
|
||||
variantPricesMap.set(variant.id, prices)
|
||||
|
||||
item.prices.forEach((price) => {
|
||||
const obj = {
|
||||
amount: price.amount,
|
||||
currency_code: price.currency_code,
|
||||
rules: {},
|
||||
}
|
||||
|
||||
if (price.region_id) {
|
||||
regionIds.add(price.region_id)
|
||||
;(obj as any).region_id = price.region_id
|
||||
}
|
||||
|
||||
prices.push(obj)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (regionIds.size) {
|
||||
const regions = await regionService.list({
|
||||
id: [...regionIds],
|
||||
})
|
||||
const regionMap = new Map<string, any>(regions.map((r) => [r.id, r]))
|
||||
|
||||
for (const [, prices] of variantPricesMap.entries()) {
|
||||
prices.forEach((price) => {
|
||||
if (price.region_id) {
|
||||
const region = regionMap.get(price.region_id)
|
||||
price.currency_code = region?.currency_code
|
||||
price.rules = {
|
||||
region_id: price.region_id,
|
||||
}
|
||||
|
||||
delete price.region_id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const remoteLink = container.resolve("remoteLink")
|
||||
const pricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
const priceSetsToCreate = variantIdsPricesData.map(({ variantId }) => ({
|
||||
rules: [{ rule_attribute: "region_id" }],
|
||||
prices: variantPricesMap.get(variantId),
|
||||
}))
|
||||
|
||||
const priceSets = await pricingModuleService.create(priceSetsToCreate)
|
||||
|
||||
const links = priceSets.map((priceSet, index) => ({
|
||||
productService: {
|
||||
variant_id: variantIdsPricesData[index].variantId,
|
||||
},
|
||||
pricingService: {
|
||||
price_set_id: priceSet.id,
|
||||
},
|
||||
}))
|
||||
|
||||
await remoteLink.create(links)
|
||||
} else {
|
||||
await productVariantServiceTx.updateVariantPrices(variantIdsPricesData)
|
||||
}
|
||||
}
|
||||
|
||||
updateProductsVariantsPrices.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { ProductDTO, ProductTypes } from "@medusajs/types"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type HandlerInput = {
|
||||
products: ProductTypes.UpdateProductDTO[]
|
||||
}
|
||||
|
||||
export async function updateProducts({
|
||||
container,
|
||||
context,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>): Promise<ProductDTO[]> {
|
||||
if (!data.products.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const productModuleService: ProductTypes.IProductModuleService =
|
||||
container.resolve(ModulesDefinition[Modules.PRODUCT].registrationName)
|
||||
|
||||
const products = await productModuleService.update(data.products)
|
||||
|
||||
return await productModuleService.list(
|
||||
{ id: products.map((p) => p.id) },
|
||||
{
|
||||
relations: [
|
||||
"variants",
|
||||
"variants.options",
|
||||
"images",
|
||||
"options",
|
||||
"tags",
|
||||
// "type",
|
||||
"collection",
|
||||
// "profiles",
|
||||
// "sales_channels",
|
||||
],
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
updateProducts.aliases = {
|
||||
products: "products",
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
import { PricingTypes } from "@medusajs/types"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
type VariantPrice = {
|
||||
id?: string
|
||||
region_id?: string
|
||||
currency_code: string
|
||||
amount: number
|
||||
min_quantity?: number
|
||||
max_quantity?: number
|
||||
rules: Record<string, string>
|
||||
}
|
||||
|
||||
type RegionDTO = {
|
||||
id: string
|
||||
currency_code: string
|
||||
}
|
||||
|
||||
type HandlerInput = {
|
||||
variantPricesMap: Map<string, VariantPrice[]>
|
||||
}
|
||||
|
||||
export async function upsertVariantPrices({
|
||||
container,
|
||||
data,
|
||||
}: WorkflowArguments<HandlerInput>) {
|
||||
const { variantPricesMap } = data
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
|
||||
if (!featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
return {
|
||||
createdLinks: [],
|
||||
originalMoneyAmounts: [],
|
||||
createdPriceSets: [],
|
||||
}
|
||||
}
|
||||
|
||||
const pricingModuleService = container.resolve("pricingModuleService")
|
||||
const regionService = container.resolve("regionService")
|
||||
const remoteLink = container.resolve("remoteLink")
|
||||
const remoteQuery = container.resolve("remoteQuery")
|
||||
|
||||
const variables = {
|
||||
variant_id: [...variantPricesMap.keys()],
|
||||
}
|
||||
|
||||
const query = {
|
||||
product_variant_price_set: {
|
||||
__args: variables,
|
||||
fields: ["variant_id", "price_set_id"],
|
||||
},
|
||||
}
|
||||
|
||||
const variantPriceSets = await remoteQuery(query)
|
||||
|
||||
const variantIdToPriceSetIdMap: Map<string, string> = new Map(
|
||||
variantPriceSets.map((variantPriceSet) => [
|
||||
variantPriceSet.variant_id,
|
||||
variantPriceSet.price_set_id,
|
||||
])
|
||||
)
|
||||
|
||||
const moneyAmountsToUpdate: PricingTypes.UpdateMoneyAmountDTO[] = []
|
||||
const createdPriceSets: PricingTypes.PriceSetDTO[] = []
|
||||
const ruleSetPricesToAdd: PricingTypes.CreatePricesDTO[] = []
|
||||
const linksToCreate: any[] = []
|
||||
|
||||
for (const [variantId, prices = []] of variantPricesMap) {
|
||||
const priceSetToCreate: PricingTypes.CreatePriceSetDTO = {
|
||||
rules: [{ rule_attribute: "region_id" }],
|
||||
prices: [],
|
||||
}
|
||||
const regionIds = prices.map((price) => price.region_id)
|
||||
const regions = await regionService.list({ id: regionIds })
|
||||
const regionsMap: Map<string, RegionDTO> = new Map(
|
||||
regions.map((region: RegionDTO) => [region.id, region])
|
||||
)
|
||||
|
||||
for (const price of prices) {
|
||||
const region = price.region_id && regionsMap.get(price.region_id)
|
||||
let region_currency_code: string | undefined
|
||||
let region_rules: Record<string, string> | undefined
|
||||
|
||||
if (region) {
|
||||
region_currency_code = region.currency_code
|
||||
region_rules = {
|
||||
region_id: region.id,
|
||||
}
|
||||
}
|
||||
|
||||
if (price.id) {
|
||||
const priceToUpdate = {
|
||||
id: price.id,
|
||||
min_quantity: price.min_quantity,
|
||||
max_quantity: price.max_quantity,
|
||||
amount: price.amount,
|
||||
currency_code: region_currency_code ?? price.currency_code,
|
||||
}
|
||||
|
||||
moneyAmountsToUpdate.push(priceToUpdate)
|
||||
} else {
|
||||
const variantPrice: PricingTypes.CreatePricesDTO = {
|
||||
min_quantity: price.min_quantity,
|
||||
max_quantity: price.max_quantity,
|
||||
amount: price.amount,
|
||||
currency_code: region_currency_code ?? price.currency_code,
|
||||
rules: region_rules ?? {},
|
||||
}
|
||||
|
||||
delete price.region_id
|
||||
|
||||
if (variantIdToPriceSetIdMap.get(variantId)) {
|
||||
ruleSetPricesToAdd.push(variantPrice)
|
||||
} else {
|
||||
priceSetToCreate.prices?.push(variantPrice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let priceSetId = variantIdToPriceSetIdMap.get(variantId)
|
||||
|
||||
if (priceSetId) {
|
||||
await pricingModuleService.addPrices({
|
||||
priceSetId,
|
||||
prices: ruleSetPricesToAdd,
|
||||
})
|
||||
} else {
|
||||
const createdPriceSet = await pricingModuleService.create(
|
||||
priceSetToCreate
|
||||
)
|
||||
priceSetId = createdPriceSet?.id
|
||||
|
||||
createdPriceSets.push(createdPriceSet)
|
||||
|
||||
linksToCreate.push({
|
||||
productService: {
|
||||
variant_id: variantId,
|
||||
},
|
||||
pricingService: {
|
||||
price_set_id: priceSetId,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const createdLinks = await remoteLink.create(linksToCreate)
|
||||
|
||||
let originalMoneyAmounts = await pricingModuleService.listMoneyAmounts(
|
||||
{
|
||||
id: moneyAmountsToUpdate.map((matu) => matu.id),
|
||||
},
|
||||
{
|
||||
select: ["id", "currency_code", "amount", "min_quantity", "max_quantity"],
|
||||
}
|
||||
)
|
||||
|
||||
if (moneyAmountsToUpdate.length) {
|
||||
await pricingModuleService.updateMoneyAmounts(moneyAmountsToUpdate)
|
||||
}
|
||||
|
||||
return {
|
||||
createdLinks,
|
||||
originalMoneyAmounts,
|
||||
createdPriceSets,
|
||||
}
|
||||
}
|
||||
|
||||
upsertVariantPrices.aliases = {
|
||||
productVariantsPrices: "productVariantsPrices",
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { isDefined } from "medusa-core-utils"
|
||||
|
||||
import { WorkflowArguments } from "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -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 "@medusajs/workflows-sdk"
|
||||
|
||||
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
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./find-sales-channel"
|
||||
Reference in New Issue
Block a user