feat: implement integration configuration provisioning flows and pos_data endpoints
This commit is contained in:
parent
490d2e77b7
commit
8f58a64bc8
@ -0,0 +1,31 @@
|
|||||||
|
# 03 Integration Configuration Flows Audit
|
||||||
|
|
||||||
|
Source checked: Uber Eats "Integration Configuration Flows" section shared by you.
|
||||||
|
|
||||||
|
## Implemented Now
|
||||||
|
|
||||||
|
- Merchant OAuth based store retrieval:
|
||||||
|
- `GET /api/v1/uber/stores/provisionable`
|
||||||
|
- Uses merchant token (`authorization_code` / `eats.pos_provisioning`)
|
||||||
|
- Store activation via POS data:
|
||||||
|
- `POST /api/v1/uber/stores/{storeId}/pos-data`
|
||||||
|
- Store integration update/deactivation:
|
||||||
|
- `PATCH /api/v1/uber/stores/{storeId}/pos-data`
|
||||||
|
- Store de-provision:
|
||||||
|
- `DELETE /api/v1/uber/stores/{storeId}/pos-data`
|
||||||
|
- Webhook provisioning-state reaction:
|
||||||
|
- `store.provisioned` marks mapped connection active
|
||||||
|
- `store.deprovisioned` marks mapped connection deprovisioned
|
||||||
|
|
||||||
|
## Existing From Earlier
|
||||||
|
|
||||||
|
- OAuth authorization URL + callback
|
||||||
|
- Merchant connection persistence
|
||||||
|
- Webhook ingestion and persistence
|
||||||
|
|
||||||
|
## Pending
|
||||||
|
|
||||||
|
- Strong store mapping workflow (location-data assisted matching UI flow)
|
||||||
|
- Typed POS data schema once exact request fields are finalized from endpoint reference
|
||||||
|
- Automated post-provisioning follow-up actions (e.g., mandatory menu upload jobs)
|
||||||
|
|
||||||
@ -29,15 +29,21 @@ Wrapper stores merchant token.
|
|||||||
|
|
||||||
`POST /api/v1/uber/menu/upsert`
|
`POST /api/v1/uber/menu/upsert`
|
||||||
|
|
||||||
## 5. Pull Orders
|
## 5. Provision Store Integration (OAuth user token flow)
|
||||||
|
|
||||||
|
`GET /api/v1/uber/stores/provisionable?merchantId=...`
|
||||||
|
|
||||||
|
`POST /api/v1/uber/stores/{storeId}/pos-data`
|
||||||
|
|
||||||
|
## 6. Pull Orders
|
||||||
|
|
||||||
`GET /api/v1/uber/orders?merchantId=...&storeId=...`
|
`GET /api/v1/uber/orders?merchantId=...&storeId=...`
|
||||||
|
|
||||||
## 6. Receive Webhooks
|
## 7. Receive Webhooks
|
||||||
|
|
||||||
`POST /api/v1/webhooks/uber`
|
`POST /api/v1/webhooks/uber`
|
||||||
|
|
||||||
## 7. Use Generic API for Any Missing Endpoint
|
## 8. Use Generic API for Any Missing Endpoint
|
||||||
|
|
||||||
`POST /api/v1/uber/request`
|
`POST /api/v1/uber/request`
|
||||||
|
|
||||||
@ -49,4 +55,3 @@ Wrapper stores merchant token.
|
|||||||
"body": {}
|
"body": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,8 @@ Flow:
|
|||||||
1. Create merchant in wrapper
|
1. Create merchant in wrapper
|
||||||
2. Generate Uber OAuth URL
|
2. Generate Uber OAuth URL
|
||||||
3. Merchant authorizes Uber account
|
3. Merchant authorizes Uber account
|
||||||
4. Callback stores tokens + store identifiers
|
4. Callback stores tokens + merchant OAuth access
|
||||||
|
5. Retrieve merchant stores (`GET /api/v1/uber/stores/provisionable`)
|
||||||
|
6. Activate selected store (`POST /api/v1/uber/stores/{storeId}/pos-data`)
|
||||||
|
|
||||||
Multi-client principle: each merchant has isolated credentials and mappings.
|
Multi-client principle: each merchant has isolated credentials and mappings.
|
||||||
|
|
||||||
|
|||||||
@ -14,3 +14,14 @@ Acknowledgement behavior:
|
|||||||
|
|
||||||
- Valid webhook events are acknowledged with `200` and empty body
|
- Valid webhook events are acknowledged with `200` and empty body
|
||||||
- Duplicate retries are de-duplicated and still acknowledged with `200`
|
- Duplicate retries are de-duplicated and still acknowledged with `200`
|
||||||
|
|
||||||
|
Common event types handled:
|
||||||
|
|
||||||
|
- `orders.notification`
|
||||||
|
- `orders.failure`
|
||||||
|
- `orders.release`
|
||||||
|
- `orders.scheduled.notification`
|
||||||
|
- `orders.cancel`
|
||||||
|
- `store.provisioned`
|
||||||
|
- `store.deprovisioned`
|
||||||
|
- `store.status.changed`
|
||||||
|
|||||||
@ -280,6 +280,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/uber/stores/provisionable": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Retrieve stores associated with merchant OAuth token",
|
||||||
|
"tags": [
|
||||||
|
"Uber Provisioning"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "merchantId",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Stores retrieved"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/uber/orders/{orderId}/action": {
|
"/api/v1/uber/orders/{orderId}/action": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "Trigger order action (accept, deny, ready, cancel)",
|
"summary": "Trigger order action (accept, deny, ready, cancel)",
|
||||||
@ -316,6 +339,71 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/uber/stores/{storeId}/pos-data": {
|
||||||
|
"post": {
|
||||||
|
"summary": "Activate integration for selected store (POST /pos_data)",
|
||||||
|
"tags": [
|
||||||
|
"Uber Provisioning"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "storeId",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Store provisioned"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"summary": "Update integration settings for selected store (PATCH /pos_data)",
|
||||||
|
"tags": [
|
||||||
|
"Uber Provisioning"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "storeId",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Store integration updated"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "De-provision integration for selected store (DELETE /pos_data)",
|
||||||
|
"tags": [
|
||||||
|
"Uber Provisioning"
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "storeId",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Store integration removed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/webhooks/uber": {
|
"/api/v1/webhooks/uber": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "Ingest Uber webhook events",
|
"summary": "Ingest Uber webhook events",
|
||||||
|
|||||||
@ -199,6 +199,139 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "List Provisionable Stores",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "x-api-key",
|
||||||
|
"value": "{{apiKey}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/v1/uber/stores/provisionable?merchantId={{merchantId}}",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"v1",
|
||||||
|
"uber",
|
||||||
|
"stores",
|
||||||
|
"provisionable"
|
||||||
|
],
|
||||||
|
"query": [
|
||||||
|
{
|
||||||
|
"key": "merchantId",
|
||||||
|
"value": "{{merchantId}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Create POS Data (Provision)",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "x-api-key",
|
||||||
|
"value": "{{apiKey}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"posData\": {\n \"partner_store_id\": \"POS_STORE_001\",\n \"integration_enabled\": true,\n \"store_configuration_data\": {}\n }\n}"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"v1",
|
||||||
|
"uber",
|
||||||
|
"stores",
|
||||||
|
"{{storeId}}",
|
||||||
|
"pos-data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Patch POS Data (Enable/Disable)",
|
||||||
|
"request": {
|
||||||
|
"method": "PATCH",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "x-api-key",
|
||||||
|
"value": "{{apiKey}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"posData\": {\n \"integration_enabled\": false\n }\n}"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"v1",
|
||||||
|
"uber",
|
||||||
|
"stores",
|
||||||
|
"{{storeId}}",
|
||||||
|
"pos-data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Delete POS Data (Deprovision)",
|
||||||
|
"request": {
|
||||||
|
"method": "DELETE",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "x-api-key",
|
||||||
|
"value": "{{apiKey}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"merchantId\": \"{{merchantId}}\"\n}"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/v1/uber/stores/{{storeId}}/pos-data",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"v1",
|
||||||
|
"uber",
|
||||||
|
"stores",
|
||||||
|
"{{storeId}}",
|
||||||
|
"pos-data"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Webhook Ingest (Simulation)",
|
"name": "Webhook Ingest (Simulation)",
|
||||||
"request": {
|
"request": {
|
||||||
|
|||||||
@ -12,12 +12,13 @@ module.exports = {
|
|||||||
cancel: "/v1/eats/orders/{orderId}/cancel"
|
cancel: "/v1/eats/orders/{orderId}/cancel"
|
||||||
},
|
},
|
||||||
stores: {
|
stores: {
|
||||||
|
list: "/v1/eats/stores",
|
||||||
getById: "/v1/eats/stores/{storeId}",
|
getById: "/v1/eats/stores/{storeId}",
|
||||||
updateHours: "/v1/eats/stores/{storeId}/hours",
|
updateHours: "/v1/eats/stores/{storeId}/hours",
|
||||||
inventory: "/v1/eats/stores/{storeId}/inventory"
|
inventory: "/v1/eats/stores/{storeId}/inventory",
|
||||||
|
posData: "/v1/eats/stores/{storeId}/pos_data"
|
||||||
},
|
},
|
||||||
webhooks: {
|
webhooks: {
|
||||||
events: "/v1/eats/stores/{storeId}/event_feed"
|
events: "/v1/eats/stores/{storeId}/event_feed"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -83,6 +83,22 @@ const uberConnectionRepository = {
|
|||||||
return db.prepare("SELECT * FROM uber_connections WHERE merchant_id = ?").get(merchantId);
|
return db.prepare("SELECT * FROM uber_connections WHERE merchant_id = ?").get(merchantId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
findByUberStoreId(uberStoreId) {
|
||||||
|
return db.prepare("SELECT * FROM uber_connections WHERE uber_store_id = ? LIMIT 1").get(uberStoreId);
|
||||||
|
},
|
||||||
|
|
||||||
|
setStatusByMerchantId(merchantId, status) {
|
||||||
|
const timestamp = nowIso();
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
UPDATE uber_connections
|
||||||
|
SET status = ?, updated_at = ?
|
||||||
|
WHERE merchant_id = ?
|
||||||
|
`
|
||||||
|
).run(status, timestamp, merchantId);
|
||||||
|
return this.findByMerchantId(merchantId);
|
||||||
|
},
|
||||||
|
|
||||||
list() {
|
list() {
|
||||||
return db
|
return db
|
||||||
.prepare(`
|
.prepare(`
|
||||||
|
|||||||
@ -103,6 +103,58 @@ async function updateHours(req, res) {
|
|||||||
return res.json({ success: true, data });
|
return res.json({ success: true, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function listProvisionableStores(req, res) {
|
||||||
|
const schema = z.object({
|
||||||
|
merchantId: z.string().min(1)
|
||||||
|
});
|
||||||
|
const payload = schema.parse(req.query);
|
||||||
|
const data = await proxyService.listProvisionableStores({
|
||||||
|
merchantId: payload.merchantId,
|
||||||
|
query: req.query
|
||||||
|
});
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createPosData(req, res) {
|
||||||
|
const schema = z.object({
|
||||||
|
merchantId: z.string().min(1),
|
||||||
|
posData: z.any()
|
||||||
|
});
|
||||||
|
const payload = schema.parse(req.body);
|
||||||
|
const data = await proxyService.createPosData({
|
||||||
|
merchantId: payload.merchantId,
|
||||||
|
storeId: req.params.storeId,
|
||||||
|
payload: payload.posData
|
||||||
|
});
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function patchPosData(req, res) {
|
||||||
|
const schema = z.object({
|
||||||
|
merchantId: z.string().min(1),
|
||||||
|
posData: z.any()
|
||||||
|
});
|
||||||
|
const payload = schema.parse(req.body);
|
||||||
|
const data = await proxyService.patchPosData({
|
||||||
|
merchantId: payload.merchantId,
|
||||||
|
storeId: req.params.storeId,
|
||||||
|
payload: payload.posData
|
||||||
|
});
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deletePosData(req, res) {
|
||||||
|
const schema = z.object({
|
||||||
|
merchantId: z.string().min(1)
|
||||||
|
});
|
||||||
|
const payload = schema.parse(req.body);
|
||||||
|
const data = await proxyService.deletePosData({
|
||||||
|
merchantId: payload.merchantId,
|
||||||
|
storeId: req.params.storeId
|
||||||
|
});
|
||||||
|
return res.json({ success: true, data });
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
genericProxy,
|
genericProxy,
|
||||||
upsertMenu,
|
upsertMenu,
|
||||||
@ -110,5 +162,9 @@ module.exports = {
|
|||||||
getMenu,
|
getMenu,
|
||||||
listOrders,
|
listOrders,
|
||||||
orderAction,
|
orderAction,
|
||||||
updateHours
|
updateHours,
|
||||||
|
listProvisionableStores,
|
||||||
|
createPosData,
|
||||||
|
patchPosData,
|
||||||
|
deletePosData
|
||||||
};
|
};
|
||||||
|
|||||||
@ -203,6 +203,56 @@ async function updateStoreHours({ merchantId, storeId, payload }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function listProvisionableStores({ merchantId, query }) {
|
||||||
|
return callUberApi({
|
||||||
|
merchantId,
|
||||||
|
method: "GET",
|
||||||
|
uberPath: uberEndpoints.stores.list,
|
||||||
|
query,
|
||||||
|
wrapperRoute: "/api/v1/uber/stores/provisionable",
|
||||||
|
authMode: "merchant",
|
||||||
|
scopes: AUTH_SCOPES.POS_PROVISIONING
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createPosData({ merchantId, storeId, payload }) {
|
||||||
|
const uberPath = interpolatePath(uberEndpoints.stores.posData, { storeId });
|
||||||
|
return callUberApi({
|
||||||
|
merchantId,
|
||||||
|
method: "POST",
|
||||||
|
uberPath,
|
||||||
|
body: payload,
|
||||||
|
wrapperRoute: "/api/v1/uber/stores/:storeId/pos-data",
|
||||||
|
authMode: "merchant",
|
||||||
|
scopes: AUTH_SCOPES.POS_PROVISIONING
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function patchPosData({ merchantId, storeId, payload }) {
|
||||||
|
const uberPath = interpolatePath(uberEndpoints.stores.posData, { storeId });
|
||||||
|
return callUberApi({
|
||||||
|
merchantId,
|
||||||
|
method: "PATCH",
|
||||||
|
uberPath,
|
||||||
|
body: payload,
|
||||||
|
wrapperRoute: "/api/v1/uber/stores/:storeId/pos-data",
|
||||||
|
authMode: "merchant",
|
||||||
|
scopes: AUTH_SCOPES.POS_PROVISIONING
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deletePosData({ merchantId, storeId }) {
|
||||||
|
const uberPath = interpolatePath(uberEndpoints.stores.posData, { storeId });
|
||||||
|
return callUberApi({
|
||||||
|
merchantId,
|
||||||
|
method: "DELETE",
|
||||||
|
uberPath,
|
||||||
|
wrapperRoute: "/api/v1/uber/stores/:storeId/pos-data",
|
||||||
|
authMode: "merchant",
|
||||||
|
scopes: AUTH_SCOPES.POS_PROVISIONING
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
genericProxy,
|
genericProxy,
|
||||||
menuUpsert,
|
menuUpsert,
|
||||||
@ -210,5 +260,9 @@ module.exports = {
|
|||||||
menuGet,
|
menuGet,
|
||||||
ordersList,
|
ordersList,
|
||||||
orderAction,
|
orderAction,
|
||||||
updateStoreHours
|
updateStoreHours,
|
||||||
|
listProvisionableStores,
|
||||||
|
createPosData,
|
||||||
|
patchPosData,
|
||||||
|
deletePosData
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const env = require("../../config/env");
|
const env = require("../../config/env");
|
||||||
const { webhookRepository } = require("../../db/adapter");
|
const { webhookRepository, uberConnectionRepository } = require("../../db/adapter");
|
||||||
|
|
||||||
function getSignatureFromHeaders(headers) {
|
function getSignatureFromHeaders(headers) {
|
||||||
const signature = headers["x-uber-signature"];
|
const signature = headers["x-uber-signature"];
|
||||||
@ -65,6 +65,28 @@ function buildDedupeKey(signature, req) {
|
|||||||
return crypto.createHash("sha256").update(basis).digest("hex");
|
return crypto.createHash("sha256").update(basis).digest("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractStoreId(payload) {
|
||||||
|
return payload?.user_id || payload?.store_id || payload?.resource_id || payload?.store?.id || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyProvisioningStateFromWebhook(eventType, payload) {
|
||||||
|
if (eventType !== "store.provisioned" && eventType !== "store.deprovisioned") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const storeId = extractStoreId(payload);
|
||||||
|
if (!storeId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = uberConnectionRepository.findByUberStoreId(String(storeId));
|
||||||
|
if (!connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextStatus = eventType === "store.provisioned" ? "active" : "deprovisioned";
|
||||||
|
uberConnectionRepository.setStatusByMerchantId(connection.merchant_id, nextStatus);
|
||||||
|
}
|
||||||
|
|
||||||
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({
|
||||||
@ -104,6 +126,8 @@ async function handleUberWebhook(req, res) {
|
|||||||
headersJson: req.headers
|
headersJson: req.headers
|
||||||
});
|
});
|
||||||
|
|
||||||
|
applyProvisioningStateFromWebhook(eventType, req.body || {});
|
||||||
|
|
||||||
return res.status(200).end();
|
return res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -69,6 +69,25 @@ router.get("/uber/menu", asyncHandler(controller.getMenu));
|
|||||||
*/
|
*/
|
||||||
router.get("/uber/orders", asyncHandler(controller.listOrders));
|
router.get("/uber/orders", asyncHandler(controller.listOrders));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /api/v1/uber/stores/provisionable:
|
||||||
|
* get:
|
||||||
|
* summary: Retrieve stores associated with merchant OAuth token
|
||||||
|
* tags:
|
||||||
|
* - Uber Provisioning
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: merchantId
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Stores retrieved
|
||||||
|
*/
|
||||||
|
router.get("/uber/stores/provisionable", asyncHandler(controller.listProvisionableStores));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
* /api/v1/uber/orders/{orderId}/action:
|
* /api/v1/uber/orders/{orderId}/action:
|
||||||
@ -101,4 +120,51 @@ router.post("/uber/orders/:orderId/action", asyncHandler(controller.orderAction)
|
|||||||
*/
|
*/
|
||||||
router.put("/uber/stores/hours", asyncHandler(controller.updateHours));
|
router.put("/uber/stores/hours", asyncHandler(controller.updateHours));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /api/v1/uber/stores/{storeId}/pos-data:
|
||||||
|
* post:
|
||||||
|
* summary: Activate integration for selected store (POST /pos_data)
|
||||||
|
* tags:
|
||||||
|
* - Uber Provisioning
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: storeId
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Store provisioned
|
||||||
|
* patch:
|
||||||
|
* summary: Update integration settings for selected store (PATCH /pos_data)
|
||||||
|
* tags:
|
||||||
|
* - Uber Provisioning
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: storeId
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Store integration updated
|
||||||
|
* delete:
|
||||||
|
* summary: De-provision integration for selected store (DELETE /pos_data)
|
||||||
|
* tags:
|
||||||
|
* - Uber Provisioning
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: storeId
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Store integration removed
|
||||||
|
*/
|
||||||
|
router.post("/uber/stores/:storeId/pos-data", asyncHandler(controller.createPosData));
|
||||||
|
router.patch("/uber/stores/:storeId/pos-data", asyncHandler(controller.patchPosData));
|
||||||
|
router.delete("/uber/stores/:storeId/pos-data", asyncHandler(controller.deletePosData));
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user