diff --git a/.changeset/real-teachers-yawn.md b/.changeset/real-teachers-yawn.md new file mode 100644 index 0000000000000..37a5f48bf39b6 --- /dev/null +++ b/.changeset/real-teachers-yawn.md @@ -0,0 +1,8 @@ +--- +"@medusajs/medusa": patch +"medusa-test-utils": patch +"@medusajs/product": patch +"@medusajs/types": patch +--- + +feat(fulfillment): implementation part 2 diff --git a/packages/auth/integration-tests/utils/database.ts b/packages/auth/integration-tests/utils/database.ts index c510b64d39455..2b708a0eb7ffa 100644 --- a/packages/auth/integration-tests/utils/database.ts +++ b/packages/auth/integration-tests/utils/database.ts @@ -5,14 +5,14 @@ import { TestDatabaseUtils } from "medusa-test-utils" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = AuthModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/cart/integration-tests/utils/database.ts b/packages/cart/integration-tests/utils/database.ts index c385f6d4b4bc4..1fc3ae99c0438 100644 --- a/packages/cart/integration-tests/utils/database.ts +++ b/packages/cart/integration-tests/utils/database.ts @@ -5,14 +5,14 @@ import * as CartModels from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = CartModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/customer/integration-tests/utils/database.ts b/packages/customer/integration-tests/utils/database.ts index 118464d4d76a0..284863d2c7297 100644 --- a/packages/customer/integration-tests/utils/database.ts +++ b/packages/customer/integration-tests/utils/database.ts @@ -5,14 +5,14 @@ import * as Models from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = Models as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/fulfillment/integration-tests/__fixtures__/index.ts b/packages/fulfillment/integration-tests/__fixtures__/index.ts deleted file mode 100644 index 172f1ae6a468c..0000000000000 --- a/packages/fulfillment/integration-tests/__fixtures__/index.ts +++ /dev/null @@ -1 +0,0 @@ -// noop diff --git a/packages/fulfillment/integration-tests/__tests__/fulfillment-module-service.spec.ts b/packages/fulfillment/integration-tests/__tests__/fulfillment-module-service.spec.ts index eb85670c2e6e4..5922f8e9b60af 100644 --- a/packages/fulfillment/integration-tests/__tests__/fulfillment-module-service.spec.ts +++ b/packages/fulfillment/integration-tests/__tests__/fulfillment-module-service.spec.ts @@ -1,921 +1,1433 @@ import { Modules } from "@medusajs/modules-sdk" -import { initModules } from "medusa-test-utils/dist" import { CreateFulfillmentSetDTO, CreateGeoZoneDTO, CreateServiceZoneDTO, + CreateShippingOptionDTO, + CreateShippingProfileDTO, GeoZoneDTO, IFulfillmentModuleService, ServiceZoneDTO, UpdateFulfillmentSetDTO, UpdateGeoZoneDTO, + UpdateServiceZoneDTO, } from "@medusajs/types" -import { getInitModuleConfig, MikroOrmWrapper } from "../utils" import { GeoZoneType } from "@medusajs/utils" +import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils" + +jest.setTimeout(100000) + +moduleIntegrationTestRunner({ + moduleName: Modules.FULFILLMENT, + testSuite: ({ + MikroOrmWrapper, + service, + }: SuiteOptions) => { + describe("Fulfillment Module Service", () => { + describe("read", () => { + describe("fulfillment set", () => { + it("should list fulfillment sets with a filter", async function () { + const createdSet1 = await service.create({ + name: "test", + type: "test-type", + }) + const createdSet2 = await service.create({ + name: "test2", + type: "test-type", + service_zones: [ + { + name: "test", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], + }) -describe("fulfillment module service", function () { - let service: IFulfillmentModuleService - let shutdownFunc: () => Promise - - beforeAll(async () => { - const initModulesConfig = getInitModuleConfig() + let listedSets = await service.list({ + type: createdSet1.type, + }) - const { medusaApp, shutdown } = await initModules(initModulesConfig) + expect(listedSets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet1.id }), + expect.objectContaining({ id: createdSet2.id }), + ]) + ) - service = medusaApp.modules[Modules.FULFILLMENT] + listedSets = await service.list({ + name: createdSet2.name, + }) - shutdownFunc = shutdown - }) + expect(listedSets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet2.id }), + ]) + ) + expect(listedSets).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet1.id }), + ]) + ) + + listedSets = await service.list({ + service_zones: { name: "test" }, + }) - beforeEach(async () => { - await MikroOrmWrapper.setupDatabase() - }) + expect(listedSets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet2.id }), + ]) + ) + expect(listedSets).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet1.id }), + ]) + ) + + listedSets = await service.list({ + service_zones: { geo_zones: { country_code: "fr" } }, + }) - afterEach(async () => { - await MikroOrmWrapper.clearDatabase() - }) + expect(listedSets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet2.id }), + ]) + ) + expect(listedSets).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdSet1.id }), + ]) + ) + }) + }) - afterAll(async () => { - await shutdownFunc() - }) + describe("service zones", () => { + it("should list service zones with a filter", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) - describe("read", () => { - describe("fulfillment set", () => { - it("should list fulfillment sets with a filter", async function () { - const createdSet1 = await service.create({ - name: "test", - type: "test-type", - }) - const createdSet2 = await service.create({ - name: "test2", - type: "test-type", - service_zones: [ - { + const createdZone1 = await service.createServiceZones({ name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + const createdZone2 = await service.createServiceZones({ + name: "test2", + fulfillment_set_id: fulfillmentSet.id, geo_zones: [ { type: GeoZoneType.COUNTRY, country_code: "fr", }, ], - }, - ], - }) + }) - let listedSets = await service.list({ type: createdSet1.type }) - - expect(listedSets).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet1.id }), - expect.objectContaining({ id: createdSet2.id }), - ]) - ) - - listedSets = await service.list({ name: createdSet2.name }) - - expect(listedSets).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet2.id }), - ]) - ) - expect(listedSets).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet1.id }), - ]) - ) - - listedSets = await service.list({ service_zones: { name: "test" } }) - - expect(listedSets).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet2.id }), - ]) - ) - expect(listedSets).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet1.id }), - ]) - ) - - listedSets = await service.list({ - service_zones: { geo_zones: { country_code: "fr" } }, - }) + let listedZones = await service.listServiceZones({ + name: createdZone2.name, + }) - expect(listedSets).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet2.id }), - ]) - ) - expect(listedSets).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdSet1.id }), - ]) - ) - }) - }) + expect(listedZones).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone2.id }), + ]) + ) + expect(listedZones).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone1.id }), + ]) + ) + + listedZones = await service.listServiceZones({ + geo_zones: { country_code: "fr" }, + }) - describe("service zones", () => { - it("should list service zones with a filter", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", + expect(listedZones).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone2.id }), + ]) + ) + expect(listedZones).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone1.id }), + ]) + ) + }) }) - const createdZone1 = await service.createServiceZones({ - name: "test", - fulfillment_set_id: fulfillmentSet.id, - }) - const createdZone2 = await service.createServiceZones({ - name: "test2", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { + describe("geo zones", () => { + it("should list geo zones with a filter", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + + const createdZone1 = await service.createGeoZones({ + service_zone_id: serviceZone.id, type: GeoZoneType.COUNTRY, country_code: "fr", - }, - ], - }) + }) + const createdZone2 = await service.createGeoZones({ + service_zone_id: serviceZone.id, + type: GeoZoneType.COUNTRY, + country_code: "us", + }) - let listedZones = await service.listServiceZones({ - name: createdZone2.name, - }) + let listedZones = await service.listGeoZones({ + type: createdZone1.type, + }) - expect(listedZones).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone2.id }), - ]) - ) - expect(listedZones).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone1.id }), - ]) - ) - - listedZones = await service.listServiceZones({ - geo_zones: { country_code: "fr" }, - }) + expect(listedZones).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone1.id }), + expect.objectContaining({ id: createdZone2.id }), + ]) + ) - expect(listedZones).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone2.id }), - ]) - ) - expect(listedZones).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone1.id }), - ]) - ) - }) - }) + listedZones = await service.listGeoZones({ + country_code: createdZone2.country_code, + }) - describe("geo zones", () => { - it("should list geo zones with a filter", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - const serviceZone = await service.createServiceZones({ - name: "test", - fulfillment_set_id: fulfillmentSet.id, + expect(listedZones).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone2.id }), + ]) + ) + expect(listedZones).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: createdZone1.id }), + ]) + ) + }) }) + }) - const createdZone1 = await service.createGeoZones({ - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "fr", - }) - const createdZone2 = await service.createGeoZones({ - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "us", - }) + describe("mutations", () => { + describe("on create", () => { + it("should create a new fulfillment set", async function () { + const data: CreateFulfillmentSetDTO = { + name: "test", + type: "test-type", + } - let listedZones = await service.listGeoZones({ - type: createdZone1.type, - }) + const fulfillmentSet = await service.create(data) - expect(listedZones).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone1.id }), - expect.objectContaining({ id: createdZone2.id }), - ]) - ) + expect(fulfillmentSet).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data.name, + type: data.type, + }) + ) + }) - listedZones = await service.listGeoZones({ - country_code: createdZone2.country_code, - }) + it("should create a collection of fulfillment sets", async function () { + const data = [ + { + name: "test", + type: "test-type", + }, + { + name: "test2", + type: "test-type2", + }, + ] - expect(listedZones).toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone2.id }), - ]) - ) - expect(listedZones).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ id: createdZone1.id }), - ]) - ) - }) - }) - }) - - describe("mutations", () => { - describe("on create", () => { - it("should create a new fulfillment set", async function () { - const data: CreateFulfillmentSetDTO = { - name: "test", - type: "test-type", - } - - const fulfillmentSet = await service.create(data) - - expect(fulfillmentSet).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data.name, - type: data.type, + const fulfillmentSets = await service.create(data) + + expect(fulfillmentSets).toHaveLength(2) + + let i = 0 + for (const data_ of data) { + expect(fulfillmentSets[i]).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data_.name, + type: data_.type, + }) + ) + ++i + } }) - ) - }) - it("should create a collection of fulfillment sets", async function () { - const data = [ - { - name: "test", - type: "test-type", - }, - { - name: "test2", - type: "test-type2", - }, - ] - - const fulfillmentSets = await service.create(data) - - expect(fulfillmentSets).toHaveLength(2) - - let i = 0 - for (const data_ of data) { - expect(fulfillmentSets[i]).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data_.name, - type: data_.type, + it("should create a new fulfillment set with new service zones", async function () { + const data = { + name: "test", + type: "test-type", + service_zones: [ + { + name: "test", + }, + ], + } + + const fulfillmentSet = await service.create(data) + + expect(fulfillmentSet).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data.name, + type: data.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + name: data.service_zones[0].name, + }), + ]), + }) + ) + }) + + it("should create a collection of fulfillment sets with new service zones", async function () { + const data = [ + { + name: "test", + type: "test-type", + service_zones: [ + { + name: "test", + }, + ], + }, + { + name: "test2", + type: "test-type2", + service_zones: [ + { + name: "test2", + }, + ], + }, + { + name: "test3", + type: "test-type3", + service_zones: [ + { + name: "test3", + }, + ], + }, + ] + + const fulfillmentSets = await service.create(data) + + expect(fulfillmentSets).toHaveLength(3) + + let i = 0 + for (const data_ of data) { + expect(fulfillmentSets[i]).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data_.name, + type: data_.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + name: data_.service_zones[0].name, + }), + ]), + }) + ) + ++i + } + }) + + it("should create a new fulfillment set with new service zones and new geo zones", async function () { + const data: CreateFulfillmentSetDTO = { + name: "test", + type: "test-type", + service_zones: [ + { + name: "test", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], + } + + const fulfillmentSet = await service.create(data) + + expect(fulfillmentSet).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data.name, + type: data.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + name: (data.service_zones![0] as any).name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + type: (data.service_zones![0] as any).geo_zones[0].type, + country_code: (data.service_zones![0] as any) + .geo_zones[0].country_code, + }), + ]), + }), + ]), + }) + ) + }) + + it("should create a collection of fulfillment sets with new service zones and new geo zones", async function () { + const data: CreateFulfillmentSetDTO[] = [ + { + name: "test", + type: "test-type", + service_zones: [ + { + name: "test", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], + }, + { + name: "test2", + type: "test-type2", + service_zones: [ + { + name: "test2", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], + }, + { + name: "test3", + type: "test-type3", + service_zones: [ + { + name: "test3", + geo_zones: [ + { + type: GeoZoneType.CITY, + country_code: "fr", + city: "lyon", + }, + ], + }, + ], + }, + ] + + const fulfillmentSets = await service.create(data) + + expect(fulfillmentSets).toHaveLength(3) + + let i = 0 + for (const data_ of data) { + expect(fulfillmentSets[i]).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data_.name, + type: data_.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + name: (data_.service_zones![0] as any).name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + type: (data_.service_zones![0] as any).geo_zones[0] + .type, + country_code: (data_.service_zones![0] as any) + .geo_zones[0].country_code, + }), + ]), + }), + ]), + }) + ) + ++i + } + }) + + it(`should fail on duplicated fulfillment set name`, async function () { + const data: CreateFulfillmentSetDTO = { + name: "test", + type: "test-type", + } + + await service.create(data) + const err = await service.create(data).catch((e) => e) + + expect(err).toBeDefined() + expect(err.constraint).toBe("IDX_fulfillment_set_name_unique") + }) + }) + + describe("on create service zones", () => { + it("should create a new service zone", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", }) - ) - ++i - } - }) - it("should create a new fulfillment set with new service zones", async function () { - const data = { - name: "test", - type: "test-type", - service_zones: [ - { + const data: CreateServiceZoneDTO = { name: "test", - }, - ], - } - - const fulfillmentSet = await service.create(data) - - expect(fulfillmentSet).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data.name, - type: data.type, - service_zones: expect.arrayContaining([ + fulfillment_set_id: fulfillmentSet.id, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + } + + const serviceZone = await service.createServiceZones(data) + + expect(serviceZone).toEqual( expect.objectContaining({ id: expect.any(String), - name: data.service_zones[0].name, - }), - ]), + name: data.name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + type: (data.geo_zones![0] as GeoZoneDTO).type, + country_code: (data.geo_zones![0] as GeoZoneDTO) + .country_code, + }), + ]), + }) + ) }) - ) - }) - it("should create a collection of fulfillment sets with new service zones", async function () { - const data = [ - { - name: "test", - type: "test-type", - service_zones: [ + it("should create a collection of service zones", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + + const data: CreateServiceZoneDTO[] = [ { name: "test", + fulfillment_set_id: fulfillmentSet.id, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], }, - ], - }, - { - name: "test2", - type: "test-type2", - service_zones: [ { name: "test2", + fulfillment_set_id: fulfillmentSet.id, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], }, - ], - }, - { - name: "test3", - type: "test-type3", - service_zones: [ { name: "test3", + fulfillment_set_id: fulfillmentSet.id, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "uk", + }, + ], }, - ], - }, - ] - - const fulfillmentSets = await service.create(data) - - expect(fulfillmentSets).toHaveLength(3) - - let i = 0 - for (const data_ of data) { - expect(fulfillmentSets[i]).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data_.name, - type: data_.type, - service_zones: expect.arrayContaining([ + ] + + const serviceZones = await service.createServiceZones(data) + + expect(serviceZones).toHaveLength(3) + + let i = 0 + for (const data_ of data) { + expect(serviceZones[i]).toEqual( expect.objectContaining({ id: expect.any(String), - name: data_.service_zones[0].name, + name: data_.name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + type: (data_.geo_zones![0] as GeoZoneDTO).type, + country_code: (data_.geo_zones![0] as GeoZoneDTO) + .country_code, + }), + ]), + }) + ) + ++i + } + }) + + it("should fail on duplicated service zone name", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + + const data: CreateServiceZoneDTO = { + name: "test", + fulfillment_set_id: fulfillmentSet.id, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + } + + await service.createServiceZones(data) + const err = await service.createServiceZones(data).catch((e) => e) + + expect(err).toBeDefined() + expect(err.constraint).toBe("IDX_service_zone_name_unique") + }) + }) + + describe("on create geo zones", () => { + it("should create a new geo zone", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + + const data: CreateGeoZoneDTO = { + service_zone_id: serviceZone.id, + type: GeoZoneType.COUNTRY, + country_code: "fr", + } + + const geoZone = await service.createGeoZones(data) + + expect(geoZone).toEqual( + expect.objectContaining({ + id: expect.any(String), + type: data.type, + country_code: data.country_code, + }) + ) + }) + + it("should create a collection of geo zones", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + + const data: CreateGeoZoneDTO[] = [ + { + service_zone_id: serviceZone.id, + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + { + service_zone_id: serviceZone.id, + type: GeoZoneType.COUNTRY, + country_code: "us", + }, + ] + + const geoZones = await service.createGeoZones(data) + + expect(geoZones).toHaveLength(2) + + let i = 0 + for (const data_ of data) { + expect(geoZones[i]).toEqual( + expect.objectContaining({ + id: expect.any(String), + type: data_.type, + country_code: data_.country_code, + }) + ) + ++i + } + }) + }) + + describe("on create shipping profiles", () => { + it("should create a new shipping profile", async function () { + const createData: CreateShippingProfileDTO = { + name: "test-default-profile", + type: "default", + } + + const createdShippingProfile = await service.createShippingProfiles( + createData + ) + + expect(createdShippingProfile).toEqual( + expect.objectContaining({ + name: createData.name, + type: createData.type, + }) + ) + }) + + it("should create multiple new shipping profiles", async function () { + const createData: CreateShippingProfileDTO[] = [ + { + name: "test-profile-1", + type: "default", + }, + { + name: "test-profile-2", + type: "custom", + }, + ] + + const createdShippingProfiles = + await service.createShippingProfiles(createData) + + expect(createdShippingProfiles).toHaveLength(2) + + let i = 0 + for (const data_ of createData) { + expect(createdShippingProfiles[i]).toEqual( + expect.objectContaining({ + name: data_.name, + type: data_.type, + }) + ) + ++i + } + }) + + it("should fail on duplicated shipping profile name", async function () { + const createData: CreateShippingProfileDTO = { + name: "test-default-profile", + type: "default", + } + + await service.createShippingProfiles(createData) + + const err = await service + .createShippingProfiles(createData) + .catch((e) => e) + + expect(err).toBeDefined() + expect(err.constraint).toBe("IDX_shipping_profile_name_unique") + }) + }) + + describe("on create shipping options", () => { + it("should create a new shipping option", async function () { + const shippingProfile = await service.createShippingProfiles({ + name: "test", + type: "default", + }) + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + + // TODO: change that for a real provider instead of fake data manual inserted data + const [{ id: providerId }] = + await MikroOrmWrapper.forkManager().execute( + "insert into service_provider (id) values ('sp_jdafwfleiwuonl') returning id" + ) + + const createData: CreateShippingOptionDTO = { + name: "test-option", + price_type: "flat", + service_zone_id: serviceZone.id, + shipping_profile_id: shippingProfile.id, + service_provider_id: providerId, + type: { + code: "test-type", + description: "test-description", + label: "test-label", + }, + data: { + amount: 1000, + }, + rules: [ + { + attribute: "test-attribute", + operator: "in", + value: "test-value", + }, + ], + } + + const createdShippingOption = await service.createShippingOptions( + createData + ) + + expect(createdShippingOption).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: createData.name, + price_type: createData.price_type, + service_zone_id: createData.service_zone_id, + shipping_profile_id: createData.shipping_profile_id, + service_provider_id: createData.service_provider_id, + shipping_option_type_id: expect.any(String), + type: expect.objectContaining({ + id: expect.any(String), + code: createData.type.code, + description: createData.type.description, + label: createData.type.label, }), - ]), + data: createData.data, + rules: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + attribute: createData.rules![0].attribute, + operator: createData.rules![0].operator, + value: createData.rules![0].value, + }), + ]), + }) + ) + }) + + it("should create multiple new shipping options", async function () { + const shippingProfile = await service.createShippingProfiles({ + name: "test", + type: "default", }) - ) - ++i - } - }) + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + + // TODO: change that for a real provider instead of fake data manual inserted data + const [{ id: providerId }] = + await MikroOrmWrapper.forkManager().execute( + "insert into service_provider (id) values ('sp_jdafwfleiwuonl') returning id" + ) + + const createData: CreateShippingOptionDTO[] = [ + { + name: "test-option", + price_type: "flat", + service_zone_id: serviceZone.id, + shipping_profile_id: shippingProfile.id, + service_provider_id: providerId, + type: { + code: "test-type", + description: "test-description", + label: "test-label", + }, + data: { + amount: 1000, + }, + rules: [ + { + attribute: "test-attribute", + operator: "in", + value: "test-value", + }, + ], + }, + { + name: "test-option-2", + price_type: "calculated", + service_zone_id: serviceZone.id, + shipping_profile_id: shippingProfile.id, + service_provider_id: providerId, + type: { + code: "test-type", + description: "test-description", + label: "test-label", + }, + data: { + amount: 1000, + }, + rules: [ + { + attribute: "test-attribute", + operator: "in", + value: "test-value", + }, + ], + }, + ] + + const createdShippingOptions = await service.createShippingOptions( + createData + ) + + expect(createdShippingOptions).toHaveLength(2) + + let i = 0 + for (const data_ of createData) { + expect(createdShippingOptions[i]).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data_.name, + price_type: data_.price_type, + service_zone_id: data_.service_zone_id, + shipping_profile_id: data_.shipping_profile_id, + service_provider_id: data_.service_provider_id, + shipping_option_type_id: expect.any(String), + type: expect.objectContaining({ + id: expect.any(String), + code: data_.type.code, + description: data_.type.description, + label: data_.type.label, + }), + data: data_.data, + rules: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + attribute: data_.rules![0].attribute, + operator: data_.rules![0].operator, + value: data_.rules![0].value, + }), + ]), + }) + ) + ++i + } + }) + }) + + describe("on update", () => { + it("should update an existing fulfillment set", async function () { + const createData: CreateFulfillmentSetDTO = { + name: "test", + type: "test-type", + } + + const createdFulfillmentSet = await service.create(createData) + + const updateData = { + id: createdFulfillmentSet.id, + name: "updated-test", + type: "updated-test-type", + } + + const updatedFulfillmentSets = await service.update(updateData) + + expect(updatedFulfillmentSets).toEqual( + expect.objectContaining({ + id: createdFulfillmentSet.id, + name: updateData.name, + type: updateData.type, + }) + ) + }) + + it("should update a collection of fulfillment sets", async function () { + const createData = [ + { + name: "test", + type: "test-type", + }, + { + name: "test2", + type: "test-type2", + }, + ] + + const createdFulfillmentSets = await service.create(createData) + + const updateData = createdFulfillmentSets.map( + (fulfillmentSet, index) => ({ + id: fulfillmentSet.id, + name: `updated-test${index + 1}`, + type: `updated-test-type${index + 1}`, + }) + ) + + const updatedFulfillmentSets = await service.update(updateData) + + expect(updatedFulfillmentSets).toHaveLength(2) + + let i = 0 + for (const data_ of updateData) { + expect(updatedFulfillmentSets[i]).toEqual( + expect.objectContaining({ + id: createdFulfillmentSets[i].id, + name: data_.name, + type: data_.type, + }) + ) + ++i + } + }) + + it("should update an existing fulfillment set and replace old service zones by a new one", async function () { + const createData: CreateFulfillmentSetDTO = { + name: "test", + type: "test-type", + service_zones: [ + { + name: "service-zone-test", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], + } + + const createdFulfillmentSet = await service.create(createData) + + const createServiceZoneData: CreateServiceZoneDTO = { + fulfillment_set_id: createdFulfillmentSet.id, + name: "service-zone-test2", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "us", + }, + ], + } + + const updateData: UpdateFulfillmentSetDTO = { + id: createdFulfillmentSet.id, + name: "updated-test", + type: "updated-test-type", + service_zones: [createServiceZoneData], + } + + const updatedFulfillmentSet = await service.update(updateData) + + expect(updatedFulfillmentSet).toEqual( + expect.objectContaining({ + id: updateData.id, + name: updateData.name, + type: updateData.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + name: (updateData.service_zones![0] as ServiceZoneDTO).name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + type: (updateData.service_zones![0] as ServiceZoneDTO) + .geo_zones[0].type, + country_code: ( + updateData.service_zones![0] as ServiceZoneDTO + ).geo_zones[0].country_code, + }), + ]), + }), + ]), + }) + ) + + const serviceZones = await service.listServiceZones() + + expect(serviceZones).toHaveLength(1) + expect(serviceZones[0]).toEqual( + expect.objectContaining({ + id: updatedFulfillmentSet.service_zones[0].id, + }) + ) + }) - it("should create a new fulfillment set with new service zones and new geo zones", async function () { - const data: CreateFulfillmentSetDTO = { - name: "test", - type: "test-type", - service_zones: [ - { + it("should update an existing fulfillment set and add a new service zone", async function () { + const createData: CreateFulfillmentSetDTO = { name: "test", + type: "test-type", + service_zones: [ + { + name: "service-zone-test", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], + } + + const createdFulfillmentSet = await service.create(createData) + + const createServiceZoneData: CreateServiceZoneDTO = { + fulfillment_set_id: createdFulfillmentSet.id, + name: "service-zone-test2", geo_zones: [ { type: GeoZoneType.COUNTRY, - country_code: "fr", + country_code: "us", }, ], - }, - ], - } - - const fulfillmentSet = await service.create(data) - - expect(fulfillmentSet).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data.name, - type: data.type, - service_zones: expect.arrayContaining([ + } + + const updateData: UpdateFulfillmentSetDTO = { + id: createdFulfillmentSet.id, + name: "updated-test", + type: "updated-test-type", + service_zones: [ + { id: createdFulfillmentSet.service_zones[0].id }, + createServiceZoneData, + ], + } + + const updatedFulfillmentSet = await service.update(updateData) + + expect(updatedFulfillmentSet).toEqual( expect.objectContaining({ - id: expect.any(String), - name: (data.service_zones![0] as any).name, - geo_zones: expect.arrayContaining([ + id: updateData.id, + name: updateData.name, + type: updateData.type, + service_zones: expect.arrayContaining([ expect.objectContaining({ - type: (data.service_zones![0] as any).geo_zones[0].type, - country_code: (data.service_zones![0] as any).geo_zones[0] - .country_code, + id: createdFulfillmentSet.service_zones[0].id, + }), + expect.objectContaining({ + id: expect.any(String), + name: (updateData.service_zones![1] as ServiceZoneDTO).name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + type: (updateData.service_zones![1] as ServiceZoneDTO) + .geo_zones[0].type, + country_code: ( + updateData.service_zones![1] as ServiceZoneDTO + ).geo_zones[0].country_code, + }), + ]), }), ]), - }), - ]), + }) + ) }) - ) - }) - it("should create a collection of fulfillment sets with new service zones and new geo zones", async function () { - const data: CreateFulfillmentSetDTO[] = [ - { - name: "test", - type: "test-type", - service_zones: [ + it("should fail on duplicated fulfillment set name", async function () { + const createData = [ { name: "test", - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - ], + type: "test-type", }, - ], - }, - { - name: "test2", - type: "test-type2", - service_zones: [ { name: "test2", - geo_zones: [ + type: "test-type2", + }, + ] + + const createdFulfillmentSets = await service.create(createData) + + const updateData = { + id: createdFulfillmentSets[1].id, + name: "test", // This is the name of the first fulfillment set + type: "updated-test-type2", + } + + const err = await service.update(updateData).catch((e) => e) + + expect(err).toBeDefined() + expect(err.constraint).toBe("IDX_fulfillment_set_name_unique") + }) + + it("should update a collection of fulfillment sets and replace old service zones by new ones", async function () { + const createData: CreateFulfillmentSetDTO[] = [ + { + name: "test1", + type: "test-type1", + service_zones: [ { - type: GeoZoneType.COUNTRY, - country_code: "fr", + name: "service-zone-test1", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], }, ], }, - ], - }, - { - name: "test3", - type: "test-type3", - service_zones: [ { - name: "test3", - geo_zones: [ + name: "test2", + type: "test-type2", + service_zones: [ { - type: GeoZoneType.CITY, - country_code: "fr", - city: "lyon", + name: "service-zone-test2", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "us", + }, + ], }, ], }, - ], - }, - ] - - const fulfillmentSets = await service.create(data) - - expect(fulfillmentSets).toHaveLength(3) - - let i = 0 - for (const data_ of data) { - expect(fulfillmentSets[i]).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data_.name, - type: data_.type, - service_zones: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - name: (data_.service_zones![0] as any).name, - geo_zones: expect.arrayContaining([ - expect.objectContaining({ - type: (data_.service_zones![0] as any).geo_zones[0].type, - country_code: (data_.service_zones![0] as any) - .geo_zones[0].country_code, - }), - ]), - }), - ]), - }) - ) - ++i - } - }) + ] - it(`should fail on duplicated fulfillment set name`, async function () { - const data: CreateFulfillmentSetDTO = { - name: "test", - type: "test-type", - } + const createdFulfillmentSets = await service.create(createData) - await service.create(data) - const err = await service.create(data).catch((e) => e) + const updateData: UpdateFulfillmentSetDTO[] = + createdFulfillmentSets.map((fulfillmentSet, index) => ({ + id: fulfillmentSet.id, + name: `updated-test${index + 1}`, + type: `updated-test-type${index + 1}`, + service_zones: [ + { + name: `new-service-zone-test${index + 1}`, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "test", + }, + ], + }, + ], + })) - expect(err).toBeDefined() - expect(err.constraint).toBe("IDX_fulfillment_set_name_unique") - }) - }) + const updatedFulfillmentSets = await service.update(updateData) - describe("on create service zones", () => { - it("should create a new service zone", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) + expect(updatedFulfillmentSets).toHaveLength(2) - const data: CreateServiceZoneDTO = { - name: "test", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - ], - } + let i = 0 + for (const data_ of updateData) { + expect(updatedFulfillmentSets[i]).toEqual( + expect.objectContaining({ + id: data_.id, + name: data_.name, + type: data_.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + name: (data_.service_zones![0] as ServiceZoneDTO).name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + type: (data_.service_zones![0] as ServiceZoneDTO) + .geo_zones[0].type, + country_code: ( + data_.service_zones![0] as ServiceZoneDTO + ).geo_zones[0].country_code, + }), + ]), + }), + ]), + }) + ) + ++i + } - const serviceZone = await service.createServiceZones(data) + const serviceZones = await service.listServiceZones() - expect(serviceZone).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data.name, - geo_zones: expect.arrayContaining([ - expect.objectContaining({ - type: (data.geo_zones![0] as GeoZoneDTO).type, - country_code: (data.geo_zones![0] as GeoZoneDTO).country_code, - }), - ]), + expect(serviceZones).toHaveLength(2) + expect(serviceZones).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: (updateData[0].service_zones![0] as ServiceZoneDTO) + .name, + }), + expect.objectContaining({ + name: (updateData[1].service_zones![0] as ServiceZoneDTO) + .name, + }), + ]) + ) }) - ) - }) - - it("should create a collection of service zones", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - const data: CreateServiceZoneDTO[] = [ - { - name: "test", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ + it("should update a collection of fulfillment sets and add new service zones", async function () { + const createData: CreateFulfillmentSetDTO[] = [ { - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - ], - }, - { - name: "test2", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "fr", + name: "test1", + type: "test-type1", + service_zones: [ + { + name: "service-zone-test1", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "fr", + }, + ], + }, + ], }, - ], - }, - { - name: "test3", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ { - type: GeoZoneType.COUNTRY, - country_code: "uk", + name: "test2", + type: "test-type2", + service_zones: [ + { + name: "service-zone-test2", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "us", + }, + ], + }, + ], }, - ], - }, - ] - - const serviceZones = await service.createServiceZones(data) - - expect(serviceZones).toHaveLength(3) + ] - let i = 0 - for (const data_ of data) { - expect(serviceZones[i]).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: data_.name, - geo_zones: expect.arrayContaining([ - expect.objectContaining({ - type: (data_.geo_zones![0] as GeoZoneDTO).type, - country_code: (data_.geo_zones![0] as GeoZoneDTO) - .country_code, - }), - ]), - }) - ) - ++i - } - }) - - it("should fail on duplicated service zone name", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - - const data: CreateServiceZoneDTO = { - name: "test", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - ], - } + const createdFulfillmentSets = await service.create(createData) - await service.createServiceZones(data) - const err = await service.createServiceZones(data).catch((e) => e) + const updateData: UpdateFulfillmentSetDTO[] = + createdFulfillmentSets.map((fulfillmentSet, index) => ({ + id: fulfillmentSet.id, + name: `updated-test${index + 1}`, + type: `updated-test-type${index + 1}`, + service_zones: [ + ...fulfillmentSet.service_zones, + { + name: `added-service-zone-test${index + 1}`, + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "test", + }, + ], + }, + ], + })) - expect(err).toBeDefined() - expect(err.constraint).toBe("IDX_service_zone_name_unique") - }) - }) + const updatedFulfillmentSets = await service.update(updateData) - describe("on create geo zones", () => { - it("should create a new geo zone", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - const serviceZone = await service.createServiceZones({ - name: "test", - fulfillment_set_id: fulfillmentSet.id, - }) + expect(updatedFulfillmentSets).toHaveLength(2) - const data: CreateGeoZoneDTO = { - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "fr", - } + let i = 0 + for (const data_ of updateData) { + expect(updatedFulfillmentSets[i]).toEqual( + expect.objectContaining({ + id: data_.id, + name: data_.name, + type: data_.type, + service_zones: expect.arrayContaining([ + expect.objectContaining({ + id: createdFulfillmentSets[i].service_zones[0].id, + }), + expect.objectContaining({ + id: expect.any(String), + name: (data_.service_zones![1] as ServiceZoneDTO).name, + geo_zones: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + type: (data_.service_zones![1] as ServiceZoneDTO) + .geo_zones[0].type, + country_code: ( + data_.service_zones![1] as ServiceZoneDTO + ).geo_zones[0].country_code, + }), + ]), + }), + ]), + }) + ) + ++i + } - const geoZone = await service.createGeoZones(data) + const serviceZones = await service.listServiceZones() - expect(geoZone).toEqual( - expect.objectContaining({ - id: expect.any(String), - type: data.type, - country_code: data.country_code, + expect(serviceZones).toHaveLength(4) + expect(serviceZones).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: createdFulfillmentSets[0].service_zones![0].name, + }), + expect.objectContaining({ + name: createdFulfillmentSets[1].service_zones![0].name, + }), + expect.objectContaining({ + name: (updateData[0].service_zones![1] as ServiceZoneDTO) + .name, + }), + expect.objectContaining({ + name: (updateData[1].service_zones![1] as ServiceZoneDTO) + .name, + }), + ]) + ) }) - ) - }) - - it("should create a collection of geo zones", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - const serviceZone = await service.createServiceZones({ - name: "test", - fulfillment_set_id: fulfillmentSet.id, }) - const data: CreateGeoZoneDTO[] = [ - { - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - { - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "us", - }, - ] - - const geoZones = await service.createGeoZones(data) - - expect(geoZones).toHaveLength(2) - - let i = 0 - for (const data_ of data) { - expect(geoZones[i]).toEqual( - expect.objectContaining({ - id: expect.any(String), - type: data_.type, - country_code: data_.country_code, - }) - ) - ++i - } - }) - }) - - describe("on update", () => { - it("should update an existing fulfillment set", async function () { - const createData: CreateFulfillmentSetDTO = { - name: "test", - type: "test-type", - } - - const createdFulfillmentSet = await service.create(createData) - - const updateData = { - id: createdFulfillmentSet.id, - name: "updated-test", - type: "updated-test-type", - } - - const updatedFulfillmentSets = await service.update(updateData) - - expect(updatedFulfillmentSets).toEqual( - expect.objectContaining({ - id: createdFulfillmentSet.id, - name: updateData.name, - type: updateData.type, - }) - ) - }) - - it("should update a collection of fulfillment sets", async function () { - const createData = [ - { - name: "test", - type: "test-type", - }, - { - name: "test2", - type: "test-type2", - }, - ] - - const createdFulfillmentSets = await service.create(createData) - - const updateData = createdFulfillmentSets.map( - (fulfillmentSet, index) => ({ - id: fulfillmentSet.id, - name: `updated-test${index + 1}`, - type: `updated-test-type${index + 1}`, - }) - ) - - const updatedFulfillmentSets = await service.update(updateData) - - expect(updatedFulfillmentSets).toHaveLength(2) - - let i = 0 - for (const data_ of updateData) { - expect(updatedFulfillmentSets[i]).toEqual( - expect.objectContaining({ - id: createdFulfillmentSets[i].id, - name: data_.name, - type: data_.type, + describe("on update service zones", () => { + it("should update an existing service zone", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", }) - ) - ++i - } - }) - it("should update an existing fulfillment set and replace old service zones by a new one", async function () { - const createData: CreateFulfillmentSetDTO = { - name: "test", - type: "test-type", - service_zones: [ - { + const createData: CreateServiceZoneDTO = { name: "service-zone-test", + fulfillment_set_id: fulfillmentSet.id, geo_zones: [ { type: GeoZoneType.COUNTRY, country_code: "fr", }, ], - }, - ], - } - - const createdFulfillmentSet = await service.create(createData) - - const createServiceZoneData: CreateServiceZoneDTO = { - fulfillment_set_id: createdFulfillmentSet.id, - name: "service-zone-test2", - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "us", - }, - ], - } - - const updateData: UpdateFulfillmentSetDTO = { - id: createdFulfillmentSet.id, - name: "updated-test", - type: "updated-test-type", - service_zones: [createServiceZoneData], - } - - const updatedFulfillmentSet = await service.update(updateData) - - expect(updatedFulfillmentSet).toEqual( - expect.objectContaining({ - id: updateData.id, - name: updateData.name, - type: updateData.type, - service_zones: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - name: (updateData.service_zones![0] as ServiceZoneDTO).name, - geo_zones: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - type: (updateData.service_zones![0] as ServiceZoneDTO) - .geo_zones[0].type, - country_code: ( - updateData.service_zones![0] as ServiceZoneDTO - ).geo_zones[0].country_code, - }), - ]), - }), - ]), - }) - ) - - const serviceZones = await service.listServiceZones() + } - expect(serviceZones).toHaveLength(1) - expect(serviceZones[0]).toEqual( - expect.objectContaining({ - id: updatedFulfillmentSet.service_zones[0].id, - }) - ) - }) + const createdServiceZone = await service.createServiceZones( + createData + ) - it("should update an existing fulfillment set and add a new service zone", async function () { - const createData: CreateFulfillmentSetDTO = { - name: "test", - type: "test-type", - service_zones: [ - { - name: "service-zone-test", + const updateData = { + id: createdServiceZone.id, + name: "updated-service-zone-test", geo_zones: [ { + id: createdServiceZone.geo_zones[0].id, type: GeoZoneType.COUNTRY, - country_code: "fr", + country_code: "us", }, ], - }, - ], - } + } - const createdFulfillmentSet = await service.create(createData) + const updatedServiceZone = await service.updateServiceZones( + updateData + ) - const createServiceZoneData: CreateServiceZoneDTO = { - fulfillment_set_id: createdFulfillmentSet.id, - name: "service-zone-test2", - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "us", - }, - ], - } - - const updateData: UpdateFulfillmentSetDTO = { - id: createdFulfillmentSet.id, - name: "updated-test", - type: "updated-test-type", - service_zones: [ - { id: createdFulfillmentSet.service_zones[0].id }, - createServiceZoneData, - ], - } - - const updatedFulfillmentSet = await service.update(updateData) - - expect(updatedFulfillmentSet).toEqual( - expect.objectContaining({ - id: updateData.id, - name: updateData.name, - type: updateData.type, - service_zones: expect.arrayContaining([ + expect(updatedServiceZone).toEqual( expect.objectContaining({ - id: createdFulfillmentSet.service_zones[0].id, - }), - expect.objectContaining({ - id: expect.any(String), - name: (updateData.service_zones![1] as ServiceZoneDTO).name, + id: updateData.id, + name: updateData.name, geo_zones: expect.arrayContaining([ expect.objectContaining({ - id: expect.any(String), - type: (updateData.service_zones![1] as ServiceZoneDTO) - .geo_zones[0].type, - country_code: ( - updateData.service_zones![1] as ServiceZoneDTO - ).geo_zones[0].country_code, + id: updateData.geo_zones[0].id, + type: updateData.geo_zones[0].type, + country_code: updateData.geo_zones[0].country_code, }), ]), - }), - ]), + }) + ) }) - ) - }) - it("should fail on duplicated fulfillment set name", async function () { - const createData = [ - { - name: "test", - type: "test-type", - }, - { - name: "test2", - type: "test-type2", - }, - ] - - const createdFulfillmentSets = await service.create(createData) - - const updateData = { - id: createdFulfillmentSets[1].id, - name: "test", // This is the name of the first fulfillment set - type: "updated-test-type2", - } - - const err = await service.update(updateData).catch((e) => e) - - expect(err).toBeDefined() - expect(err.constraint).toBe("IDX_fulfillment_set_name_unique") - }) + it("should update a collection of service zones", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) - it("should update a collection of fulfillment sets and replace old service zones by new ones", async function () { - const createData: CreateFulfillmentSetDTO[] = [ - { - name: "test1", - type: "test-type1", - service_zones: [ + const createData: CreateServiceZoneDTO[] = [ { - name: "service-zone-test1", + name: "service-zone-test", + fulfillment_set_id: fulfillmentSet.id, geo_zones: [ { type: GeoZoneType.COUNTRY, @@ -923,14 +1435,9 @@ describe("fulfillment module service", function () { }, ], }, - ], - }, - { - name: "test2", - type: "test-type2", - service_zones: [ { name: "service-zone-test2", + fulfillment_set_id: fulfillmentSet.id, geo_zones: [ { type: GeoZoneType.COUNTRY, @@ -938,84 +1445,60 @@ describe("fulfillment module service", function () { }, ], }, - ], - }, - ] - - const createdFulfillmentSets = await service.create(createData) - - const updateData: UpdateFulfillmentSetDTO[] = - createdFulfillmentSets.map((fulfillmentSet, index) => ({ - id: fulfillmentSet.id, - name: `updated-test${index + 1}`, - type: `updated-test-type${index + 1}`, - service_zones: [ - { - name: `new-service-zone-test${index + 1}`, + ] + + const createdServiceZones = await service.createServiceZones( + createData + ) + + const updateData: UpdateServiceZoneDTO[] = createdServiceZones.map( + (serviceZone, index) => ({ + id: serviceZone.id, + name: `updated-service-zone-test${index + 1}`, geo_zones: [ { type: GeoZoneType.COUNTRY, - country_code: "test", + country_code: index % 2 === 0 ? "us" : "fr", }, ], - }, - ], - })) + }) + ) - const updatedFulfillmentSets = await service.update(updateData) + const updatedServiceZones = await service.updateServiceZones( + updateData + ) - expect(updatedFulfillmentSets).toHaveLength(2) + expect(updatedServiceZones).toHaveLength(2) - let i = 0 - for (const data_ of updateData) { - expect(updatedFulfillmentSets[i]).toEqual( - expect.objectContaining({ - id: data_.id, - name: data_.name, - type: data_.type, - service_zones: expect.arrayContaining([ + let i = 0 + for (const data_ of updateData) { + expect(updatedServiceZones[i]).toEqual( expect.objectContaining({ - id: expect.any(String), - name: (data_.service_zones![0] as ServiceZoneDTO).name, + id: data_.id, + name: data_.name, geo_zones: expect.arrayContaining([ expect.objectContaining({ - id: expect.any(String), - type: (data_.service_zones![0] as ServiceZoneDTO) - .geo_zones[0].type, - country_code: (data_.service_zones![0] as ServiceZoneDTO) - .geo_zones[0].country_code, + type: (data_.geo_zones![0] as GeoZoneDTO).type, + country_code: (data_.geo_zones![0] as GeoZoneDTO) + .country_code, }), ]), - }), - ]), + }) + ) + ++i + } + }) + + it("should fail on duplicated service zone name", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", }) - ) - ++i - } - - const serviceZones = await service.listServiceZones() - - expect(serviceZones).toHaveLength(2) - expect(serviceZones).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: updateData[0].service_zones![0].name, - }), - expect.objectContaining({ - name: updateData[1].service_zones![0].name, - }), - ]) - ) - }) - it("should update a collection of fulfillment sets and add new service zones", async function () { - const createData: CreateFulfillmentSetDTO[] = [ - { - name: "test1", - type: "test-type1", - service_zones: [ + const createData: CreateServiceZoneDTO[] = [ { - name: "service-zone-test1", + name: "service-zone-test", + fulfillment_set_id: fulfillmentSet.id, geo_zones: [ { type: GeoZoneType.COUNTRY, @@ -1023,14 +1506,9 @@ describe("fulfillment module service", function () { }, ], }, - ], - }, - { - name: "test2", - type: "test-type2", - service_zones: [ { name: "service-zone-test2", + fulfillment_set_id: fulfillmentSet.id, geo_zones: [ { type: GeoZoneType.COUNTRY, @@ -1038,336 +1516,121 @@ describe("fulfillment module service", function () { }, ], }, - ], - }, - ] - - const createdFulfillmentSets = await service.create(createData) - - const updateData: UpdateFulfillmentSetDTO[] = - createdFulfillmentSets.map((fulfillmentSet, index) => ({ - id: fulfillmentSet.id, - name: `updated-test${index + 1}`, - type: `updated-test-type${index + 1}`, - service_zones: [ - ...fulfillmentSet.service_zones, - { - name: `added-service-zone-test${index + 1}`, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "test", - }, - ], - }, - ], - })) + ] - const updatedFulfillmentSets = await service.update(updateData) + const createdServiceZones = await service.createServiceZones( + createData + ) - expect(updatedFulfillmentSets).toHaveLength(2) + const updateData: UpdateServiceZoneDTO = { + id: createdServiceZones[1].id, + name: "service-zone-test", + geo_zones: [ + { + type: GeoZoneType.COUNTRY, + country_code: "us", + }, + ], + } - let i = 0 - for (const data_ of updateData) { - expect(updatedFulfillmentSets[i]).toEqual( - expect.objectContaining({ - id: data_.id, - name: data_.name, - type: data_.type, - service_zones: expect.arrayContaining([ - expect.objectContaining({ - id: createdFulfillmentSets[i].service_zones[0].id, - }), - expect.objectContaining({ - id: expect.any(String), - name: (data_.service_zones![1] as ServiceZoneDTO).name, - geo_zones: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - type: (data_.service_zones![1] as ServiceZoneDTO) - .geo_zones[0].type, - country_code: (data_.service_zones![1] as ServiceZoneDTO) - .geo_zones[0].country_code, - }), - ]), - }), - ]), - }) - ) - ++i - } - - const serviceZones = await service.listServiceZones() - - expect(serviceZones).toHaveLength(4) - expect(serviceZones).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: createdFulfillmentSets[0].service_zones![0].name, - }), - expect.objectContaining({ - name: createdFulfillmentSets[1].service_zones![0].name, - }), - expect.objectContaining({ - name: updateData[0].service_zones![1].name, - }), - expect.objectContaining({ - name: updateData[1].service_zones![1].name, - }), - ]) - ) - }) - }) + const err = await service + .updateServiceZones(updateData) + .catch((e) => e) - describe("on update service zones", () => { - it("should update an existing service zone", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", + expect(err).toBeDefined() + expect(err.constraint).toBe("IDX_service_zone_name_unique") + }) }) - const createData: CreateServiceZoneDTO = { - name: "service-zone-test", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { + describe("on update geo zones", () => { + it("should update an existing geo zone", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", + }) + + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) + + const createData: CreateGeoZoneDTO = { + service_zone_id: serviceZone.id, type: GeoZoneType.COUNTRY, country_code: "fr", - }, - ], - } - - const createdServiceZone = await service.createServiceZones(createData) - - const updateData = { - id: createdServiceZone.id, - name: "updated-service-zone-test", - geo_zones: [ - { - id: createdServiceZone.geo_zones[0].id, + } + + const createdGeoZone = await service.createGeoZones(createData) + + const updateData: UpdateGeoZoneDTO = { + id: createdGeoZone.id, type: GeoZoneType.COUNTRY, country_code: "us", - }, - ], - } + } - const updatedServiceZone = await service.updateServiceZones(updateData) + const updatedGeoZone = await service.updateGeoZones(updateData) - expect(updatedServiceZone).toEqual( - expect.objectContaining({ - id: updateData.id, - name: updateData.name, - geo_zones: expect.arrayContaining([ + expect(updatedGeoZone).toEqual( expect.objectContaining({ - id: updateData.geo_zones[0].id, - type: updateData.geo_zones[0].type, - country_code: updateData.geo_zones[0].country_code, - }), - ]), + id: updateData.id, + type: updateData.type, + country_code: updateData.country_code, + }) + ) }) - ) - }) - - it("should update a collection of service zones", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - - const createData: CreateServiceZoneDTO[] = [ - { - name: "service-zone-test", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - ], - }, - { - name: "service-zone-test2", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "us", - }, - ], - }, - ] - - const createdServiceZones = await service.createServiceZones(createData) - const updateData = createdServiceZones.map((serviceZone, index) => ({ - id: serviceZone.id, - name: `updated-service-zone-test${index + 1}`, - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: index % 2 === 0 ? "us" : "fr", - }, - ], - })) - - const updatedServiceZones = await service.updateServiceZones(updateData) - - expect(updatedServiceZones).toHaveLength(2) - - let i = 0 - for (const data_ of updateData) { - expect(updatedServiceZones[i]).toEqual( - expect.objectContaining({ - id: data_.id, - name: data_.name, - geo_zones: expect.arrayContaining([ - expect.objectContaining({ - type: data_.geo_zones[0].type, - country_code: data_.geo_zones[0].country_code, - }), - ]), + it("should update a collection of geo zones", async function () { + const fulfillmentSet = await service.create({ + name: "test", + type: "test-type", }) - ) - ++i - } - }) - it("should fail on duplicated service zone name", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) + const serviceZone = await service.createServiceZones({ + name: "test", + fulfillment_set_id: fulfillmentSet.id, + }) - const createData: CreateServiceZoneDTO[] = [ - { - name: "service-zone-test", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ + const createData: CreateGeoZoneDTO[] = [ { + service_zone_id: serviceZone.id, type: GeoZoneType.COUNTRY, country_code: "fr", }, - ], - }, - { - name: "service-zone-test2", - fulfillment_set_id: fulfillmentSet.id, - geo_zones: [ { + service_zone_id: serviceZone.id, type: GeoZoneType.COUNTRY, country_code: "us", }, - ], - }, - ] - - const createdServiceZones = await service.createServiceZones(createData) - - const updateData = { - id: createdServiceZones[1].id, - name: "service-zone-test", - geo_zones: [ - { - type: GeoZoneType.COUNTRY, - country_code: "us", - }, - ], - } - - const err = await service.updateServiceZones(updateData).catch((e) => e) - - expect(err).toBeDefined() - expect(err.constraint).toBe("IDX_service_zone_name_unique") - }) - }) + ] - describe("on update geo zones", () => { - it("should update an existing geo zone", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", - }) - - const serviceZone = await service.createServiceZones({ - name: "test", - fulfillment_set_id: fulfillmentSet.id, - }) - - const createData: CreateGeoZoneDTO = { - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "fr", - } + const createdGeoZones = await service.createGeoZones(createData) - const createdGeoZone = await service.createGeoZones(createData) + const updateData: UpdateGeoZoneDTO[] = createdGeoZones.map( + (geoZone, index) => ({ + id: geoZone.id, + type: GeoZoneType.COUNTRY, + country_code: index % 2 === 0 ? "us" : "fr", + }) + ) - const updateData: UpdateGeoZoneDTO = { - id: createdGeoZone.id, - type: GeoZoneType.COUNTRY, - country_code: "us", - } + const updatedGeoZones = await service.updateGeoZones(updateData) - const updatedGeoZone = await service.updateGeoZones(updateData) + expect(updatedGeoZones).toHaveLength(2) - expect(updatedGeoZone).toEqual( - expect.objectContaining({ - id: updateData.id, - type: updateData.type, - country_code: updateData.country_code, + let i = 0 + for (const data_ of updateData) { + expect(updatedGeoZones[i]).toEqual( + expect.objectContaining({ + id: data_.id, + type: data_.type, + country_code: data_.country_code, + }) + ) + ++i + } }) - ) - }) - - it("should update a collection of geo zones", async function () { - const fulfillmentSet = await service.create({ - name: "test", - type: "test-type", }) - - const serviceZone = await service.createServiceZones({ - name: "test", - fulfillment_set_id: fulfillmentSet.id, - }) - - const createData: CreateGeoZoneDTO[] = [ - { - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "fr", - }, - { - service_zone_id: serviceZone.id, - type: GeoZoneType.COUNTRY, - country_code: "us", - }, - ] - - const createdGeoZones = await service.createGeoZones(createData) - - const updateData: UpdateGeoZoneDTO[] = createdGeoZones.map( - (geoZone, index) => ({ - id: geoZone.id, - type: GeoZoneType.COUNTRY, - country_code: index % 2 === 0 ? "us" : "fr", - }) - ) - - const updatedGeoZones = await service.updateGeoZones(updateData) - - expect(updatedGeoZones).toHaveLength(2) - - let i = 0 - for (const data_ of updateData) { - expect(updatedGeoZones[i]).toEqual( - expect.objectContaining({ - id: data_.id, - type: data_.type, - country_code: data_.country_code, - }) - ) - ++i - } }) }) - }) + }, }) diff --git a/packages/fulfillment/integration-tests/setup-env.js b/packages/fulfillment/integration-tests/setup-env.js deleted file mode 100644 index e8e2a6b17a131..0000000000000 --- a/packages/fulfillment/integration-tests/setup-env.js +++ /dev/null @@ -1,6 +0,0 @@ -if (typeof process.env.DB_TEMP_NAME === "undefined") { - const tempName = parseInt(process.env.JEST_WORKER_ID || "1") - process.env.DB_TEMP_NAME = `medusa-fulfillment-integration-${tempName}` -} - -process.env.MEDUSA_FULFILLMENT_DB_SCHEMA = "public" diff --git a/packages/fulfillment/integration-tests/setup.js b/packages/fulfillment/integration-tests/setup.js deleted file mode 100644 index 43f99aab4ac94..0000000000000 --- a/packages/fulfillment/integration-tests/setup.js +++ /dev/null @@ -1,3 +0,0 @@ -import { JestUtils } from "medusa-test-utils" - -JestUtils.afterAllHookDropDatabase() diff --git a/packages/fulfillment/integration-tests/utils/database.ts b/packages/fulfillment/integration-tests/utils/database.ts deleted file mode 100644 index d1ba6a830cef1..0000000000000 --- a/packages/fulfillment/integration-tests/utils/database.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { TestDatabaseUtils } from "medusa-test-utils" - -import * as Models from "@models" - -const mikroOrmEntities = Models as unknown as any[] - -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( - mikroOrmEntities, - null, - process.env.MEDUSA_FULFILLMENT_DB_SCHEMA -) - -export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/fulfillment/integration-tests/utils/get-init-module-config.ts b/packages/fulfillment/integration-tests/utils/get-init-module-config.ts deleted file mode 100644 index 5ebb110c2976d..0000000000000 --- a/packages/fulfillment/integration-tests/utils/get-init-module-config.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Modules, ModulesDefinition } from "@medusajs/modules-sdk" - -import { DB_URL } from "./database" - -export function getInitModuleConfig() { - const moduleOptions = { - defaultAdapterOptions: { - database: { - clientUrl: DB_URL, - schema: process.env.MEDUSA_FULFILLMENT_DB_SCHEMA, - }, - }, - } - - const injectedDependencies = {} - - const modulesConfig_ = { - [Modules.FULFILLMENT]: { - definition: ModulesDefinition[Modules.FULFILLMENT], - options: moduleOptions, - }, - } - - return { - injectedDependencies, - modulesConfig: modulesConfig_, - databaseConfig: { - clientUrl: DB_URL, - schema: process.env.MEDUSA_FULFILLMENT_DB_SCHEMA, - }, - joinerConfig: [], - } -} diff --git a/packages/fulfillment/integration-tests/utils/index.ts b/packages/fulfillment/integration-tests/utils/index.ts deleted file mode 100644 index ba28fb552380b..0000000000000 --- a/packages/fulfillment/integration-tests/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./database" -export * from "./get-init-module-config" diff --git a/packages/fulfillment/jest.config.js b/packages/fulfillment/jest.config.js index 456054fe8ae27..62656d9c235b9 100644 --- a/packages/fulfillment/jest.config.js +++ b/packages/fulfillment/jest.config.js @@ -17,6 +17,5 @@ module.exports = { testEnvironment: `node`, moduleFileExtensions: [`js`, `ts`], modulePathIgnorePatterns: ["dist/"], - setupFiles: ["/integration-tests/setup-env.js"], - setupFilesAfterEnv: ["/integration-tests/setup.js"], + /*setupFilesAfterEnv: ["/integration-tests/setup.js"],*/ } diff --git a/packages/fulfillment/package.json b/packages/fulfillment/package.json index 94fbac4399a87..970e92e8ee050 100644 --- a/packages/fulfillment/package.json +++ b/packages/fulfillment/package.json @@ -29,7 +29,7 @@ "prepublishOnly": "cross-env NODE_ENV=production tsc --build && tsc-alias -p tsconfig.json", "build": "rimraf dist && tsc --build && tsc-alias -p tsconfig.json", "test": "jest --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts", - "test:integration": "jest --runInBand --forceExit -- integration-tests/**/__tests__/**/*.ts", + "test:integration": "jest --runInBand --forceExit -- integration-tests/**/__tests__/**/*.spec.ts", "migration:generate": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:generate", "migration:initial": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create --initial", "migration:create": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create", diff --git a/packages/fulfillment/src/migrations/.snapshot-medusa-fulfillment.json b/packages/fulfillment/src/migrations/.snapshot-medusa-fulfillment.json index f2b6dde65648d..d1b7292ae5c14 100644 --- a/packages/fulfillment/src/migrations/.snapshot-medusa-fulfillment.json +++ b/packages/fulfillment/src/migrations/.snapshot-medusa-fulfillment.json @@ -493,20 +493,7 @@ } ], "checks": [], - "foreignKeys": { - "service_zone_fulfillment_set_id_foreign": { - "constraintName": "service_zone_fulfillment_set_id_foreign", - "columnNames": [ - "fulfillment_set_id" - ], - "localTableName": "public.service_zone", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.fulfillment_set", - "updateRule": "cascade" - } - } + "foreignKeys": {} }, { "columns": { @@ -686,20 +673,7 @@ } ], "checks": [], - "foreignKeys": { - "geo_zone_service_zone_id_foreign": { - "constraintName": "geo_zone_service_zone_id_foreign", - "columnNames": [ - "service_zone_id" - ], - "localTableName": "public.geo_zone", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.service_zone", - "updateRule": "cascade" - } - } + "foreignKeys": {} }, { "columns": { @@ -828,6 +802,24 @@ "nullable": false, "mappedType": "text" }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "type": { + "name": "type", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, "metadata": { "name": "metadata", "type": "jsonb", @@ -873,6 +865,16 @@ "name": "shipping_profile", "schema": "public", "indexes": [ + { + "keyName": "IDX_shipping_profile_name_unique", + "columnNames": [ + "name" + ], + "composite": false, + "primary": false, + "unique": false, + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_shipping_profile_name_unique\" ON \"shipping_profile\" (name) WHERE deleted_at IS NULL" + }, { "keyName": "IDX_shipping_profile_deleted_at", "columnNames": [ @@ -945,7 +947,7 @@ "unsigned": false, "autoincrement": false, "primary": false, - "nullable": false, + "nullable": true, "mappedType": "text" }, "service_provider_id": { @@ -954,15 +956,6 @@ "unsigned": false, "autoincrement": false, "primary": false, - "nullable": false, - "mappedType": "text" - }, - "shipping_option_type_id": { - "name": "shipping_option_type_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, "nullable": true, "mappedType": "text" }, @@ -984,6 +977,15 @@ "nullable": true, "mappedType": "json" }, + "shipping_option_type_id": { + "name": "shipping_option_type_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, "created_at": { "name": "created_at", "type": "timestamptz", @@ -1091,18 +1093,6 @@ ], "checks": [], "foreignKeys": { - "shipping_option_service_zone_id_foreign": { - "constraintName": "shipping_option_service_zone_id_foreign", - "columnNames": [ - "service_zone_id" - ], - "localTableName": "public.shipping_option", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.service_zone", - "updateRule": "cascade" - }, "shipping_option_shipping_profile_id_foreign": { "constraintName": "shipping_option_shipping_profile_id_foreign", "columnNames": [ @@ -1113,6 +1103,7 @@ "id" ], "referencedTableName": "public.shipping_profile", + "deleteRule": "set null", "updateRule": "cascade" }, "shipping_option_service_provider_id_foreign": { @@ -1125,6 +1116,7 @@ "id" ], "referencedTableName": "public.service_provider", + "deleteRule": "set null", "updateRule": "cascade" }, "shipping_option_shipping_option_type_id_foreign": { @@ -1137,6 +1129,7 @@ "id" ], "referencedTableName": "public.shipping_option_type", + "deleteRule": "cascade", "updateRule": "cascade" } } @@ -1224,6 +1217,16 @@ "name": "shipping_option_rule", "schema": "public", "indexes": [ + { + "keyName": "IDX_shipping_option_rule_shipping_option_id", + "columnNames": [ + "shipping_option_id" + ], + "composite": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_rule_shipping_option_id\" ON \"shipping_option_rule\" (shipping_option_id) WHERE deleted_at IS NULL" + }, { "keyName": "IDX_shipping_option_rule_deleted_at", "columnNames": [ @@ -1245,20 +1248,7 @@ } ], "checks": [], - "foreignKeys": { - "shipping_option_rule_shipping_option_id_foreign": { - "constraintName": "shipping_option_rule_shipping_option_id_foreign", - "columnNames": [ - "shipping_option_id" - ], - "localTableName": "public.shipping_option_rule", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.shipping_option", - "updateRule": "cascade" - } - } + "foreignKeys": {} }, { "columns": { @@ -1760,7 +1750,7 @@ "composite": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_fulfillment_id\" ON \"fulfillment_item\" (line_item_id) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_line_item_id\" ON \"fulfillment_item\" (line_item_id) WHERE deleted_at IS NULL" }, { "keyName": "IDX_fulfillment_item_inventory_item_id", @@ -1770,7 +1760,7 @@ "composite": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_fulfillment_id\" ON \"fulfillment_item\" (inventory_item_id) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_inventory_item_id\" ON \"fulfillment_item\" (inventory_item_id) WHERE deleted_at IS NULL" }, { "keyName": "IDX_fulfillment_item_fulfillment_id", diff --git a/packages/fulfillment/src/migrations/Migration20240214103108.ts b/packages/fulfillment/src/migrations/Migration20240219115644.ts similarity index 86% rename from packages/fulfillment/src/migrations/Migration20240214103108.ts rename to packages/fulfillment/src/migrations/Migration20240219115644.ts index 1a7fa50ce5e2c..aa1294981b732 100644 --- a/packages/fulfillment/src/migrations/Migration20240214103108.ts +++ b/packages/fulfillment/src/migrations/Migration20240219115644.ts @@ -1,6 +1,6 @@ import { Migration } from '@mikro-orm/migrations'; -export class Migration20240214103108 extends Migration { +export class Migration20240219115644 extends Migration { async up(): Promise { this.addSql('create table if not exists "fulfillment_address" ("id" text not null, "fulfillment_id" text null, "company" text null, "first_name" text null, "last_name" text null, "address_1" text null, "address_2" text null, "city" text null, "country_code" text null, "province" text null, "postal_code" text null, "phone" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "fulfillment_address_pkey" primary key ("id"));'); @@ -30,10 +30,11 @@ export class Migration20240214103108 extends Migration { this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_type_shipping_option_id" ON "shipping_option_type" (shipping_option_id) WHERE deleted_at IS NULL;'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_type_deleted_at" ON "shipping_option_type" (deleted_at) WHERE deleted_at IS NOT NULL;'); - this.addSql('create table if not exists "shipping_profile" ("id" text not null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "shipping_profile_pkey" primary key ("id"));'); + this.addSql('create table if not exists "shipping_profile" ("id" text not null, "name" text not null, "type" text not null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "shipping_profile_pkey" primary key ("id"));'); + this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_shipping_profile_name_unique" ON "shipping_profile" (name) WHERE deleted_at IS NULL;'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_profile_deleted_at" ON "shipping_profile" (deleted_at) WHERE deleted_at IS NOT NULL;'); - this.addSql('create table if not exists "shipping_option" ("id" text not null, "name" text not null, "price_type" text check ("price_type" in (\'calculated\', \'flat\')) not null default \'calculated\', "service_zone_id" text not null, "shipping_profile_id" text not null, "service_provider_id" text not null, "shipping_option_type_id" text null, "data" jsonb null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "shipping_option_pkey" primary key ("id"));'); + this.addSql('create table if not exists "shipping_option" ("id" text not null, "name" text not null, "price_type" text check ("price_type" in (\'calculated\', \'flat\')) not null default \'calculated\', "service_zone_id" text not null, "shipping_profile_id" text null, "service_provider_id" text null, "data" jsonb null, "metadata" jsonb null, "shipping_option_type_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "shipping_option_pkey" primary key ("id"));'); this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_shipping_option_type_id_unique" unique ("shipping_option_type_id");'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_service_zone_id" ON "shipping_option" (service_zone_id) WHERE deleted_at IS NULL;'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_shipping_profile_id" ON "shipping_option" (shipping_profile_id) WHERE deleted_at IS NULL;'); @@ -42,6 +43,7 @@ export class Migration20240214103108 extends Migration { this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_deleted_at" ON "shipping_option" (deleted_at) WHERE deleted_at IS NOT NULL;'); this.addSql('create table if not exists "shipping_option_rule" ("id" text not null, "attribute" text not null, "operator" text not null, "value" jsonb null, "shipping_option_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "shipping_option_rule_pkey" primary key ("id"));'); + this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_rule_shipping_option_id" ON "shipping_option_rule" (shipping_option_id) WHERE deleted_at IS NULL;'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_shipping_option_rule_deleted_at" ON "shipping_option_rule" (deleted_at) WHERE deleted_at IS NOT NULL;'); this.addSql('create table if not exists "fulfillment" ("id" text not null, "location_id" text not null, "packed_at" timestamptz null, "shipped_at" timestamptz null, "delivered_at" timestamptz null, "canceled_at" timestamptz null, "data" jsonb null, "provider_id" text not null, "shipping_option_id" text null, "metadata" jsonb null, "delivery_address_id" text not null, "items_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "fulfillment_pkey" primary key ("id"));'); @@ -55,21 +57,14 @@ export class Migration20240214103108 extends Migration { this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_label_deleted_at" ON "fulfillment_label" (deleted_at) WHERE deleted_at IS NOT NULL;'); this.addSql('create table if not exists "fulfillment_item" ("id" text not null, "title" text not null, "sku" text not null, "barcode" text not null, "quantity" numeric not null, "line_item_id" text null, "inventory_item_id" text null, "fulfillment_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "fulfillment_item_pkey" primary key ("id"));'); - this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_item_fulfillment_id" ON "fulfillment_item" (line_item_id) WHERE deleted_at IS NULL;'); - this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_item_fulfillment_id" ON "fulfillment_item" (inventory_item_id) WHERE deleted_at IS NULL;'); + this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_item_line_item_id" ON "fulfillment_item" (line_item_id) WHERE deleted_at IS NULL;'); + this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_item_inventory_item_id" ON "fulfillment_item" (inventory_item_id) WHERE deleted_at IS NULL;'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_item_fulfillment_id" ON "fulfillment_item" (fulfillment_id) WHERE deleted_at IS NULL;'); this.addSql('CREATE INDEX IF NOT EXISTS "IDX_fulfillment_item_deleted_at" ON "fulfillment_item" (deleted_at) WHERE deleted_at IS NOT NULL;'); - this.addSql('alter table if exists "service_zone" add constraint "service_zone_fulfillment_set_id_foreign" foreign key ("fulfillment_set_id") references "fulfillment_set" ("id") on update cascade;'); - - this.addSql('alter table if exists "geo_zone" add constraint "geo_zone_service_zone_id_foreign" foreign key ("service_zone_id") references "service_zone" ("id") on update cascade;'); - - this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_service_zone_id_foreign" foreign key ("service_zone_id") references "service_zone" ("id") on update cascade;'); - this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_shipping_profile_id_foreign" foreign key ("shipping_profile_id") references "shipping_profile" ("id") on update cascade;'); - this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_service_provider_id_foreign" foreign key ("service_provider_id") references "service_provider" ("id") on update cascade;'); - this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_shipping_option_type_id_foreign" foreign key ("shipping_option_type_id") references "shipping_option_type" ("id") on update cascade;'); - - this.addSql('alter table if exists "shipping_option_rule" add constraint "shipping_option_rule_shipping_option_id_foreign" foreign key ("shipping_option_id") references "shipping_option" ("id") on update cascade;'); + this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_shipping_profile_id_foreign" foreign key ("shipping_profile_id") references "shipping_profile" ("id") on update cascade on delete set null;'); + this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_service_provider_id_foreign" foreign key ("service_provider_id") references "service_provider" ("id") on update cascade on delete set null;'); + this.addSql('alter table if exists "shipping_option" add constraint "shipping_option_shipping_option_type_id_foreign" foreign key ("shipping_option_type_id") references "shipping_option_type" ("id") on update cascade on delete cascade;'); this.addSql('alter table if exists "fulfillment" add constraint "fulfillment_shipping_option_id_foreign" foreign key ("shipping_option_id") references "shipping_option" ("id") on update cascade on delete set null;'); this.addSql('alter table if exists "fulfillment" add constraint "fulfillment_provider_id_foreign" foreign key ("provider_id") references "service_provider" ("id") on update cascade;'); diff --git a/packages/fulfillment/src/models/address.ts b/packages/fulfillment/src/models/address.ts index 1bb2a1dcbbb2a..b70907bdd4073 100644 --- a/packages/fulfillment/src/models/address.ts +++ b/packages/fulfillment/src/models/address.ts @@ -6,7 +6,6 @@ import { import { BeforeCreate, Entity, - Index, OnInit, OptionalProps, PrimaryKey, @@ -15,21 +14,17 @@ import { type OptionalAddressProps = DAL.SoftDeletableEntityDateColumns -const fulfillmentIdIndexName = "IDX_fulfillment_address_fulfillment_id" -const fulfillmentIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentIdIndexName, +const FulfillmentIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_address", columns: "fulfillment_id", where: "deleted_at IS NULL", -}).expression +}) -const fulfillmentDeletedAtIndexName = "IDX_fulfillment_address_deleted_at" -const fulfillmentDeletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentDeletedAtIndexName, +const FulfillmentDeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_address", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) @Entity({ tableName: "fulfillment_address" }) export default class Address { @@ -39,10 +34,7 @@ export default class Address { id!: string @Property({ columnType: "text", nullable: true }) - @Index({ - name: fulfillmentIdIndexName, - expression: fulfillmentIdIndexStatement, - }) + @FulfillmentIdIndex.MikroORMIndex() fulfillment_id: string | null = null @Property({ columnType: "text", nullable: true }) @@ -94,10 +86,7 @@ export default class Address { updated_at: Date @Property({ columnType: "timestamptz", nullable: true }) - @Index({ - name: fulfillmentDeletedAtIndexName, - expression: fulfillmentDeletedAtIndexStatement, - }) + @FulfillmentDeletedAtIndex.MikroORMIndex() deleted_at: Date | null = null @BeforeCreate() diff --git a/packages/fulfillment/src/models/fulfillment-item.ts b/packages/fulfillment/src/models/fulfillment-item.ts index b59a06cd9f82a..cde928de802fe 100644 --- a/packages/fulfillment/src/models/fulfillment-item.ts +++ b/packages/fulfillment/src/models/fulfillment-item.ts @@ -9,7 +9,6 @@ import { BeforeCreate, Entity, Filter, - Index, ManyToOne, OnInit, OptionalProps, @@ -20,37 +19,29 @@ import Fulfillment from "./fulfillment" type FulfillmentItemOptionalProps = DAL.SoftDeletableEntityDateColumns -const fulfillmentIdIndexName = "IDX_fulfillment_item_fulfillment_id" -const fulfillmentIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentIdIndexName, +const FulfillmentIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_item", columns: "fulfillment_id", where: "deleted_at IS NULL", -}).expression +}) -const lineItemIndexName = "IDX_fulfillment_item_line_item_id" -const lineItemIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentIdIndexName, +const LineItemIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_item", columns: "line_item_id", where: "deleted_at IS NULL", -}).expression +}) -const inventoryItemIndexName = "IDX_fulfillment_item_inventory_item_id" -const inventoryItemIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentIdIndexName, +const InventoryItemIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_item", columns: "inventory_item_id", where: "deleted_at IS NULL", -}).expression +}) -const fulfillmentItemDeletedAtIndexName = "IDX_fulfillment_item_deleted_at" -const fulfillmentItemDeletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentItemDeletedAtIndexName, +const FulfillmentItemDeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_item", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -73,24 +64,15 @@ export default class FulfillmentItem { quantity: number // TODO: probably allow big numbers here @Property({ columnType: "text", nullable: true }) - @Index({ - name: lineItemIndexName, - expression: lineItemIdIndexStatement, - }) + @LineItemIdIndex.MikroORMIndex() line_item_id: string | null = null @Property({ columnType: "text", nullable: true }) - @Index({ - name: inventoryItemIndexName, - expression: inventoryItemIdIndexStatement, - }) + @InventoryItemIdIndex.MikroORMIndex() inventory_item_id: string | null = null @Property({ columnType: "text" }) - @Index({ - name: fulfillmentIdIndexName, - expression: fulfillmentIdIndexStatement, - }) + @FulfillmentIdIndex.MikroORMIndex() fulfillment_id: string @ManyToOne(() => Fulfillment) @@ -111,10 +93,7 @@ export default class FulfillmentItem { }) updated_at: Date - @Index({ - name: fulfillmentItemDeletedAtIndexName, - expression: fulfillmentItemDeletedAtIndexStatement, - }) + @FulfillmentItemDeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null diff --git a/packages/fulfillment/src/models/fulfillment-label.ts b/packages/fulfillment/src/models/fulfillment-label.ts index ae35ade0a1b81..8640e5117ffad 100644 --- a/packages/fulfillment/src/models/fulfillment-label.ts +++ b/packages/fulfillment/src/models/fulfillment-label.ts @@ -9,7 +9,6 @@ import { BeforeCreate, Entity, Filter, - Index, ManyToOne, OnInit, OptionalProps, @@ -20,21 +19,17 @@ import Fulfillment from "./fulfillment" type FulfillmentLabelOptionalProps = DAL.SoftDeletableEntityDateColumns -const fulfillmentIdIndexName = "IDX_fulfillment_label_fulfillment_id" -const fulfillmentIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentIdIndexName, +const FulfillmentIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_label", columns: "fulfillment_id", where: "deleted_at IS NULL", -}).expression +}) -const deletedAtIndexName = "IDX_fulfillment_label_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_label", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -54,10 +49,7 @@ export default class FulfillmentLabel { label_url: string @Property({ columnType: "text" }) - @Index({ - name: fulfillmentIdIndexName, - expression: fulfillmentIdIndexStatement, - }) + @FulfillmentIdIndex.MikroORMIndex() fulfillment_id: string @ManyToOne(() => Fulfillment) @@ -79,10 +71,7 @@ export default class FulfillmentLabel { updated_at: Date @Property({ columnType: "timestamptz", nullable: true }) - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() deleted_at: Date | null = null @BeforeCreate() diff --git a/packages/fulfillment/src/models/fulfillment.ts b/packages/fulfillment/src/models/fulfillment.ts index f2cbca71a1429..77b4e9cbbb149 100644 --- a/packages/fulfillment/src/models/fulfillment.ts +++ b/packages/fulfillment/src/models/fulfillment.ts @@ -10,7 +10,6 @@ import { Collection, Entity, Filter, - Index, ManyToOne, OneToMany, OnInit, @@ -26,39 +25,29 @@ import ShippingOption from "./shipping-option" type FulfillmentOptionalProps = DAL.SoftDeletableEntityDateColumns -const fulfillmentDeletedAtIndexName = "IDX_fulfillment_deleted_at" -const fulfillmentDeletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentDeletedAtIndexName, +const FulfillmentDeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) -const fulfillmentProviderIdIndexName = "IDX_fulfillment_provider_id" -const fulfillmentProviderIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentProviderIdIndexName, +const FulfillmentProviderIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment", columns: "provider_id", where: "deleted_at IS NULL", -}).expression +}) -const fulfillmentLocationIdIndexName = "IDX_fulfillment_location_id" -const fulfillmentLocationIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentLocationIdIndexName, +const FulfillmentLocationIdIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment", columns: "location_id", where: "deleted_at IS NULL", -}).expression - -const fulfillmentShippingOptionIdIndexName = - "IDX_fulfillment_shipping_option_id" -const fulfillmentShippingOptionIdIndexStatement = - createPsqlIndexStatementHelper({ - name: fulfillmentShippingOptionIdIndexName, - tableName: "fulfillment", - columns: "shipping_option_id", - where: "deleted_at IS NULL", - }).expression +}) + +const FulfillmentShippingOptionIdIndex = createPsqlIndexStatementHelper({ + tableName: "fulfillment", + columns: "shipping_option_id", + where: "deleted_at IS NULL", +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -69,10 +58,7 @@ export default class Fulfillment { id: string @Property({ columnType: "text" }) - @Index({ - name: fulfillmentLocationIdIndexName, - expression: fulfillmentLocationIdIndexStatement, - }) + @FulfillmentLocationIdIndex.MikroORMIndex() location_id: string @Property({ @@ -103,17 +89,11 @@ export default class Fulfillment { data: Record | null = null @Property({ columnType: "text" }) - @Index({ - name: fulfillmentProviderIdIndexName, - expression: fulfillmentProviderIdIndexStatement, - }) + @FulfillmentProviderIdIndex.MikroORMIndex() provider_id: string @Property({ columnType: "text", nullable: true }) - @Index({ - name: fulfillmentShippingOptionIdIndexName, - expression: fulfillmentShippingOptionIdIndexStatement, - }) + @FulfillmentShippingOptionIdIndex.MikroORMIndex() shipping_option_id: string | null = null @Property({ columnType: "jsonb", nullable: true }) @@ -149,10 +129,7 @@ export default class Fulfillment { }) updated_at: Date - @Index({ - name: fulfillmentDeletedAtIndexName, - expression: fulfillmentDeletedAtIndexStatement, - }) + @FulfillmentDeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null diff --git a/packages/fulfillment/src/models/fullfilment-set.ts b/packages/fulfillment/src/models/fullfilment-set.ts index 55a4623565318..ccf4e20230977 100644 --- a/packages/fulfillment/src/models/fullfilment-set.ts +++ b/packages/fulfillment/src/models/fullfilment-set.ts @@ -11,7 +11,6 @@ import { Collection, Entity, Filter, - Index, OneToMany, OnInit, OptionalProps, @@ -22,22 +21,18 @@ import ServiceZone from "./service-zone" type FulfillmentSetOptionalProps = DAL.SoftDeletableEntityDateColumns -const deletedAtIndexName = "IDX_fulfillment_set_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_set", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) -const nameIndexName = "IDX_fulfillment_set_name_unique" -const nameIndexStatement = createPsqlIndexStatementHelper({ - name: nameIndexName, +const NameIndex = createPsqlIndexStatementHelper({ tableName: "fulfillment_set", columns: "name", unique: true, where: "deleted_at IS NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -48,10 +43,7 @@ export default class FulfillmentSet { id: string @Property({ columnType: "text" }) - @Index({ - name: nameIndexName, - expression: nameIndexStatement, - }) + @NameIndex.MikroORMIndex() name: string @Property({ columnType: "text" }) @@ -82,10 +74,7 @@ export default class FulfillmentSet { updated_at: Date @Property({ columnType: "timestamptz", nullable: true }) - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() deleted_at: Date | null = null @BeforeCreate() diff --git a/packages/fulfillment/src/models/geo-zone.ts b/packages/fulfillment/src/models/geo-zone.ts index 85d2f7ba72d01..3b557ead45623 100644 --- a/packages/fulfillment/src/models/geo-zone.ts +++ b/packages/fulfillment/src/models/geo-zone.ts @@ -11,7 +11,6 @@ import { Entity, Enum, Filter, - Index, ManyToOne, OnInit, OptionalProps, @@ -22,45 +21,35 @@ import ServiceZone from "./service-zone" type GeoZoneOptionalProps = DAL.SoftDeletableEntityDateColumns -const deletedAtIndexName = "IDX_geo_zone_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "geo_zone", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) -const countryCodeIndexName = "IDX_geo_zone_country_code" -const countryCodeIndexStatement = createPsqlIndexStatementHelper({ - name: countryCodeIndexName, +const CountryCodeIndex = createPsqlIndexStatementHelper({ tableName: "geo_zone", columns: "country_code", where: "deleted_at IS NULL", -}).expression +}) -const provinceCodeIndexName = "IDX_geo_zone_province_code" -const provinceCodeIndexStatement = createPsqlIndexStatementHelper({ - name: provinceCodeIndexName, +const ProvinceCodeIndex = createPsqlIndexStatementHelper({ tableName: "geo_zone", columns: "province_code", where: "deleted_at IS NULL AND province_code IS NOT NULL", -}).expression +}) -const cityIndexName = "IDX_geo_zone_city" -const cityIndexStatement = createPsqlIndexStatementHelper({ - name: cityIndexName, +const CityIndex = createPsqlIndexStatementHelper({ tableName: "geo_zone", columns: "city", where: "deleted_at IS NULL AND city IS NOT NULL", -}).expression +}) -const serviceZoneIdIndexName = "IDX_geo_zone_service_zone_id" -const serviceZoneIdStatement = createPsqlIndexStatementHelper({ - name: serviceZoneIdIndexName, +const ServiceZoneIdIndex = createPsqlIndexStatementHelper({ tableName: "geo_zone", columns: "service_zone_id", where: "deleted_at IS NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -73,32 +62,20 @@ export default class GeoZone { @Enum({ items: () => GeoZoneType, default: GeoZoneType.COUNTRY }) type: GeoZoneType - @Index({ - name: countryCodeIndexName, - expression: countryCodeIndexStatement, - }) + @CountryCodeIndex.MikroORMIndex() @Property({ columnType: "text" }) country_code: string - @Index({ - name: provinceCodeIndexName, - expression: provinceCodeIndexStatement, - }) + @ProvinceCodeIndex.MikroORMIndex() @Property({ columnType: "text", nullable: true }) province_code: string | null = null - @Index({ - name: cityIndexName, - expression: cityIndexStatement, - }) + @CityIndex.MikroORMIndex() @Property({ columnType: "text", nullable: true }) city: string | null = null @Property({ columnType: "text" }) - @Index({ - name: serviceZoneIdIndexName, - expression: serviceZoneIdStatement, - }) + @ServiceZoneIdIndex.MikroORMIndex() service_zone_id: string // TODO: Do we have an example or idea of what would be stored in this field? like lat/long for example? @@ -128,10 +105,7 @@ export default class GeoZone { }) updated_at: Date - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null diff --git a/packages/fulfillment/src/models/service-provider.ts b/packages/fulfillment/src/models/service-provider.ts index 4855c60c4f31a..77784a969f6ae 100644 --- a/packages/fulfillment/src/models/service-provider.ts +++ b/packages/fulfillment/src/models/service-provider.ts @@ -10,7 +10,6 @@ import { Collection, Entity, Filter, - Index, OneToMany, OnInit, OptionalProps, @@ -21,13 +20,11 @@ import ShippingOption from "./shipping-option" type ServiceProviderOptionalProps = DAL.SoftDeletableEntityDateColumns -const deletedAtIndexName = "IDX_service_provider_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "service_provider", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -61,10 +58,7 @@ export default class ServiceProvider { }) updated_at: Date - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null diff --git a/packages/fulfillment/src/models/service-zone.ts b/packages/fulfillment/src/models/service-zone.ts index fb5d5114043ee..cb73a9f39aedc 100644 --- a/packages/fulfillment/src/models/service-zone.ts +++ b/packages/fulfillment/src/models/service-zone.ts @@ -33,22 +33,18 @@ const deletedAtIndexStatement = createPsqlIndexStatementHelper({ where: "deleted_at IS NOT NULL", }).expression -const nameIndexName = "IDX_service_zone_name_unique" -const nameIndexStatement = createPsqlIndexStatementHelper({ - name: nameIndexName, +const NameIndex = createPsqlIndexStatementHelper({ tableName: "service_zone", columns: "name", unique: true, where: "deleted_at IS NULL", -}).expression +}) -const fulfillmentSetIdIndexName = "IDX_service_zone_fulfillment_set_id" -const fulfillmentSetIdIndexStatement = createPsqlIndexStatementHelper({ - name: fulfillmentSetIdIndexName, +const FulfillmentSetIdIndex = createPsqlIndexStatementHelper({ tableName: "service_zone", columns: "fulfillment_set_id", where: "deleted_at IS NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -59,20 +55,14 @@ export default class ServiceZone { id: string @Property({ columnType: "text" }) - @Index({ - name: nameIndexName, - expression: nameIndexStatement, - }) + @NameIndex.MikroORMIndex() name: string @Property({ columnType: "jsonb", nullable: true }) metadata: Record | null = null @Property({ columnType: "text" }) - @Index({ - name: fulfillmentSetIdIndexName, - expression: fulfillmentSetIdIndexStatement, - }) + @FulfillmentSetIdIndex.MikroORMIndex() fulfillment_set_id: string @ManyToOne(() => FulfillmentSet, { persist: false }) diff --git a/packages/fulfillment/src/models/shipping-option-rule.ts b/packages/fulfillment/src/models/shipping-option-rule.ts index b4bc049b4ebf0..5a0f4a7582682 100644 --- a/packages/fulfillment/src/models/shipping-option-rule.ts +++ b/packages/fulfillment/src/models/shipping-option-rule.ts @@ -9,7 +9,6 @@ import { BeforeCreate, Entity, Filter, - Index, ManyToOne, OnInit, OptionalProps, @@ -20,16 +19,17 @@ import ShippingOption from "./shipping-option" type ShippingOptionRuleOptionalProps = DAL.SoftDeletableEntityDateColumns -// TODO: need some test to see if we continue with this kind of structure or we change it -// More adjustments can appear as I move forward - -const deletedAtIndexName = "IDX_shipping_option_rule_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option_rule", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) + +const ShippingOptionIdIndex = createPsqlIndexStatementHelper({ + tableName: "shipping_option_rule", + columns: "shipping_option_id", + where: "deleted_at IS NULL", +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -49,9 +49,10 @@ export default class ShippingOptionRule { value: { value: string | string[] } | null = null @Property({ columnType: "text" }) + @ShippingOptionIdIndex.MikroORMIndex() shipping_option_id: string - @ManyToOne(() => ShippingOption) + @ManyToOne(() => ShippingOption, { persist: false }) shipping_option: ShippingOption @Property({ @@ -69,20 +70,19 @@ export default class ShippingOptionRule { }) updated_at: Date - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "sorul") + this.shipping_option_id ??= this.shipping_option?.id } @OnInit() onInit() { this.id = generateEntityId(this.id, "sorul") + this.shipping_option_id ??= this.shipping_option?.id } } diff --git a/packages/fulfillment/src/models/shipping-option-type.ts b/packages/fulfillment/src/models/shipping-option-type.ts index 80858b4511feb..ea643211fc0d3 100644 --- a/packages/fulfillment/src/models/shipping-option-type.ts +++ b/packages/fulfillment/src/models/shipping-option-type.ts @@ -9,7 +9,6 @@ import { BeforeCreate, Entity, Filter, - Index, OneToOne, OnInit, OptionalProps, @@ -20,21 +19,17 @@ import ShippingOption from "./shipping-option" type ShippingOptionTypeOptionalProps = DAL.SoftDeletableEntityDateColumns -const deletedAtIndexName = "IDX_shipping_option_type_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option_type", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) -const shippingOptionIdIndexName = "IDX_shipping_option_type_shipping_option_id" -const shippingOptionIdIndexStatement = createPsqlIndexStatementHelper({ - name: shippingOptionIdIndexName, +const ShippingOptionIdIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option_type", columns: "shipping_option_id", where: "deleted_at IS NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -54,13 +49,12 @@ export default class ShippingOptionType { code: string @Property({ columnType: "text" }) - @Index({ - name: shippingOptionIdIndexName, - expression: shippingOptionIdIndexStatement, - }) + @ShippingOptionIdIndex.MikroORMIndex() shipping_option_id: string - @OneToOne(() => ShippingOption, (so) => so.shipping_option_type) + @OneToOne(() => ShippingOption, (so) => so.type, { + persist: false, + }) shipping_option: ShippingOption @Property({ @@ -78,20 +72,19 @@ export default class ShippingOptionType { }) updated_at: Date - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "sotype") + this.shipping_option_id ??= this.shipping_option?.id } @OnInit() onInit() { this.id = generateEntityId(this.id, "sotype") + this.shipping_option_id ??= this.shipping_option?.id } } diff --git a/packages/fulfillment/src/models/shipping-option.ts b/packages/fulfillment/src/models/shipping-option.ts index 1c9d8ea267ef5..7c5dfa43c62ec 100644 --- a/packages/fulfillment/src/models/shipping-option.ts +++ b/packages/fulfillment/src/models/shipping-option.ts @@ -8,11 +8,11 @@ import { import { DAL } from "@medusajs/types" import { BeforeCreate, + Cascade, Collection, Entity, Enum, Filter, - Index, ManyToOne, OneToMany, OneToOne, @@ -30,46 +30,35 @@ import ShippingProfile from "./shipping-profile" type ShippingOptionOptionalProps = DAL.SoftDeletableEntityDateColumns -const deletedAtIndexName = "IDX_shipping_option_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) -const serviceZoneIdIndexName = "IDX_shipping_option_service_zone_id" -const serviceZoneIdIndexStatement = createPsqlIndexStatementHelper({ - name: serviceZoneIdIndexName, +const ServiceZoneIdIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option", columns: "service_zone_id", where: "deleted_at IS NULL", -}).expression +}) -const shippingProfileIdIndexName = "IDX_shipping_option_shipping_profile_id" -const shippingProfileIdIndexStatement = createPsqlIndexStatementHelper({ - name: shippingProfileIdIndexName, +const ShippingProfileIdIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option", columns: "shipping_profile_id", where: "deleted_at IS NULL", -}).expression +}) -const serviceProviderIdIndexName = "IDX_shipping_option_service_provider_id" -const serviceProviderIdIndexStatement = createPsqlIndexStatementHelper({ - name: serviceProviderIdIndexName, +const ServiceProviderIdIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option", columns: "service_provider_id", where: "deleted_at IS NULL", -}).expression +}) -const shippingOptionTypeIdIndexName = - "IDX_shipping_option_shipping_option_type_id" -const shippingOptionTypeIdIndexStatement = createPsqlIndexStatementHelper({ - name: shippingOptionTypeIdIndexName, +const ShippingOptionTypeIdIndex = createPsqlIndexStatementHelper({ tableName: "shipping_option", columns: "shipping_option_type_id", where: "deleted_at IS NULL", -}).expression +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -88,32 +77,34 @@ export default class ShippingOption { }) price_type: ShippingOptionPriceType - @Property({ columnType: "text" }) - @Index({ - name: serviceZoneIdIndexName, - expression: serviceZoneIdIndexStatement, + @ManyToOne(() => ShippingProfile, { + type: "text", + fieldName: "service_zone_id", + mapToPk: true, }) + @ServiceZoneIdIndex.MikroORMIndex() service_zone_id: string - @Property({ columnType: "text" }) - @Index({ - name: shippingProfileIdIndexName, - expression: shippingProfileIdIndexStatement, + @ManyToOne(() => ShippingProfile, { + type: "text", + fieldName: "shipping_profile_id", + mapToPk: true, + nullable: true, }) - shipping_profile_id: string - - @Property({ columnType: "text" }) - @Index({ - name: serviceProviderIdIndexName, - expression: serviceProviderIdIndexStatement, + @ShippingProfileIdIndex.MikroORMIndex() + shipping_profile_id: string | null + + @ManyToOne(() => ServiceProvider, { + type: "text", + fieldName: "service_provider_id", + mapToPk: true, + nullable: true, }) + @ServiceProviderIdIndex.MikroORMIndex() service_provider_id: string - @Property({ columnType: "text", nullable: true }) - @Index({ - name: shippingOptionTypeIdIndexName, - expression: shippingOptionTypeIdIndexStatement, - }) + @Property({ columnType: "text", persist: false }) + @ShippingOptionTypeIdIndex.MikroORMIndex() shipping_option_type_id: string | null = null @Property({ columnType: "jsonb", nullable: true }) @@ -122,21 +113,30 @@ export default class ShippingOption { @Property({ columnType: "jsonb", nullable: true }) metadata: Record | null = null - @ManyToOne(() => ServiceZone) + @ManyToOne(() => ServiceZone, { persist: false }) service_zone: ServiceZone - @ManyToOne(() => ShippingProfile) - shipping_profile: ShippingProfile + @ManyToOne(() => ShippingProfile, { + persist: false, + }) + shipping_profile: ShippingProfile | null - @ManyToOne(() => ServiceProvider) - service_provider: ServiceProvider + @ManyToOne(() => ServiceProvider, { + persist: false, + }) + service_provider: ServiceProvider | null @OneToOne(() => ShippingOptionType, (so) => so.shipping_option, { owner: true, + cascade: [Cascade.PERSIST, Cascade.REMOVE, "soft-remove"] as any, + fieldName: "shipping_option_type_id", }) - shipping_option_type: ShippingOptionType + type: ShippingOptionType - @OneToMany(() => ShippingOptionRule, (sor) => sor.shipping_option) + @OneToMany(() => ShippingOptionRule, "shipping_option", { + cascade: [Cascade.PERSIST, "soft-remove"] as any, + orphanRemoval: true, + }) rules = new Collection(this) @OneToMany(() => Fulfillment, (fulfillment) => fulfillment.shipping_option) @@ -157,20 +157,19 @@ export default class ShippingOption { }) updated_at: Date - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null @BeforeCreate() onCreate() { this.id = generateEntityId(this.id, "so") + this.shipping_option_type_id ??= this.type?.id } @OnInit() onInit() { this.id = generateEntityId(this.id, "so") + this.shipping_option_type_id ??= this.type?.id } } diff --git a/packages/fulfillment/src/models/shipping-profile.ts b/packages/fulfillment/src/models/shipping-profile.ts index b8a359e64b775..87db7f40b68d1 100644 --- a/packages/fulfillment/src/models/shipping-profile.ts +++ b/packages/fulfillment/src/models/shipping-profile.ts @@ -10,7 +10,6 @@ import { Collection, Entity, Filter, - Index, OneToMany, OnInit, OptionalProps, @@ -21,13 +20,18 @@ import ShippingOption from "./shipping-option" type ShippingProfileOptionalProps = DAL.SoftDeletableEntityDateColumns -const deletedAtIndexName = "IDX_shipping_profile_deleted_at" -const deletedAtIndexStatement = createPsqlIndexStatementHelper({ - name: deletedAtIndexName, +const DeletedAtIndex = createPsqlIndexStatementHelper({ tableName: "shipping_profile", columns: "deleted_at", where: "deleted_at IS NOT NULL", -}).expression +}) + +const ShippingProfileTypeIndex = createPsqlIndexStatementHelper({ + tableName: "shipping_profile", + columns: "name", + unique: true, + where: "deleted_at IS NULL", +}) @Entity() @Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) @@ -37,6 +41,13 @@ export default class ShippingProfile { @PrimaryKey({ columnType: "text" }) id: string + @Property({ columnType: "text" }) + @ShippingProfileTypeIndex.MikroORMIndex() + name: string + + @Property({ columnType: "text" }) + type: string + @OneToMany( () => ShippingOption, (shippingOption) => shippingOption.shipping_profile @@ -61,10 +72,7 @@ export default class ShippingProfile { }) updated_at: Date - @Index({ - name: deletedAtIndexName, - expression: deletedAtIndexStatement, - }) + @DeletedAtIndex.MikroORMIndex() @Property({ columnType: "timestamptz", nullable: true }) deleted_at: Date | null = null diff --git a/packages/fulfillment/src/module-definition.ts b/packages/fulfillment/src/module-definition.ts index db6f694b69753..bc17d7d091436 100644 --- a/packages/fulfillment/src/module-definition.ts +++ b/packages/fulfillment/src/module-definition.ts @@ -34,7 +34,7 @@ const connectionLoader = ModulesSdkUtils.mikroOrmConnectionLoaderFactory({ }) const service = FulfillmentModuleService -const loaders = [containerLoader, connectionLoader] as any +const loaders = [containerLoader, connectionLoader] export const moduleDefinition: ModuleExports = { service, diff --git a/packages/fulfillment/src/services/fulfillment-module-service.ts b/packages/fulfillment/src/services/fulfillment-module-service.ts index 2dbd8de4efc48..e65c3be8c179e 100644 --- a/packages/fulfillment/src/services/fulfillment-module-service.ts +++ b/packages/fulfillment/src/services/fulfillment-module-service.ts @@ -9,31 +9,46 @@ import { UpdateFulfillmentSetDTO, } from "@medusajs/types" import { + getSetDifference, InjectManager, InjectTransactionManager, MedusaContext, MedusaError, ModulesSdkUtils, promiseAll, - getSetDifference } from "@medusajs/utils" import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" -import { FulfillmentSet, GeoZone, ServiceZone, ShippingOption } from "@models" - -const generateMethodForModels = [ServiceZone, ShippingOption, GeoZone] +import { + FulfillmentSet, + GeoZone, + ServiceZone, + ShippingOption, + ShippingProfile, +} from "@models" + +const generateMethodForModels = [ + ServiceZone, + ShippingOption, + GeoZone, + ShippingProfile, +] type InjectedDependencies = { baseRepository: DAL.RepositoryService fulfillmentSetService: ModulesSdkTypes.InternalModuleService serviceZoneService: ModulesSdkTypes.InternalModuleService geoZoneService: ModulesSdkTypes.InternalModuleService + shippingProfileService: ModulesSdkTypes.InternalModuleService + shippingOptionService: ModulesSdkTypes.InternalModuleService } export default class FulfillmentModuleService< TEntity extends FulfillmentSet = FulfillmentSet, TServiceZoneEntity extends ServiceZone = ServiceZone, - TGeoZoneEntity extends GeoZone = GeoZone + TGeoZoneEntity extends GeoZone = GeoZone, + TShippingProfileEntity extends ShippingProfile = ShippingProfile, + TShippingOptionEntity extends ShippingOption = ShippingOption > extends ModulesSdkUtils.abstractModuleServiceFactory< InjectedDependencies, @@ -43,6 +58,7 @@ export default class FulfillmentModuleService< ServiceZone: { dto: FulfillmentTypes.ServiceZoneDTO } ShippingOption: { dto: FulfillmentTypes.ShippingOptionDTO } GeoZone: { dto: FulfillmentTypes.GeoZoneDTO } + ShippingProfile: { dto: FulfillmentTypes.ShippingProfileDTO } } >(FulfillmentSet, generateMethodForModels, entityNameToLinkableKeysMap) implements IFulfillmentModuleService @@ -51,6 +67,8 @@ export default class FulfillmentModuleService< protected readonly fulfillmentSetService_: ModulesSdkTypes.InternalModuleService protected readonly serviceZoneService_: ModulesSdkTypes.InternalModuleService protected readonly geoZoneService_: ModulesSdkTypes.InternalModuleService + protected readonly shippingProfileService_: ModulesSdkTypes.InternalModuleService + protected readonly shippingOptionService_: ModulesSdkTypes.InternalModuleService constructor( { @@ -58,6 +76,8 @@ export default class FulfillmentModuleService< fulfillmentSetService, serviceZoneService, geoZoneService, + shippingProfileService, + shippingOptionService, }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { @@ -67,6 +87,8 @@ export default class FulfillmentModuleService< this.fulfillmentSetService_ = fulfillmentSetService this.serviceZoneService_ = serviceZoneService this.geoZoneService_ = geoZoneService + this.shippingProfileService_ = shippingProfileService + this.shippingOptionService_ = shippingOptionService } __joinerConfig(): ModuleJoinerConfig { @@ -179,7 +201,7 @@ export default class FulfillmentModuleService< sharedContext?: Context ): Promise - @InjectTransactionManager("baseRepository_") + @InjectManager("baseRepository_") async createShippingOptions( data: | FulfillmentTypes.CreateShippingOptionDTO[] @@ -188,7 +210,93 @@ export default class FulfillmentModuleService< ): Promise< FulfillmentTypes.ShippingOptionDTO | FulfillmentTypes.ShippingOptionDTO[] > { - return [] + const createdShippingOptions = await this.createShippingOptions_( + data, + sharedContext + ) + + return await this.baseRepository_.serialize< + FulfillmentTypes.ShippingOptionDTO | FulfillmentTypes.ShippingOptionDTO[] + >(createdShippingOptions, { + populate: true, + }) + } + + @InjectTransactionManager("baseRepository_") + async createShippingOptions_( + data: + | FulfillmentTypes.CreateShippingOptionDTO[] + | FulfillmentTypes.CreateShippingOptionDTO, + @MedusaContext() sharedContext: Context = {} + ): Promise { + let data_ = Array.isArray(data) ? data : [data] + + if (!data_.length) { + return [] + } + + const createdShippingOptions = await this.shippingOptionService_.create( + data_, + sharedContext + ) + + return Array.isArray(data) + ? createdShippingOptions + : createdShippingOptions[0] + } + + createShippingProfiles( + data: FulfillmentTypes.CreateShippingProfileDTO[], + sharedContext?: Context + ): Promise + createShippingProfiles( + data: FulfillmentTypes.CreateShippingProfileDTO, + sharedContext?: Context + ): Promise + + @InjectTransactionManager("baseRepository_") + async createShippingProfiles( + data: + | FulfillmentTypes.CreateShippingProfileDTO[] + | FulfillmentTypes.CreateShippingProfileDTO, + @MedusaContext() sharedContext: Context = {} + ): Promise< + FulfillmentTypes.ShippingProfileDTO | FulfillmentTypes.ShippingProfileDTO[] + > { + const createdShippingProfiles = await this.createShippingProfiles_( + data, + sharedContext + ) + + return await this.baseRepository_.serialize< + | FulfillmentTypes.ShippingProfileDTO + | FulfillmentTypes.ShippingProfileDTO[] + >(createdShippingProfiles, { + populate: true, + }) + } + + @InjectTransactionManager("baseRepository_") + async createShippingProfiles_( + data: + | FulfillmentTypes.CreateShippingProfileDTO[] + | FulfillmentTypes.CreateShippingProfileDTO, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + + if (!data_.length) { + return [] + } + + const createdShippingProfiles = await this.shippingProfileService_.create( + data_, + sharedContext + ) + + return Array.isArray(data) + ? createdShippingProfiles + : createdShippingProfiles[0] } createGeoZones( @@ -473,7 +581,6 @@ export default class FulfillmentModuleService< serviceZones.map((s) => [s.id, s]) ) - const serviceZoneIdsToDelete: string[] = [] const geoZoneIdsToDelete: string[] = [] data_.forEach((serviceZone) => { @@ -567,6 +674,27 @@ export default class FulfillmentModuleService< return [] } + updateShippingProfiles( + data: FulfillmentTypes.UpdateShippingProfileDTO[], + sharedContext?: Context + ): Promise + updateShippingProfiles( + data: FulfillmentTypes.UpdateShippingProfileDTO, + sharedContext?: Context + ): Promise + + @InjectTransactionManager("baseRepository_") + async updateShippingProfiles( + data: + | FulfillmentTypes.UpdateShippingProfileDTO + | FulfillmentTypes.UpdateShippingProfileDTO[], + @MedusaContext() sharedContext: Context = {} + ): Promise< + FulfillmentTypes.ShippingProfileDTO | FulfillmentTypes.ShippingProfileDTO[] + > { + return [] + } + updateGeoZones( data: FulfillmentTypes.UpdateGeoZoneDTO[], sharedContext?: Context diff --git a/packages/medusa-test-utils/src/database.ts b/packages/medusa-test-utils/src/database.ts index 30b513ef7a365..dc8c454ff92d7 100644 --- a/packages/medusa-test-utils/src/database.ts +++ b/packages/medusa-test-utils/src/database.ts @@ -1,24 +1,28 @@ import { MikroORM, Options, SqlEntityManager } from "@mikro-orm/postgresql" -import * as process from "process" -import { Migrator } from "@mikro-orm/migrations" -export function getDatabaseURL(): string { +export function getDatabaseURL(dbName?: string): string { const DB_HOST = process.env.DB_HOST ?? "localhost" const DB_USERNAME = process.env.DB_USERNAME ?? "" const DB_PASSWORD = process.env.DB_PASSWORD - const DB_NAME = process.env.DB_TEMP_NAME + const DB_NAME = dbName ?? process.env.DB_TEMP_NAME return `postgres://${DB_USERNAME}${ DB_PASSWORD ? `:${DB_PASSWORD}` : "" }@${DB_HOST}/${DB_NAME}` } -export function getMikroOrmConfig( - mikroOrmEntities: any[], - pathToMigrations: string, // deprecated, auto inferred +export function getMikroOrmConfig({ + mikroOrmEntities, + pathToMigrations, + clientUrl, + schema, +}: { + mikroOrmEntities: any[] + pathToMigrations?: string + clientUrl?: string schema?: string -): Options { - const DB_URL = getDatabaseURL() +}): Options { + const DB_URL = clientUrl ?? getDatabaseURL() return { type: "postgresql", @@ -26,14 +30,18 @@ export function getMikroOrmConfig( entities: Object.values(mikroOrmEntities), schema: schema ?? process.env.MEDUSA_DB_SCHEMA, debug: false, - extensions: [Migrator], + migrations: { + pathTs: pathToMigrations, + silent: true, + }, } } export interface TestDatabase { mikroOrmEntities: any[] - pathToMigrations: any // deprecated, auto inferred + pathToMigrations?: string schema?: string + clientUrl?: string orm: MikroORM | null manager: SqlEntityManager | null @@ -45,14 +53,21 @@ export interface TestDatabase { getOrm(): MikroORM } -export function getMikroOrmWrapper( - mikroOrmEntities: any[], - pathToMigrations: string, // deprecated, auto inferred +export function getMikroOrmWrapper({ + mikroOrmEntities, + pathToMigrations, + clientUrl, + schema, +}: { + mikroOrmEntities: any[] + pathToMigrations?: string + clientUrl?: string schema?: string -): TestDatabase { +}): TestDatabase { return { mikroOrmEntities, - pathToMigrations, // deprecated, auto inferred + pathToMigrations, + clientUrl: clientUrl ?? getDatabaseURL(), schema: schema ?? process.env.MEDUSA_DB_SCHEMA, orm: null, @@ -83,11 +98,12 @@ export function getMikroOrmWrapper( }, async setupDatabase() { - const OrmConfig = getMikroOrmConfig( - this.mikroOrmEntities, - this.pathToMigrations, - this.schema - ) + const OrmConfig = getMikroOrmConfig({ + mikroOrmEntities: this.mikroOrmEntities, + pathToMigrations: this.pathToMigrations, + clientUrl: this.clientUrl, + schema: this.schema, + }) // Initializing the ORM this.orm = await MikroORM.init(OrmConfig) @@ -96,7 +112,9 @@ export function getMikroOrmWrapper( try { await this.orm.getSchemaGenerator().ensureDatabase() - } catch (err) {} + } catch (err) { + console.log(err) + } await this.manager?.execute( `CREATE SCHEMA IF NOT EXISTS "${this.schema ?? "public"}";` diff --git a/packages/medusa-test-utils/src/index.ts b/packages/medusa-test-utils/src/index.ts index 8351d210971fb..b53e60a744451 100644 --- a/packages/medusa-test-utils/src/index.ts +++ b/packages/medusa-test-utils/src/index.ts @@ -4,3 +4,4 @@ export * as JestUtils from "./jest" export { default as MockManager } from "./mock-manager" export { default as MockRepository } from "./mock-repository" export * from "./init-modules" +export * from "./module-test-runner" diff --git a/packages/medusa-test-utils/src/init-modules.ts b/packages/medusa-test-utils/src/init-modules.ts index 067c70a4c339f..4e4c4ad02b214 100644 --- a/packages/medusa-test-utils/src/init-modules.ts +++ b/packages/medusa-test-utils/src/init-modules.ts @@ -1,13 +1,12 @@ -import { knex } from "knex" import { MedusaApp, MedusaModule, MedusaModuleConfig, ModuleJoinerConfig, } from "@medusajs/modules-sdk" -import { ContainerRegistrationKeys } from "@medusajs/utils" +import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils" -interface InitModulesOptions { +export interface InitModulesOptions { injectedDependencies?: Record databaseConfig: { clientUrl: string @@ -15,6 +14,7 @@ interface InitModulesOptions { } modulesConfig: MedusaModuleConfig joinerConfig?: ModuleJoinerConfig[] + preventConnectionDestroyWarning?: boolean } export async function initModules({ @@ -22,19 +22,18 @@ export async function initModules({ databaseConfig, modulesConfig, joinerConfig, + preventConnectionDestroyWarning = false, }: InitModulesOptions) { injectedDependencies ??= {} let sharedPgConnection = injectedDependencies?.[ContainerRegistrationKeys.PG_CONNECTION] + let shouldDestroyConnectionAutomatically = !sharedPgConnection if (!sharedPgConnection) { - sharedPgConnection = knex({ - client: "pg", - searchPath: databaseConfig.schema, - connection: { - connectionString: databaseConfig.clientUrl, - }, + sharedPgConnection = ModulesSdkUtils.createPgConnection({ + clientUrl: databaseConfig.clientUrl, + schema: databaseConfig.schema, }) injectedDependencies[ContainerRegistrationKeys.PG_CONNECTION] = @@ -48,7 +47,16 @@ export async function initModules({ }) async function shutdown() { - await (sharedPgConnection as any).context?.destroy() + if (shouldDestroyConnectionAutomatically) { + await (sharedPgConnection as any).context?.destroy() + await (sharedPgConnection as any).destroy() + } else { + if (!preventConnectionDestroyWarning) { + console.info( + `You are using a custom shared connection. The connection won't be destroyed automatically.` + ) + } + } MedusaModule.clearInstances() } diff --git a/packages/medusa-test-utils/src/module-test-runner.ts b/packages/medusa-test-utils/src/module-test-runner.ts new file mode 100644 index 0000000000000..8907b633b9d1f --- /dev/null +++ b/packages/medusa-test-utils/src/module-test-runner.ts @@ -0,0 +1,128 @@ +import { getDatabaseURL, getMikroOrmWrapper, TestDatabase } from "./database" +import { MedusaAppOutput, ModulesDefinition } from "@medusajs/modules-sdk" +import { initModules, InitModulesOptions } from "./init-modules" +import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils" + +export interface SuiteOptions { + MikroOrmWrapper: TestDatabase + medusaApp: MedusaAppOutput + service: TService + dbConfig: { + schema: string + clientUrl: string + } +} + +export function moduleIntegrationTestRunner({ + moduleName, + moduleModels, + joinerConfig = [], + schema = "public", + testSuite, +}: { + moduleName: string + moduleModels?: any[] + joinerConfig?: any[] + schema?: string + dbName?: string + testSuite: (options: SuiteOptions) => () => void +}) { + moduleModels = Object.values(require(`${process.cwd()}/src/models`)) + // migrationPath ??= process.cwd() + "/src/migrations/!(*.d).{js,ts,cjs}" + + const tempName = parseInt(process.env.JEST_WORKER_ID || "1") + const dbName = `medusa-${moduleName.toLowerCase()}-integration-${tempName}` + + const dbConfig = { + clientUrl: getDatabaseURL(dbName), + schema, + } + + // Use a unique connection for all the entire suite + const connection = ModulesSdkUtils.createPgConnection(dbConfig) + + const MikroOrmWrapper = getMikroOrmWrapper({ + mikroOrmEntities: moduleModels, + clientUrl: dbConfig.clientUrl, + schema: dbConfig.schema, + }) + + const modulesConfig_ = { + [moduleName]: { + definition: ModulesDefinition[moduleName], + options: { + defaultAdapterOptions: { + database: dbConfig, + }, + }, + }, + } + + const moduleOptions: InitModulesOptions = { + injectedDependencies: { + [ContainerRegistrationKeys.PG_CONNECTION]: connection, + }, + modulesConfig: modulesConfig_, + databaseConfig: dbConfig, + joinerConfig, + preventConnectionDestroyWarning: true, + } + + let shutdown: () => Promise + let moduleService + let medusaApp: MedusaAppOutput = {} as MedusaAppOutput + + const options = { + MikroOrmWrapper, + medusaApp: new Proxy( + {}, + { + get: (target, prop) => { + return medusaApp[prop] + }, + } + ) as MedusaAppOutput, + service: new Proxy( + {}, + { + get: (target, prop) => { + return moduleService[prop] + }, + } + ), + } as SuiteOptions + + const beforeEach_ = async () => { + try { + await MikroOrmWrapper.setupDatabase() + const output = await initModules(moduleOptions) + shutdown = output.shutdown + medusaApp = output.medusaApp + moduleService = output.medusaApp.modules[moduleName] + } catch (error) { + console.error("Error setting up database:", error) + } + } + + const afterEach_ = async () => { + try { + await MikroOrmWrapper.clearDatabase() + await shutdown() + moduleService = {} + medusaApp = {} as MedusaAppOutput + } catch (error) { + console.error("Error tearing down database:", error) + } + } + + return describe("", () => { + beforeEach(beforeEach_) + afterEach(afterEach_) + afterAll(async () => { + await (connection as any).context?.destroy() + await (connection as any).destroy() + }) + + testSuite(options) + }) +} diff --git a/packages/order/integration-tests/utils/database.ts b/packages/order/integration-tests/utils/database.ts index 06c67a3bc2f9c..dfd64670826c5 100644 --- a/packages/order/integration-tests/utils/database.ts +++ b/packages/order/integration-tests/utils/database.ts @@ -4,10 +4,9 @@ import * as Models from "@models" const mikroOrmEntities = Models as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - null, - process.env.MEDUSA_ORDER_DB_SCHEMA -) + schema: process.env.MEDUSA_ORDER_DB_SCHEMA, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/payment/integration-tests/utils/database.ts b/packages/payment/integration-tests/utils/database.ts index 0fbf6bdd1c948..5afd38fe2c6f3 100644 --- a/packages/payment/integration-tests/utils/database.ts +++ b/packages/payment/integration-tests/utils/database.ts @@ -1,18 +1,18 @@ -import { TestDatabaseUtils } from "medusa-test-utils" +import {TestDatabaseUtils} from "medusa-test-utils" import * as PaymentModules from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = PaymentModules as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/pricing/integration-tests/utils/database.ts b/packages/pricing/integration-tests/utils/database.ts index 060158719191e..885476b676c9b 100644 --- a/packages/pricing/integration-tests/utils/database.ts +++ b/packages/pricing/integration-tests/utils/database.ts @@ -5,14 +5,14 @@ import * as PricingModels from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = PricingModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/product/integration-tests/__tests__/module.ts b/packages/product/integration-tests/__tests__/module.ts index 7ff9606ef65a5..35e83bd6aad6e 100644 --- a/packages/product/integration-tests/__tests__/module.ts +++ b/packages/product/integration-tests/__tests__/module.ts @@ -1,7 +1,7 @@ import { MedusaModule, Modules } from "@medusajs/modules-sdk" import { IProductModuleService } from "@medusajs/types" import { kebabCase } from "@medusajs/utils" -import { knex } from "knex" +import { knex } from "@mikro-orm/knex" import { initModules } from "medusa-test-utils" import * as CustomRepositories from "../__fixtures__/module" import { diff --git a/packages/promotion/integration-tests/utils/database.ts b/packages/promotion/integration-tests/utils/database.ts index 8069e5a72fe19..825aa4b93cf08 100644 --- a/packages/promotion/integration-tests/utils/database.ts +++ b/packages/promotion/integration-tests/utils/database.ts @@ -1,18 +1,18 @@ -import { TestDatabaseUtils } from "medusa-test-utils" +import {TestDatabaseUtils} from "medusa-test-utils" import * as PromotionModels from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = PromotionModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/region/integration-tests/utils/database.ts b/packages/region/integration-tests/utils/database.ts index f412f49944a8a..66272d1565204 100644 --- a/packages/region/integration-tests/utils/database.ts +++ b/packages/region/integration-tests/utils/database.ts @@ -1,18 +1,18 @@ -import { TestDatabaseUtils } from "medusa-test-utils" +import {TestDatabaseUtils} from "medusa-test-utils" import * as RegionModels from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = RegionModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/sales-channel/integration-tests/utils/database.ts b/packages/sales-channel/integration-tests/utils/database.ts index 40496a5b41aa5..26681dd7fcd81 100644 --- a/packages/sales-channel/integration-tests/utils/database.ts +++ b/packages/sales-channel/integration-tests/utils/database.ts @@ -1,18 +1,18 @@ -import { TestDatabaseUtils } from "medusa-test-utils" +import {TestDatabaseUtils} from "medusa-test-utils" import * as SalesChannelModels from "@models" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = SalesChannelModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/tax/integration-tests/utils/database.ts b/packages/tax/integration-tests/utils/database.ts index c3b4a6c848075..dfd64670826c5 100644 --- a/packages/tax/integration-tests/utils/database.ts +++ b/packages/tax/integration-tests/utils/database.ts @@ -4,10 +4,9 @@ import * as Models from "@models" const mikroOrmEntities = Models as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - null, - process.env.MEDUSA_TAX_DB_SCHEMA -) + schema: process.env.MEDUSA_ORDER_DB_SCHEMA, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/types/src/dal/index.ts b/packages/types/src/dal/index.ts index 341a50dbee5fa..ff519f167a21e 100644 --- a/packages/types/src/dal/index.ts +++ b/packages/types/src/dal/index.ts @@ -1,4 +1,4 @@ -import { Dictionary, FilterQuery, Order } from "./utils" +import { Dictionary, FilterQuery, OperatorMap, Order } from "./utils" export { FilterQuery, OperatorMap } from "./utils" diff --git a/packages/types/src/fulfillment/common/service-zone.ts b/packages/types/src/fulfillment/common/service-zone.ts index 8dcb3076f0406..acb827500e880 100644 --- a/packages/types/src/fulfillment/common/service-zone.ts +++ b/packages/types/src/fulfillment/common/service-zone.ts @@ -1,7 +1,7 @@ import { FulfillmentSetDTO } from "./fulfillment-set" import { FilterableGeoZoneProps, GeoZoneDTO } from "./geo-zone" import { ShippingOptionDTO } from "./shipping-option" -import { BaseFilterable } from "../../dal" +import { BaseFilterable, OperatorMap } from "../../dal" export interface ServiceZoneDTO { id: string @@ -17,8 +17,8 @@ export interface ServiceZoneDTO { export interface FilterableServiceZoneProps extends BaseFilterable { - id?: string | string[] - name?: string | string[] + id?: string | string[] | OperatorMap + name?: string | string[] | OperatorMap geo_zones?: FilterableGeoZoneProps shipping_options?: any // TODO } diff --git a/packages/types/src/fulfillment/common/shipping-option-rule.ts b/packages/types/src/fulfillment/common/shipping-option-rule.ts index dff66b4ca1b95..d9ac5f4f67b95 100644 --- a/packages/types/src/fulfillment/common/shipping-option-rule.ts +++ b/packages/types/src/fulfillment/common/shipping-option-rule.ts @@ -1,5 +1,5 @@ import { ShippingOptionDTO } from "./shipping-option" -import { BaseFilterable } from "../../dal" +import { BaseFilterable, OperatorMap } from "../../dal" export interface ShippingOptionRuleDTO { id: string @@ -15,8 +15,8 @@ export interface ShippingOptionRuleDTO { export interface FilterableShippingOptionRuleProps extends BaseFilterable { - id?: string | string[] - attribute?: string | string[] - operator?: string | string[] - value?: string | string[] + id?: string | string[] | OperatorMap + attribute?: string | string[] | OperatorMap + operator?: string | string[] | OperatorMap + value?: string | string[] | OperatorMap } diff --git a/packages/types/src/fulfillment/common/shipping-option-type.ts b/packages/types/src/fulfillment/common/shipping-option-type.ts index a2f86741c559c..b52a1b93c42da 100644 --- a/packages/types/src/fulfillment/common/shipping-option-type.ts +++ b/packages/types/src/fulfillment/common/shipping-option-type.ts @@ -1,5 +1,5 @@ import { ShippingOptionDTO } from "./shipping-option" -import { BaseFilterable } from "../../dal" +import { BaseFilterable, OperatorMap } from "../../dal" export interface ShippingOptionTypeDTO { id: string @@ -15,8 +15,8 @@ export interface ShippingOptionTypeDTO { export interface FilterableShippingOptionTypeProps extends BaseFilterable { - id?: string | string[] - label?: string | string[] - description?: string | string[] - code?: string | string[] + id?: string | string[] | OperatorMap + label?: string | string[] | OperatorMap + description?: string | string[] | OperatorMap + code?: string | string[] | OperatorMap } diff --git a/packages/types/src/fulfillment/common/shipping-option.ts b/packages/types/src/fulfillment/common/shipping-option.ts index 9243adfcaed6e..fe2ab7ca2a7b8 100644 --- a/packages/types/src/fulfillment/common/shipping-option.ts +++ b/packages/types/src/fulfillment/common/shipping-option.ts @@ -9,7 +9,7 @@ import { FilterableShippingOptionRuleProps, ShippingOptionRuleDTO, } from "./shipping-option-rule" -import { BaseFilterable } from "../../dal" +import { BaseFilterable, OperatorMap } from "../../dal" export type ShippingOptionPriceType = "calculated" | "flat" @@ -35,9 +35,12 @@ export interface ShippingOptionDTO { export interface FilterableShippingOptionProps extends BaseFilterable { - id?: string | string[] - name?: string | string[] - price_type?: ShippingOptionPriceType | ShippingOptionPriceType[] + id?: string | string[] | OperatorMap + name?: string | string[] | OperatorMap + price_type?: + | ShippingOptionPriceType + | ShippingOptionPriceType[] + | OperatorMap service_zone?: FilterableServiceZoneProps shipping_option_type?: FilterableShippingOptionTypeProps rules?: FilterableShippingOptionRuleProps diff --git a/packages/types/src/fulfillment/common/shipping-profile.ts b/packages/types/src/fulfillment/common/shipping-profile.ts index 3a2830e2542a7..03336147ab26c 100644 --- a/packages/types/src/fulfillment/common/shipping-profile.ts +++ b/packages/types/src/fulfillment/common/shipping-profile.ts @@ -1,11 +1,24 @@ -import { ShippingOptionDTO } from "./shipping-option" +import { + FilterableShippingOptionProps, + ShippingOptionDTO, +} from "./shipping-option" +import { BaseFilterable, OperatorMap } from "../../dal" export interface ShippingProfileDTO { id: string name: string + type: string metadata: Record | null shipping_options: ShippingOptionDTO[] created_at: Date updated_at: Date deleted_at: Date | null } + +export interface FilterableShippingProfileProps + extends BaseFilterable { + id?: string | string[] | OperatorMap + name?: string | string[] | OperatorMap + type?: string | string[] | OperatorMap + shipping_options?: FilterableShippingOptionProps +} diff --git a/packages/types/src/fulfillment/mutations/geo-zone.ts b/packages/types/src/fulfillment/mutations/geo-zone.ts index 087e9f6eada19..df2518316dd9e 100644 --- a/packages/types/src/fulfillment/mutations/geo-zone.ts +++ b/packages/types/src/fulfillment/mutations/geo-zone.ts @@ -7,21 +7,21 @@ interface CreateGeoZoneBaseDTO { metadata?: Record | null } -interface CreateCountryGeoZoneDTO extends CreateGeoZoneBaseDTO { +export interface CreateCountryGeoZoneDTO extends CreateGeoZoneBaseDTO { type: "country" } -interface CreateProvinceGeoZoneDTO extends CreateGeoZoneBaseDTO { +export interface CreateProvinceGeoZoneDTO extends CreateGeoZoneBaseDTO { type: "province" province_code: string } -interface CreateCityGeoZoneDTO extends CreateGeoZoneBaseDTO { +export interface CreateCityGeoZoneDTO extends CreateGeoZoneBaseDTO { type: "city" city: string } -interface CreateZipGeoZoneDTO extends CreateGeoZoneBaseDTO { +export interface CreateZipGeoZoneDTO extends CreateGeoZoneBaseDTO { type: "zip" postal_expression: Record } @@ -32,25 +32,25 @@ export type CreateGeoZoneDTO = | CreateCityGeoZoneDTO | CreateZipGeoZoneDTO -interface UpdateGeoZoneBaseDTO extends Partial { +export interface UpdateGeoZoneBaseDTO extends Partial { id: string } -interface UpdateCountryGeoZoneDTO extends UpdateGeoZoneBaseDTO { +export interface UpdateCountryGeoZoneDTO extends UpdateGeoZoneBaseDTO { type: "country" } -interface UpdateProvinceGeoZoneDTO extends UpdateGeoZoneBaseDTO { +export interface UpdateProvinceGeoZoneDTO extends UpdateGeoZoneBaseDTO { type: "province" province_code: string } -interface UpdateCityGeoZoneDTO extends UpdateGeoZoneBaseDTO { +export interface UpdateCityGeoZoneDTO extends UpdateGeoZoneBaseDTO { type: "city" city: string } -interface UpdateZipGeoZoneDTO extends UpdateGeoZoneBaseDTO { +export interface UpdateZipGeoZoneDTO extends UpdateGeoZoneBaseDTO { type: "zip" postal_expression: Record } diff --git a/packages/types/src/fulfillment/mutations/index.ts b/packages/types/src/fulfillment/mutations/index.ts index 6f14b920ca2ff..2f3603854796d 100644 --- a/packages/types/src/fulfillment/mutations/index.ts +++ b/packages/types/src/fulfillment/mutations/index.ts @@ -1,3 +1,4 @@ +export * from "./shipping-profile" export * from "./shipping-option-type" export * from "./shipping-option-rule" export * from "./geo-zone" diff --git a/packages/types/src/fulfillment/mutations/service-zone.ts b/packages/types/src/fulfillment/mutations/service-zone.ts index 8d678acc07b0c..6c37b3264a96d 100644 --- a/packages/types/src/fulfillment/mutations/service-zone.ts +++ b/packages/types/src/fulfillment/mutations/service-zone.ts @@ -1,13 +1,29 @@ -import { CreateGeoZoneDTO } from "./geo-zone" +import { + CreateCityGeoZoneDTO, + CreateCountryGeoZoneDTO, + CreateProvinceGeoZoneDTO, + CreateZipGeoZoneDTO, +} from "./geo-zone" export interface CreateServiceZoneDTO { name: string fulfillment_set_id: string - geo_zones?: Omit[] + geo_zones?: ( + | Omit + | Omit + | Omit + | Omit + )[] } export interface UpdateServiceZoneDTO { id: string name?: string - geo_zones?: (Omit | { id: string })[] + geo_zones?: ( + | Omit + | Omit + | Omit + | Omit + | { id: string } + )[] } diff --git a/packages/types/src/fulfillment/mutations/shipping-option.ts b/packages/types/src/fulfillment/mutations/shipping-option.ts index d0967fb89b36f..3070870b079d9 100644 --- a/packages/types/src/fulfillment/mutations/shipping-option.ts +++ b/packages/types/src/fulfillment/mutations/shipping-option.ts @@ -1,12 +1,6 @@ -import { - CreateShippingOptionTypeDTO, - UpdateShippingOptionTypeDTO, -} from "./shipping-option-type" +import { CreateShippingOptionTypeDTO } from "./shipping-option-type" import { ShippingOptionPriceType } from "../common" -import { - CreateShippingOptionRuleDTO, - UpdateShippingOptionRuleDTO, -} from "./shipping-option-rule" +import { CreateShippingOptionRuleDTO } from "./shipping-option-rule" export interface CreateShippingOptionDTO { name: string @@ -26,12 +20,10 @@ export interface UpdateShippingOptionDTO { service_zone_id?: string shipping_profile_id?: string service_provider_id?: string - type: - | Omit - | Omit + type: Omit | { id: string } data?: Record | null rules?: ( | Omit - | Omit + | { id: string } )[] } diff --git a/packages/types/src/fulfillment/mutations/shipping-profile.ts b/packages/types/src/fulfillment/mutations/shipping-profile.ts new file mode 100644 index 0000000000000..c663fa1616abe --- /dev/null +++ b/packages/types/src/fulfillment/mutations/shipping-profile.ts @@ -0,0 +1,8 @@ +export interface CreateShippingProfileDTO { + name: string + type?: string + metadata?: Record +} + +export interface UpdateShippingProfileDTO + extends Partial {} diff --git a/packages/types/src/fulfillment/service.ts b/packages/types/src/fulfillment/service.ts index ef47d0651d27a..32a74855c5558 100644 --- a/packages/types/src/fulfillment/service.ts +++ b/packages/types/src/fulfillment/service.ts @@ -4,10 +4,12 @@ import { FilterableGeoZoneProps, FilterableServiceZoneProps, FilterableShippingOptionProps, + FilterableShippingProfileProps, FulfillmentSetDTO, GeoZoneDTO, ServiceZoneDTO, ShippingOptionDTO, + ShippingProfileDTO, } from "./common" import { FindConfig } from "../common" import { Context } from "../shared-context" @@ -22,6 +24,7 @@ import { UpdateServiceZoneDTO, UpdateShippingOptionDTO, } from "./mutations" +import { CreateShippingProfileDTO } from "./mutations/shipping-profile" export interface IFulfillmentModuleService extends IModuleService { /** @@ -66,6 +69,21 @@ export interface IFulfillmentModuleService extends IModuleService { sharedContext?: Context ): Promise + /** + * Create a new shipping profile + * @param data + * @param sharedContext + */ + createShippingProfiles( + data: CreateShippingProfileDTO[], + sharedContext?: Context + ): Promise + + createShippingProfiles( + data: CreateShippingProfileDTO, + sharedContext?: Context + ): Promise + /** * Create a new geo zone * @param data @@ -122,6 +140,20 @@ export interface IFulfillmentModuleService extends IModuleService { sharedContext?: Context ): Promise + /** + * Update a shipping profile + * @param data + * @param sharedContext + */ + updateShippingProfiles( + data: CreateShippingProfileDTO[], + sharedContext?: Context + ): Promise + updateShippingProfiles( + data: CreateShippingProfileDTO, + sharedContext?: Context + ): Promise + /** * Update a geo zone * @param data @@ -160,6 +192,14 @@ export interface IFulfillmentModuleService extends IModuleService { deleteShippingOptions(ids: string[], sharedContext?: Context): Promise deleteShippingOptions(id: string, sharedContext?: Context): Promise + /** + * Delete a shipping profile + * @param ids + * @param sharedContext + */ + deleteShippingProfiles(ids: string[], sharedContext?: Context): Promise + deleteShippingProfiles(id: string, sharedContext?: Context): Promise + /** * Delete a geo zone * @param ids @@ -204,6 +244,18 @@ export interface IFulfillmentModuleService extends IModuleService { sharedContext?: Context ): Promise + /** + * Retrieve a shipping profile + * @param id + * @param config + * @param sharedContext + */ + retrieveShippingProfile( + id: string, + config?: FindConfig, + sharedContext?: Context + ): Promise + /** * Retrieve a geo zone * @param id @@ -252,6 +304,18 @@ export interface IFulfillmentModuleService extends IModuleService { sharedContext?: Context ): Promise + /** + * List shipping profiles + * @param filters + * @param config + * @param sharedContext + */ + listShippingProfiles( + filters?: FilterableShippingProfileProps, + config?: FindConfig, + sharedContext?: Context + ): Promise + /** * List geo zones * @param filters @@ -300,6 +364,18 @@ export interface IFulfillmentModuleService extends IModuleService { sharedContext?: Context ): Promise<[ShippingOptionDTO[], number]> + /** + * List and count shipping profiles + * @param filters + * @param config + * @param sharedContext + */ + listAndCountShippingProfiles( + filters?: FilterableShippingProfileProps, + config?: FindConfig, + sharedContext?: Context + ): Promise<[ShippingProfileDTO[], number]> + /** * List and count geo zones * @param filters @@ -348,6 +424,18 @@ export interface IFulfillmentModuleService extends IModuleService { sharedContext?: Context ): Promise | void> + /** + * Soft delete shipping profiles + * @param shippingProfileIds + * @param config + * @param sharedContext + */ + softDeleteShippingProfiles( + shippingProfileIds: string[], + config?: SoftDeleteReturn, + sharedContext?: Context + ): Promise | void> + /** * Soft delete geo zones * @param geoZoneIds @@ -365,4 +453,6 @@ export interface IFulfillmentModuleService extends IModuleService { config?: RestoreReturn, sharedContext?: Context ): Promise | void> + + // TODO defined the other restore methods } diff --git a/packages/user/integration-tests/utils/database.ts b/packages/user/integration-tests/utils/database.ts index 7e67163fc7298..507ff58bd28ea 100644 --- a/packages/user/integration-tests/utils/database.ts +++ b/packages/user/integration-tests/utils/database.ts @@ -1,18 +1,18 @@ import * as UserModels from "@models" -import { TestDatabaseUtils } from "medusa-test-utils" +import {TestDatabaseUtils} from "medusa-test-utils" const pathToMigrations = "../../src/migrations" const mikroOrmEntities = UserModels as unknown as any[] -export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper( +export const MikroOrmWrapper = TestDatabaseUtils.getMikroOrmWrapper({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) -export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig( +export const MikroOrmConfig = TestDatabaseUtils.getMikroOrmConfig({ mikroOrmEntities, - pathToMigrations -) + pathToMigrations, +}) export const DB_URL = TestDatabaseUtils.getDatabaseURL() diff --git a/packages/utils/src/common/__tests__/create-psql-index-helper.ts b/packages/utils/src/common/__tests__/create-psql-index-helper.ts index aea493587412d..a275477716130 100644 --- a/packages/utils/src/common/__tests__/create-psql-index-helper.ts +++ b/packages/utils/src/common/__tests__/create-psql-index-helper.ts @@ -84,7 +84,7 @@ describe("createPsqlIndexStatementHelper", function () { const indexStatement = createPsqlIndexStatementHelper(options) expect(indexStatement.expression).toEqual( - `CREATE UNIQUE INDEX IF NOT EXISTS "IDX_table_name_column_name_1_column_name_2" ON "${ + `CREATE UNIQUE INDEX IF NOT EXISTS "IDX_table_name_column_name_1_column_name_2_unique" ON "${ options.tableName }" (${options.columns.join(", ")}) WHERE ${options.where}` ) diff --git a/packages/utils/src/common/create-psql-index-helper.ts b/packages/utils/src/common/create-psql-index-helper.ts index 47852b8862830..524efcd8e191f 100644 --- a/packages/utils/src/common/create-psql-index-helper.ts +++ b/packages/utils/src/common/create-psql-index-helper.ts @@ -47,7 +47,7 @@ export function createPsqlIndexStatementHelper({ const columnsName = Array.isArray(columns) ? columns.join("_") : columns columns = Array.isArray(columns) ? columns.join(", ") : columns - name = name || `IDX_${tableName}_${columnsName}` + name = name || `IDX_${tableName}_${columnsName}${unique ? "_unique" : ""}` const typeStr = type ? ` USING ${type}` : "" const optionsStr = where ? ` WHERE ${where}` : "" @@ -63,7 +63,7 @@ export function createPsqlIndexStatementHelper({ }, name, expression, - MikroORMIndex: (options = {}) => { + MikroORMIndex: (options?: Parameters[0]) => { return Index({ name, expression, diff --git a/packages/utils/src/modules-sdk/abstract-module-service-factory.ts b/packages/utils/src/modules-sdk/abstract-module-service-factory.ts index e6e23257dff8d..b4311abde038c 100644 --- a/packages/utils/src/modules-sdk/abstract-module-service-factory.ts +++ b/packages/utils/src/modules-sdk/abstract-module-service-factory.ts @@ -97,13 +97,6 @@ export interface AbstractModuleServiceBase { ): Promise | void> } -/** - * Multiple issues on typescript around mapped types function are open, so - * when overriding a method from the base class that is mapped dynamically from the - * other models, we will have to ignore the error (2425) - * - * see: https://github.com/microsoft/TypeScript/issues/48125 - */ export type AbstractModuleService< TContainer, TMainModelDTO, diff --git a/packages/utils/src/modules-sdk/create-pg-connection.ts b/packages/utils/src/modules-sdk/create-pg-connection.ts index 4770c1a35f0e7..be5d361d0b656 100644 --- a/packages/utils/src/modules-sdk/create-pg-connection.ts +++ b/packages/utils/src/modules-sdk/create-pg-connection.ts @@ -1,4 +1,4 @@ -import knex from "knex" +import { knex } from "@mikro-orm/knex" import { ModuleServiceInitializeOptions } from "@medusajs/types" type Options = ModuleServiceInitializeOptions["database"] diff --git a/packages/workflow-engine-redis/integration-tests/__tests__/index.spec.ts b/packages/workflow-engine-redis/integration-tests/__tests__/index.spec.ts index 9d72daafb1bf8..4a8493cf3170b 100644 --- a/packages/workflow-engine-redis/integration-tests/__tests__/index.spec.ts +++ b/packages/workflow-engine-redis/integration-tests/__tests__/index.spec.ts @@ -3,7 +3,7 @@ import { TransactionStepTimeoutError, TransactionTimeoutError, } from "@medusajs/orchestration" -import { RemoteJoinerQuery } from "@medusajs/types" +import { RemoteQueryFunction } from "@medusajs/types" import { TransactionHandlerType } from "@medusajs/utils" import { IWorkflowEngineService } from "@medusajs/workflows-sdk" import { knex } from "knex" @@ -27,10 +27,7 @@ const afterEach_ = async () => { describe("Workflow Orchestrator module", function () { describe("Testing basic workflow", function () { let workflowOrcModule: IWorkflowEngineService - let query: ( - query: string | RemoteJoinerQuery | object, - variables?: Record - ) => Promise + let query: RemoteQueryFunction afterEach(afterEach_)