testes/Modulos Angular/projects/idt_app/docs/router/generate_routes_data.py

431 lines
17 KiB
Python

#!/usr/bin/env python3
"""
Script para gerar 500 dados mockados de rotas para o ERP SAAS PraFrota
Baseado nas especificações da documentação técnica
"""
import json
import random
from datetime import datetime, timedelta
from typing import List, Dict, Any
# Dados reais extraídos do CSV
REAL_PLATES = [
"TAS4J92", "MSO5821", "TAS2F98", "RJZ7H79", "TAO3J98",
"TAN6I73", "SGD4H03", "NGF2A53", "TAS2F32", "RTT1B46",
"EZQ2E60", "TDZ4J93", "SGL8D98", "TAS2F83", "RVC0J58",
"EYP4H76", "FVV7660", "RUN2B51", "RUQ9D16", "TAS5A49",
"RUN2B49", "SHX0J21", "FHT5D54", "SVG0I32", "RUN2B50",
"FYU9G72", "TAS4J93", "SRZ9B83", "TAQ4G32", "RUP2B50",
"SRG6H41", "SQX8J75", "TAS4J96", "RTT1B44", "RTM9F10",
"FLE2F99", "RUN2B63", "RVC0J65", "RUN2B52", "TUE1A37",
"RUP4H86", "RUP4H94", "RUN2B48", "SVF4I52", "STL5A43",
"TAS2J46", "TAO3I97", "TAS5A46", "SUT1B94", "LUJ7E05",
"SST4C72", "SRH6C66", "TAO6E76", "RUN2B55", "RVC8B13",
"SVF2E84", "SRO2J16", "RVT2J97", "RUN2B58", "SHB4B37",
"IWB9C17", "FJE7I82", "TAQ4G22", "SGJ9F81", "SVP9H73",
"OVM5B05", "TAO3J94", "RUP2B56", "TAO4F04", "RUN2B64",
"GGL2J42", "SRN7H36", "SFM8D30", "TAO6E80", "SVK8G96",
"SIA7J06", "TAR3E11", "RVC0J64", "RJW6G71", "SSV6C52",
"RUN2B54", "TAN6I66", "SPA0001", "SVH9G53", "RUN2B62",
"RVC0J85", "TAR3D02", "RVC4G70", "RUP4H92", "RUN2B56",
"SGL8F08", "TAO3J93", "LUC4H25", "TAN6H93", "TAQ4G30",
"RUP4H87", "SHB4B36", "SGC2B17", "RVC0J70", "SVL1G82",
"RVC0J63", "RVT2J98", "SPA0001", "RVT4F18", "TAR3C45",
"TAO4E80", "TAN6I62", "SHB4B38", "RTO9B22", "RJE8B51",
"TAO4F02", "SGJ9G23", "SRU2H94", "RTT1B48", "TAN6I69",
"RUP2B49", "RUW9C02", "RUP4H91", "RVC0J74", "TAN6H99",
"FZG8F72", "RUP4H88", "TAS2E35", "RUN2B60", "RTO9B84",
"GHM7A76", "RTM9F11", "TAN6H97", "SQX9G04", "RVU9160",
"SGL8E65", "RTT1B43", "TAO4F05", "TOG3H62", "TAS5A47",
"TAQ6J50", "SRH4E56", "NSZ5318", "RUN2B53", "TAO3J97",
"SGL8E73", "SHX0J22", "SFP6G82", "SRZ9C22", "RTT1B45",
"TAN6163", "LTO7G84", "SGL8D26", "TAN6I59", "TAO4E89",
"TAO4E90", "TAS2J51", "SGL8F81", "RTM9F14", "FKP9A34",
"TAS2J45", "QUS3C30", "GDM8I81", "TAQ4G36", "RVC0J59",
"TAS5A44", "RUN2B61", "RVC4G71", "TAS4J95", "TAQ4G37",
"SPA0001", "RTB7E19", "TAS2E31", "RUP4H81", "SGD9A92",
"RJF7I82", "EVU9280", "SPA0001", "SSC1E94", "TAR3E21",
"TAN6I71", "TAS4J92", "TAN6I57", "TAO4F90", "SGJ2F13",
"SGJ2D96", "SGJ2G40", "TAR3E14", "KRQ9A48", "RUP2B53",
"SRN5C38", "SGJ2G98", "SRA7J03", "RIU1G19", "EUQ4159",
"SRH5C60", "SSB6H85", "SRN6F73", "SRY4B65", "SGL8C62",
"STU7F45", "SGJ9G45", "RVT4F19"
]
PRODUCT_TYPES = [
"Medicamentos", "Eletrônicos", "Alimentos Perecíveis", "Alimentos Não Perecíveis",
"Roupas e Acessórios", "Livros e Papelaria", "Casa e Decoração",
"Cosméticos", "Automotive", "Brinquedos"
]
MARKETPLACES = ["Mercado Livre", "Shopee", "Amazon"]
# Coordenadas das regiões
REGIONS = {
"rioDeJaneiro": {
"center": {"lat": -22.9068, "lng": -43.1729},
"bounds": {"north": -22.7000, "south": -23.1000, "east": -43.0000, "west": -43.8000},
"addresses": [
"Rua das Flores, 123 - Copacabana, Rio de Janeiro - RJ",
"Av. Atlântica, 456 - Ipanema, Rio de Janeiro - RJ",
"Rua Barata Ribeiro, 789 - Copacabana, Rio de Janeiro - RJ",
"Av. Nossa Senhora de Copacabana, 321 - Copacabana, Rio de Janeiro - RJ",
"Rua Visconde de Pirajá, 654 - Ipanema, Rio de Janeiro - RJ",
"Av. Rio Branco, 987 - Centro, Rio de Janeiro - RJ",
"Rua da Carioca, 147 - Centro, Rio de Janeiro - RJ",
"Av. Presidente Vargas, 258 - Centro, Rio de Janeiro - RJ",
"Rua Santa Clara, 369 - Copacabana, Rio de Janeiro - RJ",
"Av. Princesa Isabel, 741 - Copacabana, Rio de Janeiro - RJ"
]
},
"saoPaulo": {
"center": {"lat": -23.5505, "lng": -46.6333},
"bounds": {"north": -23.3000, "south": -23.8000, "east": -46.3000, "west": -47.0000},
"addresses": [
"Av. Paulista, 1578 - Bela Vista, São Paulo - SP",
"Rua Augusta, 1000 - Consolação, São Paulo - SP",
"Av. Faria Lima, 2000 - Pinheiros, São Paulo - SP",
"Rua Oscar Freire, 500 - Jardins, São Paulo - SP",
"Av. Rebouças, 3000 - Pinheiros, São Paulo - SP",
"Rua da Consolação, 1200 - Consolação, São Paulo - SP",
"Av. Brigadeiro Faria Lima, 1500 - Jardim Paulistano, São Paulo - SP",
"Rua Haddock Lobo, 800 - Cerqueira César, São Paulo - SP",
"Av. Nove de Julho, 2500 - Jardim Paulista, São Paulo - SP",
"Rua Estados Unidos, 600 - Jardim América, São Paulo - SP"
]
},
"minasGerais": {
"center": {"lat": -19.9167, "lng": -43.9345},
"bounds": {"north": -19.7000, "south": -20.2000, "east": -43.7000, "west": -44.2000},
"addresses": [
"Av. Afonso Pena, 1000 - Centro, Belo Horizonte - MG",
"Rua da Bahia, 500 - Centro, Belo Horizonte - MG",
"Av. do Contorno, 2000 - Santa Efigênia, Belo Horizonte - MG",
"Rua Rio de Janeiro, 800 - Centro, Belo Horizonte - MG",
"Av. Amazonas, 1500 - Centro, Belo Horizonte - MG",
"Rua Curitiba, 300 - Centro, Belo Horizonte - MG",
"Av. Brasil, 2500 - Santa Efigênia, Belo Horizonte - MG",
"Rua Tupis, 600 - Centro, Belo Horizonte - MG",
"Av. Francisco Sales, 1200 - Santa Efigênia, Belo Horizonte - MG",
"Rua Espírito Santo, 400 - Centro, Belo Horizonte - MG"
]
},
"vitoria": {
"center": {"lat": -20.2976, "lng": -40.2958},
"bounds": {"north": -20.1000, "south": -20.5000, "east": -40.1000, "west": -40.5000},
"addresses": [
"Av. Princesa Isabel, 500 - Centro, Vitória - ES",
"Rua Sete de Setembro, 200 - Centro, Vitória - ES",
"Av. Jerônimo Monteiro, 800 - Centro, Vitória - ES",
"Rua do Comércio, 300 - Centro, Vitória - ES",
"Av. Marechal Mascarenhas de Moraes, 1000 - Bento Ferreira, Vitória - ES",
"Rua General Osório, 150 - Centro, Vitória - ES",
"Av. Nossa Senhora da Penha, 600 - Santa Lúcia, Vitória - ES",
"Rua Chapot Presvot, 400 - Praia do Canto, Vitória - ES",
"Av. Saturnino de Brito, 900 - Praia do Canto, Vitória - ES",
"Rua Joaquim Lírio, 250 - Praia do Canto, Vitória - ES"
]
}
}
# Nomes fictícios
FIRST_NAMES = [
"João", "Maria", "José", "Ana", "Carlos", "Fernanda", "Pedro", "Juliana",
"Roberto", "Mariana", "Ricardo", "Camila", "Marcos", "Patrícia", "André",
"Luciana", "Fernando", "Carla", "Rafael", "Daniela", "Paulo", "Renata",
"Gustavo", "Vanessa", "Bruno", "Cristina", "Diego", "Tatiana", "Felipe",
"Amanda", "Rodrigo", "Priscila", "Thiago", "Natália", "Leonardo", "Bianca"
]
LAST_NAMES = [
"Silva", "Santos", "Oliveira", "Souza", "Rodrigues", "Ferreira", "Alves",
"Pereira", "Lima", "Gomes", "Costa", "Ribeiro", "Martins", "Carvalho",
"Almeida", "Lopes", "Soares", "Fernandes", "Vieira", "Barbosa", "Rocha",
"Dias", "Monteiro", "Cardoso", "Reis", "Araújo", "Moreira", "Freitas",
"Mendes", "Ramos", "Castro", "Pinto", "Teixeira", "Correia", "Machado"
]
def generate_random_name():
"""Gera um nome aleatório"""
return f"{random.choice(FIRST_NAMES)} {random.choice(LAST_NAMES)}"
def generate_phone(area_code):
"""Gera um telefone aleatório"""
return f"+55 {area_code} {random.randint(90000, 99999)}-{random.randint(1000, 9999)}"
def generate_coordinates_in_region(region_name):
"""Gera coordenadas aleatórias dentro de uma região"""
region = REGIONS[region_name]
bounds = region["bounds"]
lat = random.uniform(bounds["south"], bounds["north"])
lng = random.uniform(bounds["west"], bounds["east"])
return {"lat": round(lat, 6), "lng": round(lng, 6)}
def generate_route_data(route_id: int, route_type: str, region: str) -> Dict[str, Any]:
"""Gera dados de uma rota específica"""
# Definir códigos de área por região
area_codes = {
"rioDeJaneiro": "21",
"saoPaulo": "11",
"minasGerais": "31",
"vitoria": "27"
}
area_code = area_codes[region]
# Gerar coordenadas
origin_coords = generate_coordinates_in_region(region)
dest_coords = generate_coordinates_in_region(region)
# Selecionar endereços
addresses = REGIONS[region]["addresses"]
origin_address = random.choice(addresses)
dest_address = random.choice(addresses)
# Para lastMile, usar endereços residenciais
if route_type == "lastMile":
marketplace = random.choice(MARKETPLACES)
origin_address = f"Hub {marketplace} - {region.title()}"
dest_address = random.choice(addresses) # Endereço residencial
# Definir modal baseado no tipo
if route_type == "lineHaul":
modal_choices = ["rodoviario", "aereo", "aquaviario"]
modal_weights = [0.8, 0.15, 0.05]
else:
modal_choices = ["rodoviario"]
modal_weights = [1.0]
modal = random.choices(modal_choices, weights=modal_weights)[0]
# Definir prioridade
priority = random.choices(
["normal", "express", "urgent"],
weights=[0.7, 0.2, 0.1]
)[0]
# Definir status
status = random.choices(
["pending", "inProgress", "completed", "delayed", "cancelled"],
weights=[0.1, 0.4, 0.35, 0.1, 0.05]
)[0]
# Definir valores baseados no tipo
if route_type == "lastMile":
total_value = round(random.uniform(25.0, 150.0), 2)
total_weight = round(random.uniform(0.5, 15.0), 1)
estimated_cost = round(total_value * 0.4, 2)
elif route_type == "lineHaul":
total_value = round(random.uniform(1500.0, 5000.0), 2)
total_weight = round(random.uniform(5000.0, 15000.0), 1)
estimated_cost = round(total_value * 0.35, 2)
else: # firstMile
total_value = round(random.uniform(300.0, 2000.0), 2)
total_weight = round(random.uniform(500.0, 5000.0), 1)
estimated_cost = round(total_value * 0.45, 2)
# Datas
base_date = datetime.now() - timedelta(days=random.randint(0, 30))
scheduled_departure = base_date
# Definir datas baseadas no status
actual_departure = None
estimated_arrival = scheduled_departure + timedelta(hours=random.randint(2, 12))
actual_arrival = None
current_location = None
actual_cost = None
if status in ["inProgress", "completed", "delayed"]:
actual_departure = scheduled_departure + timedelta(minutes=random.randint(-30, 60))
if status == "completed":
actual_arrival = estimated_arrival + timedelta(minutes=random.randint(-60, 120))
current_location = dest_coords
actual_cost = round(estimated_cost * random.uniform(0.8, 1.3), 2)
elif status == "inProgress":
# Posição entre origem e destino
progress = random.uniform(0.2, 0.8)
current_location = {
"lat": round(origin_coords["lat"] + (dest_coords["lat"] - origin_coords["lat"]) * progress, 6),
"lng": round(origin_coords["lng"] + (dest_coords["lng"] - origin_coords["lng"]) * progress, 6)
}
# Produto tipo
product_type = random.choice(PRODUCT_TYPES)
# Placa do veículo
vehicle_plate = random.choice(REAL_PLATES)
return {
"id": f"rt_{route_id:03d}",
"routeNumber": f"RT-2024-{route_id:06d}",
"type": route_type,
"modal": modal,
"priority": priority,
"driverId": f"drv_{route_id:03d}",
"vehicleId": f"veh_{route_id:03d}",
"companyId": "comp_001",
"customerId": f"cust_{route_id:03d}",
"origin": {
"address": origin_address,
"coordinates": origin_coords,
"contact": generate_random_name(),
"phone": generate_phone(area_code)
},
"destination": {
"address": dest_address,
"coordinates": dest_coords,
"contact": generate_random_name(),
"phone": generate_phone(area_code)
},
"scheduledDeparture": scheduled_departure.isoformat() + "Z",
"actualDeparture": actual_departure.isoformat() + "Z" if actual_departure else None,
"estimatedArrival": estimated_arrival.isoformat() + "Z",
"actualArrival": actual_arrival.isoformat() + "Z" if actual_arrival else None,
"status": status,
"currentLocation": current_location,
"contractId": f"cont_{route_id:03d}",
"tablePricesId": f"tbl_{route_id:03d}",
"totalValue": total_value,
"totalWeight": total_weight,
"estimatedCost": estimated_cost,
"actualCost": actual_cost,
"productType": product_type,
"createdAt": (base_date - timedelta(hours=random.randint(1, 48))).isoformat() + "Z",
"updatedAt": (base_date + timedelta(minutes=random.randint(0, 300))).isoformat() + "Z",
"createdBy": f"user_{random.randint(1, 10):03d}",
"vehiclePlate": vehicle_plate
}
def generate_all_routes():
"""Gera todas as 500 rotas"""
routes = []
route_id = 1
# Distribuição por tipo (conforme especificação)
type_distribution = [
("firstMile", 300),
("lineHaul", 125),
("lastMile", 75)
]
# Distribuição por região
region_distribution = [
("saoPaulo", 175),
("rioDeJaneiro", 150),
("minasGerais", 125),
("vitoria", 50)
]
# Calcular rotas por tipo e região
total_routes_per_region = {region: count for region, count in region_distribution}
for route_type, type_count in type_distribution:
# Distribuir este tipo pelas regiões proporcionalmente
for region, region_total in region_distribution:
region_proportion = region_total / 500
routes_for_this_type_region = int(type_count * region_proportion)
for _ in range(routes_for_this_type_region):
if route_id <= 500:
route = generate_route_data(route_id, route_type, region)
routes.append(route)
route_id += 1
# Completar até 500 se necessário
while len(routes) < 500:
remaining_type = random.choice(["firstMile", "lineHaul", "lastMile"])
remaining_region = random.choice(["saoPaulo", "rioDeJaneiro", "minasGerais", "vitoria"])
route = generate_route_data(route_id, remaining_type, remaining_region)
routes.append(route)
route_id += 1
return routes[:500] # Garantir exatamente 500
def main():
"""Função principal"""
print("Gerando 500 rotas mockadas...")
routes = generate_all_routes()
# Calcular estatísticas reais
type_stats = {}
status_stats = {}
region_stats = {}
for route in routes:
# Tipo
route_type = route["type"]
type_stats[route_type] = type_stats.get(route_type, 0) + 1
# Status
status = route["status"]
status_stats[status] = status_stats.get(status, 0) + 1
# Região (baseado no telefone)
phone = route["origin"]["phone"]
if "11" in phone:
region = "saoPaulo"
elif "21" in phone:
region = "rioDeJaneiro"
elif "31" in phone:
region = "minasGerais"
else:
region = "vitoria"
region_stats[region] = region_stats.get(region, 0) + 1
# Estrutura final
data = {
"routes": routes,
"metadata": {
"totalRoutes": len(routes),
"generatedAt": datetime.now().isoformat() + "Z",
"version": "1.0",
"description": "Dados mockados para o módulo de Rotas do ERP SAAS PraFrota",
"actualDistributions": {
"byType": type_stats,
"byStatus": status_stats,
"byRegion": region_stats
},
"specifications": {
"byType": {
"firstMile": "60% (300 rotas) - Coleta em centros de distribuição",
"lineHaul": "25% (125 rotas) - Transporte entre cidades",
"lastMile": "15% (75 rotas) - Entrega final (Mercado Livre, Shopee, Amazon)"
},
"byModal": {
"rodoviario": "95% (475 rotas)",
"aereo": "3% (15 rotas)",
"aquaviario": "2% (10 rotas)"
},
"regions": {
"rioDeJaneiro": "30% (150 rotas)",
"saoPaulo": "35% (175 rotas)",
"minasGerais": "25% (125 rotas)",
"vitoria": "10% (50 rotas)"
}
},
"realVehiclePlates": REAL_PLATES,
"productTypes": PRODUCT_TYPES,
"lastMileMarketplaces": MARKETPLACES,
"coordinates": REGIONS
}
}
# Salvar arquivo
output_file = "ROUTES_MOCK_DATA_COMPLETE.json"
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"✅ Arquivo {output_file} gerado com sucesso!")
print(f"📊 Estatísticas:")
print(f" Total de rotas: {len(routes)}")
print(f" Por tipo: {type_stats}")
print(f" Por status: {status_stats}")
print(f" Por região: {region_stats}")
if __name__ == "__main__":
main()