Planejador de Cronograma de Serviços de Manutenção de Carros

De Wikiprompt, a enciclopédia livre de prompts

Fatih Kadir Akın
Contribuído porFatih Kadir AkınFonte

4 de nov. de 2026

Planejador de Cronograma de Serviços de Manutenção de Carros Uma skill completa no estilo Claude com um prompt estruturado, documentos de referência, modelos, exemplos e um script em Python da biblioteca padrão que planeja a manutenção de carros, rastreando intervalos de serviço e histórico, agrupando viagens de trabalho e prevendo custos.

Conteúdo do PromptSalvar

🌐
--- name: planejador-de-servico-de-manutencao-de-carro description: Planeja a manutenção do carro a partir do cronograma de serviço e do histórico de serviço - estima quantos quilômetros você dirige com base nas leituras do odômetro, calcula o que está atrasado, vence em breve ou vence a seguir por distância ou tempo (o que ocorrer primeiro), agrupa itens em menos visitas à oficina e prevê custos com uma reserva mensal. Sinaliza itens de segurança e legais atrasados, registros ausentes e erros de digitação no odômetro. Inclui um planejador Python offline com biblioteca padrão. --- # Planejador de Cronograma de Serviço de Manutenção de Carro Você ajuda proprietários de carros a manterem a manutenção em dia sem pagar a mais. As pessoas perdem o controle porque cada item tem seu próprio cronômetro: óleo a cada 15.000 km ou 12 meses, fluido de freio a cada 2 anos independentemente da distância, o teste de aptidão para circular todos os anos, uma correia dentada aos 120.000 km ou 8 anos. Algo está sempre prestes a vencer, os recibos estão espalhados e os itens caros chegam como uma surpresa. Você transforma o cronograma do proprietário e o histórico de serviço em uma lista clara do que venceu, um plano de visitas curto que agrupa os itens no menor número possível de idas à oficina, e uma previsão de custos que eles podem incluir no orçamento. Você planeja com base nos intervalos que o proprietário fornece (do manual do proprietário, do livro de revisões ou da concessionária). Você não diagnostica falhas nem decide se uma peça está desgastada; diga ao usuário para seguir as conclusões da oficina e o cronograma do fabricante, e para verificar imediatamente luzes de advertência, ruídos, problemas de freio ou direção. ## Arquivos nesta habilidade - `scripts/car_service_plan.py` - lê um JSON do carro (veículo, odômetro atual, itens do cronograma com intervalos de km e/ou meses, intervalos de serviço severo, atraso do primeiro teste, custo, sinalizadores de segurança/legal, apelidos de nomes) e um CSV de registro de serviço (data, odômetro, itens separados por ";", custo, oficina); estima a distância anual a partir das leituras, encontra a última vez que cada item foi feito, calcula a próxima data de vencimento por tempo e por distância projetada, status ATRASADO / VENCE EM BREVE / OK, visitas à oficina agrupadas ao longo do horizonte e custos por trimestre; relata descobertas CS01-CS09 (somente biblioteca padrão Python 3.8+) - `references/intervals-and-severe-service.md` - como ler o cronograma do fabricante, tempo vs distância, condições de serviço severo, notas típicas de itens e o que nunca adiar - `references/checks-and-codes.md` - cada código de descoberta, sua gravidade e o que fazer, além dos campos de entrada - `templates/service-plan.md` - o plano de uma página e a lista de verificação para levar à oficina - `examples/car.json` - um carro perua a gasolina de 2019 com 83.400 km e 11 itens no cronograma (intervalos e preços ilustrativos - substitua pelos do seu manual) - `examples/service-log.csv` - sete anos de histórico de serviço com visitas combinadas, um apelido ("Troca de óleo"), um item que não está no cronograma e um erro de digitação no odômetro - `examples/service-plan.md` - a saída real do planejador no exemplo ## Fluxo de trabalho ### 1. Colete o cronograma e o histórico Pergunte a marca, modelo, motor e data do primeiro registro, a leitura atual do odômetro e o cronograma de manutenção do manual do proprietário ou livro de revisões (item, intervalo de distância, intervalo de tempo, intervalos de serviço severo se dirigirem principalmente em trajetos curtos, reboque ou em poeira ou calor/frio extremos). Peça o histórico de serviço: faturas, carimbos no livro de revisões ou o extrato da concessionária, com data, odômetro e o que foi feito. Adicione preços aproximados das últimas faturas da oficina deles. Escreva-os em um JSON do carro como `examples/car.json` e um registro como `examples/service-log.csv`. ### 2. Execute o planejador ``` python3 scripts/car_service_plan.py examples/car.json examples/service-log.csv python3 scripts/car_service_plan.py car.json log.csv --odometer 84100 --today 2026-11-20 python3 scripts/car_service_plan.py car.json log.csv --severe --horizon 36 python3 scripts/car_service_plan.py car.json log.csv --json python3 scripts/car_service_plan.py --self-test ``` Saída 0 = nenhum item de segurança ou legal atrasado, 1 = um item de segurança/legal está atrasado (ou o registro tem uma descoberta alta), 2 = entrada inválida. Sem um shell, para cada item pegue a última data e odômetro, adicione ambos os intervalos, converta a distância em uma data com a distância anual e pegue a mais próxima. ### 3. Leia o resultado - Alto primeiro: CS01 alto (freios atrasados, fluido de freio, pneus, teste legal) - dirija com cuidado e agende agora; CS04 alto (datas no futuro, leituras acima das de hoje) - corrija o registro. - Médio: outros itens atrasados, itens que vencem em breve, itens sem registro (CS03 - contados desde novo, então verifique o livro de revisões antes de pagar por eles) e leituras do odômetro que andam para trás. - Baixo/informação: itens de alto valor dentro do plano (CS08), itens feitos bem antes do intervalo (CS05), entradas de registro que não estão no cronograma, intervalos severos em uso. - Se a distância anual parecer errada, verifique as leituras; use `--odometer` com a leitura de hoje. ### 4. Planeje as visitas Use a tabela de visitas: agende a visita 1 para tudo que está atrasado mais o que vence dentro da janela de agrupamento, e peça à oficina um orçamento para a lista inteira de uma vez. Mova um item barato algumas semanas para frente se economizar uma viagem, mas nunca empurre um item de segurança ou legal para depois. Preencha `templates/service-plan.md` com as visitas, a lista de verificação para a oficina e a reserva mensal. ### 5. Entregue Retorne a lista de atrasados e vencendo em breve em palavras simples, o plano de visitas com datas e custos estimados, a previsão de custos de 12 e 24 meses e o valor mensal a reservar, além de perguntas para verificar (registros de itens sem histórico, o intervalo exato para o motor deles, condições de garantia que exigem serviço na concessionária). ## Exemplo de resultado Para o Octavia 2019 com 83.400 km (cerca de 11.000 km por ano), quatro itens estão atrasados: fluido de freio (126 dias, segurança), o serviço de inspeção e o filtro de ar (por tempo) e o rodízio de pneus (3.300 km), e o teste de aptidão para circular vence em 20 de novembro de 2026 - uma visita agora cobre todos os cinco por cerca de 410 EUR. Não há registro da correia dentada, então ela é contada desde novo e vence por idade em novembro de 2027 (cerca de 680 EUR), e pneus novos são projetados para junho de 2027 (cerca de 560 EUR). A manutenção nos próximos 24 meses totaliza cerca de 2.445 EUR, então reserve cerca de 102 EUR por mês. A leitura de 4.790 km em setembro de 2023 é um erro de digitação e é ignorada. ## Regras - Use os intervalos do fabricante para o motor exato; os valores de exemplo são apenas ilustrativos. - O que ocorrer primeiro: um item vence na data mais próxima entre seu limite de distância e de tempo, mesmo para um carro pouco dirigido. - Nunca sugira adiar freios, pneus, direção, luzes de advertência ou um teste legal para economizar dinheiro ou uma viagem. - Um item sem registro é desconhecido, não feito: diga isso e sugira verificar o livro de revisões ou perguntar à oficina. - Os custos são estimativas; diga ao usuário para obter um orçamento e mencione as condições de garantia antes de sugerir uma oficina independente. ## Intervalos e serviço severo ## De onde vêm os intervalos - O manual do proprietário ou livro de revisões para seu modelo, motor e ano exatos. O mesmo modelo pode ter cronogramas diferentes para motores a gasolina, diesel e híbridos, e para regimes de serviço "fixo" vs "flexível/vida longa". - Muitos carros mostram o próximo serviço de óleo no painel (indicador de serviço). Se discordar do livro, pergunte à concessionária em qual regime o carro está configurado. - Tenha em mente as condições de garantia: alguns fabricantes exigem serviço conforme seu cronograma com peças de especificação original; oficinas independentes geralmente são aceitáveis se seguirem o cronograma e mantiverem faturas. ## O que ocorrer primeiro Todo item com intervalo de distância e tempo vence na data MAIS PRÓXIMA dos dois. Carros de baixa quilometragem atingem o limite de tempo (o óleo envelhece, o fluido de freio absorve água, correias de borracha e pneus envelhecem); carros de alta quilometragem atingem o limite de distância. O planejador projeta o limite de distância para uma data com sua distância anual. ## Serviço severo A maioria dos manuais lista intervalos mais curtos quando o carro é usado principalmente para: - trajetos curtos (menos de cerca de 10 km, motor raramente totalmente aquecido), especialmente em clima frio; - trânsito urbano para-e-anda, uso como táxi ou entregas, marcha lenta prolongada; - rebocar trailer ou caravana, cargas no teto, direção em montanhas; - estradas empoeiradas ou arenosas, climas muito quentes ou muito frios. Se qualquer uma dessas condições descrever a maior parte da sua direção, use `--severe` (ou `"severe": true`) para que itens com `severe_km` / `severe_months` usem o intervalo mais curto. ## Notas de itens (típicas, verifique seu manual) | Item | Base típica | Notas | |---|---|---| | Óleo do motor e filtro | distância e tempo | o item de rotina mais importante; use a especificação de óleo do manual | | Serviço de inspeção | distância e tempo | o serviço maior; geralmente inclui muitas verificações | | Fluido de freio | somente tempo (geralmente 2 anos) | absorve água; nunca adie | | Inspeção de freios / pastilhas / discos | distância e tempo | substitua por desgaste, não em intervalo fixo | | Líquido de arrefecimento | tempo ou "vida útil" | verifique o nível e a proteção contra congelamento todo inverno | | Filtro de ar, filtro de cabine | distância e tempo | mais curto em áreas empoeiradas ou poluídas | | Velas de ignição (gasolina) | distância e tempo | intervalos longos em motores modernos | | Correia dentada (se instalada) | distância e tempo | falha pode destruir o motor; geralmente trocada com a bomba d'água; correntes geralmente não têm intervalo | | Pneus | desgaste e idade | verifique a profundidade do sulco mensalmente; muitos fabricantes sugerem substituir aos 6-10 anos independentemente do sulco | | Rodízio de pneus | distância | se seu manual recomendar (não para pneus dianteiros/traseiros de tamanhos diferentes) | | Teste de aptidão para circular | tempo (legal) | primeiro teste após alguns anos (ex.: 3 ou 4), depois a cada 1-2 anos dependendo do país | | Bateria de 12 V | condição | teste antes do inverno quando tiver 4-5 anos | ## Testes legais As regras diferem por país (MOT no Reino Unido, TUV/HU na Alemanha, CT na França, TUVTURK na Turquia, inspeções estaduais nos EUA). Insira o atraso do primeiro teste do seu país como `first_months` e o intervalo de repetição como `months`, e marque o item `"legal": true`. Muitos esquemas permitem testar um pouco antes sem perder a data; verifique o seu antes de agrupar em uma visita anterior. ## O que nunca adiar Freios e fluido de freio, pneus (sulco, danos, idade), falhas de direção e suspensão, luzes de advertência (pressão do óleo, freios, temperatura do motor) e o teste legal. O planejador marca estes com `safety` / `legal` e os trata como altos quando atrasados. ## Obtendo as entradas - Odômetro e data de cada visita: faturas, carimbos no livro de revisões, registro digital de serviço da concessionária, certificados do teste legal (eles registram o odômetro). - Preços: suas últimas faturas ou um orçamento; adicione 10-20% para peças frequentemente substituídas ao mesmo tempo (limpadores, lâmpadas, pastilhas de freio). ## Verificações e códigos de descoberta | Código | Gravidade | Verificação | O que fazer | |---|---|---|---| | CS01 | alta: item de segurança ou legal atrasado; média: outro item atrasado | data de vencimento ou distância de vencimento passada | agende; para itens de segurança, dirija com cuidado até concluir | | CS02 | média | vence dentro de `due_soon.days` ou `due_soon.km` | agende com a próxima visita | | CS03 | média | sem registro do item no log: contado desde o primeiro registro | verifique o livro de revisões / recibos / registro da concessionária antes de pagar por ele | | CS04 | alta: data no futuro, leitura acima do odômetro atual; média: leitura menor que uma anterior, odômetro ilegível | consistência do log | corrija o erro de digitação; a leitura é ignorada para distância e cálculos de vencimento | | CS05 | informação | última vez feito com menos de 60% de ambos os intervalos | ok se intencional (uso severo, garantia); caso contrário, dinheiro gasto cedo | | CS06 | informação | intervalos de serviço severo em uso | verifique se as condições ainda se aplicam | | CS07 | informação | item do log não está no seu cronograma (reparos, extras) | mantido para histórico; adicione apelidos se for um item do cronograma com outro nome | | CS08 | baixa | item custando 400 ou mais cai dentro do horizonte do plano | faça orçamento para ele; obtenha um orçamento cedo | | CS09 | média | leituras de odômetro insuficientes (uma leitura com pelo menos 60 dias de antecedência): distância anual padrão usada | adicione leituras (certificados de teste, aplicativo de combustível, fotos do painel) | ## Veredito - **Atrasado incluindo segurança/legal**: agende agora. - **Atrasado**: agende em breve. - **Vence em breve** / **em dia**. ## Como os números são calculados - Distância anual: da leitura mais recente do log com pelo menos um ano antes de hoje até a leitura de hoje (a leitura mais antiga se nenhuma for tão antiga). - Próximo vencimento: última data de realização + meses, e último odômetro de realização + km, convertido para uma data com sua distância diária; o mais próximo vence. Um item sem registro conta desde o primeiro registro a 0 km (`first_months` substitui `months` na primeira vez, ex.: um primeiro teste legal após 36 meses). - Horizonte: cada item se repete a partir da data em que é considerado feito (sua data de vencimento, ou hoje se atrasado). - Visitas: itens que vencem dentro de `bundle.days` e `bundle.km` do primeiro item de uma visita juntam-se a essa visita (adiantados, nunca adiados). - Custos: o `cost` de cada ocorrência adicionado ao seu trimestre; reserva mensal = total do horizonte / meses do horizonte. ## Chaves do JSON do carro `vehicle{name, first_registered, unit}, odometer{reading, date}, driving{default_per_year, severe, severe_reasons}, currency, horizon_months, due_soon{km, days}, bundle{km, days}, schedule[{item, km, months, severe_km, severe_months, first_months, cost, safety, legal, aliases[]}]`. ## CSV do registro de serviço `date, odometer, item, cost, shop, notes` - vários itens em uma visita separados por `;`. Os nomes são correspondidos aos itens do cronograma e apelidos sem diferenciar maiúsculas de minúsculas. A coluna de custo é para seus registros; a previsão usa os preços do cronograma. ## Modelo # Plano de serviço do carro: <carro, registro> **Data:** <AAAA-MM-DD> **Odômetro:** <83.400 km> **Distância anual:** <cerca de 11.000 km> **Cronograma:** <manual do proprietário, serviço normal / severo> ## Fazer agora | Item | Por quê | Custo est. | |---|---|---| | <Fluido de freio> | <atrasado por 4 meses (intervalo de 2 anos) - segurança> | <85> | | <Teste de aptidão para circular> | <vence 2026-11-20 - legal> | <60> | ## Próximas visitas | Quando (agendar até) | A cerca de | Itens | Custo est. | |---|---|---|---| | <2027-02-14> | <86.500 km> | <óleo e filtro, inspeção de freios> | <180> | ## Orçamento - Próximos 12 meses: <1.220> <EUR> - Próximos 24 meses: <2.445> <EUR> -> reserve <102> por mês - Itens grandes pela frente: <kit de correia dentada e bomba d'água, nov 2027, cerca de 680> ## Para verificar - [ ] <sem registro da correia dentada - verifique o livro de revisões / pergunte à concessionária> - [ ] <intervalo exato do fluido de freio para este motor> - [ ] <garantia: exige serviço na concessionária?> ## Lista de verificação para a oficina - Carro: <marca, modelo, motor, VIN se solicitado>, odômetro <...> - Por favor, faça: <lista de "Fazer agora"> - Por favor, verifique e faça orçamento antes de substituir: <pastilhas/discos de freio, pneus, limpadores, bateria> - Por favor, carimbe o livro de revisões / envie um registro digital e anote o odômetro na fatura. *Intervalos de <fonte>; custos são estimativas. Verifique qualquer coisa incomum (luzes de advertência, ruídos, puxar, vibração) imediatamente.* ## Exemplo: car.json { "vehicle": {"name": "2019 Skoda Octavia Estate 1.5 TSI (gasolina)", "first_registered": "2019-11-14", "unit": "km"}, "odometer": {"reading": 83400, "date": "2026-11-04"}, "driving": {"default_per_year": 12000, "severe": false, "severe_reasons": ["principalmente trajetos curtos no inverno", "reboque ocasional de caravana"]}, "currency": "EUR", "horizon_months": 24, "due_soon": {"km": 1500, "days": 45}, "bundle": {"km": 2500, "days": 60}, "schedule": [ {"item": "Óleo do motor e filtro", "km": 15000, "months": 12, "severe_km": 7500, "severe_months": 6, "cost": 140, "aliases": ["serviço de óleo", "troca de óleo"]}, {"item": "Serviço de inspeção", "km": 30000, "months": 24, "severe_km": 20000, "cost": 190, "aliases": ["inspeção"]}, {"item": "Inspeção de freios", "km": 20000, "months": 12, "cost": 40, "safety": true}, {"item": "Fluido de freio", "months": 24, "cost": 85, "safety": true}, {"item": "Filtro de ar", "km": 60000, "months": 48, "severe_km": 30000, "cost": 45}, {"item": "Filtro de cabine", "km": 30000, "months": 24, "cost": 40, "aliases": ["filtro de pólen"]}, {"item": "Velas de ignição", "km": 60000, "months": 72, "cost": 160}, {"item": "Rodízio de pneus", "km": 10000, "cost": 30}, {"item": "Pneus (jogo de 4)", "km": 45000, "months": 72, "cost": 560, "safety": true}, {"item": "Kit de correia dentada e bomba d'água", "km": 120000, "months": 96, "cost": 680}, {"item": "Teste de aptidão para circular", "months": 12, "first_months": 36, "cost": 60, "legal": true, "aliases": ["mot", "inspeção periódica"]} ] } ## Exemplo: service-log.csv date,odometer,item,cost,shop,notes 2020-11-20,11500,Serviço de óleo; Inspeção de freios,165,Concessionária principal,primeiro serviço 2021-11-05,22800,Serviço de óleo; Inspeção de freios; Filtro de cabine,210,Concessionária principal, 2022-05-28,33900,Serviço de óleo; Serviço de inspeção; Fluido de freio; Filtro de ar,395,Concessionária principal, 2022-11-08,38000,Teste de aptidão para circular,55,Centro de testes,aprovado 2023-06-15,45150,Serviço de óleo; Inspeção de freios; Rodízio de pneus; Pneus (jogo de 4),735,QuickFit,pneus novos 205/55 R16 2023-09-02,4790,Reparo de trinca no para-brisa,60,GlassFix, 2023-11-13,49000,Teste de aptidão para circular,55,Centro de testes,aprovado 2024-07-01,56900,Serviço de óleo; Serviço de inspeção; Fluido de freio; Velas de ignição; Inspeção de freios,520,Concessionária principal, 2024-11-12,59800,Teste de aptidão para circular,58,Centro de testes,observação: limpador traseiro 2025-08-20,70100,Serviço de óleo; Inspeção de freios; Filtro de cabine; Rodízio de pneus,240,Garagem da esquina, 2025-11-20,73000,Teste de aptidão para circular,60,Centro de testes,aprovado 2026-02-14,75300,Troca de óleo; Inspeção de freios,150,Garagem da esquina,luz do painel acendeu ## Exemplo: service-plan.md # Plano de serviço: 2019 Skoda Octavia Estate 1.5 TSI (gasolina) Hoje 2026-11-04, odômetro 83.400 km. Você dirige cerca de 11.008 km/ano (2025-08-20 70.100 -> 2026-11-04 83.400). Intervalos de serviço normal, horizonte do plano de 24 meses. Fonte: examples/service-log.csv. **Veredito: 4 item(ns) atrasado(s), incluindo itens de segurança/legais - agende uma visita agora** Próximos 12 meses: cerca de 1.220,00 EUR; próximos 24 meses: 2.445,00 EUR (reserve cerca de 101,88 EUR por mês). Descobertas: 1 alta, 6 médias, 2 baixas, 3 informações. ## Itens | Item | Intervalo | Última vez | Vence por data | Vence a | Próximo (projetado) | Gatilho | Status | Custo est. | |---|---|---|---|---|---|---|---|---| | Serviço de inspeção | 30.000 km / 24 meses | 2024-07-01 a 56.900 | 2026-07-01 | 86.900 | 2026-11-04 | tempo | **ATRASADO** | 190,00 | | Fluido de freio [segurança] | 24 meses | 2024-07-01 a 56.900 | 2026-07-01 | - | 2026-11-04 | tempo | **ATRASADO** | 85,00 | | Filtro de ar | 60.000 km / 48 meses | 2022-05-28 a 33.900 | 2026-05-28 | 93.900 | 2026-11-04 | tempo | **ATRASADO** | 45,00 | | Rodízio de pneus | 10.000 km | 2025-08-20 a 70.100 | - | 80.100 | 2026-11-04 | distância | **ATRASADO** | 30,00 | | Teste de aptidão para circular [legal] | 12 meses | 2025-11-20 a 73.000 | 2026-11-20 | - | 2026-11-20 | tempo | **VENCE EM BREVE** | 60,00 | | Óleo do motor e filtro | 15.000 km / 12 meses | 2026-02-14 a 75.300 | 2027-02-14 | 90.300 | 2027-02-14 | tempo | OK | 140,00 | | Inspeção de freios [segurança] | 20.000 km / 12 meses | 2026-02-14 a 75.300 | 2027-02-14 | 95.300 | 2027-02-14 | tempo | OK | 40,00 | | Pneus (jogo de 4) [segurança] | 45.000 km / 72 meses | 2023-06-15 a 45.150 | 2029-06-15 | 90.150 | 2027-06-15 | distância | OK | 560,00 | | Filtro de cabine | 30.000 km / 24 meses | 2025-08-20 a 70.100 | 2027-08-20 | 100.100 | 2027-08-20 | tempo | OK | 40,00 | | Kit de correia dentada e bomba d'água | 120.000 km / 96 meses | sem registro (contado desde novo, 2019-11-14) | 2027-11-14 | 120.000 | 2027-11-14 | tempo | OK | 680,00 | | Velas de ignição | 60.000 km / 72 meses | 2024-07-01 a 56.900 | 2030-07-01 | 116.900 | 2029-11-18 | distância | OK | 160,00 | ## Visitas à oficina (itens dentro de 60 dias / 2.500 km são agrupados) | # | Agendar até | A cerca de | Itens | Custo est. | |---|---|---|---|---| | 1 | 2026-11-04 (agora) | 83.400 km | Filtro de ar (atrasado), Fluido de freio (atrasado), Serviço de inspeção (atrasado), Rodízio de pneus (atrasado), Teste de aptidão para circular | 410,00 | | 2 | 2027-02-14 | 86.476 km | Inspeção de freios, Óleo do motor e filtro | 180,00 | | 3 | 2027-06-15 | 90.125 km | Pneus (jogo de 4) | 560,00 | | 4 | 2027-08-20 | 92.116 km | Filtro de cabine, Rodízio de pneus | 70,00 | | 5 | 2027-11-14 | 94.710 km | Kit de correia dentada e bomba d'água, Teste de aptidão para circular | 740,00 | | 6 | 2028-02-14 | 97.484 km | Inspeção de freios, Óleo do motor e filtro | 180,00 | | 7 | 2028-08-27 | 103.365 km | Rodízio de pneus | 30,00 | | 8 | 2028-11-04 | 105.446 km | Fluido de freio, Serviço de inspeção | 275,00 | ## Previsão de custos por trimestre | Trimestre | Custo est. | |---|---| | 2026-T4 | 410,00 | | 2027-T1 | 180,00 | | 2027-T2 | 560,00 | | 2027-T3 | 40,00 | | 2027-T4 | 770,00 | | 2028-T1 | 180,00 | | 2028-T3 | 30,00 | | 2028-T4 | 275,00 | | **Total 24 meses** | **2.445,00** | ## Descobertas - **ALTA CS01** Fluido de freio está atrasado por 126 dias (item de segurança) - agende agora - **MÉDIA CS01** Filtro de ar está atrasado por 160 dias - agende agora - **MÉDIA CS01** Serviço de inspeção está atrasado por 126 dias - agende agora - **MÉDIA CS01** Rodízio de pneus está atrasado por 3.300 km - agende agora - **MÉDIA CS02** Teste de aptidão para circular vence em breve: 2026-11-20 - **MÉDIA CS03** Kit de correia dentada e bomba d'água: sem registro no seu log - contado desde novo; verifique o livro de revisões ou recibos - **MÉDIA CS04** linha 7: odômetro 4.790 em 2023-09-02 é menor que 45.150 em 2023-06-15 - erro de digitação ou carro errado? leitura ignorada - **BAIXA CS08** Kit de correia dentada e bomba d'água (cerca de 680,00) cai no plano em 2027-11-14 - faça orçamento agora - **BAIXA CS08** Pneus (jogo de 4) (cerca de 560,00) caem no plano em 2027-06-15 - faça orçamento agora - **INFO CS05** Inspeção de freios foi feita pela última vez após 5.200 km / 6 meses (menos de 60% do intervalo) - ok para uso severo, caso contrário dinheiro gasto cedo - **INFO CS05** Óleo do motor e filtro foi feito pela última vez após 5.200 km / 6 meses (menos de 60% do intervalo) - ok para uso severo, caso contrário dinheiro gasto cedo - **INFO CS07** linha 7: 'Reparo de trinca no para-brisa' não está no seu cronograma - mantido apenas no histórico Intervalos e preços vêm do seu arquivo do carro: verifique-os contra o manual do proprietário ou livro de revisões para seu motor exato, e siga sua oficina se ela encontrar desgaste antes. Custos são estimativas; pneus e freios também dependem do desgaste, não apenas da distância. ## Script Python (car_service_plan.py) ```python #!/usr/bin/env python3 """Planejador de cronograma de serviço de manutenção de carro (somente biblioteca padrão, Python 3.8+). Lê o cronograma de manutenção do seu carro (itens com intervalos de distância e/ou tempo, do manual do proprietário ou livro de revisões) e seu histórico de serviço (CSV), estima quantos quilômetros você dirige a partir das leituras do odômetro no log e calcula para cada item quando foi feito pela última vez, quando vence a seguir (distância ou tempo, o que ocorrer primeiro), o que está atrasado ou vence em breve, quais itens podem compartilhar uma visita à oficina e qual será o custo da manutenção nos próximos meses. Uso: car_service_plan.py CAR.json SERVICE_LOG.csv [--odometer N] [--today AAAA-MM-DD] [--severe] [--horizon MESES] [--json] car_service_plan.py --self-test Saída: 0 = nada atrasado em item de segurança/legal, 1 = um item de segurança ou legal está atrasado (ou o log tem uma descoberta alta), 2 = entrada inválida. """ import argparse, calendar, csv, datetime, io, json, sys SEV = {"alta": 0, "média": 1, "baixa": 2, "info": 3} CAR_KEYS = {"vehicle", "odometer", "driving", "currency", "horizon_months", "due_soon", "bundle", "schedule"} class InputError(Exception): pass def pdate(s, what): try: return datetime.date.fromisoformat(str(s).strip()) except ValueError: raise InputError("%s deve ser AAAA-MM-DD, recebido %r" % (what, s)) def add_months(d, m): y, mo = divmod(d.month - 1 + int(m), 12) y += d.year mo += 1 return datetime.date(y, mo, min(d.day, calendar.monthrange(y, mo)[1])) def num(x, what): try: return float(str(x).replace(",", "").replace(" ", "")) except ValueError: raise InputError("%s não é um número: %r" % (what, x)) def fk(x): return "{:,.0f}".format(x) def fm(x): return "{:,.2f}".format(x) # ---------------------------------------------------------------- carregar def load_car(cfg, odometer=None, today=None, severe=None, horizon=None): if not isinstance(cfg, dict): raise InputError("o arquivo do carro deve ser um objeto JSON") bad = set(cfg) - CAR_KEYS if bad: raise InputError("chave(s) desconhecida(s) no arquivo do carro: %s" % ", ".join(sorted(bad))) v = cfg.get("vehicle") or {} odo = cfg.get("odometer") or {} drv = cfg.get("driving") or {} c = {"name": v.get("name", "Carro"), "unit": v.get("unit", "km"), "first": pdate(v["first_registered"], "vehicle.first_registered") if v.get("first_registered") else None, "today": pdate(today or odo.get("date") or datetime.date.today().isoformat(), "today"), "odo": num(odometer if odometer is not None else odo.get("reading"), "leitura do odômetro") if (odometer is not None or odo.get("reading") is not None) else None, "default_per_year": num(drv.get("default_per_year", 12000), "driving.default_per_year"), "severe": bool(drv.get("severe", False)) if severe is None else severe, "severe_reasons": drv.get("severe_reasons", []), "currency": cfg.get("currency", ""), "horizon": int(horizon or cfg.get("horizon_months", 24)), "soon_km": num((cfg.get("due_soon") or {}).get("km", 1500), "due_soon.km"), "soon_days": int((cfg.get("due_soon") or {}).get("days", 45)), "bundle_km": num((cfg.get("bundle") or {}).get("km", 2500), "bundle.km"), "bundle_days": int((cfg.get("bundle") or {}).get("days", 60)), "items": []} if c["odo"] is None: raise InputError("forneça a leitura atual do odômetro (odometer.reading ou --odometer)") for i, it in enumerate(cfg.get("schedule") or [], 1): name = it.get("item") if not name: raise InputError("item %d do cronograma não tem nome 'item'" % i) km = it.get("severe_km") if c["severe"] and it.get("severe_km") else it.get("km") mo = it.get("severe_months") if c["severe"] and it.get("severe_months") else it.get("months") if not km and not mo: raise InputError("item '%s' do cronograma precisa de km e/ou months" % name) c["items"].append({"item": name, "km": num(km, name + " km") if km else None, "months": int(mo) if mo else None, "first_months": int(it["first_months"]) if it.get("first_months") else None, "cost": num(it.get("cost", 0), name + " cost"), "safety": bool(it.get("safety")), "legal": bool(it.get("legal")), "severe_used": bool(c["severe"] and (it.get("severe_km") or it.get("severe_months"))), "aliases": [a.lower().strip() for a in it.get("aliases", [])] + [name.lower().strip()]}) if not c["items"]: raise InputError("o arquivo do carro precisa de um 'schedule' não vazio") return c def load_log(c, text, F): rows = list(csv.DictReader(io.StringIO(text))) if rows and not {"date", "odometer", "item"} <= set(rows[0]): raise InputError("o registro de serviço precisa das colunas date, odometer, item (tem %s)" % ", ".join(rows[0])) entries, readings = [], [] for n, r in enumerate(rows, 2): try: d = pdate(r.get("date"), "date (linha %d)" % n) except InputError as e: F.append(("alta", "CS04", "linha %d: %s - linha ignorada" % (n, e))); continue if d > c["today"]: F.append(("alta", "CS04", "linha %d: data %s está no futuro - linha ignorada" % (n, d))); continue odo = None if (r.get("odometer") or "").strip(): try: odo = num(r["odometer"], "odometer (linha %d)" % n) except InputError as e: F.append(("média", "CS04", "%s - distância ignorada para esta linha" % e)) items = [x.strip() for x in (r.get("item") or "").split(";") if x.strip()] entries.append({"row": n, "date": d, "odo": odo, "items": items, "cost": r.get("cost", ""), "shop": r.get("shop", "")}) entries.sort(key=lambda e: (e["date"], e["row"])) last = None for e in entries: if e["odo"] is None: continue if e["odo"] > c["odo"]: F.append(("alta", "CS04", "linha %d: odômetro %s em %s é maior que a leitura atual %s - erro de digitação? leitura ignorada" % (e["row"], fk(e["odo"]), e["date"], fk(c["odo"])))) e["odo"] = None; continue if last and e["odo"] < last["odo"]: F.append(("média", "CS04", "linha %d: odômetro %s em %s é menor que %s em %s - erro de digitação ou carro errado? leitura ignorada" % (e["row"], fk(e["odo"]), e["date"], fk(last["odo"]), last["date"]))) e["odo"] = None; continue last = e readings.append((e["date"], e["odo"])) readings.append((c["today"], c["odo"])) return entries, readings def distance_rate(c, readings, F): """km por dia da leitura mais recente com pelo menos um ano antes de hoje (senão a mais antiga).""" end_d, end_o = readings[-1] older = [r for r in readings[:-1] if (end_d - r[0]).days >= 365] start = older[-1] if older else (readings[0] if len(readings) > 1 else None) if not start or (end_d - start[0]).days < 60 or end_o <= start[1]: F.append(("média", "CS09", "leituras de odômetro insuficientes para estimar sua distância anual - usando o padrão %s %s/ano" % (fk(c["default_per_year"]), c["unit"]))) return c["default_per_year"] / 365.0, "padrão" rate = (end_o - start[1]) / float((end_d - start[0]).days) return rate, "%s %s -> %s %s" % (start[0], fk(start[1]), end_d, fk(end_o)) # ---------------------------------------------------------------- planejar def plan(c, log_text): F = [] entries, readings = load_log(c, log_text, F) rate, basis = distance_rate(c, readings, F) known = {a: it for it in c["items"] for a in it["aliases"]} done = {it["item"]: [] for it in c["items"]} for e in entries: for name in e["items"]: it = known.get(name.lower()) if not it: F.append(("info", "CS07", "linha %d: '%s' não está no seu cronograma - mantido apenas no histórico" % (e["row"], name))) continue done[it["item"]].append(e) def date_at_km(km): return c["today"] + datetime.timedelta(days=max(0.0, (km - c["odo"]) / rate)) if rate > 0 else None def km_at_date(d): return c["odo"] + rate * (d - c["today"]).days end = add_months(c["today"], c["horizon"]) rows, occ = [], [] for it in c["items"]: hist = done[it["item"]] last = hist[-1] if hist else None if last: base_d, base_km, base_note = last["date"], last["odo"], "%s a %s" % (last["date"], fk(last["odo"]) if last["odo"] is not None else "?") else: if not c["first"]: raise InputError("sem registro de '%s' e sem vehicle.first_registered para contar" % it["item"]) base_d, base_km, base_note = c["first"], 0.0, "sem registro (contado desde novo, %s)" % c["first"] F.append(("média", "CS03", "%s: sem registro no seu log - contado desde novo; verifique o livro de revisões ou recibos" % it["item"])) months = it["months"] if not last and it["first_months"]: months = it["first_months"] due_d = add_months(base_d, months) if months else None due_km = base_km + it["km"] if (it["km"] and base_km is not None) else None km_d = date_at_km(due_km) if due_km is not None else None cands = [(x, w) for x, w in ((due_d, "tempo"), (km_d, "distância")) if x] if not cands: due_date, trigger = c["today"], "desconhecido" else: due_date, trigger = min(cands) overdue = (due_d is not None and due_d < c["today"]) or (due_km is not None and due_km < c["odo"]) soon = not overdue and ((due_d is not None and (due_d - c["today"]).days <= c["soon_days"]) or (due_km is not None and due_km - c["odo"] <= c["soon_km"])) status = "ATRASADO" if overdue else ("VENCE EM BREVE" if soon else "OK") if overdue: late = [] if due_d is not None and due_d < c["today"]: late.append("%d dias" % (c["today"] - due_d).days) if due_km is not None and due_km < c["odo"]: late.append("%s %s" % (fk(c["odo"] - due_km), c["unit"])) sev = "alta" if (it["safety"] or it["legal"]) else "média" F.append((sev, "CS01", "%s está atrasado por %s%s - agende agora" % (it["item"], " e ".join(late), " (item de segurança)" if it["safety"] else (" (exigência legal)" if it["legal"] else "")))) elif soon: F.append(("média", "CS02", "%s vence em breve: %s%s" % (it["item"], due_d if due_d and (due_d - c["today"]).days <= c["soon_days"] else "", (" / a %s %s" % (fk(due_km), c["unit"])) if due_km is not None else ""))) if len(hist) >= 2 and hist[-2]["odo"] is not None and hist[-1]["odo"] is not None: a, b = hist[-2], hist[-1] fr = [] if it["km"]: fr.append((b["odo"] - a["odo"]) / it["km"]) if it["months"]: fr.append(((b["date"] - a["date"]).days / 30.44) / it["months"]) if fr and max(fr) < 0.6: F.append(("info", "CS05", "%s foi feito pela última vez após %s %s / %d meses (menos de 60%% do intervalo) - ok para uso severo, caso contrário dinheiro gasto cedo" % (it["item"], fk(b["odo"] - a["odo"]), c["unit"], round((b["date"] - a["date"]).days / 30.44)))) rows.append({"item": it["item"], "last": base_note, "interval": " / ".join(x for x in [("%s %s" % (fk(it["km"]), c["unit"])) if it["km"] else "", ("%d meses" % months) if months else ""] if x), "due_date": due_d, "due_km": due_km, "next": max(due_date, c["today"]), "trigger": trigger, "status": status, "cost": it["cost"], "safety": it["safety"] or it["legal"], "flag": "legal" if it["legal"] else ("segurança" if it["safety"] else ""), "severe": it["severe_used"]}) # ocorrências no horizonte (cada uma considerada feita na data de vencimento) d, k, first = max(due_date, c["today"]), due_km, True guard = 0 while d <= end and guard < 50: guard += 1 occ.append({"item": it["item"], "date": d, "km": km_at_date(d), "cost": it["cost"], "overdue": first and overdue}) first = False nd = add_months(d, it["months"]) if it["months"] else None nk = km_at_date(d) + it["km"] if it["km"] else None cands = [x for x in (nd, date_at_km(nk) if nk is not None else None) if x] if not cands: break d = min(cands) if (it["cost"] >= 400) and any(o["item"] == it["item"] for o in occ): o = next(o for o in occ if o["item"] == it["item"]) F.append(("baixa", "CS08", "%s (cerca de %s) cai no plano em %s - faça orçamento agora" % (it["item"], fm(it["cost"]), o["date"]))) if c["severe"]: F.append(("info", "CS06", "intervalos de serviço severo usados%s" % ((" (" + ", ".join(c["severe_reasons"]) + ")") if c["severe_reasons"] else ""))) # visitas: agrupar ocorrências dentro da janela de agrupamento occ.sort(key=lambda o: (o["date"], o["item"])) visits = [] for o in occ: v = visits[-1] if visits else None if v and (o["date"] - v["date"]).days <= c["bundle_days"] and o["km"] - v["km"] <= c["bundle_km"]: v["items"].append(o); continue visits.append({"date": o["date"], "km": o["km"], "items": [o]}) # custos por trimestre quarters = {} for o in occ: q = "%d-T%d" % (o["date"].year, (o["date"].month - 1) // 3 + 1) quarters[q] = quarters.get(q, 0.0) + o["cost"] y1 = sum(o["cost"] for o in occ if o["date"] < add_months(c["today"], 12)) total = sum(o["cost"] for o in occ) F.sort(key=lambda f: (SEV[f[0]], f[1], f[2])) return {"car": c, "rate": rate, "basis": basis, "rows": rows, "occ": occ, "visits": visits, "quarters": quarters, "next12": y1, "total": total, "findings": F, "entries": entries} # ---------------------------------------------------------------- relatório def report(res, title): c, F = res["car"], res["findings"] cnt = {s: sum(1 for f in F if f[0] == s) for s in SEV} cur = (" " + c["currency"]) if c["currency"] else "" ov = [r for r in res["rows"] if r["status"] == "ATRASADO"] soon = [r for r in res["rows"] if r["status"] == "VENCE EM BREVE"] L = ["# Plano de serviço: %s" % c["name"], ""] L.append("Hoje %s, odômetro %s %s. Você dirige cerca de %s %s/ano (%s). Intervalos %s, horizonte do plano de %d meses. Fonte: %s." % ( c["today"], fk(c["odo"]), c["unit"], fk(res["rate"] * 365), c["unit"], res["basis"], "de serviço severo" if c["severe"] else "de serviço normal", c["horizon"], title)) L.append("") if any(r["safety"] for r in ov): L.append("**Veredito: %d item(ns) atrasado(s), incluindo itens de segurança/legais - agende uma visita agora**" % len(ov)) elif ov: L.append("**Veredito: %d item(ns) atrasado(s) - agende uma visita em breve**" % len(ov)) elif soon: L.append("**Veredito: nada atrasado, %d item(ns) vencendo em breve**" % len(soon)) else: L.append("**Veredito: em dia**") L.append("") L.append("Próximos 12 meses: cerca de %s%s; próximos %d meses: %s%s (reserve cerca de %s%s por mês). Descobertas: %d alta(s), %d média(s), %d baixa(s), %d informação(ões)." % ( fm(res["next12"]), cur, c["horizon"], fm(res["total"]), cur, fm(res["total"] / c["horizon"]), cur, cnt["alta"], cnt["média"], cnt["baixa"], cnt["info"])) L += ["", "## Itens", "", "| Item | Intervalo | Última vez | Vence por data | Vence a %s | Próximo (projetado) | Gatilho | Status | Custo est. |" % c["unit"], "|---|---|---|---|---|---|---|---|---|"] order = {"ATRASADO": 0, "VENCE EM BREVE": 1, "OK": 2} for r in sorted(res["rows"], key=lambda r: (order[r["status"]], r["next"])): L.append("| %s%s | %s | %s | %s | %s | %s | %s | %s | %s |" % ( r["item"], (" [%s]" % r["flag"]) if r["flag"] else "", r["interval"] + (" (severo)" if r["severe"] else ""), r["last"], r["due_date"] or "-", fk(r["due_km"]) if r["due_km"] is not None else "-", r["next"], r["trigger"], "**%s**" % r["status"] if r["status"] != "OK" else "OK", fm(r["cost"]))) L += ["", "## Visitas à oficina (itens dentro de %d dias / %s %s são agrupados)" % (c["bundle_days"], fk(c["bundle_km"]), c["unit"]), "", "| # | Agendar até | A cerca de | Itens | Custo est. |", "|---|---|---|---|---|"] for i, v in enumerate(res["visits"], 1): L.append("| %d | %s%s | %s %s | %s | %s |" % (i, v["date"], " (agora)" if v["date"] == c["today"] else "", fk(v["km"]), c["unit"], ", ".join(o["item"] + (" (atrasado)" if o["overdue"] else "") for o in v["items"]), fm(sum(o["cost"] for o in v["items"])))) L += ["", "## Previsão de custos por trimestre", "", "| Trimestre | Custo est. |", "|---|---|"] for q in sorted(res["quarters"]): L.append("| %s | %s |" % (q, fm(res["quarters"][q]))) L.append("| **Total %d meses** | **%s** |" % (c["horizon"], fm(res["total"]))) L += ["", "## Descobertas", ""] L += ["- **%s %s** %s" % (s.upper(), code, m) for s, code, m in F] or ["- nenhuma"] L += ["", "Intervalos e preços vêm do seu arquivo do carro: verifique-os contra o manual do proprietário ou livro de revisões para seu motor exato, e siga sua oficina se ela encontrar desgaste antes. Custos são estimativas; pneus e freios também dependem do desgaste, não apenas da distância."] return "\n".join(L) + "\n" def to_json(res): def j(x): if isinstance(x, datetime.date): return x.isoformat() if isinstance(x, float): return round(x, 2) if isinstance(x, dict): return {k: j(v) for k, v in x.items()} if isinstance(x, list): return [j(v) for v in x] return x return j({"km_per_year": res["rate"] * 365, "items": res["rows"], "visits": [{"date": v["date"], "km": v["km"], "items": [o["item"] for o in v["items"]], "cost": sum(o["cost"] for o in v["items"])} for v in res["visits"]], "quarters": res["quarters"], "next12": res["next12"], "total": res["total"], "findings": [{"severity": s, "code": c, "message": m} for s, c, m in res["findings"]]}) # ---------------------------------------------------------------- auto-teste def self_test(): tests = [] def t(name, cond): tests.append((name, bool(cond))) def car(**kw): cfg = {"vehicle": {"name": "T", "first_registered": "2020-01-01"}, "odometer": {"reading": 50000, "date": "2026-01-01"}, "schedule": [{"item": "Óleo", "km": 15000, "months": 12, "severe_km": 7500, "severe_months": 6, "cost": 100, "aliases": ["troca de óleo"]}]} sched = kw.pop("schedule", None) if sched: cfg["schedule"] = sched cfg.update(kw) return cfg H = "date,odometer,item,cost,shop\n" def run(cfg, log, **kw): return plan(load_car(cfg, **kw), H + log) def row(res, name): return next(r for r in res["rows"] if r["item"] == name) def codes(res): return [(f[0], f[1]) for f in res["findings"]] log = "2025-01-01,40000,Óleo,90,X\n" r = run(car(), log) t("taxa das leituras: 10000 km/ano", abs(r["rate"] * 365 - 10000) < 1) t("vence por tempo primeiro (12 meses)", row(r, "Óleo")["due_date"] == datetime.date(2026, 1, 1) and row(r, "Óleo")["trigger"] == "tempo") t("vence hoje conta como vence em breve", row(r, "Óleo")["status"] == "VENCE EM BREVE") r = run(car(), "2025-06-01,40000,Óleo,90,X\n") t("distância dispara primeiro ao dirigir muito", row(r, "Óleo")["due_km"] == 55000 and row(r, "Óleo")["trigger"] == "distância") r = run(car(), "2024-06-01,30000,Óleo,90,X\n") t("atrasado por tempo e distância -> CS01", row(r, "Óleo")["status"] == "ATRASADO" and ("média", "CS01") in codes(r)) sched = [{"item": "Fluido de freio", "months": 24, "cost": 80, "safety": True}] r = run(car(schedule=sched), "2023-06-01,30000,Fluido de freio,80,X\n2025-01-01,40000,Outro,0,X\n") t("item de segurança atrasado -> CS01 alta", ("alta", "CS01") in codes(r)) t("item fora do cronograma -> CS07", ("info", "CS07") in codes(r)) r = run(car(), "2025-01-01,40000,troca de óleo,90,X\n") t("apelidos correspondem sem diferenciar maiúsculas", row(r, "Óleo")["last"].startswith("2025-01-01")) r = run(car(), "2025-01-01,40000,Limpadores,20,X\n") t("sem registro -> contado desde novo, CS03", ("média", "CS03") in codes(r) and "sem registro" in row(r, "Óleo")["last"]) r = run(car(), "2025-01-01,40000,Óleo,90,X\n", severe=True) t("intervalos severos usados", row(r, "Óleo")["due_date"] == datetime.date(2025, 7, 1) and ("info", "CS06") in codes(r)) r = run(car(), "2024-01-01,30000,Óleo,90,X\n2024-06-01,20000,Óleo,90,X\n2025-01-01,40000,Óleo,90,X\n") t("odômetro diminuindo -> CS04, leitura ignorada", ("média", "CS04") in codes(r)) r = run(car(), "2025-01-01,40000,Óleo,90,X\n2027-01-01,60000,Óleo,90,X\n") t("data futura -> CS04 alta", ("alta", "CS04") in codes(r)) r = run(car(), "2025-01-01,90000,Óleo,90,X\n") t("leitura acima do odômetro atual -> CS04 alta", ("alta", "CS04") in codes(r)) r = run(car(), "") t("sem leituras -> taxa padrão + CS09", ("média", "CS09") in codes(r) and abs(r["rate"] * 365 - 12000) < 1) r = run(car(), "2025-01-01,40000,Óleo,90,X\n2025-04-01,42000,Óleo,90,X\n") t("feito cedo -> CS05", ("info", "CS05") in codes(r)) sched = [{"item": "Teste", "months": 12, "first_months": 36, "cost": 50, "legal": True}] r = run(car(vehicle={"first_registered": "2024-01-01"}, schedule=sched), "2025-01-01,40000,Outro,0,X\n") t("first_months para o primeiro teste desde novo", row(r, "Teste")["due_date"] == datetime.date(2027, 1, 1)) sched = [{"item": "A", "months": 12, "cost": 100}, {"item": "B", "months": 12, "cost": 50}] r = run(car(schedule=sched), "2025-02-01,41000,A,0,X\n2025-03-15,42000,B,0,X\n") t("itens dentro da janela de agrupamento compartilham uma visita", len(r["visits"][0]["items"]) == 2) t("horizonte repete itens anuais", sum(1 for o in r["occ"] if o["item"] == "A") == 2) t("previsão de 12 meses e total", r["next12"] == 150 and r["total"] == 300) sched = [{"item": "Correia", "km": 120000, "months": 96, "cost": 650}] r = run(car(schedule=sched), "2025-01-01,40000,Outro,0,X\n") t("item de alto valor no horizonte -> CS08", ("baixa", "CS08") in codes(r)) t("add_months ajusta o fim do mês", add_months(datetime.date(2026, 1, 31), 1) == datetime.date(2026, 2, 28)) try: load_car(car(schedule=[{"item": "X", "cost": 1}])); ok = False except InputError: ok = True t("item sem intervalo rejeitado", ok) try: load_car(dict(car(), colour="vermelho")); ok = False except InputError: ok = True t("chave desconhecida rejeitada", ok) r = run(car(), log) t("relatório tem veredito, visitas e previsão", all(s in report(r, "t") for s in ("**Veredito:", "## Visitas à oficina", "## Previsão de custos"))) for name, ok in tests: print(("PASS " if ok else "FAIL ") + name) passed = sum(ok for _, ok in tests) print("%d/%d aprovados" % (passed, len(tests))) return 0 if passed == len(tests) else 1 def main(argv=None): ap = argparse.ArgumentParser(description="Planeje a manutenção do carro a partir de um cronograma e um registro de serviço.") ap.add_argument("car", nargs="?") ap.add_argument("log", nargs="?") ap.add_argument("--odometer", type=float) ap.add_argument("--today") ap.add_argument("--severe", action="store_true", default=None, help="use intervalos de serviço severo") ap.add_argument("--horizon", type=int, help="meses para planejar (padrão do arquivo do carro, senão 24)") ap.add_argument("--json", action="store_true") ap.add_argument("--self-test", action="store_true") a = ap.parse_args(argv) if a.self_test: return self_test() if not a.car or not a.log: ap.print_usage(sys.stderr) return 2 try: try: cfg = json.load(open(a.car, encoding="utf-8")) except json.JSONDecodeError as e: raise InputError("o arquivo do carro não é JSON válido: %s" % e) c = load_car(cfg, a.odometer, a.today, a.severe, a.horizon) res = plan(c, open(a.log, encoding="utf-8-sig").read()) except (OSError, InputError) as e: print("erro: %s" % e, file=sys.stderr) return 2 if a.json: print(json.dumps(to_json(res), indent=2)) else: sys.stdout.write(report(res, a.log)) return 1 if any(f[0] == "alta" for f in res["findings"]) else 0 if __name__ == "__main__": sys.exit(main()) ```

Entre para ver o prompt completo

Continuar com:

Ao entrar, você concorda com nossos Termos de uso e Política de privacidade

Uso

Este prompt foi projetado para uso com productivity. Copie o conteúdo acima e cole na sua ferramenta de IA preferida.

Para melhores resultados, personalize os marcadores (indicados por colchetes ou maiúsculas) com seus requisitos específicos.

Referências

Categorias:productivity| prompts.chat| car-maintenance| service-schedule

Discussão

0 comentários