gui-sparim commited on
Commit
9c306e9
·
verified ·
1 Parent(s): ca18aa5

Estiliza equações de depreciação e retira referências à ferramenta interna

Browse files

Ross, K e Kd são equações editáveis com fração, expoente, subscrito e legendas de 8 pt. Remove menções à ferramenta e à versão do catálogo do laudo, preservando as fontes técnicas internas e os dados de origem. Validado com 113 testes e conferência visual.

document/equations.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Editable Word equations with compact legends for depreciation factors."""
2
+ from docx.oxml import OxmlElement
3
+ from docx.oxml.ns import qn
4
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
5
+ from docx.shared import Pt, RGBColor
6
+
7
+ from .formatters.paragraph import criar_paragrafo_formatado
8
+
9
+
10
+ def _run(text, variable=False):
11
+ run = OxmlElement('m:r')
12
+ props = OxmlElement('m:rPr')
13
+ style = OxmlElement('m:sty'); style.set(qn('m:val'), 'i' if variable else 'p')
14
+ props.append(style); run.append(props)
15
+ font_props = OxmlElement('w:rPr')
16
+ font = OxmlElement('w:rFonts')
17
+ font.set(qn('w:ascii'), 'Cambria Math'); font.set(qn('w:hAnsi'), 'Cambria Math')
18
+ font_props.append(font)
19
+ size = OxmlElement('w:sz'); size.set(qn('w:val'), '28'); font_props.append(size)
20
+ run.append(font_props)
21
+ value = OxmlElement('m:t'); value.text = text
22
+ value.set(qn('xml:space'), 'preserve'); run.append(value)
23
+ return run
24
+
25
+
26
+ def _fraction(numerator, denominator):
27
+ fraction = OxmlElement('m:f')
28
+ for name, children in [('num', numerator), ('den', denominator)]:
29
+ node = OxmlElement('m:' + name)
30
+ for child in children: node.append(child)
31
+ fraction.append(node)
32
+ return fraction
33
+
34
+
35
+ def _script(kind, base, script):
36
+ node = OxmlElement('m:' + kind)
37
+ for name, child in [('e', base), ('sup' if kind=='sSup' else 'sub', script)]:
38
+ content = OxmlElement('m:' + name); content.append(child); node.append(content)
39
+ return node
40
+
41
+
42
+ def depreciation_equations(doc):
43
+ formulas = [
44
+ ([_run('Ross',True), _run(' = '), _fraction([_run('q',True), _run(' + '), _script('sSup',_run('q',True),_run('2'))],[_run('2')])],
45
+ 'Ross: parcela de depreciação associada à idade; q: fração de vida útil consumida, obtida dividindo o percentual de vida útil consumida por 100.'),
46
+ ([_run('K',True),_run(' = 1 − (1 − '),_run('Ross',True),_run(') × (1 − '),_run('H',True),_run(')')],
47
+ 'K: coeficiente de depreciação de Ross-Heidecke; H: coeficiente correspondente ao estado de conservação adotado.'),
48
+ ([_script('sSub',_run('K',True),_run('d',True)),_run(' = '),_run('R',True),_run(' + (1 − '),_run('K',True),_run(') × (1 − '),_run('R',True),_run(')')],
49
+ 'Kd: fator remanescente aplicado ao custo de reedição, com consideração do valor residual; R: valor residual em forma decimal (percentual ÷ 100); K: coeficiente de depreciação.'),
50
+ ]
51
+ for index,(elements, legend) in enumerate(formulas):
52
+ paragraph = doc.add_paragraph()
53
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
54
+ paragraph.paragraph_format.space_before = Pt(10)
55
+ paragraph.paragraph_format.space_after = Pt(4)
56
+ paragraph.paragraph_format.keep_with_next = True
57
+ paragraph.paragraph_format.keep_together = True
58
+ math = OxmlElement('m:oMath')
59
+ for element in elements: math.append(element)
60
+ paragraph._p.append(math)
61
+ note = criar_paragrafo_formatado(doc,legend,tamanho=8,cor=RGBColor(70,70,70),
62
+ alinhamento=WD_ALIGN_PARAGRAPH.LEFT,espaco_depois=8)
63
+ note.paragraph_format.keep_together = True
64
+ note.paragraph_format.keep_with_next = index < len(formulas)-1
document/evolutivo.py CHANGED
@@ -15,6 +15,7 @@ from .mesa_content import content_for
15
  from .evo_adjustments import REDUCERS, applied_reducers
16
  from .fundamentacao import number, global_foundation
17
  from .footnotes import add_footnote, add_first_footnote, order_footnotes
 
18
  from .formatters.table import set_table_font_size
19
  from .formatters.table_fit import fit_table_to_page
20
  from .anexos.metodologia import (_gerar_variaveis, _adicionar_pesquisa,
@@ -247,14 +248,12 @@ def gerar_corpo_evolutivo(doc, imported, num, caracteristicas_refs=None):
247
  construction_cub_notes(doc,groups)
248
  heading(doc,num,'BDI e justificativa',4)
249
  definitions_for(doc,rows,['bdi'])
250
- add_body_text(doc,'O BDI informado em percentual é convertido no multiplicador 1 + BDI/100. As referências gerais da MESA orientam a análise; não constituem, por si, uma composição de BDI efetivamente adotada.')
251
  construction_bdi_notes(doc,groups)
252
  heading(doc,num,'Depreciação e conservação',4)
253
- definitions_for(doc,rows,['depreciation','residual','kd','conservation'])
254
- add_body_text(doc,'Na expressão de Ross-Heidecke, q é a fração de vida útil consumida e H é o coeficiente de conservação. K representa a depreciação; R é o residual em forma decimal; Kd é o fator remanescente aplicado ao custo.')
255
- equation(doc,'q = percentual de vida útil / 100; Ross = q/2 + q²/2')
256
- equation(doc,'K = 1 − (1 − Ross) × (1 − H); Kd = R + (1 − K) × (1 − R)')
257
- add_body_text(doc,'A MESA registra a curva de Ross com seis casas decimais, K com quatro e Kd com três. Os resultados abaixo são transcritos dos registros salvos, sem recompor os valores a partir de coeficientes arredondados para exibição.')
258
  construction_depreciation_notes(doc,groups)
259
  heading(doc,num,'Cálculo por construção e exercício',4)
260
  for entries in groups.values():
@@ -444,7 +443,7 @@ def construction_bdi_notes(doc, groups):
444
  notes.setdefault('Justificativa do BDI: '+note,[]).append((row,c,i))
445
  reference = next((item for item in content_for(source(row))['referencias'].get('bdiTiposConstrucao',[]) if item.get('tipo')==c.get('tipoConstrucao')),None)
446
  if reference:
447
- notes.setdefault(f"Referência da MESA para {reference['tipo']}: BDI {reference['bdi']}. O percentual adotado consta no quadro de cálculo.",[]).append((row,c,i))
448
  composition = c.get('bdiComposicaoAdotada')
449
  if isinstance(composition,list) and composition:
450
  details = [{key:item.get(key) for key in ('descricao','percentual')} for item in composition]
@@ -581,14 +580,6 @@ def gerar_especificacao_evolutivo(doc,imported,refs):
581
  first = foundations[rows[0]['id']][key] if key else foundations[rows[0]['id']]
582
  compared(doc,rows,[(item['label'],lambda row,i=index,k=key: (foundations[row['id']][k] if k else foundations[row['id']])['items'][i]['grade'] + ' / ' + str((foundations[row['id']][k] if k else foundations[row['id']])['items'][i]['points'] if (foundations[row['id']][k] if k else foundations[row['id']])['items'][i]['points'] is not None else '—') + ' ponto(s)') for index,item in enumerate(first['items'])])
583
  grouped_notes(doc,rows,lambda row,k=key: ' '.join(f"{item['label']}: {item['detail']}" for item in (foundations[row['id']][k] if k else foundations[row['id']])['items']),'Evidências e critérios')
584
- content_versions = OrderedDict()
585
  for row in rows:
586
  f = foundations[row['id']]['terrain']
587
  if f.get('missingRequirements'): add_body_text(doc,f"{ref(row)} — o Grau III do terreno depende da declaração dos requisitos adicionais; enquadramento pendente.")
588
- catalog = content_for(source(row))
589
- saved = source(row).get('documentacaoTecnica')
590
- note = f"Conteúdo técnico MESA, versão documental {catalog['versao']}, identificação {catalog['identificador']}. " + ('Pacote identificado na exportação; dados e referências históricas do cálculo preservados.' if saved and saved.get('origem') == 'catalogo_exportacao' else 'Pacote preservado na avaliação.' if saved else 'Arquivo sem pacote documental histórico identificado; utilizadas as explicações gerais do catálogo sincronizado, preservando os dados e as referências de cálculo salvos.')
591
- content_versions.setdefault(note,[]).append(ref(row))
592
- for note,references in content_versions.items():
593
- paragraph = add_body_text(doc,note + (f" Aplicável a {', '.join(references)}." if len(content_versions)>1 else ''))
594
- paragraph.paragraph_format.keep_together = True
 
15
  from .evo_adjustments import REDUCERS, applied_reducers
16
  from .fundamentacao import number, global_foundation
17
  from .footnotes import add_footnote, add_first_footnote, order_footnotes
18
+ from .equations import depreciation_equations
19
  from .formatters.table import set_table_font_size
20
  from .formatters.table_fit import fit_table_to_page
21
  from .anexos.metodologia import (_gerar_variaveis, _adicionar_pesquisa,
 
248
  construction_cub_notes(doc,groups)
249
  heading(doc,num,'BDI e justificativa',4)
250
  definitions_for(doc,rows,['bdi'])
251
+ add_body_text(doc,'O BDI informado em percentual é convertido no multiplicador 1 + BDI/100. Os percentuais de referência orientam a análise; não constituem, por si, uma composição de BDI efetivamente adotada.')
252
  construction_bdi_notes(doc,groups)
253
  heading(doc,num,'Depreciação e conservação',4)
254
+ add_body_text(doc,'A depreciação física considera a vida útil consumida e o estado de conservação, pelo método de Ross-Heidecke. O valor residual integra o fator remanescente aplicado ao custo de reedição.').paragraph_format.keep_with_next = True
255
+ depreciation_equations(doc)
256
+ add_body_text(doc,'Os resultados apresentados são os registrados na avaliação, sem recomposição a partir dos coeficientes arredondados para exibição.')
 
 
257
  construction_depreciation_notes(doc,groups)
258
  heading(doc,num,'Cálculo por construção e exercício',4)
259
  for entries in groups.values():
 
443
  notes.setdefault('Justificativa do BDI: '+note,[]).append((row,c,i))
444
  reference = next((item for item in content_for(source(row))['referencias'].get('bdiTiposConstrucao',[]) if item.get('tipo')==c.get('tipoConstrucao')),None)
445
  if reference:
446
+ notes.setdefault(f"Referência técnica para {reference['tipo']}: BDI {reference['bdi']}. O percentual adotado consta no quadro de cálculo.",[]).append((row,c,i))
447
  composition = c.get('bdiComposicaoAdotada')
448
  if isinstance(composition,list) and composition:
449
  details = [{key:item.get(key) for key in ('descricao','percentual')} for item in composition]
 
580
  first = foundations[rows[0]['id']][key] if key else foundations[rows[0]['id']]
581
  compared(doc,rows,[(item['label'],lambda row,i=index,k=key: (foundations[row['id']][k] if k else foundations[row['id']])['items'][i]['grade'] + ' / ' + str((foundations[row['id']][k] if k else foundations[row['id']])['items'][i]['points'] if (foundations[row['id']][k] if k else foundations[row['id']])['items'][i]['points'] is not None else '—') + ' ponto(s)') for index,item in enumerate(first['items'])])
582
  grouped_notes(doc,rows,lambda row,k=key: ' '.join(f"{item['label']}: {item['detail']}" for item in (foundations[row['id']][k] if k else foundations[row['id']])['items']),'Evidências e critérios')
 
583
  for row in rows:
584
  f = foundations[row['id']]['terrain']
585
  if f.get('missingRequirements'): add_body_text(doc,f"{ref(row)} — o Grau III do terreno depende da declaração dos requisitos adicionais; enquadramento pendente.")
 
 
 
 
 
 
 
document/footnotes.py CHANGED
@@ -9,6 +9,7 @@ from docx.shared import Pt
9
  from docx.text.paragraph import Paragraph
10
  from copy import deepcopy
11
  import re
 
12
 
13
 
14
  def add_first_footnote(doc, pattern, text):
@@ -72,6 +73,7 @@ def order_footnotes(doc):
72
 
73
 
74
  def add_footnote(doc, paragraph, text):
 
75
  try:
76
  part = doc.part.part_related_by(RT.FOOTNOTES)
77
  root = parse_xml(part.blob)
 
9
  from docx.text.paragraph import Paragraph
10
  from copy import deepcopy
11
  import re
12
+ from .public_text import public_text
13
 
14
 
15
  def add_first_footnote(doc, pattern, text):
 
73
 
74
 
75
  def add_footnote(doc, paragraph, text):
76
+ text = public_text(text)
77
  try:
78
  part = doc.part.part_related_by(RT.FOOTNOTES)
79
  root = parse_xml(part.blob)
document/formatters/paragraph.py CHANGED
@@ -5,6 +5,7 @@ from docx import Document
5
  from docx.shared import Pt, Inches, Cm, RGBColor
6
  from docx.enum.text import WD_ALIGN_PARAGRAPH
7
  from typing import Optional, Tuple, Union
 
8
 
9
 
10
  def aplicar_cor_run(run, cor: Optional[Union[Tuple[int, int, int], RGBColor]]) -> None:
@@ -56,7 +57,7 @@ def criar_paragrafo_formatado(
56
  Parágrafo criado
57
  """
