Skip to content

Commit

Permalink
feat: Update service zone
Browse files Browse the repository at this point in the history
  • Loading branch information
olivermrbl committed Apr 7, 2024
1 parent 31b07ae commit 84c35dc
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 132 deletions.
131 changes: 75 additions & 56 deletions integration-tests/api/__tests__/admin/fulfillment-sets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ medusaIntegrationTestRunner({
})

describe("POST /admin/fulfillment-sets/:id/service-zones", () => {
it("should create a service zone for a fulfillment set", async () => {
it("should create, update, and delete a service zone for a fulfillment set", async () => {
const stockLocationResponse = await api.post(
`/admin/stock-locations`,
{
Expand Down Expand Up @@ -120,6 +120,77 @@ medusaIntegrationTestRunner({
]),
})
)

const serviceZoneId = fset.service_zones[0].id

const countryGeoZone = fset.service_zones[0].geo_zones.find(
(z) => z.type === "country"
)

// Updates an existing and creates a new one
const updateResponse = await api.post(
`/admin/fulfillment-sets/${fulfillmentSetId}/service-zones/${serviceZoneId}`,
{
name: "Test Zone Updated",
geo_zones: [
{
id: countryGeoZone.id,
country_code: "us",
type: "country",
},
{
country_code: "ca",
type: "country",
},
],
},
adminHeaders
)

const updatedFset = updateResponse.data.fulfillment_set

expect(updateResponse.status).toEqual(200)
expect(updatedFset).toEqual(
expect.objectContaining({
name: "Fulfillment Set",
type: "shipping",
service_zones: expect.arrayContaining([
expect.objectContaining({
id: serviceZoneId,
name: "Test Zone Updated",
fulfillment_set_id: updatedFset.id,
geo_zones: expect.arrayContaining([
expect.objectContaining({
id: countryGeoZone.id,
country_code: "us",
type: "country",
}),
expect.objectContaining({
country_code: "ca",
type: "country",
}),
]),
}),
]),
})
)

const deleteResponse = await api.delete(
`/admin/fulfillment-sets/${fulfillmentSetId}/service-zones/${serviceZoneId}`,
adminHeaders
)

expect(deleteResponse.status).toEqual(200)
expect(deleteResponse.data).toEqual(
expect.objectContaining({
id: serviceZoneId,
object: "service-zone",
deleted: true,
parent: expect.objectContaining({
id: fulfillmentSetId,
}),
})
)
})

it("should throw if invalid type is passed", async () => {
Expand Down Expand Up @@ -251,60 +322,6 @@ medusaIntegrationTestRunner({
})

describe("POST /admin/fulfillment-sets/:id/service-zones", () => {
it("should delete a service zone for a fulfillment set", async () => {
const stockLocationResponse = await api.post(
`/admin/stock-locations`,
{
name: "test location",
},
adminHeaders
)

const stockLocationId = stockLocationResponse.data.stock_location.id

const locationWithFSetResponse = await api.post(
`/admin/stock-locations/${stockLocationId}/fulfillment-sets?fields=id,*fulfillment_sets`,
{
name: "Fulfillment Set",
type: "shipping",
},
adminHeaders
)

const fulfillmentSetId =
locationWithFSetResponse.data.stock_location.fulfillment_sets[0].id

const response = await api.post(
`/admin/fulfillment-sets/${fulfillmentSetId}/service-zones`,
{
name: "Test Zone",
geo_zones: [],
},
adminHeaders
)

const fset = response.data.fulfillment_set

const serviceZoneId = fset.service_zones[0].id

const deleteResponse = await api.delete(
`/admin/fulfillment-sets/${fulfillmentSetId}/service-zones/${serviceZoneId}`,
adminHeaders
)

expect(deleteResponse.status).toEqual(200)
expect(deleteResponse.data).toEqual(
expect.objectContaining({
id: serviceZoneId,
object: "service-zone",
deleted: true,
parent: expect.objectContaining({
id: fulfillmentSetId,
}),
})
)
})

it("should throw when fulfillment set doesn't exist", async () => {
const deleteResponse = await api
.delete(
Expand All @@ -314,7 +331,9 @@ medusaIntegrationTestRunner({
.catch((e) => e.response)

expect(deleteResponse.status).toEqual(404)
expect(deleteResponse.data.message).toEqual("FulfillmentSet with id: foo was not found")
expect(deleteResponse.data.message).toEqual(
"FulfillmentSet with id: foo was not found"
)
})
})
})
Expand Down
44 changes: 44 additions & 0 deletions packages/core-flows/src/fulfillment/steps/update-service-zones.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { FulfillmentWorkflow, IFulfillmentModuleService } from "@medusajs/types"
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

type StepInput = FulfillmentWorkflow.UpdateServiceZonesWorkflowInput

export const updateServiceZonesStepId = "update-service-zones"
export const updateServiceZonesStep = createStep(
updateServiceZonesStepId,
async (input: StepInput, { container }) => {
const service = container.resolve<IFulfillmentModuleService>(
ModuleRegistrationName.FULFILLMENT
)

const { selects, relations } = getSelectsAndRelationsFromObjectArray([
input.update,
])

const prevData = await service.listServiceZones(input.selector, {
select: selects,
relations,
})

const updatedServiceZones = await service.updateServiceZones(
input.selector,
input.update
)

return new StepResponse(updatedServiceZones, prevData)
},
async (prevData, { container }) => {
if (!prevData?.length) {
return
}

const service = container.resolve<IFulfillmentModuleService>(
ModuleRegistrationName.FULFILLMENT
)

// TODO: Implement upsertServiceZones
// await service.upsertServiceZones(prevData)
}
)
3 changes: 2 additions & 1 deletion packages/core-flows/src/fulfillment/workflows/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./add-rules-to-fulfillment-shipping-option"
export * from "./create-service-zones"
export * from "./delete-service-zones"
export * from "./create-shipping-options"
export * from "./delete-service-zones"
export * from "./remove-rules-from-fulfillment-shipping-option"
export * from "./update-service-zones"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FulfillmentWorkflow } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { updateServiceZonesStep } from "../steps/update-service-zones"

export const updateServiceZonesWorkflowId = "update-service-zones-workflow"
export const updateServiceZonesWorkflow = createWorkflow(
updateServiceZonesWorkflowId,
(
input: WorkflowData<FulfillmentWorkflow.UpdateServiceZonesWorkflowInput>
): WorkflowData => {
const serviceZones = updateServiceZonesStep(input)

return serviceZones
}
)
50 changes: 37 additions & 13 deletions packages/fulfillment/src/services/fulfillment-module-service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Modules } from "@medusajs/modules-sdk"
import {
Context,
DAL,
Expand All @@ -11,20 +12,21 @@ import {
ModulesSdkTypes,
ShippingOptionDTO,
UpdateFulfillmentSetDTO,
UpdateServiceZoneDTO,
} from "@medusajs/types"
import {
arrayDifference,
EmitEvents,
FulfillmentUtils,
getSetDifference,
InjectManager,
InjectTransactionManager,
MedusaContext,
MedusaError,
ModulesSdkUtils,
arrayDifference,
getSetDifference,
isString,
promiseAll,
} from "@medusajs/utils"

import {
Fulfillment,
FulfillmentSet,
Expand All @@ -38,7 +40,6 @@ import {
import { isContextValid, validateRules } from "@utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
import FulfillmentProviderService from "./fulfillment-provider"
import { Modules } from "@medusajs/modules-sdk"

const generateMethodForModels = [
ServiceZone,
Expand Down Expand Up @@ -791,25 +792,46 @@ export default class FulfillmentModuleService<
}

updateServiceZones(
data: FulfillmentTypes.UpdateServiceZoneDTO[],
id: string,
data: FulfillmentTypes.UpdateServiceZoneDTO,
sharedContext?: Context
): Promise<FulfillmentTypes.ServiceZoneDTO[]>
): Promise<FulfillmentTypes.ServiceZoneDTO>
updateServiceZones(
selector: FulfillmentTypes.FilterableServiceZoneProps,
data: FulfillmentTypes.UpdateServiceZoneDTO,
sharedContext?: Context
): Promise<FulfillmentTypes.ServiceZoneDTO>
): Promise<FulfillmentTypes.ServiceZoneDTO[]>

@InjectManager("baseRepository_")
async updateServiceZones(
data:
| FulfillmentTypes.UpdateServiceZoneDTO[]
| FulfillmentTypes.UpdateServiceZoneDTO,
idOrSelector: string | FulfillmentTypes.FilterableServiceZoneProps,
data: FulfillmentTypes.UpdateServiceZoneDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<
FulfillmentTypes.ServiceZoneDTO[] | FulfillmentTypes.ServiceZoneDTO
> {
const normalizedInput: UpdateServiceZoneDTO[] = []

if (isString(idOrSelector)) {
normalizedInput.push({ id: idOrSelector, ...data })
} else {
const serviceZones = await this.serviceZoneService_.list(
{ ...idOrSelector },
{},
sharedContext
)

if (!serviceZones.length) {
return []
}

for (const serviceZone of serviceZones) {
normalizedInput.push({ id: serviceZone.id, ...data })
}
}

const updatedServiceZones = await this.updateServiceZones_(
data,
normalizedInput,
sharedContext
)

Expand Down Expand Up @@ -873,7 +895,7 @@ export default class FulfillmentModuleService<

data_.forEach((serviceZone) => {
if (serviceZone.geo_zones) {
const existingServiceZone = serviceZoneMap.get(serviceZone.id)!
const existingServiceZone = serviceZoneMap.get(serviceZone.id!)!
const existingGeoZones = existingServiceZone.geo_zones
const updatedGeoZones = serviceZone.geo_zones
const toDeleteGeoZoneIds = getSetDifference(
Expand Down Expand Up @@ -920,7 +942,9 @@ export default class FulfillmentModuleService<
FulfillmentModuleService.validateGeoZones([geoZone])
return geoZone
}
return geoZonesMap.get(geoZone.id)!
const existing = geoZonesMap.get(geoZone.id)!

return { ...existing, ...geoZone }
})
}
})
Expand Down
Loading

0 comments on commit 84c35dc

Please sign in to comment.