feat(admin-ui, medusa-js, medusa-react, medusa): Multiwarehousing UI (#3403)

* add "get-variant" endpoint

* import from a different place

* fix unit test

* add changeset

* inventory management for orders

* add changeset

* initial create-fulfillment

* add changeset

* type oas and admin

* Move inv. creation and listing from admin repo

* Fix location editing bug (CORE-1216)

* Fix default warehouse on inventory table view

* remove actions from each table line

* Use feature flag hook instead of context directly

* remove manage inventory action if inventory management is not enabled

* Address review comments

* fix queries made when inventorymodules are disabled

* variant form changes for feature enabled

* move exclamation icon into warning icon

* ensure queries are not run unless feature is enabled for create-fulfillment

---------

Co-authored-by: Philip Korsholm <philip.korsholm@hotmail.com>
Co-authored-by: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com>
This commit is contained in:
Rares Stefan
2023-03-08 16:08:56 +01:00
committed by GitHub
co-authored by Philip Korsholm Philip Korsholm
parent 53eda215e0
commit 57d7728dd9
49 changed files with 3922 additions and 722 deletions
@@ -3,10 +3,7 @@ import {
InventoryItemDTO,
InventoryLevelDTO,
} from "../../../../../types/inventory"
type LevelWithAvailability = InventoryLevelDTO & {
available_quantity: number
}
import { LevelWithAvailability, ResponseInventoryItem } from "../../variants"
export const buildLevelsByInventoryItemId = (
inventoryLevels: InventoryLevelDTO[],
@@ -27,7 +24,7 @@ export const getLevelsByInventoryItemId = async (
items: InventoryItemDTO[],
locationIds: string[],
inventoryService: IInventoryService
) => {
): Promise<Record<string, LevelWithAvailability[]>> => {
const [levels] = await inventoryService.listInventoryLevels({
inventory_item_id: items.map((inventoryItem) => inventoryItem.id),
})
@@ -52,7 +49,7 @@ export const joinLevels = async (
inventoryItems: InventoryItemDTO[],
locationIds: string[],
inventoryService: IInventoryService
) => {
): Promise<ResponseInventoryItem[]> => {
const levelsByItemId = await getLevelsByInventoryItemId(
inventoryItems,
locationIds,
@@ -151,8 +151,23 @@ type SalesChannelDTO = Omit<SalesChannel, "beforeInsert" | "locations"> & {
locations: string[]
}
type ResponseInventoryItem = Partial<InventoryItemDTO> & {
location_levels?: InventoryLevelDTO[]
export type LevelWithAvailability = InventoryLevelDTO & {
available_quantity: number
}
/**
* @schema ResponseInventoryItem
* allOf:
* - $ref: "#/components/schemas/InventoryItemDTO"
* - type: object
* required:
* - available_quantity
* properties:
* available_quantity:
* type: number
*/
export type ResponseInventoryItem = Partial<InventoryItemDTO> & {
location_levels?: LevelWithAvailability[]
}
/**
@@ -164,7 +179,7 @@ type ResponseInventoryItem = Partial<InventoryItemDTO> & {
* type: string
* inventory:
* description: the stock location address ID
* type: string
* $ref: "#/components/schemas/ResponseInventoryItem"
* sales_channel_availability:
* type: object
* description: An optional key-value map with additional details
@@ -0,0 +1,73 @@
import { PricingService, ProductVariantService } from "../../../../services"
import { FindParams } from "../../../../types/common"
/**
* @oas [get] /admin/variants/{id}
* operationId: "GetVariantsVariant"
* summary: "Get a Product variant"
* description: "Retrieves a Product variant."
* x-authenticated: true
* parameters:
* - (path) id=* {string} The ID of the variant.
* x-codegen:
* method: retrieve
* x-codeSamples:
* - lang: JavaScript
* label: JS Client
* source: |
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
* // must be previously logged in or use api token
* medusa.admin.variants.retrieve(product_id)
* .then(({ product }) => {
* console.log(product.id);
* });
* - lang: Shell
* label: cURL
* source: |
* curl --location --request GET 'https://medusa-url.com/admin/variants/{id}' \
* --header 'Authorization: Bearer {api_token}'
* security:
* - api_token: []
* - cookie_auth: []
* tags:
* - Products
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/AdminVariantRes"
* "400":
* $ref: "#/components/responses/400_error"
* "401":
* $ref: "#/components/responses/unauthorized"
* "404":
* $ref: "#/components/responses/not_found_error"
* "409":
* $ref: "#/components/responses/invalid_state_error"
* "422":
* $ref: "#/components/responses/invalid_request_error"
* "500":
* $ref: "#/components/responses/500_error"
*/
export default async (req, res) => {
const { id } = req.params
const productVariantService: ProductVariantService = req.scope.resolve(
"productVariantService"
)
const pricingService: PricingService = req.scope.resolve("pricingService")
const rawVariant = await productVariantService.retrieve(
id,
req.retrieveConfig
)
const [variant] = await pricingService.setVariantPrices([rawVariant])
res.status(200).json({ variant })
}
export class AdminGetVariantParams extends FindParams {}
@@ -5,6 +5,7 @@ import { PaginatedResponse } from "../../../../types/common"
import { PricedVariant } from "../../../../types/pricing"
import middlewares, { transformQuery } from "../../../middlewares"
import { checkRegisteredModules } from "../../../middlewares/check-registered-modules"
import { AdminGetVariantParams } from "./get-variant"
import { AdminGetVariantsParams } from "./list-variants"
const route = Router()
@@ -22,6 +23,16 @@ export default (app) => {
middlewares.wrap(require("./list-variants").default)
)
route.get(
"/:id",
transformQuery(AdminGetVariantParams, {
defaultRelations: defaultAdminVariantRelations,
defaultFields: defaultAdminVariantFields,
isList: false,
}),
middlewares.wrap(require("./get-variant").default)
)
route.get(
"/:id/inventory",
checkRegisteredModules({
@@ -88,5 +99,19 @@ export type AdminVariantsListRes = PaginatedResponse & {
variants: PricedVariant[]
}
/**
* @schema AdminVariantRes
* type: object
* required:
* - variant
* properties:
* variant:
* $ref: "#/components/schemas/PricedVariant"
*/
export type AdminVariantsRes = {
variant: PricedVariant
}
export * from "./list-variants"
export * from "./get-variant"
export * from "./get-inventory"