Cálculo de Preço e Ganhos
Documentação da fórmula de cálculo de ganhos do motorista, configuração de preços e exemplos práticos.
Fórmula de Ganhos
Equivalente Python (implementado em backend/app/schemas/pricing.py):
from decimal import Decimal
def calculate_driver_earning(distance_km: Decimal, config: PricingConfigOut) -> Decimal:
if distance_km <= config.min_km:
return config.base_fare
extra_km = distance_km - config.min_km
return config.base_fare + (extra_km * config.price_per_km)
Parâmetros da Configuração
| Parâmetro | Tipo | Descrição |
|---|---|---|
base_fare |
Decimal (numeric 10,2) | Valor mínimo pago ao motorista, independente da distância |
min_km |
Decimal (numeric 5,2) | Quilômetros incluídos no base_fare (sem custo adicional) |
price_per_km |
Decimal (numeric 10,2) | Valor adicional por km percorrido acima do min_km |
Configuração padrão (inserida no schema):
| Parâmetro | Valor |
|---|---|
base_fare |
R$ 15,00 |
min_km |
5 km |
price_per_km |
R$ 2,00/km |
Exemplos de Cálculo
Exemplo 1 — Rota Curta (abaixo do mínimo)
Distância: 3 km
base_fare = R$ 15,00
min_km = 5 km
price_per_km = R$ 2,00
Cálculo:
distance_km (3) <= min_km (5)
ganho = base_fare = R$ 15,00
O driver recebe a tarifa base completa mesmo em rotas curtas.
Exemplo 2 — Rota Exatamente no Mínimo
Distância: 5 km
base_fare = R$ 15,00
min_km = 5 km
price_per_km = R$ 2,00
Cálculo:
distance_km (5) <= min_km (5)
ganho = base_fare = R$ 15,00
O km mínimo é inclusivo — 5 km exatos não gera custo adicional.
Exemplo 3 — Rota Longa (acima do mínimo)
Distância: 12 km
base_fare = R$ 15,00
min_km = 5 km
price_per_km = R$ 2,00
Cálculo:
extra_km = 12 - 5 = 7 km
ganho = 15,00 + (7 × 2,00) = 15,00 + 14,00 = R$ 29,00
Exemplo 4 — Rota Muito Longa
Distância: 25 km
base_fare = R$ 15,00
min_km = 5 km
price_per_km = R$ 2,00
Cálculo:
extra_km = 25 - 5 = 20 km
ganho = 15,00 + (20 × 2,00) = 15,00 + 40,00 = R$ 55,00
Tabela de Referência Rápida
| Distância | Ganho do Driver (config padrão) |
|---|---|
| 1 km | R$ 15,00 |
| 3 km | R$ 15,00 |
| 5 km | R$ 15,00 |
| 6 km | R$ 17,00 |
| 8 km | R$ 21,00 |
| 10 km | R$ 25,00 |
| 15 km | R$ 35,00 |
| 20 km | R$ 45,00 |
| 30 km | R$ 65,00 |
Margem da Empresa
Quando o admin informa client_value ao criar a entrega, o sistema calcula automaticamente:
Exemplo:
O company_profit pode ser negativo se o client_value for menor que o driver_earning — isso é permitido pelo sistema mas é um alerta para o admin.
Snapshot de Preços por Entrega
Os valores de base_fare, price_per_km e min_km são copiados para cada entrega no momento da criação:
row = {
"base_fare": str(config.base_fare),
"price_per_km": str(config.price_per_km),
"min_km": str(config.min_km),
"driver_earning": str(driver_earning),
...
}
Isso garante que alterações futuras na pricing_config não afetam entregas já criadas.
Gestão da Configuração de Preços
Obter configuração atual
Atualizar configuração
curl -X PUT http://localhost:8000/api/v1/pricing \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"base_fare": 18.00,
"price_per_km": 2.50,
"min_km": 5.00
}'
Cada PUT insere uma nova linha em pricing_config (histórico completo).
Precisão Financeira
Sempre use Decimal, nunca float
# CORRETO
from decimal import Decimal
earning = Decimal("15.00") + extra_km * Decimal("2.00")
# ERRADO — pode causar erros de arredondamento
earning = 15.0 + extra_km * 2.0
O banco armazena como numeric(10,2), que é exato.
Python float usa ponto flutuante IEEE 754 e pode ter imprecisões:
Cálculo de Rota (ORS)
A distância (distance_km) é calculada pelo OpenRouteService usando o perfil driving-car:
# backend/app/services/routing.py
async def calculate_route(...) -> tuple[Decimal, str | None]:
url = f"{ORS_BASE}/v2/directions/driving-car"
body = {
"coordinates": [
[float(origin_lng), float(origin_lat)], # ORS: [lng, lat]
[float(dest_lng), float(dest_lat)],
],
"units": "km",
}
# ...
distance_km = Decimal(str(round(summary["distance"], 2)))
return distance_km, geometry
A distância é a distância de rota real (não linha reta), arredondada a 2 casas decimais.