58
  p = doc.add_paragraph()
59
- run = p.add_run(texto)
60
 
61
  run.bold = negrito
62
  run.underline = sublinhado
 
5
  from docx.shared import Pt, Inches, Cm, RGBColor
6
  from docx.enum.text import WD_ALIGN_PARAGRAPH
7
  from typing import Optional, Tuple, Union
8
+ from ..public_text import public_text
9
 
10
 
11
  def aplicar_cor_run(run, cor: Optional[Union[Tuple[int, int, int], RGBColor]]) -> None:
 
57
  Parágrafo criado
58
  """
59
  p = doc.add_paragraph()
60
+ run = p.add_run(public_text(texto))
61
 
62
  run.bold = negrito
63
  run.underline = sublinhado
document/formatters/table.py CHANGED
@@ -11,6 +11,7 @@ from collections.abc import Sequence as SequenceABC
11
  from typing import List, Optional, Sequence, Union, Dict, Any
12
 
13
  from .paragraph import aplicar_cor_run
 
14
 
15
  WD_ALIGN_VERTICAL = WD_CELL_VERTICAL_ALIGNMENT
16
 
@@ -89,7 +90,7 @@ def formatar_celula_tabela(cell, texto: str, negrito: bool = False, cor=None,
89
 
90
  cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
91
 
92
- run = p.add_run(texto)
93
  run.font.size = Pt(9)
94
  run.font.name = 'Arial'
95
  run.bold = negrito
@@ -266,7 +267,7 @@ def criar_celula_cabecalho_tabela(cell, texto: str, recuo_primeira_linha_cm: flo
266
  p.paragraph_format.first_line_indent = Cm(recuo_primeira_linha_cm)
267
  p.alignment = WD_ALIGN_PARAGRAPH.LEFT
268
 
269
- run = p.add_run(texto)
270
  run.bold = True
271
  run.underline = True
272
  run.font.size = Pt(11)
@@ -292,7 +293,7 @@ def criar_celula_dados_tabela(cell, texto: str, is_label: bool = False) -> None:
292
  p.paragraph_format.space_before = Pt(0)
293
  p.paragraph_format.space_after = Pt(0)
294
 
295
- run = p.add_run(texto)
296
  run.bold = is_label
297
  run.font.size = Pt(9)
298
  run.font.name = 'Arial'
 
11
  from typing import List, Optional, Sequence, Union, Dict, Any
12
 
13
  from .paragraph import aplicar_cor_run
14
+ from ..public_text import public_text
15
 
16
  WD_ALIGN_VERTICAL = WD_CELL_VERTICAL_ALIGNMENT
17
 
 
90
 
91
  cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
92
 
93
+ run = p.add_run(public_text(texto))
94
  run.font.size = Pt(9)
95
  run.font.name = 'Arial'
96
  run.bold = negrito
 
267
  p.paragraph_format.first_line_indent = Cm(recuo_primeira_linha_cm)
268
  p.alignment = WD_ALIGN_PARAGRAPH.LEFT
269
 
270
+ run = p.add_run(public_text(texto))
271
  run.bold = True
272
  run.underline = True
273
  run.font.size = Pt(11)
 
293
  p.paragraph_format.space_before = Pt(0)
294
  p.paragraph_format.space_after = Pt(0)
295
 
296
+ run = p.add_run(public_text(texto))
297
  run.bold = is_label
298
  run.font.size = Pt(9)
299
  run.font.name = 'Arial'
document/public_text.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Public wording for report text; internal tool names stay out of the report."""
2
+ import re
3
+
4
+
5
+ def public_text(text):
6
+ text = str(text)
7
+ text = re.sub(r'\bmodelo MESA\b', 'modelo estatístico', text)
8
+ for original, replacement in [
9
+ ('da MESA', 'de referência'), ('do MESA', 'da avaliação de origem'),
10
+ ('no MESA', 'na avaliação de origem'), ('na MESA', 'na avaliação de origem'),
11
+ ('pela MESA', 'pela avaliação de origem'), ('pelo MESA', 'pela avaliação de origem'),
12
+ ('a MESA', 'a avaliação de origem'), ('A MESA', 'A avaliação de origem'),
13
+ ('o MESA', 'a avaliação de origem'), ('O MESA', 'A avaliação de origem'),
14
+ ]:
15
+ text = text.replace(original, replacement)
16
+ return re.sub(r'\bMESA\b', 'avaliação de origem', text)
tests/test_equations.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import io
3
+ import unittest
4
+ import zipfile
5
+
6
+ from docx import Document
7
+ from docx.oxml import parse_xml
8
+ from docx.oxml.ns import qn
9
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
10
+ from unittest.mock import patch
11
+
12
+ from document.equations import depreciation_equations
13
+ from document.generator import LaudoGenerator
14
+ from document.public_text import public_text
15
+ from document.footnotes import add_footnote
16
+ from document.formatters import add_body_text
17
+ from test_evolutivo_documento import fixture,resolved
18
+
19
+
20
+ class DepreciationEquationTests(unittest.TestCase):
21
+ def test_editable_equations_keep_fraction_power_subscript_and_small_legends(self):
22
+ doc=Document();depreciation_equations(doc)
23
+ stream=io.BytesIO();doc.save(stream);stream.seek(0)
24
+ reopened=Document(stream)
25
+ math=list(reopened.element.body.iter(qn('m:oMath')))
26
+ self.assertEqual(len(math),3)
27
+ self.assertEqual(len(list(math[0].iter(qn('m:f')))),1)
28
+ self.assertEqual(len(list(math[0].iter(qn('m:sSup')))),1)
29
+ self.assertEqual(len(list(math[2].iter(qn('m:sSub')))),1)
30
+ texts=[''.join(t.text or '' for t in formula.iter(qn('m:t'))) for formula in math]
31
+ self.assertEqual(texts,['Ross = q + q22','K = 1 − (1 − Ross) × (1 − H)','Kd = R + (1 − K) × (1 − R)'])
32
+ self.assertEqual(len(reopened.paragraphs),6)
33
+ for index in (0,2,4):
34
+ self.assertEqual(reopened.paragraphs[index].alignment,WD_ALIGN_PARAGRAPH.CENTER)
35
+ self.assertTrue(reopened.paragraphs[index].paragraph_format.keep_with_next)
36
+ legend=reopened.paragraphs[index+1]
37
+ self.assertEqual({r.font.size.pt for r in legend.runs},{8})
38
+ self.assertIn('dividindo o percentual',reopened.paragraphs[1].text)
39
+ self.assertIn('estado de conservação',reopened.paragraphs[3].text)
40
+ self.assertIn('percentual ÷ 100',reopened.paragraphs[5].text)
41
+
42
+ def test_internal_references_stay_out_of_body_tables_and_footnotes(self):
43
+ imported=resolved(fixture((2021,)))
44
+ row=imported['avaliacoes'][0]
45
+ row['observacoes']='Resultados preservados no MESA.'
46
+ row['complementos']={'justificativa_fc':'Condição registrada no modelo MESA.'}
47
+ original=copy.deepcopy(imported)
48
+ doc=Document()
49
+ with patch('document.evolutivo.matching_local',return_value=(None,'')):
50
+ LaudoGenerator()._gerar_corpo(doc,{'avaliacoes_importadas':imported},{})
51
+ LaudoGenerator()._gerar_cabecalho(doc,{'modelo_avaliacao':'modelo MESA'})
52
+ add_footnote(doc,add_body_text(doc,'Referência técnica'),'Coeficientes da MESA preservados na avaliação.')
53
+ stream=io.BytesIO();doc.save(stream)
54
+ with zipfile.ZipFile(stream) as archive:
55
+ for name in ['word/document.xml','word/footnotes.xml']:
56
+ root=parse_xml(archive.read(name))
57
+ text=' '.join(t.text or '' for t in root.iter(qn('w:t')))
58
+ self.assertNotIn('MESA',text)
59
+ self.assertNotIn('versão documental',text)
60
+ self.assertNotIn('catálogo sincronizado',text)
61
+ self.assertEqual(imported,original)
62
+
63
+ def test_public_wording_preserves_technical_names_and_ordinary_words(self):
64
+ self.assertEqual(public_text('Método de Ross-Heidecke; ABNT NBR 14653-2; CUB.'),'Método de Ross-Heidecke; ABNT NBR 14653-2; CUB.')
65
+ self.assertEqual(public_text('modelo MESA'),'modelo estatístico')
66
+ self.assertEqual(public_text('salvo no MESA'),'salvo na avaliação de origem')
67
+ self.assertEqual(public_text('mesa de apoio'),'mesa de apoio')
68
+
69
+
70
+ if __name__=='__main__':
71
+ unittest.main()
tests/test_evolutivo_documento.py CHANGED
@@ -242,7 +242,7 @@ class EvolutivoDocumentTests(unittest.TestCase):
242
  conclusion_table(doc,imported)
