feat: Admin Shipping Profiles API (#7019)

This commit is contained in:
Oli Juhl
2024-04-09 11:03:37 +02:00
committed by GitHub
parent fbc2959b37
commit dbddfc12ed
21 changed files with 520 additions and 400 deletions

View File

@@ -1,346 +0,0 @@
const path = require("path")
const setupServer = require("../../../environment-helpers/setup-server")
const { useApi } = require("../../../environment-helpers/use-api")
const { initDb, useDb } = require("../../../environment-helpers/use-db")
const {
simpleProductFactory,
simpleShippingOptionFactory,
simpleShippingProfileFactory,
} = require("../../../factories")
const adminSeeder = require("../../../helpers/admin-seeder")
const adminReqConfig = {
headers: {
"x-medusa-access-token": "test_token",
},
}
jest.setTimeout(30000)
describe("/admin/shipping-profiles", () => {
let medusaProcess
let dbConnection
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd })
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
describe("GET /admin/shipping-profiles", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("lists shipping profiles", async () => {
const api = useApi()
const {
data: { shipping_profiles },
status,
} = await api.get("/admin/shipping-profiles", adminReqConfig)
expect(status).toEqual(200)
// Should contain default and gift_card profiles
expect(shipping_profiles.length).toEqual(2)
})
it("gets a shipping profile by id", async () => {
const api = useApi()
const profile = await simpleShippingProfileFactory(dbConnection)
const {
data: { shipping_profile },
status,
} = await api.get(
`/admin/shipping-profiles/${profile.id}`,
adminReqConfig
)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
...profile,
updated_at: expect.any(String),
created_at: expect.any(String),
})
)
})
})
describe("POST /admin/shipping-profiles", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("creates a custom shipping profile", async () => {
const api = useApi()
const payload = {
name: "test-profile-2023",
type: "custom",
}
const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})
it("creates a default shipping profile", async () => {
const api = useApi()
const payload = {
name: "test-profile-2023",
type: "default",
}
const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})
it("creates a gift_card shipping profile", async () => {
const api = useApi()
const payload = {
name: "test-profile-2023",
type: "gift_card",
}
const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})
it("creates a shipping profile with metadata", async () => {
const api = useApi()
const payload = {
name: "test-profile-2023",
type: "default",
metadata: {
custom_key: "custom_value",
},
}
const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
...payload,
})
)
})
it("fails to create a shipping profile with invalid type", async () => {
const api = useApi()
expect.assertions(2)
const payload = {
name: "test-profile-2023",
type: "invalid",
}
await api
.post("/admin/shipping-profiles", payload, adminReqConfig)
.catch((err) => {
expect(err.response.status).toEqual(400)
expect(err.response.data.message).toEqual(
"type must be one of 'default', 'custom', 'gift_card'"
)
})
})
it("updates a shipping profile", async () => {
const api = useApi()
const testProducts = await Promise.all(
[...Array(5).keys()].map(async () => {
return await simpleProductFactory(dbConnection)
})
)
const testShippingOptions = await Promise.all(
[...Array(5).keys()].map(async () => {
return await simpleShippingOptionFactory(dbConnection)
})
)
const payload = {
name: "test-profile-2023",
type: "custom",
metadata: {
my_key: "my_value",
},
}
const {
data: { shipping_profile: created },
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
const updatePayload = {
name: "test-profile-2023-updated",
products: testProducts.map((p) => p.id),
shipping_options: testShippingOptions.map((o) => o.id),
metadata: {
my_key: "",
my_new_key: "my_new_value",
},
}
const {
data: { shipping_profile },
status,
} = await api.post(
`/admin/shipping-profiles/${created.id}`,
updatePayload,
adminReqConfig
)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
name: "test-profile-2023-updated",
created_at: expect.any(String),
updated_at: expect.any(String),
metadata: {
my_new_key: "my_new_value",
},
deleted_at: null,
type: "custom",
})
)
const {
data: { products },
} = await api.get(`/admin/products`, adminReqConfig)
expect(products.length).toEqual(5)
expect(products).toEqual(
expect.arrayContaining(
testProducts.map((p) => {
return expect.objectContaining({
id: p.id,
profile_id: shipping_profile.id,
})
})
)
)
const {
data: { shipping_options },
} = await api.get(`/admin/shipping-options`, adminReqConfig)
const numberOfShippingOptionsWithProfile = shipping_options.filter(
(so) => so.profile_id === shipping_profile.id
).length
expect(numberOfShippingOptionsWithProfile).toEqual(5)
expect(shipping_options).toEqual(
expect.arrayContaining(
testShippingOptions.map((o) => {
return expect.objectContaining({
id: o.id,
profile_id: shipping_profile.id,
})
})
)
)
})
})
describe("DELETE /admin/shipping-profiles", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("deletes a shipping profile", async () => {
expect.assertions(2)
const api = useApi()
const profile = await simpleShippingProfileFactory(dbConnection)
const { status } = await api.delete(
`/admin/shipping-profiles/${profile.id}`,
adminReqConfig
)
expect(status).toEqual(200)
await api
.get(`/admin/shipping-profiles/${profile.id}`, adminReqConfig)
.catch((err) => {
expect(err.response.status).toEqual(404)
})
})
})
})

