Skip to content

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

ganho = base_fare + max(0, distance_km - min_km) × price_per_km

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:

company_profit = client_value - driver_earning

Exemplo:

client_value = R$ 40,00
driver_earning = R$ 29,00
company_profit = R$ 11,00

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

curl http://localhost:8000/api/v1/pricing \
  -H "Authorization: Bearer $ADMIN_TOKEN"

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:

>>> 0.1 + 0.2
0.30000000000000004  # ← problema real com float


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.