feat(medusa): Add product isolation FF to update cart (#5168)
**What** Update cart must use the remote query when being in product isolation mode. This pr is a first iteration that aims to quickly make compatible the end point in isolation. In a future iteration, this end point will be migrated to a workflow Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
co-authored by
Oli Juhl
parent
27d74cb399
commit
dfa5d041c9
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/modules-sdk": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Feat/update cart product isolation
|
||||||
@@ -15,6 +15,7 @@ import { AddressPayload } from "../../../../types/common"
|
|||||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||||
|
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [post] /store/carts/{id}
|
* @oas [post] /store/carts/{id}
|
||||||
@@ -75,14 +76,22 @@ export default async (req, res) => {
|
|||||||
const validated = req.validatedBody as StorePostCartsCartReq
|
const validated = req.validatedBody as StorePostCartsCartReq
|
||||||
|
|
||||||
const cartService: CartService = req.scope.resolve("cartService")
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
|
const featureFlagRouter = req.scope.resolve("featureFlagRouter")
|
||||||
const manager: EntityManager = req.scope.resolve("manager")
|
const manager: EntityManager = req.scope.resolve("manager")
|
||||||
|
|
||||||
if (req.user?.customer_id) {
|
if (req.user?.customer_id) {
|
||||||
validated.customer_id = req.user.customer_id
|
validated.customer_id = req.user.customer_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cart
|
||||||
|
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)) {
|
||||||
|
cart = await retrieveCartWithIsolatedProductModule(req, id)
|
||||||
|
}
|
||||||
|
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager.transaction(async (transactionManager) => {
|
||||||
await cartService.withTransaction(transactionManager).update(id, validated)
|
await cartService
|
||||||
|
.withTransaction(transactionManager)
|
||||||
|
.update(cart ?? id, validated)
|
||||||
|
|
||||||
const updated = await cartService
|
const updated = await cartService
|
||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
@@ -101,9 +110,60 @@ export default async (req, res) => {
|
|||||||
select: defaultStoreCartFields,
|
select: defaultStoreCartFields,
|
||||||
relations: defaultStoreCartRelations,
|
relations: defaultStoreCartRelations,
|
||||||
})
|
})
|
||||||
|
|
||||||
res.json({ cart: cleanResponseData(data, []) })
|
res.json({ cart: cleanResponseData(data, []) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function retrieveCartWithIsolatedProductModule(req, id: string) {
|
||||||
|
const cartService = req.scope.resolve("cartService")
|
||||||
|
const remoteQuery = req.scope.resolve("remoteQuery")
|
||||||
|
|
||||||
|
const relations = [
|
||||||
|
"items",
|
||||||
|
"shipping_methods",
|
||||||
|
"shipping_methods.shipping_option",
|
||||||
|
"shipping_address",
|
||||||
|
"billing_address",
|
||||||
|
"gift_cards",
|
||||||
|
"customer",
|
||||||
|
"region",
|
||||||
|
"payment_sessions",
|
||||||
|
"region.countries",
|
||||||
|
"discounts",
|
||||||
|
"discounts.rule",
|
||||||
|
]
|
||||||
|
|
||||||
|
const cart = await cartService.retrieve(id, {
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const products = await remoteQuery({
|
||||||
|
products: {
|
||||||
|
__args: {
|
||||||
|
id: cart.items.map((i) => i.product_id),
|
||||||
|
},
|
||||||
|
fields: ["id"],
|
||||||
|
variants: {
|
||||||
|
fields: ["id"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const variantsMap = new Map(
|
||||||
|
products.flatMap((p) => p.variants).map((v) => [v.id, v])
|
||||||
|
)
|
||||||
|
|
||||||
|
cart.items.forEach((item) => {
|
||||||
|
if (!item.variant_id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
item.variant = variantsMap.get(item.variant_id)
|
||||||
|
})
|
||||||
|
|
||||||
|
return cart
|
||||||
|
}
|
||||||
|
|
||||||
class GiftCard {
|
class GiftCard {
|
||||||
@IsString()
|
@IsString()
|
||||||
code: string
|
code: string
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { FlagRouter } from "@medusajs/utils"
|
import { FlagRouter } from "@medusajs/utils"
|
||||||
import { isEmpty, isEqual } from "lodash"
|
import { isEmpty, isEqual } from "lodash"
|
||||||
import { MedusaError, isDefined } from "medusa-core-utils"
|
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||||
import { DeepPartial, EntityManager, In, IsNull, Not } from "typeorm"
|
import { DeepPartial, EntityManager, In, IsNull, Not } from "typeorm"
|
||||||
import {
|
import {
|
||||||
CustomShippingOptionService,
|
|
||||||
CustomerService,
|
CustomerService,
|
||||||
|
CustomShippingOptionService,
|
||||||
DiscountService,
|
DiscountService,
|
||||||
EventBusService,
|
EventBusService,
|
||||||
GiftCardService,
|
GiftCardService,
|
||||||
@@ -29,8 +29,8 @@ import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels"
|
|||||||
import {
|
import {
|
||||||
Address,
|
Address,
|
||||||
Cart,
|
Cart,
|
||||||
CustomShippingOption,
|
|
||||||
Customer,
|
Customer,
|
||||||
|
CustomShippingOption,
|
||||||
Discount,
|
Discount,
|
||||||
DiscountRule,
|
DiscountRule,
|
||||||
DiscountRuleType,
|
DiscountRuleType,
|
||||||
@@ -49,9 +49,9 @@ import {
|
|||||||
CartCreateProps,
|
CartCreateProps,
|
||||||
CartUpdateProps,
|
CartUpdateProps,
|
||||||
FilterableCartProps,
|
FilterableCartProps,
|
||||||
|
isCart,
|
||||||
LineItemUpdate,
|
LineItemUpdate,
|
||||||
LineItemValidateData,
|
LineItemValidateData,
|
||||||
isCart,
|
|
||||||
} from "../types/cart"
|
} from "../types/cart"
|
||||||
import {
|
import {
|
||||||
AddressPayload,
|
AddressPayload,
|
||||||
@@ -1098,7 +1098,7 @@ class CartService extends TransactionBaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(cartId: string, data: CartUpdateProps): Promise<Cart> {
|
async update(cartOrId: string | Cart, data: CartUpdateProps): Promise<Cart> {
|
||||||
return await this.atomicPhase_(
|
return await this.atomicPhase_(
|
||||||
async (transactionManager: EntityManager) => {
|
async (transactionManager: EntityManager) => {
|
||||||
const cartRepo = transactionManager.withRepository(this.cartRepository_)
|
const cartRepo = transactionManager.withRepository(this.cartRepository_)
|
||||||
@@ -1117,9 +1117,11 @@ class CartService extends TransactionBaseService {
|
|||||||
"discounts.rule",
|
"discounts.rule",
|
||||||
]
|
]
|
||||||
|
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = !isString(cartOrId)
|
||||||
relations,
|
? cartOrId
|
||||||
})
|
: await this.retrieve(cartOrId, {
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
const originalCartCustomer = { ...(cart.customer ?? {}) }
|
const originalCartCustomer = { ...(cart.customer ?? {}) }
|
||||||
if (data.customer_id) {
|
if (data.customer_id) {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import {
|
|||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
ContainerRegistrationKeys,
|
ContainerRegistrationKeys,
|
||||||
ModulesSdkUtils,
|
|
||||||
isObject,
|
isObject,
|
||||||
|
ModulesSdkUtils,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { MODULE_PACKAGE_NAMES, Modules } from "./definitions"
|
import { MODULE_PACKAGE_NAMES, Modules } from "./definitions"
|
||||||
import { MedusaModule } from "./medusa-module"
|
import { MedusaModule } from "./medusa-module"
|
||||||
@@ -69,7 +69,7 @@ export async function MedusaApp({
|
|||||||
modules: Record<string, LoadedModule | LoadedModule[]>
|
modules: Record<string, LoadedModule | LoadedModule[]>
|
||||||
link: RemoteLink | undefined
|
link: RemoteLink | undefined
|
||||||
query: (
|
query: (
|
||||||
query: string | RemoteJoinerQuery,
|
query: string | RemoteJoinerQuery | object,
|
||||||
variables?: Record<string, unknown>
|
variables?: Record<string, unknown>
|
||||||
) => Promise<any>
|
) => Promise<any>
|
||||||
}> {
|
}> {
|
||||||
@@ -152,7 +152,7 @@ export async function MedusaApp({
|
|||||||
|
|
||||||
let link: RemoteLink | undefined = undefined
|
let link: RemoteLink | undefined = undefined
|
||||||
let query: (
|
let query: (
|
||||||
query: string | RemoteJoinerQuery,
|
query: string | RemoteJoinerQuery | object,
|
||||||
variables?: Record<string, unknown>
|
variables?: Record<string, unknown>
|
||||||
) => Promise<any>
|
) => Promise<any>
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ export async function MedusaApp({
|
|||||||
customRemoteFetchData: remoteFetchData,
|
customRemoteFetchData: remoteFetchData,
|
||||||
})
|
})
|
||||||
query = async (
|
query = async (
|
||||||
query: string | RemoteJoinerQuery,
|
query: string | RemoteJoinerQuery | object,
|
||||||
variables?: Record<string, unknown>
|
variables?: Record<string, unknown>
|
||||||
) => {
|
) => {
|
||||||
return await remoteQuery.query(query, variables)
|
return await remoteQuery.query(query, variables)
|
||||||
|
|||||||
Reference in New Issue
Block a user