chore(fulfillment, utils): Migrate module to DML (#10617)

**What**
- Allow to provide `foreignKeyName` option for hasOne and belongsTo relationships
  - `model.hasOne(() => OtherEntity, { foreignKey: true, foreignKeyName: 'other_entity_something_id' })`
  - The above will also output a generated type that takes into consideration the custom fk name 🔽 
- Update types to account for defined custom foreign key name
- Fix joiner config linkable generation to account for custom linkable keys that provide a public API for their model but are not part of the list of the models included in the MedusaService
  - This was supposed to be handled correctly but the implementation was not considering that custom linkable keys could reference models not part of the one provided to medusa service
- Migrate fulfillment module to DML
- Fix has one with fk behaviour and hooks (the relation should be assigned but not the fk)
- Fix has one belongsTo hooks (the relation should be assigned but not the fk)
- Fix hasOneWithFk and belongsTo non persisted fk to be selectable
- Allow to define `belongsTo` without other side definition for `ManyToOne` with no counter part defined
  - Meaning that if a user defined `belongsTo` on one side andnot mapped by and no counter part on the other entity it will be considered as a `ManyToOne`
- `orphanRemoval` on `OneToOne` have been removed, this means that when assigning a new object relation to an entity, the previous one gets deconected but not deleted automatically. This prevent removing data un volountarely

**NOTE**
As per our convention here are some information to keep in mind

**HasOne <> BelongsTo**
Define `OneToOne`, The foreign key is owned by the belongs to and the relation needs to be provided to cascade if wanted

**HasMany <> BelongsTo**
Define `OneToMane` <> `ManyToOne`, the foreign key is owned by the many to one and for those relation no cascade will be performed, the foreign key must be provided. For the `HasMany` the cascade is available

**HasOne (with FK)**
Will act similarly to belongs to with **HasOne <> BelongsTo**

Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
This commit is contained in:
Adrien de PerettiandCarlos R. L. Rodrigues authored and GitHub committed 2024-12-19 16:40:11 +00:00
1 parent 65007c49f6
commit 100da64242
39 files changed
+1153 -1857

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
---
"@medusajs/fulfillment": patch
"@medusajs/types": patch
"@medusajs/utils": patch
"@medusajs/medusa": patch
---
chore: fulfillment module DML
@@ -237,10 +237,10 @@ medusaIntegrationTestRunner({
}, },
]), ]),
provider_id: "manual_test-provider", provider_id: "manual_test-provider",
provider: { provider: expect.objectContaining({
id: "manual_test-provider", id: "manual_test-provider",
is_enabled: true, is_enabled: true,
}, }),
rules: [], rules: [],
service_zone_id: expect.any(String), service_zone_id: expect.any(String),
service_zone: { service_zone: {
@@ -39,7 +39,10 @@ medusaIntegrationTestRunner({
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
expect(response.data.stock_location.fulfillment_providers).toEqual([ expect(response.data.stock_location.fulfillment_providers).toEqual([
{ id: "manual_test-provider", is_enabled: true }, expect.objectContaining({
id: "manual_test-provider",
is_enabled: true,
}),
]) ])
}) })
@@ -502,6 +502,7 @@ medusaIntegrationTestRunner({
provider_id: provider_id, provider_id: provider_id,
data: null, data: null,
metadata: null, metadata: null,
shipping_option_type_id: expect.any(String),
type: expect.objectContaining({ type: expect.objectContaining({
id: expect.any(String), id: expect.any(String),
code: shippingOptionData.type.code, code: shippingOptionData.type.code,
+3 -1
View File
@@ -147,7 +147,9 @@ export interface EntityConstructor<Props> extends Function {
*/ */
export type InferForeignKeys<Schema extends DMLSchema> = { export type InferForeignKeys<Schema extends DMLSchema> = {
[K in keyof Schema as Schema[K] extends { $foreignKey: true } [K in keyof Schema as Schema[K] extends { $foreignKey: true }
? `${K & string}_id` ? Schema[K] extends { $foreignKeyName: `${infer FkName}` }
? `${FkName & string}`
: `${K & string}_id`
: never]: Schema[K] extends { $foreignKey: true } : never]: Schema[K] extends { $foreignKey: true }
? null extends Schema[K]["$dataType"] ? null extends Schema[K]["$dataType"]
? string | null ? string | null
@@ -87,7 +87,7 @@ export interface UpdateShippingOptionDTO {
/** /**
* The shipping option type associated with the shipping option. * The shipping option type associated with the shipping option.
*/ */
type: type?:
| Omit<CreateShippingOptionTypeDTO, "shipping_option_id"> | Omit<CreateShippingOptionTypeDTO, "shipping_option_id">
| { | {
/** /**
@@ -3018,6 +3018,7 @@ describe("Entity builder", () => {
persist: false, persist: false,
name: "user_id", name: "user_id",
nullable: false, nullable: false,
formula: expect.any(Function),
reference: "scalar", reference: "scalar",
setter: false, setter: false,
type: "string", type: "string",
@@ -3123,14 +3124,16 @@ describe("Entity builder", () => {
reference: "1:1", reference: "1:1",
name: "email", name: "email",
entity: "Email", entity: "Email",
fieldName: "email_id",
}, },
email_id: { email_id: {
columnType: "text", columnType: "text",
type: "string", type: "string",
reference: "scalar", reference: "scalar",
name: "email_id", name: "email_id",
formula: expect.any(Function),
nullable: false, nullable: false,
persist: true, persist: false,
getter: false, getter: false,
setter: false, setter: false,
}, },
@@ -3233,14 +3236,16 @@ describe("Entity builder", () => {
name: "emails", name: "emails",
entity: "Email", entity: "Email",
nullable: true, nullable: true,
fieldName: "emails_id",
}, },
emails_id: { emails_id: {
columnType: "text", columnType: "text",
type: "string", type: "string",
reference: "scalar", reference: "scalar",
name: "emails_id", name: "emails_id",
formula: expect.any(Function),
nullable: true, nullable: true,
persist: true, persist: false,
getter: false, getter: false,
setter: false, setter: false,
}, },
@@ -3334,14 +3339,16 @@ describe("Entity builder", () => {
name: "email", name: "email",
entity: "Email", entity: "Email",
mappedBy: "owner", mappedBy: "owner",
fieldName: "email_id",
}, },
email_id: { email_id: {
columnType: "text", columnType: "text",
type: "string", type: "string",
reference: "scalar", reference: "scalar",
name: "email_id", name: "email_id",
formula: expect.any(Function),
nullable: false, nullable: false,
persist: true, persist: false,
getter: false, getter: false,
setter: false, setter: false,
}, },
@@ -3439,14 +3446,16 @@ describe("Entity builder", () => {
entity: "Email", entity: "Email",
cascade: ["persist", "soft-remove"], cascade: ["persist", "soft-remove"],
mappedBy: "user", mappedBy: "user",
fieldName: "email_id",
}, },
email_id: { email_id: {
columnType: "text", columnType: "text",
type: "string", type: "string",
reference: "scalar", reference: "scalar",
name: "email_id", name: "email_id",
formula: expect.any(Function),
nullable: false, nullable: false,
persist: true, persist: false,
getter: false, getter: false,
setter: false, setter: false,
}, },
@@ -3614,14 +3623,16 @@ describe("Entity builder", () => {
entity: "Email", entity: "Email",
cascade: ["persist", "soft-remove"], cascade: ["persist", "soft-remove"],
mappedBy: "user", mappedBy: "user",
fieldName: "email_id",
}, },
email_id: { email_id: {
columnType: "text", columnType: "text",
type: "string", type: "string",
reference: "scalar", reference: "scalar",
formula: expect.any(Function),
name: "email_id", name: "email_id",
nullable: false, nullable: false,
persist: true, persist: false,
getter: false, getter: false,
setter: false, setter: false,
}, },
@@ -3704,6 +3715,7 @@ describe("Entity builder", () => {
name: "user_id", name: "user_id",
nullable: false, nullable: false,
reference: "scalar", reference: "scalar",
formula: expect.any(Function),
setter: false, setter: false,
type: "string", type: "string",
persist: false, persist: false,
@@ -4649,6 +4661,7 @@ describe("Entity builder", () => {
reference: "scalar", reference: "scalar",
persist: false, persist: false,
type: "string", type: "string",
formula: expect.any(Function),
columnType: "text", columnType: "text",
nullable: false, nullable: false,
name: "user_id", name: "user_id",
@@ -4848,6 +4861,7 @@ describe("Entity builder", () => {
type: "string", type: "string",
columnType: "text", columnType: "text",
nullable: true, nullable: true,
formula: expect.any(Function),
name: "user_id", name: "user_id",
getter: false, getter: false,
setter: false, setter: false,
@@ -5268,23 +5282,6 @@ describe("Entity builder", () => {
}) })
}) })
test("throw error when other side relationship is missing", () => {
const email = model.define("email", {
email: model.text(),
isVerified: model.boolean(),
user: model.belongsTo(() => user),
})
const user = model.define("user", {
id: model.number(),
username: model.text(),
})
expect(() => toMikroORMEntity(email)).toThrow(
'Missing property "email" on "User" entity. Make sure to define it as a relationship'
)
})
test("throw error when other side relationship is invalid", () => { test("throw error when other side relationship is invalid", () => {
const email = model.define("email", { const email = model.define("email", {
email: model.text(), email: model.text(),
@@ -5482,6 +5479,7 @@ describe("Entity builder", () => {
type: "string", type: "string",
persist: false, persist: false,
columnType: "text", columnType: "text",
formula: expect.any(Function),
nullable: false, nullable: false,
name: "user_id", name: "user_id",
getter: false, getter: false,
@@ -5682,6 +5680,7 @@ describe("Entity builder", () => {
type: "string", type: "string",
columnType: "text", columnType: "text",
nullable: false, nullable: false,
formula: expect.any(Function),
name: "user_id", name: "user_id",
getter: false, getter: false,
setter: false, setter: false,
@@ -5903,6 +5902,7 @@ describe("Entity builder", () => {
type: "string", type: "string",
columnType: "text", columnType: "text",
reference: "scalar", reference: "scalar",
formula: expect.any(Function),
persist: false, persist: false,
getter: false, getter: false,
setter: false, setter: false,
+22 -24
View File
@@ -3,15 +3,9 @@ import {
IDmlEntityConfig, IDmlEntityConfig,
RelationshipOptions, RelationshipOptions,
} from "@medusajs/types" } from "@medusajs/types"
import { DmlEntity } from "./entity" import { DmlEntity, DMLEntitySchemaBuilder } from "./entity"
import { import { createBigNumberProperties } from "./helpers/entity-builder/create-big-number-properties"
createBigNumberProperties, import { createDefaultProperties } from "./helpers/entity-builder/create-default-properties"
DMLSchemaWithBigNumber,
} from "./helpers/entity-builder/create-big-number-properties"
import {
createDefaultProperties,
DMLSchemaDefaults,
} from "./helpers/entity-builder/create-default-properties"
import { ArrayProperty } from "./properties/array" import { ArrayProperty } from "./properties/array"
import { AutoIncrementProperty } from "./properties/autoincrement" import { AutoIncrementProperty } from "./properties/autoincrement"
import { BigNumberProperty } from "./properties/big-number" import { BigNumberProperty } from "./properties/big-number"
@@ -131,20 +125,14 @@ export class EntityBuilder {
define<Schema extends DMLSchema, const TConfig extends IDmlEntityConfig>( define<Schema extends DMLSchema, const TConfig extends IDmlEntityConfig>(
nameOrConfig: TConfig, nameOrConfig: TConfig,
schema: Schema schema: Schema
): DmlEntity< ): DmlEntity<DMLEntitySchemaBuilder<Schema>, TConfig> {
Schema & DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults,
TConfig
> {
this.#disallowImplicitProperties(schema) this.#disallowImplicitProperties(schema)
return new DmlEntity<Schema, TConfig>(nameOrConfig, { return new DmlEntity<Schema, TConfig>(nameOrConfig, {
...schema, ...schema,
...createBigNumberProperties(schema), ...createBigNumberProperties(schema),
...createDefaultProperties(), ...createDefaultProperties(),
}) as unknown as DmlEntity< }) as unknown as DmlEntity<DMLEntitySchemaBuilder<Schema>, TConfig>
Schema & DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults,
TConfig
>
} }
/** /**
@@ -398,26 +386,31 @@ export class EntityBuilder {
* *
* @customNamespace Relationship Methods * @customNamespace Relationship Methods
*/ */
hasOne<T>( hasOne<T, const ForeignKeyName extends string | undefined = undefined>(
entityBuilder: T, entityBuilder: T,
options: RelationshipOptions & { options: RelationshipOptions & {
foreignKey: true foreignKey: true
foreignKeyName?: ForeignKeyName
} }
): HasOneWithForeignKey<T> ): HasOneWithForeignKey<T, ForeignKeyName>
hasOne<T>( hasOne<T>(
entityBuilder: T, entityBuilder: T,
options?: RelationshipOptions & { options?: RelationshipOptions & {
foreignKey?: false foreignKey?: false
} }
): HasOne<T> ): HasOne<T>
hasOne<T>( hasOne<T, const ForeignKeyName extends string | undefined = undefined>(
entityBuilder: T, entityBuilder: T,
options?: RelationshipOptions & { options?: RelationshipOptions & {
foreignKey?: boolean foreignKey?: boolean
foreignKeyName?: ForeignKeyName
} }
): HasOneWithForeignKey<T> | HasOne<T> { ): HasOneWithForeignKey<T, ForeignKeyName> | HasOne<T> {
if (options?.foreignKey) { if (options?.foreignKey) {
return new HasOneWithForeignKey<T>(entityBuilder, options || {}) return new HasOneWithForeignKey<T, ForeignKeyName>(
entityBuilder,
options || {}
)
} }
return new HasOne<T>(entityBuilder, options || {}) return new HasOne<T>(entityBuilder, options || {})
} }
@@ -445,8 +438,13 @@ export class EntityBuilder {
* *
* @customNamespace Relationship Methods * @customNamespace Relationship Methods
*/ */
belongsTo<T>(entityBuilder: T, options?: RelationshipOptions) { belongsTo<T, const ForeignKeyName extends string | undefined = undefined>(
return new BelongsTo<T>(entityBuilder, options || {}) entityBuilder: T,
options?: RelationshipOptions & {
foreignKeyName?: ForeignKeyName
}
) {
return new BelongsTo<T, ForeignKeyName>(entityBuilder, options || {})
} }
/** /**
+7
View File
@@ -12,9 +12,16 @@ import {
import { isObject, isString, toCamelCase, upperCaseFirst } from "../common" import { isObject, isString, toCamelCase, upperCaseFirst } from "../common"
import { transformIndexWhere } from "./helpers/entity-builder/build-indexes" import { transformIndexWhere } from "./helpers/entity-builder/build-indexes"
import { BelongsTo } from "./relations/belongs-to" import { BelongsTo } from "./relations/belongs-to"
import {
DMLSchemaDefaults,
DMLSchemaWithBigNumber,
} from "./helpers/entity-builder"
const IsDmlEntity = Symbol.for("isDmlEntity") const IsDmlEntity = Symbol.for("isDmlEntity")
export type DMLEntitySchemaBuilder<Schema extends DMLSchema> =
DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults & Schema
function extractNameAndTableName<const Config extends IDmlEntityConfig>( function extractNameAndTableName<const Config extends IDmlEntityConfig>(
nameOrConfig: Config nameOrConfig: Config
) { ) {
@@ -7,6 +7,7 @@ import {
} from "@medusajs/types" } from "@medusajs/types"
import { import {
BeforeCreate, BeforeCreate,
BeforeUpdate,
Cascade, Cascade,
ManyToMany, ManyToMany,
ManyToOne, ManyToOne,
@@ -19,13 +20,13 @@ import {
} from "@mikro-orm/core" } from "@mikro-orm/core"
import { camelToSnakeCase, pluralize } from "../../../common" import { camelToSnakeCase, pluralize } from "../../../common"
import { DmlEntity } from "../../entity" import { DmlEntity } from "../../entity"
import { BelongsTo } from "../../relations"
import { HasMany } from "../../relations/has-many" import { HasMany } from "../../relations/has-many"
import { HasOne } from "../../relations/has-one" import { HasOne } from "../../relations/has-one"
import { HasOneWithForeignKey } from "../../relations/has-one-fk" import { HasOneWithForeignKey } from "../../relations/has-one-fk"
import { ManyToMany as DmlManyToMany } from "../../relations/many-to-many" import { ManyToMany as DmlManyToMany } from "../../relations/many-to-many"
import { applyEntityIndexes } from "../mikro-orm/apply-indexes" import { applyEntityIndexes } from "../mikro-orm/apply-indexes"
import { parseEntityName } from "./parse-entity-name" import { parseEntityName } from "./parse-entity-name"
import { BelongsTo } from "../../relations"
type Context = { type Context = {
MANY_TO_MANY_TRACKED_RELATIONS: Record<string, boolean> MANY_TO_MANY_TRACKED_RELATIONS: Record<string, boolean>
@@ -181,7 +182,10 @@ export function defineHasOneWithFKRelationship(
{ relatedModelName }: { relatedModelName: string }, { relatedModelName }: { relatedModelName: string },
cascades: EntityCascades<string[], string[]> cascades: EntityCascades<string[], string[]>
) { ) {
const foreignKeyName = camelToSnakeCase(`${relationship.name}Id`) const foreignKeyName =
relationship.options.foreignKeyName ??
camelToSnakeCase(`${relationship.name}Id`)
const shouldRemoveRelated = !!cascades.delete?.includes(relationship.name) const shouldRemoveRelated = !!cascades.delete?.includes(relationship.name)
let mappedBy: string | undefined = camelToSnakeCase(MikroORMEntity.name) let mappedBy: string | undefined = camelToSnakeCase(MikroORMEntity.name)
@@ -189,21 +193,83 @@ export function defineHasOneWithFKRelationship(
mappedBy = relationship.mappedBy mappedBy = relationship.mappedBy
} }
OneToOne({ const oneToOneOptions = {
entity: relatedModelName, entity: relatedModelName,
fieldName: foreignKeyName,
...(relationship.nullable ? { nullable: relationship.nullable } : {}), ...(relationship.nullable ? { nullable: relationship.nullable } : {}),
...(mappedBy ? { mappedBy } : {}), ...(mappedBy ? { mappedBy } : {}),
cascade: shouldRemoveRelated //orphanRemoval: true,
? (["persist", "soft-remove"] as any) } as OneToOneOptions<any, any>
: undefined,
} as OneToOneOptions<any, any>)(MikroORMEntity.prototype, relationship.name) if (shouldRemoveRelated) {
oneToOneOptions.cascade = ["persist", "soft-remove"] as any
}
OneToOne(oneToOneOptions)(MikroORMEntity.prototype, relationship.name)
Property({ Property({
type: "string", type: "string",
columnType: "text", columnType: "text",
nullable: relationship.nullable, nullable: relationship.nullable,
persist: true, persist: false,
formula(alias) {
return alias + "." + foreignKeyName
},
})(MikroORMEntity.prototype, foreignKeyName) })(MikroORMEntity.prototype, foreignKeyName)
const hookFactory = function (
name: string,
type: "init" | "create" | "update",
hookFn: Function
) {
MikroORMEntity.prototype[name] = function (
this: typeof MikroORMEntity.prototype
) {
if (type !== "update") {
// During creation
const relationMeta = this.__meta.relations.find(
(relation) => relation.name === relationship.name
).targetMeta
this[relationship.name] ??= rel(
relationMeta.class,
this[foreignKeyName]
)
this[foreignKeyName] ??= this[relationship.name]?.id
return
}
if (this[relationship.name]) {
this[foreignKeyName] = this[relationship.name].id
}
if (this[relationship.name] === null) {
this[foreignKeyName] = null
}
return
}
hookFn()(MikroORMEntity.prototype, name)
}
/**
* Hook to handle foreign key assignation
*/
hookFactory(
`assignRelationFromForeignKeyValue${foreignKeyName}_init`,
"init",
OnInit
)
hookFactory(
`assignRelationFromForeignKeyValue${foreignKeyName}_create`,
"create",
BeforeCreate
)
hookFactory(
`assignRelationFromForeignKeyValue${foreignKeyName}_update`,
"update",
BeforeUpdate
)
} }
/** /**
@@ -261,82 +327,108 @@ export function defineBelongsToRelationship(
*/ */
const shouldCascade = !!relationCascades.delete?.includes(mappedBy) const shouldCascade = !!relationCascades.delete?.includes(mappedBy)
/**
* Ensure the mapped by is defined as relationship on the other side
*/
if (!otherSideRelation) {
throw new Error(
`Missing property "${mappedBy}" on "${relatedModelName}" entity. Make sure to define it as a relationship`
)
}
function applyForeignKeyAssignationHooks(foreignKeyName: string) { function applyForeignKeyAssignationHooks(foreignKeyName: string) {
const hookName = `assignRelationFromForeignKeyValue${foreignKeyName}` const hookFactory = function (
/** name: string,
* Hook to handle foreign key assignation type: "init" | "create" | "update",
*/ hookFn: Function
MikroORMEntity.prototype[hookName] = function () { ) {
/** MikroORMEntity.prototype[name] = function (
* In case of has one relation, in order to be able to have both ways this: typeof MikroORMEntity.prototype
* to associate a relation (through the relation or the foreign key) we need to handle it
* specifically
*/
if (
HasOne.isHasOne(otherSideRelation) ||
HasOneWithForeignKey.isHasOneWithForeignKey(otherSideRelation)
) { ) {
const relationMeta = this.__meta.relations.find( /**
(relation) => relation.name === relationship.name * In case of has one relation, in order to be able to have both ways
).targetMeta * to associate a relation (through the relation or the foreign key) we need to handle it
this[relationship.name] ??= rel( * specifically
relationMeta.class, */
this[foreignKeyName] if (
) HasOne.isHasOne(otherSideRelation) ||
this[relationship.name] ??= this[relationship.name]?.id HasOneWithForeignKey.isHasOneWithForeignKey(otherSideRelation)
return ) {
} if (type !== "update") {
// During creation
const relationMeta = this.__meta.relations.find(
(relation) => relation.name === relationship.name
).targetMeta
this[relationship.name] ??= rel(
relationMeta.class,
this[foreignKeyName]
)
this[foreignKeyName] ??= this[relationship.name]?.id
/** return
* Do not override the existing foreign key value if }
* exists
*/
if (this[foreignKeyName] !== undefined) {
return
}
/** if (this[relationship.name]) {
* Set the foreign key when the relationship is initialized this[foreignKeyName] = this[relationship.name].id
* as null }
*/
if (this[relationship.name] === null) {
this[foreignKeyName] = null
return
}
/** if (this[relationship.name] === null) {
* Set the foreign key when the relationship is initialized this[foreignKeyName] = null
* and as the id }
*/
if (this[relationship.name] && "id" in this[relationship.name]) { return
this[foreignKeyName] = this[relationship.name].id }
/**
* Do not override the existing foreign key value if
* exists
*/
if (this[foreignKeyName] !== undefined) {
return
}
/**
* Set the foreign key when the relationship is initialized
* as null
*/
if (this[relationship.name] === null) {
this[foreignKeyName] = null
return
}
/**
* Set the foreign key when the relationship is initialized
* and as the id
*/
if (this[relationship.name] && "id" in this[relationship.name]) {
this[foreignKeyName] = this[relationship.name].id
}
} }
hookFn()(MikroORMEntity.prototype, name)
} }
/** /**
* Execute hook via lifecycle decorators * Hook to handle foreign key assignation
*/ */
BeforeCreate()(MikroORMEntity.prototype, hookName) hookFactory(
OnInit()(MikroORMEntity.prototype, hookName) `assignRelationFromForeignKeyValue${foreignKeyName}_init`,
"init",
OnInit
)
hookFactory(
`assignRelationFromForeignKeyValue${foreignKeyName}_create`,
"create",
BeforeCreate
)
hookFactory(
`assignRelationFromForeignKeyValue${foreignKeyName}_update`,
"update",
BeforeUpdate
)
} }
/** /**
* Otherside is a has many. Hence we should defined a ManyToOne * Otherside is a has many. Hence we should defined a ManyToOne
*/ */
if ( if (
!otherSideRelation ||
HasMany.isHasMany(otherSideRelation) || HasMany.isHasMany(otherSideRelation) ||
DmlManyToMany.isManyToMany(otherSideRelation) DmlManyToMany.isManyToMany(otherSideRelation)
) { ) {
const foreignKeyName = camelToSnakeCase(`${relationship.name}Id`) const foreignKeyName =
relationship.options.foreignKeyName ??
camelToSnakeCase(`${relationship.name}Id`)
const detachCascade = const detachCascade =
!!relationship.mappedBy && !!relationship.mappedBy &&
relationCascades.detach?.includes(relationship.mappedBy) relationCascades.detach?.includes(relationship.mappedBy)
@@ -391,20 +483,18 @@ export function defineBelongsToRelationship(
HasOne.isHasOne(otherSideRelation) || HasOne.isHasOne(otherSideRelation) ||
HasOneWithForeignKey.isHasOneWithForeignKey(otherSideRelation) HasOneWithForeignKey.isHasOneWithForeignKey(otherSideRelation)
) { ) {
const foreignKeyName = camelToSnakeCase(`${relationship.name}Id`) const foreignKeyName =
relationship.options.foreignKeyName ??
Object.defineProperty(MikroORMEntity.prototype, foreignKeyName, { camelToSnakeCase(`${relationship.name}Id`)
value: null,
configurable: true,
enumerable: true,
writable: true,
})
Property({ Property({
columnType: "text", columnType: "text",
type: "string", type: "string",
nullable: relationship.nullable, nullable: relationship.nullable,
persist: false, persist: false,
formula(alias) {
return alias + "." + foreignKeyName
},
})(MikroORMEntity.prototype, foreignKeyName) })(MikroORMEntity.prototype, foreignKeyName)
const oneToOneOptions: Parameters<typeof OneToOne>[0] = { const oneToOneOptions: Parameters<typeof OneToOne>[0] = {
@@ -413,6 +503,7 @@ export function defineBelongsToRelationship(
mappedBy: mappedBy, mappedBy: mappedBy,
fieldName: foreignKeyName, fieldName: foreignKeyName,
owner: true, owner: true,
// orphanRemoval: true,
onDelete: shouldCascade ? "cascade" : undefined, onDelete: shouldCascade ? "cascade" : undefined,
} }
@@ -1,11 +1,15 @@
import { BaseRelationship } from "./base" import { BaseRelationship } from "./base"
import { RelationNullableModifier } from "./nullable" import { RelationNullableModifier } from "./nullable"
export class BelongsTo<T> extends BaseRelationship<T> { export class BelongsTo<
T,
const OptionalForeignKeyName extends string | undefined = undefined
> extends BaseRelationship<T> {
type = "belongsTo" as const type = "belongsTo" as const
declare $foreignKey: true declare $foreignKey: true
declare $foreignKeyName: OptionalForeignKeyName
static isBelongsTo<T>(relationship: any): relationship is BelongsTo<T> { static isBelongsTo<T>(relationship: any): relationship is BelongsTo<T, any> {
return relationship?.type === "belongsTo" return relationship?.type === "belongsTo"
} }
@@ -13,6 +17,10 @@ export class BelongsTo<T> extends BaseRelationship<T> {
* Apply nullable modifier on the schema * Apply nullable modifier on the schema
*/ */
nullable() { nullable() {
return new RelationNullableModifier<T, BelongsTo<T>, true>(this) return new RelationNullableModifier<
T,
BelongsTo<T, OptionalForeignKeyName>,
true
>(this)
} }
} }
@@ -11,13 +11,17 @@ import { RelationNullableModifier } from "./nullable"
* You may use the "BelongsTo" relationship to define the inverse * You may use the "BelongsTo" relationship to define the inverse
* of the "HasOne" relationship * of the "HasOne" relationship
*/ */
export class HasOneWithForeignKey<T> extends BaseRelationship<T> { export class HasOneWithForeignKey<
T,
const OptionalForeignKeyName extends string | undefined = undefined
> extends BaseRelationship<T> {
type = "hasOneWithFK" as const type = "hasOneWithFK" as const
declare $foreignKey: true declare $foreignKey: true
declare $foreignKeyName: OptionalForeignKeyName
static isHasOneWithForeignKey<T>( static isHasOneWithForeignKey<T>(
relationship: any relationship: any
): relationship is HasOneWithForeignKey<T> { ): relationship is HasOneWithForeignKey<T, any> {
return relationship?.type === "hasOneWithFK" return relationship?.type === "hasOneWithFK"
} }
@@ -25,6 +29,10 @@ export class HasOneWithForeignKey<T> extends BaseRelationship<T> {
* Apply nullable modifier on the schema * Apply nullable modifier on the schema
*/ */
nullable() { nullable() {
return new RelationNullableModifier<T, HasOneWithForeignKey<T>, true>(this) return new RelationNullableModifier<
T,
HasOneWithForeignKey<T, OptionalForeignKeyName>,
true
>(this)
} }
} }
@@ -613,10 +613,15 @@ describe("joiner-config-builder", () => {
} }
) )
const linkConfig = buildLinkConfigFromModelObjects("myService", { const linkableKeysFromDml = buildLinkableKeysFromDmlObjects([user, car])
user, const linkConfig = buildLinkConfigFromModelObjects(
car, "myService",
}) {
user,
car,
},
linkableKeysFromDml
)
expectTypeOf(linkConfig).toMatchTypeOf<{ expectTypeOf(linkConfig).toMatchTypeOf<{
user: { user: {
@@ -413,41 +413,41 @@ export function buildLinkConfigFromModelObjects<
} }
} }
} }
}
/** /**
* If the joiner config specify some custom linkable keys, we merge them with the * If the joiner config specify some custom linkable keys, we merge them with the
* existing linkable keys infered from the model above. * existing linkable keys infered from the model above.
*/ */
const linkableKeysPerModel = Object.entries(linkableKeys).reduce( for (const [linkableKey, modelName] of Object.entries(linkableKeys) ?? []) {
(acc, [key, entityName]) => { const snakeCasedModelName = camelToSnakeCase(toCamelCase(modelName))
acc[entityName] ??= []
acc[entityName].push(key) // Linkable keys by default are prepared with snake cased model name _id
return acc // So to be able to compare only the property we have to remove the first part
}, const inferredReferenceProperty = linkableKey.replace(
{} `${snakeCasedModelName}_`,
""
) )
for (const linkableKey of linkableKeysPerModel[classLikeModelName] ?? []) { linkConfig[lowerCaseFirst(modelName)] ??= {
const snakeCasedModelName = camelToSnakeCase(toCamelCase(model.name)) toJSON: function () {
const linkables = Object.entries(this)
.filter(([name]) => name !== "toJSON")
.map(([, object]) => object)
return linkables[0]
},
}
// Linkable keys by default are prepared with snake cased model name _id if (linkConfig[lowerCaseFirst(modelName)][inferredReferenceProperty]) {
// So to be able to compare only the property we have to remove the first part continue
const inferredReferenceProperty = linkableKey.replace( }
`${snakeCasedModelName}_`,
""
)
if (modelLinkConfig[inferredReferenceProperty]) { linkConfig[lowerCaseFirst(modelName)][inferredReferenceProperty] = {
continue linkable: linkableKey,
} primaryKey: inferredReferenceProperty,
serviceName,
modelLinkConfig[linkableKey] = { field: lowerCaseFirst(modelName),
linkable: linkableKey, entity: upperCaseFirst(modelName),
primaryKey: linkableKey,
serviceName,
field: lowerCaseFirst(model.name),
entity: upperCaseFirst(model.name),
}
} }
} }
@@ -88,6 +88,7 @@ export const defaultStoreCartFields = [
"shipping_methods.adjustments.code", "shipping_methods.adjustments.code",
"shipping_methods.adjustments.amount", "shipping_methods.adjustments.amount",
"shipping_methods.shipping_option_id", "shipping_methods.shipping_option_id",
"shipping_address_id",
"shipping_address.id", "shipping_address.id",
"shipping_address.first_name", "shipping_address.first_name",
"shipping_address.last_name", "shipping_address.last_name",
@@ -100,6 +101,7 @@ export const defaultStoreCartFields = [
"shipping_address.region_code", "shipping_address.region_code",
"shipping_address.province", "shipping_address.province",
"shipping_address.phone", "shipping_address.phone",
"billing_address_id",
"billing_address.id", "billing_address.id",
"billing_address.first_name", "billing_address.first_name",
"billing_address.last_name", "billing_address.last_name",
@@ -42,6 +42,7 @@ async function list(
"service_zones.shipping_options.provider", "service_zones.shipping_options.provider",
"service_zones.shipping_options.type", "service_zones.shipping_options.type",
"service_zones.shipping_options.rules", "service_zones.shipping_options.rules",
"service_zones.shipping_options.shipping_profile",
"service_zones.shipping_options.fulfillments.labels", "service_zones.shipping_options.fulfillments.labels",
"service_zones.shipping_options.fulfillments.items", "service_zones.shipping_options.fulfillments.items",
"service_zones.shipping_options.fulfillments.delivery_address", "service_zones.shipping_options.fulfillments.delivery_address",
@@ -112,20 +113,23 @@ moduleIntegrationTestRunner({
service: FulfillmentModuleService, service: FulfillmentModuleService,
}).linkable }).linkable
expect(Object.keys(linkable)).toEqual([ expect(Object.keys(linkable)).toHaveLength(12)
"fulfillmentAddress", expect(Object.keys(linkable)).toEqual(
"fulfillmentItem", expect.arrayContaining([
"fulfillmentLabel", "fulfillmentAddress",
"fulfillmentProvider", "fulfillmentItem",
"fulfillmentSet", "fulfillmentLabel",
"fulfillment", "fulfillmentProvider",
"geoZone", "fulfillmentSet",
"serviceZone", "fulfillment",
"shippingOptionRule", "geoZone",
"shippingOptionType", "serviceZone",
"shippingOption", "shippingOptionRule",
"shippingProfile", "shippingOptionType",
]) "shippingOption",
"shippingProfile",
])
)
Object.keys(linkable).forEach((key) => { Object.keys(linkable).forEach((key) => {
delete linkable[key].toJSON delete linkable[key].toJSON
@@ -20,7 +20,7 @@ import {
} from "../../__fixtures__" } from "../../__fixtures__"
import { FulfillmentProviderServiceFixtures } from "../../__fixtures__/providers" import { FulfillmentProviderServiceFixtures } from "../../__fixtures__/providers"
jest.setTimeout(100000) jest.setTimeout(1000000)
const moduleOptions = { const moduleOptions = {
providers: [ providers: [
@@ -709,7 +709,18 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
const existingRule = shippingOption.rules[0]! const existingRule = shippingOption.rules[0]!
const updateData: UpdateShippingOptionDTO = { const updateData: UpdateShippingOptionDTO & {
type: {
code: string
description: string
label: string
}
rules: {
attribute: string
operator: string
value: string
}[]
} = {
id: shippingOption.id, id: shippingOption.id,
name: "updated-test", name: "updated-test",
price_type: "calculated", price_type: "calculated",
@@ -767,9 +778,9 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}), }),
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
attribute: updateData.rules[1].attribute, attribute: updateData.rules![1].attribute,
operator: updateData.rules[1].operator, operator: updateData.rules![1].operator,
value: updateData.rules[1].value, value: updateData.rules![1].value,
}), }),
]), ]),
}) })
@@ -789,13 +800,15 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
const types = await service.listShippingOptionTypes() const types = await service.listShippingOptionTypes()
expect(types).toHaveLength(1) expect(types).toHaveLength(2)
expect(types[0]).toEqual( expect(types).toEqual(
expect.objectContaining({ expect.arrayContaining([
code: updateData.type.code, expect.objectContaining({
description: updateData.type.description, code: updateData.type.code,
label: updateData.type.label, description: updateData.type.description,
}) label: updateData.type.label,
}),
])
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(5) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(5)
@@ -1059,7 +1072,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
const types = await service.listShippingOptionTypes() const types = await service.listShippingOptionTypes()
expect(types).toHaveLength(2) expect(types).toHaveLength(4)
expect(types).toEqual( expect(types).toEqual(
expect.arrayContaining([ expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
@@ -1090,7 +1103,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
type: "default", type: "default",
}) })
const shippingOptionData = { const shippingOptionData: UpdateShippingOptionDTO = {
id: "sp_jdafwfleiwuonl", id: "sp_jdafwfleiwuonl",
name: "test", name: "test",
price_type: "flat", price_type: "flat",
@@ -1,5 +1,7 @@
{ {
"namespaces": ["public"], "namespaces": [
"public"
],
"name": "public", "name": "public",
"tables": [ "tables": [
{ {
@@ -150,15 +152,17 @@
"indexes": [ "indexes": [
{ {
"keyName": "IDX_fulfillment_address_deleted_at", "keyName": "IDX_fulfillment_address_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_address_deleted_at\" ON \"fulfillment_address\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_address_deleted_at\" ON \"fulfillment_address\" (deleted_at) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "fulfillment_address_pkey", "keyName": "fulfillment_address_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -187,14 +191,56 @@
"nullable": false, "nullable": false,
"default": "true", "default": "true",
"mappedType": "boolean" "mappedType": "boolean"
},
"created_at": {
"name": "created_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"updated_at": {
"name": "updated_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"deleted_at": {
"name": "deleted_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"length": 6,
"mappedType": "datetime"
} }
}, },
"name": "fulfillment_provider", "name": "fulfillment_provider",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"keyName": "IDX_fulfillment_provider_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_provider_deleted_at\" ON \"fulfillment_provider\" (deleted_at) WHERE deleted_at IS NULL"
},
{ {
"keyName": "fulfillment_provider_pkey", "keyName": "fulfillment_provider_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -277,25 +323,27 @@
"name": "fulfillment_set", "name": "fulfillment_set",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"keyName": "IDX_fulfillment_set_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_set_deleted_at\" ON \"fulfillment_set\" (deleted_at) WHERE deleted_at IS NULL"
},
{ {
"keyName": "IDX_fulfillment_set_name_unique", "keyName": "IDX_fulfillment_set_name_unique",
"columnNames": ["name"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_fulfillment_set_name_unique\" ON \"fulfillment_set\" (name) WHERE deleted_at IS NULL" "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_fulfillment_set_name_unique\" ON \"fulfillment_set\" (name) WHERE deleted_at IS NULL"
}, },
{
"keyName": "IDX_fulfillment_set_deleted_at",
"columnNames": ["deleted_at"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_set_deleted_at\" ON \"fulfillment_set\" (deleted_at) WHERE deleted_at IS NOT NULL"
},
{ {
"keyName": "fulfillment_set_pkey", "keyName": "fulfillment_set_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -324,15 +372,6 @@
"nullable": false, "nullable": false,
"mappedType": "text" "mappedType": "text"
}, },
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"fulfillment_set_id": { "fulfillment_set_id": {
"name": "fulfillment_set_id", "name": "fulfillment_set_id",
"type": "text", "type": "text",
@@ -342,6 +381,15 @@
"nullable": false, "nullable": false,
"mappedType": "text" "mappedType": "text"
}, },
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"created_at": { "created_at": {
"name": "created_at", "name": "created_at",
"type": "timestamptz", "type": "timestamptz",
@@ -378,17 +426,9 @@
"name": "service_zone", "name": "service_zone",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"keyName": "IDX_service_zone_name_unique",
"columnNames": ["name"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_service_zone_name_unique\" ON \"service_zone\" (name) WHERE deleted_at IS NULL"
},
{ {
"keyName": "IDX_service_zone_fulfillment_set_id", "keyName": "IDX_service_zone_fulfillment_set_id",
"columnNames": ["fulfillment_set_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -396,15 +436,25 @@
}, },
{ {
"keyName": "IDX_service_zone_deleted_at", "keyName": "IDX_service_zone_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_service_zone_deleted_at\" ON \"service_zone\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_service_zone_deleted_at\" ON \"service_zone\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_service_zone_name_unique",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_service_zone_name_unique\" ON \"service_zone\" (name) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "service_zone_pkey", "keyName": "service_zone_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -414,9 +464,13 @@
"foreignKeys": { "foreignKeys": {
"service_zone_fulfillment_set_id_foreign": { "service_zone_fulfillment_set_id_foreign": {
"constraintName": "service_zone_fulfillment_set_id_foreign", "constraintName": "service_zone_fulfillment_set_id_foreign",
"columnNames": ["fulfillment_set_id"], "columnNames": [
"fulfillment_set_id"
],
"localTableName": "public.service_zone", "localTableName": "public.service_zone",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.fulfillment_set", "referencedTableName": "public.fulfillment_set",
"deleteRule": "cascade", "deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
@@ -442,7 +496,12 @@
"primary": false, "primary": false,
"nullable": false, "nullable": false,
"default": "'country'", "default": "'country'",
"enumItems": ["country", "province", "city", "zip"], "enumItems": [
"country",
"province",
"city",
"zip"
],
"mappedType": "enum" "mappedType": "enum"
}, },
"country_code": { "country_code": {
@@ -472,15 +531,6 @@
"nullable": true, "nullable": true,
"mappedType": "text" "mappedType": "text"
}, },
"service_zone_id": {
"name": "service_zone_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"postal_expression": { "postal_expression": {
"name": "postal_expression", "name": "postal_expression",
"type": "jsonb", "type": "jsonb",
@@ -490,6 +540,15 @@
"nullable": true, "nullable": true,
"mappedType": "json" "mappedType": "json"
}, },
"service_zone_id": {
"name": "service_zone_id",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"metadata": { "metadata": {
"name": "metadata", "name": "metadata",
"type": "jsonb", "type": "jsonb",
@@ -535,33 +594,9 @@
"name": "geo_zone", "name": "geo_zone",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"keyName": "IDX_geo_zone_country_code",
"columnNames": ["country_code"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_country_code\" ON \"geo_zone\" (country_code) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_geo_zone_province_code",
"columnNames": ["province_code"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_province_code\" ON \"geo_zone\" (province_code) WHERE deleted_at IS NULL AND province_code IS NOT NULL"
},
{
"keyName": "IDX_geo_zone_city",
"columnNames": ["city"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_city\" ON \"geo_zone\" (city) WHERE deleted_at IS NULL AND city IS NOT NULL"
},
{ {
"keyName": "IDX_geo_zone_service_zone_id", "keyName": "IDX_geo_zone_service_zone_id",
"columnNames": ["service_zone_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -569,15 +604,41 @@
}, },
{ {
"keyName": "IDX_geo_zone_deleted_at", "keyName": "IDX_geo_zone_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_deleted_at\" ON \"geo_zone\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_deleted_at\" ON \"geo_zone\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_geo_zone_country_code",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_country_code\" ON \"geo_zone\" (country_code) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_geo_zone_province_code",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_province_code\" ON \"geo_zone\" (province_code) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_geo_zone_city",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_geo_zone_city\" ON \"geo_zone\" (city) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "geo_zone_pkey", "keyName": "geo_zone_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -587,9 +648,13 @@
"foreignKeys": { "foreignKeys": {
"geo_zone_service_zone_id_foreign": { "geo_zone_service_zone_id_foreign": {
"constraintName": "geo_zone_service_zone_id_foreign", "constraintName": "geo_zone_service_zone_id_foreign",
"columnNames": ["service_zone_id"], "columnNames": [
"service_zone_id"
],
"localTableName": "public.geo_zone", "localTableName": "public.geo_zone",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.service_zone", "referencedTableName": "public.service_zone",
"deleteRule": "cascade", "deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
@@ -672,15 +737,17 @@
"indexes": [ "indexes": [
{ {
"keyName": "IDX_shipping_option_type_deleted_at", "keyName": "IDX_shipping_option_type_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_type_deleted_at\" ON \"shipping_option_type\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_type_deleted_at\" ON \"shipping_option_type\" (deleted_at) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "shipping_option_type_pkey", "keyName": "shipping_option_type_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -763,25 +830,27 @@
"name": "shipping_profile", "name": "shipping_profile",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"keyName": "IDX_shipping_profile_deleted_at",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_profile_deleted_at\" ON \"shipping_profile\" (deleted_at) WHERE deleted_at IS NULL"
},
{ {
"keyName": "IDX_shipping_profile_name_unique", "keyName": "IDX_shipping_profile_name_unique",
"columnNames": ["name"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_shipping_profile_name_unique\" ON \"shipping_profile\" (name) WHERE deleted_at IS NULL" "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": ["deleted_at"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_profile_deleted_at\" ON \"shipping_profile\" (deleted_at) WHERE deleted_at IS NOT NULL"
},
{ {
"keyName": "shipping_profile_pkey", "keyName": "shipping_profile_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -818,9 +887,30 @@
"primary": false, "primary": false,
"nullable": false, "nullable": false,
"default": "'flat'", "default": "'flat'",
"enumItems": ["calculated", "flat"], "enumItems": [
"calculated",
"flat"
],
"mappedType": "enum" "mappedType": "enum"
}, },
"data": {
"name": "data",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"service_zone_id": { "service_zone_id": {
"name": "service_zone_id", "name": "service_zone_id",
"type": "text", "type": "text",
@@ -848,24 +938,6 @@
"nullable": true, "nullable": true,
"mappedType": "text" "mappedType": "text"
}, },
"data": {
"name": "data",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"shipping_option_type_id": { "shipping_option_type_id": {
"name": "shipping_option_type_id", "name": "shipping_option_type_id",
"type": "text", "type": "text",
@@ -911,16 +983,9 @@
"name": "shipping_option", "name": "shipping_option",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"columnNames": ["shipping_option_type_id"],
"composite": false,
"keyName": "shipping_option_shipping_option_type_id_unique",
"primary": false,
"unique": true
},
{ {
"keyName": "IDX_shipping_option_service_zone_id", "keyName": "IDX_shipping_option_service_zone_id",
"columnNames": ["service_zone_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -928,39 +993,25 @@
}, },
{ {
"keyName": "IDX_shipping_option_shipping_profile_id", "keyName": "IDX_shipping_option_shipping_profile_id",
"columnNames": ["shipping_profile_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_shipping_profile_id\" ON \"shipping_option\" (shipping_profile_id) WHERE deleted_at IS NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_shipping_profile_id\" ON \"shipping_option\" (shipping_profile_id) WHERE deleted_at IS NULL"
}, },
{
"keyName": "IDX_shipping_option_provider_id",
"columnNames": ["provider_id"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_provider_id\" ON \"shipping_option\" (provider_id) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_shipping_option_shipping_option_type_id",
"columnNames": ["shipping_option_type_id"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_shipping_option_type_id\" ON \"shipping_option\" (shipping_option_type_id) WHERE deleted_at IS NULL"
},
{ {
"keyName": "IDX_shipping_option_deleted_at", "keyName": "IDX_shipping_option_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_deleted_at\" ON \"shipping_option\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_deleted_at\" ON \"shipping_option\" (deleted_at) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "shipping_option_pkey", "keyName": "shipping_option_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -970,39 +1021,29 @@
"foreignKeys": { "foreignKeys": {
"shipping_option_service_zone_id_foreign": { "shipping_option_service_zone_id_foreign": {
"constraintName": "shipping_option_service_zone_id_foreign", "constraintName": "shipping_option_service_zone_id_foreign",
"columnNames": ["service_zone_id"], "columnNames": [
"service_zone_id"
],
"localTableName": "public.shipping_option", "localTableName": "public.shipping_option",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.service_zone", "referencedTableName": "public.service_zone",
"deleteRule": "cascade", "deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
}, },
"shipping_option_shipping_profile_id_foreign": { "shipping_option_shipping_profile_id_foreign": {
"constraintName": "shipping_option_shipping_profile_id_foreign", "constraintName": "shipping_option_shipping_profile_id_foreign",
"columnNames": ["shipping_profile_id"], "columnNames": [
"shipping_profile_id"
],
"localTableName": "public.shipping_option", "localTableName": "public.shipping_option",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.shipping_profile", "referencedTableName": "public.shipping_profile",
"deleteRule": "set null", "deleteRule": "set null",
"updateRule": "cascade" "updateRule": "cascade"
},
"shipping_option_provider_id_foreign": {
"constraintName": "shipping_option_provider_id_foreign",
"columnNames": ["provider_id"],
"localTableName": "public.shipping_option",
"referencedColumnNames": ["id"],
"referencedTableName": "public.fulfillment_provider",
"deleteRule": "set null",
"updateRule": "cascade"
},
"shipping_option_shipping_option_type_id_foreign": {
"constraintName": "shipping_option_shipping_option_type_id_foreign",
"columnNames": ["shipping_option_type_id"],
"localTableName": "public.shipping_option",
"referencedColumnNames": ["id"],
"referencedTableName": "public.shipping_option_type",
"deleteRule": "cascade",
"updateRule": "cascade"
} }
} }
}, },
@@ -1033,7 +1074,16 @@
"autoincrement": false, "autoincrement": false,
"primary": false, "primary": false,
"nullable": false, "nullable": false,
"enumItems": ["in", "eq", "ne", "gt", "gte", "lt", "lte", "nin"], "enumItems": [
"in",
"eq",
"ne",
"gt",
"gte",
"lt",
"lte",
"nin"
],
"mappedType": "enum" "mappedType": "enum"
}, },
"value": { "value": {
@@ -1092,7 +1142,7 @@
"indexes": [ "indexes": [
{ {
"keyName": "IDX_shipping_option_rule_shipping_option_id", "keyName": "IDX_shipping_option_rule_shipping_option_id",
"columnNames": ["shipping_option_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -1100,15 +1150,17 @@
}, },
{ {
"keyName": "IDX_shipping_option_rule_deleted_at", "keyName": "IDX_shipping_option_rule_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_rule_deleted_at\" ON \"shipping_option_rule\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_shipping_option_rule_deleted_at\" ON \"shipping_option_rule\" (deleted_at) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "shipping_option_rule_pkey", "keyName": "shipping_option_rule_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -1118,9 +1170,13 @@
"foreignKeys": { "foreignKeys": {
"shipping_option_rule_shipping_option_id_foreign": { "shipping_option_rule_shipping_option_id_foreign": {
"constraintName": "shipping_option_rule_shipping_option_id_foreign", "constraintName": "shipping_option_rule_shipping_option_id_foreign",
"columnNames": ["shipping_option_id"], "columnNames": [
"shipping_option_id"
],
"localTableName": "public.shipping_option_rule", "localTableName": "public.shipping_option_rule",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.shipping_option", "referencedTableName": "public.shipping_option",
"deleteRule": "cascade", "deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
@@ -1214,6 +1270,16 @@
"nullable": true, "nullable": true,
"mappedType": "json" "mappedType": "json"
}, },
"requires_shipping": {
"name": "requires_shipping",
"type": "boolean",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "true",
"mappedType": "boolean"
},
"provider_id": { "provider_id": {
"name": "provider_id", "name": "provider_id",
"type": "text", "type": "text",
@@ -1232,15 +1298,6 @@
"nullable": true, "nullable": true,
"mappedType": "text" "mappedType": "text"
}, },
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"delivery_address_id": { "delivery_address_id": {
"name": "delivery_address_id", "name": "delivery_address_id",
"type": "text", "type": "text",
@@ -1250,15 +1307,14 @@
"nullable": true, "nullable": true,
"mappedType": "text" "mappedType": "text"
}, },
"requires_shipping": { "metadata": {
"name": "requires_shipping", "name": "metadata",
"type": "boolean", "type": "jsonb",
"unsigned": false, "unsigned": false,
"autoincrement": false, "autoincrement": false,
"primary": false, "primary": false,
"nullable": false, "nullable": true,
"default": "true", "mappedType": "json"
"mappedType": "boolean"
}, },
"created_at": { "created_at": {
"name": "created_at", "name": "created_at",
@@ -1296,32 +1352,9 @@
"name": "fulfillment", "name": "fulfillment",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"columnNames": ["delivery_address_id"],
"composite": false,
"keyName": "fulfillment_delivery_address_id_unique",
"primary": false,
"unique": true
},
{
"keyName": "IDX_fulfillment_location_id",
"columnNames": ["location_id"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_location_id\" ON \"fulfillment\" (location_id) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_fulfillment_provider_id",
"columnNames": ["provider_id"],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_provider_id\" ON \"fulfillment\" (provider_id) WHERE deleted_at IS NULL"
},
{ {
"keyName": "IDX_fulfillment_shipping_option_id", "keyName": "IDX_fulfillment_shipping_option_id",
"columnNames": ["shipping_option_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -1329,15 +1362,25 @@
}, },
{ {
"keyName": "IDX_fulfillment_deleted_at", "keyName": "IDX_fulfillment_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_deleted_at\" ON \"fulfillment\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_deleted_at\" ON \"fulfillment\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_fulfillment_location_id",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_location_id\" ON \"fulfillment\" (location_id) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "fulfillment_pkey", "keyName": "fulfillment_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -1345,32 +1388,18 @@
], ],
"checks": [], "checks": [],
"foreignKeys": { "foreignKeys": {
"fulfillment_provider_id_foreign": {
"constraintName": "fulfillment_provider_id_foreign",
"columnNames": ["provider_id"],
"localTableName": "public.fulfillment",
"referencedColumnNames": ["id"],
"referencedTableName": "public.fulfillment_provider",
"deleteRule": "set null",
"updateRule": "cascade"
},
"fulfillment_shipping_option_id_foreign": { "fulfillment_shipping_option_id_foreign": {
"constraintName": "fulfillment_shipping_option_id_foreign", "constraintName": "fulfillment_shipping_option_id_foreign",
"columnNames": ["shipping_option_id"], "columnNames": [
"shipping_option_id"
],
"localTableName": "public.fulfillment", "localTableName": "public.fulfillment",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.shipping_option", "referencedTableName": "public.shipping_option",
"deleteRule": "set null", "deleteRule": "set null",
"updateRule": "cascade" "updateRule": "cascade"
},
"fulfillment_delivery_address_id_foreign": {
"constraintName": "fulfillment_delivery_address_id_foreign",
"columnNames": ["delivery_address_id"],
"localTableName": "public.fulfillment",
"referencedColumnNames": ["id"],
"referencedTableName": "public.fulfillment_address",
"deleteRule": "cascade",
"updateRule": "cascade"
} }
} }
}, },
@@ -1459,7 +1488,7 @@
"indexes": [ "indexes": [
{ {
"keyName": "IDX_fulfillment_label_fulfillment_id", "keyName": "IDX_fulfillment_label_fulfillment_id",
"columnNames": ["fulfillment_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -1467,15 +1496,17 @@
}, },
{ {
"keyName": "IDX_fulfillment_label_deleted_at", "keyName": "IDX_fulfillment_label_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_label_deleted_at\" ON \"fulfillment_label\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_label_deleted_at\" ON \"fulfillment_label\" (deleted_at) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "fulfillment_label_pkey", "keyName": "fulfillment_label_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -1485,9 +1516,13 @@
"foreignKeys": { "foreignKeys": {
"fulfillment_label_fulfillment_id_foreign": { "fulfillment_label_fulfillment_id_foreign": {
"constraintName": "fulfillment_label_fulfillment_id_foreign", "constraintName": "fulfillment_label_fulfillment_id_foreign",
"columnNames": ["fulfillment_id"], "columnNames": [
"fulfillment_id"
],
"localTableName": "public.fulfillment_label", "localTableName": "public.fulfillment_label",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.fulfillment", "referencedTableName": "public.fulfillment",
"deleteRule": "cascade", "deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
@@ -1541,15 +1576,6 @@
"nullable": false, "nullable": false,
"mappedType": "decimal" "mappedType": "decimal"
}, },
"raw_quantity": {
"name": "raw_quantity",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "json"
},
"line_item_id": { "line_item_id": {
"name": "line_item_id", "name": "line_item_id",
"type": "text", "type": "text",
@@ -1577,6 +1603,15 @@
"nullable": false, "nullable": false,
"mappedType": "text" "mappedType": "text"
}, },
"raw_quantity": {
"name": "raw_quantity",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "json"
},
"created_at": { "created_at": {
"name": "created_at", "name": "created_at",
"type": "timestamptz", "type": "timestamptz",
@@ -1613,25 +1648,9 @@
"name": "fulfillment_item", "name": "fulfillment_item",
"schema": "public", "schema": "public",
"indexes": [ "indexes": [
{
"keyName": "IDX_fulfillment_item_line_item_id",
"columnNames": ["line_item_id"],
"composite": false,
"primary": false,
"unique": false,
"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",
"columnNames": ["inventory_item_id"],
"composite": false,
"primary": false,
"unique": false,
"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", "keyName": "IDX_fulfillment_item_fulfillment_id",
"columnNames": ["fulfillment_id"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
@@ -1639,15 +1658,33 @@
}, },
{ {
"keyName": "IDX_fulfillment_item_deleted_at", "keyName": "IDX_fulfillment_item_deleted_at",
"columnNames": ["deleted_at"], "columnNames": [],
"composite": false, "composite": false,
"primary": false, "primary": false,
"unique": false, "unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_deleted_at\" ON \"fulfillment_item\" (deleted_at) WHERE deleted_at IS NOT NULL" "expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_deleted_at\" ON \"fulfillment_item\" (deleted_at) WHERE deleted_at IS NULL"
},
{
"keyName": "IDX_fulfillment_item_inventory_item_id",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"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_line_item_id",
"columnNames": [],
"composite": false,
"primary": false,
"unique": false,
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_fulfillment_item_line_item_id\" ON \"fulfillment_item\" (line_item_id) WHERE deleted_at IS NULL"
}, },
{ {
"keyName": "fulfillment_item_pkey", "keyName": "fulfillment_item_pkey",
"columnNames": ["id"], "columnNames": [
"id"
],
"composite": false, "composite": false,
"primary": true, "primary": true,
"unique": true "unique": true
@@ -1657,9 +1694,13 @@
"foreignKeys": { "foreignKeys": {
"fulfillment_item_fulfillment_id_foreign": { "fulfillment_item_fulfillment_id_foreign": {
"constraintName": "fulfillment_item_fulfillment_id_foreign", "constraintName": "fulfillment_item_fulfillment_id_foreign",
"columnNames": ["fulfillment_id"], "columnNames": [
"fulfillment_id"
],
"localTableName": "public.fulfillment_item", "localTableName": "public.fulfillment_item",
"referencedColumnNames": ["id"], "referencedColumnNames": [
"id"
],
"referencedTableName": "public.fulfillment", "referencedTableName": "public.fulfillment",
"deleteRule": "cascade", "deleteRule": "cascade",
"updateRule": "cascade" "updateRule": "cascade"
@@ -0,0 +1,81 @@
import { Migration } from "@mikro-orm/migrations"
export class Migration20241217110416 extends Migration {
async up(): Promise<void> {
this.addSql(
'alter table if exists "shipping_option" drop constraint if exists "shipping_option_provider_id_foreign";'
)
this.addSql(
'alter table if exists "shipping_option" drop constraint if exists "shipping_option_shipping_option_type_id_foreign";'
)
this.addSql(
'alter table if exists "fulfillment" drop constraint if exists "fulfillment_provider_id_foreign";'
)
this.addSql(
'alter table if exists "fulfillment" drop constraint if exists "fulfillment_delivery_address_id_foreign";'
)
this.addSql(
'alter table if exists "fulfillment_provider" add column if not exists "created_at" timestamptz not null default now(), add column if not exists "updated_at" timestamptz not null default now(), add column if not exists "deleted_at" timestamptz null;'
)
this.addSql(
'CREATE INDEX IF NOT EXISTS "IDX_fulfillment_provider_deleted_at" ON "fulfillment_provider" (deleted_at) WHERE deleted_at IS NULL;'
)
this.addSql(
'alter table if exists "shipping_option" drop constraint if exists "shipping_option_shipping_option_type_id_unique";'
)
this.addSql('drop index if exists "IDX_shipping_option_provider_id";')
this.addSql(
'drop index if exists "IDX_shipping_option_shipping_option_type_id";'
)
this.addSql(
'alter table if exists "fulfillment" drop constraint if exists "fulfillment_delivery_address_id_unique";'
)
this.addSql('drop index if exists "IDX_fulfillment_provider_id";')
}
async down(): Promise<void> {
this.addSql('drop index if exists "IDX_fulfillment_provider_deleted_at";')
this.addSql(
'alter table if exists "fulfillment_provider" drop column if exists "created_at";'
)
this.addSql(
'alter table if exists "fulfillment_provider" drop column if exists "updated_at";'
)
this.addSql(
'alter table if exists "fulfillment_provider" drop column if exists "deleted_at";'
)
this.addSql(
'alter table if exists "shipping_option" add constraint "shipping_option_provider_id_foreign" foreign key ("provider_id") references "fulfillment_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 "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_provider_id" ON "shipping_option" (provider_id) WHERE deleted_at IS NULL;'
)
this.addSql(
'CREATE INDEX IF NOT EXISTS "IDX_shipping_option_shipping_option_type_id" ON "shipping_option" (shipping_option_type_id) WHERE deleted_at IS NULL;'
)
this.addSql(
'alter table if exists "fulfillment" add constraint "fulfillment_provider_id_foreign" foreign key ("provider_id") references "fulfillment_provider" ("id") on update cascade on delete set null;'
)
this.addSql(
'alter table if exists "fulfillment" add constraint "fulfillment_delivery_address_id_foreign" foreign key ("delivery_address_id") references "fulfillment_address" ("id") on update cascade on delete cascade;'
)
this.addSql(
'alter table if exists "fulfillment" add constraint "fulfillment_delivery_address_id_unique" unique ("delivery_address_id");'
)
this.addSql(
'CREATE INDEX IF NOT EXISTS "IDX_fulfillment_provider_id" ON "fulfillment" (provider_id) WHERE deleted_at IS NULL;'
)
}
}
@@ -1,91 +1,16 @@
import { DAL } from "@medusajs/framework/types" import { model } from "@medusajs/framework/utils"
import {
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/framework/utils"
import {
BeforeCreate,
Entity,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
type OptionalAddressProps = DAL.SoftDeletableModelDateColumns export const FulfillmentAddress = model.define("fulfillment_address", {
id: model.id({ prefix: "fuladdr" }).primaryKey(),
const FulfillmentDeletedAtIndex = createPsqlIndexStatementHelper({ company: model.text().nullable(),
tableName: "fulfillment_address", first_name: model.text().nullable(),
columns: "deleted_at", last_name: model.text().nullable(),
where: "deleted_at IS NOT NULL", address_1: model.text().nullable(),
address_2: model.text().nullable(),
city: model.text().nullable(),
country_code: model.text().nullable(),
province: model.text().nullable(),
postal_code: model.text().nullable(),
phone: model.text().nullable(),
metadata: model.json().nullable(),
}) })
@Entity({ tableName: "fulfillment_address" })
export default class FulfillmentAddress {
[OptionalProps]: OptionalAddressProps
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text", nullable: true })
company: string | null = null
@Property({ columnType: "text", nullable: true })
first_name: string | null = null
@Property({ columnType: "text", nullable: true })
last_name: string | null = null
@Property({ columnType: "text", nullable: true })
address_1: string | null = null
@Property({ columnType: "text", nullable: true })
address_2: string | null = null
@Property({ columnType: "text", nullable: true })
city: string | null = null
@Property({ columnType: "text", nullable: true })
country_code: string | null = null
@Property({ columnType: "text", nullable: true })
province: string | null = null
@Property({ columnType: "text", nullable: true })
postal_code: string | null = null
@Property({ columnType: "text", nullable: true })
phone: string | null = null
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Property({ columnType: "timestamptz", nullable: true })
@FulfillmentDeletedAtIndex.MikroORMIndex()
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "fuladdr")
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "fuladdr")
}
}
@@ -1,122 +1,27 @@
import { import { model } from "@medusajs/framework/utils"
BigNumber,
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
MikroOrmBigNumberProperty,
} from "@medusajs/framework/utils"
import { BigNumberRawValue, DAL } from "@medusajs/framework/types" import { Fulfillment } from "./fulfillment"
import {
BeforeCreate,
Entity,
Filter,
ManyToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import Fulfillment from "./fulfillment"
type FulfillmentItemOptionalProps = DAL.SoftDeletableModelDateColumns export const FulfillmentItem = model
.define("fulfillment_item", {
const FulfillmentIdIndex = createPsqlIndexStatementHelper({ id: model.id({ prefix: "fulit" }).primaryKey(),
tableName: "fulfillment_item", title: model.text(),
columns: "fulfillment_id", sku: model.text(),
where: "deleted_at IS NULL", barcode: model.text(),
}) quantity: model.bigNumber(),
line_item_id: model.text().nullable(),
const LineItemIdIndex = createPsqlIndexStatementHelper({ inventory_item_id: model.text().nullable(),
tableName: "fulfillment_item", fulfillment: model.belongsTo(() => Fulfillment, {
columns: "line_item_id", mappedBy: "items",
where: "deleted_at IS NULL", }),
})
const InventoryItemIdIndex = createPsqlIndexStatementHelper({
tableName: "fulfillment_item",
columns: "inventory_item_id",
where: "deleted_at IS NULL",
})
const FulfillmentItemDeletedAtIndex = createPsqlIndexStatementHelper({
tableName: "fulfillment_item",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class FulfillmentItem {
[OptionalProps]?: FulfillmentItemOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
title: string
@Property({ columnType: "text" })
sku: string
@Property({ columnType: "text" })
barcode: string
@MikroOrmBigNumberProperty()
quantity: BigNumber | number
@Property({ columnType: "jsonb" })
raw_quantity: BigNumberRawValue
@Property({ columnType: "text", nullable: true })
@LineItemIdIndex.MikroORMIndex()
line_item_id: string | null = null
@Property({ columnType: "text", nullable: true })
@InventoryItemIdIndex.MikroORMIndex()
inventory_item_id: string | null = null
@ManyToOne(() => Fulfillment, {
columnType: "text",
mapToPk: true,
fieldName: "fulfillment_id",
onDelete: "cascade",
}) })
@FulfillmentIdIndex.MikroORMIndex() .indexes([
fulfillment_id: string {
on: ["inventory_item_id"],
@ManyToOne(() => Fulfillment, { persist: false }) where: "deleted_at IS NULL",
fulfillment: Rel<Fulfillment> },
{
@Property({ on: ["line_item_id"],
onCreate: () => new Date(), where: "deleted_at IS NULL",
columnType: "timestamptz", },
defaultRaw: "now()", ])
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@FulfillmentItemDeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "fulit")
this.fulfillment_id ??= this.fulfillment.id
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "fulit")
this.fulfillment_id ??= this.fulfillment.id
}
}
@@ -1,94 +1,13 @@
import { import { model } from "@medusajs/framework/utils"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
} from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { Fulfillment } from "./fulfillment"
import {
BeforeCreate,
Entity,
Filter,
ManyToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import Fulfillment from "./fulfillment"
type FulfillmentLabelOptionalProps = DAL.SoftDeletableModelDateColumns export const FulfillmentLabel = model.define("fulfillment_label", {
id: model.id({ prefix: "fulla" }).primaryKey(),
const FulfillmentIdIndex = createPsqlIndexStatementHelper({ tracking_number: model.text(),
tableName: "fulfillment_label", tracking_url: model.text(),
columns: "fulfillment_id", label_url: model.text(),
where: "deleted_at IS NULL", fulfillment: model.belongsTo(() => Fulfillment, {
mappedBy: "labels",
}),
}) })
const DeletedAtIndex = createPsqlIndexStatementHelper({
tableName: "fulfillment_label",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class FulfillmentLabel {
[OptionalProps]?: FulfillmentLabelOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
tracking_number: string
@Property({ columnType: "text" })
tracking_url: string
@Property({ columnType: "text" })
label_url: string
@ManyToOne(() => Fulfillment, {
columnType: "text",
mapToPk: true,
fieldName: "fulfillment_id",
onDelete: "cascade",
})
@FulfillmentIdIndex.MikroORMIndex()
fulfillment_id: string
@ManyToOne(() => Fulfillment, { persist: false })
fulfillment: Rel<Fulfillment>
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Property({ columnType: "timestamptz", nullable: true })
@DeletedAtIndex.MikroORMIndex()
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "fulla")
this.fulfillment_id ??= this.fulfillment.id
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "fulla")
this.fulfillment_id ??= this.fulfillment.id
}
}
@@ -1,28 +1,6 @@
import { Searchable, generateEntityId } from "@medusajs/framework/utils" import { model } from "@medusajs/framework/utils"
import {
BeforeCreate,
Entity,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
@Entity() export const FulfillmentProvider = model.define("fulfillment_provider", {
export default class FulfillmentProvider { id: model.id({ prefix: "serpro" }).primaryKey(),
@Searchable() is_enabled: model.boolean().default(true),
@PrimaryKey({ columnType: "text" }) })
id: string
@Property({ columnType: "boolean", defaultRaw: "true" })
is_enabled: boolean = true
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "serpro")
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "serpro")
}
}
@@ -1,90 +1,24 @@
import { import { model } from "@medusajs/framework/utils"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
} from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { ServiceZone } from "./service-zone"
import {
BeforeCreate,
Cascade,
Collection,
Entity,
Filter,
OneToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import ServiceZone from "./service-zone"
type FulfillmentSetOptionalProps = DAL.SoftDeletableModelDateColumns export const FulfillmentSet = model
.define("fulfillment_set", {
const DeletedAtIndex = createPsqlIndexStatementHelper({ id: model.id({ prefix: "fuset" }).primaryKey(),
tableName: "fulfillment_set", name: model.text(),
columns: "deleted_at", type: model.text(),
where: "deleted_at IS NOT NULL", service_zones: model.hasMany(() => ServiceZone, {
}) mappedBy: "fulfillment_set",
}),
const NameIndex = createPsqlIndexStatementHelper({ metadata: model.json().nullable(),
tableName: "fulfillment_set",
columns: "name",
unique: true,
where: "deleted_at IS NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class FulfillmentSet {
[OptionalProps]?: FulfillmentSetOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
@NameIndex.MikroORMIndex()
name: string
@Property({ columnType: "text" })
type: string
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@OneToMany(() => ServiceZone, "fulfillment_set", {
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
}) })
service_zones = new Collection<Rel<ServiceZone>>(this) .indexes([
{
@Property({ on: ["name"],
onCreate: () => new Date(), where: "deleted_at IS NULL",
columnType: "timestamptz", unique: true,
defaultRaw: "now()", },
])
.cascades({
delete: ["service_zones"],
}) })
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Property({ columnType: "timestamptz", nullable: true })
@DeletedAtIndex.MikroORMIndex()
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "fuset")
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "fuset")
}
}
@@ -1,183 +1,54 @@
import { import { model } from "@medusajs/framework/utils"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
} from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { FulfillmentAddress } from "./address"
import { import { FulfillmentItem } from "./fulfillment-item"
BeforeCreate, import { FulfillmentLabel } from "./fulfillment-label"
Cascade, import { FulfillmentProvider } from "./fulfillment-provider"
Collection, import { ShippingOption } from "./shipping-option"
Entity,
Filter,
ManyToOne,
OneToMany,
OneToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import FulfillmentAddress from "./address"
import FulfillmentItem from "./fulfillment-item"
import FulfillmentLabel from "./fulfillment-label"
import FulfillmentProvider from "./fulfillment-provider"
import ShippingOption from "./shipping-option"
type FulfillmentOptionalProps = DAL.SoftDeletableModelDateColumns export const Fulfillment = model
.define("fulfillment", {
const FulfillmentDeletedAtIndex = createPsqlIndexStatementHelper({ id: model.id({ prefix: "ful" }).primaryKey(),
tableName: "fulfillment", location_id: model.text(),
columns: "deleted_at", packed_at: model.dateTime().nullable(),
where: "deleted_at IS NOT NULL", shipped_at: model.dateTime().nullable(),
}) marked_shipped_by: model.text().nullable(),
created_by: model.text().nullable(),
const FulfillmentProviderIdIndex = createPsqlIndexStatementHelper({ delivered_at: model.dateTime().nullable(),
tableName: "fulfillment", canceled_at: model.dateTime().nullable(),
columns: "provider_id", data: model.json().nullable(),
where: "deleted_at IS NULL", requires_shipping: model.boolean().default(true),
}) items: model.hasMany(() => FulfillmentItem, {
mappedBy: "fulfillment",
const FulfillmentLocationIdIndex = createPsqlIndexStatementHelper({ }),
tableName: "fulfillment", labels: model.hasMany(() => FulfillmentLabel, {
columns: "location_id", mappedBy: "fulfillment",
where: "deleted_at IS NULL", }),
}) provider: model
.hasOne(() => FulfillmentProvider, {
const FulfillmentShippingOptionIdIndex = createPsqlIndexStatementHelper({ foreignKey: true,
tableName: "fulfillment", mappedBy: undefined,
columns: "shipping_option_id", })
where: "deleted_at IS NULL", .nullable(),
}) shipping_option: model
.belongsTo(() => ShippingOption, {
@Entity() mappedBy: "fulfillments",
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions) })
export default class Fulfillment { .nullable(),
[OptionalProps]?: FulfillmentOptionalProps delivery_address: model
.hasOne(() => FulfillmentAddress, {
@PrimaryKey({ columnType: "text" }) foreignKey: true,
id: string mappedBy: undefined,
})
@Property({ columnType: "text" }) .nullable(),
@FulfillmentLocationIdIndex.MikroORMIndex() metadata: model.json().nullable(),
location_id: string
@Property({
columnType: "timestamptz",
nullable: true,
}) })
packed_at: Date | null = null .indexes([
{
@Property({ on: ["location_id"],
columnType: "timestamptz", where: "deleted_at IS NULL",
nullable: true, },
])
.cascades({
delete: ["delivery_address", "items", "labels"],
}) })
shipped_at: Date | null = null
@Property({ columnType: "text", nullable: true })
marked_shipped_by: string | null = null
@Property({ columnType: "text", nullable: true })
created_by: string | null = null
@Property({
columnType: "timestamptz",
nullable: true,
})
delivered_at: Date | null = null
@Property({
columnType: "timestamptz",
nullable: true,
})
canceled_at: Date | null = null
@Property({ columnType: "jsonb", nullable: true })
data: Record<string, unknown> | null = null
@ManyToOne(() => FulfillmentProvider, {
columnType: "text",
fieldName: "provider_id",
mapToPk: true,
nullable: true,
onDelete: "set null",
})
@FulfillmentProviderIdIndex.MikroORMIndex()
provider_id: string
@ManyToOne(() => ShippingOption, {
columnType: "text",
fieldName: "shipping_option_id",
nullable: true,
mapToPk: true,
onDelete: "set null",
})
@FulfillmentShippingOptionIdIndex.MikroORMIndex()
shipping_option_id: string | null = null
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@ManyToOne(() => ShippingOption, { persist: false })
shipping_option: ShippingOption | null
@ManyToOne(() => FulfillmentProvider, { persist: false })
provider: Rel<FulfillmentProvider>
@OneToOne({
entity: () => FulfillmentAddress,
owner: true,
cascade: [Cascade.PERSIST, "soft-remove"] as any,
nullable: true,
onDelete: "cascade",
})
delivery_address!: Rel<FulfillmentAddress>
@Property({ columnType: "boolean", default: true })
requires_shipping: boolean = true
@OneToMany(() => FulfillmentItem, (item) => item.fulfillment, {
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
})
items = new Collection<Rel<FulfillmentItem>>(this)
@OneToMany(() => FulfillmentLabel, (label) => label.fulfillment, {
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
})
labels = new Collection<Rel<FulfillmentLabel>>(this)
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@FulfillmentDeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "ful")
this.provider_id ??= this.provider_id ?? this.provider?.id
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "ful")
this.provider_id ??= this.provider_id ?? this.provider?.id
}
}
@@ -1,128 +1,53 @@
import { import {
createPsqlIndexStatementHelper, BelongsTo,
DALUtils, DmlEntity,
generateEntityId, DMLEntitySchemaBuilder,
GeoZoneType, GeoZoneType,
IdProperty,
JSONProperty,
model,
NullableModifier,
PrimaryKeyModifier,
TextProperty,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { ServiceZone } from "./service-zone"
import {
BeforeCreate,
Entity,
Enum,
Filter,
ManyToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import ServiceZone from "./service-zone"
type GeoZoneOptionalProps = DAL.SoftDeletableModelDateColumns export type GeoZoneSchema = {
id: PrimaryKeyModifier<string, IdProperty>
const DeletedAtIndex = createPsqlIndexStatementHelper({ type: TextProperty
tableName: "geo_zone", country_code: TextProperty
columns: "deleted_at", province_code?: NullableModifier<string, TextProperty>
where: "deleted_at IS NOT NULL", city?: NullableModifier<string, TextProperty>
}) postal_expression?: NullableModifier<Record<string, unknown>, JSONProperty>
service_zone: BelongsTo<() => typeof ServiceZone>
const CountryCodeIndex = createPsqlIndexStatementHelper({ metadata?: NullableModifier<Record<string, unknown>, JSONProperty>
tableName: "geo_zone",
columns: "country_code",
where: "deleted_at IS NULL",
})
const ProvinceCodeIndex = createPsqlIndexStatementHelper({
tableName: "geo_zone",
columns: "province_code",
where: "deleted_at IS NULL AND province_code IS NOT NULL",
})
const CityIndex = createPsqlIndexStatementHelper({
tableName: "geo_zone",
columns: "city",
where: "deleted_at IS NULL AND city IS NOT NULL",
})
const ServiceZoneIdIndex = createPsqlIndexStatementHelper({
tableName: "geo_zone",
columns: "service_zone_id",
where: "deleted_at IS NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class GeoZone {
[OptionalProps]?: GeoZoneOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Enum({ items: () => GeoZoneType, default: GeoZoneType.COUNTRY })
type: GeoZoneType
@CountryCodeIndex.MikroORMIndex()
@Property({ columnType: "text" })
country_code: string
@ProvinceCodeIndex.MikroORMIndex()
@Property({ columnType: "text", nullable: true })
province_code: string | null = null
@CityIndex.MikroORMIndex()
@Property({ columnType: "text", nullable: true })
city: string | null = null
@ManyToOne(() => ServiceZone, {
type: "text",
mapToPk: true,
fieldName: "service_zone_id",
onDelete: "cascade",
})
@ServiceZoneIdIndex.MikroORMIndex()
service_zone_id: string
@Property({ columnType: "jsonb", nullable: true })
postal_expression: Record<string, unknown> | null = null
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@ManyToOne(() => ServiceZone, {
persist: false,
})
service_zone: Rel<ServiceZone>
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@DeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "fgz")
this.service_zone_id ??= this.service_zone?.id
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "fgz")
this.service_zone_id ??= this.service_zone?.id
}
} }
export const GeoZone = model
.define("geo_zone", {
id: model.id({ prefix: "fgz" }).primaryKey(),
type: model.enum(GeoZoneType).default(GeoZoneType.COUNTRY),
country_code: model.text(),
province_code: model.text().nullable(),
city: model.text().nullable(),
postal_expression: model.json().nullable(),
service_zone: model.belongsTo<() => typeof ServiceZone>(() => ServiceZone, {
mappedBy: "geo_zones",
}),
metadata: model.json().nullable(),
})
.indexes([
{
on: ["country_code"],
where: "deleted_at IS NULL",
},
{
on: ["province_code"],
where: "deleted_at IS NULL",
},
{
on: ["city"],
where: "deleted_at IS NULL",
},
]) as unknown as DmlEntity<DMLEntitySchemaBuilder<GeoZoneSchema>, "GeoZone">
@@ -1,12 +1,12 @@
export { default as FulfillmentAddress } from "./address" export { FulfillmentAddress } from "./address"
export { default as Fulfillment } from "./fulfillment" export { Fulfillment } from "./fulfillment"
export { default as FulfillmentItem } from "./fulfillment-item" export { FulfillmentItem } from "./fulfillment-item"
export { default as FulfillmentLabel } from "./fulfillment-label" export { FulfillmentLabel } from "./fulfillment-label"
export { default as FulfillmentProvider } from "./fulfillment-provider" export { FulfillmentProvider } from "./fulfillment-provider"
export { default as FulfillmentSet } from "./fulfillment-set" export { FulfillmentSet } from "./fulfillment-set"
export { default as GeoZone } from "./geo-zone" export { GeoZone } from "./geo-zone"
export { default as ServiceZone } from "./service-zone" export { ServiceZone } from "./service-zone"
export { default as ShippingOption } from "./shipping-option" export { ShippingOption } from "./shipping-option"
export { default as ShippingOptionRule } from "./shipping-option-rule" export { ShippingOptionRule } from "./shipping-option-rule"
export { default as ShippingOptionType } from "./shipping-option-type" export { ShippingOptionType } from "./shipping-option-type"
export { default as ShippingProfile } from "./shipping-profile" export { ShippingProfile } from "./shipping-profile"
@@ -1,126 +1,60 @@
import { import {
createPsqlIndexStatementHelper, BelongsTo,
DALUtils, DmlEntity,
generateEntityId, DMLEntitySchemaBuilder,
HasMany,
IdProperty,
JSONProperty,
model,
NullableModifier,
PrimaryKeyModifier,
TextProperty,
} from "@medusajs/framework/utils" } from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { FulfillmentSet } from "./fulfillment-set"
import { import { GeoZone } from "./geo-zone"
BeforeCreate, import { ShippingOption } from "./shipping-option"
Cascade,
Collection,
Entity,
Filter,
Index,
ManyToOne,
OneToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import FulfillmentSet from "./fulfillment-set"
import GeoZone from "./geo-zone"
import ShippingOption from "./shipping-option"
type ServiceZoneOptionalProps = DAL.SoftDeletableModelDateColumns export type ServiceZoneSchema = {
id: PrimaryKeyModifier<string, IdProperty>
const deletedAtIndexName = "IDX_service_zone_deleted_at" name: TextProperty
const deletedAtIndexStatement = createPsqlIndexStatementHelper({ fulfillment_set: BelongsTo<() => typeof FulfillmentSet>
name: deletedAtIndexName, geo_zones: HasMany<() => typeof GeoZone>
tableName: "service_zone", shipping_options: HasMany<() => typeof ShippingOption>
columns: "deleted_at", metadata: NullableModifier<Record<string, unknown>, JSONProperty>
where: "deleted_at IS NOT NULL",
}).expression
const NameIndex = createPsqlIndexStatementHelper({
tableName: "service_zone",
columns: "name",
unique: true,
where: "deleted_at IS NULL",
})
const FulfillmentSetIdIndex = createPsqlIndexStatementHelper({
tableName: "service_zone",
columns: "fulfillment_set_id",
where: "deleted_at IS NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class ServiceZone {
[OptionalProps]?: ServiceZoneOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
@NameIndex.MikroORMIndex()
name: string
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@ManyToOne(() => FulfillmentSet, {
type: "text",
mapToPk: true,
fieldName: "fulfillment_set_id",
onDelete: "cascade",
})
@FulfillmentSetIdIndex.MikroORMIndex()
fulfillment_set_id: string
@ManyToOne(() => FulfillmentSet, { persist: false })
fulfillment_set: Rel<FulfillmentSet>
@OneToMany(() => GeoZone, "service_zone", {
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
})
geo_zones = new Collection<Rel<GeoZone>>(this)
@OneToMany(
() => ShippingOption,
(shippingOption) => shippingOption.service_zone,
{
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
}
)
shipping_options = new Collection<Rel<ShippingOption>>(this)
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({
name: deletedAtIndexName,
expression: deletedAtIndexStatement,
})
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "serzo")
this.fulfillment_set_id ??= this.fulfillment_set?.id
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "serzo")
this.fulfillment_set_id ??= this.fulfillment_set?.id
}
} }
export const ServiceZone = model
.define("service_zone", {
id: model.id({ prefix: "serzo" }).primaryKey(),
name: model.text(),
fulfillment_set: model.belongsTo<() => typeof FulfillmentSet>(
() => FulfillmentSet,
{
mappedBy: "service_zones",
}
),
geo_zones: model.hasMany<() => typeof GeoZone>(() => GeoZone, {
mappedBy: "service_zone",
}),
shipping_options: model.hasMany<() => typeof ShippingOption>(
() => ShippingOption,
{
mappedBy: "service_zone",
}
),
metadata: model.json().nullable(),
})
.indexes([
{
on: ["name"],
unique: true,
where: "deleted_at IS NULL",
},
])
.cascades({
delete: ["geo_zones", "shipping_options"],
}) as unknown as DmlEntity<
DMLEntitySchemaBuilder<ServiceZoneSchema>,
"ServiceZone"
>
@@ -1,100 +1,12 @@
import { DAL } from "@medusajs/framework/types" import { model, RuleOperator } from "@medusajs/framework/utils"
import { import { ShippingOption } from "./shipping-option"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
RuleOperator,
} from "@medusajs/framework/utils"
import {
BeforeCreate,
Entity,
Enum,
Filter,
ManyToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import ShippingOption from "./shipping-option"
type ShippingOptionRuleOptionalProps = DAL.SoftDeletableModelDateColumns export const ShippingOptionRule = model.define("shipping_option_rule", {
id: model.id({ prefix: "sorul" }).primaryKey(),
const DeletedAtIndex = createPsqlIndexStatementHelper({ attribute: model.text(),
tableName: "shipping_option_rule", operator: model.enum(RuleOperator),
columns: "deleted_at", value: model.json().nullable(),
where: "deleted_at IS NOT NULL", shipping_option: model.belongsTo(() => ShippingOption, {
mappedBy: "rules",
}),
}) })
const ShippingOptionIdIndex = createPsqlIndexStatementHelper({
tableName: "shipping_option_rule",
columns: "shipping_option_id",
where: "deleted_at IS NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class ShippingOptionRule {
[OptionalProps]?: ShippingOptionRuleOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
attribute: string
@Enum({
items: () => Object.values(RuleOperator),
columnType: "text",
})
operator: Lowercase<keyof typeof RuleOperator>
@Property({ columnType: "jsonb", nullable: true })
value: string | string[] | null = null
@ManyToOne(() => ShippingOption, {
type: "text",
mapToPk: true,
fieldName: "shipping_option_id",
onDelete: "cascade",
})
@ShippingOptionIdIndex.MikroORMIndex()
shipping_option_id: string
@ManyToOne(() => ShippingOption, {
persist: false,
})
shipping_option: Rel<ShippingOption>
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@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
}
}
@@ -1,80 +1,13 @@
import { import { model } from "@medusajs/framework/utils"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
} from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { ShippingOption } from "./shipping-option"
import {
BeforeCreate,
Entity,
Filter,
OneToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import ShippingOption from "./shipping-option"
type ShippingOptionTypeOptionalProps = DAL.SoftDeletableModelDateColumns export const ShippingOptionType = model.define("shipping_option_type", {
id: model.id({ prefix: "sotype" }).primaryKey(),
const DeletedAtIndex = createPsqlIndexStatementHelper({ label: model.text(),
tableName: "shipping_option_type", description: model.text().nullable(),
columns: "deleted_at", code: model.text(),
where: "deleted_at IS NOT NULL", shipping_option: model.hasOne(() => ShippingOption, {
mappedBy: "type",
}),
}) })
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class ShippingOptionType {
[OptionalProps]?: ShippingOptionTypeOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
label: string
@Property({ columnType: "text", nullable: true })
description: string | null = null
@Property({ columnType: "text" })
code: string
@OneToOne(() => ShippingOption, (so) => so.type, {
type: "text",
onDelete: "cascade",
})
shipping_option: Rel<ShippingOption>
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@DeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "sotype")
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "sotype")
}
}
@@ -1,182 +1,42 @@
import { import { model, ShippingOptionPriceType } from "@medusajs/framework/utils"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
Searchable,
ShippingOptionPriceType,
} from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { Fulfillment } from "./fulfillment"
import { import { FulfillmentProvider } from "./fulfillment-provider"
BeforeCreate, import { ServiceZone } from "./service-zone"
Cascade, import { ShippingOptionRule } from "./shipping-option-rule"
Collection, import { ShippingOptionType } from "./shipping-option-type"
Entity, import { ShippingProfile } from "./shipping-profile"
Enum,
Filter,
ManyToOne,
OneToMany,
OneToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import Fulfillment from "./fulfillment"
import FulfillmentProvider from "./fulfillment-provider"
import ServiceZone from "./service-zone"
import ShippingOptionRule from "./shipping-option-rule"
import ShippingOptionType from "./shipping-option-type"
import ShippingProfile from "./shipping-profile"
type ShippingOptionOptionalProps = DAL.SoftDeletableModelDateColumns export const ShippingOption = model
.define("shipping_option", {
const DeletedAtIndex = createPsqlIndexStatementHelper({ id: model.id({ prefix: "so" }).primaryKey(),
tableName: "shipping_option", name: model.text(),
columns: "deleted_at", price_type: model
where: "deleted_at IS NOT NULL", .enum(ShippingOptionPriceType)
}) .default(ShippingOptionPriceType.FLAT),
data: model.json().nullable(),
const ServiceZoneIdIndex = createPsqlIndexStatementHelper({ metadata: model.json().nullable(),
tableName: "shipping_option", service_zone: model.belongsTo(() => ServiceZone, {
columns: "service_zone_id", mappedBy: "shipping_options",
where: "deleted_at IS NULL", }),
}) shipping_profile: model
.belongsTo(() => ShippingProfile, {
const ShippingProfileIdIndex = createPsqlIndexStatementHelper({ mappedBy: "shipping_options",
tableName: "shipping_option", })
columns: "shipping_profile_id", .nullable(),
where: "deleted_at IS NULL", provider: model.belongsTo(() => FulfillmentProvider).nullable(),
}) type: model.hasOne(() => ShippingOptionType, {
foreignKey: true,
const FulfillmentProviderIdIndex = createPsqlIndexStatementHelper({ foreignKeyName: "shipping_option_type_id",
tableName: "shipping_option", mappedBy: undefined,
columns: "provider_id", }),
where: "deleted_at IS NULL", rules: model.hasMany(() => ShippingOptionRule, {
}) mappedBy: "shipping_option",
}),
const ShippingOptionTypeIdIndex = createPsqlIndexStatementHelper({ fulfillments: model.hasMany(() => Fulfillment, {
tableName: "shipping_option", mappedBy: "shipping_option",
columns: "shipping_option_type_id", }),
where: "deleted_at IS NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class ShippingOption {
[OptionalProps]?: ShippingOptionOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Searchable()
@Property({ columnType: "text" })
name: string
@Enum({
items: () => ShippingOptionPriceType,
default: ShippingOptionPriceType.FLAT,
}) })
price_type: ShippingOptionPriceType .cascades({
delete: ["rules", "type"],
@ManyToOne(() => ServiceZone, {
type: "text",
fieldName: "service_zone_id",
mapToPk: true,
onDelete: "cascade",
}) })
@ServiceZoneIdIndex.MikroORMIndex()
service_zone_id: string
@ManyToOne(() => ShippingProfile, {
type: "text",
fieldName: "shipping_profile_id",
mapToPk: true,
nullable: true,
onDelete: "set null",
})
@ShippingProfileIdIndex.MikroORMIndex()
shipping_profile_id: string | null
@ManyToOne(() => FulfillmentProvider, {
type: "text",
fieldName: "provider_id",
mapToPk: true,
nullable: true,
})
@FulfillmentProviderIdIndex.MikroORMIndex()
provider_id: string
@Property({ columnType: "text", persist: false })
@ShippingOptionTypeIdIndex.MikroORMIndex()
shipping_option_type_id: string | null = null
@Property({ columnType: "jsonb", nullable: true })
data: Record<string, unknown> | null = null
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@ManyToOne(() => ServiceZone, { persist: false })
service_zone: Rel<ServiceZone>
@ManyToOne(() => ShippingProfile, {
persist: false,
})
shipping_profile: Rel<ShippingProfile> | null
@ManyToOne(() => FulfillmentProvider, {
persist: false,
})
provider: Rel<FulfillmentProvider> | null
@OneToOne(() => ShippingOptionType, (so) => so.shipping_option, {
owner: true,
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
fieldName: "shipping_option_type_id",
onDelete: "cascade",
})
type: Rel<ShippingOptionType>
@OneToMany(() => ShippingOptionRule, "shipping_option", {
cascade: [Cascade.PERSIST, "soft-remove"] as any,
orphanRemoval: true,
})
rules = new Collection<Rel<ShippingOptionRule>>(this)
@OneToMany(() => Fulfillment, (fulfillment) => fulfillment.shipping_option)
fulfillments = new Collection<Rel<Fulfillment>>(this)
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@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
}
}
@@ -1,92 +1,21 @@
import { import { model } from "@medusajs/framework/utils"
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
Searchable,
} from "@medusajs/framework/utils"
import { DAL } from "@medusajs/framework/types" import { ShippingOption } from "./shipping-option"
import {
BeforeCreate,
Collection,
Entity,
Filter,
OneToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Rel,
} from "@mikro-orm/core"
import ShippingOption from "./shipping-option"
type ShippingProfileOptionalProps = DAL.SoftDeletableModelDateColumns export const ShippingProfile = model
.define("shipping_profile", {
const DeletedAtIndex = createPsqlIndexStatementHelper({ id: model.id({ prefix: "sp" }).primaryKey(),
tableName: "shipping_profile", name: model.text(),
columns: "deleted_at", type: model.text(),
where: "deleted_at IS NOT NULL", shipping_options: model.hasMany(() => ShippingOption, {
}) mappedBy: "shipping_profile",
}),
const ShippingProfileTypeIndex = createPsqlIndexStatementHelper({ metadata: model.json().nullable(),
tableName: "shipping_profile",
columns: "name",
unique: true,
where: "deleted_at IS NULL",
})
@Entity()
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
export default class ShippingProfile {
[OptionalProps]?: ShippingProfileOptionalProps
@PrimaryKey({ columnType: "text" })
id: string
@Searchable()
@Property({ columnType: "text" })
@ShippingProfileTypeIndex.MikroORMIndex()
name: string
@Searchable()
@Property({ columnType: "text" })
type: string
@OneToMany(
() => ShippingOption,
(shippingOption) => shippingOption.shipping_profile
)
shipping_options = new Collection<Rel<ShippingOption>>(this)
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
}) })
created_at: Date .indexes([
{
@Property({ on: ["name"],
onCreate: () => new Date(), unique: true,
onUpdate: () => new Date(), where: "deleted_at IS NULL",
columnType: "timestamptz", },
defaultRaw: "now()", ])
})
updated_at: Date
@DeletedAtIndex.MikroORMIndex()
@Property({ columnType: "timestamptz", nullable: true })
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "sp")
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "sp")
}
}
@@ -1,59 +0,0 @@
/*
import { Context, FulfillmentTypes } from "@medusajs/framework/types"
import { DALUtils, promiseAll } from "@medusajs/framework/utils"
import { FulfillmentSet, ServiceZone } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
interface CreateFulfillmentSetDTO
extends FulfillmentTypes.CreateFulfillmentSetDTO {
service_zones: { id: string; name: string }[]
}
export class FulfillmentSetRepository extends DALUtils.mikroOrmBaseRepositoryFactory<FulfillmentSet>(
FulfillmentSet
) {
async update(
data: {
entity: FulfillmentSet
update: FulfillmentTypes.FulfillmentSetDTO
}[],
context?: Context
): Promise<FulfillmentSet[]> {
const manager = this.getActiveManager<SqlEntityManager>(context)
// init all service zones collections
await promiseAll(
data.map(async ({ entity }) => {
return await entity.service_zones.init()
})
)
const flfillmentSetsToUpdate = data.map(({ entity, update }) => {
const { service_zones, ...restToUpdate } = update
const currentServiceZones = entity.service_zones.getItems()
const serviceZonesToDetach = currentServiceZones.filter(
(serviceZone) =>
!update.service_zones.find(
(newServiceZone) => newServiceZone.id === serviceZone.id
)
)
const serviceZonesToAttach = update.service_zones.filter(
(newServiceZone) =>
!currentServiceZones.find(
(serviceZone) => serviceZone.id === newServiceZone.id
)
)
entity.service_zones.remove(serviceZonesToDetach)
entity.service_zones.add(serviceZonesToAttach as unknown as ServiceZone[])
return manager.assign(entity, restToUpdate)
})
manager.persist(flfillmentSetsToUpdate)
return flfillmentSetsToUpdate
}
}
*/
@@ -1 +0,0 @@
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/framework/utils"
@@ -8,6 +8,7 @@ import {
FulfillmentOption, FulfillmentOption,
FulfillmentTypes, FulfillmentTypes,
IFulfillmentModuleService, IFulfillmentModuleService,
InferEntityType,
InternalModuleDeclaration, InternalModuleDeclaration,
Logger, Logger,
ModuleJoinerConfig, ModuleJoinerConfig,
@@ -19,6 +20,7 @@ import {
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { import {
arrayDifference, arrayDifference,
deepCopy,
deepEqualObj, deepEqualObj,
EmitEvents, EmitEvents,
getSetDifference, getSetDifference,
@@ -49,6 +51,7 @@ import {
buildCreatedServiceZoneEvents, buildCreatedServiceZoneEvents,
eventBuilders, eventBuilders,
isContextValid, isContextValid,
Rule,
validateAndNormalizeRules, validateAndNormalizeRules,
} from "@utils" } from "@utils"
import { joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
@@ -70,6 +73,7 @@ const generateMethodForModels = {
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
fulfillmentAddressService: ModulesSdkTypes.IMedusaInternalService<any>
fulfillmentSetService: ModulesSdkTypes.IMedusaInternalService<any> fulfillmentSetService: ModulesSdkTypes.IMedusaInternalService<any>
serviceZoneService: ModulesSdkTypes.IMedusaInternalService<any> serviceZoneService: ModulesSdkTypes.IMedusaInternalService<any>
geoZoneService: ModulesSdkTypes.IMedusaInternalService<any> geoZoneService: ModulesSdkTypes.IMedusaInternalService<any>
@@ -96,15 +100,31 @@ export default class FulfillmentModuleService
implements IFulfillmentModuleService implements IFulfillmentModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
protected readonly fulfillmentSetService_: ModulesSdkTypes.IMedusaInternalService<FulfillmentSet> protected readonly fulfillmentSetService_: ModulesSdkTypes.IMedusaInternalService<
protected readonly serviceZoneService_: ModulesSdkTypes.IMedusaInternalService<ServiceZone> InferEntityType<typeof FulfillmentSet>
protected readonly geoZoneService_: ModulesSdkTypes.IMedusaInternalService<GeoZone> >
protected readonly shippingProfileService_: ModulesSdkTypes.IMedusaInternalService<ShippingProfile> protected readonly serviceZoneService_: ModulesSdkTypes.IMedusaInternalService<
protected readonly shippingOptionService_: ModulesSdkTypes.IMedusaInternalService<ShippingOption> InferEntityType<typeof ServiceZone>
protected readonly shippingOptionRuleService_: ModulesSdkTypes.IMedusaInternalService<ShippingOptionRule> >
protected readonly shippingOptionTypeService_: ModulesSdkTypes.IMedusaInternalService<ShippingOptionType> protected readonly geoZoneService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof GeoZone>
>
protected readonly shippingProfileService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof ShippingProfile>
>
protected readonly shippingOptionService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof ShippingOption>
>
protected readonly shippingOptionRuleService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof ShippingOptionRule>
>
protected readonly shippingOptionTypeService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof ShippingOptionType>
>
protected readonly fulfillmentProviderService_: FulfillmentProviderService protected readonly fulfillmentProviderService_: FulfillmentProviderService
protected readonly fulfillmentService_: ModulesSdkTypes.IMedusaInternalService<Fulfillment> protected readonly fulfillmentService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof Fulfillment>
>
constructor( constructor(
{ {
@@ -118,6 +138,7 @@ export default class FulfillmentModuleService
shippingOptionTypeService, shippingOptionTypeService,
fulfillmentProviderService, fulfillmentProviderService,
fulfillmentService, fulfillmentService,
fulfillmentAddressService,
}: InjectedDependencies, }: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration protected readonly moduleDeclaration: InternalModuleDeclaration
) { ) {
@@ -188,7 +209,7 @@ export default class FulfillmentModuleService
return isContextValid( return isContextValid(
context, context,
shippingOption.rules.map((r) => r) shippingOption.rules.map((r) => r) as unknown as Rule[]
) )
}) })
} }
@@ -292,7 +313,7 @@ export default class FulfillmentModuleService
| FulfillmentTypes.CreateFulfillmentSetDTO | FulfillmentTypes.CreateFulfillmentSetDTO
| FulfillmentTypes.CreateFulfillmentSetDTO[], | FulfillmentTypes.CreateFulfillmentSetDTO[],
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<FulfillmentSet[]> { ): Promise<InferEntityType<typeof FulfillmentSet>[]> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -358,7 +379,7 @@ export default class FulfillmentModuleService
| FulfillmentTypes.CreateServiceZoneDTO[] | FulfillmentTypes.CreateServiceZoneDTO[]
| FulfillmentTypes.CreateServiceZoneDTO, | FulfillmentTypes.CreateServiceZoneDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ServiceZone[]> { ): Promise<InferEntityType<typeof ServiceZone>[]> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -422,7 +443,7 @@ export default class FulfillmentModuleService
| FulfillmentTypes.CreateShippingOptionDTO[] | FulfillmentTypes.CreateShippingOptionDTO[]
| FulfillmentTypes.CreateShippingOptionDTO, | FulfillmentTypes.CreateShippingOptionDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ShippingOption[]> { ): Promise<InferEntityType<typeof ShippingOption>[]> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -491,7 +512,7 @@ export default class FulfillmentModuleService
| FulfillmentTypes.CreateShippingProfileDTO[] | FulfillmentTypes.CreateShippingProfileDTO[]
| FulfillmentTypes.CreateShippingProfileDTO, | FulfillmentTypes.CreateShippingProfileDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ShippingProfile[]> { ): Promise<InferEntityType<typeof ShippingProfile>[]> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -580,7 +601,7 @@ export default class FulfillmentModuleService
| FulfillmentTypes.CreateShippingOptionRuleDTO[] | FulfillmentTypes.CreateShippingOptionRuleDTO[]
| FulfillmentTypes.CreateShippingOptionRuleDTO, | FulfillmentTypes.CreateShippingOptionRuleDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ShippingOptionRule[]> { ): Promise<InferEntityType<typeof ShippingOptionRule>[]> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -625,7 +646,7 @@ export default class FulfillmentModuleService
try { try {
const providerResult = const providerResult =
await this.fulfillmentProviderService_.createFulfillment( await this.fulfillmentProviderService_.createFulfillment(
provider_id, provider_id!, // TODO: should we add a runtime check on provider_id being provided?
fulfillmentData || {}, fulfillmentData || {},
items.map((i) => i), items.map((i) => i),
order, order,
@@ -692,7 +713,7 @@ export default class FulfillmentModuleService
try { try {
const providerResult = const providerResult =
await this.fulfillmentProviderService_.createReturn( await this.fulfillmentProviderService_.createReturn(
fulfillment.provider_id, fulfillment.provider_id!, // TODO: should we add a runtime check on provider_id being provided?,
fulfillment as Record<any, any> fulfillment as Record<any, any>
) )
await this.fulfillmentService_.update( await this.fulfillmentService_.update(
@@ -750,7 +771,10 @@ export default class FulfillmentModuleService
protected async updateFulfillmentSets_( protected async updateFulfillmentSets_(
data: UpdateFulfillmentSetDTO[] | UpdateFulfillmentSetDTO, data: UpdateFulfillmentSetDTO[] | UpdateFulfillmentSetDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<FulfillmentSet[] | FulfillmentSet> { ): Promise<
| InferEntityType<typeof FulfillmentSet>[]
| InferEntityType<typeof FulfillmentSet>
> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -789,9 +813,10 @@ export default class FulfillmentModuleService
) )
} }
const fulfillmentSetMap = new Map<string, FulfillmentSet>( const fulfillmentSetMap = new Map<
fulfillmentSets.map((f) => [f.id, f]) string,
) InferEntityType<typeof FulfillmentSet>
>(fulfillmentSets.map((f) => [f.id, f]))
const serviceZoneIdsToDelete: string[] = [] const serviceZoneIdsToDelete: string[] = []
const geoZoneIdsToDelete: string[] = [] const geoZoneIdsToDelete: string[] = []
@@ -1013,7 +1038,9 @@ export default class FulfillmentModuleService
| FulfillmentTypes.UpdateServiceZoneDTO[] | FulfillmentTypes.UpdateServiceZoneDTO[]
| FulfillmentTypes.UpdateServiceZoneDTO, | FulfillmentTypes.UpdateServiceZoneDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ServiceZone | ServiceZone[]> { ): Promise<
InferEntityType<typeof ServiceZone> | InferEntityType<typeof ServiceZone>[]
> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -1052,7 +1079,7 @@ export default class FulfillmentModuleService
) )
} }
const serviceZoneMap = new Map<string, ServiceZone>( const serviceZoneMap = new Map<string, InferEntityType<typeof ServiceZone>>(
serviceZones.map((s) => [s.id, s]) serviceZones.map((s) => [s.id, s])
) )
@@ -1209,7 +1236,9 @@ export default class FulfillmentModuleService
| FulfillmentTypes.UpsertServiceZoneDTO[] | FulfillmentTypes.UpsertServiceZoneDTO[]
| FulfillmentTypes.UpsertServiceZoneDTO, | FulfillmentTypes.UpsertServiceZoneDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ServiceZone[] | ServiceZone> { ): Promise<
InferEntityType<typeof ServiceZone>[] | InferEntityType<typeof ServiceZone>
> {
const input = Array.isArray(data) ? data : [data] const input = Array.isArray(data) ? data : [data]
const forUpdate = input.filter( const forUpdate = input.filter(
(serviceZone): serviceZone is FulfillmentTypes.UpdateServiceZoneDTO => (serviceZone): serviceZone is FulfillmentTypes.UpdateServiceZoneDTO =>
@@ -1220,8 +1249,8 @@ export default class FulfillmentModuleService
!serviceZone.id !serviceZone.id
) )
const created: ServiceZone[] = [] const created: InferEntityType<typeof ServiceZone>[] = []
const updated: ServiceZone[] = [] const updated: InferEntityType<typeof ServiceZone>[] = []
if (forCreate.length) { if (forCreate.length) {
const createdServiceZones = await this.createServiceZones_( const createdServiceZones = await this.createServiceZones_(
@@ -1304,8 +1333,13 @@ export default class FulfillmentModuleService
async updateShippingOptions_( async updateShippingOptions_(
data: UpdateShippingOptionsInput[] | UpdateShippingOptionsInput, data: UpdateShippingOptionsInput[] | UpdateShippingOptionsInput,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ShippingOption | ShippingOption[]> { ): Promise<
const dataArray = Array.isArray(data) ? data : [data] | InferEntityType<typeof ShippingOption>
| InferEntityType<typeof ShippingOption>[]
> {
const dataArray = Array.isArray(data)
? data.map((d) => deepCopy(d))
: [deepCopy(data)]
if (!dataArray.length) { if (!dataArray.length) {
return [] return []
@@ -1365,7 +1399,8 @@ export default class FulfillmentModuleService
const existingRulesMap: Map< const existingRulesMap: Map<
string, string,
FulfillmentTypes.UpdateShippingOptionRuleDTO | ShippingOptionRule | FulfillmentTypes.UpdateShippingOptionRuleDTO
| InferEntityType<typeof ShippingOptionRule>
> = new Map(existingRules.map((rule) => [rule.id, rule])) > = new Map(existingRules.map((rule) => [rule.id, rule]))
const updatedRules = shippingOption.rules const updatedRules = shippingOption.rules
@@ -1378,6 +1413,13 @@ export default class FulfillmentModuleService
updatedRuleIds.push(rule.id) updatedRuleIds.push(rule.id)
} }
// @ts-ignore
delete rule.created_at
// @ts-ignore
delete rule.updated_at
// @ts-ignore
delete rule.deleted_at
const ruleData: FulfillmentTypes.UpdateShippingOptionRuleDTO = { const ruleData: FulfillmentTypes.UpdateShippingOptionRuleDTO = {
...existingRule, ...existingRule,
...rule, ...rule,
@@ -1530,7 +1572,7 @@ export default class FulfillmentModuleService
| FulfillmentTypes.UpsertShippingOptionDTO[] | FulfillmentTypes.UpsertShippingOptionDTO[]
| FulfillmentTypes.UpsertShippingOptionDTO, | FulfillmentTypes.UpsertShippingOptionDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ShippingOption[] | ShippingOption> { ): Promise<InferEntityType<typeof ShippingOption>[]> {
const input = Array.isArray(data) ? data : [data] const input = Array.isArray(data) ? data : [data]
const forUpdate = input.filter( const forUpdate = input.filter(
(shippingOption): shippingOption is UpdateShippingOptionsInput => (shippingOption): shippingOption is UpdateShippingOptionsInput =>
@@ -1543,8 +1585,8 @@ export default class FulfillmentModuleService
!shippingOption.id !shippingOption.id
) )
let created: ShippingOption[] = [] let created: InferEntityType<typeof ShippingOption>[] = []
let updated: ShippingOption[] = [] let updated: InferEntityType<typeof ShippingOption>[] = []
if (forCreate.length) { if (forCreate.length) {
const createdShippingOptions = await this.createShippingOptions_( const createdShippingOptions = await this.createShippingOptions_(
@@ -1649,8 +1691,8 @@ export default class FulfillmentModuleService
(prof): prof is FulfillmentTypes.CreateShippingProfileDTO => !prof.id (prof): prof is FulfillmentTypes.CreateShippingProfileDTO => !prof.id
) )
let created: ShippingProfile[] = [] let created: InferEntityType<typeof ShippingProfile>[] = []
let updated: ShippingProfile[] = [] let updated: InferEntityType<typeof ShippingProfile>[] = []
if (forCreate.length) { if (forCreate.length) {
created = await this.shippingProfileService_.create( created = await this.shippingProfileService_.create(
@@ -1755,7 +1797,10 @@ export default class FulfillmentModuleService
| FulfillmentTypes.UpdateShippingOptionRuleDTO[] | FulfillmentTypes.UpdateShippingOptionRuleDTO[]
| FulfillmentTypes.UpdateShippingOptionRuleDTO, | FulfillmentTypes.UpdateShippingOptionRuleDTO,
@MedusaContext() sharedContext: Context = {} @MedusaContext() sharedContext: Context = {}
): Promise<ShippingOptionRule | ShippingOptionRule[]> { ): Promise<
| InferEntityType<typeof ShippingOptionRule>
| InferEntityType<typeof ShippingOptionRule>[]
> {
const data_ = Array.isArray(data) ? data : [data] const data_ = Array.isArray(data) ? data : [data]
if (!data_.length) { if (!data_.length) {
@@ -1796,8 +1841,8 @@ export default class FulfillmentModuleService
id: string, id: string,
data: FulfillmentTypes.UpdateFulfillmentDTO, data: FulfillmentTypes.UpdateFulfillmentDTO,
@MedusaContext() sharedContext: Context @MedusaContext() sharedContext: Context
): Promise<Fulfillment> { ): Promise<InferEntityType<typeof Fulfillment>> {
const existingFulfillment: Fulfillment = const existingFulfillment: InferEntityType<typeof Fulfillment> =
await this.fulfillmentService_.retrieve( await this.fulfillmentService_.retrieve(
id, id,
{ {
@@ -1868,7 +1913,7 @@ export default class FulfillmentModuleService
} }
private handleFulfillmentUpdateEvents( private handleFulfillmentUpdateEvents(
fulfillment: Fulfillment, fulfillment: InferEntityType<typeof Fulfillment>,
existingLabelIds: string[], existingLabelIds: string[],
updatedLabelIds: string[], updatedLabelIds: string[],
deletedLabelIds: string[], deletedLabelIds: string[],
@@ -1919,7 +1964,7 @@ export default class FulfillmentModuleService
if (!fulfillment.canceled_at) { if (!fulfillment.canceled_at) {
try { try {
await this.fulfillmentProviderService_.cancelFulfillment( await this.fulfillmentProviderService_.cancelFulfillment(
fulfillment.provider_id, fulfillment.provider_id!, // TODO: should we add a runtime check on provider_id being provided?,
fulfillment.data ?? {} fulfillment.data ?? {}
) )
} catch (error) { } catch (error) {
@@ -2094,7 +2139,9 @@ export default class FulfillmentModuleService
} }
} }
protected static canCancelFulfillmentOrThrow(fulfillment: Fulfillment) { protected static canCancelFulfillmentOrThrow(
fulfillment: InferEntityType<typeof Fulfillment>
) {
if (fulfillment.shipped_at) { if (fulfillment.shipped_at) {
throw new MedusaError( throw new MedusaError(
MedusaError.Types.INVALID_DATA, MedusaError.Types.INVALID_DATA,
@@ -2113,7 +2160,7 @@ export default class FulfillmentModuleService
} }
protected static validateMissingShippingOptions_( protected static validateMissingShippingOptions_(
shippingOptions: ShippingOption[], shippingOptions: InferEntityType<typeof ShippingOption>[],
shippingOptionsData: UpdateShippingOptionsInput[] shippingOptionsData: UpdateShippingOptionsInput[]
) { ) {
const missingShippingOptionIds = arrayDifference( const missingShippingOptionIds = arrayDifference(
@@ -2132,7 +2179,7 @@ export default class FulfillmentModuleService
} }
protected static validateMissingShippingOptionRules( protected static validateMissingShippingOptionRules(
shippingOption: ShippingOption, shippingOption: InferEntityType<typeof ShippingOption>,
shippingOptionUpdateData: FulfillmentTypes.UpdateShippingOptionDTO shippingOptionUpdateData: FulfillmentTypes.UpdateShippingOptionDTO
) { ) {
if (!shippingOptionUpdateData.rules) { if (!shippingOptionUpdateData.rules) {
@@ -7,7 +7,7 @@ import {
ShippingOptionRule, ShippingOptionRule,
ShippingOptionType, ShippingOptionType,
} from "@models" } from "@models"
import { Context } from "@medusajs/framework/types" import { Context, InferEntityType } from "@medusajs/framework/types"
import { import {
CommonEvents, CommonEvents,
FulfillmentEvents, FulfillmentEvents,
@@ -172,7 +172,7 @@ export function buildCreatedFulfillmentEvents({
fulfillments, fulfillments,
sharedContext, sharedContext,
}: { }: {
fulfillments: Fulfillment[] fulfillments: InferEntityType<typeof Fulfillment>[]
sharedContext: Context sharedContext: Context
}) { }) {
if (!fulfillments.length) { if (!fulfillments.length) {
@@ -210,7 +210,7 @@ export function buildCreatedShippingOptionEvents({
shippingOptions, shippingOptions,
sharedContext, sharedContext,
}: { }: {
shippingOptions: ShippingOption[] shippingOptions: InferEntityType<typeof ShippingOption>[]
sharedContext: Context sharedContext: Context
}) { }) {
if (!shippingOptions.length) { if (!shippingOptions.length) {
@@ -218,8 +218,8 @@ export function buildCreatedShippingOptionEvents({
} }
const options: { id: string }[] = [] const options: { id: string }[] = []
const types: ShippingOptionType[] = [] const types: InferEntityType<typeof ShippingOptionType>[] = []
const rules: ShippingOptionRule[] = [] const rules: InferEntityType<typeof ShippingOptionRule>[] = []
shippingOptions.forEach((shippingOption) => { shippingOptions.forEach((shippingOption) => {
options.push({ id: shippingOption.id }) options.push({ id: shippingOption.id })
@@ -242,14 +242,14 @@ export function buildCreatedFulfillmentSetEvents({
fulfillmentSets, fulfillmentSets,
sharedContext, sharedContext,
}: { }: {
fulfillmentSets: FulfillmentSet[] fulfillmentSets: InferEntityType<typeof FulfillmentSet>[]
sharedContext: Context sharedContext: Context
}): void { }): void {
if (!fulfillmentSets.length) { if (!fulfillmentSets.length) {
return return
} }
const serviceZones: ServiceZone[] = [] const serviceZones: InferEntityType<typeof ServiceZone>[] = []
fulfillmentSets.forEach((fulfillmentSet) => { fulfillmentSets.forEach((fulfillmentSet) => {
if (!fulfillmentSet.service_zones?.length) { if (!fulfillmentSet.service_zones?.length) {
@@ -268,14 +268,14 @@ export function buildCreatedServiceZoneEvents({
serviceZones, serviceZones,
sharedContext, sharedContext,
}: { }: {
serviceZones: ServiceZone[] serviceZones: InferEntityType<typeof ServiceZone>[]
sharedContext: Context sharedContext: Context
}): void { }): void {
if (!serviceZones.length) { if (!serviceZones.length) {
return return
} }
const geoZones: GeoZone[] = [] const geoZones: InferEntityType<typeof GeoZone>[] = []
serviceZones.forEach((serviceZone) => { serviceZones.forEach((serviceZone) => {
if (!serviceZone.geo_zones.length) { if (!serviceZone.geo_zones.length) {
@@ -16,7 +16,7 @@ import {
export type Rule = { export type Rule = {
attribute: string attribute: string
operator: Lowercase<keyof typeof RuleOperator> operator: Lowercase<keyof typeof RuleOperator> | (string & {})
value: string | string[] | null value: string | string[] | null
} }
@@ -23,11 +23,13 @@ moduleIntegrationTestRunner<IPaymentModuleService>({
service: PaymentModuleService, service: PaymentModuleService,
}).linkable }).linkable
expect(Object.keys(linkable)).toHaveLength(5)
expect(Object.keys(linkable)).toEqual([ expect(Object.keys(linkable)).toEqual([
"paymentCollection", "paymentCollection",
"paymentSession", "paymentSession",
"payment", "payment",
"refundReason", "refundReason",
"paymentProvider",
]) ])
Object.keys(linkable).forEach((key) => { Object.keys(linkable).forEach((key) => {
@@ -71,6 +73,15 @@ moduleIntegrationTestRunner<IPaymentModuleService>({
field: "refundReason", field: "refundReason",
}, },
}, },
paymentProvider: {
id: {
linkable: "payment_provider_id",
entity: "PaymentProvider",
primaryKey: "id",
serviceName: "payment",
field: "paymentProvider",
},
},
}) })
}) })
@@ -854,6 +854,7 @@ moduleIntegrationTestRunner({
code: "PROMOTION_1", code: "PROMOTION_1",
application_method: { application_method: {
id: expect.any(String), id: expect.any(String),
promotion_id: expect.any(String),
type: "fixed", type: "fixed",
}, },
}, },