feat(core-flows,medusa,types): fulfillment API: create (#7101)
what: - adds fulfillment create API RESOLVES CORE-1962
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/types": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(core-flows,medusa,types): add create shipment api for fulfillments
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/types": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(core-flows,medusa,types): fulfillment API: create
|
||||||
@@ -30,7 +30,8 @@ export function generateCreateFulfillmentData(
|
|||||||
country_code: "test-country-code_" + randomString,
|
country_code: "test-country-code_" + randomString,
|
||||||
province: "test-province_" + randomString,
|
province: "test-province_" + randomString,
|
||||||
phone: "test-phone_" + randomString,
|
phone: "test-phone_" + randomString,
|
||||||
full_name: "test-full-name_" + randomString,
|
first_name: "test-first-name_" + randomString,
|
||||||
|
last_name: "test-last-name_" + randomString,
|
||||||
},
|
},
|
||||||
items: data.items ?? [
|
items: data.items ?? [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
import {
|
||||||
|
createFulfillmentWorkflow,
|
||||||
|
createFulfillmentWorkflowId,
|
||||||
|
createShipmentWorkflow,
|
||||||
|
createShipmentWorkflowId,
|
||||||
|
updateFulfillmentWorkflow,
|
||||||
|
updateFulfillmentWorkflowId,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IFulfillmentModuleService } from "@medusajs/types"
|
||||||
|
import { medusaIntegrationTestRunner } from "medusa-test-utils/dist"
|
||||||
|
import {
|
||||||
|
generateCreateFulfillmentData,
|
||||||
|
generateCreateShippingOptionsData,
|
||||||
|
} from "../fixtures"
|
||||||
|
|
||||||
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
const providerId = "manual_test-provider"
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: { MEDUSA_FF_MEDUSA_V2: true },
|
||||||
|
testSuite: ({ getContainer }) => {
|
||||||
|
describe("Workflows: Fulfillment", () => {
|
||||||
|
let appContainer
|
||||||
|
let service: IFulfillmentModuleService
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
appContainer = getContainer()
|
||||||
|
service = appContainer.resolve(ModuleRegistrationName.FULFILLMENT)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("createFulfillmentWorkflow", () => {
|
||||||
|
describe("compensation", () => {
|
||||||
|
it("should cancel created fulfillment if step following step throws error", async () => {
|
||||||
|
const workflow = createFulfillmentWorkflow(appContainer)
|
||||||
|
|
||||||
|
workflow.appendAction("throw", createFulfillmentWorkflowId, {
|
||||||
|
invoke: async function failStep() {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to do something after creating fulfillment`
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingProfile = await service.createShippingProfiles({
|
||||||
|
name: "test",
|
||||||
|
type: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillmentSet = await service.create({
|
||||||
|
name: "test",
|
||||||
|
type: "test-type",
|
||||||
|
})
|
||||||
|
|
||||||
|
const serviceZone = await service.createServiceZones({
|
||||||
|
name: "test",
|
||||||
|
fulfillment_set_id: fulfillmentSet.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
const { errors } = await workflow.run({
|
||||||
|
input: data,
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(errors).toEqual([
|
||||||
|
{
|
||||||
|
action: "throw",
|
||||||
|
handlerType: "invoke",
|
||||||
|
error: expect.objectContaining({
|
||||||
|
message: `Failed to do something after creating fulfillment`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const fulfillments = await service.listFulfillments()
|
||||||
|
|
||||||
|
expect(fulfillments.filter((f) => !!f.canceled_at)).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("updateFulfillmentWorkflow", () => {
|
||||||
|
describe("compensation", () => {
|
||||||
|
it("should rollback updated fulfillment if step following step throws error", async () => {
|
||||||
|
const workflow = updateFulfillmentWorkflow(appContainer)
|
||||||
|
|
||||||
|
workflow.appendAction("throw", updateFulfillmentWorkflowId, {
|
||||||
|
invoke: async function failStep() {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to do something after updating fulfillment`
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingProfile = await service.createShippingProfiles({
|
||||||
|
name: "test",
|
||||||
|
type: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillmentSet = await service.create({
|
||||||
|
name: "test",
|
||||||
|
type: "test-type",
|
||||||
|
})
|
||||||
|
|
||||||
|
const serviceZone = await service.createServiceZones({
|
||||||
|
name: "test",
|
||||||
|
fulfillment_set_id: fulfillmentSet.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillment = await service.createFulfillment(data)
|
||||||
|
|
||||||
|
const date = new Date()
|
||||||
|
const { errors } = await workflow.run({
|
||||||
|
input: {
|
||||||
|
id: fulfillment.id,
|
||||||
|
shipped_at: date,
|
||||||
|
packed_at: date,
|
||||||
|
location_id: "new location",
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(errors).toEqual([
|
||||||
|
{
|
||||||
|
action: "throw",
|
||||||
|
handlerType: "invoke",
|
||||||
|
error: expect.objectContaining({
|
||||||
|
message: `Failed to do something after updating fulfillment`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const fulfillmentAfterRollback = await service.retrieveFulfillment(
|
||||||
|
fulfillment.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(fulfillmentAfterRollback).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
location_id: data.location_id,
|
||||||
|
shipped_at: data.shipped_at,
|
||||||
|
packed_at: data.packed_at,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("createShipmentWorkflow", () => {
|
||||||
|
describe("compensation", () => {
|
||||||
|
it("should rollback shipment workflow if following step throws error", async () => {
|
||||||
|
const workflow = createShipmentWorkflow(appContainer)
|
||||||
|
|
||||||
|
workflow.appendAction("throw", createShipmentWorkflowId, {
|
||||||
|
invoke: async function failStep() {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to do something after creating shipment`
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingProfile = await service.createShippingProfiles({
|
||||||
|
name: "test",
|
||||||
|
type: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillmentSet = await service.create({
|
||||||
|
name: "test",
|
||||||
|
type: "test-type",
|
||||||
|
})
|
||||||
|
|
||||||
|
const serviceZone = await service.createServiceZones({
|
||||||
|
name: "test",
|
||||||
|
fulfillment_set_id: fulfillmentSet.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillment = await service.createFulfillment({
|
||||||
|
...data,
|
||||||
|
labels: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const { errors } = await workflow.run({
|
||||||
|
input: {
|
||||||
|
id: fulfillment.id,
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
tracking_number: "test-tracking-number",
|
||||||
|
tracking_url: "test-tracking-url",
|
||||||
|
label_url: "test-label-url",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(errors).toEqual([
|
||||||
|
{
|
||||||
|
action: "throw",
|
||||||
|
handlerType: "invoke",
|
||||||
|
error: expect.objectContaining({
|
||||||
|
message: `Failed to do something after creating shipment`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const fulfillmentAfterRollback = await service.retrieveFulfillment(
|
||||||
|
fulfillment.id,
|
||||||
|
{ select: ["shipped_at"], relations: ["labels"] }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(fulfillmentAfterRollback).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
shipped_at: null,
|
||||||
|
// TODO: the revert isn't handling deleting the labels. This needs to be handled uniformly across.
|
||||||
|
// labels: [],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -2,7 +2,11 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|||||||
import { IFulfillmentModuleService } from "@medusajs/types"
|
import { IFulfillmentModuleService } from "@medusajs/types"
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils/dist"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils/dist"
|
||||||
import { createAdminUser } from "../../../helpers/create-admin-user"
|
import { createAdminUser } from "../../../helpers/create-admin-user"
|
||||||
import { setupFullDataFulfillmentStructure } from "../fixtures"
|
import {
|
||||||
|
generateCreateFulfillmentData,
|
||||||
|
generateCreateShippingOptionsData,
|
||||||
|
setupFullDataFulfillmentStructure,
|
||||||
|
} from "../fixtures"
|
||||||
|
|
||||||
jest.setTimeout(100000)
|
jest.setTimeout(100000)
|
||||||
|
|
||||||
@@ -10,6 +14,7 @@ const env = { MEDUSA_FF_MEDUSA_V2: true }
|
|||||||
const adminHeaders = {
|
const adminHeaders = {
|
||||||
headers: { "x-medusa-access-token": "test_token" },
|
headers: { "x-medusa-access-token": "test_token" },
|
||||||
}
|
}
|
||||||
|
const providerId = "manual_test-provider"
|
||||||
|
|
||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
env,
|
||||||
@@ -33,9 +38,7 @@ 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, {
|
await setupFullDataFulfillmentStructure(service, { providerId })
|
||||||
providerId: `manual_test-provider`,
|
|
||||||
})
|
|
||||||
|
|
||||||
const fulfillmentSets = await service.list(
|
const fulfillmentSets = await service.list(
|
||||||
{},
|
{},
|
||||||
@@ -89,9 +92,7 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should cancel a fulfillment", async () => {
|
it("should cancel a fulfillment", async () => {
|
||||||
await setupFullDataFulfillmentStructure(service, {
|
await setupFullDataFulfillmentStructure(service, { providerId })
|
||||||
providerId: `manual_test-provider`,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [fulfillment] = await service.listFulfillments()
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
@@ -110,5 +111,177 @@ medusaIntegrationTestRunner({
|
|||||||
expect(canceledFulfillment.canceled_at).toBeTruthy()
|
expect(canceledFulfillment.canceled_at).toBeTruthy()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/fulfillments", () => {
|
||||||
|
it("should create a fulfillment", async () => {
|
||||||
|
const shippingProfile = await service.createShippingProfiles({
|
||||||
|
name: "test",
|
||||||
|
type: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
const fulfillmentSet = await service.create({
|
||||||
|
name: "test",
|
||||||
|
type: "test-type",
|
||||||
|
})
|
||||||
|
|
||||||
|
const serviceZone = await service.createServiceZones({
|
||||||
|
name: "test",
|
||||||
|
fulfillment_set_id: fulfillmentSet.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(`/admin/fulfillments`, data, adminHeaders)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.fulfillment).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
location_id: "test-location",
|
||||||
|
packed_at: null,
|
||||||
|
shipped_at: null,
|
||||||
|
delivered_at: null,
|
||||||
|
canceled_at: null,
|
||||||
|
provider_id: "manual_test-provider",
|
||||||
|
delivery_address: expect.objectContaining({
|
||||||
|
address_1: expect.any(String),
|
||||||
|
address_2: expect.any(String),
|
||||||
|
city: expect.any(String),
|
||||||
|
country_code: expect.any(String),
|
||||||
|
province: expect.any(String),
|
||||||
|
postal_code: expect.any(String),
|
||||||
|
}),
|
||||||
|
items: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
title: expect.any(String),
|
||||||
|
sku: expect.any(String),
|
||||||
|
barcode: expect.any(String),
|
||||||
|
raw_quantity: {
|
||||||
|
value: "1",
|
||||||
|
precision: 20,
|
||||||
|
},
|
||||||
|
quantity: 1,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
labels: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
tracking_number: expect.any(String),
|
||||||
|
tracking_url: expect.any(String),
|
||||||
|
label_url: expect.any(String),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/fulfillments/:id/shipment", () => {
|
||||||
|
it("should throw an error when id is not found", async () => {
|
||||||
|
const error = await api
|
||||||
|
.post(
|
||||||
|
`/admin/fulfillments/does-not-exist/shipment`,
|
||||||
|
{
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
tracking_number: "test-tracking-number",
|
||||||
|
tracking_url: "test-tracking-url",
|
||||||
|
label_url: "test-label-url",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.response.status).toEqual(404)
|
||||||
|
expect(error.response.data).toEqual({
|
||||||
|
type: "not_found",
|
||||||
|
message: "Fulfillment with id: does-not-exist was not found",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update a fulfillment to be shipped", async () => {
|
||||||
|
await setupFullDataFulfillmentStructure(service, { providerId })
|
||||||
|
|
||||||
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/fulfillments/${fulfillment.id}/shipment`,
|
||||||
|
{
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
tracking_number: "test-tracking-number",
|
||||||
|
tracking_url: "test-tracking-url",
|
||||||
|
label_url: "test-label-url",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.fulfillment).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: fulfillment.id,
|
||||||
|
shipped_at: expect.any(String),
|
||||||
|
labels: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
tracking_number: "test-tracking-number",
|
||||||
|
tracking_url: "test-tracking-url",
|
||||||
|
label_url: "test-label-url",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw error when already shipped", async () => {
|
||||||
|
await setupFullDataFulfillmentStructure(service, { providerId })
|
||||||
|
|
||||||
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
|
await service.updateFulfillment(fulfillment.id, {
|
||||||
|
shipped_at: new Date(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const error = await api
|
||||||
|
.post(
|
||||||
|
`/admin/fulfillments/${fulfillment.id}/shipment`,
|
||||||
|
{
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
tracking_number: "test-tracking-number",
|
||||||
|
tracking_url: "test-tracking-url",
|
||||||
|
label_url: "test-label-url",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.response.status).toEqual(400)
|
||||||
|
expect(error.response.data).toEqual({
|
||||||
|
type: "not_allowed",
|
||||||
|
message: "Shipment has already been created",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { FulfillmentTypes, IFulfillmentModuleService } from "@medusajs/types"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
export const createFulfillmentStepId = "create-fulfillment"
|
||||||
|
export const createFulfillmentStep = createStep(
|
||||||
|
createFulfillmentStepId,
|
||||||
|
async (data: FulfillmentTypes.CreateFulfillmentDTO, { container }) => {
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
const fulfillment = await service.createFulfillment(data)
|
||||||
|
|
||||||
|
return new StepResponse(fulfillment, fulfillment.id)
|
||||||
|
},
|
||||||
|
async (id, { container }) => {
|
||||||
|
if (!id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.cancelFulfillment(id)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from "./add-rules-to-fulfillment-shipping-option"
|
export * from "./add-rules-to-fulfillment-shipping-option"
|
||||||
export * from "./add-shipping-options-prices"
|
export * from "./add-shipping-options-prices"
|
||||||
export * from "./cancel-fulfillment"
|
export * from "./cancel-fulfillment"
|
||||||
|
export * from "./create-fulfillment"
|
||||||
export * from "./create-fulfillment-set"
|
export * from "./create-fulfillment-set"
|
||||||
export * from "./create-service-zones"
|
export * from "./create-service-zones"
|
||||||
export * from "./create-shipping-profiles"
|
export * from "./create-shipping-profiles"
|
||||||
@@ -9,4 +10,6 @@ export * from "./delete-service-zones"
|
|||||||
export * from "./delete-shipping-options"
|
export * from "./delete-shipping-options"
|
||||||
export * from "./remove-rules-from-fulfillment-shipping-option"
|
export * from "./remove-rules-from-fulfillment-shipping-option"
|
||||||
export * from "./set-shipping-options-prices"
|
export * from "./set-shipping-options-prices"
|
||||||
|
export * from "./update-fulfillment"
|
||||||
export * from "./upsert-shipping-options"
|
export * from "./upsert-shipping-options"
|
||||||
|
export * from "./validate-shipment"
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { FulfillmentWorkflow } from "@medusajs/types"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
import { updateFulfillmentWorkflow } from "../workflows/update-fulfillment"
|
||||||
|
|
||||||
|
export const updateFulfillmentWorkflowStepId = "update-fulfillment-workflow"
|
||||||
|
export const updateFulfillmentWorkflowStep = createStep(
|
||||||
|
updateFulfillmentWorkflowStepId,
|
||||||
|
async (
|
||||||
|
data: FulfillmentWorkflow.UpdateFulfillmentWorkflowInput,
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
transaction,
|
||||||
|
result: updated,
|
||||||
|
errors,
|
||||||
|
} = await updateFulfillmentWorkflow(container).run({
|
||||||
|
input: data,
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StepResponse(updated, transaction)
|
||||||
|
},
|
||||||
|
|
||||||
|
async (transaction, { container }) => {
|
||||||
|
if (!transaction) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateFulfillmentWorkflow(container).cancel({ transaction })
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { FulfillmentWorkflow, IFulfillmentModuleService } from "@medusajs/types"
|
||||||
|
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
export const updateFulfillmentStepId = "update-fulfillment"
|
||||||
|
export const updateFulfillmentStep = createStep(
|
||||||
|
updateFulfillmentStepId,
|
||||||
|
async (
|
||||||
|
input: FulfillmentWorkflow.UpdateFulfillmentWorkflowInput,
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
const { id, ...data } = input
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([data])
|
||||||
|
const fulfillment = await service.retrieveFulfillment(id, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
await service.updateFulfillment(id, data)
|
||||||
|
|
||||||
|
return new StepResponse(void 0, fulfillment)
|
||||||
|
},
|
||||||
|
async (fulfillment, { container }) => {
|
||||||
|
if (!fulfillment) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
const { id, ...data } = fulfillment
|
||||||
|
|
||||||
|
// TODO: this does not revert the relationships that are created in invoke step
|
||||||
|
// There should be a consistent way to handle across workflows
|
||||||
|
await service.updateFulfillment(id, data)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IFulfillmentModuleService } from "@medusajs/types"
|
||||||
|
import { MedusaError } from "@medusajs/utils"
|
||||||
|
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
export const validateShipmentStepId = "validate-shipment"
|
||||||
|
export const validateShipmentStep = createStep(
|
||||||
|
validateShipmentStepId,
|
||||||
|
async (id: string, { container }) => {
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
const fulfillment = await service.retrieveFulfillment(id, {
|
||||||
|
select: ["shipped_at", "canceled_at", "shipping_option_id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
if (fulfillment.shipped_at) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
"Shipment has already been created"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fulfillment.canceled_at) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
"Cannot create shipment for a canceled fulfillment"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fulfillment.shipping_option_id) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
"Cannot create shipment without a Shipping Option"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StepResponse(void 0)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { FulfillmentDTO, FulfillmentWorkflow } from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { createFulfillmentStep } from "../steps"
|
||||||
|
|
||||||
|
export const createFulfillmentWorkflowId = "create-fulfillment-workflow"
|
||||||
|
export const createFulfillmentWorkflow = createWorkflow(
|
||||||
|
createFulfillmentWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<FulfillmentWorkflow.CreateFulfillmentWorkflowInput>
|
||||||
|
): WorkflowData<FulfillmentDTO> => {
|
||||||
|
return createFulfillmentStep(input)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { FulfillmentWorkflow } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
WorkflowData,
|
||||||
|
createWorkflow,
|
||||||
|
transform,
|
||||||
|
} from "@medusajs/workflows-sdk"
|
||||||
|
import { validateShipmentStep } from "../steps"
|
||||||
|
import { updateFulfillmentWorkflowStep } from "../steps/update-fulfillment-workflow"
|
||||||
|
|
||||||
|
export const createShipmentWorkflowId = "create-shipment-workflow"
|
||||||
|
export const createShipmentWorkflow = createWorkflow(
|
||||||
|
createShipmentWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<FulfillmentWorkflow.CreateShipmentWorkflowInput>
|
||||||
|
): WorkflowData<void> => {
|
||||||
|
validateShipmentStep(input.id)
|
||||||
|
|
||||||
|
const update = transform({ input }, (data) => ({
|
||||||
|
...data.input,
|
||||||
|
shipped_at: new Date(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
updateFulfillmentWorkflowStep(update)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
export * from "./add-rules-to-fulfillment-shipping-option"
|
export * from "./add-rules-to-fulfillment-shipping-option"
|
||||||
export * from "./cancel-fulfillment"
|
export * from "./cancel-fulfillment"
|
||||||
|
export * from "./create-fulfillment"
|
||||||
export * from "./create-service-zones"
|
export * from "./create-service-zones"
|
||||||
|
export * from "./create-shipment"
|
||||||
export * from "./create-shipping-options"
|
export * from "./create-shipping-options"
|
||||||
export * from "./create-shipping-profiles"
|
export * from "./create-shipping-profiles"
|
||||||
export * from "./delete-fulfillment-sets"
|
export * from "./delete-fulfillment-sets"
|
||||||
export * from "./delete-service-zones"
|
export * from "./delete-service-zones"
|
||||||
export * from "./delete-shipping-options"
|
export * from "./delete-shipping-options"
|
||||||
export * from "./remove-rules-from-fulfillment-shipping-option"
|
export * from "./remove-rules-from-fulfillment-shipping-option"
|
||||||
|
export * from "./update-fulfillment"
|
||||||
export * from "./update-service-zones"
|
export * from "./update-service-zones"
|
||||||
export * from "./update-shipping-options"
|
export * from "./update-shipping-options"
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { FulfillmentWorkflow } from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { updateFulfillmentStep } from "../steps"
|
||||||
|
|
||||||
|
export const updateFulfillmentWorkflowId = "update-fulfillment-workflow"
|
||||||
|
export const updateFulfillmentWorkflow = createWorkflow(
|
||||||
|
updateFulfillmentWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<FulfillmentWorkflow.UpdateFulfillmentWorkflowInput>
|
||||||
|
): WorkflowData<void> => {
|
||||||
|
updateFulfillmentStep(input)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -162,12 +162,12 @@ export default class Fulfillment {
|
|||||||
@BeforeCreate()
|
@BeforeCreate()
|
||||||
onCreate() {
|
onCreate() {
|
||||||
this.id = generateEntityId(this.id, "ful")
|
this.id = generateEntityId(this.id, "ful")
|
||||||
this.provider_id ??= this.provider.id
|
this.provider_id ??= this.provider_id ?? this.provider?.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnInit()
|
@OnInit()
|
||||||
onInit() {
|
onInit() {
|
||||||
this.id = generateEntityId(this.id, "ful")
|
this.id = generateEntityId(this.id, "ful")
|
||||||
this.provider_id ??= this.provider.id
|
this.provider_id ??= this.provider_id ?? this.provider?.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { createShipmentWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../types/routing"
|
||||||
|
import { refetchFulfillment } from "../../helpers"
|
||||||
|
import { AdminCreateShipmentType } from "../../validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminCreateShipmentType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const { id } = req.params
|
||||||
|
|
||||||
|
const { errors } = await createShipmentWorkflow(req.scope).run({
|
||||||
|
input: { id, ...req.validatedBody },
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const fulfillment = await refetchFulfillment(
|
||||||
|
id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ fulfillment })
|
||||||
|
}
|
||||||
@@ -3,7 +3,12 @@ import { authenticate } from "../../../utils/authenticate-middleware"
|
|||||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
import * as QueryConfig from "./query-config"
|
import * as QueryConfig from "./query-config"
|
||||||
import { AdminCancelFulfillment, AdminFulfillmentParams } from "./validators"
|
import {
|
||||||
|
AdminCancelFulfillment,
|
||||||
|
AdminCreateFulfillment,
|
||||||
|
AdminCreateShipment,
|
||||||
|
AdminFulfillmentParams,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
export const adminFulfillmentsRoutesMiddlewares: MiddlewareRoute[] = [
|
export const adminFulfillmentsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
{
|
{
|
||||||
@@ -22,4 +27,26 @@ export const adminFulfillmentsRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/fulfillments",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCreateFulfillment),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminFulfillmentParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/fulfillments/:id/shipment",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCreateShipment),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminFulfillmentParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -9,8 +9,13 @@ export const defaultAdminFulfillmentsFields = [
|
|||||||
"provider_id",
|
"provider_id",
|
||||||
"shipping_option_id",
|
"shipping_option_id",
|
||||||
"metadata",
|
"metadata",
|
||||||
|
"order",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
"*delivery_address",
|
||||||
|
"*items",
|
||||||
|
"*labels",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
export const retrieveTransformQueryConfig = {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { createFulfillmentWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../types/routing"
|
||||||
|
import { refetchFulfillment } from "./helpers"
|
||||||
|
import { AdminCreateFulfillmentType } from "./validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminCreateFulfillmentType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const { result: fullfillment, errors } = await createFulfillmentWorkflow(
|
||||||
|
req.scope
|
||||||
|
).run({
|
||||||
|
input: req.validatedBody,
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const fulfillment = await refetchFulfillment(
|
||||||
|
fullfillment.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ fulfillment })
|
||||||
|
}
|
||||||
@@ -1,7 +1,39 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
import { AddressPayload } from "../../utils/common-validators"
|
||||||
import { createSelectParams } from "../../utils/validators"
|
import { createSelectParams } from "../../utils/validators"
|
||||||
|
|
||||||
export const AdminFulfillmentParams = createSelectParams()
|
export const AdminFulfillmentParams = createSelectParams()
|
||||||
|
|
||||||
export const AdminCancelFulfillment = z.object({})
|
const AdminCreateFulfillmentItem = z.object({
|
||||||
|
title: z.string(),
|
||||||
|
sku: z.string(),
|
||||||
|
quantity: z.number(),
|
||||||
|
barcode: z.string(),
|
||||||
|
line_item_id: z.string().optional(),
|
||||||
|
inventory_item_id: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const AdminCreateFulfillmentLabel = z.object({
|
||||||
|
tracking_number: z.string(),
|
||||||
|
tracking_url: z.string(),
|
||||||
|
label_url: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
export type AdminCancelFulfillmentType = z.infer<typeof AdminCancelFulfillment>
|
export type AdminCancelFulfillmentType = z.infer<typeof AdminCancelFulfillment>
|
||||||
|
export const AdminCancelFulfillment = z.object({})
|
||||||
|
|
||||||
|
export type AdminCreateFulfillmentType = z.infer<typeof AdminCreateFulfillment>
|
||||||
|
export const AdminCreateFulfillment = z.object({
|
||||||
|
location_id: z.string(),
|
||||||
|
provider_id: z.string(),
|
||||||
|
delivery_address: AddressPayload,
|
||||||
|
items: z.array(AdminCreateFulfillmentItem),
|
||||||
|
labels: z.array(AdminCreateFulfillmentLabel),
|
||||||
|
order: z.object({}),
|
||||||
|
metadata: z.record(z.unknown()).optional().nullable(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AdminCreateShipmentType = z.infer<typeof AdminCreateShipment>
|
||||||
|
export const AdminCreateShipment = z.object({
|
||||||
|
labels: z.array(AdminCreateFulfillmentLabel),
|
||||||
|
})
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const AddressPayload = z
|
|||||||
country_code: z.string().optional(),
|
country_code: z.string().optional(),
|
||||||
province: z.string().optional(),
|
province: z.string().optional(),
|
||||||
postal_code: z.string().optional(),
|
postal_code: z.string().optional(),
|
||||||
metadata: z.record(z.string()).optional(),
|
metadata: z.record(z.string()).optional().nullable(),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
|
|
||||||
|
|||||||
@@ -110,4 +110,9 @@ export interface UpdateFulfillmentDTO {
|
|||||||
* Holds custom data in key-value pairs.
|
* Holds custom data in key-value pairs.
|
||||||
*/
|
*/
|
||||||
metadata?: Record<string, unknown> | null
|
metadata?: Record<string, unknown> | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The labels associated with the fulfillment.
|
||||||
|
*/
|
||||||
|
labels?: Omit<CreateFulfillmentLabelDTO, "fulfillment_id">[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/**
|
||||||
|
* The fulfillment address to be created.
|
||||||
|
*/
|
||||||
|
export type CreateFulfillmentAddressWorkflowDTO = {
|
||||||
|
/**
|
||||||
|
* The company of the fulfillment address.
|
||||||
|
*/
|
||||||
|
company?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first name of the fulfillment address.
|
||||||
|
*/
|
||||||
|
first_name?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last name of the fulfillment address.
|
||||||
|
*/
|
||||||
|
last_name?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first line of the fulfillment address.
|
||||||
|
*/
|
||||||
|
address_1?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The second line of the fulfillment address.
|
||||||
|
*/
|
||||||
|
address_2?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The city of the fulfillment address.
|
||||||
|
*/
|
||||||
|
city?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ISO 2 character country code of the fulfillment address.
|
||||||
|
*/
|
||||||
|
country_code?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The province of the fulfillment address.
|
||||||
|
*/
|
||||||
|
province?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The postal code of the fulfillment address.
|
||||||
|
*/
|
||||||
|
postal_code?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The phone of the fulfillment address.
|
||||||
|
*/
|
||||||
|
phone?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds custom data in key-value pairs.
|
||||||
|
*/
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fulfillment item to be created.
|
||||||
|
*/
|
||||||
|
export type CreateFulfillmentItemWorkflowDTO = {
|
||||||
|
/**
|
||||||
|
* The title of the fulfillment item.
|
||||||
|
*/
|
||||||
|
title: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SKU of the fulfillment item.
|
||||||
|
*/
|
||||||
|
sku: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The quantity of the fulfillment item.
|
||||||
|
*/
|
||||||
|
quantity: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The barcode of the fulfillment item.
|
||||||
|
*/
|
||||||
|
barcode: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated line item's ID.
|
||||||
|
*/
|
||||||
|
line_item_id?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated inventory item's ID.
|
||||||
|
*/
|
||||||
|
inventory_item_id?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fulfillment label to be created.
|
||||||
|
*/
|
||||||
|
export type CreateFulfillmentLabelWorkflowDTO = {
|
||||||
|
/**
|
||||||
|
* The tracking number of the fulfillment label.
|
||||||
|
*/
|
||||||
|
tracking_number: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tracking URL of the fulfillment label.
|
||||||
|
*/
|
||||||
|
tracking_url: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the label.
|
||||||
|
*/
|
||||||
|
label_url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateFulfillmentOrderWorkflowDTO = Record<string, any>
|
||||||
|
|
||||||
|
export type CreateFulfillmentWorkflowInput = {
|
||||||
|
/**
|
||||||
|
* The associated location's ID.
|
||||||
|
*/
|
||||||
|
location_id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was packed.
|
||||||
|
*/
|
||||||
|
packed_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was shipped.
|
||||||
|
*/
|
||||||
|
shipped_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was delivered.
|
||||||
|
*/
|
||||||
|
delivered_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was canceled.
|
||||||
|
*/
|
||||||
|
canceled_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data necessary for the associated fulfillment provider to process the fulfillment.
|
||||||
|
*/
|
||||||
|
data?: Record<string, unknown> | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated fulfillment provider's ID.
|
||||||
|
*/
|
||||||
|
provider_id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated shipping option's ID.
|
||||||
|
*/
|
||||||
|
shipping_option_id?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds custom data in key-value pairs.
|
||||||
|
*/
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The address associated with the fulfillment. It's used for delivery.
|
||||||
|
*/
|
||||||
|
delivery_address: CreateFulfillmentAddressWorkflowDTO
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The items associated with the fulfillment.
|
||||||
|
*/
|
||||||
|
items: CreateFulfillmentItemWorkflowDTO[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The labels associated with the fulfillment.
|
||||||
|
*/
|
||||||
|
labels: CreateFulfillmentLabelWorkflowDTO[]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated fulfillment order.
|
||||||
|
*/
|
||||||
|
order: CreateFulfillmentOrderWorkflowDTO
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { CreateFulfillmentLabelWorkflowDTO } from "./create-fulfillment"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes to update in the fulfillment.
|
||||||
|
*/
|
||||||
|
export interface CreateShipmentWorkflowInput {
|
||||||
|
/**
|
||||||
|
* The ID of the fulfillment
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The labels associated with the fulfillment.
|
||||||
|
*/
|
||||||
|
labels?: CreateFulfillmentLabelWorkflowDTO[]
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
export * from "./create-fulfillment"
|
||||||
|
export * from "./create-shipment"
|
||||||
export * from "./create-shipping-options"
|
export * from "./create-shipping-options"
|
||||||
export * from "./service-zones"
|
|
||||||
export * from "./delete-shipping-options"
|
export * from "./delete-shipping-options"
|
||||||
|
export * from "./service-zones"
|
||||||
export * from "./shipping-profiles"
|
export * from "./shipping-profiles"
|
||||||
|
export * from "./update-fulfillment"
|
||||||
export * from "./update-shipping-options"
|
export * from "./update-shipping-options"
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* The attributes to update in the fulfillment.
|
||||||
|
*/
|
||||||
|
export interface UpdateFulfillmentWorkflowInput {
|
||||||
|
/**
|
||||||
|
* The ID of the fulfillment
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated location's ID.
|
||||||
|
*/
|
||||||
|
location_id?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was packed.
|
||||||
|
*/
|
||||||
|
packed_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was shipped.
|
||||||
|
*/
|
||||||
|
shipped_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date the fulfillment was delivered.
|
||||||
|
*/
|
||||||
|
delivered_at?: Date | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data necessary for the associated fulfillment provider to process the fulfillment.
|
||||||
|
*/
|
||||||
|
data?: Record<string, unknown> | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds custom data in key-value pairs.
|
||||||
|
*/
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user