Merge branch 'develop' into fix/2152

This commit is contained in:
Harminder Virk
2024-05-17 09:54:37 +05:30
62 changed files with 1838 additions and 1176 deletions
-1
View File
@@ -28,7 +28,6 @@
"@medusajs/utils": "workspace:^",
"@medusajs/workflow-engine-inmemory": "workspace:*",
"faker": "^5.5.3",
"medusa-interfaces": "workspace:*",
"pg": "^8.11.0",
"typeorm": "^0.3.16"
},
@@ -0,0 +1,473 @@
import { ModuleRegistrationName, Modules } from "@medusajs/modules-sdk"
import {
FulfillmentWorkflow,
IOrderModuleService,
IRegionModuleService,
IStockLocationServiceNext,
OrderWorkflow,
ProductDTO,
RegionDTO,
ShippingOptionDTO,
StockLocationDTO,
} from "@medusajs/types"
import { medusaIntegrationTestRunner } from "medusa-test-utils/dist"
import {
createReturnOrderWorkflow,
createShippingOptionsWorkflow,
} from "@medusajs/core-flows"
import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
RuleOperator,
} from "@medusajs/utils"
jest.setTimeout(500000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const providerId = "manual_test-provider"
async function prepareDataFixtures({ container }) {
const fulfillmentService = container.resolve(
ModuleRegistrationName.FULFILLMENT
)
const salesChannelService = container.resolve(
ModuleRegistrationName.SALES_CHANNEL
)
const stockLocationModule: IStockLocationServiceNext = container.resolve(
ModuleRegistrationName.STOCK_LOCATION
)
const productModule = container.resolve(ModuleRegistrationName.PRODUCT)
const inventoryModule = container.resolve(ModuleRegistrationName.INVENTORY)
const shippingProfile = await fulfillmentService.createShippingProfiles({
name: "test",
type: "default",
})
const fulfillmentSet = await fulfillmentService.create({
name: "Test fulfillment set",
type: "manual_test",
})
const serviceZone = await fulfillmentService.createServiceZones({
name: "Test service zone",
fulfillment_set_id: fulfillmentSet.id,
geo_zones: [
{
type: "country",
country_code: "US",
},
],
})
const regionService = container.resolve(
ModuleRegistrationName.REGION
) as IRegionModuleService
const [region] = await regionService.create([
{
name: "Test region",
currency_code: "eur",
countries: ["fr"],
},
])
const salesChannel = await salesChannelService.create({
name: "Webshop",
})
const location: StockLocationDTO = await stockLocationModule.create({
name: "Warehouse",
address: {
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
phone: "12345",
},
})
const [product] = await productModule.create([
{
title: "Test product",
variants: [
{
title: "Test variant",
sku: "test-variant",
},
],
},
])
const inventoryItem = await inventoryModule.create({
sku: "inv-1234",
})
await inventoryModule.createInventoryLevels([
{
inventory_item_id: inventoryItem.id,
location_id: location.id,
stocked_quantity: 2,
reserved_quantity: 0,
},
])
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
await remoteLink.create([
{
[Modules.STOCK_LOCATION]: {
stock_location_id: location.id,
},
[Modules.FULFILLMENT]: {
fulfillment_set_id: fulfillmentSet.id,
},
},
{
[Modules.SALES_CHANNEL]: {
sales_channel_id: salesChannel.id,
},
[Modules.STOCK_LOCATION]: {
stock_location_id: location.id,
},
},
{
[Modules.PRODUCT]: {
variant_id: product.variants[0].id,
},
[Modules.INVENTORY]: {
inventory_item_id: inventoryItem.id,
},
},
])
const shippingOptionData: FulfillmentWorkflow.CreateShippingOptionsWorkflowInput =
{
name: "Return shipping option",
price_type: "flat",
service_zone_id: serviceZone.id,
shipping_profile_id: shippingProfile.id,
provider_id: providerId,
type: {
code: "manual-type",
label: "Manual Type",
description: "Manual Type Description",
},
prices: [
{
currency_code: "usd",
amount: 10,
},
{
region_id: region.id,
amount: 100,
},
],
rules: [
{
attribute: "is_return",
operator: RuleOperator.EQ,
value: '"true"',
},
],
}
const { result } = await createShippingOptionsWorkflow(container).run({
input: [shippingOptionData],
})
const remoteQueryObject = remoteQueryObjectFromString({
entryPoint: "shipping_option",
variables: {
id: result[0].id,
},
fields: [
"id",
"name",
"price_type",
"service_zone_id",
"shipping_profile_id",
"provider_id",
"data",
"metadata",
"type.*",
"created_at",
"updated_at",
"deleted_at",
"shipping_option_type_id",
"prices.*",
],
})
const remoteQuery = container.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const [createdShippingOption] = await remoteQuery(remoteQueryObject)
return {
shippingOption: createdShippingOption,
region,
salesChannel,
location,
product,
}
}
async function createOrderFixture({ container, product }) {
const orderService: IOrderModuleService = container.resolve(
ModuleRegistrationName.ORDER
)
let order = await orderService.create({
region_id: "test_region_idclear",
email: "foo@bar.com",
items: [
{
title: "Custom Item 2",
variant_sku: product.variants[0].sku,
variant_title: product.variants[0].title,
quantity: 1,
unit_price: 50,
adjustments: [
{
code: "VIP_25 ETH",
amount: "0.000000000000000005",
description: "VIP discount",
promotion_id: "prom_123",
provider_id: "coupon_kings",
},
],
} as any,
],
transactions: [
{
amount: 50, // TODO: check calculation, I think it should be 60 wit the shipping but the order total is 50
currency_code: "usd",
},
],
sales_channel_id: "test",
shipping_address: {
first_name: "Test",
last_name: "Test",
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
phone: "12345",
},
billing_address: {
first_name: "Test",
last_name: "Test",
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
},
shipping_methods: [
{
name: "Test shipping method",
amount: 10,
data: {},
tax_lines: [
{
description: "shipping Tax 1",
tax_rate_id: "tax_usa_shipping",
code: "code",
rate: 10,
},
],
adjustments: [
{
code: "VIP_10",
amount: 1,
description: "VIP discount",
promotion_id: "prom_123",
},
],
},
],
currency_code: "usd",
customer_id: "joe",
})
await orderService.addOrderAction([
{
action: "FULFILL_ITEM",
order_id: order.id,
version: order.version,
reference: "fullfilment",
reference_id: "fulfill_123",
details: {
reference_id: order.items![0].id,
quantity: 1,
},
},
{
action: "SHIP_ITEM",
order_id: order.id,
version: order.version,
reference: "fullfilment",
reference_id: "fulfill_123",
details: {
reference_id: order.items![0].id,
quantity: 1,
},
},
])
await orderService.applyPendingOrderActions(order.id)
order = await orderService.retrieve(order.id, {
relations: ["items"],
})
return order
}
medusaIntegrationTestRunner({
env,
testSuite: ({ getContainer }) => {
let container
beforeAll(() => {
container = getContainer()
})
describe("Create return order workflow", () => {
let shippingOption: ShippingOptionDTO
let region: RegionDTO
let location: StockLocationDTO
let product: ProductDTO
let orderService: IOrderModuleService
beforeEach(async () => {
const fixtures = await prepareDataFixtures({
container,
})
shippingOption = fixtures.shippingOption
region = fixtures.region
location = fixtures.location
product = fixtures.product
orderService = container.resolve(ModuleRegistrationName.ORDER)
})
it("should create a return order", async () => {
const order = await createOrderFixture({ container, product })
const createReturnOrderData: OrderWorkflow.CreateOrderReturnWorkflowInput =
{
order_id: order.id,
return_shipping: {
option_id: shippingOption.id,
},
items: [
{
id: order.items![0].id,
quantity: 1,
},
],
}
await createReturnOrderWorkflow(container).run({
input: createReturnOrderData,
throwOnError: false,
})
const remoteQuery = container.resolve(
ContainerRegistrationKeys.REMOTE_QUERY
)
const remoteQueryObject = remoteQueryObjectFromString({
entryPoint: "order",
variables: {
id: order.id,
},
fields: [
"*",
"items.*",
"shipping_methods.*",
"total",
"item_total",
"fulfillments.*",
],
})
const [returnOrder] = await remoteQuery(remoteQueryObject)
expect(returnOrder).toEqual(
expect.objectContaining({
id: expect.any(String),
display_id: 1,
region_id: "test_region_idclear",
customer_id: "joe",
version: 2,
sales_channel_id: "test", // TODO: What about order with a sales channel but a shipping option link to a stock from another channel?
status: "pending",
is_draft_order: false,
email: "foo@bar.com",
currency_code: "usd",
shipping_address_id: expect.any(String),
billing_address_id: expect.any(String),
items: [
expect.objectContaining({
id: order.items![0].id,
title: "Custom Item 2",
variant_sku: product.variants[0].sku,
variant_title: product.variants[0].title,
requires_shipping: true,
is_discountable: true,
is_tax_inclusive: false,
compare_at_unit_price: null,
unit_price: 50,
quantity: 1,
detail: expect.objectContaining({
id: expect.any(String),
order_id: expect.any(String),
version: 2,
item_id: expect.any(String),
quantity: 1,
fulfilled_quantity: 1,
shipped_quantity: 1,
return_requested_quantity: 1,
return_received_quantity: 0,
return_dismissed_quantity: 0,
written_off_quantity: 0,
}),
}),
],
shipping_methods: expect.arrayContaining([
expect.objectContaining({
id: expect.any(String),
name: "Test shipping method",
description: null,
is_tax_inclusive: false,
shipping_option_id: null,
amount: 10,
order_id: expect.any(String),
}),
expect.objectContaining({
id: expect.any(String),
name: shippingOption.name,
description: null,
is_tax_inclusive: false,
shipping_option_id: shippingOption.id,
amount: 10,
order_id: expect.any(String),
}),
]),
fulfillments: [
expect.objectContaining({
id: expect.any(String),
location_id: location.id,
provider_id: providerId,
shipping_option_id: shippingOption.id,
// TODO: Validate the address once we are fixed on it
/*delivery_address: {
id: "fuladdr_01HY0RTAP0P1EEAFK7BXJ0BKBN",
},*/
}),
],
})
)
})
})
},
})
-1
View File
@@ -31,7 +31,6 @@
"@medusajs/utils": "workspace:^",
"@medusajs/workflow-engine-inmemory": "workspace:*",
"faker": "^5.5.3",
"medusa-interfaces": "workspace:*",
"medusa-test-utils": "workspace:*",
"pg": "^8.11.0",
"typeorm": "^0.3.16"
@@ -62,6 +62,7 @@
},
"actions": {
"save": "Save",
"select": "Select",
"saveAsDraft": "Save as draft",
"publish": "Publish",
"create": "Create",
@@ -653,8 +654,8 @@
}
},
"shipping": {
"title": "Location & Shipping",
"domain": "Location & Shipping",
"title": "Locations & Shipping",
"domain": "Locations & Shipping",
"description": "Choose where you ship and how much you charge for shipping at checkout. Define shipping options specific for your locations.",
"createLocation": "Create location",
"createLocationDetailsHint": "Specify the details of the location.",
@@ -714,10 +715,12 @@
"edit": {
"title": "Edit Service Zone"
},
"editAreasTitle": "Manage {{zone}} areas",
"deleteWarning": "Are you sure you want to delete \"{{name}}\". This will also delete all assocciated shipping options.",
"toast": {
"delete": "Zone \"{{name}}\" deleted successfully."
},
"manageAreas": "Manage areas",
"editPrices": "Edit prices",
"editOption": "Edit option",
"optionsLength_one": "shipping option",
@@ -745,8 +748,8 @@
"allocation": "Shipping amount",
"fixed": "Fixed",
"fixedDescription": "Shipping option's price is always the same amount.",
"enable": "Enable in store",
"enableDescription": "Enable or disable the shipping option visiblity in store",
"enable": "Show publicly",
"enableDescription": "When disabled, the shipping option can only be applied by admins.",
"calculated": "Calculated",
"calculatedDescription": "Shipping option's price is calculated by the fulfillment provider.",
"profile": "Shipping profile"
@@ -41,7 +41,7 @@ export const useStockLocation = (
) => {
const { data, ...rest } = useQuery({
queryFn: () => client.stockLocations.retrieve(id, query),
queryKey: stockLocationsQueryKeys.detail(id, query),
queryKey: stockLocationsQueryKeys.details(),
...options,
})
@@ -744,6 +744,13 @@ export const RouteMap: RouteObject[] = [
"../../v2-routes/shipping/service-zone-edit"
),
},
{
path: "edit-areas",
lazy: () =>
import(
"../../v2-routes/shipping/service-zone-areas-edit"
),
},
{
path: "shipping-option",
children: [
@@ -764,6 +771,13 @@ export const RouteMap: RouteObject[] = [
"../../v2-routes/shipping/shipping-option-edit"
),
},
{
path: "edit-pricing",
lazy: () =>
import(
"../../v2-routes/shipping/shipping-options-edit-pricing"
),
},
],
},
],
@@ -156,7 +156,7 @@ function ShippingOption({
{
label: t("shipping.serviceZone.editPrices"),
icon: <CurrencyDollar />,
disabled: true,
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/edit-pricing`,
},
{
label: t("actions.delete"),
@@ -199,7 +199,7 @@ function ServiceZoneOptions({
{t("shipping.serviceZone.shippingOptions")}
</span>
<Button
className="text-ui-fg-interactive txt-small px-0 font-medium hover:bg-transparent"
className="text-ui-fg-interactive txt-small px-0 font-medium hover:bg-transparent active:bg-transparent"
variant="transparent"
onClick={() =>
navigate(
@@ -231,7 +231,7 @@ function ServiceZoneOptions({
{t("shipping.serviceZone.returnOptions")}
</span>
<Button
className="text-ui-fg-interactive txt-small px-0 font-medium hover:bg-transparent"
className="text-ui-fg-interactive txt-small px-0 font-medium hover:bg-transparent active:bg-transparent"
variant="transparent"
onClick={() =>
navigate(
@@ -313,6 +313,7 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
.filter((g) => g.type === "country")
.map((g) => g.country_code)
.map((code) => staticCountries.find((c) => c.iso_2 === code))
.sort((c1, c2) => c1.name.localeCompare(c2.name))
}, zone.geo_zones)
const [shippingOptionsCount, returnOptionsCount] = useMemo(() => {
@@ -385,16 +386,16 @@ function ServiceZone({ zone, locationId, fulfillmentSetId }: ServiceZoneProps) {
groups={[
{
actions: [
// {
// label: t("shipping.serviceZone.addOption"),
// icon: <Plus />,
// to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/shipping-option/create`,
// },
{
label: t("actions.edit"),
icon: <PencilSquare />,
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/edit`,
},
{
label: t("shipping.serviceZone.manageAreas"),
icon: <Map />,
to: `/settings/shipping/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${zone.id}/edit-areas`,
},
{
label: t("actions.delete"),
icon: <Trash />,
@@ -181,7 +181,7 @@ function Location(props: LocationProps) {
]}
/>
<Button
className="text-ui-fg-interactive rounded-none pl-5 hover:bg-transparent"
className="text-ui-fg-interactive rounded-none pl-5 hover:bg-transparent active:bg-transparent"
onClick={() => navigate(`/settings/shipping/${location.id}`)}
variant="transparent"
>
@@ -0,0 +1,344 @@
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import {
ColumnDef,
createColumnHelper,
RowSelectionState,
} from "@tanstack/react-table"
import * as zod from "zod"
import {
Alert,
Badge,
Button,
Checkbox,
Heading,
IconButton,
Text,
toast,
} from "@medusajs/ui"
import { RegionCountryDTO, RegionDTO, ServiceZoneDTO } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import { XMarkMini } from "@medusajs/icons"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
import { SplitView } from "../../../../../components/layout/split-view"
import {
useCreateServiceZone,
useUpdateServiceZone,
} from "../../../../../hooks/api/stock-locations"
import { useEffect, useMemo, useState } from "react"
import { useCountryTableQuery } from "../../../../regions/common/hooks/use-country-table-query"
import { useCountries } from "../../../../regions/common/hooks/use-countries"
import { countries as staticCountries } from "../../../../../lib/countries"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { useCountryTableColumns } from "../../../../regions/common/hooks/use-country-table-columns"
import { DataTable } from "../../../../../components/table/data-table"
const PREFIX = "ac"
const PAGE_SIZE = 50
const ConditionsFooter = ({ onSave }: { onSave: () => void }) => {
const { t } = useTranslation()
return (
<div className="flex items-center justify-end gap-x-2 border-t p-4">
<SplitView.Close type="button" asChild>
<Button variant="secondary" size="small">
{t("actions.cancel")}
</Button>
</SplitView.Close>
<Button size="small" type="button" onClick={onSave}>
{t("actions.select")}
</Button>
</div>
)
}
const EditeServiceZoneSchema = zod.object({
countries: zod.array(zod.string().length(2)).min(1),
})
type EditServiceZoneAreasFormProps = {
fulfillmentSetId: string
locationId: string
zone: ServiceZoneDTO
}
export function EditServiceZoneAreasForm({
fulfillmentSetId,
locationId,
zone,
}: EditServiceZoneAreasFormProps) {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const [open, setOpen] = useState(false)
const [rowSelection, setRowSelection] = useState<RowSelectionState>(
zone.geo_zones
.map((z) => z.country_code)
.reduce((acc, v) => {
acc[v] = true
return acc
}, {})
)
const form = useForm<zod.infer<typeof EditeServiceZoneSchema>>({
defaultValues: {
countries: zone.geo_zones.map((z) => z.country_code),
},
resolver: zodResolver(EditeServiceZoneSchema),
})
const { mutateAsync: editServiceZone, isPending: isLoading } =
useUpdateServiceZone(fulfillmentSetId, zone.id, locationId)
const handleSubmit = form.handleSubmit(async (data) => {
try {
await editServiceZone({
geo_zones: data.countries.map((iso2) => ({
country_code: iso2,
type: "country",
})),
})
} catch (e) {
toast.error(t("general.error"), {
description: e.message,
dismissLabel: t("general.close"),
})
}
handleSuccess()
})
const handleOpenChange = (open: boolean) => {
setOpen(open)
}
const { searchParams, raw } = useCountryTableQuery({
pageSize: PAGE_SIZE,
prefix: PREFIX,
})
const { countries, count } = useCountries({
countries: staticCountries.map((c, i) => ({
display_name: c.display_name,
name: c.name,
id: i as any,
iso_2: c.iso_2,
iso_3: c.iso_3,
num_code: c.num_code,
region_id: null,
region: {} as RegionDTO,
})),
...searchParams,
})
const columns = useColumns()
const { table } = useDataTable({
data: countries || [],
columns,
count,
enablePagination: true,
enableRowSelection: true,
getRowId: (row) => row.iso_2,
pageSize: PAGE_SIZE,
rowSelection: {
state: rowSelection,
updater: setRowSelection,
},
prefix: PREFIX,
})
const countriesWatch = form.watch("countries")
const onCountriesSave = () => {
form.setValue("countries", Object.keys(rowSelection))
setOpen(false)
}
const removeCountry = (iso2: string) => {
const state = { ...rowSelection }
delete state[iso2]
setRowSelection(state)
form.setValue(
"countries",
countriesWatch.filter((c) => c !== iso2)
)
}
const clearAll = () => {
setRowSelection({})
form.setValue("countries", [])
}
const selectedCountries = useMemo(() => {
return staticCountries.filter((c) => c.iso_2 in rowSelection)
}, [countriesWatch])
useEffect(() => {
// set selected rows from form state on open
if (open) {
setRowSelection(
countriesWatch.reduce((acc, c) => {
acc[c] = true
return acc
}, {})
)
}
}, [open])
const showAreasError =
form.formState.errors["countries"]?.type === "too_small"
return (
<RouteFocusModal.Form form={form}>
<form
className="flex h-full flex-col overflow-hidden"
onSubmit={handleSubmit}
>
<RouteFocusModal.Header>
<div className="flex items-center justify-end gap-x-2">
<RouteFocusModal.Close asChild>
<Button variant="secondary" size="small">
{t("actions.cancel")}
</Button>
</RouteFocusModal.Close>
<Button type="submit" size="small" isLoading={isLoading}>
{t("actions.save")}
</Button>
</div>
</RouteFocusModal.Header>
<RouteFocusModal.Body className="m-auto flex h-full w-full flex-col items-center divide-y overflow-hidden">
<SplitView open={open} onOpenChange={handleOpenChange}>
<SplitView.Content className="mx-auto max-w-[720px]">
<div className="container w-fit px-1 py-8">
<Heading className="mt-8 text-2xl">
{t("shipping.serviceZone.editAreasTitle", {
zone: zone.name,
})}
</Heading>
</div>
<div className="container flex items-center justify-between py-8 pr-1">
<div>
<Text weight="plus">
{t("shipping.serviceZone.areas.title")}
</Text>
<Text className="text-ui-fg-subtle mt-2">
{t("shipping.serviceZone.areas.description")}
</Text>
</div>
<Button
onClick={() => setOpen(true)}
variant="secondary"
type="button"
>
{t("shipping.serviceZone.areas.manage")}
</Button>
</div>
{!!selectedCountries.length && (
<div className="flex flex-wrap items-center gap-4">
{selectedCountries.map((c) => (
<Badge
key={c.iso_2}
className="text-ui-fg-subtle txt-small flex items-center gap-1 divide-x pr-0"
>
{c.display_name}
<IconButton
type="button"
onClick={() => removeCountry(c.iso_2)}
className="text-ui-fg-subtle p-0 px-1 pt-[1px]"
variant="transparent"
>
<XMarkMini />
</IconButton>
</Badge>
))}
<Button
type="button"
onClick={clearAll}
variant="transparent"
className="txt-small text-ui-fg-muted font-medium"
>
{t("actions.clearAll")}
</Button>
</div>
)}
{showAreasError && (
<Alert dismissible variant="error">
{t("shipping.serviceZone.areas.error")}
</Alert>
)}
</SplitView.Content>
<SplitView.Drawer>
<div className="flex size-full flex-col overflow-hidden">
<DataTable
table={table}
columns={columns}
pageSize={PAGE_SIZE}
count={count}
search
pagination
layout="fill"
orderBy={["name", "code"]}
queryObject={raw}
prefix={PREFIX}
/>
<ConditionsFooter onSave={onCountriesSave} />
</div>
</SplitView.Drawer>
</SplitView>
</RouteFocusModal.Body>
</form>
</RouteFocusModal.Form>
)
}
const columnHelper = createColumnHelper<RegionCountryDTO>()
const useColumns = () => {
const base = useCountryTableColumns()
return useMemo(
() => [
columnHelper.display({
id: "select",
header: ({ table }) => {
return (
<Checkbox
checked={
table.getIsSomePageRowsSelected()
? "indeterminate"
: table.getIsAllPageRowsSelected()
}
onCheckedChange={(value) =>
table.toggleAllPageRowsSelected(!!value)
}
/>
)
},
cell: ({ row }) => {
const isPreselected = !row.getCanSelect()
return (
<Checkbox
checked={row.getIsSelected() || isPreselected}
disabled={isPreselected}
onCheckedChange={(value) => row.toggleSelected(!!value)}
onClick={(e) => {
e.stopPropagation()
}}
/>
)
},
}),
...base,
],
[base]
) as ColumnDef<RegionCountryDTO>[]
}
@@ -0,0 +1 @@
export * from "./edit-service-zone-areas-form"
@@ -0,0 +1 @@
export { ServiceZoneAreasEdit as Component } from "./service-zone-areas-edit"
@@ -0,0 +1,45 @@
import { json, useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { EditServiceZoneAreasForm } from "./components/edit-region-areas-form"
import { useStockLocation } from "../../../hooks/api/stock-locations"
export const ServiceZoneAreasEdit = () => {
const { location_id, fset_id, zone_id } = useParams()
const { stock_location, isPending, isError, error } = useStockLocation(
location_id!,
{
// NOTE: use same query for all details page subroutes & fetches
fields:
"name,*sales_channels,address.city,address.country_code,fulfillment_sets.type,fulfillment_sets.name,*fulfillment_sets.service_zones.geo_zones,*fulfillment_sets.service_zones,*fulfillment_sets.service_zones.shipping_options,*fulfillment_sets.service_zones.shipping_options.rules,*fulfillment_sets.service_zones.shipping_options.shipping_profile",
}
)
const zone = stock_location?.fulfillment_sets
.find((f) => f.id === fset_id)
?.service_zones.find((z) => z.id === zone_id)
if (isError) {
throw error
}
if (!isPending && !zone) {
throw json(
{ message: `Service zone with ID ${zone_id} was not found` },
404
)
}
return (
<RouteFocusModal>
{!isPending && zone && (
<EditServiceZoneAreasForm
zone={zone}
fulfillmentSetId={fset_id}
locationId={location_id}
/>
)}
</RouteFocusModal>
)
}
@@ -16,10 +16,11 @@ import {
IconButton,
Input,
Text,
toast,
} from "@medusajs/ui"
import { FulfillmentSetDTO, RegionCountryDTO, RegionDTO } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import { Map, XMark, XMarkMini } from "@medusajs/icons"
import { XMarkMini } from "@medusajs/icons"
import {
RouteFocusModal,
@@ -87,13 +88,20 @@ export function CreateServiceZoneForm({
useCreateServiceZone(locationId, fulfillmentSet.id)
const handleSubmit = form.handleSubmit(async (data) => {
await createServiceZone({
name: data.name,
geo_zones: data.countries.map((iso2) => ({
country_code: iso2,
type: "country",
})),
})
try {
await createServiceZone({
name: data.name,
geo_zones: data.countries.map((iso2) => ({
country_code: iso2,
type: "country",
})),
})
} catch (e) {
toast.error(t("general.error"), {
description: e.message,
dismissLabel: t("general.close"),
})
}
handleSuccess()
})
@@ -201,7 +209,7 @@ export function CreateServiceZoneForm({
<RouteFocusModal.Body className="m-auto flex h-full w-full flex-col items-center divide-y overflow-hidden">
<SplitView open={open} onOpenChange={handleOpenChange}>
<SplitView.Content className="mx-auto max-w-[720px]">
<div className="container w-fit px-1 py-8">
<div className="container w-fit px-1 py-8">
<Heading className="mb-12 mt-8 text-2xl">
{t("shipping.fulfillmentSet.create.title", {
fulfillmentSet: fulfillmentSet.name,
@@ -6,7 +6,9 @@ import { StockLocationRes } from "../../../types/api-responses"
import { stockLocationsQueryKeys } from "../../../hooks/api/stock-locations"
const fulfillmentSetCreateQuery = (id: string) => ({
queryKey: stockLocationsQueryKeys.detail(id),
queryKey: stockLocationsQueryKeys.detail(id, {
fields: "*fulfillment_sets",
}),
queryFn: async () =>
client.stockLocations.retrieve(id, {
fields: "*fulfillment_sets",
@@ -45,7 +45,7 @@ type StepStatus = {
[key in Tab]: ProgressStatus
}
const CreateServiceZoneSchema = zod.object({
const CreateShippingOptionSchema = zod.object({
name: zod.string().min(1),
price_type: zod.nativeEnum(ShippingAllocation),
enabled_in_store: zod.boolean().optional(),
@@ -55,7 +55,7 @@ const CreateServiceZoneSchema = zod.object({
currency_prices: zod.record(zod.string(), zod.string().optional()),
})
type CreateServiceZoneFormProps = {
type CreateShippingOptionFormProps = {
zone: ServiceZoneDTO
isReturn?: boolean
}
@@ -63,7 +63,7 @@ type CreateServiceZoneFormProps = {
export function CreateShippingOptionsForm({
zone,
isReturn,
}: CreateServiceZoneFormProps) {
}: CreateShippingOptionFormProps) {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const [tab, setTab] = React.useState<Tab>(Tab.DETAILS)
@@ -77,7 +77,7 @@ export function CreateShippingOptionsForm({
fields: "id,currency_code",
})
const form = useForm<zod.infer<typeof CreateServiceZoneSchema>>({
const form = useForm<zod.infer<typeof CreateShippingOptionSchema>>({
defaultValues: {
name: "",
price_type: ShippingAllocation.FlatRate,
@@ -87,7 +87,7 @@ export function CreateShippingOptionsForm({
region_prices: {},
currency_prices: {},
},
resolver: zodResolver(CreateServiceZoneSchema),
resolver: zodResolver(CreateShippingOptionSchema),
})
const isCalculatedPriceType =
@@ -6,7 +6,10 @@ import { StockLocationRes } from "../../../types/api-responses"
import { stockLocationsQueryKeys } from "../../../hooks/api/stock-locations"
const fulfillmentSetCreateQuery = (id: string) => ({
queryKey: stockLocationsQueryKeys.list(), // Use the list cache key for now
queryKey: stockLocationsQueryKeys.detail(id, {
fields:
"*fulfillment_sets,*fulfillment_sets.service_zones,*fulfillment_sets.service_zones.shipping_options",
}),
queryFn: async () =>
client.stockLocations.retrieve(id, {
fields:
@@ -0,0 +1,319 @@
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import React, { useEffect, useMemo, useState } from "react"
import * as zod from "zod"
import { Button, toast } from "@medusajs/ui"
import {
CurrencyDTO,
PriceDTO,
ProductVariantDTO,
RegionDTO,
ShippingOptionDTO,
} from "@medusajs/types"
import { useTranslation } from "react-i18next"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/route-modal"
import {
getDbAmount,
getPresentationalAmount,
} from "../../../../../lib/money-amount-helpers"
import { useRegions } from "../../../../../hooks/api/regions"
import { useStore } from "../../../../../hooks/api/store.tsx"
import { useCurrencies } from "../../../../../hooks/api/currencies"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { CurrencyCell } from "../../../../../components/grid/grid-cells/common/currency-cell"
import { DataGridMeta } from "../../../../../components/grid/types"
import { DataGrid } from "../../../../../components/grid/data-grid"
import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options.ts"
const getInitialCurrencyPrices = (prices: PriceDTO[]) => {
const ret: Record<string, number> = {}
prices.forEach((p) => {
if (p.price_rules!.length) {
// this is a region price
return
}
ret[p.currency_code!] = getPresentationalAmount(
p.amount as number,
p.currency_code!
)
})
return ret
}
const getInitialRegionPrices = (prices: PriceDTO[]) => {
const ret: Record<string, number> = {}
prices.forEach((p) => {
if (p.price_rules!.length) {
const regionId = p.price_rules![0].value
ret[regionId] = getPresentationalAmount(
p.amount as number,
p.currency_code!
)
}
})
return ret
}
const EditShippingOptionPricingSchema = zod.object({
region_prices: zod.record(
zod.string(),
zod.string().or(zod.number()).optional()
),
currency_prices: zod.record(
zod.string(),
zod.string().or(zod.number()).optional()
),
})
enum ColumnType {
REGION = "region",
CURRENCY = "currency",
}
type EnabledColumnRecord = Record<string, ColumnType>
type EditShippingOptionPricingFormProps = {
shippingOption: ShippingOptionDTO & { prices: PriceDTO[] }
}
export function EditShippingOptionsPricingForm({
shippingOption,
}: EditShippingOptionPricingFormProps) {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const form = useForm<zod.infer<typeof EditShippingOptionPricingSchema>>({
defaultValues: {
region_prices: getInitialRegionPrices(shippingOption.prices),
currency_prices: getInitialCurrencyPrices(shippingOption.prices),
},
resolver: zodResolver(EditShippingOptionPricingSchema),
})
const { mutateAsync, isPending: isLoading } = useUpdateShippingOptions(
shippingOption.id
)
const { regions } = useRegions()
const { store, isLoading: isStoreLoading } = useStore()
const { currencies, isLoading: isCurrenciesLoading } = useCurrencies(
{
code: store?.supported_currency_codes,
},
{
enabled: !!store,
}
)
const [enabledColumns, setEnabledColumns] = useState<EnabledColumnRecord>({})
useEffect(() => {
if (
store?.default_currency_code &&
Object.keys(enabledColumns).length === 0
) {
setEnabledColumns({
...enabledColumns,
[store.default_currency_code]: ColumnType.CURRENCY,
})
}
}, [store, enabledColumns])
const columns = useColumns({
currencies,
regions,
})
const data = useMemo(
() => [[...(currencies || []), ...(regions || [])]],
[currencies, regions]
)
const handleSubmit = form.handleSubmit(async (data) => {
const currencyPrices = Object.entries(data.currency_prices)
.map(([code, value]) => {
if (value === "") {
return undefined
}
const amount = getDbAmount(Number(value), code)
const priceRecord = {
currency_code: code,
amount: amount,
}
const price = shippingOption.prices.find(
(p) => p.currency_code === code && !p.price_rules!.length
)
// if that currency price is already defined for the SO, we will do an update
if (price) {
priceRecord["id"] = price.id
}
return priceRecord
})
.filter((p) => !!p)
const regionsMap = new Map(regions.map((r) => [r.id, r.currency_code]))
const regionPrices = Object.entries(data.region_prices)
.map(([region_id, value]) => {
if (value === "") {
return undefined
}
const code = regionsMap.get(region_id)!
const amount = getDbAmount(Number(value), code)
const priceRecord = {
region_id,
amount: amount,
}
/**
* HACK - when trying to update prices which already have a region price
* we get error: `Price rule with price_id: , rule_type_id: already exist`,
* so for now, we recreate region prices.
*/
// const price = shippingOption.prices.find(
// (p) => p.price_rules?.[0]?.value === region_id
// )
//
// if (price) {
// priceRecord["id"] = price.id
// }
return priceRecord
})
.filter((p) => !!p)
try {
await mutateAsync({
prices: [...currencyPrices, ...regionPrices],
})
toast.error(t("general.success"), {
dismissLabel: t("general.close"),
})
handleSuccess()
} catch (e) {
toast.error(t("general.error"), {
description: e.message,
dismissLabel: t("general.close"),
})
}
})
const initializing =
isStoreLoading || isCurrenciesLoading || !store || !currencies
return (
<RouteFocusModal.Form form={form}>
<form
className="flex h-full flex-col overflow-hidden"
onSubmit={handleSubmit}
>
<RouteFocusModal.Header>
<div className="flex items-center justify-end gap-x-2">
<RouteFocusModal.Close asChild>
<Button variant="secondary" size="small">
{t("actions.cancel")}
</Button>
</RouteFocusModal.Close>
<Button
size="small"
className="whitespace-nowrap"
isLoading={isLoading}
onClick={handleSubmit}
type="button"
>
{t("actions.save")}
</Button>
</div>
</RouteFocusModal.Header>
<RouteFocusModal.Body className="flex h-full w-fit overflow-auto">
<div
style={{ width: "100vw" }}
className="flex size-full flex-col divide-y"
>
<DataGrid
columns={columns}
data={data}
isLoading={initializing}
state={form}
/>
</div>
</RouteFocusModal.Body>
</form>
</RouteFocusModal.Form>
)
}
const columnHelper = createColumnHelper<
ExtendedProductDTO | ProductVariantDTO
>()
const useColumns = ({
currencies = [],
regions = [],
}: {
currencies?: CurrencyDTO[]
regions?: RegionDTO[]
}) => {
const { t } = useTranslation()
const colDefs: ColumnDef<ExtendedProductDTO | ProductVariantDTO>[] =
useMemo(() => {
return [
...currencies.map((currency) => {
return columnHelper.display({
header: t("fields.priceTemplate", {
regionOrCountry: currency.code.toUpperCase(),
}),
cell: ({ row, table }) => {
return (
<CurrencyCell
currency={currency}
meta={table.options.meta as DataGridMeta<any>}
field={`currency_prices.${currency.code}`}
/>
)
},
})
}),
...regions.map((region) => {
return columnHelper.display({
header: t("fields.priceTemplate", {
regionOrCountry: region.name,
}),
cell: ({ row, table }) => {
return (
<CurrencyCell
currency={currencies.find(
(c) => c.code === region.currency_code
)}
meta={table.options.meta as DataGridMeta<any>}
field={`region_prices.${region.id}`}
/>
)
},
})
}),
]
}, [t, currencies, regions])
return colDefs
}
@@ -0,0 +1 @@
export * from "./edit-shipping-options-pricing-form.tsx"
@@ -0,0 +1 @@
export { ShippingOptionsEditPricing as Component } from "./shipping-options-edit-pricing"
@@ -0,0 +1,30 @@
import { useParams } from "react-router-dom"
import { RouteFocusModal } from "../../../components/route-modal"
import { useShippingOptions } from "../../../hooks/api/shipping-options"
import { EditShippingOptionsPricingForm } from "./components/create-shipping-options-form"
export function ShippingOptionsEditPricing() {
const { so_id } = useParams()
const { shipping_options, isPending } = useShippingOptions({
// TODO: change this when GET option by id endpoint is implemented
id: [so_id],
fields: "*prices,*prices.price_rules",
limit: 999,
})
const shippingOption = shipping_options?.find((so) => so.id === so_id)
if (!isPending && !shippingOption) {
throw new Error(`Shipping option with id: ${so_id} not found`)
}
return (
<RouteFocusModal>
{shippingOption && (
<EditShippingOptionsPricingForm shippingOption={shippingOption} />
)}
</RouteFocusModal>
)
}
+2 -2
View File
@@ -52,13 +52,13 @@ git checkout package.json; npm install --force
You can prevent the automatic dependencies scan and instead specify a list of
packages you want to link by using the `--packages` option:
`medusa-dev --packages @medusajs/medusa medusa-interfaces`
`medusa-dev --packages @medusajs/medusa`
#### `--scan-once`
With this flag, the tool will do an initial scan and copy and then quit. This is
useful for setting up automated testing/builds of Medusa projects from the latest
code.
code.
#### `--quiet`
@@ -1,2 +1,3 @@
export * from "./steps/remove-remote-links"
export * from "./steps/use-remote-query"
export * from "./steps/create-remote-links"
@@ -0,0 +1,29 @@
import { LinkDefinition, RemoteLink } from "@medusajs/modules-sdk"
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
import { ContainerRegistrationKeys } from "@medusajs/utils"
type CreateRemoteLinksStepInput = LinkDefinition[]
export const createLinksStepId = "create-links"
export const createLinkStep = createStep(
createLinksStepId,
async (data: CreateRemoteLinksStepInput, { container }) => {
const link = container.resolve<RemoteLink>(
ContainerRegistrationKeys.REMOTE_LINK
)
await link.create(data)
return new StepResponse(data, data)
},
async (createdLinks, { container }) => {
if (!createdLinks) {
return
}
const link = container.resolve<RemoteLink>(
ContainerRegistrationKeys.REMOTE_LINK
)
await link.dismiss(createdLinks)
}
)
@@ -0,0 +1,29 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { CreateOrderReturnDTO, IOrderModuleService } from "@medusajs/types"
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
type CreateReturnStepInput = CreateOrderReturnDTO
export const createReturnStepId = "create-return"
export const createReturnStep = createStep(
createReturnStepId,
async (data: CreateReturnStepInput, { container }) => {
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
const created = await service.createReturn(data)
return new StepResponse(created, created)
},
async (createdId, { container }) => {
if (!createdId) {
return
}
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
// TODO: delete return
}
)
@@ -6,12 +6,12 @@ import {
OrderShippingMethodDTO,
OrderWorkflowDTO,
ShippingTaxLineDTO,
TaxCalculationContext,
TaxableItemDTO,
TaxableShippingDTO,
TaxCalculationContext,
} from "@medusajs/types"
import { MedusaError } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
interface StepInput {
order: OrderWorkflowDTO
@@ -104,8 +104,8 @@ export const getOrderItemTaxLinesStep = createStep(
async (data: StepInput, { container }) => {
const {
order,
items,
shipping_methods: shippingMethods,
items = [],
shipping_methods: shippingMethods = [],
force_tax_calculation: forceTaxCalculation = false,
} = data
const taxService = container.resolve<ITaxModuleService>(
@@ -123,15 +123,19 @@ export const getOrderItemTaxLinesStep = createStep(
return new StepResponse(stepResponseData)
}
stepResponseData.lineItemTaxLines = (await taxService.getTaxLines(
normalizeLineItemsForTax(order, items),
taxContext
)) as ItemTaxLineDTO[]
if (items.length) {
stepResponseData.lineItemTaxLines = (await taxService.getTaxLines(
normalizeLineItemsForTax(order, items),
taxContext
)) as ItemTaxLineDTO[]
}
stepResponseData.shippingMethodsTaxLines = (await taxService.getTaxLines(
normalizeLineItemsForShipping(order, shippingMethods),
taxContext
)) as ShippingTaxLineDTO[]
if (shippingMethods.length) {
stepResponseData.shippingMethodsTaxLines = (await taxService.getTaxLines(
normalizeLineItemsForShipping(order, shippingMethods),
taxContext
)) as ShippingTaxLineDTO[]
}
return new StepResponse(stepResponseData)
}
@@ -0,0 +1,339 @@
import {
CreateOrderShippingMethodDTO,
FulfillmentWorkflow,
OrderDTO,
OrderWorkflow,
ShippingOptionDTO,
WithCalculatedPrice,
} from "@medusajs/types"
import {
createWorkflow,
transform,
WorkflowData,
} from "@medusajs/workflows-sdk"
import { createLinkStep, useRemoteQueryStep } from "../../common"
import {
arrayDifference,
ContainerRegistrationKeys,
isDefined,
MathBN,
MedusaError,
Modules,
} from "@medusajs/utils"
import { updateOrderTaxLinesStep } from "../steps"
import { createReturnStep } from "../steps/create-return"
import { createFulfillmentWorkflow } from "../../fulfillment"
function throwIfOrderIsCancelled({ order }: { order: OrderDTO }) {
// TODO: need work, check canceled
if (false /*order.canceled_at*/) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order with id ${order.id} has been cancelled.`
)
}
}
function throwIfItemsDoesNotExistsInOrder({
order,
inputItems,
}: {
order: Pick<OrderDTO, "id" | "items">
inputItems: OrderWorkflow.CreateOrderReturnWorkflowInput["items"]
}) {
const orderItemIds = order.items?.map((i) => i.id) ?? []
const inputItemIds = inputItems.map((i) => i.id)
const diff = arrayDifference(inputItemIds, orderItemIds)
if (diff.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Items with ids ${diff.join(", ")} does not exist in order with id ${
order.id
}.`
)
}
}
function validateReturnReasons(
{
orderId,
inputItems,
}: {
orderId: string
inputItems: OrderWorkflow.CreateOrderReturnWorkflowInput["items"]
},
{ container }
) {
const reasonIds = inputItems.map((i) => i.reason_id).filter(Boolean)
if (!reasonIds.length) {
return
}
const remoteQuery = container.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const returnReasons = remoteQuery({
entry_point: "return_reasons",
fields: ["return_reason_children.*"],
variables: { id: [inputItems.map((item) => item.reason_id)] },
})
const reasons = returnReasons.map((r) => r.id)
const hasInvalidReasons = reasons.filter(
// We do not allow for root reason to be applied
(reason) => reason.return_reason_children.length > 0
)
const hasNonExistingReasons = arrayDifference(reasonIds, reasons)
if (hasNonExistingReasons.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Return reason with id ${hasNonExistingReasons.join(
", "
)} does not exists.`
)
}
if (hasInvalidReasons.length()) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Cannot apply return reason with id ${hasInvalidReasons.join(
", "
)} to order with id ${orderId}. Return reason has nested reasons.`
)
}
}
function prepareShippingMethodData({
orderId,
inputShippingOption,
returnShippingOption,
}: {
orderId: string
inputShippingOption: OrderWorkflow.CreateOrderReturnWorkflowInput["return_shipping"]
returnShippingOption: ShippingOptionDTO & WithCalculatedPrice
}) {
const obj: CreateOrderShippingMethodDTO = {
name: returnShippingOption.name,
order_id: orderId,
shipping_option_id: returnShippingOption.id,
amount: 0,
data: {},
// Computed later in the flow
tax_lines: [],
adjustments: [],
}
if (isDefined(inputShippingOption.price) && inputShippingOption.price >= 0) {
obj.amount = inputShippingOption.price
} else {
if (returnShippingOption.price_type === "calculated") {
// TODO: retrieve calculated price and assign to amount
} else {
obj.amount = returnShippingOption.calculated_price.calculated_amount
}
}
return obj
}
function validateCustomRefundAmount({
order,
refundAmount,
}: {
order: Pick<OrderDTO, "item_total">
refundAmount?: number
}) {
// validate that the refund prop input is less than order.item_total (item total)
// TODO: Probably this amount should be retrieved from the payments linked to the order
if (refundAmount && MathBN.gt(refundAmount, order.item_total)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Refund amount cannot be greater than order total.`
)
}
}
function prepareFulfillmentData({
order,
input,
returnShippingOption,
}: {
order: OrderDTO
input: OrderWorkflow.CreateOrderReturnWorkflowInput
returnShippingOption: {
id: string
provider_id: string
service_zone: { fulfillment_set: { location?: { id: string } } }
}
}) {
const inputItems = input.items
const orderItemsMap = new Map<string, Required<OrderDTO>["items"][0]>(
order.items!.map((i) => [i.id, i])
)
const fulfillmentItems = inputItems.map((i) => {
const orderItem = orderItemsMap.get(i.id)!
return {
line_item_id: i.id,
quantity: i.quantity,
return_quantity: i.quantity,
title: orderItem.variant_title ?? orderItem.title,
sku: orderItem.variant_sku || "",
barcode: orderItem.variant_barcode || "",
} as FulfillmentWorkflow.CreateFulfillmentItemWorkflowDTO
})
let locationId: string | undefined = input.location_id
if (!locationId) {
locationId = returnShippingOption.service_zone.fulfillment_set.location?.id
}
if (!locationId) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Cannot create return without stock location, either provide a location or you should link the shipping option ${returnShippingOption.id} to a stock location.`
)
}
return {
input: {
location_id: locationId,
provider_id: returnShippingOption.provider_id,
shipping_option_id: input.return_shipping.option_id,
items: fulfillmentItems,
labels: [] as FulfillmentWorkflow.CreateFulfillmentLabelWorkflowDTO[],
delivery_address: order.shipping_address ?? ({} as any), // TODO: should it be the stock location address?
order: {} as FulfillmentWorkflow.CreateFulfillmentOrderWorkflowDTO, // TODO see what todo here, is that even necessary?
},
}
}
function prepareReturnShippingOptionQueryVariables({
order,
input,
}: {
order: {
currency_code: string
region_id?: string
}
input: {
return_shipping: OrderWorkflow.CreateOrderReturnWorkflowInput["return_shipping"]
}
}) {
const variables = {
id: input.return_shipping.option_id,
calculated_price: {
context: {
currency_code: order.currency_code,
},
},
}
if (order.region_id) {
variables.calculated_price.context["region_id"] = order.region_id
}
return variables
}
export const createReturnOrderWorkflowId = "create-return-order"
export const createReturnOrderWorkflow = createWorkflow(
createReturnOrderWorkflowId,
(
input: WorkflowData<OrderWorkflow.CreateOrderReturnWorkflowInput>
): WorkflowData<void> => {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: [
"id",
"region_id",
"currency_code",
"total",
"item_total",
"items.*",
],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
})
transform({ order }, throwIfOrderIsCancelled)
transform(
{ order, inputItems: input.items },
throwIfItemsDoesNotExistsInOrder
)
transform(
{ orderId: input.order_id, inputItems: input.items },
validateReturnReasons
)
transform(
{ order, refundAmount: input.refund_amount },
validateCustomRefundAmount
)
const returnShippingOptionsVariables = transform(
{ input, order },
prepareReturnShippingOptionQueryVariables
)
const returnShippingOption = useRemoteQueryStep({
entry_point: "shipping_options",
fields: [
"id",
"price_type",
"name",
"provider_id",
"calculated_price.calculated_amount",
"service_zone.fulfillment_set.location.id",
],
variables: returnShippingOptionsVariables,
list: false,
throw_if_key_not_found: true,
}).config({ name: "return-shipping-option" })
const shippingMethodData = transform(
{
orderId: input.order_id,
inputShippingOption: input.return_shipping,
returnShippingOption,
},
prepareShippingMethodData
)
createReturnStep({
order_id: input.order_id,
items: input.items,
shipping_method: shippingMethodData,
created_by: input.created_by,
})
updateOrderTaxLinesStep({
order_id: input.order_id,
shipping_methods: [shippingMethodData as any], // The types does not seems correct in that step and expect too many things compared to the actual needs
})
const fulfillmentData = transform(
{ order, input, returnShippingOption },
prepareFulfillmentData
)
const fulfillment = createFulfillmentWorkflow.runAsStep(fulfillmentData)
// TODO call the createReturn from the fulfillment provider
const link = transform(
{ order_id: input.order_id, fulfillment },
(data) => {
return [
{
[Modules.ORDER]: { order_id: data.order_id },
[Modules.FULFILLMENT]: { fulfillment_id: data.fulfillment.id },
},
]
}
)
createLinkStep(link)
}
)
@@ -1,2 +1,3 @@
export * from "./create-orders"
export * from "./update-tax-lines"
export * from "./create-return"
+1 -1
View File
@@ -14,7 +14,7 @@ export type DeleteEntityInput = {
}
export type RestoreEntityInput = DeleteEntityInput
type LinkDefinition = {
export type LinkDefinition = {
[moduleName: string]: {
[fieldName: string]: string
}
+1
View File
@@ -3,3 +3,4 @@ export * from "./rule"
export * from "./batch"
export * from "./config-module"
export * from "./medusa-container"
export * from "./with-calculated"
@@ -0,0 +1,3 @@
export interface WithCalculatedPrice {
calculated_price: { calculated_amount: number }
}
@@ -120,6 +120,14 @@ export interface UpdateShippingOptionDTO {
id: string
}
)[]
/**
* The shipping option pricing
*/
prices: (
| { currency_code: string; amount: number; id?: string }
| { region_id: string; amount: number; id?: string }
)[]
}
/**
+14 -1
View File
@@ -2,6 +2,19 @@ import { BaseFilterable } from "../dal"
import { OperatorMap } from "../dal/utils"
import { BigNumberRawValue, BigNumberValue } from "../totals"
export type ChangeActionType =
| "CANCEL"
| "CANCEL_RETURN"
| "FULFILL_ITEM"
| "ITEM_ADD"
| "ITEM_REMOVE"
| "RECEIVE_DAMAGED_RETURN_ITEM"
| "RECEIVE_RETURN_ITEM"
| "RETURN_ITEM"
| "SHIPPING_ADD"
| "SHIP_ITEM"
| "WRITE_OFF_ITEM"
export type OrderSummaryDTO = {
total: BigNumberValue
subtotal: BigNumberValue
@@ -1187,7 +1200,7 @@ export interface OrderChangeActionDTO {
/**
* The action of the order change action
*/
action: string
action: ChangeActionType
/**
* The details of the order change action
*/
+2 -1
View File
@@ -1,5 +1,6 @@
import { BigNumberInput } from "../totals"
import {
ChangeActionType,
OrderItemDTO,
OrderLineItemDTO,
OrderReturnReasonDTO,
@@ -300,7 +301,7 @@ export interface CreateOrderChangeActionDTO {
version?: number
reference?: string
reference_id?: string
action: string
action: ChangeActionType
internal_note?: string
amount?: BigNumberInput
details?: Record<string, unknown>
@@ -9,3 +9,4 @@ export * as ProductCategoryWorkflow from "./product-category"
export * as RegionWorkflow from "./region"
export * as ReservationWorkflow from "./reservation"
export * as UserWorkflow from "./user"
export * as OrderWorkflow from "./order"
@@ -0,0 +1,26 @@
import { BigNumberInput } from "../../totals"
interface CreateOrderReturnItem {
id: string
quantity: BigNumberInput
internal_note?: string
reason_id?: string
metadata?: Record<string, any>
}
export interface CreateOrderReturnWorkflowInput {
order_id: string
created_by?: string // The id of the authenticated user
items: CreateOrderReturnItem[]
return_shipping: {
option_id: string
price?: number
}
note?: string
receive_now?: boolean
refund_amount?: number
/**
* Default fallback to the shipping option location id
*/
location_id?: string
}
@@ -0,0 +1 @@
export * from "./create-return-order"
+6
View File
@@ -80,4 +80,10 @@ export const LINKS = {
Modules.PAYMENT,
"payment_collection_id"
),
OrderFulfillment: composeLinkName(
Modules.ORDER,
"order_id",
Modules.FULFILLMENT,
"fulfillment_id"
),
}
@@ -57,7 +57,7 @@ export async function resolveValue(input, transactionContext) {
)
if (typeof parentRef[key] === "object") {
await unwrapInput(parentRef[key], parentRef[key])
parentRef[key] = await unwrapInput(parentRef[key], parentRef[key])
}
}
@@ -201,7 +201,7 @@ export type ReturnWorkflow<
runAsStep: ({
input,
}: {
input: TData
input: TData | WorkflowData<TData>
}) => ReturnType<StepFunction<TData, TResult>>
run: <TDataOverride = undefined, TResultOverride = undefined>(
...args: Parameters<
-13
View File
@@ -1,13 +0,0 @@
{
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-instanceof",
["@babel/plugin-transform-runtime", { "regenerator": true }]
],
"presets": ["@babel/preset-env"],
"env": {
"test": {
"plugins": ["@babel/plugin-transform-runtime"]
}
}
}
-7
View File
@@ -1,7 +0,0 @@
dist/
node_modules/
.DS_store
.env*
/*.js
!index.js
yarn.lock
-339
View File
@@ -1,339 +0,0 @@
# Change Log
## 1.3.9
### Patch Changes
- [#6700](https://github.com/medusajs/medusa/pull/6700) [`8f8a4f9b13`](https://github.com/medusajs/medusa/commit/8f8a4f9b1353087d98f6cc75346d43a7f49901a8) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Version all modules to allow for initial testing
## 1.3.8
### Patch Changes
- [#5869](https://github.com/medusajs/medusa/pull/5869) [`45996d58a2`](https://github.com/medusajs/medusa/commit/45996d58a2665d72335faad11bea958f8da74195) Thanks [@adrien2p](https://github.com/adrien2p)! - chore(medusa, interfaces, utils, webshiper): Uniformise class checks
## 1.3.7
### Patch Changes
- [#3041](https://github.com/medusajs/medusa/pull/3041) [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724) Thanks [@riqwan](https://github.com/riqwan)! - chore(medusa): Typeorm fixes / enhancements
- upgrade typeorm from 0.2.51 to 0.3.11
- Plugin repository loader to work with Typeorm update
## 1.3.7-rc.0
### Patch Changes
- [#3041](https://github.com/medusajs/medusa/pull/3041) [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724) Thanks [@riqwan](https://github.com/riqwan)! - chore(medusa): Typeorm fixes / enhancements
- upgrade typeorm from 0.2.51 to 0.3.11
- Plugin repository loader to work with Typeorm update
## 1.3.6
### Patch Changes
- [#3217](https://github.com/medusajs/medusa/pull/3217) [`8c5219a31`](https://github.com/medusajs/medusa/commit/8c5219a31ef76ee571fbce84d7d57a63abe56eb0) Thanks [@adrien2p](https://github.com/adrien2p)! - chore: Fix npm packages files included
- Updated dependencies [[`8c5219a31`](https://github.com/medusajs/medusa/commit/8c5219a31ef76ee571fbce84d7d57a63abe56eb0)]:
- medusa-core-utils@1.1.39
## 1.3.5
### Patch Changes
- [#3185](https://github.com/medusajs/medusa/pull/3185) [`08324355a`](https://github.com/medusajs/medusa/commit/08324355a4466b017a0bc7ab1d333ee3cd27b8c4) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Patches all dependencies + minor bumps `winston` to include a [fix for a significant memory leak](https://github.com/winstonjs/winston/pull/2057)
- Updated dependencies [[`08324355a`](https://github.com/medusajs/medusa/commit/08324355a4466b017a0bc7ab1d333ee3cd27b8c4)]:
- medusa-core-utils@1.1.38
## 1.3.4
### Patch Changes
- [#3025](https://github.com/medusajs/medusa/pull/3025) [`93d0dc1bd`](https://github.com/medusajs/medusa/commit/93d0dc1bdcb54cf6e87428a7bb9b0dac196b4de2) Thanks [@adrien2p](https://github.com/adrien2p)! - fix(medusa): test, build and watch scripts
## 1.3.3
### Patch Changes
- [#1962](https://github.com/medusajs/medusa/pull/1962) [`c97ccd3fb`](https://github.com/medusajs/medusa/commit/c97ccd3fb5dbe796b0e4fbf37def5bb6e8201557) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Convert FulfillmentService to TypeScript
## 1.3.2
### Patch Changes
- [#1914](https://github.com/medusajs/medusa/pull/1914) [`1dec44287`](https://github.com/medusajs/medusa/commit/1dec44287df5ac69b4c5769b59f9ebef58d3da68) Thanks [@fPolic](https://github.com/fPolic)! - Version bump due to missing changesets in merged PRs
* [#1874](https://github.com/medusajs/medusa/pull/1874) [`b8ddb31f6`](https://github.com/medusajs/medusa/commit/b8ddb31f6fe296a11d2d988276ba8e991c37fa9b) Thanks [@adrien2p](https://github.com/adrien2p)! - Move search indexing into a separate subscriber to defer the work load
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.1](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.3.0...medusa-interfaces@1.3.1) (2022-07-05)
### Bug Fixes
- **medusa:** Remove deps `mongoose` + `mongodb` ([#1218](https://github.com/medusajs/medusa/issues/1218)) ([c76e23e](https://github.com/medusajs/medusa/commit/c76e23e84dd8cb08c3c709f9f95c4c17b9685439))
# [1.3.0](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.2.1...medusa-interfaces@1.3.0) (2022-05-01)
### Bug Fixes
- ensures no duplicate tax lines when completing cart ([#1262](https://github.com/medusajs/medusa/issues/1262)) ([607a382](https://github.com/medusajs/medusa/commit/607a382b4ee190c25eafa345674b55b74a7d6349))
## [1.2.1](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.34...medusa-interfaces@1.2.1) (2022-02-28)
### Bug Fixes
- atomic phase error handler ([#1104](https://github.com/medusajs/medusa/issues/1104)) ([f983cfa](https://github.com/medusajs/medusa/commit/f983cfada675b9c2ad89f1dea37f862673383f54))
# [1.2.0](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.34...medusa-interfaces@1.2.0) (2022-02-25)
### Bug Fixes
- atomic phase error handler ([#1104](https://github.com/medusajs/medusa/issues/1104)) ([62c263c](https://github.com/medusajs/medusa/commit/62c263c36080541023fda5ae33a458c58cbaeb1e))
## [1.1.34](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.33...medusa-interfaces@1.1.34) (2022-02-06)
### Bug Fixes
- release ([fc3fbc8](https://github.com/medusajs/medusa/commit/fc3fbc897fad5c8a5d3eea828ac7277fba9d70af))
## [1.1.33](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.32...medusa-interfaces@1.1.33) (2022-02-06)
**Note:** Version bump only for package medusa-interfaces
## [1.1.32](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.31...medusa-interfaces@1.1.32) (2021-12-08)
**Note:** Version bump only for package medusa-interfaces
## [1.1.31](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.30...medusa-interfaces@1.1.31) (2021-11-23)
**Note:** Version bump only for package medusa-interfaces
## [1.1.30](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.29...medusa-interfaces@1.1.30) (2021-11-22)
**Note:** Version bump only for package medusa-interfaces
## [1.1.29](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.28...medusa-interfaces@1.1.29) (2021-11-19)
**Note:** Version bump only for package medusa-interfaces
## [1.1.28](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.27...medusa-interfaces@1.1.28) (2021-11-19)
### Features
- Allow retrieval of soft-deleted products ([#723](https://github.com/medusajs/medusa/issues/723)) ([1e50aee](https://github.com/medusajs/medusa/commit/1e50aee4feb55092560dd4a9c51a0671363e8576))
- Typescript for API layer ([#817](https://github.com/medusajs/medusa/issues/817)) ([373532e](https://github.com/medusajs/medusa/commit/373532ecbc8196f47e71af95a8cf82a14a4b1f9e))
## [1.1.27](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.26...medusa-interfaces@1.1.27) (2021-10-18)
**Note:** Version bump only for package medusa-interfaces
## [1.1.26](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.25...medusa-interfaces@1.1.26) (2021-10-18)
**Note:** Version bump only for package medusa-interfaces
## [1.1.25](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.23...medusa-interfaces@1.1.25) (2021-10-18)
### Bug Fixes
- filter type in jsdoc ([c3a6045](https://github.com/medusajs/medusa/commit/c3a6045dd889a0d32d9e7f6e806d96d8333ea0a5))
- product ordering ([57a6612](https://github.com/medusajs/medusa/commit/57a6612e845c078aec023d0cc49d6bfc175a1b37))
- use type to choose transformer before adding or replacing documents ([24eecd2](https://github.com/medusajs/medusa/commit/24eecd2922e0c3425f2d43549b3227c756820387))
## [1.1.24](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.23...medusa-interfaces@1.1.24) (2021-10-18)
### Bug Fixes
- filter type in jsdoc ([c3a6045](https://github.com/medusajs/medusa/commit/c3a6045dd889a0d32d9e7f6e806d96d8333ea0a5))
- product ordering ([57a6612](https://github.com/medusajs/medusa/commit/57a6612e845c078aec023d0cc49d6bfc175a1b37))
- use type to choose transformer before adding or replacing documents ([24eecd2](https://github.com/medusajs/medusa/commit/24eecd2922e0c3425f2d43549b3227c756820387))
## [1.1.23](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.22...medusa-interfaces@1.1.23) (2021-09-15)
**Note:** Version bump only for package medusa-interfaces
## [1.1.22](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.21...medusa-interfaces@1.1.22) (2021-09-14)
**Note:** Version bump only for package medusa-interfaces
## [1.1.21](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.20...medusa-interfaces@1.1.21) (2021-08-05)
**Note:** Version bump only for package medusa-interfaces
## [1.1.20](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.19...medusa-interfaces@1.1.20) (2021-07-26)
**Note:** Version bump only for package medusa-interfaces
## [1.1.19](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.17...medusa-interfaces@1.1.19) (2021-07-15)
**Note:** Version bump only for package medusa-interfaces
## [1.1.18](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.17...medusa-interfaces@1.1.18) (2021-07-15)
**Note:** Version bump only for package medusa-interfaces
## [1.1.17](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.16...medusa-interfaces@1.1.17) (2021-07-02)
**Note:** Version bump only for package medusa-interfaces
## [1.1.16](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.15...medusa-interfaces@1.1.16) (2021-06-22)
### Bug Fixes
- release assist ([668e8a7](https://github.com/medusajs/medusa/commit/668e8a740200847fc2a41c91d2979097f1392532))
## [1.1.15](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.14...medusa-interfaces@1.1.15) (2021-06-09)
**Note:** Version bump only for package medusa-interfaces
## [1.1.14](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.13...medusa-interfaces@1.1.14) (2021-06-09)
**Note:** Version bump only for package medusa-interfaces
## [1.1.13](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.12...medusa-interfaces@1.1.13) (2021-06-09)
**Note:** Version bump only for package medusa-interfaces
## [1.1.12](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.11...medusa-interfaces@1.1.12) (2021-06-09)
**Note:** Version bump only for package medusa-interfaces
## [1.1.11](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.10...medusa-interfaces@1.1.11) (2021-06-08)
**Note:** Version bump only for package medusa-interfaces
## [1.1.10](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.7...medusa-interfaces@1.1.10) (2021-04-28)
**Note:** Version bump only for package medusa-interfaces
## [1.1.9](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.8...medusa-interfaces@1.1.9) (2021-04-20)
**Note:** Version bump only for package medusa-interfaces
## [1.1.8](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.7...medusa-interfaces@1.1.8) (2021-04-20)
**Note:** Version bump only for package medusa-interfaces
## [1.1.7](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.6...medusa-interfaces@1.1.7) (2021-04-13)
**Note:** Version bump only for package medusa-interfaces
## [1.1.6](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.5...medusa-interfaces@1.1.6) (2021-04-09)
**Note:** Version bump only for package medusa-interfaces
## [1.1.5](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.4...medusa-interfaces@1.1.5) (2021-03-30)
**Note:** Version bump only for package medusa-interfaces
## [1.1.4](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.3...medusa-interfaces@1.1.4) (2021-03-17)
**Note:** Version bump only for package medusa-interfaces
## [1.1.3](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.1...medusa-interfaces@1.1.3) (2021-03-17)
### Features
- **medusa:** Add support for filtering with gt, lt, gte and lte ([#190](https://github.com/medusajs/medusa/issues/190)) ([dd0491f](https://github.com/medusajs/medusa/commit/dd0491f52132aed24f642589b12fcf636b719580))
## [1.1.2](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.1...medusa-interfaces@1.1.2) (2021-03-17)
### Features
- **medusa:** Add support for filtering with gt, lt, gte and lte ([#190](https://github.com/medusajs/medusa/issues/190)) ([dd0491f](https://github.com/medusajs/medusa/commit/dd0491f52132aed24f642589b12fcf636b719580))
## [1.1.1](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.1.0...medusa-interfaces@1.1.1) (2021-02-17)
### Features
- notifications ([#172](https://github.com/medusajs/medusa/issues/172)) ([7308946](https://github.com/medusajs/medusa/commit/7308946e567ed4e63e1ed3d9d31b30c4f1a73f0d))
# [1.1.0](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.0.14...medusa-interfaces@1.1.0) (2021-01-26)
**Note:** Version bump only for package medusa-interfaces
## [1.0.14](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.0.13...medusa-interfaces@1.0.14) (2020-11-24)
**Note:** Version bump only for package medusa-interfaces
## [1.0.13](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.0.12...medusa-interfaces@1.0.13) (2020-10-20)
### Features
- **medusa-interfaces:** Adds schema options to base model ([cc23a3b](https://github.com/medusajs/medusa/commit/cc23a3b0706c41ec57bb25ea3de9c6e39bd04f31))
## [1.0.12](https://github.com/medusajs/medusa/compare/medusa-interfaces@1.0.11...medusa-interfaces@1.0.12) (2020-10-14)
### Features
- return shipping and flow ([#125](https://github.com/medusajs/medusa/issues/125)) ([c1e821d](https://github.com/medusajs/medusa/commit/c1e821d9d4d33756c7309e5cf110d7aa9b67297d))
## 1.0.11 (2020-10-05)
### Features
- webshipper ([#118](https://github.com/medusajs/medusa/issues/118)) ([893a7f6](https://github.com/medusajs/medusa/commit/893a7f69afea67e854a67fc3b92c8a10c9c1b75c))
## 1.0.10 (2020-09-09)
### Bug Fixes
- updates license ([db519fb](https://github.com/medusajs/medusa/commit/db519fbaa6f8ad02c19cbecba5d4f28ba1ee81aa))
## 1.0.7 (2020-09-07)
## 1.0.1 (2020-09-05)
## 1.0.1-beta.0 (2020-09-04)
# 1.0.0 (2020-09-03)
# 1.0.0-alpha.30 (2020-08-28)
# 1.0.0-alpha.27 (2020-08-27)
### Features
- **pagination:** Adds MVP pagination to orders and products for admin routes ([9dc6999](https://github.com/medusajs/medusa/commit/9dc6999a9a0c11d33eb9affa953ad1b44bd5e8b8))
# 1.0.0-alpha.24 (2020-08-27)
# 1.0.0-alpha.3 (2020-08-20)
# 1.0.0-alpha.2 (2020-08-20)
# 1.0.0-alpha.1 (2020-08-20)
# 1.0.0-alpha.0 (2020-08-20)
### Reverts
- Revert "[medusa-interfaces] : Adds decorator functionality to BaseService (#39)" (#41) ([2273cc5](https://github.com/medusajs/medusa/commit/2273cc519ad4d6ae16157173aba3955d16745e1d)), closes [#39](https://github.com/medusajs/medusa/issues/39) [#41](https://github.com/medusajs/medusa/issues/41)
# 0.3.0 (2020-04-06)
# 0.2.0 (2020-04-06)
# 0.2.0-alpha.0 (2020-04-04)
## 0.1.6-alpha.0 (2020-03-24)
## 0.1.5-alpha.0 (2020-03-24)
## 0.1.4-alpha.0 (2020-03-24)
## 0.1.3-alpha.0 (2020-03-24)
## 0.1.2-alpha.0 (2020-03-24)
## 0.1.1-alpha.0 (2020-03-24)
# 0.1.0-alpha.0 (2020-03-24)
## [1.0.10](https://github.com/medusajs/medusa/compare/v1.0.9...v1.0.10) (2020-09-09)
### Bug Fixes
- updates license ([db519fb](https://github.com/medusajs/medusa/commit/db519fbaa6f8ad02c19cbecba5d4f28ba1ee81aa))
-43
View File
@@ -1,43 +0,0 @@
{
"name": "medusa-interfaces",
"version": "1.3.9",
"description": "Core interfaces for Medusa",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "https://github.com/medusajs/medusa",
"directory": "packages/medusa-interfaces"
},
"engines": {
"node": ">=16"
},
"scripts": {
"prepare": "cross-env NODE_ENV=production yarn run build",
"test": "jest --passWithNoTests src",
"build": "rimraf dist && babel src --out-dir dist --ignore '**/__tests__','**/__mocks__'",
"watch": "babel -w src --out-dir dist --ignore '**/__tests__','**/__mocks__'"
},
"files": [
"dist"
],
"author": "Sebastian Rindom",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-transform-classes": "^7.9.5",
"@babel/plugin-transform-instanceof": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/preset-env": "^7.7.5",
"@babel/preset-typescript": "^7.13.0",
"@babel/runtime": "^7.9.6",
"cross-env": "^5.2.1",
"jest": "^25.5.4",
"medusa-core-utils": "^1.2.1",
"medusa-test-utils": "^1.1.42",
"rimraf": "^5.0.1",
"typescript": "^4.4.4"
},
"gitHead": "cd1f5afa5aa8c0b15ea957008ee19f1d695cbd2e"
}
@@ -1,66 +0,0 @@
import BaseService from "../base-service"
describe("BaseService", () => {
describe("addDecorator", () => {
const baseService = new BaseService()
it("successfully adds decorator", () => {
baseService.addDecorator(obj => {
return (obj.decorator1 = true)
})
expect(baseService.decorators_.length).toEqual(1)
})
it("throws if decorator is not a function", () => {
expect(() => baseService.addDecorator("not a function")).toThrow(
"Decorators must be of type function"
)
})
})
describe("runDecorators_", () => {
it("returns success when passwords match", async () => {
const baseService = new BaseService()
baseService.addDecorator(obj => {
obj.decorator1 = true
return obj
})
baseService.addDecorator(obj => {
obj.decorator2 = true
return obj
})
const result = await baseService.runDecorators_({ data: "initial" })
expect(result).toEqual({
data: "initial",
decorator1: true,
decorator2: true,
})
})
it("skips failing decorator", async () => {
const baseService = new BaseService()
baseService.addDecorator(obj => {
obj.decorator1 = true
return obj
})
baseService.addDecorator(obj => {
return Promise.reject("fail")
})
baseService.addDecorator(obj => {
obj.decorator3 = true
return Promise.resolve(obj)
})
const result = await baseService.runDecorators_({ data: "initial" })
expect(result).toEqual({
data: "initial",
decorator1: true,
decorator3: true,
})
})
})
})
@@ -1,174 +0,0 @@
// Import from dist to avoid circular deps which result in the base service to be undefined
import {
buildQuery,
setMetadata,
validateId,
} from "@medusajs/medusa/dist/utils"
/**
* Common functionality for Services
* @interface
* @deprecated use TransactionBaseService from @medusajs/medusa instead
*/
export default class BaseService {
constructor() {
this.decorators_ = []
}
withTransaction() {
console.log("WARN: withTransaction called without custom implementation")
return this
}
/**
* Used to build TypeORM queries.
*/
buildQuery_(selector, config = {}) {
return buildQuery(selector, config)
}
/**
* Confirms whether a given raw id is valid. Fails if the provided
* id is null or undefined. The validate function takes an optional config
* param, to support checking id prefix and length.
* @param {string} rawId - the id to validate.
* @param {object?} config - optional config
* @returns {string} the rawId given that nothing failed
*/
validateId_(rawId, config = {}) {
return validateId(rawId, config)
}
shouldRetryTransaction(err) {
const code = typeof err === "object" ? String(err.code) : null
return code === "40001" || code === "40P01"
}
/**
* Wraps some work within a transactional block. If the service already has
* a transaction manager attached this will be reused, otherwise a new
* transaction manager is created.
* @param {function} work - the transactional work to be done
* @param {string} isolation - the isolation level to be used for the work.
* @return {any} the result of the transactional work
*/
async atomicPhase_(
work,
isolationOrErrorHandler,
maybeErrorHandlerOrDontFail
) {
let errorHandler = maybeErrorHandlerOrDontFail
let isolation = isolationOrErrorHandler
let dontFail = false
if (typeof isolationOrErrorHandler === "function") {
isolation = null
errorHandler = isolationOrErrorHandler
dontFail = !!maybeErrorHandlerOrDontFail
}
if (this.transactionManager_) {
const doWork = async (m) => {
this.manager_ = m
this.transactionManager_ = m
try {
const result = await work(m)
return result
} catch (error) {
if (errorHandler) {
const queryRunner = this.transactionManager_.queryRunner
if (queryRunner.isTransactionActive) {
await queryRunner.rollbackTransaction()
}
await errorHandler(error)
}
throw error
}
}
return doWork(this.transactionManager_)
} else {
const temp = this.manager_
const doWork = async (m) => {
this.manager_ = m
this.transactionManager_ = m
try {
const result = await work(m)
this.manager_ = temp
this.transactionManager_ = undefined
return result
} catch (error) {
this.manager_ = temp
this.transactionManager_ = undefined
throw error
}
}
if (isolation) {
let result
try {
result = await this.manager_.transaction(isolation, (m) => doWork(m))
return result
} catch (error) {
if (this.shouldRetryTransaction(error)) {
return this.manager_.transaction(isolation, (m) => doWork(m))
} else {
if (errorHandler) {
await errorHandler(error)
}
throw error
}
}
}
try {
return await this.manager_.transaction((m) => doWork(m))
} catch (error) {
if (errorHandler) {
const result = await errorHandler(error)
if (dontFail) {
return result
}
}
throw error
}
}
}
/**
* Dedicated method to set metadata.
* @param {string} obj - the entity to apply metadata to.
* @param {object} metadata - the metadata to set
* @return {Promise} resolves to the updated result.
*/
setMetadata_(obj, metadata) {
return setMetadata(obj, metadata)
}
/**
* Adds a decorator to a service. The decorator must be a function and should
* return a decorated object.
* @param {function} fn - the decorator to add to the service
*/
addDecorator(fn) {
if (typeof fn !== "function") {
throw Error("Decorators must be of type function")
}
this.decorators_.push(fn)
}
/**
* Runs the decorators registered on the service. The decorators are run in
* the order they have been registered in. Failing decorators will be skipped
* in order to ensure deliverability in spite of breaking code.
* @param {object} obj - the object to decorate.
* @return {object} the decorated object.
*/
runDecorators_(obj, fields = [], expandFields = []) {
return this.decorators_.reduce(async (acc, next) => {
return acc.then((res) => next(res, fields, expandFields)).catch(() => acc)
}, Promise.resolve(obj))
}
}
@@ -1,28 +0,0 @@
import BaseService from "./base-service"
/**
* Interface for file connectors
* @interface
* @deprecated use AbstractFileService from @medusajs/medusa instead
*/
class BaseFileService extends BaseService {
static _isFileService = true
static isFileService(obj) {
return obj?.constructor?._isFileService
}
constructor() {
super()
}
upload() {
throw Error("upload must be overridden by the child class")
}
delete() {
throw Error("delete must be overridden by the child class")
}
}
export default BaseFileService
@@ -1,117 +0,0 @@
import BaseService from "./base-service"
/**
* The interface that all fulfillment services must inherit from. The intercace
* provides the necessary methods for creating, authorizing and managing
* fulfillment orders.
* @interface
* @deprecated use AbstractFulfillmentService from @medusajs/medusa instead
*/
class BaseFulfillmentService extends BaseService {
static _isFulfillmentService = true
static isFulfillmentService(obj) {
return obj?.constructor?._isFulfillmentService
}
constructor() {
super()
}
getIdentifier() {
return this.constructor.identifier
}
/**
* Called before a shipping option is created in Admin. The method should
* return all of the options that the fulfillment provider can be used with,
* and it is here the distinction between different shipping options are
* enforced. For example, a fulfillment provider may offer Standard Shipping
* and Express Shipping as fulfillment options, it is up to the store operator
* to create shipping options in Medusa that can be chosen between by the
* customer.
*/
getFulfillmentOptions() {
throw Error("getFulfillmentOptions must be overridden by the child class")
}
/**
* Called before a shipping method is set on a cart to ensure that the data
* sent with the shipping method is valid. The data object may contain extra
* data about the shipment such as an id of a drop point. It is up to the
* fulfillment provider to enforce that the correct data is being sent
* through.
* @param {object} optionData - the data to validate
* @param {object} data - the data to validate
* @param {object | undefined} cart - the cart to which the shipping method will be applied
* @return {object} the data to populate `cart.shipping_methods.$.data` this
* is usually important for future actions like generating shipping labels
*/
validateFulfillmentData(optionData, data, cart) {
throw Error("validateFulfillmentData must be overridden by the child class")
}
/**
* Called before a shipping option is created in Admin. Use this to ensure
* that a fulfillment option does in fact exist.
*/
validateOption(data) {
throw Error("validateOption must be overridden by the child class")
}
canCalculate(data) {
throw Error("canCalculate must be overridden by the child class")
}
/**
* Used to calculate a price for a given shipping option.
*/
calculatePrice(optionData, data, cart) {
throw Error("calculatePrice must be overridden by the child class")
}
createFulfillment(data, items, order, fulfillment) {
throw Error("createFulfillment must be overridden by the child class")
}
cancelFulfillment(fulfillment) {
throw Error("cancelFulfillment must be overridden by the child class")
}
/**
* Used to retrieve documents associated with a fulfillment.
* Will default to returning no documents.
*/
getFulfillmentDocuments(data) {
return []
}
/**
* Used to create a return order. Should return the data necessary for future
* operations on the return; in particular the data may be used to receive
* documents attached to the return.
*/
createReturn(fromData) {
throw Error("createReturn must be overridden by the child class")
}
/**
* Used to retrieve documents related to a return order.
*/
getReturnDocuments(data) {
return []
}
/**
* Used to retrieve documents related to a shipment.
*/
getShipmentDocuments(data) {
return []
}
retrieveDocuments(fulfillmentData, documentType) {
throw Error("retrieveDocuments must be overridden by the child class")
}
}
export default BaseFulfillmentService
-7
View File
@@ -1,7 +0,0 @@
export { default as BaseService } from "./base-service"
export { default as PaymentService } from "./payment-service"
export { default as FulfillmentService } from "./fulfillment-service"
export { default as FileService } from "./file-service"
export { default as NotificationService } from "./notification-service"
export { default as OauthService } from "./oauth-service"
export { default as SearchService } from "./search-service"
@@ -1,35 +0,0 @@
import BaseService from "./base-service"
/**
* Interface for Notification Providers
* @interface
* @deprecated use AbstractNotificationService from @medusajs/medusa instead
*/
class BaseNotificationService extends BaseService {
static _isNotificationService = true
static isNotificationService(obj) {
return obj?.constructor?._isNotificationService
}
constructor() {
super()
}
getIdentifier() {
return this.constructor.identifier
}
/**
* Used to retrieve documents related to a shipment.
*/
sendNotification(event, data) {
throw new Error("Must be overridden by child")
}
resendNotification(notification, config = {}) {
throw new Error("Must be overridden by child")
}
}
export default BaseNotificationService
@@ -1,31 +0,0 @@
import BaseService from "./base-service"
/**
* Interface for file connectors
* @interface
*/
class BaseOauthService extends BaseService {
static _isOauthService = true
static isOauthService(obj) {
return obj?.constructor?._isOauthService
}
constructor() {
super()
}
generateToken() {
throw Error("generateToken must be overridden by the child class")
}
refreshToken() {
throw Error("refreshToken must be overridden by the child class")
}
destroyToken() {
throw Error("destroyToken must be overridden by the child class")
}
}
export default BaseOauthService
@@ -1,85 +0,0 @@
import BaseService from "./base-service"
/**
* The interface that all payment services must inherit from. The intercace
* provides the necessary methods for creating, authorizing and managing
* payments.
* @interface
* @deprecated use AbstractPaymentProcessor from @medusajs/medusa instead
*/
class BasePaymentService extends BaseService {
static _isPaymentService = true
static isPaymentService(obj) {
return obj?.constructor?._isPaymentService
}
constructor() {
super()
}
getIdentifier() {
return this.constructor.identifier
}
/**
* Used to create a payment to be processed with the service's payment gateway.
* @param cart {object} - the cart that the payment should cover.
* @return {Promise<{object}>} - returns a promise that resolves to an object
* containing the payment data. This data will be saved to the cart for later
* use.
*/
createPayment(cart) {
throw Error("createPayment must be overridden by the child class")
}
/**
* Used to retrieve a payment.
* @param cart {object} - the cart whose payment should be retrieved.
* @return {Promise<{object}>} - returns a promise that resolves to the
* payment object as stored with the provider.
*/
retrievePayment(cart) {
throw Error("getPayment must be overridden by the child class")
}
/**
* Used to update a payment. This method is called when the cart is updated.
* @param cart {object} - the cart whose payment should be updated.
* @return {Promise<{object}>} - returns a promise that resolves to the
* payment object as stored with the provider.
*/
updatePayment(cart) {
throw Error("updatePayment must be overridden by the child class")
}
getStatus() {
throw Error("getStatus must be overridden by the child class")
}
authorizePayment() {
throw Error("authorizePayment must be overridden by the child class")
}
capturePayment() {
throw Error("capturePayment must be overridden by the child class")
}
refundPayment() {
throw Error("refundPayment must be overridden by the child class")
}
deletePayment() {
throw Error("deletePayment must be overridden by the child class")
}
/**
* If the payment provider can save a payment method this function will
* retrieve them.
*/
retrieveSavedMethods(customer) {
return Promise.resolve([])
}
}
export default BasePaymentService
@@ -1,107 +0,0 @@
import BaseService from "./base-service"
/**
* The interface that all search services must implement.
* @interface
* @deprecated use AbstractSearchService from @medusajs/utils instead
*/
class SearchService extends BaseService {
static _isSearchService = true
static isSearchService(obj) {
return obj?.constructor?._isSearchService
}
constructor() {
super()
}
get options() {
return this.options_ ?? {}
}
/**
* Used to create an index
* @param indexName {string} - the index name
* @param [options] {string} - the index name
* @return {Promise<{object}>} - returns response from search engine provider
*/
createIndex(indexName, options) {
throw Error("createIndex must be overridden by a child class")
}
/**
* Used to get an index
* @param indexName {string} - the index name.
* @return {Promise<{object}>} - returns response from search engine provider
*/
getIndex(indexName) {
throw Error("getIndex must be overridden by a child class")
}
/**
* Used to index documents by the search engine provider
* @param indexName {string} - the index name
* @param documents {Array.<Object>} - documents array to be indexed
* @param type {string} - type of documents to be added (e.g: products, regions, orders, etc)
* @return {Promise<{object}>} - returns response from search engine provider
*/
addDocuments(indexName, documents, type) {
throw Error("addDocuments must be overridden by a child class")
}
/**
* Used to replace documents
* @param indexName {string} - the index name.
* @param documents {Object} - array of document objects that will replace existing documents
* @param type {Array.<Object>} - type of documents to be replaced (e.g: products, regions, orders, etc)
* @return {Promise<{object}>} - returns response from search engine provider
*/
replaceDocuments(indexName, documents, type) {
throw Error("updateDocument must be overridden by a child class")
}
/**
* Used to delete document
* @param indexName {string} - the index name
* @param document_id {string} - the id of the document
* @return {Promise<{object}>} - returns response from search engine provider
*/
deleteDocument(indexName, document_id) {
throw Error("deleteDocument must be overridden by a child class")
}
/**
* Used to delete all documents
* @param indexName {string} - the index name
* @return {Promise<{object}>} - returns response from search engine provider
*/
deleteAllDocuments(indexName) {
throw Error("deleteAllDocuments must be overridden by a child class")
}
/**
* Used to search for a document in an index
* @param indexName {string} - the index name
* @param query {string} - the search query
* @param options {{ paginationOptions: { limit: number, offset: number }, filter: any, additionalOptions: any}}
* - any options passed to the request object other than the query and indexName
* - additionalOptions contain any provider specific options
* @return {Promise<{ hits: any[]; [k: string]: any; }>} returns response from search engine provider
*/
search(indexName, query, options) {
throw Error("search must be overridden by a child class")
}
/**
* Used to update the settings of an index
* @param indexName {string} - the index name
* @param settings {object} - settings object
* @return {Promise<{object}>} - returns response from search engine provider
*/
updateSettings(indexName, settings) {
throw Error("updateSettings must be overridden by a child class")
}
}
export default SearchService
-28
View File
@@ -1,28 +0,0 @@
{
"compilerOptions": {
"lib": ["es2021"],
"target": "es2021",
"outDir": "./dist",
"esModuleInterop": true,
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"noImplicitReturns": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"allowJs": true,
"skipLibCheck": true,
"downlevelIteration": true // to use ES5 specific tooling
},
"include": ["./src/**/*", "index.d.ts"],
"exclude": [
"./dist/**/*",
"./src/**/__tests__",
"./src/**/__mocks__",
"node_modules"
]
}
-1
View File
@@ -1 +0,0 @@
declare module "medusa-interfaces"
-4
View File
@@ -31,7 +31,6 @@
"@types/multer": "^1.4.7",
"cross-env": "^5.2.1",
"jest": "^25.5.4",
"medusa-interfaces": "^1.3.9",
"medusa-test-utils": "^1.1.44",
"rimraf": "^5.0.1",
"supertest": "^4.0.2",
@@ -45,9 +44,6 @@
"serve": "node dist/app.js",
"test": "jest --silent --bail --maxWorkers=50% --forceExit"
},
"peerDependencies": {
"medusa-interfaces": "^1.3.7"
},
"dependencies": {
"@medusajs/admin-sdk": "0.0.1",
"@medusajs/core-flows": "^0.0.9",
@@ -14,17 +14,17 @@ import {
UpdateServiceZoneDTO,
} from "@medusajs/types"
import {
arrayDifference,
EmitEvents,
FulfillmentUtils,
getSetDifference,
InjectManager,
InjectTransactionManager,
isString,
MedusaContext,
MedusaError,
Modules,
ModulesSdkUtils,
arrayDifference,
getSetDifference,
isString,
promiseAll,
} from "@medusajs/utils"
import {
@@ -49,6 +49,9 @@ export const LocationFulfillmentSet: ModuleJoinerConfig = {
},
{
serviceName: Modules.FULFILLMENT,
fieldAlias: {
location: "locations_link.location",
},
relationship: {
serviceName: LINKS.LocationFulfillmentSet,
primaryKey: "fulfillment_set_id",
@@ -12,3 +12,4 @@ export * from "./readonly"
export * from "./region-payment-provider"
export * from "./sales-channel-location"
export * from "./shipping-option-price-set"
export * from "./order-fulfillment"
@@ -0,0 +1,63 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { LINKS } from "@medusajs/utils"
export const OrderFulfillment: ModuleJoinerConfig = {
serviceName: LINKS.OrderFulfillment,
isLink: true,
databaseConfig: {
tableName: "order_fulfillment",
idPrefix: "orderful",
},
alias: [
{
name: ["order_fulfillment", "order_fulfillments"],
args: {
entity: "LinkOrderFulfillment",
},
},
],
primaryKeys: ["id", "order_id", "fulfillment_id"],
relationships: [
{
serviceName: Modules.ORDER,
primaryKey: "id",
foreignKey: "order_id",
alias: "order",
},
{
serviceName: Modules.FULFILLMENT,
primaryKey: "id",
foreignKey: "fulfillment_id",
alias: "fulfillments",
args: {
// TODO: We are not suppose to know the module implementation here, wait for later to think about inferring it
methodSuffix: "Fulfillments",
},
},
],
extends: [
{
serviceName: Modules.ORDER,
fieldAlias: {
fulfillments: "fulfillment_link.fulfillments",
},
relationship: {
serviceName: LINKS.OrderFulfillment,
primaryKey: "order_id",
foreignKey: "id",
alias: "fulfillment_link",
isList: true,
},
},
{
serviceName: Modules.FULFILLMENT,
relationship: {
serviceName: LINKS.OrderFulfillment,
primaryKey: "fulfillment_id",
foreignKey: "id",
alias: "order_link",
},
},
],
}
@@ -2214,7 +2214,7 @@ export default class OrderModuleService<
if (!isString(data.shipping_method)) {
const methods = await this.createShippingMethods(
data.order_id,
data.shipping_method as any,
[{ order_id: data.order_id, ...data.shipping_method }],
sharedContext
)
shippingMethodId = methods[0].id
+9 -36
View File
@@ -870,7 +870,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/cli@npm:^7.12.10, @babel/cli@npm:^7.14.3, @babel/cli@npm:^7.7.5":
"@babel/cli@npm:^7.12.10, @babel/cli@npm:^7.14.3":
version: 7.24.5
resolution: "@babel/cli@npm:7.24.5"
dependencies:
@@ -1366,7 +1366,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-proposal-class-properties@npm:^7.10.4, @babel/plugin-proposal-class-properties@npm:^7.12.1, @babel/plugin-proposal-class-properties@npm:^7.7.4":
"@babel/plugin-proposal-class-properties@npm:^7.10.4, @babel/plugin-proposal-class-properties@npm:^7.12.1":
version: 7.18.6
resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6"
dependencies:
@@ -1875,7 +1875,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-classes@npm:^7.10.4, @babel/plugin-transform-classes@npm:^7.12.1, @babel/plugin-transform-classes@npm:^7.24.5, @babel/plugin-transform-classes@npm:^7.9.5":
"@babel/plugin-transform-classes@npm:^7.10.4, @babel/plugin-transform-classes@npm:^7.12.1, @babel/plugin-transform-classes@npm:^7.24.5":
version: 7.24.5
resolution: "@babel/plugin-transform-classes@npm:7.24.5"
dependencies:
@@ -2012,7 +2012,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-instanceof@npm:^7.10.4, @babel/plugin-transform-instanceof@npm:^7.12.1, @babel/plugin-transform-instanceof@npm:^7.8.3":
"@babel/plugin-transform-instanceof@npm:^7.10.4, @babel/plugin-transform-instanceof@npm:^7.12.1":
version: 7.24.1
resolution: "@babel/plugin-transform-instanceof@npm:7.24.1"
dependencies:
@@ -2360,7 +2360,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-runtime@npm:^7.11.5, @babel/plugin-transform-runtime@npm:^7.12.1, @babel/plugin-transform-runtime@npm:^7.7.6":
"@babel/plugin-transform-runtime@npm:^7.11.5, @babel/plugin-transform-runtime@npm:^7.12.1":
version: 7.24.3
resolution: "@babel/plugin-transform-runtime@npm:7.24.3"
dependencies:
@@ -2571,7 +2571,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/preset-env@npm:^7.11.5, @babel/preset-env@npm:^7.12.11, @babel/preset-env@npm:^7.12.7, @babel/preset-env@npm:^7.23.2, @babel/preset-env@npm:^7.7.5":
"@babel/preset-env@npm:^7.11.5, @babel/preset-env@npm:^7.12.11, @babel/preset-env@npm:^7.12.7, @babel/preset-env@npm:^7.23.2":
version: 7.24.5
resolution: "@babel/preset-env@npm:7.24.5"
dependencies:
@@ -2732,7 +2732,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.0, @babel/preset-typescript@npm:^7.23.0":
"@babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.0, @babel/preset-typescript@npm:^7.23.0":
version: 7.24.1
resolution: "@babel/preset-typescript@npm:7.24.1"
dependencies:
@@ -2769,7 +2769,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6":
"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
version: 7.24.5
resolution: "@babel/runtime@npm:7.24.5"
dependencies:
@@ -5672,7 +5672,6 @@ __metadata:
jsonwebtoken: ^9.0.0
lodash: ^4.17.21
medusa-core-utils: ^1.2.2
medusa-interfaces: ^1.3.9
medusa-telemetry: ^0.0.17
medusa-test-utils: ^1.1.44
morgan: ^1.9.1
@@ -5693,8 +5692,6 @@ __metadata:
typescript: ^4.4.4
uuid: ^9.0.0
zod: 3.22.4
peerDependencies:
medusa-interfaces: ^1.3.7
bin:
medusa: ./cli.js
languageName: unknown
@@ -20250,7 +20247,6 @@ __metadata:
form-data: ^4.0.0
jest: ^26.6.3
jest-environment-node: 26.6.2
medusa-interfaces: "workspace:*"
pg: ^8.11.0
typeorm: ^0.3.16
languageName: unknown
@@ -20290,7 +20286,6 @@ __metadata:
faker: ^5.5.3
jest: ^26.6.3
jest-environment-node: 26.6.2
medusa-interfaces: "workspace:*"
medusa-test-utils: "workspace:*"
pg: ^8.11.0
typeorm: ^0.3.16
@@ -24207,7 +24202,7 @@ __metadata:
languageName: node
linkType: hard
"medusa-core-utils@^1.2.0, medusa-core-utils@^1.2.1, medusa-core-utils@^1.2.2, medusa-core-utils@workspace:packages/medusa-core-utils":
"medusa-core-utils@^1.2.0, medusa-core-utils@^1.2.2, medusa-core-utils@workspace:packages/medusa-core-utils":
version: 0.0.0-use.local
resolution: "medusa-core-utils@workspace:packages/medusa-core-utils"
dependencies:
@@ -24246,28 +24241,6 @@ __metadata:
languageName: unknown
linkType: soft
"medusa-interfaces@^1.3.9, medusa-interfaces@workspace:*, medusa-interfaces@workspace:packages/medusa-interfaces":
version: 0.0.0-use.local
resolution: "medusa-interfaces@workspace:packages/medusa-interfaces"
dependencies:
"@babel/cli": ^7.7.5
"@babel/core": ^7.7.5
"@babel/plugin-proposal-class-properties": ^7.7.4
"@babel/plugin-transform-classes": ^7.9.5
"@babel/plugin-transform-instanceof": ^7.8.3
"@babel/plugin-transform-runtime": ^7.7.6
"@babel/preset-env": ^7.7.5
"@babel/preset-typescript": ^7.13.0
"@babel/runtime": ^7.9.6
cross-env: ^5.2.1
jest: ^25.5.4
medusa-core-utils: ^1.2.1
medusa-test-utils: ^1.1.42
rimraf: ^5.0.1
typescript: ^4.4.4
languageName: unknown
linkType: soft
"medusa-react@npm:latest":
version: 9.0.17
resolution: "medusa-react@npm:9.0.17"