feat(core-flows,medusa,types): cancel fulfillments API (#7095)
what: - adds POST cancel fulfillments endpoint RESOLVES CORE-1972
This commit is contained in:
1 parent
ccb50bb3da
commit
62b9dcc6c1
13 files changed
+202
-9
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/types": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(core-flows,medusa,types): cancel fulfillments API
|
||||||
@@ -1,22 +1,31 @@
|
|||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
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 { setupFullDataFulfillmentStructure } from "../fixtures"
|
import { setupFullDataFulfillmentStructure } from "../fixtures"
|
||||||
|
|
||||||
jest.setTimeout(100000)
|
jest.setTimeout(100000)
|
||||||
|
|
||||||
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
||||||
|
const adminHeaders = {
|
||||||
|
headers: { "x-medusa-access-token": "test_token" },
|
||||||
|
}
|
||||||
|
|
||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
env,
|
||||||
testSuite: ({ getContainer }) => {
|
testSuite: ({ getContainer, api, dbConnection }) => {
|
||||||
let service: IFulfillmentModuleService
|
let service: IFulfillmentModuleService
|
||||||
|
let container
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
const container = getContainer()
|
container = getContainer()
|
||||||
service = container.resolve(ModuleRegistrationName.FULFILLMENT)
|
service = container.resolve(ModuleRegistrationName.FULFILLMENT)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test runner run both the medusa migrations as well as the modules
|
* The test runner run both the medusa migrations as well as the modules
|
||||||
* migrations. In order to ensure the backward compatibility
|
* migrations. In order to ensure the backward compatibility
|
||||||
@@ -65,5 +74,41 @@ medusaIntegrationTestRunner({
|
|||||||
expect(fulfillment.items).toHaveLength(1)
|
expect(fulfillment.items).toHaveLength(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/fulfillments/:id/cancel", () => {
|
||||||
|
it("should throw an error when id is not found", async () => {
|
||||||
|
const error = await api
|
||||||
|
.post(`/admin/fulfillments/does-not-exist/cancel`, {}, 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 cancel a fulfillment", async () => {
|
||||||
|
await setupFullDataFulfillmentStructure(service, {
|
||||||
|
providerId: `manual_test-provider`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [fulfillment] = await service.listFulfillments()
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/fulfillments/${fulfillment.id}/cancel`,
|
||||||
|
{},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
|
const canceledFulfillment = await service.retrieveFulfillment(
|
||||||
|
fulfillment.id
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(canceledFulfillment.canceled_at).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IFulfillmentModuleService } from "@medusajs/types"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
export const cancelFulfillmentStepId = "cancel-fulfillment"
|
||||||
|
export const cancelFulfillmentStep = createStep(
|
||||||
|
cancelFulfillmentStepId,
|
||||||
|
async (id: string, { container }) => {
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.cancelFulfillment(id)
|
||||||
|
|
||||||
|
return new StepResponse(void 0, id)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
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 "./create-fulfillment-set"
|
export * from "./create-fulfillment-set"
|
||||||
export * from "./create-service-zones"
|
export * from "./create-service-zones"
|
||||||
export * from "./upsert-shipping-options"
|
export * from "./create-shipping-profiles"
|
||||||
|
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 "./delete-fulfillment-sets"
|
|
||||||
export * from "./create-shipping-profiles"
|
|
||||||
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 "./upsert-shipping-options"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { cancelFulfillmentStep } from "../steps"
|
||||||
|
|
||||||
|
export const cancelFulfillmentWorkflowId = "cancel-fulfillment-workflow"
|
||||||
|
export const cancelFulfillmentWorkflow = createWorkflow(
|
||||||
|
cancelFulfillmentWorkflowId,
|
||||||
|
(input: WorkflowData<{ id: string }>) => {
|
||||||
|
cancelFulfillmentStep(input.id)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
export * from "./add-rules-to-fulfillment-shipping-option"
|
export * from "./add-rules-to-fulfillment-shipping-option"
|
||||||
|
export * from "./cancel-fulfillment"
|
||||||
export * from "./create-service-zones"
|
export * from "./create-service-zones"
|
||||||
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-service-zones"
|
export * from "./delete-service-zones"
|
||||||
export * from "./delete-shipping-options"
|
export * from "./delete-shipping-options"
|
||||||
export * from "./delete-fulfillment-sets"
|
|
||||||
export * from "./remove-rules-from-fulfillment-shipping-option"
|
export * from "./remove-rules-from-fulfillment-shipping-option"
|
||||||
export * from "./update-service-zones"
|
export * from "./update-service-zones"
|
||||||
export * from "./update-shipping-options"
|
export * from "./update-shipping-options"
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { cancelFulfillmentWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../types/routing"
|
||||||
|
import { refetchFulfillment } from "../../helpers"
|
||||||
|
import { AdminCancelFulfillmentType } from "../../validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminCancelFulfillmentType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const { id } = req.params
|
||||||
|
const { errors } = await cancelFulfillmentWorkflow(req.scope).run({
|
||||||
|
input: { id },
|
||||||
|
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 })
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { MedusaContainer } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const refetchFulfillment = async (
|
||||||
|
fulfillmentId: string,
|
||||||
|
scope: MedusaContainer,
|
||||||
|
fields: string[]
|
||||||
|
) => {
|
||||||
|
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "fulfillments",
|
||||||
|
variables: {
|
||||||
|
filters: { id: fulfillmentId },
|
||||||
|
},
|
||||||
|
fields: fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [fulfillment] = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
return fulfillment
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { MiddlewareRoute } from "../../../types/middlewares"
|
||||||
|
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||||
|
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||||
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
import { AdminCancelFulfillment, AdminFulfillmentParams } from "./validators"
|
||||||
|
|
||||||
|
export const adminFulfillmentsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: "ALL",
|
||||||
|
matcher: "/admin/fulfillments*",
|
||||||
|
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/fulfillments/:id/cancel",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCancelFulfillment),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminFulfillmentParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export const defaultAdminFulfillmentsFields = [
|
||||||
|
"id",
|
||||||
|
"location_id",
|
||||||
|
"packed_at",
|
||||||
|
"shipped_at",
|
||||||
|
"delivered_at",
|
||||||
|
"canceled_at",
|
||||||
|
"data",
|
||||||
|
"provider_id",
|
||||||
|
"shipping_option_id",
|
||||||
|
"metadata",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveTransformQueryConfig = {
|
||||||
|
defaults: defaultAdminFulfillmentsFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { createSelectParams } from "../../utils/validators"
|
||||||
|
|
||||||
|
export const AdminFulfillmentParams = createSelectParams()
|
||||||
|
|
||||||
|
export const AdminCancelFulfillment = z.object({})
|
||||||
|
export type AdminCancelFulfillmentType = z.infer<typeof AdminCancelFulfillment>
|
||||||
@@ -7,14 +7,15 @@ import { adminCustomerGroupRoutesMiddlewares } from "./admin/customer-groups/mid
|
|||||||
import { adminCustomerRoutesMiddlewares } from "./admin/customers/middlewares"
|
import { adminCustomerRoutesMiddlewares } from "./admin/customers/middlewares"
|
||||||
import { adminDraftOrderRoutesMiddlewares } from "./admin/draft-orders/middlewares"
|
import { adminDraftOrderRoutesMiddlewares } from "./admin/draft-orders/middlewares"
|
||||||
import { adminFulfillmentSetsRoutesMiddlewares } from "./admin/fulfillment-sets/middlewares"
|
import { adminFulfillmentSetsRoutesMiddlewares } from "./admin/fulfillment-sets/middlewares"
|
||||||
|
import { adminFulfillmentsRoutesMiddlewares } from "./admin/fulfillments/middlewares"
|
||||||
import { adminInventoryRoutesMiddlewares } from "./admin/inventory-items/middlewares"
|
import { adminInventoryRoutesMiddlewares } from "./admin/inventory-items/middlewares"
|
||||||
import { adminInviteRoutesMiddlewares } from "./admin/invites/middlewares"
|
import { adminInviteRoutesMiddlewares } from "./admin/invites/middlewares"
|
||||||
import { adminPaymentRoutesMiddlewares } from "./admin/payments/middlewares"
|
import { adminPaymentRoutesMiddlewares } from "./admin/payments/middlewares"
|
||||||
import { adminPriceListsRoutesMiddlewares } from "./admin/price-lists/middlewares"
|
import { adminPriceListsRoutesMiddlewares } from "./admin/price-lists/middlewares"
|
||||||
import { adminPricingRoutesMiddlewares } from "./admin/pricing/middlewares"
|
import { adminPricingRoutesMiddlewares } from "./admin/pricing/middlewares"
|
||||||
import { adminProductCategoryRoutesMiddlewares } from "./admin/product-categories/middlewares"
|
import { adminProductCategoryRoutesMiddlewares } from "./admin/product-categories/middlewares"
|
||||||
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
|
|
||||||
import { adminProductTypeRoutesMiddlewares } from "./admin/product-types/middlewares"
|
import { adminProductTypeRoutesMiddlewares } from "./admin/product-types/middlewares"
|
||||||
|
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
|
||||||
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
||||||
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
||||||
import { adminReservationRoutesMiddlewares } from "./admin/reservations/middlewares"
|
import { adminReservationRoutesMiddlewares } from "./admin/reservations/middlewares"
|
||||||
@@ -74,5 +75,6 @@ export const config: MiddlewaresConfig = {
|
|||||||
...adminProductCategoryRoutesMiddlewares,
|
...adminProductCategoryRoutesMiddlewares,
|
||||||
...adminReservationRoutesMiddlewares,
|
...adminReservationRoutesMiddlewares,
|
||||||
...adminShippingProfilesMiddlewares,
|
...adminShippingProfilesMiddlewares,
|
||||||
|
...adminFulfillmentsRoutesMiddlewares,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { DeleteResponse } from "../../../common"
|
||||||
import { AdminFulfillmentAddressResponse } from "./fulfillment-address"
|
import { AdminFulfillmentAddressResponse } from "./fulfillment-address"
|
||||||
import { AdminFulfillmentProviderResponse } from "./fulfillment-provider"
|
|
||||||
import { AdminFulfillmentItemResponse } from "./fulfillment-item"
|
import { AdminFulfillmentItemResponse } from "./fulfillment-item"
|
||||||
import { AdminFulfillmentLabelResponse } from "./fulfillment-label"
|
import { AdminFulfillmentLabelResponse } from "./fulfillment-label"
|
||||||
import { DeleteResponse } from "../../../common"
|
import { AdminFulfillmentProviderResponse } from "./fulfillment-provider"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @experimental
|
* @experimental
|
||||||
|
|||||||
Reference in new issue
Block a user