View File

@@ -0,0 +1,228 @@
import { medusaIntegrationTestRunner } from "medusa-test-utils"
import { breaking } from "../../../helpers/breaking"
import {
adminHeaders,
createAdminUser,
} from "../../../helpers/create-admin-user"
let {
simpleProductFactory,
simpleShippingOptionFactory,
simpleShippingProfileFactory,
} = {}
jest.setTimeout(30000)
medusaIntegrationTestRunner({
env: {
// MEDUSA_FF_MEDUSA_V2: true,
},
testSuite: ({ dbConnection, getContainer, api }) => {
let appContainer
beforeAll(() => {
;({
simpleProductFactory,
simpleShippingOptionFactory,
simpleShippingProfileFactory,
} = require("../../../factories"))
})
beforeEach(async () => {
appContainer = getContainer()
await createAdminUser(dbConnection, adminHeaders, appContainer)
})
describe("Admin - Shipping Profiles", () => {
// TODO: Missing update and delete tests
it("should test the entire lifecycle of a shipping profile", async () => {
const payload = {
name: "test-profile-2023",
type: "custom",
}
const {
data: { shipping_profile },
status,
} = await api.post("/admin/shipping-profiles", payload, adminHeaders)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
id: expect.any(String),
created_at: expect.any(String),
updated_at: expect.any(String),
...payload,
})
)
const {
data: { shipping_profiles },
} = await api.get("/admin/shipping-profiles", adminHeaders)
// In V1, response should contain default and gift_card profiles too
expect(shipping_profiles.length).toEqual(
breaking(
() => 3,
() => 1
)
)
const {
data: { shipping_profile: retrievedProfile },
} = await api.get(
`/admin/shipping-profiles/${shipping_profile.id}`,
adminHeaders
)
expect(status).toEqual(200)
expect(retrievedProfile).toEqual(
expect.objectContaining({
id: shipping_profile.id,
updated_at: expect.any(String),
created_at: expect.any(String),
})
)
})
})
describe("POST /admin/shipping-profiles", () => {
// TODO: There is no invalid types in V2 yet, so this will fail
it("fails to create a shipping profile with invalid type", async () => {
expect.assertions(2)
const payload = {
name: "test-profile-2023",
type: "invalid",
}
await api
.post("/admin/shipping-profiles", payload, adminHeaders)
.catch((err) => {
expect(err.response.status).toEqual(400)
expect(err.response.data.message).toEqual(
"type must be one of 'default', 'custom', 'gift_card'"
)
})
})
it("updates a shipping profile", async () => {
// TODO: Update is not added yet
const testProducts = await Promise.all(
[...Array(5).keys()].map(async () => {
return await simpleProductFactory(dbConnection)
})
)
const testShippingOptions = await Promise.all(
[...Array(5).keys()].map(async () => {
return await simpleShippingOptionFactory(dbConnection)
})
)
const payload = {
name: "test-profile-2023",
type: "custom",
metadata: {
my_key: "my_value",
},
}
const {
data: { shipping_profile: created },
} = await api.post("/admin/shipping-profiles", payload, adminHeaders)
const updatePayload = {
name: "test-profile-2023-updated",
products: testProducts.map((p) => p.id),
shipping_options: testShippingOptions.map((o) => o.id),
metadata: {
my_key: "",
my_new_key: "my_new_value",
},
}
const {
data: { shipping_profile },
status,
} = await api.post(
`/admin/shipping-profiles/${created.id}`,
updatePayload,
adminHeaders
)
expect(status).toEqual(200)
expect(shipping_profile).toEqual(
expect.objectContaining({
name: "test-profile-2023-updated",
created_at: expect.any(String),
updated_at: expect.any(String),
metadata: {
my_new_key: "my_new_value",
},
deleted_at: null,
type: "custom",
})
)
const {
data: { products },
} = await api.get(`/admin/products`, adminHeaders)
expect(products.length).toEqual(5)
expect(products).toEqual(
expect.arrayContaining(
testProducts.map((p) => {
return expect.objectContaining({
id: p.id,
profile_id: shipping_profile.id,
})
})
)
)
const {
data: { shipping_options },
} = await api.get(`/admin/shipping-options`, adminHeaders)
const numberOfShippingOptionsWithProfile = shipping_options.filter(
(so) => so.profile_id === shipping_profile.id
).length
expect(numberOfShippingOptionsWithProfile).toEqual(5)
expect(shipping_options).toEqual(
expect.arrayContaining(
testShippingOptions.map((o) => {
return expect.objectContaining({
id: o.id,
profile_id: shipping_profile.id,
})
})
)
)
})
})
describe("DELETE /admin/shipping-profiles", () => {
// TODO: Delete is not added yet
it("deletes a shipping profile", async () => {
expect.assertions(2)
const profile = await simpleShippingProfileFactory(dbConnection)
const { status } = await api.delete(
`/admin/shipping-profiles/${profile.id}`,
adminHeaders
)
expect(status).toEqual(200)
await api
.get(`/admin/shipping-profiles/${profile.id}`, adminHeaders)
.catch((err) => {
expect(err.response.status).toEqual(404)
})
})
})
},
})

