Handle store.menu_refresh_request webhook with store metadata tracking
This commit is contained in:
parent
64f214f3ae
commit
bc3d4e6641
@ -16,6 +16,10 @@ Source checked: Uber Eats "Webhook" section shared by you.
|
|||||||
- `resource_id`
|
- `resource_id`
|
||||||
- `resource_href`
|
- `resource_href`
|
||||||
- signature and dedupe key
|
- signature and dedupe key
|
||||||
|
- Added explicit event handling for `store.menu_refresh_request`:
|
||||||
|
- mapped via `store_id`
|
||||||
|
- records latest menu refresh request metadata on `uber_connections`
|
||||||
|
- stores webhook UUID and `X-Environment` marker
|
||||||
|
|
||||||
## Existing Before
|
## Existing Before
|
||||||
|
|
||||||
@ -27,4 +31,3 @@ Source checked: Uber Eats "Webhook" section shared by you.
|
|||||||
- Per-event downstream job workers (accept/deny SLA orchestration).
|
- Per-event downstream job workers (accept/deny SLA orchestration).
|
||||||
- Alerting if order accept/deny not sent before timeout window.
|
- Alerting if order accept/deny not sent before timeout window.
|
||||||
- Full typed schema validation per webhook `event_type`.
|
- Full typed schema validation per webhook `event_type`.
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,17 @@ Common event types handled:
|
|||||||
- `delivery.state_changed`
|
- `delivery.state_changed`
|
||||||
- `store.provisioned`
|
- `store.provisioned`
|
||||||
- `store.deprovisioned`
|
- `store.deprovisioned`
|
||||||
|
- `store.menu_refresh_request`
|
||||||
- `store.status.changed`
|
- `store.status.changed`
|
||||||
|
|
||||||
|
Menu refresh handling:
|
||||||
|
|
||||||
|
- On `store.menu_refresh_request`, wrapper records the request on the mapped Uber store connection.
|
||||||
|
- Persisted fields include:
|
||||||
|
- `last_menu_refresh_requested_at`
|
||||||
|
- `last_menu_refresh_webhook_uuid`
|
||||||
|
- `last_webhook_environment` (from `X-Environment`)
|
||||||
|
|
||||||
Retail fulfillment follow-up:
|
Retail fulfillment follow-up:
|
||||||
|
|
||||||
- On `orders.fulfillment_issues.resolved`, fetch updated order details and inspect customer acknowledgment before next action.
|
- On `orders.fulfillment_issues.resolved`, fetch updated order details and inspect customer acknowledgment before next action.
|
||||||
|
|||||||
@ -1659,6 +1659,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Webhook Ingest - Menu Refresh (Simulation)",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "X-Uber-Signature",
|
||||||
|
"value": "replace-with-valid-hmac"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "X-Environment",
|
||||||
|
"value": "production"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"event_type\": \"store.menu_refresh_request\",\n \"partner_store_id\": \"123456\",\n \"resource_href\": \"https://api.uber.com/v1/eats/stores/{{storeId}}\",\n \"store_id\": \"{{storeId}}\",\n \"webhook_meta\": {\n \"client_id\": \"app_client_id\",\n \"webhook_config_id\": \"merchant-integration.menu-refresh-request\",\n \"webhook_msg_timestamp\": 1622813397,\n \"webhook_msg_uuid\": \"b2340f4c-6dd7-4d65-a9bc-016631a2a13a\"\n }\n}"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/v1/webhooks/uber",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"v1",
|
||||||
|
"webhooks",
|
||||||
|
"uber"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Generic Uber Request",
|
"name": "Generic Uber Request",
|
||||||
"request": {
|
"request": {
|
||||||
|
|||||||
@ -107,6 +107,31 @@ const uberConnectionRepository = {
|
|||||||
return this.findByMerchantId(merchantId);
|
return this.findByMerchantId(merchantId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
markMenuRefreshRequestedByStoreId(uberStoreId, payload) {
|
||||||
|
const existing = this.findByUberStoreId(uberStoreId);
|
||||||
|
if (!existing) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const timestamp = nowIso();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
UPDATE uber_connections
|
||||||
|
SET last_menu_refresh_requested_at = ?,
|
||||||
|
last_menu_refresh_webhook_uuid = ?,
|
||||||
|
last_webhook_environment = ?,
|
||||||
|
updated_at = ?
|
||||||
|
WHERE uber_store_id = ?
|
||||||
|
`
|
||||||
|
).run(
|
||||||
|
payload?.requestedAt || timestamp,
|
||||||
|
payload?.webhookMsgUuid || null,
|
||||||
|
payload?.environment || null,
|
||||||
|
timestamp,
|
||||||
|
uberStoreId
|
||||||
|
);
|
||||||
|
return this.findByUberStoreId(uberStoreId);
|
||||||
|
},
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
return db
|
return db
|
||||||
.prepare(`
|
.prepare(`
|
||||||
|
|||||||
@ -120,6 +120,16 @@ function initSchema() {
|
|||||||
if (!tableHasColumn("api_logs", "order_id")) {
|
if (!tableHasColumn("api_logs", "order_id")) {
|
||||||
db.exec("ALTER TABLE api_logs ADD COLUMN order_id TEXT");
|
db.exec("ALTER TABLE api_logs ADD COLUMN order_id TEXT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tableHasColumn("uber_connections", "last_menu_refresh_requested_at")) {
|
||||||
|
db.exec("ALTER TABLE uber_connections ADD COLUMN last_menu_refresh_requested_at TEXT");
|
||||||
|
}
|
||||||
|
if (!tableHasColumn("uber_connections", "last_menu_refresh_webhook_uuid")) {
|
||||||
|
db.exec("ALTER TABLE uber_connections ADD COLUMN last_menu_refresh_webhook_uuid TEXT");
|
||||||
|
}
|
||||||
|
if (!tableHasColumn("uber_connections", "last_webhook_environment")) {
|
||||||
|
db.exec("ALTER TABLE uber_connections ADD COLUMN last_webhook_environment TEXT");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@ -87,6 +87,23 @@ function applyProvisioningStateFromWebhook(eventType, payload) {
|
|||||||
uberConnectionRepository.setStatusByMerchantId(connection.merchant_id, nextStatus);
|
uberConnectionRepository.setStatusByMerchantId(connection.merchant_id, nextStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyMenuRefreshRequestFromWebhook(eventType, payload, headers) {
|
||||||
|
if (eventType !== "store.menu_refresh_request") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeId = extractStoreId(payload);
|
||||||
|
if (!storeId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uberConnectionRepository.markMenuRefreshRequestedByStoreId(String(storeId), {
|
||||||
|
requestedAt: new Date().toISOString(),
|
||||||
|
webhookMsgUuid: payload?.webhook_meta?.webhook_msg_uuid || null,
|
||||||
|
environment: headers?.["x-environment"] || null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function handleUberWebhook(req, res) {
|
async function handleUberWebhook(req, res) {
|
||||||
if (!verifyBasicAuthIfConfigured(req)) {
|
if (!verifyBasicAuthIfConfigured(req)) {
|
||||||
return res.status(401).json({
|
return res.status(401).json({
|
||||||
@ -133,6 +150,7 @@ async function handleUberWebhook(req, res) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
applyProvisioningStateFromWebhook(eventType, req.body || {});
|
applyProvisioningStateFromWebhook(eventType, req.body || {});
|
||||||
|
applyMenuRefreshRequestFromWebhook(eventType, req.body || {}, req.headers || {});
|
||||||
|
|
||||||
return res.status(200).end();
|
return res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user