feat(medusa): Stock location module (#2907)
* feat: stock location module
This commit is contained in:
committed by
GitHub
parent
cc10c20f35
commit
c07ffb6165
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
"@medusajs/medusa-js": patch
|
||||
"@medusajs/stock-location": major
|
||||
---
|
||||
|
||||
Stock locations module added
|
||||
@@ -24,6 +24,7 @@ import AdminReturnsResource from "./returns"
|
||||
import AdminSalesChannelsResource from "./sales-channels"
|
||||
import AdminShippingOptionsResource from "./shipping-options"
|
||||
import AdminShippingProfilesResource from "./shipping-profiles"
|
||||
import AdminStockLocationsResource from "./stock-locations"
|
||||
import AdminStoresResource from "./store"
|
||||
import AdminSwapsResource from "./swaps"
|
||||
import AdminTaxRatesResource from "./tax-rates"
|
||||
@@ -59,6 +60,7 @@ class Admin extends BaseResource {
|
||||
public salesChannels = new AdminSalesChannelsResource(this.client)
|
||||
public swaps = new AdminSwapsResource(this.client)
|
||||
public shippingProfiles = new AdminShippingProfilesResource(this.client)
|
||||
public stockLocations = new AdminStockLocationsResource(this.client)
|
||||
public store = new AdminStoresResource(this.client)
|
||||
public shippingOptions = new AdminShippingOptionsResource(this.client)
|
||||
public regions = new AdminRegionsResource(this.client)
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
AdminSalesChannelsListRes,
|
||||
AdminDeleteSalesChannelsChannelProductsBatchReq,
|
||||
AdminPostSalesChannelsChannelProductsBatchReq,
|
||||
AdminPostSalesChannelsChannelStockLocationsReq,
|
||||
AdminDeleteSalesChannelsChannelStockLocationsReq,
|
||||
} from "@medusajs/medusa"
|
||||
import { ResponsePromise } from "../../typings"
|
||||
import BaseResource from "../base"
|
||||
@@ -121,6 +123,38 @@ class AdminSalesChannelsResource extends BaseResource {
|
||||
const path = `/admin/sales-channels/${salesChannelId}/products/batch`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a location to a sales channel
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `sales_channels` in your medusa backend project.
|
||||
* @description Add a stock location to a SalesChannel
|
||||
* @returns the Medusa SalesChannel
|
||||
*/
|
||||
addLocation(
|
||||
salesChannelId: string,
|
||||
payload: AdminPostSalesChannelsChannelStockLocationsReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminSalesChannelsRes> {
|
||||
const path = `/admin/sales-channels/${salesChannelId}/stock-locations`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a location from a sales channel
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `sales_channels` in your medusa backend project.
|
||||
* @description Remove a stock location from a SalesChannel
|
||||
* @returns an deletion result
|
||||
*/
|
||||
removeLocation(
|
||||
salesChannelId: string,
|
||||
payload: AdminDeleteSalesChannelsChannelStockLocationsReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminSalesChannelsRes> {
|
||||
const path = `/admin/sales-channels/${salesChannelId}/stock-locations`
|
||||
return this.client.request("DELETE", path, payload, {}, customHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminSalesChannelsResource
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
AdminGetStockLocationsParams,
|
||||
AdminStockLocationsRes,
|
||||
AdminPostStockLocationsLocationReq,
|
||||
AdminPostStockLocationsReq,
|
||||
AdminStockLocationsListRes,
|
||||
} from "@medusajs/medusa"
|
||||
import { ResponsePromise } from "../../typings"
|
||||
import BaseResource from "../base"
|
||||
import qs from "qs"
|
||||
|
||||
class AdminStockLocationsResource extends BaseResource {
|
||||
/** retrieve an stock location
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please install @medusajs/stock-location
|
||||
* @description gets a medusa stock location
|
||||
* @returns a medusa stock location
|
||||
*/
|
||||
create(
|
||||
payload: AdminPostStockLocationsReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminStockLocationsRes> {
|
||||
const path = `/admin/stock-locations`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
/** retrieve an stock location
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please install @medusajs/stock-location
|
||||
* @description gets a medusa stock location
|
||||
* @returns a medusa stock location
|
||||
*/
|
||||
retrieve(
|
||||
itemId: string,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminStockLocationsRes> {
|
||||
const path = `/admin/stock-locations/${itemId}`
|
||||
return this.client.request("GET", path, undefined, {}, customHeaders)
|
||||
}
|
||||
|
||||
/** update an stock location
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please install @medusajs/stock-location
|
||||
* @description updates an stock location
|
||||
* @returns the updated medusa stock location
|
||||
*/
|
||||
update(
|
||||
stockLocationId: string,
|
||||
payload: AdminPostStockLocationsLocationReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminStockLocationsRes> {
|
||||
const path = `/admin/stock-locations/${stockLocationId}`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of stock locations
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please install @medusajs/stock-location
|
||||
* @description Retrieve a list of stock locations
|
||||
* @returns the list of stock locations as well as the pagination properties
|
||||
*/
|
||||
list(
|
||||
query?: AdminGetStockLocationsParams,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminStockLocationsListRes> {
|
||||
let path = `/admin/stock-locations`
|
||||
|
||||
if (query) {
|
||||
const queryString = qs.stringify(query)
|
||||
path += `?${queryString}`
|
||||
}
|
||||
|
||||
return this.client.request("GET", path, undefined, {}, customHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminStockLocationsResource
|
||||
@@ -44,6 +44,7 @@ export * from "./routes/admin/returns"
|
||||
export * from "./routes/admin/sales-channels"
|
||||
export * from "./routes/admin/shipping-options"
|
||||
export * from "./routes/admin/shipping-profiles"
|
||||
export * from "./routes/admin/stock-locations"
|
||||
export * from "./routes/admin/store"
|
||||
export * from "./routes/admin/swaps"
|
||||
export * from "./routes/admin/tax-rates"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { NextFunction, Request, Response } from "express"
|
||||
|
||||
export function checkRegisteredModules(services: {
|
||||
[serviceName: string]: string
|
||||
}): (req: Request, res: Response, next: NextFunction) => Promise<void> {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
for (const service of Object.keys(services)) {
|
||||
if (!req.scope.resolve(service, { allowUnregistered: true })) {
|
||||
return next(new Error(services[service]))
|
||||
}
|
||||
}
|
||||
|
||||
next()
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import returnRoutes from "./returns"
|
||||
import salesChannelRoutes from "./sales-channels"
|
||||
import shippingOptionRoutes from "./shipping-options"
|
||||
import shippingProfileRoutes from "./shipping-profiles"
|
||||
import stockLocationRoutes from "./stock-locations"
|
||||
import storeRoutes from "./store"
|
||||
import swapRoutes from "./swaps"
|
||||
import taxRateRoutes from "./tax-rates"
|
||||
@@ -98,6 +99,7 @@ export default (app, container, config) => {
|
||||
salesChannelRoutes(route)
|
||||
shippingOptionRoutes(route, featureFlagRouter)
|
||||
shippingProfileRoutes(route)
|
||||
stockLocationRoutes(route)
|
||||
storeRoutes(route)
|
||||
swapRoutes(route)
|
||||
taxRateRoutes(route)
|
||||
|
||||
@@ -75,7 +75,7 @@ export default async (req, res) => {
|
||||
result = await claimService.retrieve(result.claim_order_id)
|
||||
}
|
||||
|
||||
const order = await orderService.retrieve(result.order_id, {
|
||||
const order = await orderService.retrieve(result.order_id!, {
|
||||
select: defaultAdminOrdersFields,
|
||||
relations: defaultAdminOrdersRelations,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import { IsString } from "class-validator"
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
import {
|
||||
SalesChannelService,
|
||||
SalesChannelLocationService,
|
||||
} from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /sales-channels/{id}/stock-locations
|
||||
* operationId: "PostSalesChannelsSalesChannelStockLocation"
|
||||
* summary: "Associate a stock location to a Sales Channel"
|
||||
* description: "Associates a stock location to a Sales Channel."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Sales Channel.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: "#/components/schemas/AdminPostSalesChannelsChannelStockLocationsReq"
|
||||
* 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.salesChannels.addLocation(sales_channel_id, {
|
||||
* location_id: 'App'
|
||||
* })
|
||||
* .then(({ sales_channel }) => {
|
||||
* console.log(sales_channel.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/admin/sales-channels/{id}/stock-locations' \
|
||||
* --header 'Authorization: Bearer {api_token}' \
|
||||
* --header 'Content-Type: application/json' \
|
||||
* --data-raw '{
|
||||
* "locaton_id": "stock_location_id"
|
||||
* }'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Sales Channel
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sales_channel:
|
||||
* $ref: "#/components/schemas/SalesChannel"
|
||||
* "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: Request, res: Response) => {
|
||||
const { id } = req.params
|
||||
const { validatedBody } = req as {
|
||||
validatedBody: AdminPostSalesChannelsChannelStockLocationsReq
|
||||
}
|
||||
|
||||
const salesChannelService: SalesChannelService = req.scope.resolve(
|
||||
"salesChannelService"
|
||||
)
|
||||
const channelLocationService: SalesChannelLocationService = req.scope.resolve(
|
||||
"salesChannelLocationService"
|
||||
)
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
await manager.transaction(async (transactionManager) => {
|
||||
return await channelLocationService
|
||||
.withTransaction(transactionManager)
|
||||
.associateLocation(id, validatedBody.location_id)
|
||||
})
|
||||
|
||||
const channel = await salesChannelService.retrieve(id)
|
||||
|
||||
res.status(200).json({ sales_channel: channel })
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema AdminPostSalesChannelsChannelStockLocationsReq
|
||||
* type: object
|
||||
* required:
|
||||
* - location_id
|
||||
* properties:
|
||||
* location_id:
|
||||
* description: The ID of the stock location
|
||||
* type: string
|
||||
*/
|
||||
|
||||
export class AdminPostSalesChannelsChannelStockLocationsReq {
|
||||
@IsString()
|
||||
location_id: string
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import { AdminPostSalesChannelsReq } from "./create-sales-channel"
|
||||
import { AdminDeleteSalesChannelsChannelProductsBatchReq } from "./delete-products-batch"
|
||||
import { AdminGetSalesChannelsParams } from "./list-sales-channels"
|
||||
import { AdminPostSalesChannelsSalesChannelReq } from "./update-sales-channel"
|
||||
import { AdminPostSalesChannelsChannelStockLocationsReq } from "./associate-stock-location"
|
||||
import { AdminDeleteSalesChannelsChannelStockLocationsReq } from "./remove-stock-location"
|
||||
|
||||
const route = Router()
|
||||
|
||||
@@ -43,6 +45,16 @@ export default (app) => {
|
||||
transformBody(AdminPostSalesChannelsSalesChannelReq),
|
||||
middlewares.wrap(require("./update-sales-channel").default)
|
||||
)
|
||||
salesChannelRouter.post(
|
||||
"/stock-locations",
|
||||
transformBody(AdminPostSalesChannelsChannelStockLocationsReq),
|
||||
middlewares.wrap(require("./associate-stock-location").default)
|
||||
)
|
||||
salesChannelRouter.delete(
|
||||
"/stock-locations",
|
||||
transformBody(AdminDeleteSalesChannelsChannelStockLocationsReq),
|
||||
middlewares.wrap(require("./remove-stock-location").default)
|
||||
)
|
||||
salesChannelRouter.delete(
|
||||
"/products/batch",
|
||||
transformBody(AdminDeleteSalesChannelsChannelProductsBatchReq),
|
||||
@@ -81,3 +93,5 @@ export * from "./delete-sales-channel"
|
||||
export * from "./get-sales-channel"
|
||||
export * from "./list-sales-channels"
|
||||
export * from "./update-sales-channel"
|
||||
export * from "./associate-stock-location"
|
||||
export * from "./remove-stock-location"
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { IsString } from "class-validator"
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
|
||||
import { SalesChannelLocationService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [delete] /sales-channels/{id}/stock-locations
|
||||
* operationId: "DeleteSalesChannelsSalesChannelStockLocation"
|
||||
* summary: "Remove a stock location from a Sales Channel"
|
||||
* description: "Removes a stock location from a Sales Channel."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Sales Channel.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: "#/components/schemas/AdminDeleteSalesChannelsChannelStockLocationsReq"
|
||||
* 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.salesChannels.removeLocation(sales_channel_id, {
|
||||
* location_id: 'App'
|
||||
* })
|
||||
* .then(({ sales_channel }) => {
|
||||
* console.log(sales_channel.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request DELETE 'https://medusa-url.com/admin/sales-channels/{id}/stock-locations' \
|
||||
* --header 'Authorization: Bearer {api_token}' \
|
||||
* --header 'Content-Type: application/json' \
|
||||
* --data-raw '{
|
||||
* "locaton_id": "stock_location_id"
|
||||
* }'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Sales Channel
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: The ID of the removed stock location from a sales channel
|
||||
* object:
|
||||
* type: string
|
||||
* description: The type of the object that was removed.
|
||||
* default: stock-location
|
||||
* deleted:
|
||||
* type: boolean
|
||||
* description: Whether or not the items were deleted.
|
||||
* default: true
|
||||
* "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: Request, res: Response) => {
|
||||
const { id } = req.params
|
||||
const { validatedBody } = req as {
|
||||
validatedBody: AdminDeleteSalesChannelsChannelStockLocationsReq
|
||||
}
|
||||
|
||||
const channelLocationService: SalesChannelLocationService = req.scope.resolve(
|
||||
"salesChannelLocationService"
|
||||
)
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
await manager.transaction(async (transactionManager) => {
|
||||
await channelLocationService
|
||||
.withTransaction(transactionManager)
|
||||
.removeLocation(id, validatedBody.location_id)
|
||||
})
|
||||
|
||||
res.json({
|
||||
id,
|
||||
object: "stock-location",
|
||||
deleted: true,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema AdminDeleteSalesChannelsChannelStockLocationsReq
|
||||
* type: object
|
||||
* required:
|
||||
* - location_id
|
||||
* properties:
|
||||
* location_id:
|
||||
* description: The ID of the stock location
|
||||
* type: string
|
||||
*/
|
||||
export class AdminDeleteSalesChannelsChannelStockLocationsReq {
|
||||
@IsString()
|
||||
location_id: string
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import { Request, Response } from "express"
|
||||
import { Type } from "class-transformer"
|
||||
import { ValidateNested, IsOptional, IsString, IsObject } from "class-validator"
|
||||
|
||||
import { IStockLocationService } from "../../../../interfaces"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /stock-locations
|
||||
* operationId: "PostStockLocations"
|
||||
* summary: "Create a Stock Location"
|
||||
* description: "Creates a Stock Location."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (query) expand {string} Comma separated list of relations to include in the results.
|
||||
* - (query) fields {string} Comma separated list of fields to include in the results.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: "#/components/schemas/AdminPostStockLocationsReq"
|
||||
* 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.stockLocations.create({
|
||||
* name: 'Main Warehouse',
|
||||
* location_id: 'sloc'
|
||||
* })
|
||||
* .then(({ stock_location }) => {
|
||||
* console.log(stock_location.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/admin/stock-locations' \
|
||||
* --header 'Authorization: Bearer {api_token}' \
|
||||
* --header 'Content-Type: application/json' \
|
||||
* --data-raw '{
|
||||
* "name": "App"
|
||||
* }'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Stock Location
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* stock_location:
|
||||
* $ref: "#/components/schemas/StockLocationDTO"
|
||||
* "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: Request, res: Response) => {
|
||||
const locationService: IStockLocationService = req.scope.resolve(
|
||||
"stockLocationService"
|
||||
)
|
||||
|
||||
const createdStockLocation = await locationService.create(
|
||||
req.validatedBody as AdminPostStockLocationsReq
|
||||
)
|
||||
|
||||
const stockLocation = await locationService.retrieve(
|
||||
createdStockLocation.id,
|
||||
req.retrieveConfig
|
||||
)
|
||||
|
||||
res.status(200).json({ stock_location: stockLocation })
|
||||
}
|
||||
|
||||
class StockLocationAddress {
|
||||
@IsString()
|
||||
address_1: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
address_2?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
city?: string
|
||||
|
||||
@IsString()
|
||||
country_code: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
phone?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
postal_code?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
province?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema AdminPostStockLocationsReq
|
||||
* type: object
|
||||
* required:
|
||||
* - name
|
||||
* properties:
|
||||
* name:
|
||||
* description: the name of the stock location
|
||||
* type: string
|
||||
* address_id:
|
||||
* description: the stock location address ID
|
||||
* type: string
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
* address:
|
||||
* $ref: "#/components/schemas/StockLocationAddressInput"
|
||||
*/
|
||||
export class AdminPostStockLocationsReq {
|
||||
@IsString()
|
||||
name: string
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => StockLocationAddress)
|
||||
address?: StockLocationAddress
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
address_id?: string
|
||||
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export class AdminPostStockLocationsParams extends FindParams {}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { IStockLocationService } from "../../../../interfaces"
|
||||
import { Request, Response } from "express"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /stock-locations/{id}
|
||||
* operationId: "GetStockLocationsStockLocation"
|
||||
* summary: "Get a Stock Location"
|
||||
* description: "Retrieves the Stock Location."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Stock Location.
|
||||
* - (query) expand {string} Comma separated list of relations to include in the results.
|
||||
* - (query) fields {string} Comma separated list of fields to include in the results.
|
||||
* 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.stockLocations.retrieve(stock_location_id)
|
||||
* .then(({ stock_location }) => {
|
||||
* console.log(stock_location.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request GET 'https://medusa-url.com/admin/stock-locations/{id}' \
|
||||
* --header 'Authorization: Bearer {api_token}' \
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Stock Location
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* stock_location:
|
||||
* $ref: "#/components/schemas/StockLocationDTO"
|
||||
*/
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { id } = req.params
|
||||
|
||||
const locationService: IStockLocationService = req.scope.resolve(
|
||||
"stockLocationService"
|
||||
)
|
||||
const stockLocation = await locationService.retrieve(id, req.retrieveConfig)
|
||||
|
||||
res.status(200).json({ stock_location: stockLocation })
|
||||
}
|
||||
|
||||
export class AdminGetStockLocationsLocationParams extends FindParams {}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Router } from "express"
|
||||
import "reflect-metadata"
|
||||
import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
|
||||
import { StockLocationDTO } from "../../../../types/stock-location"
|
||||
import middlewares, {
|
||||
transformBody,
|
||||
transformQuery,
|
||||
} from "../../../middlewares"
|
||||
import { AdminGetStockLocationsParams } from "./list-stock-locations"
|
||||
import { AdminGetStockLocationsLocationParams } from "./get-stock-location"
|
||||
import {
|
||||
AdminPostStockLocationsLocationParams,
|
||||
AdminPostStockLocationsLocationReq,
|
||||
} from "./update-stock-location"
|
||||
import {
|
||||
AdminPostStockLocationsParams,
|
||||
AdminPostStockLocationsReq,
|
||||
} from "./create-stock-location"
|
||||
import { checkRegisteredModules } from "../../../middlewares/check-registered-modules"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default (app) => {
|
||||
app.use(
|
||||
"/stock-locations",
|
||||
checkRegisteredModules({
|
||||
stockLocationService:
|
||||
"Stock Locations are not enabled. Please add a Stock Location module to enable this functionality.",
|
||||
}),
|
||||
route
|
||||
)
|
||||
|
||||
route.get(
|
||||
"/",
|
||||
transformQuery(AdminGetStockLocationsParams, {
|
||||
defaultFields: defaultAdminStockLocationFields,
|
||||
defaultRelations: defaultAdminStockLocationRelations,
|
||||
isList: true,
|
||||
}),
|
||||
middlewares.wrap(require("./list-stock-locations").default)
|
||||
)
|
||||
route.post(
|
||||
"/",
|
||||
transformQuery(AdminPostStockLocationsParams, {
|
||||
defaultFields: defaultAdminStockLocationFields,
|
||||
defaultRelations: defaultAdminStockLocationRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostStockLocationsReq),
|
||||
middlewares.wrap(require("./create-stock-location").default)
|
||||
)
|
||||
|
||||
route.get(
|
||||
"/:id",
|
||||
transformQuery(AdminGetStockLocationsLocationParams, {
|
||||
defaultFields: defaultAdminStockLocationFields,
|
||||
defaultRelations: defaultAdminStockLocationRelations,
|
||||
isList: false,
|
||||
}),
|
||||
middlewares.wrap(require("./get-stock-location").default)
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/:id",
|
||||
transformQuery(AdminPostStockLocationsLocationParams, {
|
||||
defaultFields: defaultAdminStockLocationFields,
|
||||
defaultRelations: defaultAdminStockLocationRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostStockLocationsLocationReq),
|
||||
middlewares.wrap(require("./update-stock-location").default)
|
||||
)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export const defaultAdminStockLocationFields: (keyof StockLocationDTO)[] = [
|
||||
"id",
|
||||
"name",
|
||||
"address_id",
|
||||
"metadata",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
export const defaultAdminStockLocationRelations = []
|
||||
|
||||
export type AdminStockLocationsRes = {
|
||||
stock_location: StockLocationDTO
|
||||
}
|
||||
|
||||
export type AdminStockLocationsDeleteRes = DeleteResponse
|
||||
|
||||
export type AdminStockLocationsListRes = PaginatedResponse & {
|
||||
stock_locations: StockLocationDTO[]
|
||||
}
|
||||
|
||||
export * from "./list-stock-locations"
|
||||
export * from "./get-stock-location"
|
||||
export * from "./create-stock-location"
|
||||
export * from "./update-stock-location"
|
||||
@@ -0,0 +1,179 @@
|
||||
import { IsOptional } from "class-validator"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
|
||||
import { IStockLocationService } from "../../../../interfaces"
|
||||
import { extendedFindParamsMixin } from "../../../../types/common"
|
||||
import { Request, Response } from "express"
|
||||
|
||||
/**
|
||||
* @oas [get] /stock-locations
|
||||
* operationId: "GetStockLocations"
|
||||
* summary: "List Stock Locations"
|
||||
* description: "Retrieves a list of stock locations"
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (query) id {string} ID of the stock location
|
||||
* - (query) name {string} Name of the stock location
|
||||
* - (query) order {string} The field to order the results by.
|
||||
* - in: query
|
||||
* name: created_at
|
||||
* description: Date comparison for when resulting collections were created.
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* lt:
|
||||
* type: string
|
||||
* description: filter by dates less than this date
|
||||
* format: date
|
||||
* gt:
|
||||
* type: string
|
||||
* description: filter by dates greater than this date
|
||||
* format: date
|
||||
* lte:
|
||||
* type: string
|
||||
* description: filter by dates less than or equal to this date
|
||||
* format: date
|
||||
* gte:
|
||||
* type: string
|
||||
* description: filter by dates greater than or equal to this date
|
||||
* format: date
|
||||
* - in: query
|
||||
* name: updated_at
|
||||
* description: Date comparison for when resulting collections were updated.
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* lt:
|
||||
* type: string
|
||||
* description: filter by dates less than this date
|
||||
* format: date
|
||||
* gt:
|
||||
* type: string
|
||||
* description: filter by dates greater than this date
|
||||
* format: date
|
||||
* lte:
|
||||
* type: string
|
||||
* description: filter by dates less than or equal to this date
|
||||
* format: date
|
||||
* gte:
|
||||
* type: string
|
||||
* description: filter by dates greater than or equal to this date
|
||||
* format: date
|
||||
* - in: query
|
||||
* name: deleted_at
|
||||
* description: Date comparison for when resulting collections were deleted.
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* lt:
|
||||
* type: string
|
||||
* description: filter by dates less than this date
|
||||
* format: date
|
||||
* gt:
|
||||
* type: string
|
||||
* description: filter by dates greater than this date
|
||||
* format: date
|
||||
* lte:
|
||||
* type: string
|
||||
* description: filter by dates less than or equal to this date
|
||||
* format: date
|
||||
* gte:
|
||||
* type: string
|
||||
* description: filter by dates greater than or equal to this date
|
||||
* format: date
|
||||
* - (query) offset=0 {integer} How many stock locations to skip in the result.
|
||||
* - (query) limit=20 {integer} Limit the number of stock locations returned.
|
||||
* - (query) expand {string} (Comma separated) Which fields should be expanded in each stock location of the result.
|
||||
* - (query) fields {string} (Comma separated) Which fields should be included in each stock location of the result.
|
||||
* 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.stockLocations.list()
|
||||
* .then(({ stock_locations, limit, offset, count }) => {
|
||||
* console.log(stock_locations.length);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request GET 'https://medusa-url.com/admin/stock-locations' \
|
||||
* --header 'Authorization: Bearer {api_token}'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Sales Channel
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* stock_locations:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/StockLocationDTO"
|
||||
* count:
|
||||
* type: integer
|
||||
* description: The total number of items available
|
||||
* offset:
|
||||
* type: integer
|
||||
* description: The number of items skipped before these items
|
||||
* limit:
|
||||
* type: integer
|
||||
* description: The number of items per page
|
||||
* "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: Request, res: Response) => {
|
||||
const stockLocationService: IStockLocationService = req.scope.resolve(
|
||||
"stockLocationService"
|
||||
)
|
||||
|
||||
const { filterableFields, listConfig } = req
|
||||
const { skip, take } = listConfig
|
||||
|
||||
const [locations, count] = await stockLocationService.listAndCount(
|
||||
filterableFields,
|
||||
listConfig
|
||||
)
|
||||
|
||||
res.status(200).json({
|
||||
stock_locations: locations,
|
||||
count,
|
||||
offset: skip,
|
||||
limit: take,
|
||||
})
|
||||
}
|
||||
|
||||
export class AdminGetStockLocationsParams extends extendedFindParamsMixin({
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}) {
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
name?: string | string[]
|
||||
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
address_id?: string | string[]
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import { Request, Response } from "express"
|
||||
import { Type } from "class-transformer"
|
||||
import { ValidateNested, IsOptional, IsString, IsObject } from "class-validator"
|
||||
|
||||
import { IStockLocationService } from "../../../../interfaces"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /stock-locations/{id}
|
||||
* operationId: "PostStockLocationsStockLocation"
|
||||
* summary: "Update a Stock Location"
|
||||
* description: "Updates a Stock Location."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Stock Location.
|
||||
* - (query) expand {string} Comma separated list of relations to include in the results.
|
||||
* - (query) fields {string} Comma separated list of fields to include in the results.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: "#/components/schemas/AdminPostStockLocationsLocationReq"
|
||||
* 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.stockLocations.update(stock_location_id, {
|
||||
* name: 'App'
|
||||
* })
|
||||
* .then(({ stock_location }) => {
|
||||
* console.log(stock_location.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/admin/stock-locations/{id}' \
|
||||
* --header 'Authorization: Bearer {api_token}' \
|
||||
* --header 'Content-Type: application/json' \
|
||||
* --data-raw '{
|
||||
* "name": "App"
|
||||
* }'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Stock Location
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* stock_location:
|
||||
* $ref: "#/components/schemas/StockLocationDTO"
|
||||
* "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: Request, res: Response) => {
|
||||
const { id } = req.params
|
||||
|
||||
const locationService: IStockLocationService = req.scope.resolve(
|
||||
"stockLocationService"
|
||||
)
|
||||
|
||||
await locationService.update(
|
||||
id,
|
||||
req.validatedBody as AdminPostStockLocationsLocationReq
|
||||
)
|
||||
|
||||
const stockLocation = await locationService.retrieve(id, req.retrieveConfig)
|
||||
|
||||
res.status(200).json({ stock_location: stockLocation })
|
||||
}
|
||||
|
||||
class StockLocationAddress {
|
||||
@IsString()
|
||||
address_1: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
address_2?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
city?: string
|
||||
|
||||
@IsString()
|
||||
country_code: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
phone?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
postal_code?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
province?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema AdminPostStockLocationsLocationReq
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* description: the name of the stock location
|
||||
* type: string
|
||||
* address_id:
|
||||
* description: the stock location address ID
|
||||
* type: string
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
* address:
|
||||
* $ref: "#/components/schemas/StockLocationAddressInput"
|
||||
*/
|
||||
export class AdminPostStockLocationsLocationReq {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => StockLocationAddress)
|
||||
address?: StockLocationAddress
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
address_id?: string
|
||||
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export class AdminPostStockLocationsLocationParams extends FindParams {}
|
||||
@@ -9,3 +9,6 @@ export * from "./types/global"
|
||||
export * from "./models"
|
||||
export * from "./services"
|
||||
export * from "./utils"
|
||||
export * from "./types/global"
|
||||
export * from "./types/stock-location"
|
||||
export * from "./types/common"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface IEventBusService {
|
||||
emit(event: string, data: any): Promise<void>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./cache"
|
||||
export * from "./event-bus"
|
||||
export * from "./stock-location"
|
||||
export * from "./inventory"
|
||||
|
||||
@@ -18,7 +18,10 @@ export interface IStockLocationService {
|
||||
config?: FindConfig<StockLocationDTO>
|
||||
): Promise<[StockLocationDTO[], number]>
|
||||
|
||||
retrieve(id: string): Promise<StockLocationDTO>
|
||||
retrieve(
|
||||
id: string,
|
||||
config?: FindConfig<StockLocationDTO>
|
||||
): Promise<StockLocationDTO>
|
||||
|
||||
create(input: CreateStockLocationInput): Promise<StockLocationDTO>
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ export * from "./region"
|
||||
export * from "./return"
|
||||
export * from "./return-item"
|
||||
export * from "./return-reason"
|
||||
export * from "./sales-channel-location"
|
||||
export * from "./sales-channel"
|
||||
export * from "./sales-channel-location"
|
||||
export * from "./shipping-method"
|
||||
|
||||
@@ -108,8 +108,8 @@ export class LineItem extends BaseEntity {
|
||||
@Column()
|
||||
title: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
description: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
description: string | null
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
thumbnail: string | null
|
||||
@@ -126,14 +126,14 @@ export class LineItem extends BaseEntity {
|
||||
@Column({ default: true })
|
||||
allow_discounts: boolean
|
||||
|
||||
@Column({ nullable: true })
|
||||
has_shipping: boolean
|
||||
@Column({ nullable: true, type: "boolean" })
|
||||
has_shipping: boolean | null
|
||||
|
||||
@Column({ type: "int" })
|
||||
unit_price: number
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true })
|
||||
@Column({ nullable: true, type: "text" })
|
||||
variant_id: string | null
|
||||
|
||||
@ManyToOne(() => ProductVariant, { eager: true })
|
||||
@@ -144,13 +144,13 @@ export class LineItem extends BaseEntity {
|
||||
quantity: number
|
||||
|
||||
@Column({ nullable: true, type: "int" })
|
||||
fulfilled_quantity: number
|
||||
fulfilled_quantity: number | null
|
||||
|
||||
@Column({ nullable: true, type: "int" })
|
||||
returned_quantity: number
|
||||
returned_quantity: number | null
|
||||
|
||||
@Column({ nullable: true, type: "int" })
|
||||
shipped_quantity: number
|
||||
shipped_quantity: number | null
|
||||
|
||||
@DbAwareColumn({ type: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown>
|
||||
|
||||
@@ -41,24 +41,24 @@ export class Return extends BaseEntity {
|
||||
items: ReturnItem[]
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true })
|
||||
swap_id: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
swap_id: string | null
|
||||
|
||||
@OneToOne(() => Swap, (swap) => swap.return_order)
|
||||
@JoinColumn({ name: "swap_id" })
|
||||
swap: Swap
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true })
|
||||
claim_order_id: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
claim_order_id: string | null
|
||||
|
||||
@OneToOne(() => ClaimOrder, (co) => co.return_order)
|
||||
@JoinColumn({ name: "claim_order_id" })
|
||||
claim_order: ClaimOrder
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true })
|
||||
order_id: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
order_id: string | null
|
||||
|
||||
@ManyToOne(() => Order, (o) => o.returns)
|
||||
@JoinColumn({ name: "order_id" })
|
||||
@@ -69,13 +69,13 @@ export class Return extends BaseEntity {
|
||||
})
|
||||
shipping_method: ShippingMethod
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true, type: "text" })
|
||||
location_id: string | null
|
||||
|
||||
@DbAwareColumn({ type: "jsonb", nullable: true })
|
||||
shipping_data: Record<string, unknown>
|
||||
|
||||
@Index()
|
||||
@Column({ nullable: true })
|
||||
location_id: string
|
||||
|
||||
@Column({ type: "int" })
|
||||
refund_amount: number
|
||||
|
||||
@@ -83,13 +83,13 @@ export class Return extends BaseEntity {
|
||||
received_at: Date
|
||||
|
||||
@Column({ type: "boolean", nullable: true })
|
||||
no_notification: boolean
|
||||
no_notification: boolean | null
|
||||
|
||||
@DbAwareColumn({ type: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown>
|
||||
metadata: Record<string, unknown> | null
|
||||
|
||||
@Column({ nullable: true })
|
||||
idempotency_key: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
idempotency_key: string | null
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { FeatureFlagEntity } from "../utils/feature-flag-decorators"
|
||||
import { BaseEntity } from "../interfaces"
|
||||
import { generateEntityId } from "../utils"
|
||||
|
||||
@FeatureFlagEntity("sales_channels")
|
||||
export class SalesChannelLocation extends BaseEntity {
|
||||
@Index()
|
||||
@Column({ type: "text" })
|
||||
|
||||
@@ -45,23 +45,23 @@ export class Store extends BaseEntity {
|
||||
})
|
||||
currencies: Currency[]
|
||||
|
||||
@Column({ nullable: true })
|
||||
swap_link_template: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
swap_link_template: string | null
|
||||
|
||||
@Column({ nullable: true })
|
||||
payment_link_template: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
payment_link_template: string | null
|
||||
|
||||
@Column({ nullable: true })
|
||||
invite_link_template: string
|
||||
@Column({ nullable: true, type: "text" })
|
||||
invite_link_template: string | null
|
||||
|
||||
@Column({ nullable: true })
|
||||
default_location_id: string
|
||||
|
||||
@DbAwareColumn({ type: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown>
|
||||
metadata: Record<string, unknown> | null
|
||||
|
||||
@FeatureFlagColumn("sales_channels", { nullable: true })
|
||||
default_sales_channel_id: string
|
||||
@FeatureFlagColumn("sales_channels", { nullable: true, type: "text" })
|
||||
default_sales_channel_id: string | null
|
||||
|
||||
@FeatureFlagDecorators("sales_channels", [
|
||||
OneToOne(() => SalesChannel),
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
EntityRepository,
|
||||
FindConditions,
|
||||
FindManyOptions,
|
||||
FindOperator,
|
||||
OrderByCondition,
|
||||
Repository,
|
||||
} from "typeorm"
|
||||
|
||||
@@ -37,27 +37,27 @@ import {
|
||||
import { buildQuery, setMetadata } from "../utils"
|
||||
import { FlagRouter } from "../utils/flag-router"
|
||||
import { validateEmail } from "../utils/is-email"
|
||||
import CustomShippingOptionService from "./custom-shipping-option"
|
||||
import CustomerService from "./customer"
|
||||
import DiscountService from "./discount"
|
||||
import EventBusService from "./event-bus"
|
||||
import GiftCardService from "./gift-card"
|
||||
import {
|
||||
NewTotalsService,
|
||||
ProductVariantInventoryService,
|
||||
SalesChannelService,
|
||||
} from "./index"
|
||||
import LineItemService from "./line-item"
|
||||
import LineItemAdjustmentService from "./line-item-adjustment"
|
||||
import PaymentProviderService from "./payment-provider"
|
||||
import ProductService from "./product"
|
||||
import ProductVariantService from "./product-variant"
|
||||
import RegionService from "./region"
|
||||
import ShippingOptionService from "./shipping-option"
|
||||
import StoreService from "./store"
|
||||
import TaxProviderService from "./tax-provider"
|
||||
import TotalsService from "./totals"
|
||||
import { PaymentSessionInput } from "../types/payment"
|
||||
import {
|
||||
CustomShippingOptionService,
|
||||
CustomerService,
|
||||
DiscountService,
|
||||
EventBusService,
|
||||
GiftCardService,
|
||||
LineItemService,
|
||||
LineItemAdjustmentService,
|
||||
NewTotalsService,
|
||||
PaymentProviderService,
|
||||
ProductService,
|
||||
ProductVariantService,
|
||||
ProductVariantInventoryService,
|
||||
RegionService,
|
||||
ShippingOptionService,
|
||||
StoreService,
|
||||
TaxProviderService,
|
||||
TotalsService,
|
||||
SalesChannelService,
|
||||
} from "."
|
||||
|
||||
type InjectedDependencies = {
|
||||
manager: EntityManager
|
||||
@@ -584,11 +584,7 @@ class CartService extends TransactionBaseService {
|
||||
{ sales_channel_id }: { sales_channel_id: string | null },
|
||||
lineItem: LineItemValidateData
|
||||
): Promise<boolean> {
|
||||
if (!sales_channel_id) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (!lineItem.variant_id) {
|
||||
if (!sales_channel_id || !lineItem.variant_id) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class ClaimItemService extends TransactionBaseService {
|
||||
)
|
||||
}
|
||||
|
||||
if (lineItem.fulfilled_quantity < quantity) {
|
||||
if (lineItem.fulfilled_quantity! < quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Cannot claim more of an item than has been fulfilled."
|
||||
|
||||
@@ -332,8 +332,8 @@ export default class ClaimService extends TransactionBaseService {
|
||||
lines as LineItem[]
|
||||
)
|
||||
}
|
||||
|
||||
let newItems: LineItem[] = []
|
||||
|
||||
if (isDefined(additional_items)) {
|
||||
newItems = await Promise.all(
|
||||
additional_items.map(async (i) =>
|
||||
|
||||
@@ -145,7 +145,7 @@ class FulfillmentService extends TransactionBaseService {
|
||||
return null
|
||||
}
|
||||
|
||||
if (quantity > item.quantity - item.fulfilled_quantity) {
|
||||
if (quantity > item.quantity - item.fulfilled_quantity!) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Cannot fulfill more items than have been purchased"
|
||||
@@ -285,7 +285,7 @@ class FulfillmentService extends TransactionBaseService {
|
||||
|
||||
for (const fItem of fulfillment.items) {
|
||||
const item = await lineItemServiceTx.retrieve(fItem.item_id)
|
||||
const fulfilledQuantity = item.fulfilled_quantity - fItem.quantity
|
||||
const fulfilledQuantity = item.fulfilled_quantity! - fItem.quantity
|
||||
await lineItemServiceTx.update(item.id, {
|
||||
fulfilled_quantity: fulfilledQuantity,
|
||||
})
|
||||
|
||||
@@ -30,22 +30,26 @@ import { UpdateOrderInput } from "../types/orders"
|
||||
import { CreateShippingMethodDto } from "../types/shipping-options"
|
||||
import { buildQuery, isString, setMetadata } from "../utils"
|
||||
import { FlagRouter } from "../utils/flag-router"
|
||||
import CartService from "./cart"
|
||||
import CustomerService from "./customer"
|
||||
import DiscountService from "./discount"
|
||||
import DraftOrderService from "./draft-order"
|
||||
import EventBusService from "./event-bus"
|
||||
import FulfillmentService from "./fulfillment"
|
||||
import FulfillmentProviderService from "./fulfillment-provider"
|
||||
import GiftCardService from "./gift-card"
|
||||
import LineItemService from "./line-item"
|
||||
import PaymentProviderService from "./payment-provider"
|
||||
import RegionService from "./region"
|
||||
import ShippingOptionService from "./shipping-option"
|
||||
import ShippingProfileService from "./shipping-profile"
|
||||
import TotalsService from "./totals"
|
||||
import ProductVariantInventoryService from "./product-variant-inventory"
|
||||
import { NewTotalsService, TaxProviderService } from "./index"
|
||||
|
||||
import {
|
||||
CartService,
|
||||
CustomerService,
|
||||
DiscountService,
|
||||
DraftOrderService,
|
||||
EventBusService,
|
||||
FulfillmentService,
|
||||
FulfillmentProviderService,
|
||||
GiftCardService,
|
||||
ProductVariantInventoryService,
|
||||
LineItemService,
|
||||
PaymentProviderService,
|
||||
RegionService,
|
||||
ShippingOptionService,
|
||||
ShippingProfileService,
|
||||
TotalsService,
|
||||
NewTotalsService,
|
||||
TaxProviderService,
|
||||
} from "."
|
||||
|
||||
export const ORDER_CART_ALREADY_EXISTS_ERROR = "Order from cart already exists"
|
||||
|
||||
@@ -1264,7 +1268,7 @@ class OrderService extends TransactionBaseService {
|
||||
return null
|
||||
}
|
||||
|
||||
if (quantity > item.quantity - item.fulfilled_quantity) {
|
||||
if (quantity > item.quantity - item.fulfilled_quantity!) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Cannot fulfill more items than have been purchased"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||
import { DeepPartial, EntityManager } from "typeorm"
|
||||
import { ProductVariantInventoryService } from "."
|
||||
import { TransactionBaseService } from "../interfaces"
|
||||
import {
|
||||
FulfillmentStatus,
|
||||
@@ -17,13 +16,17 @@ import { FindConfig, Selector } from "../types/common"
|
||||
import { OrdersReturnItem } from "../types/orders"
|
||||
import { CreateReturnInput, UpdateReturnInput } from "../types/return"
|
||||
import { buildQuery, setMetadata } from "../utils"
|
||||
import FulfillmentProviderService from "./fulfillment-provider"
|
||||
import LineItemService from "./line-item"
|
||||
import OrderService from "./order"
|
||||
import ReturnReasonService from "./return-reason"
|
||||
import ShippingOptionService from "./shipping-option"
|
||||
import TaxProviderService from "./tax-provider"
|
||||
import TotalsService from "./totals"
|
||||
|
||||
import {
|
||||
FulfillmentProviderService,
|
||||
ProductVariantInventoryService,
|
||||
LineItemService,
|
||||
OrderService,
|
||||
ReturnReasonService,
|
||||
ShippingOptionService,
|
||||
TaxProviderService,
|
||||
TotalsService,
|
||||
} from "."
|
||||
|
||||
type InjectedDependencies = {
|
||||
manager: EntityManager
|
||||
@@ -226,7 +229,7 @@ class ReturnService extends TransactionBaseService {
|
||||
)
|
||||
}
|
||||
|
||||
const returnable = item.quantity - item.returned_quantity
|
||||
const returnable = item.quantity - item.returned_quantity!
|
||||
if (quantity > returnable) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
@@ -590,7 +593,7 @@ class ReturnService extends TransactionBaseService {
|
||||
|
||||
const order = await this.orderService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(orderId, {
|
||||
.retrieve(orderId!, {
|
||||
relations: [
|
||||
"items",
|
||||
"returns",
|
||||
@@ -671,14 +674,15 @@ class ReturnService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
const inventoryServiceTx =
|
||||
const productVarInventoryTx =
|
||||
this.productVariantInventoryService_.withTransaction(manager)
|
||||
|
||||
for (const line of newLines) {
|
||||
const orderItem = order.items.find((i) => i.id === line.item_id)
|
||||
if (orderItem && orderItem?.variant_id) {
|
||||
await inventoryServiceTx.adjustInventory(
|
||||
if (orderItem && orderItem.variant_id) {
|
||||
await productVarInventoryTx.adjustInventory(
|
||||
orderItem.variant_id,
|
||||
returnObj.location_id,
|
||||
returnObj.location_id!,
|
||||
line.received_quantity
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,13 +11,17 @@ type InjectedDependencies = {
|
||||
manager: EntityManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Service for managing the stock locations of sales channels
|
||||
*/
|
||||
|
||||
class SalesChannelLocationService extends TransactionBaseService {
|
||||
protected manager_: EntityManager
|
||||
protected transactionManager_: EntityManager | undefined
|
||||
|
||||
protected readonly salesChannelService_: SalesChannelService
|
||||
protected readonly eventBusService_: EventBusService
|
||||
protected readonly stockLocationService_: IStockLocationService
|
||||
protected readonly eventBusService: EventBusService
|
||||
protected readonly stockLocationService: IStockLocationService
|
||||
|
||||
constructor({
|
||||
salesChannelService,
|
||||
@@ -30,14 +34,15 @@ class SalesChannelLocationService extends TransactionBaseService {
|
||||
|
||||
this.manager_ = manager
|
||||
this.salesChannelService_ = salesChannelService
|
||||
this.eventBusService_ = eventBusService
|
||||
this.stockLocationService_ = stockLocationService
|
||||
this.eventBusService = eventBusService
|
||||
this.stockLocationService = stockLocationService
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes location from sales channel
|
||||
* @param salesChannelId sales channel id
|
||||
* @param locationId location id
|
||||
* Removes an association between a sales channel and a stock location.
|
||||
* @param {string} salesChannelId - The ID of the sales channel.
|
||||
* @param {string} locationId - The ID of the stock location.
|
||||
* @returns {Promise<void>} A promise that resolves when the association has been removed.
|
||||
*/
|
||||
async removeLocation(
|
||||
salesChannelId: string,
|
||||
@@ -51,9 +56,10 @@ class SalesChannelLocationService extends TransactionBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Links location to sales channel
|
||||
* @param salesChannelId sales channel id
|
||||
* @param locationId location id
|
||||
* Associates a sales channel with a stock location.
|
||||
* @param {string} salesChannelId - The ID of the sales channel.
|
||||
* @param {string} locationId - The ID of the stock location.
|
||||
* @returns {Promise<void>} A promise that resolves when the association has been created.
|
||||
*/
|
||||
async associateLocation(
|
||||
salesChannelId: string,
|
||||
@@ -63,7 +69,7 @@ class SalesChannelLocationService extends TransactionBaseService {
|
||||
const salesChannel = await this.salesChannelService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(salesChannelId)
|
||||
const stockLocation = await this.stockLocationService_.retrieve(locationId)
|
||||
const stockLocation = await this.stockLocationService.retrieve(locationId)
|
||||
|
||||
const salesChannelLocation = manager.create(SalesChannelLocation, {
|
||||
sales_channel_id: salesChannel.id,
|
||||
@@ -74,9 +80,9 @@ class SalesChannelLocationService extends TransactionBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all locations associated with sales channel by id
|
||||
* @param salesChannelId sales channel id
|
||||
* @returns list of location ids associated with sales channel
|
||||
* Lists the stock locations associated with a sales channel.
|
||||
* @param {string} salesChannelId - The ID of the sales channel.
|
||||
* @returns {Promise<string[]>} A promise that resolves with an array of location IDs.
|
||||
*/
|
||||
async listLocations(salesChannelId: string): Promise<string[]> {
|
||||
const manager = this.transactionManager_ || this.manager_
|
||||
|
||||
@@ -1,21 +1,132 @@
|
||||
import { StringComparisonOperator } from "./common"
|
||||
|
||||
/**
|
||||
* @schema StockLocationAddressDTO
|
||||
* title: "Stock Location Address"
|
||||
* description: "Represents a Stock Location Address"
|
||||
* type: object
|
||||
* required:
|
||||
* - address_1
|
||||
* - country_code
|
||||
* - created_at
|
||||
* - updated_at
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: The stock location address' ID
|
||||
* example: laddr_51G4ZW853Y6TFXWPG5ENJ81X42
|
||||
* address_1:
|
||||
* type: string
|
||||
* description: Stock location address
|
||||
* example: 35, Jhon Doe Ave
|
||||
* address_2:
|
||||
* type: string
|
||||
* description: Stock location address' complement
|
||||
* example: apartment 4432
|
||||
* city:
|
||||
* type: string
|
||||
* description: Stock location address' city
|
||||
* example: Mexico city
|
||||
* country_code:
|
||||
* type: string
|
||||
* description: Stock location address' country
|
||||
* example: MX
|
||||
* phone:
|
||||
* type: string
|
||||
* description: Stock location address' phone number
|
||||
* example: +1 555 61646
|
||||
* postal_code:
|
||||
* type: string
|
||||
* description: Stock location address' postal code
|
||||
* example: HD3-1G8
|
||||
* province:
|
||||
* type: string
|
||||
* description: Stock location address' province
|
||||
* example: Sinaloa
|
||||
* created_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the resource was created."
|
||||
* format: date-time
|
||||
* updated_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the resource was updated."
|
||||
* format: date-time
|
||||
* deleted_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the resource was deleted."
|
||||
* format: date-time
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
*/
|
||||
export type StockLocationAddressDTO = {
|
||||
id?: string
|
||||
address_1: string
|
||||
address_2?: string
|
||||
city?: string
|
||||
country_code?: string
|
||||
phone?: string
|
||||
postal_code?: string
|
||||
province?: string
|
||||
address_2?: string | null
|
||||
country_code: string
|
||||
city?: string | null
|
||||
phone?: string | null
|
||||
postal_code?: string | null
|
||||
province?: string | null
|
||||
metadata?: Record<string, unknown> | null
|
||||
created_at: string | Date
|
||||
updated_at: string | Date
|
||||
deleted_at: string | Date | null
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema StockLocationDTO
|
||||
* title: "Stock Location"
|
||||
* description: "Represents a Stock Location"
|
||||
* type: object
|
||||
* required:
|
||||
* - id
|
||||
* - name
|
||||
* - address_id
|
||||
* - created_at
|
||||
* - updated_at
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: The stock location's ID
|
||||
* example: sloc_51G4ZW853Y6TFXWPG5ENJ81X42
|
||||
* address_id:
|
||||
* type: string
|
||||
* description: Stock location address' ID
|
||||
* example: laddr_05B2ZE853Y6FTXWPW85NJ81A44
|
||||
* name:
|
||||
* type: string
|
||||
* description: The name of the stock location
|
||||
* example: Main Warehouse
|
||||
* address:
|
||||
* description: "The Address of the Stock Location"
|
||||
* allOf:
|
||||
* - $ref: "#/components/schemas/StockLocationAddressDTO"
|
||||
* - type: object
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
* created_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the resource was created."
|
||||
* format: date-time
|
||||
* updated_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the resource was updated."
|
||||
* format: date-time
|
||||
* deleted_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the resource was deleted."
|
||||
* format: date-time
|
||||
*/
|
||||
export type StockLocationDTO = {
|
||||
id: string
|
||||
name: string
|
||||
metadata: Record<string, unknown> | null
|
||||
address_id: string
|
||||
address?: StockLocationAddressDTO
|
||||
created_at: string | Date
|
||||
updated_at: string | Date
|
||||
deleted_at: string | Date | null
|
||||
@@ -26,23 +137,115 @@ export type FilterableStockLocationProps = {
|
||||
name?: string | string[] | StringComparisonOperator
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema StockLocationAddressInput
|
||||
* title: "Stock Location Address Input"
|
||||
* description: "Represents a Stock Location Address Input"
|
||||
* type: object
|
||||
* required:
|
||||
* - address_1
|
||||
* - country_code
|
||||
* properties:
|
||||
* address_1:
|
||||
* type: string
|
||||
* description: Stock location address
|
||||
* example: 35, Jhon Doe Ave
|
||||
* address_2:
|
||||
* type: string
|
||||
* description: Stock location address' complement
|
||||
* example: apartment 4432
|
||||
* city:
|
||||
* type: string
|
||||
* description: Stock location address' city
|
||||
* example: Mexico city
|
||||
* country_code:
|
||||
* type: string
|
||||
* description: Stock location address' country
|
||||
* example: MX
|
||||
* phone:
|
||||
* type: string
|
||||
* description: Stock location address' phone number
|
||||
* example: +1 555 61646
|
||||
* postal_code:
|
||||
* type: string
|
||||
* description: Stock location address' postal code
|
||||
* example: HD3-1G8
|
||||
* province:
|
||||
* type: string
|
||||
* description: Stock location address' province
|
||||
* example: Sinaloa
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
*/
|
||||
export type StockLocationAddressInput = {
|
||||
address_1: string
|
||||
address_2?: string
|
||||
country_code: string
|
||||
city?: string
|
||||
country_code?: string
|
||||
phone?: string
|
||||
province?: string
|
||||
postal_code?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema CreateStockLocationInput
|
||||
* title: "Create Stock Location Input"
|
||||
* description: "Represents the Input to create a Stock Location"
|
||||
* type: object
|
||||
* required:
|
||||
* - name
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description: The stock location name
|
||||
* address_id:
|
||||
* type: string
|
||||
* description: The Stock location address ID
|
||||
* address:
|
||||
* description: Stock location address object
|
||||
* allOf:
|
||||
* - $ref: "#/components/schemas/StockLocationAddressInput"
|
||||
* - type: object
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
*/
|
||||
export type CreateStockLocationInput = {
|
||||
name: string
|
||||
address_id?: string
|
||||
address?: string | StockLocationAddressInput
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema UpdateStockLocationInput
|
||||
* title: "Update Stock Location Input"
|
||||
* description: "Represents the Input to update a Stock Location"
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description: The stock location name
|
||||
* address_id:
|
||||
* type: string
|
||||
* description: The Stock location address ID
|
||||
* address:
|
||||
* description: Stock location address object
|
||||
* allOf:
|
||||
* - $ref: "#/components/schemas/StockLocationAddressInput"
|
||||
* - type: object
|
||||
* metadata:
|
||||
* type: object
|
||||
* description: An optional key-value map with additional details
|
||||
* example: {car: "white"}
|
||||
*/
|
||||
export type UpdateStockLocationInput = {
|
||||
name?: string
|
||||
address_id?: string
|
||||
address?: StockLocationAddressInput
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/dist
|
||||
node_modules
|
||||
.DS_store
|
||||
.env*
|
||||
.env
|
||||
*.sql
|
||||
@@ -0,0 +1,10 @@
|
||||
src
|
||||
.turbo
|
||||
.prettierrc
|
||||
.env
|
||||
.babelrc.js
|
||||
.eslintrc
|
||||
.gitignore
|
||||
ormconfig.json
|
||||
tsconfig.json
|
||||
jest.config.md
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
globals: {
|
||||
"ts-jest": {
|
||||
tsConfig: "tsconfig.json",
|
||||
isolatedModules: false,
|
||||
},
|
||||
},
|
||||
transform: {
|
||||
"^.+\\.[jt]s?$": "ts-jest",
|
||||
},
|
||||
testEnvironment: `node`,
|
||||
moduleFileExtensions: [`js`, `ts`],
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "@medusajs/stock-location",
|
||||
"version": "1.0.0",
|
||||
"description": "Stock Location Module for Medusa",
|
||||
"main": "dist/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/stock-location"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"author": "Medusa",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@medusajs/medusa": "^1.7.1",
|
||||
"cross-env": "^5.2.1",
|
||||
"jest": "^25.5.2",
|
||||
"ts-jest": "^25.5.1",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "tsc --build --watch",
|
||||
"prepare": "cross-env NODE_ENV=production yarn run build",
|
||||
"build": "tsc --build",
|
||||
"test": "jest --passWithNoTests",
|
||||
"test:unit": "jest --passWithNoTests"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/medusa": "^1.7.1",
|
||||
"medusa-interfaces": "1.3.3",
|
||||
"typeorm": "^0.2.31"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export const CONNECTION_NAME = "stock_location_connection"
|
||||
@@ -0,0 +1,7 @@
|
||||
import ConnectionLoader from "./loaders/connection"
|
||||
import StockLocationService from "./services/stock-location"
|
||||
import * as SchemaMigration from "./migrations/schema-migrations/1665749860179-setup"
|
||||
|
||||
export const service = StockLocationService
|
||||
export const migrations = [SchemaMigration]
|
||||
export const loaders = [ConnectionLoader]
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ConfigModule } from "@medusajs/medusa"
|
||||
import { ConnectionOptions, createConnection } from "typeorm"
|
||||
import { CONNECTION_NAME } from "../config"
|
||||
|
||||
import { StockLocation, StockLocationAddress } from "../models"
|
||||
|
||||
export default async ({
|
||||
configModule,
|
||||
}: {
|
||||
configModule: ConfigModule
|
||||
}): Promise<void> => {
|
||||
await createConnection({
|
||||
name: CONNECTION_NAME,
|
||||
type: configModule.projectConfig.database_type,
|
||||
url: configModule.projectConfig.database_url,
|
||||
database: configModule.projectConfig.database_database,
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
entities: [StockLocation, StockLocationAddress],
|
||||
logging: configModule.projectConfig.database_logging || false,
|
||||
} as ConnectionOptions)
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { ConfigModule } from "@medusajs/medusa"
|
||||
import {
|
||||
createConnection,
|
||||
ConnectionOptions,
|
||||
MigrationInterface,
|
||||
QueryRunner,
|
||||
} from "typeorm"
|
||||
|
||||
import { CONNECTION_NAME } from "../../config"
|
||||
|
||||
export const up = async ({ configModule }: { configModule: ConfigModule }) => {
|
||||
const connection = await createConnection({
|
||||
name: CONNECTION_NAME,
|
||||
type: configModule.projectConfig.database_type,
|
||||
url: configModule.projectConfig.database_url,
|
||||
database: configModule.projectConfig.database_database,
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
migrations: [setup1665749860179],
|
||||
logging: true,
|
||||
} as ConnectionOptions)
|
||||
|
||||
await connection.runMigrations()
|
||||
}
|
||||
|
||||
export const down = async ({
|
||||
configModule,
|
||||
}: {
|
||||
configModule: ConfigModule
|
||||
}) => {
|
||||
const connection = await createConnection({
|
||||
name: CONNECTION_NAME,
|
||||
type: configModule.projectConfig.database_type,
|
||||
url: configModule.projectConfig.database_url,
|
||||
database: configModule.projectConfig.database_database,
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
migrations: [setup1665749860179],
|
||||
logging: true,
|
||||
} as ConnectionOptions)
|
||||
|
||||
await connection.undoLastMigration({ transaction: "all" })
|
||||
}
|
||||
|
||||
export class setup1665749860179 implements MigrationInterface {
|
||||
name = "setup1665749860179"
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE "stock_location_address"
|
||||
(
|
||||
"id" CHARACTER VARYING NOT NULL,
|
||||
"created_at" TIMESTAMP WITH TIME zone NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMP WITH TIME zone NOT NULL DEFAULT Now(),
|
||||
"deleted_at" TIMESTAMP WITH TIME zone,
|
||||
"address_1" TEXT NOT NULL,
|
||||
"address_2" TEXT,
|
||||
"city" TEXT,
|
||||
"country_code" TEXT NOT NULL,
|
||||
"phone" TEXT,
|
||||
"province" TEXT,
|
||||
"postal_code" TEXT,
|
||||
"metadata" JSONB,
|
||||
CONSTRAINT "PK_b79bc27285bede680501b7b81a5" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "IDX_stock_location_address_country_code" ON "stock_location_address" ("country_code");
|
||||
|
||||
CREATE TABLE "stock_location"
|
||||
(
|
||||
"id" CHARACTER VARYING NOT NULL,
|
||||
"created_at" TIMESTAMP WITH time zone NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMP WITH time zone NOT NULL DEFAULT Now(),
|
||||
"deleted_at" TIMESTAMP WITH time zone,
|
||||
"name" TEXT NOT NULL,
|
||||
"address_id" TEXT NOT NULL,
|
||||
"metadata" JSONB,
|
||||
CONSTRAINT "PK_adf770067d0df1421f525fa25cc" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "IDX_stock_location_address_id" ON "stock_location" ("address_id");
|
||||
`)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
DROP INDEX "IDX_stock_location_address_id";
|
||||
DROP TABLE "stock_location";
|
||||
|
||||
DROP INDEX "IDX_stock_location_address_country_code";
|
||||
DROP TABLE "stock_location_address";
|
||||
`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./stock-location"
|
||||
export * from "./stock-location-address"
|
||||
@@ -0,0 +1,35 @@
|
||||
import { BeforeInsert, Column, Entity, Index } from "typeorm"
|
||||
import { SoftDeletableEntity, generateEntityId } from "@medusajs/medusa"
|
||||
|
||||
@Entity()
|
||||
export class StockLocationAddress extends SoftDeletableEntity {
|
||||
@Column({ type: "text" })
|
||||
address_1: string
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
address_2: string | null
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
city: string | null
|
||||
|
||||
@Index()
|
||||
@Column({ type: "text" })
|
||||
country_code: string
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
phone: string | null
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
province: string | null
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
postal_code: string | null
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
this.id = generateEntityId(this.id, "laddr")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
BeforeInsert,
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
} from "typeorm"
|
||||
import { SoftDeletableEntity, generateEntityId } from "@medusajs/medusa"
|
||||
|
||||
import { StockLocationAddress } from "."
|
||||
|
||||
@Entity()
|
||||
export class StockLocation extends SoftDeletableEntity {
|
||||
@Column({ type: "text" })
|
||||
name: string
|
||||
|
||||
@Index()
|
||||
@Column({ type: "text" })
|
||||
address_id: string
|
||||
|
||||
@ManyToOne(() => StockLocationAddress)
|
||||
@JoinColumn({ name: "address_id" })
|
||||
address: StockLocationAddress | null
|
||||
|
||||
@Column({ type: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
this.id = generateEntityId(this.id, "sloc")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as StockLocationService } from "./stock-location"
|
||||
@@ -0,0 +1,253 @@
|
||||
import { getConnection, EntityManager } from "typeorm"
|
||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||
import {
|
||||
FindConfig,
|
||||
buildQuery,
|
||||
FilterableStockLocationProps,
|
||||
CreateStockLocationInput,
|
||||
UpdateStockLocationInput,
|
||||
StockLocationAddressInput,
|
||||
IEventBusService,
|
||||
setMetadata,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
import { StockLocation, StockLocationAddress } from "../models"
|
||||
import { CONNECTION_NAME } from "../config"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: IEventBusService
|
||||
}
|
||||
|
||||
/**
|
||||
* Service for managing stock locations.
|
||||
*/
|
||||
|
||||
export default class StockLocationService {
|
||||
static Events = {
|
||||
CREATED: "stock-location.created",
|
||||
UPDATED: "stock-location.updated",
|
||||
DELETED: "stock-location.deleted",
|
||||
}
|
||||
|
||||
protected readonly manager_: EntityManager
|
||||
|
||||
protected readonly eventBusService_: IEventBusService
|
||||
|
||||
constructor({ eventBusService }: InjectedDependencies) {
|
||||
this.eventBusService_ = eventBusService
|
||||
}
|
||||
|
||||
private getManager(): EntityManager {
|
||||
const connection = getConnection(CONNECTION_NAME)
|
||||
return connection.manager
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all stock locations that match the given selector.
|
||||
* @param {FilterableStockLocationProps} [selector={}] - Properties to filter by.
|
||||
* @param {FindConfig} [config={ relations: [], skip: 0, take: 10 }] - Additional configuration for the query.
|
||||
* @return {Promise<StockLocation[]>} A list of stock locations.
|
||||
*/
|
||||
async list(
|
||||
selector: FilterableStockLocationProps = {},
|
||||
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 }
|
||||
): Promise<StockLocation[]> {
|
||||
const manager = this.getManager()
|
||||
const locationRepo = manager.getRepository(StockLocation)
|
||||
|
||||
const query = buildQuery(selector, config)
|
||||
return await locationRepo.find(query)
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all stock locations that match the given selector and returns the count of matching stock locations.
|
||||
* @param {FilterableStockLocationProps} [selector={}] - Properties to filter by.
|
||||
* @param {FindConfig} [config={ relations: [], skip: 0, take: 10 }] - Additional configuration for the query.
|
||||
* @return {Promise<[StockLocation[], number]>} A list of stock locations and the count of matching stock locations.
|
||||
*/
|
||||
async listAndCount(
|
||||
selector: FilterableStockLocationProps = {},
|
||||
config: FindConfig<StockLocation> = { relations: [], skip: 0, take: 10 }
|
||||
): Promise<[StockLocation[], number]> {
|
||||
const manager = this.getManager()
|
||||
const locationRepo = manager.getRepository(StockLocation)
|
||||
|
||||
const query = buildQuery(selector, config)
|
||||
return await locationRepo.findAndCount(query)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a stock location by its ID.
|
||||
* @param {string} stockLocationId - The ID of the stock location.
|
||||
* @param {FindConfig} [config={}] - Additional configuration for the query.
|
||||
* @return {Promise<StockLocation>} The stock location.
|
||||
* @throws {MedusaError} If the stock location ID is not defined.
|
||||
* @throws {MedusaError} If the stock location with the given ID was not found.
|
||||
*/
|
||||
async retrieve(
|
||||
stockLocationId: string,
|
||||
config: FindConfig<StockLocation> = {}
|
||||
): Promise<StockLocation> {
|
||||
if (!isDefined(stockLocationId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`"stockLocationId" must be defined`
|
||||
)
|
||||
}
|
||||
|
||||
const manager = this.getManager()
|
||||
const locationRepo = manager.getRepository(StockLocation)
|
||||
|
||||
const query = buildQuery({ id: stockLocationId }, config)
|
||||
const loc = await locationRepo.findOne(query)
|
||||
|
||||
if (!loc) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`StockLocation with id ${stockLocationId} was not found`
|
||||
)
|
||||
}
|
||||
|
||||
return loc
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stock location.
|
||||
* @param {CreateStockLocationInput} data - The input data for creating a stock location.
|
||||
* @returns {Promise<StockLocation>} - The created stock location.
|
||||
*/
|
||||
async create(data: CreateStockLocationInput): Promise<StockLocation> {
|
||||
const defaultManager = this.getManager()
|
||||
return await defaultManager.transaction(async (manager) => {
|
||||
const locationRepo = manager.getRepository(StockLocation)
|
||||
|
||||
const loc = locationRepo.create({
|
||||
name: data.name,
|
||||
})
|
||||
|
||||
if (isDefined(data.address) || isDefined(data.address_id)) {
|
||||
if (typeof data.address === "string" || data.address_id) {
|
||||
const addrId = (data.address ?? data.address_id) as string
|
||||
const address = await this.retrieve(addrId, {
|
||||
select: ["id"],
|
||||
})
|
||||
loc.address_id = address.id
|
||||
} else {
|
||||
const locAddressRepo = manager.getRepository(StockLocationAddress)
|
||||
const locAddress = locAddressRepo.create(data.address!)
|
||||
const addressResult = await locAddressRepo.save(locAddress)
|
||||
loc.address_id = addressResult.id
|
||||
}
|
||||
}
|
||||
|
||||
const { metadata } = data
|
||||
if (metadata) {
|
||||
loc.metadata = setMetadata(loc, metadata)
|
||||
}
|
||||
|
||||
const result = await locationRepo.save(loc)
|
||||
|
||||
await this.eventBusService_.emit(StockLocationService.Events.CREATED, {
|
||||
id: result.id,
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing stock location.
|
||||
* @param {string} stockLocationId - The ID of the stock location to update.
|
||||
* @param {UpdateStockLocationInput} updateData - The update data for the stock location.
|
||||
* @returns {Promise<StockLocation>} - The updated stock location.
|
||||
*/
|
||||
|
||||
async update(
|
||||
stockLocationId: string,
|
||||
updateData: UpdateStockLocationInput
|
||||
): Promise<StockLocation> {
|
||||
const defaultManager = this.getManager()
|
||||
return await defaultManager.transaction(async (manager) => {
|
||||
const locationRepo = manager.getRepository(StockLocation)
|
||||
|
||||
const item = await this.retrieve(stockLocationId)
|
||||
|
||||
const { address, metadata, ...data } = updateData
|
||||
|
||||
if (address) {
|
||||
if (item.address_id) {
|
||||
await this.updateAddress(item.address_id, address, { manager })
|
||||
} else {
|
||||
const locAddressRepo = manager.getRepository(StockLocationAddress)
|
||||
const locAddress = locAddressRepo.create(address)
|
||||
const addressResult = await locAddressRepo.save(locAddress)
|
||||
data.address_id = addressResult.id
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata) {
|
||||
item.metadata = setMetadata(item, metadata)
|
||||
}
|
||||
|
||||
const toSave = locationRepo.merge(item, data)
|
||||
await locationRepo.save(toSave)
|
||||
|
||||
await this.eventBusService_.emit(StockLocationService.Events.UPDATED, {
|
||||
id: stockLocationId,
|
||||
})
|
||||
|
||||
return item
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an address for a stock location.
|
||||
* @param {string} addressId - The ID of the address to update.
|
||||
* @param {StockLocationAddressInput} address - The update data for the address.
|
||||
* @param {Object} context - Context for the update.
|
||||
* @param {EntityManager} context.manager - The entity manager to use for the update.
|
||||
* @returns {Promise<StockLocationAddress>} - The updated stock location address.
|
||||
*/
|
||||
|
||||
protected async updateAddress(
|
||||
addressId: string,
|
||||
address: StockLocationAddressInput,
|
||||
context: { manager?: EntityManager } = {}
|
||||
): Promise<StockLocationAddress> {
|
||||
const manager = context.manager || this.getManager()
|
||||
const locationAddressRepo = manager.getRepository(StockLocationAddress)
|
||||
|
||||
const existingAddress = await locationAddressRepo.findOne(addressId)
|
||||
if (!existingAddress) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`StockLocation address with id ${addressId} was not found`
|
||||
)
|
||||
}
|
||||
|
||||
const toSave = locationAddressRepo.merge(existingAddress, address)
|
||||
|
||||
const { metadata } = address
|
||||
if (metadata) {
|
||||
toSave.metadata = setMetadata(toSave, metadata)
|
||||
}
|
||||
|
||||
return await locationAddressRepo.save(toSave)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a stock location.
|
||||
* @param {string} id - The ID of the stock location to delete.
|
||||
* @returns {Promise<void>} - An empty promise.
|
||||
*/
|
||||
async delete(id: string): Promise<void> {
|
||||
const manager = this.getManager()
|
||||
const locationRepo = manager.getRepository(StockLocation)
|
||||
|
||||
await locationRepo.softRemove({ id })
|
||||
|
||||
await this.eventBusService_.emit(StockLocationService.Events.DELETED, {
|
||||
id,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es5",
|
||||
"es6",
|
||||
"es2019"
|
||||
],
|
||||
"target": "es5",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
+113
-83
@@ -3,111 +3,141 @@
|
||||
const fs = require("fs")
|
||||
const OAS = require("oas-normalize")
|
||||
const swaggerInline = require("swagger-inline")
|
||||
const { exec } = require("child_process");
|
||||
const { exec } = require("child_process")
|
||||
|
||||
const isDryRun = process.argv.indexOf('--dry-run') !== -1;
|
||||
const isDryRun = process.argv.indexOf("--dry-run") !== -1
|
||||
|
||||
// Storefront API
|
||||
swaggerInline(
|
||||
["./packages/medusa/src/models", "./packages/medusa/src/api/middlewares" , "./packages/medusa/src/api/routes/store"],
|
||||
[
|
||||
"./packages/medusa/src/models",
|
||||
"./packages/medusa/src/types",
|
||||
"./packages/medusa/src/api/middlewares",
|
||||
"./packages/medusa/src/api/routes/store",
|
||||
],
|
||||
{
|
||||
base: "./docs/api/store-spec3-base.yaml",
|
||||
}
|
||||
).then((gen) => {
|
||||
const oas = new OAS(gen)
|
||||
oas
|
||||
.validate(true)
|
||||
.then(() => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/store-spec3.json", gen)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in store")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in store")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
});
|
||||
)
|
||||
.then((gen) => {
|
||||
const oas = new OAS(gen)
|
||||
oas
|
||||
.validate(true)
|
||||
.then(() => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/store-spec3.json", gen)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in store")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in store")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
swaggerInline(
|
||||
["./packages/medusa/src/models", "./packages/medusa/src/api/middlewares" , "./packages/medusa/src/api/routes/store"],
|
||||
[
|
||||
"./packages/medusa/src/models",
|
||||
"./packages/medusa/src/types",
|
||||
"./packages/medusa/src/api/middlewares",
|
||||
"./packages/medusa/src/api/routes/store",
|
||||
],
|
||||
{
|
||||
base: "./docs/api/store-spec3-base.yaml",
|
||||
format: "yaml",
|
||||
}
|
||||
).then((gen) => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/store-spec3.yaml", gen)
|
||||
exec("rm -rf docs/api/store/ && yarn run -- redocly split docs/api/store-spec3.yaml --outDir=docs/api/store/", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
throw new Error(`error: ${error.message}`)
|
||||
}
|
||||
console.log(`${stderr || stdout}`);
|
||||
});
|
||||
} else {
|
||||
console.log('No errors occurred while generating Store API Reference');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in store")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
)
|
||||
.then((gen) => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/store-spec3.yaml", gen)
|
||||
exec(
|
||||
"rm -rf docs/api/store/ && yarn run -- redocly split docs/api/store-spec3.yaml --outDir=docs/api/store/",
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
throw new Error(`error: ${error.message}`)
|
||||
}
|
||||
console.log(`${stderr || stdout}`)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
console.log("No errors occurred while generating Store API Reference")
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in store")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
// Admin API
|
||||
swaggerInline(
|
||||
["./packages/medusa/src/models", "./packages/medusa/src/api/middlewares" , "./packages/medusa/src/api/routes/admin"],
|
||||
[
|
||||
"./packages/medusa/src/models",
|
||||
"./packages/medusa/src/types",
|
||||
"./packages/medusa/src/api/middlewares",
|
||||
"./packages/medusa/src/api/routes/admin",
|
||||
],
|
||||
{
|
||||
base: "./docs/api/admin-spec3-base.yaml",
|
||||
}
|
||||
).then((gen) => {
|
||||
const oas = new OAS(gen)
|
||||
oas
|
||||
.validate(true)
|
||||
.then(() => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/admin-spec3.json", gen)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in admin")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in admin")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
)
|
||||
.then((gen) => {
|
||||
const oas = new OAS(gen)
|
||||
oas
|
||||
.validate(true)
|
||||
.then(() => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/admin-spec3.json", gen)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in admin")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in admin")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
swaggerInline(
|
||||
["./packages/medusa/src/models", "./packages/medusa/src/api/middlewares" , "./packages/medusa/src/api/routes/admin"],
|
||||
[
|
||||
"./packages/medusa/src/models",
|
||||
"./packages/medusa/src/types",
|
||||
"./packages/medusa/src/api/middlewares",
|
||||
"./packages/medusa/src/api/routes/admin",
|
||||
],
|
||||
{
|
||||
base: "./docs/api/admin-spec3-base.yaml",
|
||||
format: "yaml",
|
||||
}
|
||||
).then((gen) => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/admin-spec3.yaml", gen)
|
||||
exec("rm -rf docs/api/admin/ && yarn run -- redocly split docs/api/admin-spec3.yaml --outDir=docs/api/admin/", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
throw new Error(`error: ${error.message}`)
|
||||
}
|
||||
console.log(`${stderr || stdout}`);
|
||||
return;
|
||||
});
|
||||
} else {
|
||||
console.log('No errors occurred while generating Admin API Reference');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in admin")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
)
|
||||
.then((gen) => {
|
||||
if (!isDryRun) {
|
||||
fs.writeFileSync("./docs/api/admin-spec3.yaml", gen)
|
||||
exec(
|
||||
"rm -rf docs/api/admin/ && yarn run -- redocly split docs/api/admin-spec3.yaml --outDir=docs/api/admin/",
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
throw new Error(`error: ${error.message}`)
|
||||
}
|
||||
console.log(`${stderr || stdout}`)
|
||||
return
|
||||
}
|
||||
)
|
||||
} else {
|
||||
console.log("No errors occurred while generating Admin API Reference")
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Error in admin")
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
@@ -4466,6 +4466,22 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@medusajs/stock-location@workspace:packages/stock-location":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@medusajs/stock-location@workspace:packages/stock-location"
|
||||
dependencies:
|
||||
"@medusajs/medusa": ^1.7.1
|
||||
cross-env: ^5.2.1
|
||||
jest: ^25.5.2
|
||||
ts-jest: ^25.5.1
|
||||
typescript: ^4.4.4
|
||||
peerDependencies:
|
||||
"@medusajs/medusa": ^1.7.1
|
||||
medusa-interfaces: 1.3.3
|
||||
typeorm: ^0.2.31
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@microsoft/fetch-event-source@npm:2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "@microsoft/fetch-event-source@npm:2.0.1"
|
||||
|
||||
Reference in New Issue
Block a user