{
  "openapi": "3.0.3",
  "info": {
    "title": "Smart Pay API",
    "version": "6.0.0",
    "description": "API multi-tenant SaaS para restaurante/pizzaria com delivery, mesas, adicionais e comissões.\n\n## Autenticação\nUse `Bearer {token}` no header `Authorization`.\n\n## Perfis de acesso\n| Role | Acesso |\n|---|---|\n| `admin` | Total |\n| `partner` | Tenant + descendants |\n| `sub_partner` | Subárvore do partner |\n| `operator` | Apenas sua system_unit |",
    "contact": { "name": "SmartPay", "email": "dev@smartpay.com" }
  },
  "servers": [
    { "url": "http://localhost:8000/api", "description": "Local" }
  ],
  "tags": [
    { "name": "Auth", "description": "Autenticação admin/partner" },
    { "name": "Operators Auth", "description": "Autenticação de operadores" },
    { "name": "Partners", "description": "Hierarquia multi-tenant de parceiros" },
    { "name": "Beneficiaries", "description": "Beneficiários (PF/PJ)" },
    { "name": "System Units", "description": "Unidades físicas" },
    { "name": "Machines", "description": "Terminais e dispositivos físicos" },
    { "name": "Operators", "description": "Gestão de operadores" },
    { "name": "Tables", "description": "Controle de mesas" },
    { "name": "Products", "description": "Produtos e adicionais" },
    { "name": "Sales Orders", "description": "Pedidos (TABLE/COUNTER/DELIVERY)" },
    { "name": "Deliveries", "description": "Delivery com rastreamento" },
    { "name": "Devices", "description": "PDV/Tablet/Kiosk" },
    { "name": "Referrers", "description": "Guias turísticos com comissão" },
    { "name": "Cash Register", "description": "Caixa (operator only)" },
    { "name": "Payments", "description": "Pagamentos" },
    { "name": "Fiscal Documents", "description": "NF-e" },
    { "name": "Modules", "description": "Módulos do sistema (admin only)" },
    { "name": "Activation", "description": "Ativação de máquinas (público)" },
    { "name": "App Config", "description": "White label (público)" },
    { "name": "Webhooks", "description": "Eventos webhook internos" },
    { "name": "Tickets", "description": "Tickets gerados automaticamente após pagamento aprovado.\n\n**Fluxo Operador (9 passos):**\n1. POST /operators/login\n2. POST /cash-register/open\n3. POST /sales-orders → salva `sales_order_id`\n4. POST /sales-orders/{id}/items → adiciona itens\n5. POST /sales-orders/{id}/confirm\n6. POST /pagamentos → salva `pagamento_id` (status: pending)\n7. PUT /pagamentos/{id} → status: approved → **tickets gerados automaticamente**\n8. GET /tickets/order/{id} → lista tickets (1 por unidade de `quantidade`)\n9. POST /tickets/validate → consome ticket (uso único)\n\n**Fluxo Público (6 passos):**\n1. POST /public/orders\n2. POST /public/orders/{id}/items\n3. POST /public/orders/{id}/checkout\n4. POST /public/payment → tickets gerados na resposta\n5. GET /tickets/{codigo} → verifica ticket\n6. POST /tickets/validate → consome ticket\n\n**Status:** `PENDING` → `USED` (validate) | `CANCELED` (cancel)\n\n**QR Code:** cada ticket tem `qrcode` com URL de validação" },
    { "name": "Public Orders", "description": "Fluxo público de autoatendimento sem autenticação" },
    { "name": "Table Reservations", "description": "Agendamento de reservas de mesa com data/hora e cliente" },
    { "name": "Comandas", "description": "Comandas (abas) por cliente/grupo em uma mesa — múltiplas por mesa" },
    { "name": "Parking - Pricings", "description": "Tabelas de preço do estacionamento (HOURLY/DAILY/MONTHLY)" },
    { "name": "Parking - Monthly Customers", "description": "Mensalistas — acesso livre, valor zero" },
    { "name": "Parking - Tickets", "description": "Controle de entrada e saída de veículos" },
    { "name": "SmartRoute - Entregadores Auth", "description": "Autenticação de entregadores (SmartRoute)" },
    { "name": "SmartRoute - Entregadores", "description": "Gestão de entregadores" },
    { "name": "SmartRoute - Rotas", "description": "Rotas de entrega — criação, inicio, finalização e rastreamento" },
    { "name": "SmartRoute - Paradas", "description": "Paradas individuais de entrega executadas pelo entregador" }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" }
    },
    "schemas": {
      "Error403": {
        "type": "object",
        "properties": {
          "message": { "type": "string", "example": "Acesso não autorizado para este perfil" },
          "required_roles": { "type": "array", "items": { "type": "string" } },
          "your_role": { "type": "string" }
        }
      },
      "Error422": {
        "type": "object",
        "properties": { "message": { "type": "string" } }
      },
      "Paginated": {
        "type": "object",
        "properties": {
          "current_page": { "type": "integer" },
          "data": { "type": "array", "items": {} },
          "last_page": { "type": "integer" },
          "per_page": { "type": "integer" },
          "total": { "type": "integer" }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "role": { "type": "string", "enum": ["admin","partner","sub_partner"] },
          "partner_id": { "type": "integer", "nullable": true }
        }
      },
      "Operator": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "email": { "type": "string" },
          "role": { "type": "string", "example": "operator" },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer" },
          "commission_type": { "type": "string", "enum": ["none","percentage","fixed"] },
          "commission_value": { "type": "number" }
        }
      },
        "Partner": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "parent_id": { "type": "integer", "nullable": true },
          "level": { "type": "integer" },
          "hierarchy_path": { "type": "string" },
          "name": { "type": "string" },
          "document": { "type": "string" },
          "email": { "type": "string" },
          "primary_color": { "type": "string" },
          "active": { "type": "boolean" }
        }
      },
      "Beneficiary": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "name": { "type": "string" },
          "document": { "type": "string" },
          "type": { "type": "string", "enum": ["individual","company"] },
          "regime_tributario": { "type": "string" },
          "inscricao_estadual": { "type": "string", "nullable": true },
          "inscricao_municipal": { "type": "string", "nullable": true },
          "cep": { "type": "string" },
          "cidade": { "type": "string" },
          "estado": { "type": "string" },
          "cert_password": { "type": "string", "nullable": true, "description": "Senha do certificado digital" },
          "csc": { "type": "string", "nullable": true, "description": "CSC para NFC-e" },
          "csc_id": { "type": "string", "nullable": true, "description": "ID do CSC" },
          "fiscal_ambiente": { "type": "integer", "default": 2, "description": "1=Produção, 2=Homologação" },
          "certificado_path": { "type": "string", "nullable": true, "description": "Caminho personalizado do certificado" },
          "active": { "type": "boolean" }
        }
      },
      "RestaurantTable": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer" },
          "number": { "type": "string" },
          "name": { "type": "string", "nullable": true },
          "capacity": { "type": "integer" },
          "status": { "type": "string", "enum": ["FREE","OCCUPIED","RESERVED"] },
          "current_order_id": { "type": "integer", "nullable": true }
        }
      },
      "ProductOptionGroup": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "produto_id": { "type": "integer" },
          "name": { "type": "string" },
          "min_select": { "type": "integer" },
          "max_select": { "type": "integer" },
          "required": { "type": "boolean" },
          "options": { "type": "array", "items": { "$ref": "#/components/schemas/ProductOption" } }
        }
      },
      "ProductOption": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "price": { "type": "number" },
          "active": { "type": "boolean" }
        }
      },
      "SalesOrder": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "numero": { "type": "string" },
          "type": { "type": "string", "enum": ["TABLE","COUNTER","DELIVERY"] },
          "status": { "type": "string", "enum": ["draft","confirmed","closed","cancelled","paid"] },
          "subtotal": { "type": "number" },
          "desconto": { "type": "number" },
          "service_fee": { "type": "number" },
          "additional_fees": { "type": "number" },
          "total": { "type": "number" },
          "referrer_id": { "type": "integer", "nullable": true },
          "restaurant_table_id": { "type": "integer", "nullable": true }
        }
      },
      "Delivery": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "sales_order_id": { "type": "integer" },
          "status": { "type": "string", "enum": ["CREATED","CONFIRMED","PREPARING","READY_FOR_PICKUP","OUT_FOR_DELIVERY","DELIVERED","CANCELED"] },
          "customer_name": { "type": "string" },
          "customer_phone": { "type": "string" },
          "destination_address": { "type": "string" },
          "destination_lat": { "type": "number" },
          "destination_lng": { "type": "number" },
          "delivery_fee": { "type": "number" },
          "estimated_distance": { "type": "number" },
          "estimated_delivery_time": { "type": "integer" },
          "last_lat": { "type": "number", "nullable": true },
          "last_lng": { "type": "number", "nullable": true },
          "started_at": { "type": "string", "format": "date-time", "nullable": true },
          "delivered_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "Device": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "type": { "type": "string", "enum": ["POS","TABLET","KIOSK"] },
          "identifier": { "type": "string" },
          "status": { "type": "string", "enum": ["active","inactive","blocked"] }
        }
      },
      "Referrer": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "name": { "type": "string" },
          "commission_type": { "type": "string", "enum": ["percentage","fixed"] },
          "commission_value": { "type": "number" },
          "active": { "type": "boolean" }
        }
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "sales_order_id": { "type": "integer" },
          "sales_order_item_id": { "type": "integer" },
          "produto_id": { "type": "integer", "nullable": true },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer", "nullable": true },
          "nome_produto": { "type": "string" },
          "codigo_unico": { "type": "string", "format": "uuid" },
          "barcode": { "type": "string" },
          "qrcode": { "type": "string", "description": "URL de validação via QR Code" },
          "status": { "type": "string", "enum": ["PENDING","USED","CANCELED"] },
          "used_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "ParkingPricing": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer", "nullable": true },
          "name": { "type": "string", "example": "Padrão" },
          "type": { "type": "string", "enum": ["HOURLY", "DAILY", "MONTHLY"] },
          "price_per_hour": { "type": "number", "format": "float" },
          "price_per_minute_exceeded": { "type": "number", "format": "float" },
          "grace_period_minutes": { "type": "integer", "description": "Tolerância em minutos sem cobrança" },
          "daily_max_price": { "type": "number", "format": "float", "nullable": true },
          "monthly_price": { "type": "number", "format": "float", "nullable": true },
          "is_active": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "MonthlyCustomer": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "pricing_id": { "type": "integer" },
          "name": { "type": "string" },
          "document": { "type": "string", "nullable": true },
          "plate": { "type": "string", "example": "ABC1234" },
          "start_date": { "type": "string", "format": "date" },
          "end_date": { "type": "string", "format": "date" },
          "status": { "type": "string", "enum": ["ACTIVE", "INACTIVE"] },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "ParkingTicket": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer" },
          "operator_id": { "type": "integer", "nullable": true },
          "pricing_id": { "type": "integer" },
          "monthly_customer_id": { "type": "integer", "nullable": true },
          "sales_order_id": { "type": "integer", "nullable": true },
          "plate": { "type": "string", "example": "ABC1234" },
          "vehicle_type": { "type": "string", "example": "car" },
          "entry_time": { "type": "string", "format": "date-time" },
          "exit_time": { "type": "string", "format": "date-time", "nullable": true },
          "duration_minutes": { "type": "integer", "nullable": true },
          "status": { "type": "string", "enum": ["OPEN", "CLOSED"] },
          "is_monthly": { "type": "boolean" },
          "total_amount": { "type": "number", "format": "float" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "Entregador": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer", "nullable": true },
          "name": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "active": { "type": "boolean" },
          "last_login_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "DeliveryRoute": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "partner_id": { "type": "integer" },
          "system_unit_id": { "type": "integer", "nullable": true },
          "entregador_id": { "type": "integer" },
          "status": { "type": "string", "enum": ["criada", "em_andamento", "finalizada"] },
          "notes": { "type": "string", "nullable": true },
          "started_at": { "type": "string", "format": "date-time", "nullable": true },
          "finished_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "entregador": { "$ref": "#/components/schemas/Entregador" },
          "stops": { "type": "array", "items": { "$ref": "#/components/schemas/DeliveryStop" } }
        }
      },
      "DeliveryStop": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "delivery_route_id": { "type": "integer" },
          "sales_order_id": { "type": "integer", "nullable": true },
          "partner_id": { "type": "integer" },
          "sequence": { "type": "integer" },
          "customer_name": { "type": "string" },
          "address": { "type": "string" },
          "latitude": { "type": "number", "format": "float" },
          "longitude": { "type": "number", "format": "float" },
          "status": { "type": "string", "enum": ["pendente", "em_andamento", "entregue"] },
          "payment_type": { "type": "string", "enum": ["antecipado", "na_entrega"] },
          "payment_status": { "type": "string", "enum": ["pendente", "pago"] },
          "actual_latitude": { "type": "number", "format": "float", "nullable": true },
          "actual_longitude": { "type": "number", "format": "float", "nullable": true },
          "distance_meters": { "type": "number", "format": "float", "nullable": true, "description": "Distância em metros entre o local previsto e o local real da entrega" },
          "delivered_at": { "type": "string", "format": "date-time", "nullable": true },
          "notes": { "type": "string", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "DeliveryTracking": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "delivery_route_id": { "type": "integer" },
          "entregador_id": { "type": "integer" },
          "latitude": { "type": "number", "format": "float" },
          "longitude": { "type": "number", "format": "float" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      }
    }
  },
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/auth/token": {
      "post": {
        "tags": ["Auth"], "summary": "Login admin/partner",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email","password"], "properties": { "email": { "type": "string", "format": "email" }, "password": { "type": "string" } } } } } },
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "access_token": { "type": "string" }, "token_type": { "type": "string" }, "user": { "$ref": "#/components/schemas/User" } } } } } }, "401": { "description": "Credenciais inválidas" } }
      }
    },
    "/auth/register": {
      "post": {
        "tags": ["Auth"], "summary": "Registrar usuário",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","email","password","password_confirmation"], "properties": { "name": { "type": "string" }, "email": { "type": "string", "format": "email" }, "password": { "type": "string", "minLength": 8 }, "password_confirmation": { "type": "string" }, "role": { "type": "string", "enum": ["admin","partner","sub_partner"], "default": "partner" }, "partner_id": { "type": "integer", "nullable": true } } } } } },
        "responses": { "201": { "description": "Criado" } }
      }
    },
    "/auth/me": {
      "get": { "tags": ["Auth"], "summary": "Perfil do usuário autenticado", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } }
    },
    "/auth/logout": {
      "post": { "tags": ["Auth"], "summary": "Logout", "responses": { "200": { "description": "OK" } } }
    },
    "/auth/refresh": {
      "post": { "tags": ["Auth"], "summary": "Renovar token", "responses": { "200": { "description": "Novo token" } } }
    },
    "/operators/login": {
      "post": {
        "tags": ["Operators Auth"], "summary": "Login operador por senha",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email","password"], "properties": { "email": { "type": "string" }, "password": { "type": "string" } } } } } },
        "responses": { "200": { "description": "Token com role=operator, partner_id, system_unit_id" } }
      }
    },
    "/operators/login-pin": {
      "post": {
        "tags": ["Operators Auth"], "summary": "Login operador por PIN",
        "security": [],
        "parameters": [{ "name": "X-Activation-Key", "in": "header", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["pin"], "properties": { "pin": { "type": "string", "maxLength": 6 } } } } } },
        "responses": { "200": { "description": "OK" }, "401": { "description": "PIN inválido" } }
      }
    },
    "/operators/me": {
      "get": { "tags": ["Operators Auth"], "summary": "Perfil do operador autenticado", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Operator" } } } } } }
    },
    "/partners": {
      "get": {
        "tags": ["Partners"], "summary": "Listar parceiros (tenant-scoped)",
        "parameters": [
          { "name": "level", "in": "query", "schema": { "type": "integer" } },
          { "name": "root", "in": "query", "schema": { "type": "boolean" } },
          { "name": "parent_id", "in": "query", "schema": { "type": "integer" } },
          { "name": "all", "in": "query", "schema": { "type": "boolean" }, "description": "Sem paginação" }
        ],
        "responses": { "200": { "description": "Lista paginada de parceiros" } }
      },
      "post": {
        "tags": ["Partners"], "summary": "Criar sub-partner",
        "description": "partner_id pai vem do JWT. Admin pode informar parent_id.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","document","email"], "properties": { "name": { "type": "string" }, "document": { "type": "string" }, "email": { "type": "string" }, "parent_id": { "type": "integer", "nullable": true }, "primary_color": { "type": "string" }, "show_in_app": { "type": "boolean" } } } } } },
        "responses": { "201": { "description": "Parceiro criado" }, "403": { "description": "Sem permissão" } }
      }
    },
    "/partners/tree": {
      "get": { "tags": ["Partners"], "summary": "Árvore hierárquica (tenant-scoped)", "responses": { "200": { "description": "Árvore de parceiros" } } }
    },
    "/partners/my/tree": {
      "get": { "tags": ["Partners"], "summary": "Minha sub-árvore", "responses": { "200": { "description": "OK" } } }
    },
    "/partners/{id}": {
      "get": {
        "tags": ["Partners"], "summary": "Detalhe do parceiro",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "OK" }, "403": { "description": "Fora do tenant", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error403" } } } } }
      },
      "put": {
        "tags": ["Partners"], "summary": "Atualizar parceiro",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "primary_color": { "type": "string" }, "active": { "type": "boolean" } } } } } },
        "responses": { "200": { "description": "OK" }, "403": { "description": "Sem permissão" } }
      },
      "delete": {
        "tags": ["Partners"], "summary": "Excluir parceiro",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "OK" }, "422": { "description": "Tem sub-parceiros" } }
      }
    },
    "/partners/{id}/descendants": {
      "get": { "tags": ["Partners"], "summary": "Todos os descendentes", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/partners/{id}/ancestors": {
      "get": { "tags": ["Partners"], "summary": "Todos os ancestrais (filtrado pelo tenant)", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/partners/{id}/move": {
      "put": {
        "tags": ["Partners"], "summary": "Mover parceiro na hierarquia",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "new_parent_id": { "type": "integer", "nullable": true } } } } } },
        "responses": { "200": { "description": "OK" } }
      }
    },
    "/beneficiaries": {
      "get": { "tags": ["Beneficiaries"], "summary": "Listar (tenant-scoped)", "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Beneficiaries"], "summary": "Criar beneficiário",
        "description": "partner_id vem do JWT. Não enviar no body.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "document": { "type": "string" }, "type": { "type": "string", "enum": ["individual","company"] }, "phone": { "type": "string" }, "email": { "type": "string" } } } } } },
        "responses": { "201": { "description": "OK" } }
      }
    },
      "/beneficiaries/{id}": {
        "get": { "tags": ["Beneficiaries"], "summary": "Detalhe", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Beneficiary" } } } }, "403": { "description": "Fora do tenant" } } },
        "put": { "tags": ["Beneficiaries"], "summary": "Atualizar dados básicos ou fiscais", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "phone": { "type": "string" }, "email": { "type": "string" }, "cert_password": { "type": "string", "description": "Senha do certificado" }, "csc": { "type": "string", "description": "CSC para NFC-e" }, "csc_id": { "type": "string", "description": "ID do CSC" }, "fiscal_ambiente": { "type": "integer", "description": "1=Produção, 2=Homologação" } } } } } }, "responses": { "200": { "description": "OK" } } },
        "delete": { "tags": ["Beneficiaries"], "summary": "Excluir", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
      },
    "/system-units": {
      "get": { "tags": ["System Units"], "summary": "Listar unidades (tenant-scoped)", "responses": { "200": { "description": "OK" } } },
      "post": { "tags": ["System Units"], "summary": "Criar unidade", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "beneficiary_id": { "type": "integer", "nullable": true }, "phone": { "type": "string" }, "email": { "type": "string" } } } } } }, "responses": { "201": { "description": "OK" } } }
    },
    "/system-units/{id}/modules": {
      "get": { "tags": ["System Units"], "summary": "Módulos da unidade", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } },
      "post": { "tags": ["System Units"], "summary": "Vincular módulo", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["modulo_id"], "properties": { "modulo_id": { "type": "integer" }, "status": { "type": "integer", "enum": [1,2,3] }, "config": { "type": "object" } } } } } }, "responses": { "201": { "description": "OK" } } }
    },
    "/machines": {
      "get": { "tags": ["Machines"], "summary": "Listar máquinas (tenant-scoped)", "responses": { "200": { "description": "OK" } } },
      "post": { "tags": ["Machines"], "summary": "Criar máquina", "description": "partner_id vem do JWT.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","app_password"], "properties": { "system_unit_id": { "type": "integer" }, "name": { "type": "string" }, "serial_number": { "type": "string" }, "app_password": { "type": "string", "minLength": 4 } } } } } }, "responses": { "201": { "description": "OK" } } }
    },
    "/operators-admin": {
      "get": { "tags": ["Operators"], "summary": "Listar operadores (tenant-scoped)", "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Operators"], "summary": "Criar operador",
        "description": "partner_id vem do JWT. commission_type: none | percentage | fixed",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","email","password"], "properties": { "system_unit_id": { "type": "integer" }, "name": { "type": "string" }, "email": { "type": "string" }, "password": { "type": "string", "minLength": 6 }, "pin": { "type": "string", "minLength": 4, "maxLength": 4 }, "commission_type": { "type": "string", "enum": ["none","percentage","fixed"], "default": "none" }, "commission_value": { "type": "number", "default": 0 } } } } } },
        "responses": { "201": { "description": "OK" } }
      }
    },
    "/tables": {
      "get": {
        "tags": ["Tables"], "summary": "Listar mesas (tenant-scoped)",
        "parameters": [
          { "name": "system_unit_id", "in": "query", "schema": { "type": "integer" } },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["FREE","OCCUPIED","RESERVED"] } }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RestaurantTable" } } } } } }
      },
      "post": {
        "tags": ["Tables"], "summary": "Criar mesa",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["system_unit_id","number"], "properties": { "system_unit_id": { "type": "integer" }, "number": { "type": "string" }, "name": { "type": "string" }, "capacity": { "type": "integer", "default": 4 } } } } } },
        "responses": { "201": { "description": "Mesa criada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestaurantTable" } } } } }
      }
    },
    "/tables/{id}/open": {
      "post": {
        "tags": ["Tables"], "summary": "Abrir mesa → cria pedido TABLE",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "pessoa_id": { "type": "integer", "nullable": true } } } } } },
        "responses": { "201": { "description": "Mesa aberta com pedido draft" }, "422": { "description": "Mesa não está livre" } }
      }
    },
    "/tables/{id}/close": {
      "post": {
        "tags": ["Tables"], "summary": "Fechar mesa → fecha pedido, calcula comissões, libera mesa",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "Mesa liberada e pedido encerrado" }, "422": { "description": "Mesa não está ocupada ou sem pedido aberto" } }
      }
    },
    "/tables/{id}/reserve": {
      "post": { "tags": ["Tables"], "summary": "Reservar mesa (FREE → RESERVED)", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/tables/{id}/release": {
      "post": { "tags": ["Tables"], "summary": "Liberar reserva (RESERVED → FREE)", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/produtos/{produtoId}/option-groups": {
      "get": { "tags": ["Products"], "summary": "Listar grupos de adicionais", "parameters": [{ "name": "produtoId", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProductOptionGroup" } } } } } } },
      "post": {
        "tags": ["Products"], "summary": "Criar grupo de adicionais",
        "parameters": [{ "name": "produtoId", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "min_select": { "type": "integer", "default": 0 }, "max_select": { "type": "integer", "default": 1 }, "required": { "type": "boolean", "default": false }, "ordem": { "type": "integer" } } } } } },
        "responses": { "201": { "description": "OK" } }
      }
    },
    "/produtos/{produtoId}/option-groups/{groupId}/options": {
      "post": {
        "tags": ["Products"], "summary": "Criar opção dentro de um grupo",
        "parameters": [{ "name": "produtoId", "in": "path", "required": true, "schema": { "type": "integer" } }, { "name": "groupId", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "price": { "type": "number", "default": 0 }, "ordem": { "type": "integer" } } } } } },
        "responses": { "201": { "description": "OK" } }
      }
    },
    "/sales-orders": {
      "get": {
        "tags": ["Sales Orders"], "summary": "Listar pedidos",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["draft","confirmed","closed","cancelled","paid"] } },
          { "name": "type", "in": "query", "schema": { "type": "string", "enum": ["TABLE","COUNTER","DELIVERY"] } },
          { "name": "referrer_id", "in": "query", "schema": { "type": "integer" } }
        ],
        "responses": { "200": { "description": "OK" } }
      },
      "post": {
        "tags": ["Sales Orders"], "summary": "Criar pedido",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "type": { "type": "string", "enum": ["TABLE","COUNTER","DELIVERY"], "default": "COUNTER" }, "restaurant_table_id": { "type": "integer", "nullable": true }, "referrer_id": { "type": "integer", "nullable": true }, "service_fee": { "type": "number", "default": 0 }, "additional_fees": { "type": "number", "default": 0 }, "pessoa_id": { "type": "integer", "nullable": true } } } } } },
        "responses": { "201": { "description": "Pedido criado" } }
      }
    },
    "/sales-orders/{id}/items": {
      "post": {
        "tags": ["Sales Orders"], "summary": "Adicionar item com adicionais",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["quantidade","preco_unitario"], "properties": { "produto_id": { "type": "integer", "nullable": true }, "nome_produto": { "type": "string" }, "quantidade": { "type": "number" }, "preco_unitario": { "type": "number" }, "desconto": { "type": "number", "default": 0 }, "options": { "type": "array", "description": "Adicionais selecionados", "items": { "type": "object", "required": ["product_option_id"], "properties": { "product_option_id": { "type": "integer" } } } } } } } } },
        "responses": { "201": { "description": "Item adicionado com adicionais", "content": { "application/json": { "example": { "items": [{ "nome_produto": "Pizza", "preco_unitario": 49.90, "total": 53.40, "options": [{ "group_name": "Borda", "option_name": "Cheddar", "price": 3.50 }] }] } } } } }
      }
    },
    "/sales-orders/{id}/close": {
      "post": {
        "tags": ["Sales Orders"], "summary": "Fechar pedido — calcula totais e comissões",
        "description": "1. Recalcula subtotal, fees, total\n2. Calcula comissão do operador\n3. Calcula comissão do guia (se referrer_id)\n4. Valida delivery (se DELIVERY)\n5. Libera mesa (se TABLE)\n6. Status → closed",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "Pedido fechado com comissões calculadas" }, "422": { "description": "Pedido sem itens, ou DELIVERY sem entrega vinculada" } }
      }
    },
    "/sales-orders/{id}/confirm": {
      "post": {
        "tags": ["Sales Orders"], "summary": "Confirmar pedido",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "OK" }, "422": { "description": "Sem itens ou DELIVERY sem delivery vinculado" } }
      }
    },
    "/sales-orders/{id}/cancel": {
      "post": { "tags": ["Sales Orders"], "summary": "Cancelar pedido", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/deliveries/estimate": {
      "post": {
        "tags": ["Deliveries"], "summary": "Calcular distância e tempo estimado (público)",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["origin_lat","origin_lng","destination_lat","destination_lng"], "properties": { "origin_lat": { "type": "number" }, "origin_lng": { "type": "number" }, "destination_lat": { "type": "number" }, "destination_lng": { "type": "number" } } } } } },
        "responses": { "200": { "description": "OK", "content": { "application/json": { "example": { "estimated_distance": 2.847, "estimated_delivery_time": 16 } } } } }
      }
    },
    "/deliveries": {
      "get": { "tags": ["Deliveries"], "summary": "Listar deliveries (tenant-scoped)", "parameters": [{ "name": "status", "in": "query", "schema": { "type": "string" } }, { "name": "system_unit_id", "in": "query", "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Deliveries"], "summary": "Criar delivery para um pedido",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["sales_order_id","destination_address","customer_name"], "properties": { "sales_order_id": { "type": "integer" }, "destination_address": { "type": "string" }, "destination_reference": { "type": "string" }, "destination_lat": { "type": "number" }, "destination_lng": { "type": "number" }, "customer_name": { "type": "string" }, "customer_phone": { "type": "string" }, "delivery_fee": { "type": "number" }, "delivery_user_id": { "type": "integer", "nullable": true }, "origin_lat": { "type": "number" }, "origin_lng": { "type": "number" }, "origin_address": { "type": "string" } } } } } },
        "responses": { "201": { "description": "Delivery criado com estimativas automáticas" } }
      }
    },
    "/deliveries/{id}/status": {
      "put": {
        "tags": ["Deliveries"], "summary": "Atualizar status do delivery",
        "description": "Transições permitidas: CREATED→CONFIRMED→PREPARING→READY_FOR_PICKUP→OUT_FOR_DELIVERY→DELIVERED",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["CREATED","CONFIRMED","PREPARING","READY_FOR_PICKUP","OUT_FOR_DELIVERY","DELIVERED","CANCELED"] }, "delivery_user_id": { "type": "integer", "nullable": true } } } } } },
        "responses": { "200": { "description": "Status atualizado" }, "422": { "description": "Transição inválida", "content": { "application/json": { "example": { "message": "Transição inválida: CREATED → DELIVERED", "allowed": ["CONFIRMED","CANCELED"] } } } } }
      }
    },
    "/deliveries/{id}/location": {
      "put": {
        "tags": ["Deliveries"], "summary": "Atualizar localização do entregador (rastreamento)",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["lat","lng"], "properties": { "lat": { "type": "number" }, "lng": { "type": "number" } } } } } },
        "responses": { "200": { "description": "Localização atualizada" } }
      }
    },
    "/devices": {
      "get": { "tags": ["Devices"], "summary": "Listar dispositivos (tenant-scoped)", "parameters": [{ "name": "type", "in": "query", "schema": { "type": "string", "enum": ["POS","TABLET","KIOSK"] } }, { "name": "system_unit_id", "in": "query", "schema": { "type": "integer" } }, { "name": "status", "in": "query", "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } },
      "post": { "tags": ["Devices"], "summary": "Criar dispositivo", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["system_unit_id","name","type","identifier"], "properties": { "system_unit_id": { "type": "integer" }, "name": { "type": "string" }, "type": { "type": "string", "enum": ["POS","TABLET","KIOSK"] }, "identifier": { "type": "string" }, "status": { "type": "string", "enum": ["active","inactive","blocked"], "default": "active" } } } } } }, "responses": { "201": { "description": "OK" } } }
    },
    "/devices/{id}": {
      "get": { "tags": ["Devices"], "summary": "Detalhe", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } },
      "put": { "tags": ["Devices"], "summary": "Atualizar", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "status": { "type": "string", "enum": ["active","inactive","blocked"] } } } } } }, "responses": { "200": { "description": "OK" } } },
      "delete": { "tags": ["Devices"], "summary": "Excluir", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/referrers": {
      "get": { "tags": ["Referrers"], "summary": "Listar guias turísticos", "parameters": [{ "name": "active", "in": "query", "schema": { "type": "boolean" } }], "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Referrers"], "summary": "Criar guia turístico",
        "description": "partner_id vem do JWT. commission_type: percentage | fixed",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","commission_type","commission_value"], "properties": { "name": { "type": "string" }, "document": { "type": "string" }, "phone": { "type": "string" }, "email": { "type": "string" }, "commission_type": { "type": "string", "enum": ["percentage","fixed"] }, "commission_value": { "type": "number" } } } } } },
        "responses": { "201": { "description": "OK" } }
      }
    },
    "/referrers/{id}/commissions": {
      "get": { "tags": ["Referrers"], "summary": "Histórico de comissões do guia", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/cash-register/status": {
      "get": { "tags": ["Cash Register"], "summary": "Status do caixa atual", "responses": { "200": { "description": "OK" } } }
    },
    "/cash-register/open": {
      "post": { "tags": ["Cash Register"], "summary": "Abrir caixa", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "valor_abertura": { "type": "number" }, "observacao": { "type": "string" } } } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/cash-register/close": {
      "post": { "tags": ["Cash Register"], "summary": "Fechar caixa", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "valor_fechamento": { "type": "number" }, "observacao": { "type": "string" } } } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/pagamentos": {
      "get": { "tags": ["Payments"], "summary": "Listar pagamentos (paginado)", "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Payments"], "summary": "Criar pagamento pendente (PASSO 6 do fluxo operador)",
        "description": "Cria o registro de pagamento com status `pending` ANTES de acionar o SDK do POS. Salve o `id` retornado. Após retorno do POS, chame `PUT /pagamentos/{id}` com o resultado.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["sales_order_id"], "properties": { "sales_order_id": { "type": "integer", "description": "ID do pedido confirmado" }, "forma_pagamento": { "type": "string", "enum": ["dinheiro","credito","debito","pix","voucher"], "description": "Alias PT-BR (alternativa a payment_type)" }, "payment_type": { "type": "string", "enum": ["cash","credit","debit","pix","voucher"], "description": "Alias EN (alternativa a forma_pagamento)" }, "valor": { "type": "number", "description": "Valor em reais (alternativa a amount)" }, "amount": { "type": "integer", "description": "Valor em centavos (alternativa a valor)" }, "installments": { "type": "integer", "minimum": 1, "maximum": 12, "default": 1 } } } } } },
        "responses": { "201": { "description": "Pagamento criado com status pending", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" }, "sales_order_id": { "type": "integer" }, "status": { "type": "string", "example": "pending" }, "amount": { "type": "integer", "description": "Valor em centavos" }, "payment_type": { "type": "string" } } } } } }, "422": { "description": "Pedido não confirmado ou já possui pagamento aprovado" } }
      }
    },
    "/pagamentos/{id}": {
      "get": { "tags": ["Payments"], "summary": "Detalhe do pagamento", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "OK" } } },
      "put": {
        "tags": ["Payments"], "summary": "Atualizar pagamento com retorno do POS — gera tickets se aprovado (PASSO 7)",
        "description": "Chamado após o POS retornar o resultado da transação. Quando `status=approved`:\n- Atualiza o pedido para `paid`\n- Registra movimento no caixa\n- **Gera tickets automaticamente** via TicketService (1 ticket por unidade de quantidade)",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["approved","declined","cancelled"], "description": "approved → gera tickets e marca pedido como paid" }, "nsu": { "type": "string" }, "authorization_code": { "type": "string" }, "transaction_code": { "type": "string" }, "response_code": { "type": "string" }, "reason_message": { "type": "string" }, "brand": { "type": "string", "example": "VISA" }, "card_number": { "type": "string", "example": "****1234" }, "card_holder": { "type": "string" }, "installments": { "type": "integer" }, "is_captured": { "type": "boolean" } } } } } },
        "responses": {
          "200": { "description": "Pagamento atualizado. Se approved: pedido paid + tickets gerados.", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" }, "status": { "type": "string", "example": "approved" }, "sales_order": { "type": "object", "properties": { "id": { "type": "integer" }, "status": { "type": "string", "example": "paid" }, "paid_at": { "type": "string", "format": "date-time" } } } } } } } },
          "404": { "description": "Pagamento não encontrado" }
        }
      }
    },
    "/pagamentos/{id}/status": {
      "put": {
        "tags": ["Payments"], "summary": "Atualização simples de status (Flutter/app mobile)",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["approved","declined","cancelled","refunded"] } } } } } },
        "responses": { "200": { "description": "Status atualizado" } }
      }
    },
    "/fiscal-documents/gerar": {
      "post": { "tags": ["Fiscal Documents"], "summary": "Gerar NF-e", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["sales_order_id"], "properties": { "sales_order_id": { "type": "integer" }, "serie": { "type": "string" }, "natureza_operacao": { "type": "string" } } } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/modulos": {
      "get": { "tags": ["Modules"], "summary": "Listar módulos (admin only)", "responses": { "200": { "description": "OK" }, "403": { "$ref": "#/components/schemas/Error403" } } }
    },
    "/activation/machine": {
      "get": { "tags": ["Activation"], "summary": "Buscar máquina por código de ativação", "security": [], "parameters": [{ "name": "codigo", "in": "query", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/app-config/config": {
      "get": { "tags": ["App Config"], "summary": "Configuração white label por domínio", "security": [], "responses": { "200": { "description": "OK" } } }
    },
    "/webhooks/payment": {
      "post": { "tags": ["Webhooks"], "summary": "Receber evento de pagamento", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "event": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" }, "data": { "type": "object" } } } } } }, "responses": { "200": { "description": "Recebido" } } }
    },
    "/webhooks/order": {
      "post": { "tags": ["Webhooks"], "summary": "Receber evento de pedido", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "event": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" }, "data": { "type": "object" } } } } } }, "responses": { "200": { "description": "Recebido" } } }
    },
    "/webhooks/fiscal": {
      "post": { "tags": ["Webhooks"], "summary": "Receber evento fiscal", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "event": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" }, "data": { "type": "object" } } } } } }, "responses": { "200": { "description": "Recebido" } } }
    },
    "/tickets/validate": {
      "post": {
        "tags": ["Tickets"], "summary": "Validar e consumir ticket — uso único (PASSO 9 / PASSO 6)",
        "description": "Consome o ticket: muda status de `PENDING` → `USED`. Chamada idempotente: segunda chamada retorna 422 com `valid: false`.\n\nUso: leitores de QR Code no ponto de entrada, integração via `qrcode` URL do ticket.",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["codigo"], "properties": { "codigo": { "type": "string", "format": "uuid", "example": "550e8400-e29b-41d4-a716-446655440000" } } } } } },
        "responses": {
          "200": { "description": "Ticket válido e marcado como USED", "content": { "application/json": { "schema": { "type": "object", "properties": { "valid": { "type": "boolean", "example": true }, "status": { "type": "string", "example": "USED" }, "produto": { "type": "string" }, "pedido": { "type": "string" }, "used_at": { "type": "string", "format": "date-time" } } } } } },
          "404": { "description": "Ticket não encontrado" },
          "422": { "description": "Ticket já utilizado ou cancelado" }
        }
      }
    },
    "/tickets/{codigo}": {
      "get": {
        "tags": ["Tickets"], "summary": "Buscar ticket pelo código único (PASSO 5 do fluxo público)",
        "description": "Retorna os dados do ticket incluindo status, produto, QR code e pedido vinculado.",
        "security": [],
        "parameters": [{ "name": "codigo", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "UUID do ticket (campo codigo_unico)" }],
        "responses": {
          "200": { "description": "Dados do ticket", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ticket" } } } },
          "404": { "description": "Ticket não encontrado" }
        }
      }
    },
    "/tickets/order/{order_id}": {
      "get": {
        "tags": ["Tickets"], "summary": "Listar tickets de um pedido (PASSO 8 do fluxo operador)",
        "description": "Retorna todos os tickets gerados para o pedido. Um ticket é gerado por unidade de quantidade de cada item (ex: item com quantidade=2 gera 2 tickets). Salve `codigo_unico` do primeiro ticket para o passo 9.",
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "name": "order_id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": {
            "description": "Lista de tickets do pedido",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Ticket" } } } }
          }
        }
      }
    },
    "/tickets/print/{order_id}": {
      "post": {
        "tags": ["Tickets"], "summary": "Dados para impressão dos tickets de um pedido", "security": [{ "bearerAuth": [] }],
        "parameters": [{ "name": "order_id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "Pedido e lista de tickets para impressão" } }
      }
    },
    "/tickets/{codigo}/cancel": {
      "post": {
        "tags": ["Tickets"], "summary": "Cancelar ticket PENDING", "security": [{ "bearerAuth": [] }],
        "parameters": [{ "name": "codigo", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Ticket cancelado" }, "422": { "description": "Ticket não está PENDING" } }
      }
    },
    "/public/orders": {
      "post": {
        "tags": ["Public Orders"], "summary": "Criar pedido público (autoatendimento)", "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["partner_id","system_unit_id"], "properties": { "partner_id": { "type": "integer" }, "system_unit_id": { "type": "integer" }, "pessoa_id": { "type": "integer", "nullable": true }, "observacao": { "type": "string", "nullable": true } } } } } },
        "responses": { "201": { "description": "Pedido criado" } }
      }
    },
    "/public/orders/{id}/items": {
      "post": {
        "tags": ["Public Orders"], "summary": "Adicionar item ao pedido público", "security": [],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["produto_id","quantidade"], "properties": { "produto_id": { "type": "integer" }, "quantidade": { "type": "integer", "minimum": 1 }, "preco_unitario": { "type": "number", "nullable": true } } } } } },
        "responses": { "201": { "description": "Item adicionado" }, "422": { "description": "Pedido já confirmado" } }
      }
    },
    "/public/orders/{id}/checkout": {
      "post": {
        "tags": ["Public Orders"], "summary": "Confirmar pedido público", "security": [],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "Pedido confirmado" }, "422": { "description": "Sem itens ou já confirmado" } }
      }
    },
    "/table-reservations": {
      "get": { "tags": ["Table Reservations"], "summary": "Listar reservas", "parameters": [{"name":"date","in":"query","schema":{"type":"string","format":"date"}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","confirmed","cancelled","completed"]}},{"name":"restaurant_table_id","in":"query","schema":{"type":"integer"}}], "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Table Reservations"], "summary": "Criar reserva de mesa",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["restaurant_table_id","customer_name","reservation_date","reservation_time"], "properties": { "restaurant_table_id": { "type": "integer" }, "customer_name": { "type": "string" }, "customer_phone": { "type": "string" }, "reservation_date": { "type": "string", "format": "date" }, "reservation_time": { "type": "string", "example": "19:30" }, "num_people": { "type": "integer", "default": 1 }, "notes": { "type": "string" } } } } } },
        "responses": { "201": { "description": "Reserva criada" } }
      }
    },
    "/table-reservations/{id}": {
      "get": { "tags": ["Table Reservations"], "summary": "Detalhe da reserva", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "OK" } } },
      "put": { "tags": ["Table Reservations"], "summary": "Atualizar reserva", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "customer_name": { "type": "string" }, "customer_phone": { "type": "string" }, "reservation_date": { "type": "string", "format": "date" }, "reservation_time": { "type": "string" }, "num_people": { "type": "integer" }, "notes": { "type": "string" } } } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/table-reservations/{id}/confirm": {
      "post": { "tags": ["Table Reservations"], "summary": "Confirmar reserva e marcar mesa como RESERVED", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Confirmada" }, "422": { "description": "Mesa não livre ou reserva não pendente" } } }
    },
    "/table-reservations/{id}/cancel": {
      "post": { "tags": ["Table Reservations"], "summary": "Cancelar reserva", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Cancelada" } } }
    },
    "/table-reservations/{id}/complete": {
      "post": { "tags": ["Table Reservations"], "summary": "Cliente chegou — libera mesa para abertura de comanda/pedido", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Concluída" } } }
    },
    "/comandas": {
      "get": { "tags": ["Comandas"], "summary": "Listar comandas", "parameters": [{"name":"status","in":"query","schema":{"type":"string","enum":["aberta","fechada","paga","cancelada"]}},{"name":"restaurant_table_id","in":"query","schema":{"type":"integer"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}}], "responses": { "200": { "description": "OK" } } },
      "post": {
        "tags": ["Comandas"], "summary": "Abrir nova comanda",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "restaurant_table_id": { "type": "integer", "nullable": true }, "pessoa_id": { "type": "integer", "nullable": true }, "cliente_nome": { "type": "string" }, "num_pessoas": { "type": "integer", "default": 1 }, "observacao": { "type": "string" } } } } } },
        "responses": { "201": { "description": "Comanda aberta" } }
      }
    },
    "/comandas/{id}": {
      "get": { "tags": ["Comandas"], "summary": "Detalhe da comanda com itens", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "OK" } } }
    },
    "/comandas/{id}/items": {
      "post": {
        "tags": ["Comandas"], "summary": "Adicionar item à comanda",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["quantidade"], "properties": { "produto_id": { "type": "integer" }, "nome_produto": { "type": "string" }, "quantidade": { "type": "number", "minimum": 0.001 }, "preco_unitario": { "type": "number" }, "desconto": { "type": "number", "default": 0 }, "observacao": { "type": "string" } } } } } },
        "responses": { "201": { "description": "Item adicionado" } }
      }
    },
    "/comandas/{id}/items/{itemId}": {
      "delete": { "tags": ["Comandas"], "summary": "Remover item da comanda", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "OK" } } }
    },
    "/comandas/{id}/desconto": {
      "post": { "tags": ["Comandas"], "summary": "Aplicar desconto global", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["desconto"], "properties": { "desconto": { "type": "number" } } } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/comandas/{id}/transferir": {
      "post": { "tags": ["Comandas"], "summary": "Transferir comanda para outra mesa", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["restaurant_table_id"], "properties": { "restaurant_table_id": { "type": "integer" } } } } } }, "responses": { "200": { "description": "Transferida" }, "422": { "description": "Mesa destino não está livre" } } }
    },
    "/comandas/{id}/fechar": {
      "post": { "tags": ["Comandas"], "summary": "Fechar comanda (pronta para pagamento)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Fechada" } } }
    },
    "/comandas/{id}/pagar": {
      "post": {
        "tags": ["Comandas"], "summary": "Pagar comanda e liberar mesa",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["payment_type"], "properties": { "payment_type": { "type": "string", "enum": ["credit","debit","pix","cash","voucher"] }, "amount": { "type": "integer", "description": "Valor em centavos. Omitir para usar total da comanda." } } } } } },
        "responses": { "200": { "description": "Paga" } }
      }
    },
    "/comandas/{id}/cancelar": {
      "post": { "tags": ["Comandas"], "summary": "Cancelar comanda", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Cancelada" }, "422": { "description": "Comanda já paga" } } }
    },
    "/parking/pricings": {
      "get": { "tags": ["Parking - Pricings"], "summary": "Listar tabelas de preço", "parameters": [{"name":"type","in":"query","schema":{"type":"string","enum":["HOURLY","DAILY","MONTHLY"]}},{"name":"is_active","in":"query","schema":{"type":"boolean"}}], "responses": { "200": { "description": "Lista de tabelas", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ParkingPricing" } } } } } } },
      "post": {
        "tags": ["Parking - Pricings"], "summary": "Criar tabela de preço",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","type"], "properties": { "name": { "type": "string", "example": "Padrão" }, "type": { "type": "string", "enum": ["HOURLY","DAILY","MONTHLY"] }, "price_per_hour": { "type": "number", "example": 5.00 }, "price_per_minute_exceeded": { "type": "number", "example": 0.10 }, "grace_period_minutes": { "type": "integer", "example": 10 }, "daily_max_price": { "type": "number", "example": 30.00, "nullable": true }, "monthly_price": { "type": "number", "nullable": true }, "is_active": { "type": "boolean" } } } } } },
        "responses": { "201": { "description": "Tabela criada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ParkingPricing" } } } } }
      }
    },
    "/parking/pricings/{id}": {
      "get": { "tags": ["Parking - Pricings"], "summary": "Buscar tabela de preço", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Tabela", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ParkingPricing" } } } } } },
      "put": { "tags": ["Parking - Pricings"], "summary": "Atualizar tabela de preço", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "price_per_hour": { "type": "number" }, "price_per_minute_exceeded": { "type": "number" }, "grace_period_minutes": { "type": "integer" }, "daily_max_price": { "type": "number" }, "monthly_price": { "type": "number" }, "is_active": { "type": "boolean" } } } } } }, "responses": { "200": { "description": "Atualizada" } } },
      "delete": { "tags": ["Parking - Pricings"], "summary": "Remover tabela (bloqueado se em uso)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Removida" }, "422": { "description": "Em uso por tickets abertos" } } }
    },
    "/parking/monthly": {
      "get": { "tags": ["Parking - Monthly Customers"], "summary": "Listar mensalistas", "parameters": [{"name":"status","in":"query","schema":{"type":"string","enum":["ACTIVE","INACTIVE"]}},{"name":"plate","in":"query","schema":{"type":"string"}}], "responses": { "200": { "description": "Lista paginada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Paginated" } } } } } },
      "post": {
        "tags": ["Parking - Monthly Customers"], "summary": "Cadastrar mensalista",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","plate","pricing_id","start_date","end_date"], "properties": { "name": { "type": "string" }, "document": { "type": "string", "nullable": true }, "plate": { "type": "string", "example": "ABC1234" }, "pricing_id": { "type": "integer" }, "start_date": { "type": "string", "format": "date" }, "end_date": { "type": "string", "format": "date" }, "status": { "type": "string", "enum": ["ACTIVE","INACTIVE"] } } } } } },
        "responses": { "201": { "description": "Mensalista criado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MonthlyCustomer" } } } } }
      }
    },
    "/parking/monthly/{id}": {
      "get": { "tags": ["Parking - Monthly Customers"], "summary": "Buscar mensalista", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Mensalista", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MonthlyCustomer" } } } } } },
      "put": { "tags": ["Parking - Monthly Customers"], "summary": "Atualizar mensalista", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "plate": { "type": "string" }, "start_date": { "type": "string", "format": "date" }, "end_date": { "type": "string", "format": "date" }, "status": { "type": "string", "enum": ["ACTIVE","INACTIVE"] } } } } } }, "responses": { "200": { "description": "Atualizado" } } },
      "delete": { "tags": ["Parking - Monthly Customers"], "summary": "Remover mensalista", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Removido" } } }
    },
    "/parking/open": {
      "get": { "tags": ["Parking - Tickets"], "summary": "Veículos atualmente no estacionamento (status=OPEN)", "responses": { "200": { "description": "Lista de tickets abertos", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ParkingTicket" } } } } } } }
    },
    "/parking/tickets": {
      "get": { "tags": ["Parking - Tickets"], "summary": "Listar todos os tickets", "parameters": [{"name":"status","in":"query","schema":{"type":"string","enum":["OPEN","CLOSED"]}},{"name":"plate","in":"query","schema":{"type":"string"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}}], "responses": { "200": { "description": "Lista paginada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Paginated" } } } } } }
    },
    "/parking/tickets/{id}": {
      "get": { "tags": ["Parking - Tickets"], "summary": "Buscar ticket por ID", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Ticket", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ParkingTicket" } } } } } }
    },
    "/parking/entry": {
      "post": {
        "tags": ["Parking - Tickets"], "summary": "Registrar entrada de veículo",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["plate","pricing_id"], "properties": { "plate": { "type": "string", "example": "ABC1234" }, "vehicle_type": { "type": "string", "example": "car", "enum": ["car","motorcycle","truck","van","other"] }, "pricing_id": { "type": "integer" } } } } } },
        "responses": {
          "201": { "description": "Ticket criado — mensalista detectado automaticamente", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ParkingTicket" } } } },
          "422": { "description": "Já existe ticket aberto para esta placa" }
        }
      }
    },
    "/parking/exit/{id}": {
      "post": {
        "tags": ["Parking - Tickets"], "summary": "Registrar saída — calcula tempo, valor e cria SalesOrder",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "responses": {
          "200": {
            "description": "Saída registrada com cálculo de valor",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" }, "duration_minutes": { "type": "integer" }, "total_amount": { "type": "number" }, "ticket": { "$ref": "#/components/schemas/ParkingTicket" }, "sales_order": { "type": "object" } } } } }
          },
          "422": { "description": "Ticket já encerrado" }
        }
      }
    },
    "/entregadores/login": {
      "post": {
        "tags": ["SmartRoute - Entregadores Auth"], "summary": "Login de entregador", "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email","password"], "properties": { "email": { "type": "string", "format": "email" }, "password": { "type": "string" } } } } } },
        "responses": { "200": { "description": "Token JWT", "content": { "application/json": { "schema": { "type": "object", "properties": { "access_token": { "type": "string" }, "token_type": { "type": "string" }, "expires_in": { "type": "integer" }, "entregador": { "$ref": "#/components/schemas/Entregador" } } } } } }, "401": { "description": "Credenciais inválidas" } }
      }
    },
    "/entregadores/me": {
      "get": { "tags": ["SmartRoute - Entregadores Auth"], "summary": "Perfil do entregador autenticado", "security": [{"bearerAuth": []}], "responses": { "200": { "description": "Entregador", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Entregador" } } } } } }
    },
    "/entregadores/logout": {
      "post": { "tags": ["SmartRoute - Entregadores Auth"], "summary": "Logout do entregador", "security": [{"bearerAuth": []}], "responses": { "200": { "description": "Logout realizado" } } }
    },
    "/entregadores": {
      "get": { "tags": ["SmartRoute - Entregadores"], "summary": "Listar entregadores", "parameters": [{"name":"active","in":"query","schema":{"type":"boolean"}}], "responses": { "200": { "description": "Lista paginada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Paginated" } } } } } },
      "post": {
        "tags": ["SmartRoute - Entregadores"], "summary": "Criar entregador",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name","email","password","system_unit_id"], "properties": { "name": { "type": "string" }, "email": { "type": "string", "format": "email" }, "password": { "type": "string", "minLength": 6 }, "system_unit_id": { "type": "integer" }, "active": { "type": "boolean" } } } } } },
        "responses": { "201": { "description": "Entregador criado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Entregador" } } } }, "422": { "$ref": "#/components/schemas/Error422" } }
      }
    },
    "/entregadores/{id}": {
      "get": { "tags": ["SmartRoute - Entregadores"], "summary": "Buscar entregador", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Entregador", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Entregador" } } } } } },
      "put": {
        "tags": ["SmartRoute - Entregadores"], "summary": "Atualizar entregador",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "email": { "type": "string" }, "password": { "type": "string" }, "active": { "type": "boolean" } } } } } },
        "responses": { "200": { "description": "Entregador atualizado" } }
      },
      "delete": { "tags": ["SmartRoute - Entregadores"], "summary": "Remover entregador", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Removido" } } }
    },
    "/delivery-routes": {
      "get": { "tags": ["SmartRoute - Rotas"], "summary": "Listar rotas de entrega", "parameters": [{"name":"status","in":"query","schema":{"type":"string","enum":["criada","em_andamento","finalizada"]}},{"name":"entregador_id","in":"query","schema":{"type":"integer"}},{"name":"date","in":"query","schema":{"type":"string","format":"date"}}], "responses": { "200": { "description": "Lista paginada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Paginated" } } } } } },
      "post": {
        "tags": ["SmartRoute - Rotas"], "summary": "Criar rota de entrega",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["entregador_id"], "properties": { "entregador_id": { "type": "integer" }, "notes": { "type": "string" }, "stops": { "type": "array", "items": { "type": "object", "required": ["customer_name","address","latitude","longitude"], "properties": { "customer_name": { "type": "string" }, "address": { "type": "string" }, "latitude": { "type": "number" }, "longitude": { "type": "number" }, "payment_type": { "type": "string", "enum": ["antecipado","na_entrega"], "default": "antecipado" }, "sales_order_id": { "type": "integer", "nullable": true }, "notes": { "type": "string" } } } } } } } } },
        "responses": { "201": { "description": "Rota criada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryRoute" } } } }, "422": { "$ref": "#/components/schemas/Error422" } }
      }
    },
    "/delivery-routes/{id}": {
      "get": { "tags": ["SmartRoute - Rotas"], "summary": "Buscar rota com paradas", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Rota", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryRoute" } } } } } },
      "put": { "tags": ["SmartRoute - Rotas"], "summary": "Atualizar rota (apenas status=criada)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "entregador_id": { "type": "integer" }, "notes": { "type": "string" } } } } } }, "responses": { "200": { "description": "Atualizada" }, "422": { "description": "Rota já iniciada" } } },
      "delete": { "tags": ["SmartRoute - Rotas"], "summary": "Remover rota (apenas status=criada)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Removida" }, "422": { "description": "Rota já iniciada" } } }
    },
    "/delivery-routes/{id}/stops": {
      "post": {
        "tags": ["SmartRoute - Rotas"], "summary": "Adicionar parada à rota (apenas status=criada)",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["customer_name","address","latitude","longitude"], "properties": { "customer_name": { "type": "string" }, "address": { "type": "string" }, "latitude": { "type": "number" }, "longitude": { "type": "number" }, "payment_type": { "type": "string", "enum": ["antecipado","na_entrega"] }, "sales_order_id": { "type": "integer", "nullable": true }, "notes": { "type": "string" } } } } } },
        "responses": { "201": { "description": "Parada adicionada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryStop" } } } } }
      }
    },
    "/delivery-routes/{id}/tracking": {
      "get": { "tags": ["SmartRoute - Rotas"], "summary": "Histórico de rastreamento da rota", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Histórico de posições", "content": { "application/json": { "schema": { "type": "object", "properties": { "route_id": { "type": "integer" }, "status": { "type": "string" }, "trackings": { "type": "array", "items": { "$ref": "#/components/schemas/DeliveryTracking" } } } } } } } } }
    },
    "/entregador/routes": {
      "get": { "tags": ["SmartRoute - Rotas"], "summary": "Minhas rotas (entregador autenticado)", "parameters": [{"name":"status","in":"query","schema":{"type":"string","enum":["criada","em_andamento","finalizada"]}}], "responses": { "200": { "description": "Lista paginada" } } }
    },
    "/entregador/routes/{id}/start": {
      "post": { "tags": ["SmartRoute - Rotas"], "summary": "Iniciar rota", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Rota iniciada" }, "422": { "description": "Rota já iniciada ou sem paradas" } } }
    },
    "/entregador/routes/{id}/finish": {
      "post": { "tags": ["SmartRoute - Rotas"], "summary": "Finalizar rota (todas as paradas devem estar entregues)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Rota finalizada" }, "422": { "description": "Paradas pendentes" } } }
    },
    "/entregador/routes/{id}/location": {
      "post": {
        "tags": ["SmartRoute - Rotas"], "summary": "Atualizar localização do entregador em tempo real",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["latitude","longitude"], "properties": { "latitude": { "type": "number" }, "longitude": { "type": "number" } } } } } },
        "responses": { "201": { "description": "Posição registrada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeliveryTracking" } } } } }
      }
    },
    "/entregador/stops/{id}/start": {
      "post": { "tags": ["SmartRoute - Paradas"], "summary": "Iniciar parada (pendente → em_andamento)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Parada iniciada" }, "422": { "description": "Parada já iniciada" } } }
    },
    "/entregador/stops/{id}/arrive": {
      "post": {
        "tags": ["SmartRoute - Paradas"], "summary": "Registrar chegada e calcular distância ao local previsto",
        "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["latitude","longitude"], "properties": { "latitude": { "type": "number", "description": "Latitude real da entrega" }, "longitude": { "type": "number", "description": "Longitude real da entrega" } } } } } },
        "responses": { "200": { "description": "Chegada registrada com distância calculada", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" }, "distance_meters": { "type": "number" }, "stop": { "$ref": "#/components/schemas/DeliveryStop" } } } } } } }
      }
    },
    "/entregador/stops/{id}/pay": {
      "post": { "tags": ["SmartRoute - Paradas"], "summary": "Registrar pagamento na entrega (payment_type=na_entrega)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Pagamento registrado" }, "422": { "description": "Parada não requer pagamento na entrega ou já pago" } } }
    },
    "/entregador/stops/{id}/deliver": {
      "post": { "tags": ["SmartRoute - Paradas"], "summary": "Finalizar entrega (bloqueado se pagamento não confirmado ou chegada não registrada)", "parameters": [{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}], "responses": { "200": { "description": "Entrega finalizada" }, "422": { "description": "Pagamento pendente ou chegada não registrada" } } }
    },
    "/public/payment": {
      "post": {
        "tags": ["Public Orders"], "summary": "Registrar pagamento público e gerar tickets", "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["sales_order_id","amount","payment_type"], "properties": { "sales_order_id": { "type": "integer" }, "amount": { "type": "integer", "description": "Valor em centavos", "example": 5000 }, "payment_type": { "type": "string", "enum": ["credit","debit","pix","cash","voucher"] } } } } } },
        "responses": {
          "201": { "description": "Pagamento confirmado e tickets gerados", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" }, "order": { "type": "object" }, "tickets": { "type": "array", "items": { "$ref": "#/components/schemas/Ticket" } } } } } } },
          "422": { "description": "Pedido não confirmado ou já pago" }
        }
      }
    }
  }
}
