Sistema de configuração logística inteligente para microindústrias
- Python 3.10+
- MySQL
- Git
git clone <URL_DO_REPOSITORIO>
cd backendpip install -r requirements.txt- Crie o arquivo abaixo na pasta raiz:
DBCREDENTIALS.env - Insira no arquivo
DBCREDENTIALS.envos dados do seu MySQL:DB_NAME=milo_db DB_USER=seu_usuario DB_PASSWORD=sua_senha DB_HOST=localhost DB_PORT=3306
Acesse o MySQL e execute:
CREATE DATABASE milo_db;python manage.py makemigrations
python manage.py migrateou
py manage.py makemigrations
py manage.py migratepython manage.py precarregar_maceioou
py manage.py precarregar_maceiopython manage.py runserverou
py manage.py runserver- Endpoint:
POST http://127.0.0.1:8000/api/usuarios/register/ - Body (JSON):
{ "cnpj": "12345678000199", "nome": "Empresa Exemplo", "telefone": "11999999999", "email": "empresa@exemplo.com", "cep": "12345678", "rua": "Rua Exemplo", "numero": "123", "bairro": "Centro", "cidade": "São Paulo", "estado": "SP", "password": "senhaSegura123" }
- CNPJ e Nome são obrigatórios
- Email OU Telefone - pelo menos um dos dois deve ser fornecido (não é obrigatório fornecer ambos)
- Todos os campos de endereço são obrigatórios: cep, rua, numero, bairro, cidade, estado
Exemplos válidos:
Cadastro apenas com email:
{
"cnpj": "12345678000199",
"nome": "Empresa Exemplo",
"email": "empresa@exemplo.com",
"cep": "12345678",
"rua": "Rua Exemplo",
"numero": "123",
"bairro": "Centro",
"cidade": "São Paulo",
"estado": "SP",
"password": "senhaSegura123"
}Cadastro apenas com telefone:
{
"cnpj": "12345678000198",
"nome": "Empresa Exemplo 2",
"telefone": "11999999999",
"cep": "12345678",
"rua": "Rua Exemplo",
"numero": "123",
"bairro": "Centro",
"cidade": "São Paulo",
"estado": "SP",
"password": "senhaSegura123"
}Cadastro com ambos (email e telefone):
{
"cnpj": "12345678000197",
"nome": "Empresa Exemplo 3",
"telefone": "11999999999",
"email": "empresa@exemplo.com",
"cep": "12345678",
"rua": "Rua Exemplo",
"numero": "123",
"bairro": "Centro",
"cidade": "São Paulo",
"estado": "SP",
"password": "senhaSegura123"
}❌ Exemplos que gerarão erro:
Erro: Nenhum contato fornecido
{
"cnpj": "12345678000199",
"nome": "Empresa Exemplo",
"cep": "12345678",
"rua": "Rua Exemplo",
"numero": "123",
"bairro": "Centro",
"cidade": "São Paulo",
"estado": "SP",
"password": "senhaSegura123"
}Erro: "Pelo menos um dos campos: email ou telefone deve ser fornecido"
Erro: Campos de endereço faltando
{
"cnpj": "12345678000199",
"nome": "Empresa Exemplo",
"email": "empresa@exemplo.com",
"password": "senhaSegura123"
}Erro: "Os seguintes campos de endereço são obrigatórios: cep, rua, numero, bairro, cidade, estado"
- Endpoint:
POST http://127.0.0.1:8000/api/usuarios/login/ - Body (JSON):
{ "cnpj": "12345678000199", "password": "senhaSegura123" } - Resposta:
{ "refresh": "...", "access": "..." }
- Endpoint:
POST http://127.0.0.1:8000/api/usuarios/logout/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUIContent-Type: application/json
- Body (JSON):
{ "refresh_token": "SEU_REFRESH_TOKEN_AQUI" } - Resposta de sucesso:
{ "message": "Logout realizado com sucesso" } - Observação: O refresh token será invalidado e não poderá ser usado novamente
- Endpoint:
POST http://127.0.0.1:8000/api/usuarios/trocar-senha/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUIContent-Type: application/json
- Body (JSON):
{ "nova_senha": "novaSenhaSegura123" } - Resposta de sucesso:
{ "mensagem": "Senha atualizada com sucesso" }- Observação: Essa rota exige autenticação com token válido (access token)
-
Endpoint:
DELETE http://127.0.0.1:8000/api/usuarios/deletar-conta/ -
Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
-
Body (JSON):
não é necessário enviar nenhum corpo na requisição
-
Resposta de sucesso:
{ "mensagem": "Conta deletada com sucesso" }- **Observação:**A conta autenticada será permanentemente removida do sistema
- Endpoint:
POST http://127.0.0.1:8000/api/usuarios/solicitar-reset/ - Headers:
Content-Type: application/json
- Body (JSON):
{ "email": "usuario@exemplo.com" } - Resposta de sucesso:
{ "mensagem": "Email de reset enviado com sucesso. Verifique sua caixa de entrada." } - Observação:
- Sistema envia email com link de reset válido por 24 horas
- Por segurança, sempre retorna sucesso mesmo se email não existir
- Verifique também a pasta de spam
- Endpoint:
POST http://127.0.0.1:8000/api/usuarios/confirmar-reset/ - Headers:
Content-Type: application/json
- Body (JSON):
{ "token": "abc123def456...", "uidb64": "xyz789...", "new_password": "novaSenhaSegura123" } - Resposta de sucesso:
{ "mensagem": "Senha redefinida com sucesso. Você pode fazer login com a nova senha." } - Observação:
- Token e uidb64 são fornecidos no link do email
- Nova senha deve ter no mínimo 8 caracteres
- Token expira em 24 horas
Para usar o sistema de reset de senha, configure as credenciais de email:
-
Edite o arquivo
EMAILCREDENTIALS.env:EMAIL_HOST_USER=seu-email@gmail.com EMAIL_HOST_PASSWORD=sua-senha-de-app-16-chars DEFAULT_FROM_EMAIL=seu-email@gmail.com FRONTEND_URL=http://localhost:3000
-
Teste a configuração:
cd backend python test_email.py -
Se der erro, verifique:
- Verificação em 2 etapas ativada no Gmail
- Senha de app gerada corretamente (16 caracteres)
- Credenciais corretas no arquivo .env
- Para acessar rotas protegidas, envie o token no header:
- Key:
Authorization - Value:
Bearer SEU_TOKEN_AQUI
- Key:
- Endpoint:
POST http://127.0.0.1:8000/api/produtos/cadastrar-com-categoria/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "nome": "Notebook Pro", "codigo_barras": "9876543210987", "descricao": "Notebook profissional", "data_fabricacao": "2024-01-15", "validade": "2025-01-15", "lote": "LOT002", "preco_custo": "1500.00", "preco_venda": "2200.00", "marca": "TechBrand", "estoque_minimo": 3, "estoque_atual": 8, "fornecedor": 1, "categoria_id": 1 }
- Endpoint:
POST http://127.0.0.1:8000/api/produtos/cadastrar-com-categoria/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "nome": "Produto Especial", "codigo_barras": "1112223334445", "descricao": "Produto com categoria nova", "data_fabricacao": "2024-01-15", "validade": "2025-01-15", "lote": "LOT003", "preco_custo": "100.00", "preco_venda": "150.00", "marca": "MarcaNova", "estoque_minimo": 3, "estoque_atual": 8, "fornecedor": 1, "nova_categoria": "Categoria Especial" }
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
PUT http://127.0.0.1:8000/api/produtos/{id}/atualizar/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "nome": "Smartphone XYZ Atualizado", "codigo_barras": "1234567890123", "descricao": "Smartphone atualizado", "data_fabricacao": "2024-01-15", "validade": "2025-01-15", "lote": "LOT001", "preco_custo": "850.00", "preco_venda": "1250.00", "marca": "TechBrand", "estoque_minimo": 5, "estoque_atual": 12, "fornecedor": 1, "categoria": 1 }
- Endpoint:
DELETE http://127.0.0.1:8000/api/produtos/{id}/excluir/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
POST http://127.0.0.1:8000/api/produtos/categorias/criar/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "nome": "Eletrônicos" }
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/categorias/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
POST http://127.0.0.1:8000/api/produtos/fornecedores/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "nome": "Fornecedor ABC LTDA", "telefone": "(11) 99999-9999", "email": "contato@fornecedorabc.com", "endereco": "Rua do Fornecedor, 123 - São Paulo/SP" }
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/fornecedores/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
O sistema registra automaticamente todas as movimentações de estoque quando:
- Criação de produto: Se o produto for criado com estoque inicial, registra uma movimentação de entrada
- Atualização de produto: Se o estoque for alterado durante a atualização, registra automaticamente a movimentação
- Finalização de venda: Quando uma venda é finalizada, registra movimentações de saída para cada produto vendido
- Criação de rota: Quando uma rota é criada, registra movimentações de saída para os produtos incluídos na rota
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/movimentacoes/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
[ { "id": 1, "produto": 1, "produto_nome": "Smartphone XYZ", "tipo": "entrada", "tipo_display": "Entrada", "quantidade": 20, "estoque_anterior": 0, "estoque_atual": 20, "data_movimentacao": "2024-01-20T10:30:00Z", "observacao": "Cadastro inicial do produto" }, { "id": 2, "produto": 1, "produto_nome": "Smartphone XYZ", "tipo": "saida", "tipo_display": "Saída", "quantidade": 5, "estoque_anterior": 20, "estoque_atual": 15, "data_movimentacao": "2024-01-20T11:00:00Z", "observacao": "Remoção de 5 unidades do estoque" } ]
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/movimentacoes/produto/{produto_id}/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/movimentacoes/?tipo=entrada - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/movimentacoes/?produto=1 - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/movimentacoes/?search=Smartphone - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/?categoria=1 - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/produtos/?search=smartphone - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
POST http://127.0.0.1:8000/api/vendas/create/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "observacoes": "Venda para cliente especial", "itens": [ { "produto": 1, "quantidade": 2, "preco_unitario": 15.00 }, { "produto": 2, "quantidade": 1 } ] } - Resposta:
{ "id": 1, "data_criacao": "2024-01-20T10:30:00Z", "data_atualizacao": "2024-01-20T10:30:00Z", "total": 55.00, "status": "pendente", "status_display": "Pendente", "observacoes": "Venda para cliente especial", "total_itens": 2, "itens": [ { "id": 1, "produto": 1, "produto_nome": "Smartphone XYZ", "produto_codigo_barras": "1234567890123", "produto_preco_venda": 15.00, "produto_estoque_atual": 18, "quantidade": 2, "preco_unitario": 15.00, "subtotal": 30.00 }, { "id": 2, "produto": 2, "produto_nome": "Tablet ABC", "produto_codigo_barras": "9876543210987", "produto_preco_venda": 25.00, "produto_estoque_atual": 12, "quantidade": 1, "preco_unitario": 25.00, "subtotal": 25.00 } ] }
- Endpoint:
GET http://127.0.0.1:8000/api/vendas/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
[ { "id": 1, "data_criacao": "2024-01-20T10:30:00Z", "data_atualizacao": "2024-01-20T10:30:00Z", "total": 55.00, "status": "pendente", "status_display": "Pendente", "observacoes": "Venda para cliente especial", "total_itens": 2, "itens": [...] } ]
- Endpoint:
GET http://127.0.0.1:8000/api/vendas/{id}/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
PUT http://127.0.0.1:8000/api/vendas/{id}/update/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "observacoes": "Venda atualizada - cliente VIP", "status": "pendente" }
- Endpoint:
DELETE http://127.0.0.1:8000/api/vendas/{id}/delete/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Observação: Apenas vendas pendentes ou canceladas podem ser excluídas
- Endpoint:
POST http://127.0.0.1:8000/api/vendas/{id}/finalizar/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{} - Observação: Esta ação registra automaticamente as movimentações de estoque e altera o status para "finalizada"
- Endpoint:
POST http://127.0.0.1:8000/api/vendas/{id}/cancelar/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{} - Observação: Apenas vendas pendentes podem ser canceladas
- Endpoint:
POST http://127.0.0.1:8000/api/vendas/{venda_id}/itens/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "produto": 3, "quantidade": 1, "preco_unitario": 20.00 } - Observação: O campo
preco_unitarioé opcional. Se não informado, será usado automaticamente opreco_vendado produto.
- Endpoint:
PUT http://127.0.0.1:8000/api/vendas/{venda_id}/itens/{id}/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "quantidade": 3, "preco_unitario": 18.00 }
- Endpoint:
DELETE http://127.0.0.1:8000/api/vendas/{venda_id}/itens/{id}/delete/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/vendas/estatisticas/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
{ "total_vendas": 15, "vendas_finalizadas": 12, "vendas_pendentes": 2, "vendas_canceladas": 1, "total_faturado": 2500.00, "total_pendente": 300.00, "venda_maior_valor": { "id": 5, "total": 450.00, "data": "2024-01-20T14:30:00Z" } }
- Endpoint:
GET http://127.0.0.1:8000/api/vendas/?status=pendente - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/vendas/?search=cliente - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/vendas/?ordering=-data_criacao(mais recentes primeiro) - Endpoint:
GET http://127.0.0.1:8000/api/vendas/?ordering=total(menor valor primeiro) - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
pendente- Pendente (pode ser modificada)finalizada- Finalizada (estoque já foi atualizado)cancelada- Cancelada
Preço de Venda vs Preço Unitário:
preco_venda: Preço padrão cadastrado no produto (referência)preco_unitario: Preço específico usado nesta venda (opcional)
Como funciona:
- Se
preco_unitarionão for informado: Usa automaticamente opreco_vendado produto - Se
preco_unitariofor informado: Usa o valor específico (permite descontos/acréscimos)
Exemplos:
// Usando preço padrão (preco_unitario omitido)
{
"produto": 1,
"quantidade": 2
// preco_unitario será automaticamente o preco_venda do produto
}
// Usando preço personalizado (com desconto)
{
"produto": 1,
"quantidade": 2,
"preco_unitario": 12.00 // Desconto de R$ 3,00 por unidade
}-
Endpoint:
POST http://127.0.0.1:8000/api/rotas/veiculos/criar/ -
Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
-
Body (JSON):
{ "nome": "Caminhão Mercedes-Benz", "tipo_combustivel": "diesel", "eficiencia_km_l": "8.5" }Exemplos com outros tipos de combustível:
{ "nome": "Carro Flex", "tipo_combustivel": "etanol", "eficiencia_km_l": "12.0" }{ "nome": "Van GNV", "tipo_combustivel": "gnv", "eficiencia_km_l": "15.5" } -
Resposta:
{ "id": 1, "nome": "Caminhão Mercedes-Benz", "tipo_combustivel": "diesel", "tipo_combustivel_display": "Diesel", "eficiencia_km_l": "8.50", "data_cadastro": "2024-01-20T10:30:00Z", "data_atualizacao": "2024-01-20T10:30:00Z" }
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/veiculos/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
[ { "id": 1, "nome": "Caminhão Mercedes-Benz", "tipo_combustivel": "diesel", "tipo_combustivel_display": "Diesel", "consumo_por_km": "8.50", "data_cadastro": "2024-01-20T10:30:00Z", "data_atualizacao": "2024-01-20T10:30:00Z" }, { "id": 2, "nome": "Van Ford Transit", "tipo_combustivel": "gasolina", "tipo_combustivel_display": "Gasolina", "eficiencia_km_l": "10.2", "data_cadastro": "2024-01-20T11:00:00Z", "data_atualizacao": "2024-01-20T11:00:00Z" }, { "id": 3, "nome": "Carro Flex", "tipo_combustivel": "etanol", "tipo_combustivel_display": "Etanol", "eficiencia_km_l": "12.0", "data_cadastro": "2024-01-20T12:00:00Z", "data_atualizacao": "2024-01-20T12:00:00Z" }, { "id": 4, "nome": "Van GNV", "tipo_combustivel": "gnv", "tipo_combustivel_display": "Gás Veicular (GNV)", "eficiencia_km_l": "15.5", "data_cadastro": "2024-01-20T13:00:00Z", "data_atualizacao": "2024-01-20T13:00:00Z" } ]
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/veiculos/{id}/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
{ "id": 1, "nome": "Caminhão Mercedes-Benz", "tipo_combustivel": "diesel", "tipo_combustivel_display": "Diesel", "eficiencia_km_l": "8.50", "data_cadastro": "2024-01-20T10:30:00Z", "data_atualizacao": "2024-01-20T10:30:00Z" }
- Endpoint:
PUT http://127.0.0.1:8000/api/rotas/veiculos/{id}/atualizar/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "nome": "Caminhão Mercedes-Benz Atualizado", "tipo_combustivel": "diesel", "eficiencia_km_l": "8.3" }
- Endpoint:
DELETE http://127.0.0.1:8000/api/rotas/veiculos/{id}/excluir/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/veiculos/?tipo_combustivel=diesel - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
Valores válidos para filtro:
diesel- Filtrar veículos a dieselgasolina- Filtrar veículos a gasolinaetanol- Filtrar veículos a etanolgnv- Filtrar veículos a GNV
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/veiculos/?search=mercedes - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
diesel- Dieselgasolina- Gasolinaetanol- Etanolgnv- Gás Veicular (GNV)
-
Endpoint:
POST http://127.0.0.1:8000/api/rotas/rotas/criar/ -
Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
-
Body (JSON):
{ "enderecos_destino": [ "Avenida Paulista, 1000, São Paulo, Brasil", "Rua Augusta, 1500, São Paulo, Brasil", "Mercado Municipal de São Paulo" ], "nome_motorista": "João Silva", "veiculo_id": 1, "preco_combustivel": 6.50, "produtos_quantidades": [ { "produto_id": 1, "quantidade": 5 }, { "produto_id": 2, "quantidade": 3 } ] }Exemplo sem veículo e motorista (campos opcionais):
{ "enderecos_destino": [ "Rua Prof. Silvio de Macedo, 125, Jatiúca", "Universidade Federal de Alagoas" ], "produtos_quantidades": [ { "produto_id": 1, "quantidade": 5 } ] }Exemplo com preço personalizado de combustível:
{ "enderecos_destino": [ "Avenida Paulista, 1000, São Paulo, Brasil" ], "veiculo_id": 1, "preco_combustivel": 7.20, "produtos_quantidades": [ { "produto_id": 1, "quantidade": 3 } ] }Exemplo usando valor base (sem informar preço):
{ "enderecos_destino": [ "Rua Augusta, 1500, São Paulo, Brasil" ], "veiculo_id": 2, "produtos_quantidades": [ { "produto_id": 1, "quantidade": 2 } ] }- Resposta:
{ "id": 1, "data_geracao": "2024-01-20T10:30:00Z", "enderecos_otimizados": [ "Rua da Empresa", "Universidade Federal de Alagoas", "Rua Prof. Silvio de Macedo, 125, Jatiúca", "Rua da Empresa" ], "coordenadas_otimizadas": [ [-11.1111, -11.1111], [-9.5536252, -35.7739006], [-9.6461711, -35.7034641], [-11.1111, -11.1111] ], "distancia_total_km": "25.50", "tempo_estimado_minutos": 45, "veiculo": 1, "veiculo_nome": "Caminhão Mercedes-Benz", "nome_motorista": "João Silva", "valor_rota": "350.75", "preco_combustivel_usado": 6.50, "produtos_quantidades": [ { "produto_id": 1, "quantidade": 5 }, { "produto_id": 2, "quantidade": 3 } ], "link_maps": "https://www.google.com/maps/dir/?api=1&origin=-23.5505,-46.6333&destination=-23.5505,-46.6333&waypoints=-23.5631,-46.6544|-23.5489,-46.6388", "status": "em_progresso", "status_display": "Em Progresso", "preco_combustivel_na_geracao": 6.50 }
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/rotas/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
[ { "id": 1, "data_geracao": "2024-01-20T10:30:00Z", "enderecos_otimizados": [...], "coordenadas_otimizadas": [...], "distancia_total_km": "25.50", "tempo_estimado_minutos": 45, "veiculo": 1, "veiculo_nome": "Caminhão Mercedes-Benz", "nome_motorista": "João Silva", "valor_rota": "350.75", "produtos_quantidades": [...], "link_maps": "...", "status": "em_progresso", "status_display": "Em Progresso", "preco_combustivel_na_geracao": 5.8 } ]
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/rotas/{id}/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
PUT http://127.0.0.1:8000/api/rotas/rotas/{id}/status/ - Headers:
Content-Type: application/jsonAuthorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Body (JSON):
{ "status": "concluido" }
- Endpoint:
DELETE http://127.0.0.1:8000/api/rotas/rotas/{id}/excluir/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/rotas/?status=em_progresso - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/rotas/?veiculo=1 - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/rotas/?search=joão - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
em_progresso- Em Progressoconcluido- Concluído
- Endpoint:
GET http://127.0.0.1:8000/api/relatorios/conta/html/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Query Params:
periodo:ultimo_mes(padrão) |ultimos_6_meses|ultimo_ano|custom- Se
periodo=custom, informar também:inicio=YYYY-MM-DDefim=YYYY-MM-DD
- Exemplos:
- Último mês:
GET http://127.0.0.1:8000/api/relatorios/conta/html/?periodo=ultimo_mes - Últimos 6 meses:
GET http://127.0.0.1:8000/api/relatorios/conta/html/?periodo=ultimos_6_meses - Último ano:
GET http://127.0.0.1:8000/api/relatorios/conta/html/?periodo=ultimo_ano - Período customizado:
GET http://127.0.0.1:8000/api/relatorios/conta/html/?periodo=custom&inicio=2025-01-01&fim=2025-03-31
- Último mês:
- Resposta: Página HTML interativa contendo:
- Resumo Executivo: Métricas principais do período
- Análise de Produtos: Top entradas, saídas, mais/menos vendidos
- Análise de Rotas: Top bairros visitados, produtos mais/menos enviados
- Detalhamento de Rotas: Tabela completa com custos, vendas, lucros e destinos de entrega
- Detalhamento de Vendas: Todas as vendas do período (diretas + rotas) com tipo identificado
- Endpoint:
GET http://127.0.0.1:8000/api/rotas/precos-combustivel/ - Headers:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI - Resposta:
{
"diesel": 5.80,
"gasolina": 6.36,
"etanol": 4.20,
"gnv": 3.50,
"unidades": {
"diesel": "R$/L",
"gasolina": "R$/L",
"etanol": "R$/L",
"gnv": "R$/m³"
},
"fonte": "combustivelapi.com.br",
"atualizado_em": "2024-01-20T10:30:00Z"
}- Registrar usuário (POST
/api/usuarios/register/) - Login (POST
/api/usuarios/login/) - Guarde o token - Testar reset de senha (POST
/api/usuarios/solicitar-reset/) - Configure email primeiro - Trocar senha (POST
/api/usuarios/trocar-senha/) - Com token válido
- Criar categoria (POST
/api/produtos/categorias/criar/) - Criar fornecedor (POST
/api/produtos/fornecedores/) - Cadastrar produto (POST
/api/produtos/cadastrar-com-categoria/) - Listar produtos (GET
/api/produtos/) - Verificar movimentações (GET
/api/produtos/movimentacoes/) - Atualizar produto (PUT
/api/produtos/{id}/atualizar/) - Alterar estoque - Verificar movimentações novamente (GET
/api/produtos/movimentacoes/)
- Criar venda (POST
/api/vendas/create/) - Listar vendas (GET
/api/vendas/) - Adicionar item à venda (POST
/api/vendas/{id}/itens/) - Atualizar item da venda (PUT
/api/vendas/{venda_id}/itens/{id}/) - Finalizar venda (POST
/api/vendas/{id}/finalizar/) - Verificar movimentações de estoque da venda (GET
/api/produtos/movimentacoes/) - Verificar estatísticas de vendas (GET
/api/vendas/estatisticas/)
- Cadastrar veículo (POST
/api/rotas/veiculos/criar/) - Listar veículos (GET
/api/rotas/veiculos/) - Atualizar veículo (PUT
/api/rotas/veiculos/{id}/atualizar/) - Testar filtros de veículos (GET
/api/rotas/veiculos/?tipo_combustivel=dieselouetanolougnv) - Obter preços de combustível (GET
/api/rotas/precos-combustivel/) - Criar rota otimizada (POST
/api/rotas/rotas/criar/) - Listar rotas (GET
/api/rotas/rotas/) - Verificar movimentações de estoque da rota (GET
/api/produtos/movimentacoes/) - Atualizar status da rota (PUT
/api/rotas/rotas/{id}/status/) - Testar filtros de rotas (GET
/api/rotas/rotas/?status=em_progresso)
- Gerar relatório (GET
/api/relatorios/conta/html/) - Exportar produtos (GET
/api/planilhas/exportar-produtos/) - Importar produtos (POST
/api/planilhas/importar-produtos/)
- Nunca commite o arquivo
DBCCREDENTIALS.env! - Eficiência de combustível: O sistema usa
eficiencia_km_l(quilômetros por litro) como padrão da indústria automotiva - Exemplo: Se um carro faz 12 km/L, significa que percorre 12 quilômetros com 1 litro de combustível
- Todos os endpoints de produtos, veículos, rotas e vendas requerem autenticação
- Código de barras deve ter exatamente 13 dígitos numéricos
- Preço de venda não pode ser menor que o preço de custo
- Categorias e fornecedores são únicos por usuário
- Fornecedores não podem ter o mesmo nome para o mesmo usuário
- Movimentações de estoque são registradas automaticamente quando o estoque é alterado
- Vendas registram movimentações de saída quando finalizadas
- Rotas registram movimentações de saída quando criadas
- Veículos, rotas e vendas são isolados por usuário (multi-tenant)
- Rotas sempre começam e terminam no endereço do usuário (origem = destino)
- Estoque é automaticamente reduzido quando uma rota é criada ou venda é finalizada
- Algoritmo de otimização usa TSP (Traveling Salesman Problem) para encontrar a melhor rota
- Vendas pendentes podem ser modificadas, vendas finalizadas não podem ser alteradas
- Apenas vendas pendentes ou canceladas podem ser excluídas
- nome
- preco_custo
- preco_venda
- estoque_minimo
- estoque_atual
Os demais campos (código de barras, descrição, data de fabricação, lote, marca, fornecedor, categoria) são opcionais.
- nome
- tipo_combustivel (diesel, gasolina, etanol ou gnv)
- eficiencia_km_l (deve ser maior que 0.01 km/L para líquidos, km/m³ para GNV)
Nota sobre eficiência:
- Combustíveis líquidos (diesel, gasolina, etanol): eficiência em km/L
- GNV: eficiência em km/m³ (quilômetros por metro cúbico)
- O sistema automaticamente detecta o tipo de combustível e aplica a unidade correta
- enderecos_destino (lista de endereços)
- produtos_quantidades (lista com produto_id e quantidade)
- nome_motorista (string, opcional)
- veiculo_id (integer, opcional - se não informado, usa veículo padrão com consumo de 8.0 km/L)
- preco_combustivel (decimal, opcional - se não informado, usa valor base do tipo de combustível)
- preco_combustivel_usado: Preço do combustível usado no cálculo da rota (R$/L ou R$/m³)
- preco_combustivel_na_geracao: Preço do combustível usado no cálculo da rota (R$/L ou R$/m³) - campo legado
- valor_rota: Custo total da rota calculado com o preço do combustível fornecido ou valor base
- distancia_total_km: Distância total da rota otimizada
- tempo_estimado_minutos: Tempo estimado para completar a rota
O sistema de rotas requer as seguintes bibliotecas Python:
- osmnx (para geocodificação e análise de redes)
- networkx (para algoritmos de grafos)
- ortools (para otimização TSP)
- requests (para APIs externas)
O sistema integra com a API combustivelapi.com.br para obter preços atualizados de combustível:
- Endpoint:
GET /api/rotas/precos-combustivel/ - Fonte: https://combustivelapi.com.br
- Fallback: Valores padrão caso a API esteja indisponível
- Mapeamento:
- Diesel (diesel, diesel_s10)
- Gasolina (gasolina_comum, gasolina_aditivada)
- Etanol (etanol)
- GNV (gnv) - em R$/m³
Ao criar uma rota, você pode especificar um preço personalizado para o combustível:
Como funciona:
- Com preço personalizado: O sistema usa o valor fornecido no campo
preco_combustivel - Sem preço personalizado: O sistema usa o valor base do tipo de combustível do veículo
Valores base (usados quando não há preço personalizado):
- Diesel: R$ 5,80/L
- Gasolina: R$ 6,36/L
- Etanol: R$ 4,20/L
- GNV: R$ 3,50/m³
Exemplo de uso:
{
"enderecos_destino": ["Rua A, 123"],
"veiculo_id": 1,
"preco_combustivel": 7.50, // Preço personalizado
"produtos_quantidades": [{"produto_id": 1, "quantidade": 2}]
}O sistema calcula o consumo de combustível de forma diferente para cada tipo:
Combustíveis Líquidos (Diesel, Gasolina, Etanol):
- Eficiência: km/L (quilômetros por litro)
- Cálculo:
litros_consumidos = distancia_total_km / eficiencia_km_l - Valor:
litros_consumidos × preco_por_litro
GNV (Gás Natural Veicular):
- Eficiência: km/m³ (quilômetros por metro cúbico)
- Cálculo:
metros_cubicos_consumidos = distancia_total_km / eficiencia_km_m3 - Valor:
metros_cubicos_consumidos × preco_por_m3
Exemplo prático:
- Veículo GNV com eficiência de 12 km/m³
- Distância de 100 km
- Preço do GNV: R$ 3,50/m³
- Consumo: 100 ÷ 12 = 8,33 m³
- Valor: 8,33 × 3,50 = R$ 29,16
Quando nenhum veículo é especificado na criação da rota:
- Consumo padrão: 8.0 km/L
- Tipo de combustível: Gasolina
- Nome exibido: "Veículo Padrão"
- Cálculo: Usa preço da gasolina atual para calcular o valor da rota
GET /api/planilhas/exportar-produtos/
- Necessário enviar o token JWT no header:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Faça login e obtenha o token de acesso.
- Crie uma requisição GET para:
http://127.0.0.1:8000/api/planilhas/exportar-produtos/ - No Postman, vá em "Headers" e adicione:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Execute a requisição.
- O Postman fará o download do arquivo
produtos.csvcontendo todos os produtos do usuário logado.
| ID | Nome | Descrição | Preço Custo | Preço Venda | Estoque Mínimo | Estoque Atual | Validade | Código Barras | Data Fabricação | Lote | Marca | Fornecedor | Categoria |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ...dados... |
- Todos os produtos exportados são filtrados por usuário (multi-tenant).
- As colunas são organizadas e compatíveis para futura importação.
POST /api/planilhas/importar-produtos/
- Necessário enviar o token JWT no header:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Faça login e obtenha o token de acesso.
- Crie uma requisição POST para:
http://127.0.0.1:8000/api/planilhas/importar-produtos/ - No Postman, vá em "Body" e selecione "form-data".
- Adicione o campo
arquivoe selecione o arquivo.csv. - Adicione o campo
fornecedor_idcom o ID do fornecedor já cadastrado.
- Adicione o campo
- No Postman, vá em "Headers" e adicione:
Authorization: Bearer SEU_ACCESS_TOKEN_AQUI
- Execute a requisição.
- O sistema irá importar todos os produtos do arquivo, associando ao fornecedor escolhido.
A planilha deve conter o cabeçalho abaixo (exatamente igual):
| Nome | Descrição | Preço Custo | Preço Venda | Estoque Mínimo | Estoque Atual | Validade | Código Barras | Data Fabricação | Lote | Marca | Categoria |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Produto A | Descrição A | 10.00 | 15.00 | 5 | 10 | 2025-12-31 | 1234567890123 | 2024-01-01 | LOTE001 | MarcaX | Alimentos |
| Produto B | Descrição B | 20.00 | 30.00 | 2 | 5 | 2025-11-30 | 9876543210987 | 2024-02-01 | LOTE002 | MarcaY | Higiene |
O campo "Categoria" pode ser preenchido com o nome da categoria desejada. Se a categoria não existir para o usuário, ela será criada automaticamente.
Os campos podem ser deixados em branco se não forem obrigatórios.
Datas devem estar no formato YYYY-MM-DD.
O fornecedor é escolhido via campo fornecedor_id no corpo da requisição.
Todos os produtos da planilha serão associados ao mesmo fornecedor.
- Se todos os produtos forem importados com sucesso:
{ "produtos_importados": ["Produto A", "Produto B"], "erros": [] } - Se houver erros em alguma linha:
{ "produtos_importados": ["Produto A"], "erros": ["Linha 3: Preço de venda não pode ser menor que o preço de custo."] }
# Carrega grafo e endereços comuns (recomendado)
python manage.py precarregar_maceio
# Apenas o grafo (raio padrão: 15km)
python manage.py precarregar_maceio --apenas-grafo --raio 20
# Apenas endereços comuns
python manage.py precarregar_maceio --apenas-enderecos
# Ver estatísticas do cache
python manage.py precarregar_maceio --estatisticas
# Limpar cache existente antes de carregar
python manage.py precarregar_maceio --limpar-cache# Ver estatísticas do cache
GET /api/rotas/cache-maceio/stats/
# Pré-carregar cache
POST /api/rotas/cache-maceio/preload/
{
"raio_km": 15,
"apenas_grafo": false,
"apenas_enderecos": false
}
# Limpar cache
POST /api/rotas/cache-maceio/clear/