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:
Adrien de Peretti
2024-03-05 11:11:14 +00:00
committed by GitHub
parent f9ef37a2f2
commit 62a7bcc30c
55 changed files with 4066 additions and 2749 deletions
+22 -3
View File
@@ -148,11 +148,30 @@ export const mikroOrmSerializer = async <TOutput extends object>(
options?: any
): Promise<TOutput> => {
options ??= {}
const data_ = Array.isArray(data) ? data : [data]
const forSerialization: unknown[] = []
const notForSerialization: unknown[] = []
data_.forEach((object) => {
if (object.__meta) {
return forSerialization.push(object)
}
return notForSerialization.push(object)
})
const { serialize } = await import("@mikro-orm/core")
const result = serialize(data, {
let result: any = serialize(forSerialization, {
forceObject: true,
populate: true,
...options,
})
return result as unknown as Promise<TOutput>
}) as TOutput[]
if (notForSerialization.length) {
result = result.concat(notForSerialization)
}
return Array.isArray(data) ? result : result[0]
}
+1
View File
@@ -1,2 +1,3 @@
export * from "./geo-zone"
export * from "./shipping-options"
export * from "./provider"
@@ -0,0 +1,65 @@
import { IFulfillmentProvider } from "@medusajs/types"
export class AbstractFulfillmentProviderService
implements IFulfillmentProvider
{
static identifier: string
static _isFulfillmentService = true
static isFulfillmentService(obj) {
return obj?.constructor?._isFulfillmentService
}
getIdentifier() {
return (this.constructor as any).identifier
}
async getFulfillmentOptions(): Promise<Record<string, unknown>[]> {
throw Error("getFulfillmentOptions must be overridden by the child class")
}
async validateFulfillmentData(optionData, data, context): Promise<any> {
throw Error("validateFulfillmentData must be overridden by the child class")
}
async validateOption(data): Promise<boolean> {
throw Error("validateOption must be overridden by the child class")
}
async canCalculate(data) {
throw Error("canCalculate must be overridden by the child class")
}
async calculatePrice(optionData, data, cart) {
throw Error("calculatePrice must be overridden by the child class")
}
async createFulfillment(data, items, order, fulfillment): Promise<any> {
throw Error("createFulfillment must be overridden by the child class")
}
async cancelFulfillment(fulfillment): Promise<any> {
throw Error("cancelFulfillment must be overridden by the child class")
}
async getFulfillmentDocuments(data) {
return []
}
async createReturnFulfillment(fromData): Promise<any> {
throw Error("createReturn must be overridden by the child class")
}
async getReturnDocuments(data) {
return []
}
async getShipmentDocuments(data) {
return []
}
async retrieveDocuments(fulfillmentData, documentType) {
throw Error("retrieveDocuments must be overridden by the child class")
}
}