243
  text = all_text(doc)
244
  for part in ['3.3 AVALIAÇÃO DO TERRENO','3.3.1.1 Variáveis','3.4 AVALIAÇÃO DAS CONSTRUÇÕES','3.4.1.3 BDI','3.5 AVALIAÇÃO DO IMÓVEL OBJETO',
245
- 'Ross-Heidecke','CUNIT = CUB','Kd = R +','Unidade autônoma da gleba','Composição justificada do caso','50.000,00','4.126,73','10/2021','R$ 427.500,00','R$ 420.000,00','quatrocentos e vinte mil reais','Critério da adoção','CUB composto','Caracterização salva']:
246
  self.assertIn(part,text)
247
  self.assertNotIn('SEGREDO INTERNO',text)
248
  self.assertNotIn('11/2021',text)
 
242
  conclusion_table(doc,imported)
243
  text = all_text(doc)
244
  for part in ['3.3 AVALIAÇÃO DO TERRENO','3.3.1.1 Variáveis','3.4 AVALIAÇÃO DAS CONSTRUÇÕES','3.4.1.3 BDI','3.5 AVALIAÇÃO DO IMÓVEL OBJETO',
245
+ 'Ross-Heidecke','CUNIT = CUB','Kd: fator remanescente','Unidade autônoma da gleba','Composição justificada do caso','50.000,00','4.126,73','10/2021','R$ 427.500,00','R$ 420.000,00','quatrocentos e vinte mil reais','Critério da adoção','CUB composto','Caracterização salva']:
246
  self.assertIn(part,text)
247
  self.assertNotIn('SEGREDO INTERNO',text)
248
  self.assertNotIn('11/2021',text)