import copy import unittest from docx import Document from docx.opc.constants import RELATIONSHIP_TYPE as RT from docx.oxml import parse_xml from docx.oxml.ns import qn from document.evolutivo import construction_bdi_notes, construction_groups from test_evo_adjustments import body from test_evolutivo_documento import fixture, resolved LABELS = ['Administração central', 'Despesas financeiras', 'Seguros e garantias', 'Riscos', 'Tributos', 'Remuneração'] def composition(values): return [{'descricao': label, 'percentual': value} for label, value in zip(LABELS, values)] def notes(doc): root = parse_xml(doc.part.part_related_by(RT.FOOTNOTES).blob) return ' '.join(''.join(n.itertext(qn('w:t'))) for n in root if int(n.get(qn('w:id'))) > 0) class BdiSectionsTests(unittest.TestCase): def data(self): data = fixture((2021, 2022)) for year in data['anos']: c = year['construcao']['construcoes'][0] c.update(bdiComposicaoAdotada=composition([4, 1, 1, 2, 7, 10]), bdiJustificativa='Composição aditiva sobre o custo direto.') return data def render(self, data): imported = resolved(data) before = copy.deepcopy(imported) doc = Document() construction_bdi_notes(doc, construction_groups(imported['avaliacoes'])) self.assertEqual(imported, before) return doc def test_general_chapter_only_introduction_and_each_construction_has_total(self): data = self.data() for year in data['anos']: second = copy.deepcopy(year['construcao']['construcoes'][0]) second.update(id='second', seq=2, nome='Galpão B', bdi=20, bdiComposicaoAdotada=composition([3, 1, 1, 2, 6, 7])) year['construcao']['construcoes'].append(second) doc = body(resolved(data)) paragraphs = [p.text for p in doc.paragraphs] start = paragraphs.index('3.4.1.3 BDI e justificativa') end = paragraphs.index('3.4.1.3.1 Construção 1 — Galpão A') self.assertEqual(len(paragraphs[start + 1:end]), 2) self.assertTrue(paragraphs[start + 1].startswith('BDI (%):')) self.assertTrue(paragraphs[start + 2].startswith('O BDI informado em percentual')) self.assertIn('3.4.1.3.2 Construção 2 — Galpão B', paragraphs) tables = [t for t in doc.tables if t.cell(0, 0).text == 'Componente de BDI adotado'] self.assertEqual(len(tables), 2) for table, total in zip(tables, ['25,00%', '20,00%']): self.assertEqual([c.text for c in table.rows[-1].cells], ['Total do BDI', total]) self.assertEqual(len(table.rows), 8) self.assertEqual(len(table.columns), 2) self.assertTrue(all(run.bold for c in table.rows[-1].cells for p in c.paragraphs for run in p.runs)) self.assertFalse(any('Aplicável a Construção' in p for p in paragraphs[start:paragraphs.index('3.4.1.4 Depreciação e conservação')])) def test_year_changes_compare_components_and_totals_without_duplicate_subchapters(self): data = self.data() c = data['anos'][1]['construcao']['construcoes'][0] c.update(bdi=20, bdiComposicaoAdotada=composition([3, 1, 1, 2, 6, 7]), bdiJustificativa='Justificativa do segundo exercício.') doc = self.render(data) self.assertEqual(len(doc.tables), 1) table = doc.tables[0] self.assertEqual([c.text for c in table.rows[0].cells], ['Parâmetro / valor', 'IPTU 2022', 'IPTU 2023']) self.assertEqual([c.text for c in table.rows[1].cells], ['Administração central', '4,00%', '3,00%']) self.assertEqual([c.text for c in table.rows[-1].cells], ['Total do BDI', '25,00%', '20,00%']) text = '\n'.join(p.text for p in doc.paragraphs) self.assertIn('Justificativa do BDI (IPTU 2022): Composição aditiva', text) self.assertIn('Justificativa do BDI (IPTU 2023): Justificativa do segundo exercício.', text) def test_divergent_sum_does_not_replace_saved_bdi(self): data = self.data() for year in data['anos']: year['construcao']['construcoes'][0]['bdiComposicaoAdotada'][0]['percentual'] = 5 doc = self.render(data) self.assertEqual([c.text for c in doc.tables[0].rows[-2].cells], ['Soma dos componentes', '26,00%']) self.assertEqual([c.text for c in doc.tables[0].rows[-1].cells], ['Total do BDI', '25,00%']) self.assertIn('difere do percentual global registrado', notes(doc)) def test_missing_composition_and_private_reason_are_not_invented_or_exposed(self): data = self.data() for year in data['anos']: c = year['construcao']['construcoes'][0] c.pop('bdiComposicaoAdotada') c.update(bdi=0, bdiJustificativa='JUSTIFICATIVA INTERNA', bdiJustificativaInterna=True) doc = self.render(data) self.assertEqual(len(doc.tables[0].rows), 2) self.assertEqual([c.text for c in doc.tables[0].rows[-1].cells], ['Total do BDI', '0,00%']) self.assertNotIn('JUSTIFICATIVA INTERNA', '\n'.join(p.text for p in doc.paragraphs) + notes(doc)) self.assertIn('sem discriminar sua composição', notes(doc)) if __name__ == '__main__': unittest.main()