Spaces:
Sleeping
Sleeping
Unifica composição das áreas com construção na primeira coluna
Browse filesReúne as áreas equivalentes em uma tabela, preservando nome da construção e exercícios quando a composição variar. Mantém dimensões e coeficientes, com ajuste automático da fonte. Validação: 108 testes e renderização da cobaia.
- document/evolutivo.py +11 -6
- tests/test_evo_adjustments.py +37 -1
document/evolutivo.py
CHANGED
|
@@ -352,19 +352,24 @@ def construction_characteristics(doc, groups):
|
|
| 352 |
for values,subset in variants.items():
|
| 353 |
records.append([entry_scope(subset,groups,show_base=False)]+list(values))
|
| 354 |
if len(records)>1: table(doc,records,[1.6,1.6,1.2,1.1,1.5],font_size=7)
|
| 355 |
-
|
| 356 |
for entries in groups.values():
|
|
|
|
| 357 |
for row,c,i in entries:
|
| 358 |
details = [{key:a.get(key) for key in ('descricao','area','coeficiente')} for a in c.get('areasEquivalentes') or []]
|
| 359 |
# A single area at coefficient 1 contributes no additional explanation.
|
| 360 |
if not details or (len(details)==1 and number(details[0].get('coeficiente'))==1
|
| 361 |
and number(c.get('areaTotal'))==number(c.get('areaCalculada'))==number(details[0].get('area'))): continue
|
| 362 |
areas.setdefault(json.dumps(details,sort_keys=True,ensure_ascii=False),[]).append((row,c,i))
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
|
| 369 |
|
| 370 |
def construction_cub_notes(doc, groups):
|
|
|
|
| 352 |
for values,subset in variants.items():
|
| 353 |
records.append([entry_scope(subset,groups,show_base=False)]+list(values))
|
| 354 |
if len(records)>1: table(doc,records,[1.6,1.6,1.2,1.1,1.5],font_size=7)
|
| 355 |
+
area_records = [['Construção / referência','Tipo de área','Área real (m²)','Coeficiente','Parcela equivalente (m²)']]
|
| 356 |
for entries in groups.values():
|
| 357 |
+
areas = OrderedDict()
|
| 358 |
for row,c,i in entries:
|
| 359 |
details = [{key:a.get(key) for key in ('descricao','area','coeficiente')} for a in c.get('areasEquivalentes') or []]
|
| 360 |
# A single area at coefficient 1 contributes no additional explanation.
|
| 361 |
if not details or (len(details)==1 and number(details[0].get('coeficiente'))==1
|
| 362 |
and number(c.get('areaTotal'))==number(c.get('areaCalculada'))==number(details[0].get('area'))): continue
|
| 363 |
areas.setdefault(json.dumps(details,sort_keys=True,ensure_ascii=False),[]).append((row,c,i))
|
| 364 |
+
for identity,subset in areas.items():
|
| 365 |
+
label = entry_scope(subset,groups,show_base=False)
|
| 366 |
+
area_records.extend([
|
| 367 |
+
[label,a.get('descricao') or 'Não informado',fmt(a.get('area')),fmt(a.get('coeficiente'),4),
|
| 368 |
+
fmt(number(a['area'])*number(a['coeficiente'])) if number(a.get('area')) is not None and number(a.get('coeficiente')) is not None else 'Não informado'] for a in json.loads(identity)])
|
| 369 |
+
if len(area_records)>1:
|
| 370 |
+
add_body_text(doc,'Composição das áreas').paragraph_format.keep_with_next = True
|
| 371 |
+
obj = table(doc,area_records,[2.1,2.8,1,1,1.4],auto_fit=False)
|
| 372 |
+
fit_table_to_page(doc,obj)
|
| 373 |
|
| 374 |
|
| 375 |
def construction_cub_notes(doc, groups):
|
tests/test_evo_adjustments.py
CHANGED
|
@@ -5,7 +5,7 @@ from unittest.mock import patch
|
|
| 5 |
|
| 6 |
from docx import Document
|
| 7 |
from document.evo_adjustments import applied_reducers, visible_memory
|
| 8 |
-
from document.evolutivo import gerar_corpo_evolutivo, condition_description
|
| 9 |
from document.avaliacoes_importadas import calculation_sections
|
| 10 |
from document.numbering import NumeradorSecoes
|
| 11 |
from test_evolutivo_documento import fixture, resolved, all_text
|
|
@@ -19,6 +19,42 @@ def body(imported):
|
|
| 19 |
|
| 20 |
|
| 21 |
class AppliedAdjustmentsTests(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
def test_neutral_execution_overrides_selected_conditions_and_reference_rates(self):
|
| 23 |
row=resolved(fixture((2021,)))['avaliacoes'][0]
|
| 24 |
row['evolutivo']['resultadoComposicao']['redutor88I']=.7
|
|
|
|
| 5 |
|
| 6 |
from docx import Document
|
| 7 |
from document.evo_adjustments import applied_reducers, visible_memory
|
| 8 |
+
from document.evolutivo import gerar_corpo_evolutivo, condition_description, construction_characteristics, construction_groups
|
| 9 |
from document.avaliacoes_importadas import calculation_sections
|
| 10 |
from document.numbering import NumeradorSecoes
|
| 11 |
from test_evolutivo_documento import fixture, resolved, all_text
|
|
|
|
| 19 |
|
| 20 |
|
| 21 |
class AppliedAdjustmentsTests(unittest.TestCase):
|
| 22 |
+
def test_area_compositions_share_one_table_with_construction_names(self):
|
| 23 |
+
data=fixture((2021,2022))
|
| 24 |
+
for year in data['anos']:
|
| 25 |
+
first=year['construcao']['construcoes'][0]
|
| 26 |
+
first.update(nome='Casa principal',areaTotal=90,areaCalculada=87.5,
|
| 27 |
+
areasEquivalentes=[{'descricao':'área privativa','area':80,'coeficiente':1},
|
| 28 |
+
{'descricao':'varandas','area':10,'coeficiente':.75}])
|
| 29 |
+
second=copy.deepcopy(first)
|
| 30 |
+
second.update(id='segundo',seq=2,nome='Edícula de apoio',areaTotal=50,areaCalculada=45,
|
| 31 |
+
areasEquivalentes=[{'descricao':'área privativa','area':40,'coeficiente':1},
|
| 32 |
+
{'descricao':'área de serviço','area':10,'coeficiente':.5}])
|
| 33 |
+
year['construcao']['construcoes'].append(second)
|
| 34 |
+
doc=Document()
|
| 35 |
+
construction_characteristics(doc,construction_groups(resolved(data)['avaliacoes']))
|
| 36 |
+
tables=[t for t in doc.tables if t.rows[0].cells[1].text=='Tipo de área']
|
| 37 |
+
self.assertEqual(len(tables),1)
|
| 38 |
+
rows=[[c.text for c in row.cells] for row in tables[0].rows]
|
| 39 |
+
self.assertEqual(rows[1:], [
|
| 40 |
+
['Construção 1 — Casa principal','área privativa','80,00','1,0000','80,00'],
|
| 41 |
+
['Construção 1 — Casa principal','varandas','10,00','0,7500','7,50'],
|
| 42 |
+
['Construção 2 — Edícula de apoio','área privativa','40,00','1,0000','40,00'],
|
| 43 |
+
['Construção 2 — Edícula de apoio','área de serviço','10,00','0,5000','5,00']])
|
| 44 |
+
self.assertEqual([p.text for p in doc.paragraphs if p.text.startswith('Composição das áreas')],['Composição das áreas'])
|
| 45 |
+
|
| 46 |
+
def test_area_changes_preserve_exercise_scope_in_the_unified_table(self):
|
| 47 |
+
data=fixture((2021,2022))
|
| 48 |
+
data['anos'][1]['construcao']['construcoes'][0]['areasEquivalentes'][0]['coeficiente']=.8
|
| 49 |
+
doc=Document()
|
| 50 |
+
construction_characteristics(doc,construction_groups(resolved(data)['avaliacoes']))
|
| 51 |
+
table=next(t for t in doc.tables if t.rows[0].cells[1].text=='Tipo de área')
|
| 52 |
+
self.assertEqual(len(table.rows),3)
|
| 53 |
+
self.assertIn('IPTU 2022',table.cell(1,0).text)
|
| 54 |
+
self.assertIn('IPTU 2023',table.cell(2,0).text)
|
| 55 |
+
self.assertEqual(table.cell(1,4).text,'75,00')
|
| 56 |
+
self.assertEqual(table.cell(2,4).text,'80,00')
|
| 57 |
+
|
| 58 |
def test_neutral_execution_overrides_selected_conditions_and_reference_rates(self):
|
| 59 |
row=resolved(fixture((2021,)))['avaliacoes'][0]
|
| 60 |
row['evolutivo']['resultadoComposicao']['redutor88I']=.7
|