Align Update Item to v2 sparse item endpoint

This commit is contained in:
MOHAN 2026-03-29 18:39:27 +05:30
parent d80f9e9baf
commit 519f2f7169
8 changed files with 46 additions and 12 deletions

View File

@ -17,7 +17,9 @@ Source checked: Uber Eats "Menu Integration" section shared by you.
- validates known menu_type enum values
- Individual item updates:
- `POST /api/v1/uber/menu/items`
- supports stock/price style item-level updates via Menu Items endpoint
- aligned to upstream `POST /v2/eats/stores/{store_id}/menus/items/{item_id}`
- request body is sparse update (only provided fields are changed)
- supports `menu_type` enum for split delivery/pickup/dine-in menus
## Existing Before

View File

@ -21,6 +21,13 @@ Current wrapper route for full replacement:
Item update route:
- `POST /api/v1/uber/menu/items`
- upstream mapped to `POST /v2/eats/stores/{store_id}/menus/items/{item_id}`
- sparse update only (only provided fields are changed)
- wrapper payload shape:
- `merchantId`
- `storeId`
- `itemId`
- `update` object with fields such as `price_info`, `suspension_info`, `menu_type`, `product_info`, `classifications`, `beverage_info`, `physical_properties_info`, `medication_info`, `nutritional_info`, `selling_info`
Menu fetch route:

View File

@ -318,13 +318,13 @@
},
"/api/v1/uber/menu/items": {
"post": {
"summary": "Update individual menu items (stock/price updates)",
"summary": "Update single menu item (POST /v2/eats/stores/{store_id}/menus/items/{item_id})",
"tags": [
"Uber Menu"
],
"responses": {
"200": {
"description": "Menu items updated"
"description": "Menu item sparsely updated (Uber returns 204 No Content)"
}
}
}

View File

@ -200,7 +200,7 @@
}
},
{
"name": "Update Menu Items",
"name": "Update Item (v2 Sparse)",
"request": {
"method": "POST",
"header": [
@ -215,7 +215,7 @@
],
"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}"
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"storeId\": \"{{storeId}}\",\n \"itemId\": \"item_1\",\n \"update\": {\n \"menu_type\": \"MENU_TYPE_FULFILLMENT_DELIVERY\",\n \"price_info\": {\n \"price\": 799\n },\n \"suspension_info\": {\n \"suspension\": null\n }\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/menu/items",

View File

@ -3,7 +3,7 @@ module.exports = {
upsert: "/v1/eats/stores/{storeId}/menus",
upload: "/v2/eats/stores/{storeId}/menus",
get: "/v2/eats/stores/{storeId}/menus",
itemsUpdate: "/v1/eats/stores/{storeId}/menus/items"
itemUpdate: "/v2/eats/stores/{storeId}/menus/items/{itemId}"
},
orders: {
list: "/v1/eats/stores/{storeId}/orders",

View File

@ -90,16 +90,41 @@ async function replaceMenu(req, res) {
}
async function updateMenuItems(req, res) {
const menuTypeEnum = z.enum([
"MENU_TYPE_FULFILLMENT_DELIVERY",
"MENU_TYPE_FULFILLMENT_PICK_UP",
"MENU_TYPE_FULFILLMENT_DINE_IN"
]);
const updateSchema = z
.object({
price_info: z.any().optional(),
suspension_info: z.any().optional(),
menu_type: menuTypeEnum.optional(),
product_info: z.any().optional(),
classifications: z.any().optional(),
beverage_info: z.any().optional(),
physical_properties_info: z.any().optional(),
medication_info: z.any().optional(),
nutritional_info: z.any().optional(),
selling_info: z.any().optional()
})
.refine((value) => Object.keys(value).length > 0, {
message: "update must include at least one sparse-update field"
});
const schema = z.object({
merchantId: z.string().min(1),
storeId: z.string().min(1),
items: z.array(z.any()).min(1)
itemId: z.string().min(1),
update: updateSchema
});
const payload = schema.parse(req.body);
const data = await proxyService.updateMenuItems({
merchantId: payload.merchantId,
storeId: payload.storeId,
payload: { items: payload.items }
itemId: payload.itemId,
payload: payload.update
});
return res.json({ success: true, data });
}

View File

@ -188,8 +188,8 @@ async function menuGet({ merchantId, storeId, menuType }) {
});
}
async function updateMenuItems({ merchantId, storeId, payload }) {
const uberPath = interpolatePath(uberEndpoints.menu.itemsUpdate, { storeId });
async function updateMenuItems({ merchantId, storeId, itemId, payload }) {
const uberPath = interpolatePath(uberEndpoints.menu.itemUpdate, { storeId, itemId });
return callUberApi({
merchantId,
method: "POST",

View File

@ -47,12 +47,12 @@ router.put("/uber/menu/replace", asyncHandler(controller.replaceMenu));
* @openapi
* /api/v1/uber/menu/items:
* post:
* summary: Update individual menu items (stock/price updates)
* summary: Update single menu item (POST /v2/eats/stores/{store_id}/menus/items/{item_id})
* tags:
* - Uber Menu
* responses:
* 200:
* description: Menu items updated
* description: Menu item sparsely updated (Uber returns 204 No Content)
*/
router.post("/uber/menu/items", asyncHandler(controller.updateMenuItems));