feat: implement order fulfillment api v1.0.0 delivery endpoints and webhook compatibility

This commit is contained in:
MOHAN 2026-03-29 18:23:34 +05:30
parent d4042fb656
commit 53e5bd970c
10 changed files with 1034 additions and 3 deletions

View File

@ -0,0 +1,46 @@
# 06 Order API 1.0.0 Audit
Source checked: "Order Fulfillment API (1.0.0)" shared by you.
## Implemented Now (Dedicated Wrapper Namespace)
- Get Order Details:
- `GET /api/v1/uber/delivery-order/orders/{orderId}`
- upstream: `/v1/delivery/order/{order_id}`
- List Orders Details:
- `GET /api/v1/uber/delivery-order/stores/{storeId}/orders`
- upstream: `/v1/delivery/store/{store_id}/orders`
- Accept Order:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/accept`
- Deny Order:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/deny`
- Cancel Order:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/cancel`
- Mark Order Ready:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/ready`
- Adjust Order Price:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/adjust-price`
- Update Order Ready Time:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/update-ready-time`
- Resolve Fulfillment Issues:
- `POST /api/v1/uber/delivery-order/orders/{orderId}/resolve-fulfillment-issues`
- Get Replacement Recommendations:
- `POST /api/v1/uber/delivery-order/replacement-recommendations`
## Validation Added
- adjust-price reasons enum and `custom_reason` required when reason is `OTHER`
- update-ready-time requires `ready_for_pickup_time`
- deny/cancel reason object shape validation
- list orders page size max enforced (`<= 50`)
## Existing Before
- Legacy order routes under `/api/v1/uber/orders...`
- Retail fulfillment helpers and related webhooks
## Pending
- Response normalization nuances for `204 No Content` cancel semantics if required by consuming clients
- Deeper typed schemas for webhook metadata and fulfillment issue object variants

View File

@ -26,3 +26,16 @@ Retail fulfillment guidance:
- Read customer preference (`REPLACE_FOR_ME`, `SUBSTITUTE_ME`, `REMOVE_ITEM`) from order details. - Read customer preference (`REPLACE_FOR_ME`, `SUBSTITUTE_ME`, `REMOVE_ITEM`) from order details.
- Update issue states via fulfillment endpoint (`FOUND_ITEM`, `PARTIAL_AVAILABILITY`, `OUT_OF_ITEM`). - Update issue states via fulfillment endpoint (`FOUND_ITEM`, `PARTIAL_AVAILABILITY`, `OUT_OF_ITEM`).
- On `orders.fulfillment_issues.resolved` webhook, fetch latest order and continue resolution. - On `orders.fulfillment_issues.resolved` webhook, fetch latest order and continue resolution.
Order API 1.0.0 coverage (delivery namespace):
- `GET /api/v1/uber/delivery-order/orders/{orderId}`
- `GET /api/v1/uber/delivery-order/stores/{storeId}/orders`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/accept`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/deny`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/cancel`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/ready`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/adjust-price`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/update-ready-time`
- `POST /api/v1/uber/delivery-order/orders/{orderId}/resolve-fulfillment-issues`
- `POST /api/v1/uber/delivery-order/replacement-recommendations`

View File

@ -22,6 +22,7 @@ Common event types handled:
- `orders.release` - `orders.release`
- `orders.scheduled.notification` - `orders.scheduled.notification`
- `orders.cancel` - `orders.cancel`
- `delivery.state_changed`
- `store.provisioned` - `store.provisioned`
- `store.deprovisioned` - `store.deprovisioned`
- `store.status.changed` - `store.status.changed`

View File