View File

@@ -0,0 +1,36 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
CreateShippingProfileDTO,
IFulfillmentModuleService,
} from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
type StepInput = CreateShippingProfileDTO[]
export const createShippingProfilesStepId = "create-shipping-profiles"
export const createShippingProfilesStep = createStep(
createShippingProfilesStepId,
async (input: StepInput, { container }) => {
const service = container.resolve<IFulfillmentModuleService>(
ModuleRegistrationName.FULFILLMENT
)
const createdShippingProfiles = await service.createShippingProfiles(input)
return new StepResponse(
createdShippingProfiles,
createdShippingProfiles.map((created) => created.id)
)
},
async (createdShippingProfiles, { container }) => {
if (!createdShippingProfiles?.length) {
return
}
const service = container.resolve<IFulfillmentModuleService>(
ModuleRegistrationName.FULFILLMENT
)
await service.deleteShippingProfiles(createdShippingProfiles)
}
)

View File

@@ -4,4 +4,5 @@ export * from "./create-fulfillment-set"
export * from "./create-service-zones"
export * from "./upsert-shipping-options"
export * from "./delete-service-zones"
export * from "./create-shipping-profiles"
export * from "./remove-rules-from-fulfillment-shipping-option"

View File

@@ -0,0 +1,16 @@
import { FulfillmentWorkflow } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { createShippingProfilesStep } from "../steps"
export const createShippingProfilesWorkflowId =
"create-shipping-profiles-workflow"
export const createShippingProfilesWorkflow = createWorkflow(
createShippingProfilesWorkflowId,
(
input: WorkflowData<FulfillmentWorkflow.CreateShippingProfilesWorkflowInput>
): WorkflowData => {
const shippingProfiles = createShippingProfilesStep(input.data)
return shippingProfiles
}
)

View File

@@ -1,7 +1,8 @@
export * from "./add-rules-to-fulfillment-shipping-option"
export * from "./create-service-zones"
export * from "./create-shipping-options"
export * from "./update-shipping-options"
export * from "./create-shipping-profiles"
export * from "./delete-service-zones"
export * from "./remove-rules-from-fulfillment-shipping-option"
export * from "./update-service-zones"
export * from "./update-shipping-options"

View File

