feat(workflows,medusa,utils): add medusa v2 feature flag (#5603)
* chore: add medusa v2 feature flag * chore: cleanup more FF * chore: cleanup workflows FF * chore: add comments on broken specs * chore: added check for package registration * chore: reenable workflows FF for create order workflow * chore: disable FF on test cli db * chore: hide loader validation behind FF * chore: use medusa v2 enabled * chore: register feature flag router in use-db * chore: change to minro
This commit is contained in:
7
.changeset/selfish-planets-repeat.md
Normal file
7
.changeset/selfish-planets-repeat.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@medusajs/workflows": minor
|
||||
"@medusajs/medusa": patch
|
||||
"@medusajs/utils": minor
|
||||
---
|
||||
|
||||
feat(workflows,medusa,utils): add medusa v2 feature flag
|
||||
2
.github/workflows/test-cli-with-database.yml
vendored
2
.github/workflows/test-cli-with-database.yml
vendored
@@ -86,4 +86,4 @@ jobs:
|
||||
working-directory: ../cli-test
|
||||
|
||||
- name: Testing server
|
||||
uses: ./.github/actions/test-server
|
||||
uses: ./.github/actions/test-server
|
||||
|
||||
@@ -2,7 +2,11 @@ const path = require("path")
|
||||
|
||||
const { getConfigFile } = require("medusa-core-utils")
|
||||
const { asValue } = require("awilix")
|
||||
const { isObject, createMedusaContainer } = require("@medusajs/utils")
|
||||
const {
|
||||
isObject,
|
||||
createMedusaContainer,
|
||||
MedusaV2Flag,
|
||||
} = require("@medusajs/utils")
|
||||
const { dropDatabase } = require("pg-god")
|
||||
const { DataSource } = require("typeorm")
|
||||
const dbFactory = require("./use-template-db")
|
||||
@@ -140,27 +144,25 @@ module.exports = {
|
||||
|
||||
instance.setDb(dbDataSource)
|
||||
|
||||
const IsolateProductDomainFeatureFlag =
|
||||
require("@medusajs/medusa/dist/loaders/feature-flags/isolate-product-domain").default
|
||||
const IsolatePricingDomainFeatureFlag =
|
||||
require("@medusajs/medusa/dist/loaders/feature-flags/isolate-pricing-domain").default
|
||||
|
||||
if (
|
||||
featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key) ||
|
||||
featureFlagRouter.isFeatureEnabled(IsolatePricingDomainFeatureFlag.key)
|
||||
) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const pgConnectionLoader =
|
||||
require("@medusajs/medusa/dist/loaders/pg-connection").default
|
||||
|
||||
const featureFlagLoader =
|
||||
require("@medusajs/medusa/dist/loaders/feature-flags").default
|
||||
|
||||
const medusaAppLoader =
|
||||
require("@medusajs/medusa/dist/loaders/medusa-app").default
|
||||
|
||||
const container = createMedusaContainer()
|
||||
|
||||
const featureFlagRouter = await featureFlagLoader(configModule)
|
||||
|
||||
container.register({
|
||||
[ContainerRegistrationKeys.CONFIG_MODULE]: asValue(configModule),
|
||||
[ContainerRegistrationKeys.LOGGER]: asValue(console),
|
||||
[ContainerRegistrationKeys.MANAGER]: asValue(dbDataSource.manager),
|
||||
featureFlagRouter: asValue(featureFlagRouter),
|
||||
})
|
||||
|
||||
const pgConnection = await pgConnectionLoader({ configModule, container })
|
||||
|
||||
@@ -24,8 +24,7 @@ const adminHeaders = {
|
||||
}
|
||||
|
||||
const env = {
|
||||
MEDUSA_FF_ISOLATE_PRICING_DOMAIN: true,
|
||||
MEDUSA_FF_ISOLATE_PRODUCT_DOMAIN: true,
|
||||
MEDUSA_FF_MEDUSA_V2: true,
|
||||
}
|
||||
|
||||
describe("Link Modules", () => {
|
||||
|
||||
@@ -18,8 +18,7 @@ const adminHeaders = {
|
||||
}
|
||||
|
||||
const env = {
|
||||
MEDUSA_FF_ISOLATE_PRICING_DOMAIN: true,
|
||||
MEDUSA_FF_ISOLATE_PRODUCT_DOMAIN: true,
|
||||
MEDUSA_FF_MEDUSA_V2: true,
|
||||
}
|
||||
|
||||
describe("[Product & Pricing Module] POST /admin/products", () => {
|
||||
|
||||
@@ -7,13 +7,14 @@ import adminSeeder from "../../../../helpers/admin-seeder"
|
||||
import productSeeder from "../../../../helpers/product-seeder"
|
||||
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { Workflows } from "@medusajs/workflows"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { AxiosInstance } from "axios"
|
||||
import { getContainer } from "../../../../environment-helpers/use-container"
|
||||
import {
|
||||
simpleProductFactory,
|
||||
simpleSalesChannelFactory,
|
||||
} from "../../../../factories"
|
||||
import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types"
|
||||
|
||||
jest.setTimeout(5000000)
|
||||
|
||||
@@ -23,6 +24,10 @@ const adminHeaders = {
|
||||
},
|
||||
}
|
||||
|
||||
const env = {
|
||||
MEDUSA_FF_MEDUSA_V2: true,
|
||||
}
|
||||
|
||||
describe("/admin/products", () => {
|
||||
let dbConnection
|
||||
let shutdownServer
|
||||
@@ -30,8 +35,8 @@ describe("/admin/products", () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
|
||||
dbConnection = await initDb({ cwd })
|
||||
shutdownServer = await startBootstrapApp({ cwd })
|
||||
dbConnection = await initDb({ cwd, env })
|
||||
shutdownServer = await startBootstrapApp({ cwd, env })
|
||||
medusaContainer = getContainer()
|
||||
})
|
||||
|
||||
@@ -52,9 +57,7 @@ describe("/admin/products", () => {
|
||||
it("Should have enabled workflows feature flag", function () {
|
||||
const flagRouter = medusaContainer.resolve("featureFlagRouter")
|
||||
|
||||
const workflowsFlag = flagRouter.isFeatureEnabled({
|
||||
workflows: Workflows.CreateProducts,
|
||||
})
|
||||
const workflowsFlag = flagRouter.isFeatureEnabled(MedusaV2Flag.key)
|
||||
|
||||
expect(workflowsFlag).toBe(true)
|
||||
})
|
||||
@@ -63,6 +66,7 @@ describe("/admin/products", () => {
|
||||
beforeEach(async () => {
|
||||
await productSeeder(dbConnection)
|
||||
await adminSeeder(dbConnection)
|
||||
await createDefaultRuleTypes(medusaContainer)
|
||||
|
||||
await simpleSalesChannelFactory(dbConnection, {
|
||||
name: "Default channel",
|
||||
@@ -196,25 +200,28 @@ describe("/admin/products", () => {
|
||||
id: expect.stringMatching(/^ma_*/),
|
||||
currency_code: "usd",
|
||||
amount: 100,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
variant_id: expect.stringMatching(/^variant_*/),
|
||||
// TODO: enable this in the Pricing Module PR
|
||||
// created_at: expect.any(String),
|
||||
// updated_at: expect.any(String),
|
||||
// variant_id: expect.stringMatching(/^variant_*/),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: expect.stringMatching(/^ma_*/),
|
||||
currency_code: "eur",
|
||||
amount: 45,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
variant_id: expect.stringMatching(/^variant_*/),
|
||||
// TODO: enable this in the Pricing Module PR
|
||||
// created_at: expect.any(String),
|
||||
// updated_at: expect.any(String),
|
||||
// variant_id: expect.stringMatching(/^variant_*/),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: expect.stringMatching(/^ma_*/),
|
||||
currency_code: "dkk",
|
||||
amount: 30,
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
variant_id: expect.stringMatching(/^variant_*/),
|
||||
// TODO: enable this in the Pricing Module PR
|
||||
// created_at: expect.any(String),
|
||||
// updated_at: expect.any(String),
|
||||
// variant_id: expect.stringMatching(/^variant_*/),
|
||||
}),
|
||||
]),
|
||||
options: expect.arrayContaining([
|
||||
@@ -576,10 +583,11 @@ describe("/admin/products", () => {
|
||||
expect(response?.data.product).toEqual(
|
||||
expect.objectContaining({
|
||||
id: toUpdateWithSalesChannels,
|
||||
sales_channels: [
|
||||
expect.objectContaining({ id: "channel-2" }),
|
||||
expect.objectContaining({ id: "channel-3" }),
|
||||
],
|
||||
// TODO: Introduce this in the sale channel PR
|
||||
// sales_channels: [
|
||||
// expect.objectContaining({ id: "channel-2" }),
|
||||
// expect.objectContaining({ id: "channel-3" }),
|
||||
// ],
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
@@ -22,8 +22,7 @@ const adminHeaders = {
|
||||
}
|
||||
|
||||
const env = {
|
||||
MEDUSA_FF_ISOLATE_PRICING_DOMAIN: true,
|
||||
MEDUSA_FF_ISOLATE_PRODUCT_DOMAIN: true,
|
||||
MEDUSA_FF_MEDUSA_V2: true,
|
||||
}
|
||||
|
||||
describe("[Product & Pricing Module] POST /admin/products/:id/variants/:id", () => {
|
||||
|
||||
@@ -20,8 +20,7 @@ const adminHeaders = {
|
||||
}
|
||||
|
||||
const env = {
|
||||
MEDUSA_FF_ISOLATE_PRICING_DOMAIN: true,
|
||||
MEDUSA_FF_ISOLATE_PRODUCT_DOMAIN: true,
|
||||
MEDUSA_FF_MEDUSA_V2: true,
|
||||
}
|
||||
|
||||
describe("[Product & Pricing Module] POST /admin/products/:id", () => {
|
||||
|
||||
@@ -7,8 +7,7 @@ const DB_NAME = process.env.DB_TEMP_NAME
|
||||
const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`
|
||||
process.env.POSTGRES_URL = DB_URL
|
||||
|
||||
const enablePricing = process.env.MEDUSA_FF_ISOLATE_PRICING_DOMAIN == "true"
|
||||
const enableProduct = process.env.MEDUSA_FF_ISOLATE_PRODUCT_DOMAIN == "true"
|
||||
const enableMedusaV2 = process.env.MEDUSA_FF_MEDUSA_V2 == "true"
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
@@ -37,11 +36,8 @@ module.exports = {
|
||||
database_extra: { idle_in_transaction_session_timeout: 0 },
|
||||
},
|
||||
featureFlags: {
|
||||
isolate_product_domain: enableProduct,
|
||||
isolate_pricing_domain: enablePricing,
|
||||
medusa_v2: enableMedusaV2,
|
||||
workflows: {
|
||||
[Workflows.CreateProducts]: true,
|
||||
[Workflows.UpdateProducts]: true,
|
||||
[Workflows.CreateCart]: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { NextFunction, Request, Response } from "express"
|
||||
|
||||
import { FlagRouter } from "@medusajs/utils"
|
||||
import { FlagRouter, MedusaV2Flag } from "@medusajs/utils"
|
||||
import SalesChannelFeatureFlag from "../../loaders/feature-flags/sales-channels"
|
||||
import { SalesChannelService } from "../../services"
|
||||
import IsolateProductDomain from "../../loaders/feature-flags/isolate-product-domain"
|
||||
|
||||
/**
|
||||
* Middleware that includes the default sales channel on the request, if no sales channels present
|
||||
@@ -25,7 +24,7 @@ export function withDefaultSalesChannel(
|
||||
if (
|
||||
!featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) ||
|
||||
// Do not attach the default SC if the isolate product domain feature flag is enabled
|
||||
featureFlagRouter.isFeatureEnabled(IsolateProductDomain.key) ||
|
||||
featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) ||
|
||||
req.query.sales_channel_id?.length ||
|
||||
req.get("x-publishable-api-key")
|
||||
) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { IInventoryService, WorkflowTypes } from "@medusajs/types"
|
||||
import { createProducts, Workflows } from "@medusajs/workflows"
|
||||
import { Workflows, createProducts } from "@medusajs/workflows"
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
@@ -39,10 +39,9 @@ import {
|
||||
} from "./transaction/create-product-variant"
|
||||
|
||||
import { DistributedTransaction } from "@medusajs/orchestration"
|
||||
import { FlagRouter, promiseAll } from "@medusajs/utils"
|
||||
import { FlagRouter, MedusaV2Flag, promiseAll } from "@medusajs/utils"
|
||||
import { Type } from "class-transformer"
|
||||
import { EntityManager } from "typeorm"
|
||||
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import { ProductStatus } from "../../../../models"
|
||||
import { Logger } from "../../../../types/global"
|
||||
@@ -137,12 +136,9 @@ export default async (req, res) => {
|
||||
|
||||
const entityManager: EntityManager = req.scope.resolve("manager")
|
||||
const productModuleService = req.scope.resolve("productModuleService")
|
||||
const isMedusaV2Enabled = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)
|
||||
|
||||
const isWorkflowEnabled = featureFlagRouter.isFeatureEnabled({
|
||||
workflows: Workflows.CreateProducts,
|
||||
})
|
||||
|
||||
if (isWorkflowEnabled && !productModuleService) {
|
||||
if (isMedusaV2Enabled && !productModuleService) {
|
||||
logger.warn(
|
||||
`Cannot run ${Workflows.CreateProducts} workflow without '@medusajs/product' installed`
|
||||
)
|
||||
@@ -150,7 +146,7 @@ export default async (req, res) => {
|
||||
|
||||
let product
|
||||
|
||||
if (isWorkflowEnabled && !!productModuleService) {
|
||||
if (isMedusaV2Enabled && !!productModuleService) {
|
||||
const createProductWorkflow = createProducts(req.scope)
|
||||
|
||||
const input = {
|
||||
@@ -260,7 +256,7 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
let rawProduct
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)) {
|
||||
if (isMedusaV2Enabled) {
|
||||
rawProduct = await getProductWithIsolatedProductModule(req, product.id)
|
||||
} else {
|
||||
rawProduct = await productService.retrieve(product.id, {
|
||||
|
||||
@@ -5,8 +5,7 @@ import {
|
||||
SalesChannelService,
|
||||
} from "../../../../services"
|
||||
|
||||
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import { MedusaError, promiseAll } from "@medusajs/utils"
|
||||
import { MedusaError, MedusaV2Flag, promiseAll } from "@medusajs/utils"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
import { defaultAdminProductRemoteQueryObject } from "./index"
|
||||
|
||||
@@ -76,7 +75,7 @@ export default async (req, res) => {
|
||||
)
|
||||
|
||||
let rawProduct
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
rawProduct = await getProductWithIsolatedProductModule(
|
||||
req,
|
||||
id,
|
||||
|
||||
@@ -7,14 +7,13 @@ import {
|
||||
SalesChannelService,
|
||||
} from "../../../../services"
|
||||
|
||||
import { FilterableProductProps } from "../../../../types/product"
|
||||
import { IInventoryService } from "@medusajs/types"
|
||||
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import { PricedProduct } from "../../../../types/pricing"
|
||||
import { Product } from "../../../../models"
|
||||
import { MedusaV2Flag, promiseAll } from "@medusajs/utils"
|
||||
import { Type } from "class-transformer"
|
||||
import { Product } from "../../../../models"
|
||||
import { PricedProduct } from "../../../../types/pricing"
|
||||
import { FilterableProductProps } from "../../../../types/product"
|
||||
import { defaultAdminProductRemoteQueryObject } from "./index"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
/**
|
||||
* @oas [get] /admin/products
|
||||
@@ -248,7 +247,7 @@ export default async (req, res) => {
|
||||
let rawProducts
|
||||
let count
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const [products, count_] =
|
||||
await listAndCountProductWithIsolatedProductModule(
|
||||
req,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { DistributedTransaction } from "@medusajs/orchestration"
|
||||
import { FlagRouter, MedusaError, promiseAll } from "@medusajs/utils"
|
||||
import { updateProducts, Workflows } from "@medusajs/workflows"
|
||||
import {
|
||||
FlagRouter,
|
||||
MedusaError,
|
||||
MedusaV2Flag,
|
||||
promiseAll,
|
||||
} from "@medusajs/utils"
|
||||
import { Workflows, updateProducts } from "@medusajs/workflows"
|
||||
import { Type } from "class-transformer"
|
||||
import {
|
||||
IsArray,
|
||||
@@ -51,7 +56,6 @@ import { ProductVariantRepository } from "../../../../repositories/product-varia
|
||||
import { Logger } from "../../../../types/global"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
|
||||
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
|
||||
/**
|
||||
@@ -140,17 +144,15 @@ export default async (req, res) => {
|
||||
const productModuleService = req.scope.resolve("productModuleService")
|
||||
|
||||
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
||||
const isWorkflowEnabled = featureFlagRouter.isFeatureEnabled({
|
||||
workflows: Workflows.UpdateProducts,
|
||||
})
|
||||
const isMedusaV2Enabled = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)
|
||||
|
||||
if (isWorkflowEnabled && !productModuleService) {
|
||||
if (isMedusaV2Enabled && !productModuleService) {
|
||||
logger.warn(
|
||||
`Cannot run ${Workflows.UpdateProducts} workflow without '@medusajs/product' installed`
|
||||
)
|
||||
}
|
||||
|
||||
if (isWorkflowEnabled && !!productModuleService) {
|
||||
if (isMedusaV2Enabled) {
|
||||
const updateProductWorkflow = updateProducts(req.scope)
|
||||
|
||||
const input = {
|
||||
@@ -289,7 +291,7 @@ export default async (req, res) => {
|
||||
|
||||
let rawProduct
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)) {
|
||||
if (isMedusaV2Enabled) {
|
||||
rawProduct = await getProductWithIsolatedProductModule(req, id)
|
||||
} else {
|
||||
rawProduct = await productService.retrieve(id, {
|
||||
|
||||
@@ -13,8 +13,8 @@ import {
|
||||
} from "class-validator"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||
import IsolatePricingDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-pricing-domain"
|
||||
import {
|
||||
PricingService,
|
||||
ProductService,
|
||||
@@ -124,7 +124,7 @@ export default async (req, res) => {
|
||||
|
||||
const validatedQueryParams = await validator(PriceSelectionParams, req.query)
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolatePricingDomainFeatureFlag.key)) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const updateVariantsWorkflow = UpdateProductVariants.updateProductVariants(
|
||||
req.scope
|
||||
)
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
CartService,
|
||||
LineItemService,
|
||||
ProductVariantInventoryService,
|
||||
RegionService,
|
||||
} from "../../../../services"
|
||||
import { createCart as createCartWorkflow } from "@medusajs/workflows"
|
||||
import {
|
||||
IsArray,
|
||||
IsInt,
|
||||
@@ -13,22 +8,25 @@ import {
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { MedusaError, isDefined } from "medusa-core-utils"
|
||||
import {
|
||||
Workflows,
|
||||
createCart as createCartWorkflow,
|
||||
} from "@medusajs/workflows"
|
||||
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
|
||||
import {
|
||||
CartService,
|
||||
LineItemService,
|
||||
ProductVariantInventoryService,
|
||||
RegionService,
|
||||
} from "../../../../services"
|
||||
|
||||
import { CartCreateProps } from "../../../../types/cart"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
import { FlagRouter } from "@medusajs/utils"
|
||||
import { LineItem } from "../../../../models"
|
||||
import { MedusaContainer } from "@medusajs/modules-sdk"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import { FlagRouter } from "@medusajs/utils"
|
||||
import { Workflows } from "@medusajs/workflows"
|
||||
import { Type } from "class-transformer"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import reqIp from "request-ip"
|
||||
import { EntityManager } from "typeorm"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import { LineItem } from "../../../../models"
|
||||
import { CartCreateProps } from "../../../../types/cart"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
|
||||
/**
|
||||
* @oas [post] /store/carts
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import {
|
||||
CartService,
|
||||
ProductVariantInventoryService,
|
||||
} from "../../../../services"
|
||||
import {
|
||||
IsArray,
|
||||
IsEmail,
|
||||
@@ -10,15 +6,19 @@ import {
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
|
||||
import {
|
||||
CartService,
|
||||
ProductVariantInventoryService,
|
||||
} from "../../../../services"
|
||||
|
||||
import { AddressPayload } from "../../../../types/common"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { Type } from "class-transformer"
|
||||
import { EntityManager } from "typeorm"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import { AddressPayload } from "../../../../types/common"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import { Type } from "class-transformer"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
|
||||
/**
|
||||
* @oas [post] /store/carts/{id}
|
||||
@@ -90,7 +90,7 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
let cart
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
cart = await retrieveCartWithIsolatedProductModule(req, id)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
RegionService,
|
||||
} from "../../../../services"
|
||||
|
||||
import { MedusaError, promiseAll } from "@medusajs/utils"
|
||||
import IsolateProductDomain from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import { MedusaError, MedusaV2Flag, promiseAll } from "@medusajs/utils"
|
||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import { cleanResponseData } from "../../../../utils"
|
||||
import { defaultStoreProductRemoteQueryObject } from "./index"
|
||||
@@ -96,7 +95,7 @@ export default async (req, res) => {
|
||||
const featureFlagRouter = req.scope.resolve("featureFlagRouter")
|
||||
|
||||
let rawProduct
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomain.key)) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
rawProduct = await getProductWithIsolatedProductModule(req, id)
|
||||
} else {
|
||||
rawProduct = await productService.retrieve(id, req.retrieveConfig)
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
CartService,
|
||||
ProductService,
|
||||
ProductVariantInventoryService,
|
||||
SalesChannelService,
|
||||
} from "../../../../services"
|
||||
import { Transform, Type } from "class-transformer"
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
@@ -12,20 +7,24 @@ import {
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { Transform, Type } from "class-transformer"
|
||||
import {
|
||||
CartService,
|
||||
ProductService,
|
||||
ProductVariantInventoryService,
|
||||
SalesChannelService,
|
||||
} from "../../../../services"
|
||||
|
||||
import { DateComparisonOperator } from "../../../../types/common"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import IsolateProductDomain from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import PricingService from "../../../../services/pricing"
|
||||
import { MedusaV2Flag, promiseAll } from "@medusajs/utils"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import PricingService from "../../../../services/pricing"
|
||||
import { DateComparisonOperator } from "../../../../types/common"
|
||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import { defaultStoreCategoryScope } from "../product-categories"
|
||||
import { defaultStoreProductRemoteQueryObject } from "./index"
|
||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||
import { promiseAll } from "@medusajs/utils"
|
||||
|
||||
/**
|
||||
* @oas [get] /store/products
|
||||
@@ -252,7 +251,7 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
const isIsolateProductDomain = featureFlagRouter.isFeatureEnabled(
|
||||
IsolateProductDomain.key
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
|
||||
const promises: Promise<any>[] = []
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { FlagRouter } from "@medusajs/utils"
|
||||
import { FlagRouter, MedusaV2Flag } from "@medusajs/utils"
|
||||
import { IsBooleanString, IsOptional, IsString } from "class-validator"
|
||||
import { defaultRelations } from "."
|
||||
import IsolateProductDomainFeatureFlag from "../../../../loaders/feature-flags/isolate-product-domain"
|
||||
import {
|
||||
PricingService,
|
||||
ProductService,
|
||||
@@ -86,9 +85,7 @@ export default async (req, res) => {
|
||||
query.admin_only = false
|
||||
|
||||
if (productIds.length) {
|
||||
if (
|
||||
featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)
|
||||
) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const productShippinProfileMap =
|
||||
await shippingProfileService.getMapProfileIdsByProductIds(productIds)
|
||||
|
||||
|
||||
@@ -5,12 +5,10 @@ import getMigrations, {
|
||||
runIsolatedModulesMigration,
|
||||
} from "./utils/get-migrations"
|
||||
|
||||
import { createMedusaContainer } from "@medusajs/utils"
|
||||
import { MedusaV2Flag, createMedusaContainer } from "@medusajs/utils"
|
||||
import configModuleLoader from "../loaders/config"
|
||||
import databaseLoader from "../loaders/database"
|
||||
import featureFlagLoader from "../loaders/feature-flags"
|
||||
import IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain"
|
||||
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
|
||||
import Logger from "../loaders/logger"
|
||||
import { loadMedusaApp } from "../loaders/medusa-app"
|
||||
import pgConnectionLoader from "../loaders/pg-connection"
|
||||
@@ -71,10 +69,8 @@ const main = async function ({ directory }) {
|
||||
await dataSource.runMigrations()
|
||||
await dataSource.destroy()
|
||||
await runIsolatedModulesMigration(configModule)
|
||||
if (
|
||||
featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key) ||
|
||||
featureFlagRouter.isFeatureEnabled(IsolatePricingDomainFeatureFlag.key)
|
||||
) {
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
await runLinkMigrations(directory)
|
||||
}
|
||||
process.exit()
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import express from "express"
|
||||
import fs from "fs"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import { track } from "medusa-telemetry"
|
||||
import path from "path"
|
||||
import { DataSource, DataSourceOptions } from "typeorm"
|
||||
import loaders from "../loaders"
|
||||
import { handleConfigError } from "../loaders/config"
|
||||
import featureFlagLoader from "../loaders/feature-flags"
|
||||
import Logger from "../loaders/logger"
|
||||
import { SalesChannel } from "../models"
|
||||
import {
|
||||
ProductCategoryService,
|
||||
ProductCollectionService,
|
||||
@@ -11,25 +25,11 @@ import {
|
||||
StoreService,
|
||||
UserService,
|
||||
} from "../services"
|
||||
import getMigrations, { getModuleSharedResources } from "./utils/get-migrations"
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import express from "express"
|
||||
import fs from "fs"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import { track } from "medusa-telemetry"
|
||||
import path from "path"
|
||||
import loaders from "../loaders"
|
||||
import { handleConfigError } from "../loaders/config"
|
||||
import featureFlagLoader from "../loaders/feature-flags"
|
||||
import IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain"
|
||||
import Logger from "../loaders/logger"
|
||||
import { SalesChannel } from "../models"
|
||||
import PublishableApiKeyService from "../services/publishable-api-key"
|
||||
import { ConfigModule } from "../types/global"
|
||||
import { CreateProductInput } from "../types/product"
|
||||
import { CreateProductCategoryInput } from "../types/product-category"
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import getMigrations, { getModuleSharedResources } from "./utils/get-migrations"
|
||||
|
||||
type SeedOptions = {
|
||||
directory: string
|
||||
@@ -284,9 +284,7 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
featureFlagRouter.isFeatureEnabled(IsolatePricingDomainFeatureFlag.key)
|
||||
) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
for (const ruleType of rule_types) {
|
||||
await pricingModuleService.createRuleTypes(ruleType)
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { FlagSettings } from "../../types/feature-flags"
|
||||
|
||||
const IsolatePricingDomainFeatureFlag: FlagSettings = {
|
||||
key: "isolate_pricing_domain",
|
||||
default_val: false,
|
||||
env_key: "MEDUSA_FF_ISOLATE_PRICING_DOMAIN",
|
||||
description: "[WIP] use price module integration for pricing",
|
||||
}
|
||||
|
||||
export default IsolatePricingDomainFeatureFlag
|
||||
@@ -1,10 +0,0 @@
|
||||
import { FlagSettings } from "../../types/feature-flags"
|
||||
|
||||
const IsolateProductDomainFeatureFlag: FlagSettings = {
|
||||
key: "isolate_product_domain",
|
||||
default_val: false,
|
||||
env_key: "MEDUSA_FF_ISOLATE_PRODUCT_DOMAIN",
|
||||
description: "[WIP] Isolate product domain dependencies from the core",
|
||||
}
|
||||
|
||||
export default IsolateProductDomainFeatureFlag
|
||||
3
packages/medusa/src/loaders/feature-flags/medusa-v2.ts
Normal file
3
packages/medusa/src/loaders/feature-flags/medusa-v2.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
|
||||
export default MedusaV2Flag
|
||||
@@ -1,10 +1,3 @@
|
||||
import { FeatureFlagTypes } from "@medusajs/types"
|
||||
|
||||
const WorkflowsFeatureFlag: FeatureFlagTypes.FlagSettings = {
|
||||
key: "workflows",
|
||||
default_val: false,
|
||||
env_key: "MEDUSA_FF_WORKFLOWS",
|
||||
description: "[WIP] Enable workflows",
|
||||
}
|
||||
import { WorkflowsFeatureFlag } from "@medusajs/utils"
|
||||
|
||||
export default WorkflowsFeatureFlag
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import {
|
||||
MODULE_PACKAGE_NAMES,
|
||||
MedusaApp,
|
||||
MedusaAppOutput,
|
||||
MedusaModule,
|
||||
Modules,
|
||||
ModulesDefinition,
|
||||
} from "@medusajs/modules-sdk"
|
||||
import {
|
||||
CommonTypes,
|
||||
InternalModuleDeclaration,
|
||||
MedusaContainer,
|
||||
ModuleDefinition,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
MedusaApp,
|
||||
MedusaAppOutput,
|
||||
ModulesDefinition,
|
||||
} from "@medusajs/modules-sdk"
|
||||
import { FlagRouter, MedusaV2Flag } from "@medusajs/utils"
|
||||
|
||||
import { ContainerRegistrationKeys, isObject } from "@medusajs/utils"
|
||||
import { asValue } from "awilix"
|
||||
import { joinerConfig } from "../joiner-config"
|
||||
import { remoteQueryFetchData } from ".."
|
||||
import { joinerConfig } from "../joiner-config"
|
||||
|
||||
export function mergeDefaultModules(
|
||||
modulesConfig: CommonTypes.ConfigModule["modules"]
|
||||
@@ -46,6 +50,8 @@ export const loadMedusaApp = async (
|
||||
},
|
||||
config = { registerInContainer: true }
|
||||
): Promise<MedusaAppOutput> => {
|
||||
const featureFlagRouter = container.resolve<FlagRouter>("featureFlagRouter")
|
||||
const isMedusaV2Enabled = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)
|
||||
const injectedDependencies = {
|
||||
[ContainerRegistrationKeys.PG_CONNECTION]: container.resolve(
|
||||
ContainerRegistrationKeys.PG_CONNECTION
|
||||
@@ -94,6 +100,30 @@ export const loadMedusaApp = async (
|
||||
injectedDependencies,
|
||||
})
|
||||
|
||||
const requiredModuleKeys = [Modules.PRODUCT, Modules.PRICING]
|
||||
|
||||
const missingPackages: string[] = []
|
||||
|
||||
if (isMedusaV2Enabled) {
|
||||
for (const requiredModuleKey of requiredModuleKeys) {
|
||||
const isModuleInstalled = MedusaModule.isInstalled(requiredModuleKey)
|
||||
|
||||
if (!isModuleInstalled) {
|
||||
missingPackages.push(
|
||||
MODULE_PACKAGE_NAMES[requiredModuleKey] || requiredModuleKey
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (missingPackages.length) {
|
||||
throw new Error(
|
||||
`FeatureFlag medusa_v2 (MEDUSA_FF_MEDUSA_V2) requires the following packages/module registration: (${missingPackages.join(
|
||||
", "
|
||||
)})`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.registerInContainer) {
|
||||
return medusaApp
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
import IsolateProductDomain from "../loaders/feature-flags/isolate-product-domain"
|
||||
|
||||
export const featureFlag = IsolateProductDomain.key
|
||||
export const featureFlag = MedusaV2Flag.key
|
||||
|
||||
export class LineItemProductId1692870898424 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
import IsolateProductDomain from "../loaders/feature-flags/isolate-product-domain"
|
||||
|
||||
export const featureFlag = IsolateProductDomain.key
|
||||
export const featureFlag = MedusaV2Flag.key
|
||||
|
||||
export class AddTimestempsToProductShippingProfiles1692870898425
|
||||
implements MigrationInterface
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
|
||||
import IsolateProductDomain from "../loaders/feature-flags/isolate-product-domain"
|
||||
|
||||
export const featureFlag = IsolateProductDomain.key
|
||||
export const featureFlag = MedusaV2Flag.key
|
||||
|
||||
export class dropFksIsolatedProducts1694602553610
|
||||
implements MigrationInterface
|
||||
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
OneToMany,
|
||||
} from "typeorm"
|
||||
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { BaseEntity } from "../interfaces"
|
||||
import { featureFlagRouter } from "../loaders/feature-flags"
|
||||
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
|
||||
import { DbAwareColumn, generateEntityId } from "../utils"
|
||||
import {
|
||||
@@ -27,8 +29,6 @@ import { Order } from "./order"
|
||||
import { OrderEdit } from "./order-edit"
|
||||
import { ProductVariant } from "./product-variant"
|
||||
import { Swap } from "./swap"
|
||||
import IsolateProductDomain from "../loaders/feature-flags/isolate-product-domain"
|
||||
import { featureFlagRouter } from "../loaders/feature-flags"
|
||||
|
||||
@Check(`"fulfilled_quantity" <= "quantity"`)
|
||||
@Check(`"shipped_quantity" <= "fulfilled_quantity"`)
|
||||
@@ -131,7 +131,7 @@ export class LineItem extends BaseEntity {
|
||||
@JoinColumn({ name: "variant_id" })
|
||||
variant: ProductVariant
|
||||
|
||||
@FeatureFlagColumn(IsolateProductDomain.key, { nullable: true, type: "text" })
|
||||
@FeatureFlagColumn(MedusaV2Flag.key, { nullable: true, type: "text" })
|
||||
product_id: string | null
|
||||
|
||||
@Column({ type: "int" })
|
||||
@@ -170,7 +170,7 @@ export class LineItem extends BaseEntity {
|
||||
this.id = generateEntityId(this.id, "item")
|
||||
|
||||
// This is to maintain compatibility while isolating the product domain
|
||||
if (featureFlagRouter.isFeatureEnabled(IsolateProductDomain.key)) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
if (
|
||||
this.variant &&
|
||||
Object.keys(this.variant).length === 1 &&
|
||||
@@ -184,7 +184,7 @@ export class LineItem extends BaseEntity {
|
||||
/**
|
||||
* @apiIgnore
|
||||
*/
|
||||
@FeatureFlagDecorators(IsolateProductDomain.key, [BeforeUpdate()])
|
||||
@FeatureFlagDecorators(MedusaV2Flag.key, [BeforeUpdate()])
|
||||
beforeUpdate(): void {
|
||||
if (
|
||||
this.variant &&
|
||||
@@ -198,7 +198,7 @@ export class LineItem extends BaseEntity {
|
||||
/**
|
||||
* @apiIgnore
|
||||
*/
|
||||
@FeatureFlagDecorators(IsolateProductDomain.key, [AfterLoad(), AfterUpdate()])
|
||||
@FeatureFlagDecorators(MedusaV2Flag.key, [AfterLoad(), AfterUpdate()])
|
||||
afterUpdateOrLoad(): void {
|
||||
if (this.variant) {
|
||||
return
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { MedusaModule, Modules } from "@medusajs/modules-sdk"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { DeleteResult, EntityTarget, In, Not } from "typeorm"
|
||||
import { dataSource } from "../loaders/database"
|
||||
import { featureFlagRouter } from "../loaders/feature-flags"
|
||||
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
|
||||
import {
|
||||
Discount,
|
||||
DiscountCondition,
|
||||
@@ -229,7 +229,7 @@ export const DiscountConditionRepository = dataSource
|
||||
|
||||
if (
|
||||
type !== DiscountConditionType.CUSTOMER_GROUPS &&
|
||||
featureFlagRouter.isFeatureEnabled(IsolateProductDomainFeatureFlag.key)
|
||||
featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)
|
||||
) {
|
||||
const module = MedusaModule.getModuleInstance(Modules.PRODUCT)[
|
||||
Modules.PRODUCT
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { FlagRouter, MedusaError, promiseAll } from "@medusajs/utils"
|
||||
import { IPricingModuleService, MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
FlagRouter,
|
||||
MedusaError,
|
||||
MedusaV2Flag,
|
||||
promiseAll,
|
||||
} from "@medusajs/utils"
|
||||
import dotenv from "dotenv"
|
||||
import express from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
import IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain"
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import loaders from "../loaders"
|
||||
import loadMedusaApp from "../loaders/medusa-app"
|
||||
import { ProductVariant } from "../models"
|
||||
import { ProductVariantService } from "../services"
|
||||
import { createDefaultRuleTypes } from "./create-default-rule-types"
|
||||
import dotenv from "dotenv"
|
||||
import express from "express"
|
||||
import loadMedusaApp from "../loaders/medusa-app"
|
||||
import loaders from "../loaders"
|
||||
|
||||
dotenv.config()
|
||||
|
||||
@@ -93,10 +96,7 @@ const migrate = async function ({ directory }) {
|
||||
"featureFlagRouter"
|
||||
)
|
||||
|
||||
if (
|
||||
!featureFlagRouter.isFeatureEnabled(IsolatePricingDomainFeatureFlag.key) &&
|
||||
!featureFlagRouter.isFeatureEnabled(Modules.PRICING)
|
||||
) {
|
||||
if (!featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Pricing module not enabled"
|
||||
|
||||
@@ -1,34 +1,12 @@
|
||||
import { FlagRouter, isDefined, MedusaError, promiseAll } from "@medusajs/utils"
|
||||
import {
|
||||
FlagRouter,
|
||||
isDefined,
|
||||
MedusaError,
|
||||
MedusaV2Flag,
|
||||
promiseAll,
|
||||
} from "@medusajs/utils"
|
||||
import { isEmpty, isEqual } from "lodash"
|
||||
import { DeepPartial, EntityManager, In, IsNull, Not } from "typeorm"
|
||||
import {
|
||||
Address,
|
||||
Cart,
|
||||
Customer,
|
||||
CustomShippingOption,
|
||||
Discount,
|
||||
DiscountRule,
|
||||
DiscountRuleType,
|
||||
LineItem,
|
||||
PaymentSession,
|
||||
PaymentSessionStatus,
|
||||
SalesChannel,
|
||||
ShippingMethod,
|
||||
} from "../models"
|
||||
import {
|
||||
AddressPayload,
|
||||
FindConfig,
|
||||
TotalField,
|
||||
WithRequiredProperty,
|
||||
} from "../types/common"
|
||||
import {
|
||||
CartCreateProps,
|
||||
CartUpdateProps,
|
||||
FilterableCartProps,
|
||||
isCart,
|
||||
LineItemUpdate,
|
||||
LineItemValidateData,
|
||||
} from "../types/cart"
|
||||
import {
|
||||
CustomerService,
|
||||
CustomShippingOptionService,
|
||||
@@ -52,16 +30,43 @@ import {
|
||||
TotalsService,
|
||||
} from "."
|
||||
import { IPriceSelectionStrategy, TransactionBaseService } from "../interfaces"
|
||||
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
|
||||
import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels"
|
||||
import {
|
||||
Address,
|
||||
Cart,
|
||||
Customer,
|
||||
CustomShippingOption,
|
||||
Discount,
|
||||
DiscountRule,
|
||||
DiscountRuleType,
|
||||
LineItem,
|
||||
PaymentSession,
|
||||
PaymentSessionStatus,
|
||||
SalesChannel,
|
||||
ShippingMethod,
|
||||
} from "../models"
|
||||
import {
|
||||
CartCreateProps,
|
||||
CartUpdateProps,
|
||||
FilterableCartProps,
|
||||
isCart,
|
||||
LineItemUpdate,
|
||||
LineItemValidateData,
|
||||
} from "../types/cart"
|
||||
import {
|
||||
AddressPayload,
|
||||
FindConfig,
|
||||
TotalField,
|
||||
WithRequiredProperty,
|
||||
} from "../types/common"
|
||||
import { buildQuery, isString, setMetadata } from "../utils"
|
||||
|
||||
import { AddressRepository } from "../repositories/address"
|
||||
import { CartRepository } from "../repositories/cart"
|
||||
import { LineItemRepository } from "../repositories/line-item"
|
||||
import { PaymentSessionInput } from "../types/payment"
|
||||
import { PaymentSessionRepository } from "../repositories/payment-session"
|
||||
import { ShippingMethodRepository } from "../repositories/shipping-method"
|
||||
import { PaymentSessionInput } from "../types/payment"
|
||||
import { validateEmail } from "../utils/is-email"
|
||||
|
||||
type InjectedDependencies = {
|
||||
@@ -233,11 +238,7 @@ class CartService extends TransactionBaseService {
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
this.featureFlagRouter_.isFeatureEnabled(
|
||||
IsolateProductDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
if (Array.isArray(options.relations)) {
|
||||
for (let i = 0; i < options.relations.length; i++) {
|
||||
if (options.relations[i].startsWith("items.variant")) {
|
||||
@@ -321,11 +322,7 @@ class CartService extends TransactionBaseService {
|
||||
|
||||
const opt = { ...options, relations }
|
||||
|
||||
if (
|
||||
this.featureFlagRouter_.isFeatureEnabled(
|
||||
IsolateProductDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
if (Array.isArray(opt.relations)) {
|
||||
for (let i = 0; i < opt.relations.length; i++) {
|
||||
if (opt.relations[i].startsWith("items.variant")) {
|
||||
@@ -2243,11 +2240,7 @@ class CartService extends TransactionBaseService {
|
||||
|
||||
let productShippinProfileMap = new Map<string, string>()
|
||||
|
||||
if (
|
||||
this.featureFlagRouter_.isFeatureEnabled(
|
||||
IsolateProductDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
productShippinProfileMap =
|
||||
await this.shippingProfileService_.getMapProfileIdsByProductIds(
|
||||
cart.items.map((item) => item.variant.product_id)
|
||||
|
||||
@@ -2,9 +2,8 @@ import { MedusaError } from "medusa-core-utils"
|
||||
import { EntityManager, In } from "typeorm"
|
||||
import { DeepPartial } from "typeorm/common/DeepPartial"
|
||||
|
||||
import { FlagRouter } from "@medusajs/utils"
|
||||
import { FlagRouter, MedusaV2Flag } from "@medusajs/utils"
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
|
||||
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
|
||||
import {
|
||||
LineItem,
|
||||
@@ -385,11 +384,7 @@ class LineItemService extends TransactionBaseService {
|
||||
should_merge: shouldMerge,
|
||||
}
|
||||
|
||||
if (
|
||||
this.featureFlagRouter_.isFeatureEnabled(
|
||||
IsolateProductDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
rawLineItem.product_id = variant.product_id
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,13 @@ import {
|
||||
PriceSetMoneyAmountDTO,
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/types"
|
||||
import { FlagRouter, promiseAll, removeNullish } from "@medusajs/utils"
|
||||
import {
|
||||
FlagRouter,
|
||||
MedusaV2Flag,
|
||||
promiseAll,
|
||||
removeNullish,
|
||||
} from "@medusajs/utils"
|
||||
import { ProductVariantService, RegionService, TaxProviderService } from "."
|
||||
import {
|
||||
IPriceSelectionStrategy,
|
||||
PriceSelectionContext,
|
||||
@@ -24,15 +30,12 @@ import {
|
||||
ProductVariantPricing,
|
||||
TaxedPricing,
|
||||
} from "../types/pricing"
|
||||
import { ProductVariantService, RegionService, TaxProviderService } from "."
|
||||
|
||||
import { EntityManager } from "typeorm"
|
||||
import IsolatePricingDomainFeatureFlag from "../loaders/feature-flags/isolate-pricing-domain"
|
||||
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
|
||||
import { TaxServiceRate } from "../types/tax-service"
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import { calculatePriceTaxAmount } from "../utils"
|
||||
|
||||
type InjectedDependencies = {
|
||||
@@ -275,14 +278,7 @@ class PricingService extends TransactionBaseService {
|
||||
}[],
|
||||
context: PricingContext
|
||||
): Promise<Map<string, ProductVariantPricing>> {
|
||||
if (
|
||||
this.featureFlagRouter.isFeatureEnabled(
|
||||
IsolateProductDomainFeatureFlag.key
|
||||
) &&
|
||||
this.featureFlagRouter.isFeatureEnabled(
|
||||
IsolatePricingDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (this.featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
return await this.getProductVariantPricingModulePricing_(data, context)
|
||||
}
|
||||
|
||||
@@ -718,11 +714,7 @@ class PricingService extends TransactionBaseService {
|
||||
variants: ProductVariant[],
|
||||
context: PriceSelectionContext = {}
|
||||
): Promise<PricedVariant[]> {
|
||||
if (
|
||||
!this.featureFlagRouter.isFeatureEnabled(
|
||||
IsolatePricingDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (!this.featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
return await this.setVariantPrices(variants, context)
|
||||
}
|
||||
|
||||
@@ -754,11 +746,7 @@ class PricingService extends TransactionBaseService {
|
||||
async setAdminProductPricing(
|
||||
products: Product[]
|
||||
): Promise<(Product | PricedProduct)[]> {
|
||||
if (
|
||||
!this.featureFlagRouter.isFeatureEnabled(
|
||||
IsolatePricingDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (!this.featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
return await this.setProductPrices(products)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { FlagRouter, isDefined, promiseAll } from "@medusajs/utils"
|
||||
import {
|
||||
FlagRouter,
|
||||
MedusaV2Flag,
|
||||
isDefined,
|
||||
promiseAll,
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { EntityManager, In } from "typeorm"
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import IsolateProductDomainFeatureFlag from "../loaders/feature-flags/isolate-product-domain"
|
||||
import {
|
||||
Cart,
|
||||
CustomShippingOption,
|
||||
@@ -518,11 +522,7 @@ class ShippingProfileService extends TransactionBaseService {
|
||||
protected async getProfilesInCart(cart: Cart): Promise<string[]> {
|
||||
let profileIds = new Set<string>()
|
||||
|
||||
if (
|
||||
this.featureFlagRouter_.isFeatureEnabled(
|
||||
IsolateProductDomainFeatureFlag.key
|
||||
)
|
||||
) {
|
||||
if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const productShippinProfileMap = await this.getMapProfileIdsByProductIds(
|
||||
cart.items.map((item) => item.variant?.product_id)
|
||||
)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export * from "./analytics"
|
||||
export * from "./many-to-many-inventory"
|
||||
export * from "./medusa-v2"
|
||||
export * from "./order-editing"
|
||||
export * from "./product-categories"
|
||||
export * from "./publishable-api-keys"
|
||||
@@ -6,4 +8,3 @@ export * from "./sales-channels"
|
||||
export * from "./tax-inclusive-pricing"
|
||||
export * from "./utils"
|
||||
export * from "./workflows"
|
||||
export * from "./many-to-many-inventory"
|
||||
|
||||
8
packages/utils/src/feature-flags/medusa-v2.ts
Normal file
8
packages/utils/src/feature-flags/medusa-v2.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { FeatureFlagTypes } from "@medusajs/types"
|
||||
|
||||
export const MedusaV2Flag: FeatureFlagTypes.FlagSettings = {
|
||||
key: "medusa_v2",
|
||||
default_val: false,
|
||||
env_key: "MEDUSA_FF_MEDUSA_V2",
|
||||
description: "[WIP] Enable Medusa V2",
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
import { FlagRouter } from "../flag-router"
|
||||
|
||||
const someFlag = {
|
||||
key: "some_flag",
|
||||
default_val: false,
|
||||
env_key: "MEDUSA_FF_SOME_FLAG",
|
||||
description: "[WIP] Enable some flag",
|
||||
}
|
||||
|
||||
const workflows = {
|
||||
key: "workflows",
|
||||
default_val: {},
|
||||
env_key: "MEDUSA_FF_WORKFLOWS",
|
||||
description: "[WIP] Enable workflows",
|
||||
}
|
||||
|
||||
describe("FlagRouter", function () {
|
||||
it("should set a top-level flag", async function () {
|
||||
const flagRouter = new FlagRouter({})
|
||||
|
||||
flagRouter.setFlag(someFlag.key, true)
|
||||
|
||||
expect(flagRouter.listFlags()).toEqual([
|
||||
{
|
||||
key: someFlag.key,
|
||||
value: true,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should set a nested flag", async function () {
|
||||
const flagRouter = new FlagRouter({})
|
||||
|
||||
flagRouter.setFlag(workflows.key, { createCart: true })
|
||||
|
||||
expect(flagRouter.listFlags()).toEqual([
|
||||
{
|
||||
key: workflows.key,
|
||||
value: {
|
||||
createCart: true,
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should append to a nested flag", async function () {
|
||||
const flagRouter = new FlagRouter({})
|
||||
|
||||
flagRouter.setFlag(workflows.key, { createCart: true })
|
||||
flagRouter.setFlag(workflows.key, { addShippingMethod: true })
|
||||
|
||||
expect(flagRouter.listFlags()).toEqual([
|
||||
{
|
||||
key: workflows.key,
|
||||
value: {
|
||||
createCart: true,
|
||||
addShippingMethod: true,
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should check if top-level flag is enabled", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[someFlag.key]: true,
|
||||
})
|
||||
|
||||
const isEnabled = flagRouter.isFeatureEnabled(someFlag.key)
|
||||
|
||||
expect(isEnabled).toEqual(true)
|
||||
})
|
||||
|
||||
it("should check if nested flag is enabled", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[workflows.key]: {
|
||||
createCart: true,
|
||||
},
|
||||
})
|
||||
|
||||
const isEnabled = flagRouter.isFeatureEnabled({ workflows: "createCart" })
|
||||
|
||||
expect(isEnabled).toEqual(true)
|
||||
})
|
||||
|
||||
it("should check if nested flag is enabled using top-level access", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[workflows.key]: {
|
||||
createCart: true,
|
||||
},
|
||||
})
|
||||
|
||||
const isEnabled = flagRouter.isFeatureEnabled(workflows.key)
|
||||
|
||||
expect(isEnabled).toEqual(true)
|
||||
})
|
||||
|
||||
it("should return true if top-level is enabled using nested-level access", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[workflows.key]: true,
|
||||
})
|
||||
|
||||
const isEnabled = flagRouter.isFeatureEnabled({
|
||||
[workflows.key]: "createCart",
|
||||
})
|
||||
|
||||
expect(isEnabled).toEqual(true)
|
||||
})
|
||||
|
||||
it("should return false if flag is disabled using top-level access", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[workflows.key]: false,
|
||||
})
|
||||
|
||||
const isEnabled = flagRouter.isFeatureEnabled(workflows.key)
|
||||
|
||||
expect(isEnabled).toEqual(false)
|
||||
})
|
||||
|
||||
it("should return false if nested flag is disabled", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[workflows.key]: {
|
||||
createCart: false,
|
||||
},
|
||||
})
|
||||
|
||||
const isEnabled = flagRouter.isFeatureEnabled({ workflows: "createCart" })
|
||||
|
||||
expect(isEnabled).toEqual(false)
|
||||
})
|
||||
|
||||
it("should initialize with both types of flags", async function () {
|
||||
const flagRouter = new FlagRouter({
|
||||
[workflows.key]: {
|
||||
createCart: true,
|
||||
},
|
||||
[someFlag.key]: true,
|
||||
})
|
||||
|
||||
const flags = flagRouter.listFlags()
|
||||
|
||||
expect(flags).toEqual([
|
||||
{
|
||||
key: workflows.key,
|
||||
value: {
|
||||
createCart: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: someFlag.key,
|
||||
value: true,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PricingTypes } from "@medusajs/types"
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type HandlerInput = {
|
||||
@@ -20,7 +21,7 @@ export async function revertVariantPrices({
|
||||
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const isPricingDomainEnabled = featureFlagRouter.isFeatureEnabled(
|
||||
"isolate_pricing_domain"
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
|
||||
if (!isPricingDomainEnabled) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Modules, ModulesDefinition } from "@medusajs/modules-sdk"
|
||||
import { ProductTypes, ProductWorkflow, WorkflowTypes } from "@medusajs/types"
|
||||
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type VariantPrice = {
|
||||
@@ -27,7 +27,7 @@ export async function updateProductVariantsPrepareData({
|
||||
}: WorkflowArguments<WorkflowTypes.ProductWorkflow.UpdateProductVariantsWorkflowInputDTO>): Promise<UpdateProductVariantsPreparedData> {
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const isPricingDomainEnabled = featureFlagRouter.isFeatureEnabled(
|
||||
"isolate_pricing_domain"
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
let productVariants: ProductWorkflow.UpdateProductVariantsInputDTO[] =
|
||||
data.productVariants || []
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ProductDTO, SalesChannelDTO, WorkflowTypes } from "@medusajs/types"
|
||||
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type ProductWithSalesChannelsDTO = ProductDTO & {
|
||||
@@ -28,7 +28,7 @@ export async function updateProductsPrepareData({
|
||||
}: WorkflowArguments<WorkflowTypes.ProductWorkflow.UpdateProductsWorkflowInputDTO>): Promise<UpdateProductsPreparedData> {
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
const isPricingDomainEnabled = featureFlagRouter.isFeatureEnabled(
|
||||
"isolate_pricing_domain"
|
||||
MedusaV2Flag.key
|
||||
)
|
||||
|
||||
const variantPricesMap = new Map<string, VariantPrice[]>()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ProductTypes, WorkflowTypes } from "@medusajs/types"
|
||||
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { MedusaError, MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type ProductHandle = string
|
||||
type VariantIndexAndPrices = {
|
||||
@@ -99,7 +99,7 @@ export async function updateProductsVariantsPrices({
|
||||
}
|
||||
}
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled("isolate_pricing_domain")) {
|
||||
if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
const remoteLink = container.resolve("remoteLink")
|
||||
const pricingModuleService = container.resolve(
|
||||
ModuleRegistrationName.PRICING
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PricingTypes } from "@medusajs/types"
|
||||
|
||||
import { MedusaV2Flag } from "@medusajs/utils"
|
||||
import { WorkflowArguments } from "../../helper"
|
||||
|
||||
type VariantPrice = {
|
||||
@@ -29,8 +29,8 @@ export async function upsertVariantPrices({
|
||||
const { variantPricesMap } = data
|
||||
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
|
||||
if (!featureFlagRouter.isFeatureEnabled("isolate_pricing_domain")) {
|
||||
|
||||
if (!featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) {
|
||||
return {
|
||||
createdLinks: [],
|
||||
originalMoneyAmounts: [],
|
||||
|
||||
Reference in New Issue
Block a user