Feat(fulfillment): service provider registration + fulfillment management (#6524)
**What** - Create the fulfillment manual package with a first iteration API - Create a new `AbstractFulfillmentProviderService` and `IFulfillmentProvider` - Modify the module service interface to add new methods to manipulate the fulfillment and the communication with the external provider - create (no bulk) - cancel (no bulk) - update (no bulk) - list - listAndCount - retrieve - Add new methods to the service provider service to include communication with the third party provider - get options - create - cancel - validate data - validate option - Update/create interfaces and DTO's - fix repository serializer to allow non entity to be passed without throwing - split module tests into multiple files to simplify navigation - Add integration tests to validate fulfillments manipulation and external provider loading + communication FIXES CORE-1729 FIXES CORE-1785 FIXES CORE-1784 FIXES CORE-1766
This commit is contained in:
@@ -14,12 +14,6 @@ import {
|
||||
|
||||
type OptionalAddressProps = DAL.SoftDeletableEntityDateColumns
|
||||
|
||||
const FulfillmentIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "fulfillment_address",
|
||||
columns: "fulfillment_id",
|
||||
where: "deleted_at IS NULL",
|
||||
})
|
||||
|
||||
const FulfillmentDeletedAtIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "fulfillment_address",
|
||||
columns: "deleted_at",
|
||||
@@ -33,10 +27,6 @@ export default class Address {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@FulfillmentIdIndex.MikroORMIndex()
|
||||
fulfillment_id: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
company: string | null = null
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import {
|
||||
BigNumber,
|
||||
createPsqlIndexStatementHelper,
|
||||
DALUtils,
|
||||
generateEntityId,
|
||||
MikroOrmBigNumberProperty,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
import { DAL } from "@medusajs/types"
|
||||
import { BigNumberRawValue, DAL } from "@medusajs/types"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
@@ -60,8 +62,11 @@ export default class FulfillmentItem {
|
||||
@Property({ columnType: "text" })
|
||||
barcode: string
|
||||
|
||||
@Property({ columnType: "numeric", serializer: Number })
|
||||
quantity: number // TODO: probably allow big numbers here
|
||||
@MikroOrmBigNumberProperty()
|
||||
quantity: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_quantity: BigNumberRawValue
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@LineItemIdIndex.MikroORMIndex()
|
||||
@@ -71,11 +76,16 @@ export default class FulfillmentItem {
|
||||
@InventoryItemIdIndex.MikroORMIndex()
|
||||
inventory_item_id: string | null = null
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
@ManyToOne(() => Fulfillment, {
|
||||
columnType: "text",
|
||||
mapToPk: true,
|
||||
fieldName: "fulfillment_id",
|
||||
onDelete: "cascade",
|
||||
})
|
||||
@FulfillmentIdIndex.MikroORMIndex()
|
||||
fulfillment_id: string
|
||||
|
||||
@ManyToOne(() => Fulfillment)
|
||||
@ManyToOne(() => Fulfillment, { persist: false })
|
||||
fulfillment: Fulfillment
|
||||
|
||||
@Property({
|
||||
@@ -100,10 +110,12 @@ export default class FulfillmentItem {
|
||||
@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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +48,16 @@ export default class FulfillmentLabel {
|
||||
@Property({ columnType: "text" })
|
||||
label_url: string
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
@ManyToOne(() => Fulfillment, {
|
||||
columnType: "text",
|
||||
mapToPk: true,
|
||||
fieldName: "fulfillment_id",
|
||||
onDelete: "cascade",
|
||||
})
|
||||
@FulfillmentIdIndex.MikroORMIndex()
|
||||
fulfillment_id: string
|
||||
|
||||
@ManyToOne(() => Fulfillment)
|
||||
@ManyToOne(() => Fulfillment, { persist: false })
|
||||
fulfillment: Fulfillment
|
||||
|
||||
@Property({
|
||||
@@ -77,10 +82,12 @@ export default class FulfillmentLabel {
|
||||
@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
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -18,18 +18,18 @@ import {
|
||||
} from "@mikro-orm/core"
|
||||
import ShippingOption from "./shipping-option"
|
||||
|
||||
type ServiceProviderOptionalProps = DAL.SoftDeletableEntityDateColumns
|
||||
type FulfillmentProviderOptionalProps = DAL.SoftDeletableEntityDateColumns
|
||||
|
||||
const DeletedAtIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "service_provider",
|
||||
tableName: "fulfillment_provider",
|
||||
columns: "deleted_at",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
@Entity()
|
||||
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
|
||||
export default class ServiceProvider {
|
||||
[OptionalProps]?: ServiceProviderOptionalProps
|
||||
export default class FulfillmentProvider {
|
||||
[OptionalProps]?: FulfillmentProviderOptionalProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
@@ -39,7 +39,7 @@ export default class ServiceProvider {
|
||||
|
||||
@OneToMany(
|
||||
() => ShippingOption,
|
||||
(shippingOption) => shippingOption.service_provider
|
||||
(shippingOption) => shippingOption.fulfillment_provider
|
||||
)
|
||||
shipping_options = new Collection<ShippingOption>(this)
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Filter,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
OnInit,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
@@ -20,7 +21,7 @@ import {
|
||||
import Address from "./address"
|
||||
import FulfillmentItem from "./fulfillment-item"
|
||||
import FulfillmentLabel from "./fulfillment-label"
|
||||
import ServiceProvider from "./service-provider"
|
||||
import FulfillmentProvider from "./fulfillment-provider"
|
||||
import ShippingOption from "./shipping-option"
|
||||
|
||||
type FulfillmentOptionalProps = DAL.SoftDeletableEntityDateColumns
|
||||
@@ -88,28 +89,37 @@ export default class Fulfillment {
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
data: Record<string, unknown> | null = null
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
@ManyToOne(() => FulfillmentProvider, {
|
||||
columnType: "text",
|
||||
fieldName: "provider_id",
|
||||
mapToPk: true,
|
||||
})
|
||||
@FulfillmentProviderIdIndex.MikroORMIndex()
|
||||
provider_id: string
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@ManyToOne(() => ShippingOption, {
|
||||
columnType: "text",
|
||||
fieldName: "shipping_option_id",
|
||||
nullable: true,
|
||||
mapToPk: true,
|
||||
})
|
||||
@FulfillmentShippingOptionIdIndex.MikroORMIndex()
|
||||
shipping_option_id: string | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = null
|
||||
|
||||
@ManyToOne(() => ShippingOption, { nullable: true })
|
||||
@ManyToOne(() => ShippingOption, { persist: false })
|
||||
shipping_option: ShippingOption | null
|
||||
|
||||
@ManyToOne(() => ServiceProvider)
|
||||
provider: ServiceProvider
|
||||
@ManyToOne(() => FulfillmentProvider, { persist: false })
|
||||
provider: FulfillmentProvider
|
||||
|
||||
@ManyToOne(() => Address)
|
||||
delivery_address: Address
|
||||
@OneToOne()
|
||||
delivery_address!: Address
|
||||
|
||||
@ManyToOne(() => FulfillmentItem)
|
||||
items: FulfillmentItem
|
||||
@OneToMany(() => FulfillmentItem, (item) => item.fulfillment)
|
||||
items = new Collection<FulfillmentItem>(this)
|
||||
|
||||
@OneToMany(() => FulfillmentLabel, (label) => label.fulfillment)
|
||||
labels = new Collection<FulfillmentLabel>(this)
|
||||
@@ -136,10 +146,12 @@ export default class Fulfillment {
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ful")
|
||||
this.provider_id ??= this.provider.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ful")
|
||||
this.provider_id ??= this.provider.id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export { default as GeoZone } from "./geo-zone"
|
||||
export { default as ServiceZone } from "./service-zone"
|
||||
export { default as FulfillmentItem } from "./fulfillment-item"
|
||||
export { default as FulfillmentLabel } from "./fulfillment-label"
|
||||
export { default as ServiceProvider } from "./service-provider"
|
||||
export { default as FulfillmentProvider } from "./fulfillment-provider"
|
||||
export { default as ShippingOption } from "./shipping-option"
|
||||
export { default as ShippingOptionType } from "./shipping-option-type"
|
||||
export { default as ShippingOptionRule } from "./shipping-option-rule"
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import Fulfillment from "./fulfillment"
|
||||
import ServiceProvider from "./service-provider"
|
||||
import FulfillmentProvider from "./fulfillment-provider"
|
||||
import ServiceZone from "./service-zone"
|
||||
import ShippingOptionRule from "./shipping-option-rule"
|
||||
import ShippingOptionType from "./shipping-option-type"
|
||||
@@ -48,9 +48,9 @@ const ShippingProfileIdIndex = createPsqlIndexStatementHelper({
|
||||
where: "deleted_at IS NULL",
|
||||
})
|
||||
|
||||
const ServiceProviderIdIndex = createPsqlIndexStatementHelper({
|
||||
const FulfillmentProviderIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "shipping_option",
|
||||
columns: "service_provider_id",
|
||||
columns: "fulfillment_provider_id",
|
||||
where: "deleted_at IS NULL",
|
||||
})
|
||||
|
||||
@@ -94,14 +94,14 @@ export default class ShippingOption {
|
||||
@ShippingProfileIdIndex.MikroORMIndex()
|
||||
shipping_profile_id: string | null
|
||||
|
||||
@ManyToOne(() => ServiceProvider, {
|
||||
@ManyToOne(() => FulfillmentProvider, {
|
||||
type: "text",
|
||||
fieldName: "service_provider_id",
|
||||
fieldName: "fulfillment_provider_id",
|
||||
mapToPk: true,
|
||||
nullable: true,
|
||||
})
|
||||
@ServiceProviderIdIndex.MikroORMIndex()
|
||||
service_provider_id: string
|
||||
@FulfillmentProviderIdIndex.MikroORMIndex()
|
||||
fulfillment_provider_id: string
|
||||
|
||||
@Property({ columnType: "text", persist: false })
|
||||
@ShippingOptionTypeIdIndex.MikroORMIndex()
|
||||
@@ -121,10 +121,10 @@ export default class ShippingOption {
|
||||
})
|
||||
shipping_profile: ShippingProfile | null
|
||||
|
||||
@ManyToOne(() => ServiceProvider, {
|
||||
@ManyToOne(() => FulfillmentProvider, {
|
||||
persist: false,
|
||||
})
|
||||
service_provider: ServiceProvider | null
|
||||
fulfillment_provider: FulfillmentProvider | null
|
||||
|
||||
@OneToOne(() => ShippingOptionType, (so) => so.shipping_option, {
|
||||
owner: true,
|
||||
|
||||
Reference in New Issue
Block a user