@@ -40,7 +40,7 @@ export const GET = async (
if (!service_zone) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Service zone with id ${req.params.zone_id} not found`
`Service zone with id: ${req.params.zone_id} not found`
)
}

View File

@@ -0,0 +1,26 @@
import { AdminShippingProfileResponse } from "@medusajs/types"
import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../types/routing"
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse<AdminShippingProfileResponse>
) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const query = remoteQueryObjectFromString({
entryPoint: "shipping_profiles",
variables: { id: req.params.id },
fields: req.remoteQueryConfig.fields,
})
const [shippingProfile] = await remoteQuery(query)
res.status(200).json({ shipping_profile: shippingProfile })
}

View File

@@ -0,0 +1,51 @@
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { authenticate } from "../../../utils/authenticate-middleware"
import { validateAndTransformBody } from "../../utils/validate-body"
import { validateAndTransformQuery } from "../../utils/validate-query"
import {
listTransformQueryConfig,
retrieveTransformQueryConfig,
} from "./query-config"
import {
AdminCreateShippingProfile,
AdminShippingProfileParams,
AdminShippingProfilesParams,
} from "./validators"
export const adminShippingProfilesMiddlewares: MiddlewareRoute[] = [
{
matcher: "/admin/shipping-profiles*",
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
},
{
method: ["POST"],
matcher: "/admin/shipping-profiles",
middlewares: [
validateAndTransformQuery(
AdminShippingProfilesParams,
retrieveTransformQueryConfig
),
validateAndTransformBody(AdminCreateShippingProfile),
],
},
{
method: ["GET"],
matcher: "/admin/shipping-profiles",
middlewares: [
validateAndTransformQuery(
AdminShippingProfilesParams,
listTransformQueryConfig
),
],
},
{
method: ["GET"],
matcher: "/admin/shipping-profiles/:id",
middlewares: [
validateAndTransformQuery(
AdminShippingProfileParams,
retrieveTransformQueryConfig
),
],
},
]

View File

@@ -0,0 +1,18 @@
export const defaultAdminShippingProfileFields = [
"id",
"name",
"type",
"metadata",
"created_at",
"updated_at",
]
export const retrieveTransformQueryConfig = {
defaults: defaultAdminShippingProfileFields,
isList: false,
}
export const listTransformQueryConfig = {
...retrieveTransformQueryConfig,
isList: true,
}

View File

@@ -0,0 +1,71 @@
import { createShippingProfilesWorkflow } from "@medusajs/core-flows"
import {
AdminShippingProfileResponse,
AdminShippingProfilesResponse,
} from "@medusajs/types"
import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../types/routing"
import { AdminCreateShippingProfileType } from "./validators"
export const POST = async (
req: AuthenticatedMedusaRequest<AdminCreateShippingProfileType>,
res: MedusaResponse<AdminShippingProfileResponse>
) => {
const shippingProfilePayload = req.validatedBody
const { result, errors } = await createShippingProfilesWorkflow(
req.scope
).run({
input: { data: [shippingProfilePayload] },
throwOnError: false,
})
if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}
const shippingProfileId = result?.[0].id
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const query = remoteQueryObjectFromString({
entryPoint: "shipping_profiles",
variables: { id: shippingProfileId },
fields: req.remoteQueryConfig.fields,
})
const [shippingProfile] = await remoteQuery(query)
res.status(200).json({ shipping_profile: shippingProfile })
}
export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse<AdminShippingProfilesResponse>
) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const query = remoteQueryObjectFromString({
entryPoint: "shipping_profiles",
variables: {
filters: req.filterableFields,
...req.remoteQueryConfig.pagination,
},
fields: req.remoteQueryConfig.fields,
})
const { rows: shippingProfiles, metadata } = await remoteQuery(query)
res.status(200).json({
shipping_profiles: shippingProfiles,
count: metadata.count,
offset: metadata.skip,
limit: metadata.take,
})
}

View File

@@ -0,0 +1,25 @@
import { z } from "zod"
import { createFindParams, createSelectParams } from "../../utils/validators"
export const AdminShippingProfileParams = createSelectParams()
export const AdminShippingProfilesParams = createFindParams({
limit: 20,
offset: 0,
}).merge(
z.object({
type: z.string().optional(),
name: z.string().optional(),
})
)
export const AdminCreateShippingProfile = z
.object({
name: z.string(),
type: z.string(),
metadata: z.record(z.string(), z.unknown()).optional(),
})
.strict()
export type AdminCreateShippingProfileType = z.infer<
typeof AdminCreateShippingProfile
>

View File

@@ -19,6 +19,7 @@ import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
import { adminSalesChannelRoutesMiddlewares } from "./admin/sales-channels/middlewares"
import { adminShippingOptionRoutesMiddlewares } from "./admin/shipping-options/middlewares"
import { adminShippingProfilesMiddlewares } from "./admin/shipping-profiles/middlewares"
import { adminStockLocationRoutesMiddlewares } from "./admin/stock-locations/middlewares"
import { adminStoreRoutesMiddlewares } from "./admin/stores/middlewares"
import { adminTaxRateRoutesMiddlewares } from "./admin/tax-rates/middlewares"
@@ -69,5 +70,6 @@ export const config: MiddlewaresConfig = {
...adminUploadRoutesMiddlewares,
...adminFulfillmentSetsRoutesMiddlewares,
...adminProductCategoryRoutesMiddlewares,
...adminShippingProfilesMiddlewares,
],
}

View File

@@ -2,7 +2,6 @@ export * from "./api"
export * from "./api-v2"
export * from "./api/middlewares"
export * from "./interfaces"
export * from "./joiner-config"
export * from "./models"
export * from "./modules-config"
export * from "./services"

View File

@@ -1,5 +0,0 @@
import * as joinerConfigs from "./joiner-configs"
export const joinerConfig = Object.values(joinerConfigs).map(
(config) => config.default
)

View File

@@ -1 +0,0 @@
export * as shippingProfile from "./shipping-profile-service"

View File

@@ -1,29 +0,0 @@
import { ModuleJoinerConfig } from "@medusajs/types"
export default {
serviceName: "shippingProfileService",
primaryKeys: ["id"],
linkableKeys: { profile_id: "ShippingProfile" },
schema: `
scalar Date
scalar JSON
type ShippingProfile {
id: ID!
name: String!
type: String!
created_at: Date!
updated_at: Date!
deleted_at: Date
metadata: JSON
}
`,
alias: [
{
name: ["shipping_profile", "shipping_profiles"],
args: {
entity: "ShippingProfile",
},
},
],
} as ModuleJoinerConfig

View File

@@ -1,3 +1,12 @@
import {
MODULE_PACKAGE_NAMES,
MedusaApp,
MedusaAppMigrateUp,
MedusaAppOutput,
MedusaModule,
Modules,
ModulesDefinition,
} from "@medusajs/modules-sdk"
import {
CommonTypes,
InternalModuleDeclaration,
@@ -8,21 +17,11 @@ import {
import {
ContainerRegistrationKeys,
FlagRouter,
isObject,
MedusaV2Flag,
isObject,
} from "@medusajs/utils"
import {
MedusaApp,
MedusaAppMigrateUp,
MedusaAppOutput,
MedusaModule,
MODULE_PACKAGE_NAMES,
Modules,
ModulesDefinition,
} from "@medusajs/modules-sdk"
import { asValue } from "awilix"
import { joinerConfig } from "../joiner-config"
import { remoteQueryFetchData } from "../utils/remote-query-fetch-data"
export function mergeDefaultModules(
@@ -101,7 +100,6 @@ export async function migrateMedusaApp(
await MedusaAppMigrateUp({
modulesConfig: configModules,
servicesConfig: joinerConfig,
remoteFetchData: remoteQueryFetchData(container),
sharedContainer: container,
sharedResourcesConfig,
@@ -170,7 +168,6 @@ export const loadMedusaApp = async (
const medusaApp = await MedusaApp({
workerMode: configModule.projectConfig.worker_mode,
modulesConfig: configModules,
servicesConfig: joinerConfig,
remoteFetchData: remoteQueryFetchData(container),
sharedContainer: container,
sharedResourcesConfig,
@@ -291,7 +288,6 @@ export async function runModulesLoader({
await MedusaApp({
modulesConfig: configModules,
servicesConfig: joinerConfig,
remoteFetchData: remoteQueryFetchData(container),
sharedContainer: container,
sharedResourcesConfig,

View File

@@ -1,7 +1,9 @@
import { PaginatedResponse } from "../../../common"
/**
* @experimental
*/
export interface AdminShippingProfileResponse {
export interface ShippingProfileResponse {
id: string
name: string
type: string
@@ -10,3 +12,11 @@ export interface AdminShippingProfileResponse {
updated_at: Date
deleted_at: Date | null
}
export interface AdminShippingProfileResponse {
shipping_profile: ShippingProfileResponse
}
export interface AdminShippingProfilesResponse extends PaginatedResponse {
shipping_profiles: ShippingProfileResponse[]
}

View File

@@ -1,3 +1,4 @@
export * from "./create-shipping-options"
export * from "./update-shipping-options"
export * from "./service-zones"
export * from "./shipping-profiles"
export * from "./update-shipping-options"

View File

@@ -0,0 +1,20 @@
import { FilterableShippingProfileProps } from "../../fulfillment"
interface CreateShippingProfile {
name: string
type: string
}
export interface CreateShippingProfilesWorkflowInput {
data: CreateShippingProfile[]
}
interface UpdateShippingProfile {
name?: string
type?: string
}
export interface UpdateShippingProfilesWorkflowInput {
selector: FilterableShippingProfileProps
update: UpdateShippingProfile
}