feat(medusa,fulfillment): pass stock location data to fulfillment provider (#9322)
**What** - Fetches the stock location's details when creating a fulfillment and return fulfillment. - Passes the data to the fulfillment module, which in turn passes it to the fulfillment provider. **Why** - When creating a fulfillment in a multi-location setup the fulfillment provider will need to know where the package is being sent from (so the shipping service can pick it up). - Previously, we didn't pass anything but the location id to the fulfillment provider. Because the fulfillment provider can't have a dependency on the stock location module this was not sufficient. - This change ensures there is enough data passed to the fulfillment provider to build integrations properly.
This commit is contained in:
1 parent
d00afb76a6
commit
17b2868a50
6 files changed
+248
-16
No files matched your search
@@ -9,12 +9,13 @@ export function generateCreateFulfillmentData(
|
|||||||
provider_id: string
|
provider_id: string
|
||||||
shipping_option_id: string
|
shipping_option_id: string
|
||||||
order_id: string
|
order_id: string
|
||||||
|
location_id: string
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const randomString = Math.random().toString(36).substring(7)
|
const randomString = Math.random().toString(36).substring(7)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
location_id: "test-location",
|
location_id: data.location_id,
|
||||||
packed_at: null,
|
packed_at: null,
|
||||||
shipped_at: null,
|
shipped_at: null,
|
||||||
delivered_at: null,
|
delivered_at: null,
|
||||||
@@ -97,8 +98,10 @@ export async function setupFullDataFulfillmentStructure(
|
|||||||
service: IFulfillmentModuleService,
|
service: IFulfillmentModuleService,
|
||||||
{
|
{
|
||||||
providerId,
|
providerId,
|
||||||
|
locationId,
|
||||||
}: {
|
}: {
|
||||||
providerId: string
|
providerId: string
|
||||||
|
locationId: string
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const randomString = Math.random().toString(36).substring(7)
|
const randomString = Math.random().toString(36).substring(7)
|
||||||
@@ -133,6 +136,8 @@ export async function setupFullDataFulfillmentStructure(
|
|||||||
|
|
||||||
await service.createFulfillment(
|
await service.createFulfillment(
|
||||||
generateCreateFulfillmentData({
|
generateCreateFulfillmentData({
|
||||||
|
order_id: "fake-order",
|
||||||
|
location_id: locationId,
|
||||||
provider_id: providerId,
|
provider_id: providerId,
|
||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ import {
|
|||||||
updateFulfillmentWorkflow,
|
updateFulfillmentWorkflow,
|
||||||
updateFulfillmentWorkflowId,
|
updateFulfillmentWorkflowId,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
import { IFulfillmentModuleService } from "@medusajs/types"
|
import {
|
||||||
import { Modules } from "@medusajs/utils"
|
IFulfillmentModuleService,
|
||||||
|
MedusaContainer,
|
||||||
|
StockLocationDTO,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { ContainerRegistrationKeys, Modules } from "@medusajs/utils"
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
import {
|
import {
|
||||||
generateCreateFulfillmentData,
|
generateCreateFulfillmentData,
|
||||||
@@ -22,7 +26,8 @@ medusaIntegrationTestRunner({
|
|||||||
env: { MEDUSA_FF_MEDUSA_V2: true },
|
env: { MEDUSA_FF_MEDUSA_V2: true },
|
||||||
testSuite: ({ getContainer }) => {
|
testSuite: ({ getContainer }) => {
|
||||||
describe("Workflows: Fulfillment", () => {
|
describe("Workflows: Fulfillment", () => {
|
||||||
let appContainer
|
let location: StockLocationDTO
|
||||||
|
let appContainer: MedusaContainer
|
||||||
let service: IFulfillmentModuleService
|
let service: IFulfillmentModuleService
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@@ -30,7 +35,101 @@ medusaIntegrationTestRunner({
|
|||||||
service = appContainer.resolve(Modules.FULFILLMENT)
|
service = appContainer.resolve(Modules.FULFILLMENT)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const stockLocationService = appContainer.resolve(
|
||||||
|
Modules.STOCK_LOCATION
|
||||||
|
)
|
||||||
|
|
||||||
|
location = await stockLocationService.createStockLocations({
|
||||||
|
name: "Test Location",
|
||||||
|
address: {
|
||||||
|
address_1: "Test Address",
|
||||||
|
address_2: "tttest",
|
||||||
|
city: "Test City",
|
||||||
|
country_code: "us",
|
||||||
|
postal_code: "12345",
|
||||||
|
metadata: { email: "test@mail.com" },
|
||||||
|
},
|
||||||
|
metadata: { custom_location: "yes" },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("createFulfillmentWorkflow", () => {
|
describe("createFulfillmentWorkflow", () => {
|
||||||
|
describe("invoke", () => {
|
||||||
|
it("should get stock location", async () => {
|
||||||
|
const workflow = createFulfillmentWorkflow(appContainer)
|
||||||
|
|
||||||
|
const link = appContainer.resolve(
|
||||||
|
ContainerRegistrationKeys.REMOTE_LINK
|
||||||
|
)
|
||||||
|
|
||||||
|
const shippingProfile = await service.createShippingProfiles({
|
||||||
|
name: "test",
|
||||||
|
type: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillmentSet = await service.createFulfillmentSets({
|
||||||
|
name: "test",
|
||||||
|
type: "test-type",
|
||||||
|
})
|
||||||
|
|
||||||
|
await link.create({
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: location.id,
|
||||||
|
},
|
||||||
|
[Modules.FULFILLMENT]: {
|
||||||
|
fulfillment_set_id: fulfillmentSet.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const serviceZone = await service.createServiceZones({
|
||||||
|
name: "test",
|
||||||
|
fulfillment_set_id: fulfillmentSet.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingOption = await service.createShippingOptions(
|
||||||
|
generateCreateShippingOptionsData({
|
||||||
|
provider_id: providerId,
|
||||||
|
service_zone_id: serviceZone.id,
|
||||||
|
shipping_profile_id: shippingProfile.id,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const data = generateCreateFulfillmentData({
|
||||||
|
provider_id: providerId,
|
||||||
|
shipping_option_id: shippingOption.id,
|
||||||
|
order_id: "fake-order",
|
||||||
|
location_id: location.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { transaction } = await workflow.run({
|
||||||
|
input: data,
|
||||||
|
throwOnError: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
transaction.context.invoke["get-location"].output.output
|
||||||
|
).toEqual({
|
||||||
|
id: expect.any(String),
|
||||||
|
created_at: expect.any(Date),
|
||||||
|
updated_at: expect.any(Date),
|
||||||
|
name: "Test Location",
|
||||||
|
address: {
|
||||||
|
id: expect.any(String),
|
||||||
|
address_1: "Test Address",
|
||||||
|
address_2: "tttest",
|
||||||
|
city: "Test City",
|
||||||
|
country_code: "us",
|
||||||
|
postal_code: "12345",
|
||||||
|
metadata: { email: "test@mail.com" },
|
||||||
|
phone: null,
|
||||||
|
province: null,
|
||||||
|
},
|
||||||
|
metadata: { custom_location: "yes" },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("compensation", () => {
|
describe("compensation", () => {
|
||||||
it("should cancel created fulfillment if step following step throws error", async () => {
|
it("should cancel created fulfillment if step following step throws error", async () => {
|
||||||
const workflow = createFulfillmentWorkflow(appContainer)
|
const workflow = createFulfillmentWorkflow(appContainer)
|
||||||
@@ -70,6 +169,7 @@ medusaIntegrationTestRunner({
|
|||||||
provider_id: providerId,
|
provider_id: providerId,
|
||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
order_id: "fake-order",
|
order_id: "fake-order",
|
||||||
|
location_id: location.id,
|
||||||
})
|
})
|
||||||
const { errors } = await workflow.run({
|
const { errors } = await workflow.run({
|
||||||
input: data,
|
input: data,
|
||||||
@@ -130,11 +230,16 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const data = generateCreateFulfillmentData({
|
const data = generateCreateFulfillmentData({
|
||||||
|
order_id: "fake-order",
|
||||||
provider_id: providerId,
|
provider_id: providerId,
|
||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
|
location_id: location.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const fulfillment = await service.createFulfillment(data)
|
const fulfillment = await service.createFulfillment({
|
||||||
|
...data,
|
||||||
|
location,
|
||||||
|
})
|
||||||
|
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
const { errors } = await workflow.run({
|
const { errors } = await workflow.run({
|
||||||
@@ -142,7 +247,7 @@ medusaIntegrationTestRunner({
|
|||||||
id: fulfillment.id,
|
id: fulfillment.id,
|
||||||
shipped_at: date,
|
shipped_at: date,
|
||||||
packed_at: date,
|
packed_at: date,
|
||||||
location_id: "new location",
|
location_id: location.id,
|
||||||
},
|
},
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
})
|
})
|
||||||
@@ -209,12 +314,15 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const data = generateCreateFulfillmentData({
|
const data = generateCreateFulfillmentData({
|
||||||
|
order_id: "fake-order",
|
||||||
provider_id: providerId,
|
provider_id: providerId,
|
||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
|
location_id: location.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const fulfillment = await service.createFulfillment({
|
const fulfillment = await service.createFulfillment({
|
||||||
...data,
|
...data,
|
||||||
|
location,
|
||||||
labels: [],
|
labels: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IFulfillmentModuleService } from "@medusajs/types"
|
import { IFulfillmentModuleService, StockLocationDTO } from "@medusajs/types"
|
||||||
import { Modules } from "@medusajs/utils"
|
import { Modules } from "@medusajs/utils"
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
import { createAdminUser } from "../../../helpers/create-admin-user"
|
import { createAdminUser } from "../../../helpers/create-admin-user"
|
||||||
@@ -21,6 +21,7 @@ medusaIntegrationTestRunner({
|
|||||||
testSuite: ({ getContainer, api, dbConnection }) => {
|
testSuite: ({ getContainer, api, dbConnection }) => {
|
||||||
let service: IFulfillmentModuleService
|
let service: IFulfillmentModuleService
|
||||||
let container
|
let container
|
||||||
|
let location: StockLocationDTO
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
container = getContainer()
|
container = getContainer()
|
||||||
@@ -29,6 +30,20 @@ medusaIntegrationTestRunner({
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await createAdminUser(dbConnection, adminHeaders, container)
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
const stockLocationService = container.resolve(Modules.STOCK_LOCATION)
|
||||||
|
|
||||||
|
location = await stockLocationService.createStockLocations({
|
||||||
|
name: "Test Location",
|
||||||
|
address: {
|
||||||
|
address_1: "Test Address",
|
||||||
|
address_2: "tttest",
|
||||||
|
city: "Test City",
|
||||||
|
country_code: "us",
|
||||||
|
postal_code: "12345",
|
||||||
|
metadata: { email: "test@mail.com" },
|
||||||
|
},
|
||||||
|
metadata: { custom_location: "yes" },
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +53,10 @@ medusaIntegrationTestRunner({
|
|||||||
*/
|
*/
|
||||||
describe("Fulfillment module migrations backward compatibility", () => {
|
describe("Fulfillment module migrations backward compatibility", () => {
|
||||||
it("should allow to create a full data structure after the backward compatible migration have run on top of the medusa v1 database", async () => {
|
it("should allow to create a full data structure after the backward compatible migration have run on top of the medusa v1 database", async () => {
|
||||||
await setupFullDataFulfillmentStructure(service, { providerId })
|
await setupFullDataFulfillmentStructure(service, {
|
||||||
|
providerId,
|
||||||
|
locationId: location.id,
|
||||||
|
})
|
||||||
|
|
||||||
const fulfillmentSets = await service.listFulfillmentSets(
|
const fulfillmentSets = await service.listFulfillmentSets(
|
||||||
{},
|
{},
|
||||||
@@ -92,7 +110,10 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should cancel a fulfillment", async () => {
|
it("should cancel a fulfillment", async () => {
|
||||||
await setupFullDataFulfillmentStructure(service, { providerId })
|
await setupFullDataFulfillmentStructure(service, {
|
||||||
|
providerId,
|
||||||
|
locationId: location.id,
|
||||||
|
})
|
||||||
|
|
||||||
const [fulfillment] = await service.listFulfillments()
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
@@ -138,6 +159,7 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const data = generateCreateFulfillmentData({
|
const data = generateCreateFulfillmentData({
|
||||||
|
location_id: location.id,
|
||||||
provider_id: providerId,
|
provider_id: providerId,
|
||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
order_id: "order_123",
|
order_id: "order_123",
|
||||||
@@ -151,7 +173,7 @@ medusaIntegrationTestRunner({
|
|||||||
expect(response.data.fulfillment).toEqual(
|
expect(response.data.fulfillment).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
location_id: "test-location",
|
location_id: location.id,
|
||||||
packed_at: null,
|
packed_at: null,
|
||||||
shipped_at: null,
|
shipped_at: null,
|
||||||
delivered_at: null,
|
delivered_at: null,
|
||||||
@@ -218,7 +240,10 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should update a fulfillment to be shipped", async () => {
|
it("should update a fulfillment to be shipped", async () => {
|
||||||
await setupFullDataFulfillmentStructure(service, { providerId })
|
await setupFullDataFulfillmentStructure(service, {
|
||||||
|
providerId,
|
||||||
|
locationId: location.id,
|
||||||
|
})
|
||||||
|
|
||||||
const [fulfillment] = await service.listFulfillments()
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
@@ -255,7 +280,10 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should throw error when already shipped", async () => {
|
it("should throw error when already shipped", async () => {
|
||||||
await setupFullDataFulfillmentStructure(service, { providerId })
|
await setupFullDataFulfillmentStructure(service, {
|
||||||
|
providerId,
|
||||||
|
locationId: location.id,
|
||||||
|
})
|
||||||
|
|
||||||
const [fulfillment] = await service.listFulfillments()
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import { FulfillmentDTO, FulfillmentWorkflow } from "@medusajs/framework/types"
|
import {
|
||||||
|
FulfillmentDTO,
|
||||||
|
FulfillmentWorkflow,
|
||||||
|
StockLocationDTO,
|
||||||
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
WorkflowData,
|
||||||
WorkflowResponse,
|
WorkflowResponse,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
|
transform,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { createFulfillmentStep } from "../steps"
|
import { createFulfillmentStep } from "../steps"
|
||||||
|
import { useRemoteQueryStep } from "../../common"
|
||||||
|
|
||||||
export const createFulfillmentWorkflowId = "create-fulfillment-workflow"
|
export const createFulfillmentWorkflowId = "create-fulfillment-workflow"
|
||||||
/**
|
/**
|
||||||
@@ -15,6 +21,47 @@ export const createFulfillmentWorkflow = createWorkflow(
|
|||||||
(
|
(
|
||||||
input: WorkflowData<FulfillmentWorkflow.CreateFulfillmentWorkflowInput>
|
input: WorkflowData<FulfillmentWorkflow.CreateFulfillmentWorkflowInput>
|
||||||
): WorkflowResponse<FulfillmentDTO> => {
|
): WorkflowResponse<FulfillmentDTO> => {
|
||||||
return new WorkflowResponse(createFulfillmentStep(input))
|
const location: StockLocationDTO = useRemoteQueryStep({
|
||||||
|
entry_point: "stock_location",
|
||||||
|
fields: [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"address.id",
|
||||||
|
"address.address_1",
|
||||||
|
"address.address_2",
|
||||||
|
"address.city",
|
||||||
|
"address.country_code",
|
||||||
|
"address.phone",
|
||||||
|
"address.province",
|
||||||
|
"address.postal_code",
|
||||||
|
"address.metadata",
|
||||||
|
],
|
||||||
|
variables: { id: input.location_id },
|
||||||
|
list: false,
|
||||||
|
throw_if_key_not_found: true,
|
||||||
|
}).config({ name: "get-location" })
|
||||||
|
|
||||||
|
const stepInput = transform({ input, location }, ({ input, location }) => {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// When we have support for hooks with a return this would be a great
|
||||||
|
// place to put a hook for people to collect additional data they would
|
||||||
|
// like to pass down to the provider.
|
||||||
|
//
|
||||||
|
// const providerDataHook = createHook("getProviderData", stepInput)
|
||||||
|
//
|
||||||
|
// The collected provider data would be passed to createFulfillment in a
|
||||||
|
// additional_provider_data: Record<string, unknown> field.
|
||||||
|
|
||||||
|
const result = createFulfillmentStep(stepInput)
|
||||||
|
|
||||||
|
return new WorkflowResponse(result)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
import { FulfillmentDTO, FulfillmentWorkflow } from "@medusajs/framework/types"
|
import {
|
||||||
|
FulfillmentDTO,
|
||||||
|
FulfillmentWorkflow,
|
||||||
|
StockLocationDTO,
|
||||||
|
} from "@medusajs/framework/types"
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
WorkflowData,
|
||||||
WorkflowResponse,
|
WorkflowResponse,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
|
transform,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { createReturnFulfillmentStep } from "../steps"
|
import { createReturnFulfillmentStep } from "../steps"
|
||||||
|
import { useRemoteQueryStep } from "../../common"
|
||||||
|
|
||||||
export const createReturnFulfillmentWorkflowId =
|
export const createReturnFulfillmentWorkflowId =
|
||||||
"create-return-fulfillment-workflow"
|
"create-return-fulfillment-workflow"
|
||||||
@@ -16,6 +22,38 @@ export const createReturnFulfillmentWorkflow = createWorkflow(
|
|||||||
(
|
(
|
||||||
input: WorkflowData<FulfillmentWorkflow.CreateFulfillmentWorkflowInput>
|
input: WorkflowData<FulfillmentWorkflow.CreateFulfillmentWorkflowInput>
|
||||||
): WorkflowResponse<FulfillmentDTO> => {
|
): WorkflowResponse<FulfillmentDTO> => {
|
||||||
return new WorkflowResponse(createReturnFulfillmentStep(input))
|
const location: StockLocationDTO = useRemoteQueryStep({
|
||||||
|
entry_point: "stock_location",
|
||||||
|
fields: [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"address.id",
|
||||||
|
"address.address_1",
|
||||||
|
"address.address_2",
|
||||||
|
"address.city",
|
||||||
|
"address.country_code",
|
||||||
|
"address.phone",
|
||||||
|
"address.province",
|
||||||
|
"address.postal_code",
|
||||||
|
"address.metadata",
|
||||||
|
],
|
||||||
|
variables: { id: input.location_id },
|
||||||
|
list: false,
|
||||||
|
throw_if_key_not_found: true,
|
||||||
|
}).config({ name: "get-location" })
|
||||||
|
|
||||||
|
const stepInput = transform({ input, location }, ({ input, location }) => {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = createReturnFulfillmentStep(stepInput)
|
||||||
|
|
||||||
|
return new WorkflowResponse(result)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { OrderDTO } from "../../order"
|
import { OrderDTO } from "../../order"
|
||||||
|
import { StockLocationDTO } from "../../stock-location"
|
||||||
import { CreateFulfillmentAddressDTO } from "./fulfillment-address"
|
import { CreateFulfillmentAddressDTO } from "./fulfillment-address"
|
||||||
import { CreateFulfillmentItemDTO } from "./fulfillment-item"
|
import { CreateFulfillmentItemDTO } from "./fulfillment-item"
|
||||||
import { CreateFulfillmentLabelDTO } from "./fulfillment-label"
|
import { CreateFulfillmentLabelDTO } from "./fulfillment-label"
|
||||||
@@ -12,6 +13,11 @@ export interface CreateFulfillmentDTO {
|
|||||||
*/
|
*/
|
||||||
location_id: string
|
location_id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated location's data.
|
||||||
|
*/
|
||||||
|
location?: StockLocationDTO
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The date the fulfillment was packed.
|
* The date the fulfillment was packed.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in new issue
Block a user