Payments
This commit is contained in:
@@ -22,7 +22,6 @@ Todas as chamadas devem usar autenticação híbrida.
|
||||
**GET** `/api/store/:storeId/info` - Retorna a configuração completa da loja, incluindo dados bancários, horários e flags de pagamento.
|
||||
|
||||
**Resposta Exemplo:**
|
||||
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
@@ -73,7 +72,6 @@ Todas as chamadas devem usar autenticação híbrida.
|
||||
**GET** `/api/store/:storeId/dashboard`
|
||||
|
||||
**Resposta Detalhada (100% Parity):**
|
||||
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
@@ -104,9 +102,84 @@ Todas as chamadas devem usar autenticação híbrida.
|
||||
|
||||
## 🍴 Catálogo e Menu (Complex Payloads)
|
||||
|
||||
### 4. Categorias de Pizza
|
||||
**POST** `/api/store/:storeId/catalog/categories`
|
||||
### 3.1 Catálogo Consolidado (App)
|
||||
**GET** `/api/store/:storeId/catalog`
|
||||
|
||||
**Resposta:**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"code": "STORE_CATALOG_RETRIEVED",
|
||||
"result": [
|
||||
{
|
||||
"id": "cat_lanches",
|
||||
"name": "Lanches",
|
||||
"isPizzaCategory": false,
|
||||
"products": [
|
||||
{
|
||||
"id": "prod_xburger",
|
||||
"type": "prepared",
|
||||
"name": "X-Burger",
|
||||
"description": "Pão, carne e queijo",
|
||||
"image": "/uploads/products/xburger.jpg",
|
||||
"price": "25.00",
|
||||
"addons": "yes",
|
||||
"addonGroups": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cat_pizzas",
|
||||
"name": "Pizzas",
|
||||
"isPizzaCategory": true,
|
||||
"pizzaConfig": {
|
||||
"sizes": [{ "id": "broto", "name": "Broto", "slices": 4, "maxFlavors": 1 }],
|
||||
"doughs": [{ "id": "tradicional", "name": "Tradicional", "active": true }],
|
||||
"crusts": [{ "id": "catupiry", "name": "Catupiry", "active": true, "priceModifier": "10.00" }]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"id": "prod_pizza_calabresa",
|
||||
"type": "pizza",
|
||||
"name": "Pizza Calabresa",
|
||||
"description": "Molho, mussarela e calabresa",
|
||||
"image": "/uploads/products/pizza-calabresa.jpg",
|
||||
"price": "0.00",
|
||||
"pizzaPrices": {
|
||||
"broto": "35.00",
|
||||
"grande": "55.00"
|
||||
},
|
||||
"addons": "yes",
|
||||
"addonGroups": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Regra de identificação de pizza:**
|
||||
- Item pizza: `products[].type === "pizza"`.
|
||||
- Configuração de montagem vem em `category.pizzaConfig`.
|
||||
- Preço por tamanho vem em `product.pizzaPrices`.
|
||||
|
||||
### 4. Listar Categorias do Catálogo
|
||||
**GET** `/api/store/:storeId/catalog/categories`
|
||||
|
||||
**Resposta:**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"code": "CATEGORIES_RETRIEVED",
|
||||
"result": [
|
||||
{ "id": "cat_1", "name": "Pizzas", "isActive": true }
|
||||
],
|
||||
"message": "Categorias recuperadas com sucesso"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Criar Categoria (Ex.: Pizza)
|
||||
**POST** `/api/store/:storeId/catalog/categories`
|
||||
```json
|
||||
{
|
||||
"name": "Pizzas Salgadas",
|
||||
@@ -122,9 +195,14 @@ Todas as chamadas devem usar autenticação híbrida.
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Produtos Tipo Combo ou Pizza
|
||||
**POST** `/api/store/:storeId/catalog/products`
|
||||
### 6. Atualizar Categoria
|
||||
**PUT** `/api/store/:storeId/catalog/categories/:id`
|
||||
|
||||
### 7. Excluir Categoria
|
||||
**DELETE** `/api/store/:storeId/catalog/categories/:id`
|
||||
|
||||
### 8. Produtos Tipo Combo ou Pizza
|
||||
**POST** `/api/store/:storeId/catalog/products`
|
||||
```json
|
||||
{
|
||||
"type": "pizza",
|
||||
@@ -148,11 +226,10 @@ Todas as chamadas devem usar autenticação híbrida.
|
||||
|
||||
## 📦 Histórico e Detalhes do Pedido
|
||||
|
||||
### 6. Histórico com Filtros
|
||||
### 9. Histórico com Filtros
|
||||
**GET** `/api/store/:storeId/orders/history?start=2024-01-01&end=2024-01-31&q=Ana`
|
||||
|
||||
**Objeto de Pedido Completo (result.list[0]):**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "order_guid",
|
||||
@@ -181,7 +258,7 @@ Todas as chamadas devem usar autenticação híbrida.
|
||||
> O campo `confirmOtp` (8 dígitos) é o código que o motoboy deve utilizar para iniciar a confirmação. O `customerOtp` (4 dígitos do cliente) **NÃO** é retornado via API por questões de segurança.
|
||||
```
|
||||
|
||||
### 7. Detalhes de um Pedido Individual
|
||||
### 10. Detalhes de um Pedido Individual
|
||||
**GET** `/api/store/:storeId/orders/:orderId`
|
||||
|
||||
Retorna o objeto completo do pedido (parity 100% com o painel).
|
||||
@@ -190,7 +267,7 @@ Retorna o objeto completo do pedido (parity 100% com o painel).
|
||||
|
||||
## 💰 Financeiro Detalhado
|
||||
|
||||
### 7. Resumo de Performance e Gateway
|
||||
### 11. Resumo de Performance e Gateway
|
||||
**GET** `/api/store/:storeId/financial/summary`
|
||||
|
||||
**Resposta:**
|
||||
@@ -216,7 +293,7 @@ Retorna o objeto completo do pedido (parity 100% com o painel).
|
||||
|
||||
## ⭐ Reviews e Avaliações
|
||||
|
||||
### 8. Métricas e Respostas
|
||||
### 12. Métricas e Respostas
|
||||
**GET** `/api/store/:storeId/reviews`
|
||||
|
||||
**Resposta:**
|
||||
@@ -330,13 +407,58 @@ Endpoints utilizados pela página pública (CORS habilitado para domínios parce
|
||||
---
|
||||
|
||||
## 🛒 Checkout e Criação de Pedido
|
||||
### 10.0 Validar Endereço de Entrega (Checkout)
|
||||
**POST** `/api/store/:storeId/delivery/validate-address`
|
||||
|
||||
Endpoint para validar cobertura de entrega no checkout, quando o cliente troca o endereço antes do pagamento.
|
||||
|
||||
**Payload:**
|
||||
```json
|
||||
{
|
||||
"address": {
|
||||
"street": "Avenida das Andorinhas",
|
||||
"number": "477",
|
||||
"neighborhood": "Jardim Andorinhas",
|
||||
"city": "Campinas",
|
||||
"state": "SP",
|
||||
"zip": "13101-400",
|
||||
"lat": -22.918,
|
||||
"lng": -47.01813
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Resposta Exemplo:**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"code": "DELIVERY_ADDRESS_VALIDATED",
|
||||
"result": {
|
||||
"deliveryAllowed": true,
|
||||
"reasonCode": "DELIVERY_ALLOWED",
|
||||
"reasonMessage": "Endereço válido para entrega",
|
||||
"deliveryMode": "KM",
|
||||
"distance": 1.3,
|
||||
"deliveryFee": 8,
|
||||
"deliveryTime": "35 min",
|
||||
"sameCity": false,
|
||||
"matchedKmRange": { "from": 1, "to": 2, "price": 8, "time": 35 },
|
||||
"matchedNeighborhood": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Regras:**
|
||||
- `KM`: aprova somente até o limite da última faixa + `0.5 km` de tolerância.
|
||||
- `NEIGHBORHOOD`: reprova se a cidade do endereço for diferente da cidade da loja.
|
||||
- `NEIGHBORHOOD`: aprova com bairro configurado ou com fallback de mesma cidade.
|
||||
|
||||
### 10. Criar Novo Pedido (Public)
|
||||
**POST** `/api/public/orders`
|
||||
|
||||
Este endpoint é utilizado pelo front-end de checkout (Pedi Foods) para criar o pedido no sistema da loja.
|
||||
|
||||
**Payload:**
|
||||
|
||||
```json
|
||||
{
|
||||
"storeId": "store_123456",
|
||||
@@ -367,23 +489,152 @@ Este endpoint é utilizado pelo front-end de checkout (Pedi Foods) para criar o
|
||||
"name": "Pizza",
|
||||
"price": 50.00,
|
||||
"qty": 1,
|
||||
"image": "..."
|
||||
"image": "...",
|
||||
"addons": [
|
||||
{
|
||||
"addonId": "addon_bacon",
|
||||
"name": "Bacon",
|
||||
"price": 4.00,
|
||||
"qty": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Resposta Sucesso:**
|
||||
**Regras para `items[].addons`:**
|
||||
- `qty` do adicional é suportado (ex.: 2x bacon/ovo).
|
||||
- Se `qty` não for enviado ou vier inválido, a API assume `1`.
|
||||
- `qty` mínimo efetivo é `1`.
|
||||
|
||||
**Resposta Sucesso:**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"result": {
|
||||
"id": "order_guid",
|
||||
"shortId": "1234",
|
||||
"status": "PENDING",
|
||||
"status": "PAYMENT_PENDING",
|
||||
"paymentStatus": "PENDING",
|
||||
"paymentPayload": "..." // Se PIX (Big String Base64 ou Copia e Cola)
|
||||
"paymentMethod": "PIX",
|
||||
"paymentPayload": {
|
||||
"copyPaste": "000201010212...",
|
||||
"qrCodeImage": "iVBORw0KGgoAAAANSUhEUgAA...",
|
||||
"expirationDate": "2026-02-14T22:30:00.000Z"
|
||||
},
|
||||
"payment": {
|
||||
"method": "PIX",
|
||||
"status": "PENDING",
|
||||
"pix": {
|
||||
"copyPaste": "000201010212...",
|
||||
"qrCodeImage": "iVBORw0KGgoAAAANSUhEUgAA...",
|
||||
"expirationDate": "2026-02-14T22:30:00.000Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Observação de segurança:** o Atomenta não retorna links de checkout/fatura do Asaas no response de criação de pedido.
|
||||
|
||||
### 10.1 Realtime de Status de Pedido (Socket.IO)
|
||||
Para atualização em tempo real do checkout/app (sem depender de push), usar Socket.IO.
|
||||
|
||||
**Socket endpoint:**
|
||||
- `ws://<host>:<port>/socket.io/` (usar `wss://` em produção com TLS)
|
||||
|
||||
**Auth no handshake:**
|
||||
- Enviar JWT no campo `auth.token`.
|
||||
- Exemplo: `Bearer <JWT_TOKEN>`.
|
||||
|
||||
**Evento para o cliente:**
|
||||
- `order_update`
|
||||
|
||||
**Payload típico do evento:**
|
||||
```json
|
||||
{
|
||||
"id": "order_guid",
|
||||
"shortId": "1234",
|
||||
"storeId": "store_123456",
|
||||
"userId": "user_guid",
|
||||
"status": "CONFIRMED",
|
||||
"paymentStatus": "CONFIRMED",
|
||||
"updatedAt": "2026-02-15T20:10:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 Fallback de Status (Polling)
|
||||
Caso não haja conexão socket, consultar status por HTTP até estado final.
|
||||
|
||||
**Endpoint:**
|
||||
- `GET /api/public/orders/:orderId`
|
||||
|
||||
**Recomendação de intervalo:**
|
||||
- 0-60s: `3s`
|
||||
- 60-180s: `5s`
|
||||
- acima de 180s: `10s`
|
||||
- parar em status final (`COMPLETED`, `CANCELED`, `REFUNDED`).
|
||||
|
||||
### 11. Listar Lojas (Public App)
|
||||
**GET** `/api/public/stores`
|
||||
|
||||
Endpoint utilizado pelo aplicativo Pedi Foods para listar todas as lojas disponíveis para o cliente.
|
||||
|
||||
**Resposta Sucesso:**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"result": [
|
||||
{
|
||||
"id": "company_guid",
|
||||
"storeId": "store_123456",
|
||||
"name": "Pizzaria do Arantes",
|
||||
"logo": "https://...",
|
||||
"cover": "https://...",
|
||||
"category": "Restaurante",
|
||||
"isOpen": true,
|
||||
"statusLabel": "Aberto Agora",
|
||||
"rating": 4.8,
|
||||
"deliveryTime": "30-45 min",
|
||||
"deliveryFee": 5.00
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Gestão de Contratos (Store)
|
||||
|
||||
### 12. Verificar Status do Contrato
|
||||
**GET** `/api/store/:storeId/contract/status`
|
||||
Retorna o ID e o status do contrato mais recente da loja.
|
||||
|
||||
**Resposta Exemplo:**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"result": {
|
||||
"id": "contract_guid",
|
||||
"status": "draft" // ou "signed"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 13. Assinar Contrato
|
||||
**POST** `/api/store/:storeId/contract/sign`
|
||||
Assina o contrato draft atual da loja.
|
||||
|
||||
**Payload:**
|
||||
```json
|
||||
{
|
||||
"method": "typed",
|
||||
"typedName": "João Silva", // Obrigatório se method === "typed"
|
||||
"signatureDataUrl": "data:image/png;base64,..." // Obrigatório se method === "draw"
|
||||
}
|
||||
```
|
||||
|
||||
### 14. Visualizar PDF do Contrato
|
||||
**GET** `/api/store/contract/:contractId/pdf`
|
||||
Retorna o stream do arquivo PDF do contrato (draft ou assinado).
|
||||
|
||||
Reference in New Issue
Block a user