diff --git a/output/pdf/resumo-alteracoes-ultimas-duas-semanas.pdf b/output/pdf/resumo-alteracoes-ultimas-duas-semanas.pdf new file mode 100644 index 0000000..defba76 --- /dev/null +++ b/output/pdf/resumo-alteracoes-ultimas-duas-semanas.pdf @@ -0,0 +1,93 @@ +%PDF-1.4 +%“Œ‹ž ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +5 0 obj +<< +/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +6 0 obj +<< +/PageMode /UseNone /Pages 8 0 R /Type /Catalog +>> +endobj +7 0 obj +<< +/Author (Nexstar Graphs) /CreationDate (D:20260812150606-03'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260812150606-03'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (Resumo de Altera\347\365es - Nexstar Graphs) /Trapped /False +>> +endobj +8 0 obj +<< +/Count 2 /Kids [ 4 0 R 5 0 R ] /Type /Pages +>> +endobj +9 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 2000 +>> +stream +GauHL9lo&I&A@sBi95>`L**-B/]dTYilWPf(k1L[?HFZe2$(!=s1BlmNsQQ@kcQU\Q_?ijXJRo1+!'ZHbL9$T9-nYO`mkM?c;5tE_K_4:ALN'JX>_36,E!:^)YOV_oo*.&.jP(nAIf.UQO!5Q[?Vtu3&"6RSEbaZ!%okXnG/=:[B=2//ZE(h^X!L_kjml@7fFCaQ16'Aa[cIoI`l_;T,iQ5#Y?mr9oNPDEm'rXsN2/`SCEIZ4s7<#.4Xa=jkr_9=<\tDVq)]-=_s!-$lo;S!@`&@,AAa@pQU$VpBa!i*P[s$d_L_AM\B?$esZCeND_nJJN)HPE15%E5GodJFX>R6l$H365IMt4uUMo+Y,iJ)"FGgrU$*U]V;rPOgh$,BsZWA&D]$$"hGMLFIAYN-CI\EbH[;%#n6aMVf,]LX;VA`7P84)!ZVdpE&K+S(_k/B*C4X",HSk$>5*D/V!L]O@@BRi+XZA5Z`MZRM_;eok4o?1;RKbPaYI>Trp(o&r%`1+q:;T-:oYLsAm[;)99CeNaW']iR)^Ug>U:j.++`^C4>Ngc_]b6a"2jM-#MGSS^$a`bXNn)+UBktI>65*_4j2iel+e48"KBDoPKY(=2Es!bDn]^TSIdCr@^-YV>/FJdl[bm:!H!-`#_BKeC\IH4]&#j0E-'$1^rP'VO8hW*fIY:'#l*+G,gr9k_API\$`bT0DEM?[e8LWFd3'+49/.;\@N.OtNpE4Ei2g&,Ek\WI0ibsHu^DHMh")?#9X>o%;+Kci'\?]UO%t8VgqZ9&C=*`D>CdKSFDtM>7([=HB$74MrC!"N,9&+B=#mF&?<[\&3eVC_A'n_qI(udD^ugf\-/_H%b@Q3b'7d>NgOV48Llp+=95"CB"krYkU3]DimG);Y^X-\:QkN5s.u3It!Bub%mJ8Z+mn#ORs&7Gj;NnVmOWVm$ftXoMNH"~>endstream +endobj +10 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1422 +>> +stream +GauI69lo#Z&;KZQ'n(24Lk6nj7rAWuCi+$PF^d6V?cGtGj,u7AN'pP=om(m04q+6o#;9WsPVeinI_,FD-DVga6N>b`iLT,a2Wk)09n/32:F4Gh683eW:OaKlI[HJY&&:>5H3*(e_=KiFLr/\tr%Ah`,,dj]Z5M%'?!hb*\1tVb1)\N`V4K=Kp#=Xe@Da;2"?u,PJo5J@*m6%qA#QK7#SPhaGs(g_jFkIkkq$Z[`C\lej5<:WZ3H39+c^KNfkkh'dcdfrt=*%2Ppf\d,hF^A9sJ"C/K/gXa\g,3n)BK5BoTOo`.CWiLp^2')66iM<-c*2a+I$b(JUEAD<8VtBbiASEopZs`O/;p()#J6hIqd@Xq8-;VqR@J]1NCL6dATN/3>]Q8o-O6FYH0Lp!mrK-="Hbr?F\=9GiV#TqVUp@jRIdhk?HU5h[(C_A,.aFm$Al&SXWLj?9#"6]p)J$Q'eNY>Di&@PhJK*)1c\`U+[)W<\%Q2-DL<$)Y.nen36<*_U/EG'iu+M4EBbNRi&XM(Q+R+%S9oIA4`Z#$'R,<2cI62A,em3`G`%Ou<4!1j$MNp$*O.ebFAG`m,Re;bJ%"3"YtV-H[POVL4n=e.HE\?H:PN40ItnjLG-fGD*`]XXYN.'_q':*0QEqEeUfu-erbEt';1&g4n"(F8b%(WE]+s:-W^=!J7mPs]Rbnd-2OsbkfF?-q-rm]n1]90d(_VUN=]8qTcZBuar]'9916K-_;/cT)Q526T^EU!RcG?<]sN-/@%3#Vo[9+e]A!406T;a[0K^d&~>endstream +endobj +xref +0 11 +0000000000 65535 f +0000000061 00000 n +0000000102 00000 n +0000000209 00000 n +0000000321 00000 n +0000000514 00000 n +0000000708 00000 n +0000000776 00000 n +0000001087 00000 n +0000001152 00000 n +0000003243 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (opensource) + +/Info 7 0 R +/Root 6 0 R +/Size 11 +>> +startxref +4757 +%%EOF diff --git a/scripts/create_changes_summary_pdf.py b/scripts/create_changes_summary_pdf.py new file mode 100644 index 0000000..b1edefa --- /dev/null +++ b/scripts/create_changes_summary_pdf.py @@ -0,0 +1,204 @@ +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()