@ -840,6 +840,156 @@
} }
} }
}, },
"/api/v1/uber/delivery-order/orders/{orderId}": {
"get": {
"summary": "Order API 1.0.0 - Get order details",
"tags": [
"Uber Delivery Order v1"
],
"parameters": [
{
"in": "path",
"name": "orderId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Order details retrieved"
}
}
}
},
"/api/v1/uber/delivery-order/stores/{storeId}/orders": {
"get": {
"summary": "Order API 1.0.0 - List store orders with details",
"tags": [
"Uber Delivery Order v1"
],
"parameters": [
{
"in": "path",
"name": "storeId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Orders listed"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/accept": {
"post": {
"summary": "Order API 1.0.0 - Accept order",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Order accepted"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/deny": {
"post": {
"summary": "Order API 1.0.0 - Deny order",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Order denied"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/cancel": {
"post": {
"summary": "Order API 1.0.0 - Cancel order",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Order canceled"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/ready": {
"post": {
"summary": "Order API 1.0.0 - Mark order ready",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Order ready"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/adjust-price": {
"post": {
"summary": "Order API 1.0.0 - Adjust order price",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Order price adjusted"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/update-ready-time": {
"post": {
"summary": "Order API 1.0.0 - Update order ready time",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Order ready time updated"
}
}
}
},
"/api/v1/uber/delivery-order/orders/{orderId}/resolve-fulfillment-issues": {
"post": {
"summary": "Order API 1.0.0 - Resolve fulfillment issues",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Fulfillment issue resolution submitted"
}
}
}
},
"/api/v1/uber/delivery-order/replacement-recommendations": {
"post": {
"summary": "Order API 1.0.0 - Get replacement recommendations",
"tags": [
"Uber Delivery Order v1"
],
"responses": {
"200": {
"description": "Replacement recommendations returned"
}
}
}
},
"/api/v1/uber/reporting/fetch": { "/api/v1/uber/reporting/fetch": {
"post": { "post": {
"summary": "Fetch Uber reporting CSV with retries and header-based parsing", "summary": "Fetch Uber reporting CSV with retries and header-based parsing",

View File

@ -516,6 +516,349 @@
} }
} }
}, },
{
"name": "Delivery Order API - Get Order Details",
"request": {
"method": "GET",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}?expand=carts,deliveries,payment",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}"
],
"query": [
{
"key": "expand",
"value": "carts,deliveries,payment"
}
]
}
}
},
{
"name": "Delivery Order API - List Store Orders",
"request": {
"method": "GET",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/stores/{{storeId}}/orders?page_size=50",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"stores",
"{{storeId}}",
"orders"
],
"query": [
{
"key": "page_size",
"value": "50"
}
]
}
}
},
{
"name": "Delivery Order API - Accept",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ready_for_pickup_time\": \"2026-04-01T18:50:05.000Z\",\n \"accepted_by\": \"John Smith\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/accept",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"accept"
]
}
}
},
{
"name": "Delivery Order API - Deny",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"deny_reason\": {\n \"type\": \"ITEM_ISSUE\",\n \"info\": \"Item is not available\"\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/deny",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"deny"
]
}
}
},
{
"name": "Delivery Order API - Cancel",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"cancellation_reason\": {\n \"type\": \"ITEM_ISSUE\",\n \"info\": \"Item sold out\"\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/cancel",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"cancel"
]
}
}
},
{
"name": "Delivery Order API - Ready",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/ready",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"ready"
]
}
}
},
{
"name": "Delivery Order API - Adjust Price",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"amount_e5\": -500000,\n \"reason\": \"ITEM_SOLD_OUT\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/adjust-price",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"adjust-price"
]
}
}
},
{
"name": "Delivery Order API - Update Ready Time",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ready_for_pickup_time\": \"2026-04-01T18:50:05.000Z\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/update-ready-time",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"update-ready-time"
]
}
}
},
{
"name": "Delivery Order API - Resolve Fulfillment Issues",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"fulfillment_issues\": [\n {}\n ]\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/orders/{{orderId}}/resolve-fulfillment-issues",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"orders",
"{{orderId}}",
"resolve-fulfillment-issues"
]
}
}
},
{
"name": "Delivery Order API - Replacement Recommendations",
"request": {
"method": "POST",
"header": [
{
"key": "x-api-key",
"value": "{{apiKey}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"id\": \"3679399\",\n \"order_id\": \"{{orderId}}\",\n \"store_id\": \"{{storeId}}\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/uber/delivery-order/replacement-recommendations",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"uber",
"delivery-order",
"replacement-recommendations"
]
}
}
},
{ {
"name": "Get Store By ID", "name": "Get Store By ID",
"request": { "request": {

View File

@ -31,6 +31,18 @@ module.exports = {
updatePrepTime: "/v1/delivery/store/{storeId}/update-store-prep-time", updatePrepTime: "/v1/delivery/store/{storeId}/update-store-prep-time",
updateFulfillmentConfig: "/v1/delivery/store/{storeId}/update-fulfillment-configuration" updateFulfillmentConfig: "/v1/delivery/store/{storeId}/update-fulfillment-configuration"
}, },
deliveryOrder: {
getById: "/v1/delivery/order/{orderId}",
listByStore: "/v1/delivery/store/{storeId}/orders",
accept: "/v1/delivery/order/{orderId}/accept",
deny: "/v1/delivery/order/{orderId}/deny",
cancel: "/v1/delivery/order/{orderId}/cancel",
ready: "/v1/delivery/order/{orderId}/ready",
adjustPrice: "/v1/delivery/order/{orderId}/adjust-price",
updateReadyTime: "/v1/delivery/order/{orderId}/update-ready-time",
resolveFulfillmentIssues: "/v1/delivery/order/{orderId}/resolve-fulfillment-issues",
replacementRecommendations: "/v1/delivery/get-replacement-recommendations"
},
webhooks: { webhooks: {
events: "/v1/eats/stores/{storeId}/event_feed" events: "/v1/eats/stores/{storeId}/event_feed"
} }

View File

@ -444,6 +444,159 @@ async function deliveryUpdateFulfillmentConfig(req, res) {
return res.json({ success: true, data }); return res.json({ success: true, data });
} }
async function deliveryGetOrderDetails(req, res) {
const schema = z.object({
expand: z.string().optional()
});
const query = schema.parse(req.query || {});
const data = await proxyService.deliveryGetOrderDetails({
orderId: req.params.orderId,
query
});
return res.json({ success: true, data });
}
async function deliveryListOrders(req, res) {
const schema = z.object({
expand: z.string().optional(),
state: z.string().optional(),
status: z.string().optional(),
start_time: z.string().optional(),
end_time: z.string().optional(),
next_page_token: z.string().optional(),
page_size: z.coerce.number().int().min(1).max(50).optional()
});
const query = schema.parse(req.query || {});
const data = await proxyService.deliveryListOrders({
storeId: req.params.storeId,
query
});
return res.json({ success: true, data });
}
async function deliveryAcceptOrder(req, res) {
const schema = z.object({
ready_for_pickup_time: z.string().optional(),
external_reference_id: z.string().optional(),
accepted_by: z.string().optional(),
order_pickup_instructions: z.string().optional()
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryAcceptOrder({
orderId: req.params.orderId,
payload
});
return res.json({ success: true, data });
}
async function deliveryDenyOrder(req, res) {
const denyReasonSchema = z.object({
info: z.string().optional(),
type: z.string().min(1),
client_error_code: z.string().optional(),
item_metadata: z.record(z.string(), z.any()).optional()
});
const schema = z.object({
deny_reason: denyReasonSchema
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryDenyOrder({
orderId: req.params.orderId,
payload
});
return res.json({ success: true, data });
}
async function deliveryCancelOrder(req, res) {
const cancelReasonSchema = z.object({
info: z.string().optional(),
type: z.string().min(1),
client_error_code: z.string().optional(),
item_metadata: z.record(z.string(), z.any()).optional()
});
const schema = z.object({
cancellation_reason: cancelReasonSchema
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryCancelOrder({
orderId: req.params.orderId,
payload
});
return res.json({ success: true, data });
}
async function deliveryMarkOrderReady(req, res) {
const data = await proxyService.deliveryMarkOrderReady({
orderId: req.params.orderId,
payload: req.body || {}
});
return res.json({ success: true, data });
}
async function deliveryAdjustOrderPrice(req, res) {
const schema = z
.object({
amount_e5: z.coerce.number(),
tax_rate: z.string().optional(),
reason: z.enum([
"REQUESTED_ADD_ONS",
"BIGGER_SIZE",
"NEW_ITEM_ADDED",
"ITEM_SOLD_OUT",
"REMOVED_ITEM",
"ADD_ON_UNAVAILABLE",
"OTHER"
]),
custom_reason: z.string().optional()
})
.refine((value) => value.reason !== "OTHER" || Boolean(value.custom_reason), {
message: "custom_reason is required when reason is OTHER"
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryAdjustOrderPrice({
orderId: req.params.orderId,
payload
});
return res.json({ success: true, data });
}
async function deliveryUpdateReadyTime(req, res) {
const schema = z.object({
ready_for_pickup_time: z.string().min(1)
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryUpdateReadyTime({
orderId: req.params.orderId,
payload
});
return res.json({ success: true, data });
}
async function deliveryResolveFulfillmentIssues(req, res) {
const schema = z.object({
fulfillment_issues: z.array(z.any()).min(1)
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryResolveFulfillmentIssues({
orderId: req.params.orderId,
payload
});
return res.json({ success: true, data });
}
async function deliveryGetReplacementRecommendations(req, res) {
const schema = z.object({
id: z.string().min(1),
order_id: z.string().min(1),
store_id: z.string().min(1)
});
const payload = schema.parse(req.body || {});
const data = await proxyService.deliveryGetReplacementRecommendations({
payload
});
return res.json({ success: true, data });
}
module.exports = { module.exports = {
genericProxy, genericProxy,
upsertMenu, upsertMenu,
@ -473,5 +626,15 @@ module.exports = {
deliveryGetStoreStatus, deliveryGetStoreStatus,
deliverySetStoreStatus, deliverySetStoreStatus,
deliveryUpdatePrepTime, deliveryUpdatePrepTime,
deliveryUpdateFulfillmentConfig deliveryUpdateFulfillmentConfig,
deliveryGetOrderDetails,
deliveryListOrders,
deliveryAcceptOrder,
deliveryDenyOrder,
deliveryCancelOrder,
deliveryMarkOrderReady,
deliveryAdjustOrderPrice,
deliveryUpdateReadyTime,
deliveryResolveFulfillmentIssues,
deliveryGetReplacementRecommendations
}; };

View File

@ -470,6 +470,125 @@ async function deliveryUpdateFulfillmentConfig({ storeId, payload }) {
}); });
} }
async function deliveryGetOrderDetails({ orderId, query }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.getById, { orderId });
return callUberApi({
method: "GET",
uberPath,
query,
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryListOrders({ storeId, query }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.listByStore, { storeId });
return callUberApi({
method: "GET",
uberPath,
query,
wrapperRoute: "/api/v1/uber/delivery-order/stores/:storeId/orders",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryAcceptOrder({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.accept, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload || {},
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/accept",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryDenyOrder({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.deny, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/deny",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryCancelOrder({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.cancel, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/cancel",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryMarkOrderReady({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.ready, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload || {},
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/ready",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryAdjustOrderPrice({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.adjustPrice, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/adjust-price",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryUpdateReadyTime({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.updateReadyTime, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/update-ready-time",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryResolveFulfillmentIssues({ orderId, payload }) {
const uberPath = interpolatePath(uberEndpoints.deliveryOrder.resolveFulfillmentIssues, { orderId });
return callUberApi({
method: "POST",
uberPath,
body: payload,
wrapperRoute: "/api/v1/uber/delivery-order/orders/:orderId/resolve-fulfillment-issues",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
async function deliveryGetReplacementRecommendations({ payload }) {
return callUberApi({
method: "POST",
uberPath: uberEndpoints.deliveryOrder.replacementRecommendations,
body: payload,
wrapperRoute: "/api/v1/uber/delivery-order/replacement-recommendations",
authMode: "app",
scopes: AUTH_SCOPES.ORDER
});
}
module.exports = { module.exports = {
genericProxy, genericProxy,
menuUpsert, menuUpsert,
@ -499,5 +618,15 @@ module.exports = {
deliveryGetStoreStatus, deliveryGetStoreStatus,
deliverySetStoreStatus, deliverySetStoreStatus,
deliveryUpdatePrepTime, deliveryUpdatePrepTime,
deliveryUpdateFulfillmentConfig deliveryUpdateFulfillmentConfig,
deliveryGetOrderDetails,
deliveryListOrders,
deliveryAcceptOrder,
deliveryDenyOrder,
deliveryCancelOrder,
deliveryMarkOrderReady,
deliveryAdjustOrderPrice,
deliveryUpdateReadyTime,
deliveryResolveFulfillmentIssues,
deliveryGetReplacementRecommendations
}; };

View File

@ -105,7 +105,12 @@ async function handleUberWebhook(req, res) {
const merchantId = req.query.merchantId || req.body?.merchant_id || null; const merchantId = req.query.merchantId || req.body?.merchant_id || null;
const eventType = req.body?.event_type || req.body?.type || "unknown"; const eventType = req.body?.event_type || req.body?.type || "unknown";
const resourceId = req.body?.resource_id || req.body?.order_id || req.body?.order?.id || null; const resourceId =
req.body?.resource_id ||
req.body?.meta?.resource_id ||
req.body?.order_id ||
req.body?.order?.id ||
null;
const resourceHref = req.body?.resource_href || null; const resourceHref = req.body?.resource_href || null;
const dedupeKey = buildDedupeKey(verification.signature, req); const dedupeKey = buildDedupeKey(verification.signature, req);

View File

@ -481,4 +481,173 @@ router.post(
asyncHandler(controller.deliveryUpdateFulfillmentConfig) asyncHandler(controller.deliveryUpdateFulfillmentConfig)
); );
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}:
* get:
* summary: Order API 1.0.0 - Get order details
* tags:
* - Uber Delivery Order v1
* parameters:
* - in: path
* name: orderId
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Order details retrieved
*/
router.get("/uber/delivery-order/orders/:orderId", asyncHandler(controller.deliveryGetOrderDetails));
/**
* @openapi
* /api/v1/uber/delivery-order/stores/{storeId}/orders:
* get:
* summary: Order API 1.0.0 - List store orders with details
* tags:
* - Uber Delivery Order v1
* parameters:
* - in: path
* name: storeId
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Orders listed
*/
router.get(
"/uber/delivery-order/stores/:storeId/orders",
asyncHandler(controller.deliveryListOrders)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/accept:
* post:
* summary: Order API 1.0.0 - Accept order
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Order accepted
*/
router.post(
"/uber/delivery-order/orders/:orderId/accept",
asyncHandler(controller.deliveryAcceptOrder)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/deny:
* post:
* summary: Order API 1.0.0 - Deny order
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Order denied
*/
router.post(
"/uber/delivery-order/orders/:orderId/deny",
asyncHandler(controller.deliveryDenyOrder)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/cancel:
* post:
* summary: Order API 1.0.0 - Cancel order
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Order canceled
*/
router.post(
"/uber/delivery-order/orders/:orderId/cancel",
asyncHandler(controller.deliveryCancelOrder)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/ready:
* post:
* summary: Order API 1.0.0 - Mark order ready
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Order ready
*/
router.post(
"/uber/delivery-order/orders/:orderId/ready",
asyncHandler(controller.deliveryMarkOrderReady)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/adjust-price:
* post:
* summary: Order API 1.0.0 - Adjust order price
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Order price adjusted
*/
router.post(
"/uber/delivery-order/orders/:orderId/adjust-price",
asyncHandler(controller.deliveryAdjustOrderPrice)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/update-ready-time:
* post:
* summary: Order API 1.0.0 - Update order ready time
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Order ready time updated
*/
router.post(
"/uber/delivery-order/orders/:orderId/update-ready-time",
asyncHandler(controller.deliveryUpdateReadyTime)
);
/**
* @openapi
* /api/v1/uber/delivery-order/orders/{orderId}/resolve-fulfillment-issues:
* post:
* summary: Order API 1.0.0 - Resolve fulfillment issues
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Fulfillment issue resolution submitted
*/
router.post(
"/uber/delivery-order/orders/:orderId/resolve-fulfillment-issues",
asyncHandler(controller.deliveryResolveFulfillmentIssues)
);
/**
* @openapi
* /api/v1/uber/delivery-order/replacement-recommendations:
* post:
* summary: Order API 1.0.0 - Get replacement recommendations
* tags:
* - Uber Delivery Order v1
* responses:
* 200:
* description: Replacement recommendations returned
*/
router.post(
"/uber/delivery-order/replacement-recommendations",
asyncHandler(controller.deliveryGetReplacementRecommendations)
);
module.exports = router; module.exports = router;