feat: implement menu items update endpoint and align menu integration routes
This commit is contained in:
parent
1474781c08
commit
8fb333918c
25
docs/developer-portal/05-menu-integration-audit.md
Normal file
25
docs/developer-portal/05-menu-integration-audit.md
Normal file
@ -0,0 +1,25 @@
|
||||
# 05 Menu Integration Audit
|
||||
|
||||
Source checked: Uber Eats "Menu Integration" section shared by you.
|
||||
|
||||
## Implemented Now
|
||||
|
||||
- Retrieve menu:
|
||||
- `GET /api/v1/uber/menu`
|
||||
- Full menu upload/replace:
|
||||
- `PUT /api/v1/uber/menu/replace` (primary)
|
||||
- Individual item updates:
|
||||
- `POST /api/v1/uber/menu/items`
|
||||
- supports stock/price style item-level updates via Menu Items endpoint
|
||||
|
||||
## Existing Before
|
||||
|
||||
- Legacy menu upsert helper route (`POST /api/v1/uber/menu/upsert`)
|
||||
- Store/menu module structure and app-token auth for menu calls
|
||||
|
||||
## Pending
|
||||
|
||||
- Strict typed schemas for full menu payload entities (item, modifier group, category, menu)
|
||||
- Validation rules for image metadata limits and alcoholic item classifications
|
||||
- Dedicated mapper helpers for `core_price` and `bundled_items` enrichment
|
||||
|
||||
@ -4,9 +4,18 @@ Menu sync between POS and Uber Eats:
|
||||
|
||||
- Full menu replacement via PUT
|
||||
- Fetch menu from Uber
|
||||
- Item-level updates (out-of-stock/price updates)
|
||||
- Item and modifier mapping strategy
|
||||
- Validation and publish error handling
|
||||
|
||||
Current wrapper route for full replacement:
|
||||
|
||||
- `PUT /api/v1/uber/menu/replace`
|
||||
|
||||
Item update route:
|
||||
|
||||
- `POST /api/v1/uber/menu/items`
|
||||
|
||||
Best-practice note:
|
||||
|
||||
- Use API-managed menus only for integrated stores (avoid manual Menu Maker edits to prevent drift).
|
||||
|
||||
@ -230,7 +230,7 @@
|
||||
},
|
||||
"/api/v1/uber/menu/upsert": {
|
||||
"post": {
|
||||
"summary": "Upsert store menu",
|
||||
"summary": "Legacy upsert helper for store menu",
|
||||
"tags": [
|
||||
"Uber Menu"
|
||||
],
|
||||
@ -254,6 +254,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/uber/menu/items": {
|
||||
"post": {
|
||||
"summary": "Update individual menu items (stock/price updates)",
|
||||
"tags": [
|
||||
"Uber Menu"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Menu items updated"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/uber/menu": {
|
||||
"get": {
|
||||
"summary": "Fetch store menu",
|
||||
|
||||
@ -199,6 +199,39 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update Menu Items",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "x-api-key",
|
||||
"value": "{{apiKey}}"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"storeId\": \"{{storeId}}\",\n \"items\": [\n {\n \"id\": \"item_1\",\n \"price_info\": {\n \"price\": 799\n },\n \"suspension_info\": {\n \"suspend_until\": null\n }\n }\n ]\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/v1/uber/menu/items",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"v1",
|
||||
"uber",
|
||||
"menu",
|
||||
"items"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List Provisionable Stores",
|
||||
"request": {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
module.exports = {
|
||||
menu: {
|
||||
upsert: "/v1/eats/stores/{storeId}/menus",
|
||||
get: "/v1/eats/stores/{storeId}/menus"
|
||||
get: "/v1/eats/stores/{storeId}/menus",
|
||||
itemsUpdate: "/v1/eats/stores/{storeId}/menus/items"
|
||||
},
|
||||
orders: {
|
||||
list: "/v1/eats/stores/{storeId}/orders",
|
||||
|
||||
@ -57,6 +57,21 @@ async function replaceMenu(req, res) {
|
||||
return res.json({ success: true, data });
|
||||
}
|
||||
|
||||
async function updateMenuItems(req, res) {
|
||||
const schema = z.object({
|
||||
merchantId: z.string().min(1),
|
||||
storeId: z.string().min(1),
|
||||
items: z.array(z.any()).min(1)
|
||||
});
|
||||
const payload = schema.parse(req.body);
|
||||
const data = await proxyService.updateMenuItems({
|
||||
merchantId: payload.merchantId,
|
||||
storeId: payload.storeId,
|
||||
payload: { items: payload.items }
|
||||
});
|
||||
return res.json({ success: true, data });
|
||||
}
|
||||
|
||||
async function listOrders(req, res) {
|
||||
const schema = z.object({
|
||||
merchantId: z.string().min(1),
|
||||
@ -208,6 +223,7 @@ module.exports = {
|
||||
genericProxy,
|
||||
upsertMenu,
|
||||
replaceMenu,
|
||||
updateMenuItems,
|
||||
getMenu,
|
||||
listOrders,
|
||||
orderAction,
|
||||
|
||||
@ -151,6 +151,19 @@ async function menuGet({ merchantId, storeId }) {
|
||||
});
|
||||
}
|
||||
|
||||
async function updateMenuItems({ merchantId, storeId, payload }) {
|
||||
const uberPath = interpolatePath(uberEndpoints.menu.itemsUpdate, { storeId });
|
||||
return callUberApi({
|
||||
merchantId,
|
||||
method: "POST",
|
||||
uberPath,
|
||||
body: payload,
|
||||
wrapperRoute: "/api/v1/uber/menu/items",
|
||||
authMode: "app",
|
||||
scopes: AUTH_SCOPES.STORE
|
||||
});
|
||||
}
|
||||
|
||||
async function ordersList({ merchantId, storeId, query }) {
|
||||
const uberPath = interpolatePath(uberEndpoints.orders.list, { storeId });
|
||||
return callUberApi({
|
||||
@ -326,6 +339,7 @@ module.exports = {
|
||||
menuUpsert,
|
||||
menuReplace,
|
||||
menuGet,
|
||||
updateMenuItems,
|
||||
ordersList,
|
||||
orderAction,
|
||||
updateStoreHours,
|
||||
|
||||
@ -21,7 +21,7 @@ router.post("/uber/request", asyncHandler(controller.genericProxy));
|
||||
* @openapi
|
||||
* /api/v1/uber/menu/upsert:
|
||||
* post:
|
||||
* summary: Upsert store menu
|
||||
* summary: Legacy upsert helper for store menu
|
||||
* tags:
|
||||
* - Uber Menu
|
||||
* responses:
|
||||
@ -43,6 +43,19 @@ router.post("/uber/menu/upsert", asyncHandler(controller.upsertMenu));
|
||||
*/
|
||||
router.put("/uber/menu/replace", asyncHandler(controller.replaceMenu));
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /api/v1/uber/menu/items:
|
||||
* post:
|
||||
* summary: Update individual menu items (stock/price updates)
|
||||
* tags:
|
||||
* - Uber Menu
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Menu items updated
|
||||
*/
|
||||
router.post("/uber/menu/items", asyncHandler(controller.updateMenuItems));
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /api/v1/uber/menu:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user