Files
graphs/scripts/create_changes_summary_pdf.py
2026-08-12 15:12:03 -03:00

205 lines
8.0 KiB
Python

from pathlib import Path
from reportlab.lib.colors import HexColor
from reportlab.lib.enums import TA_LEFT
from reportlab.lib.pagesizes import LETTER
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.platypus import (
BaseDocTemplate,
Frame,
PageBreak,
PageTemplate,
Paragraph,
Spacer,
)
OUTPUT = Path("output/pdf/resumo-alteracoes-ultimas-duas-semanas.pdf")
BLUE = HexColor("#2E75B6")
NAVY = HexColor("#1F4E79")
BLACK = HexColor("#000000")
GRAY = HexColor("#666666")
def footer(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 9)
canvas.setFillColor(GRAY)
canvas.drawRightString(7.45 * inch, 0.47 * inch, "Nexstar Graphs")
canvas.restoreState()
def make_styles():
styles = getSampleStyleSheet()
return {
"title": ParagraphStyle(
"SummaryTitle",
parent=styles["Normal"],
fontName="Helvetica-Bold",
fontSize=18,
leading=22,
textColor=BLACK,
spaceAfter=13,
alignment=TA_LEFT,
),
"overview": ParagraphStyle(
"Overview",
parent=styles["Normal"],
fontName="Helvetica-Bold",
fontSize=10,
leading=13.5,
textColor=NAVY,
spaceAfter=16,
),
"section": ParagraphStyle(
"Section",
parent=styles["Normal"],
fontName="Helvetica-Bold",
fontSize=14.2,
leading=17.4,
textColor=BLUE,
spaceBefore=1,
spaceAfter=7,
),
"bullet": ParagraphStyle(
"Bullet",
parent=styles["Normal"],
fontName="Helvetica",
fontSize=9.8,
leading=13.1,
textColor=BLACK,
leftIndent=19,
firstLineIndent=-12,
spaceAfter=1.8,
),
}
def bullet(text, styles):
return Paragraph(f"•   {text}", styles["bullet"])
def section(title, items, styles):
flowables = [Paragraph(title, styles["section"])]
flowables.extend(bullet(item, styles) for item in items)
flowables.append(Spacer(1, 8))
return flowables
def main():
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
document = BaseDocTemplate(
str(OUTPUT),
pagesize=LETTER,
leftMargin=0.96 * inch,
rightMargin=0.84 * inch,
topMargin=1.08 * inch,
bottomMargin=0.75 * inch,
title="Resumo de Alterações - Nexstar Graphs",
author="Nexstar Graphs",
)
frame = Frame(
document.leftMargin,
document.bottomMargin,
document.width,
document.height,
id="content",
)
document.addPageTemplates([PageTemplate(id="main", frames=[frame], onPage=footer)])
styles = make_styles()
story = [
Paragraph("RESUMO DE ALTERAÇÕES", styles["title"]),
Paragraph(
"Visão geral: nas últimas duas semanas, o Graphs evoluiu a integração com a Olist, "
"o planejamento de corte, a gestão de ordens de produção, suprimentos e a experiência operacional.",
styles["overview"],
),
]
story.extend(
section(
"Integração Olist e dados de produção",
[
"Implementada conexão OAuth nativa com a API V3 da Olist, com armazenamento seguro de token, renovação automática e reconexão pela tela de monitoramento.",
"Criada sincronização de produtos fabricados e composições, com atualização incremental, retomada após reinício e limite de requisições compatível com a operação.",
"Adicionado agendamento diário às 11h, com exibição da próxima execução, progresso, duração, histórico, logs por produto e falhas na tela Olist.",
"Incluídos controles para parar e continuar a sincronização e importação de OPs finalizadas por CSV, com deduplicação em reimportações.",
"As observações das OPs agora fornecem fornecedor, lote, bobinas, quilos de malha e ribana e rendimento; as pendências podem ser exportadas pela tela Olist.",
],
styles,
)
)
story.extend(
section(
"Plano de corte e rendimentos",
[
"Reorganizada a tela de Plano de Corte para priorizar produto, necessidade de corte, demanda, disponível e situação operacional, sem repetir indicadores.",
"Incluídas edição contextual por SKU, visualização de produto e paginação no plano e na prévia de OPs.",
"Centralizada a configuração de corte e simplificado o preenchimento de rendimentos por família.",
"Corrigida a taxonomia: BLCS, BLOS, BLMC, BLPM e BLRM representam camiseta regular, oversize, moletom, pima e regata.",
"Importado histórico de OPs finalizadas para sugerir rendimento por família e, quando disponível, por fornecedor de tecido.",
],
styles,
)
)
story.extend(
section(
"Ordens de produção",
[
"Melhorada a prévia das OPs com paginação e seleção de itens individuais, página atual, todos os elegíveis ou somente itens com dados completos.",
"Reestruturada a página de Ordens de Produção para usar detalhes expansíveis na tabela, evitando painel lateral e duplicidade de controles.",
"Transformado o status em um menu compacto com opções claras para Em aberto, Em andamento, Finalizada e Cancelada.",
"Adicionada ação para devolver uma OP local em aberto ao Plano de Corte, preservando o histórico e devolvendo a necessidade ao planejamento.",
],
styles,
)
)
story.append(PageBreak())
story.extend(
section(
"Suprimentos, compras e estoque",
[
"Redesenhado o hub de Suprimentos para seguir o fluxo Necessidade de Compra, Plano de Corte e Ordens de Produção, com foco nas próximas ações.",
"Simplificado o fluxo de Necessidade de Compra: removida a área de mapeamento separada e incluída edição direta dos materiais por ícone.",
"Materiais sem saldo, com saldo negativo ou com necessidade de serviço passaram a usar filtros e estados visuais consistentes entre abas.",
"Criado centro de exceções para saldos negativos, SKUs sem composição e cadastro para corte, mantendo essas filas informativas e auditáveis.",
"Aplicada regra de estoque disponível: saldo negativo vale zero para compras e corte, sem esconder o saldo original para auditoria.",
],
styles,
)
)
story.extend(
section(
"Cadastros e produtos",
[
"Adicionada paginação com 10 itens por padrão nas listas de Produtos, Categorias e Referências de Consumo.",
"Incluídas ações de edição para Categorias, Produtos e Referências de Consumo, aproximando Cadastros da página de Produtos.",
"Melhorados os detalhes de composição e a navegação entre variações de produto para tornar a consulta mais direta.",
"Criadas ações compactas por ícone para materiais, preservando a leitura das tabelas.",
],
styles,
)
)
story.extend(
section(
"Experiência e navegação",
[
"Padronizado o visual de Suprimentos, Corte e Produção com as tabelas, filtros, badges e paginação já usados em Produtos.",
"Ajustada a cor da família BLCS no Plano de Corte e removidos cartões-resumo redundantes de Vendedores.",
"Aprimorada a navegação para dispositivos menores e refinados os estados de carregamento nas páginas comerciais.",
],
styles,
)
)
document.build(story)
print(OUTPUT)
if __name__ == "__main__":
main()