Spaces:
Sleeping
Sleeping
Guilherme Silberfarb Costa commited on
Commit ·
3bda4f3
1
Parent(s): d4612a2
Review venal values per SIAT exercise
Browse files- extractors/pdf_extractor.py +11 -7
- frontend/src/App.jsx +10 -6
- tests/test_pdf_extractor.py +5 -1
extractors/pdf_extractor.py
CHANGED
|
@@ -22,18 +22,18 @@ def anos_venais_ausentes(anos):
|
|
| 22 |
|
| 23 |
|
| 24 |
def anos_venais_para_revisao(registros):
|
| 25 |
-
"""Identifica anos repetidos ou com
|
| 26 |
contagem_por_ano = {}
|
| 27 |
-
|
| 28 |
-
for ano,
|
| 29 |
contagem_por_ano[ano] = contagem_por_ano.get(ano, 0) + 1
|
| 30 |
-
if
|
| 31 |
-
|
| 32 |
|
| 33 |
return [
|
| 34 |
int(ano)
|
| 35 |
for ano in contagem_por_ano
|
| 36 |
-
if contagem_por_ano[ano] > 1 or ano in
|
| 37 |
]
|
| 38 |
|
| 39 |
|
|
@@ -175,7 +175,11 @@ def extrair_dados_pdf(pdf_file) -> Optional[Dict]:
|
|
| 175 |
try:
|
| 176 |
ano = re.search(r'(\d{4})', m).group(1)
|
| 177 |
valores = re.findall(r'(\d{1,3}(?:\.\d{3})*,\d{2})', m)
|
| 178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
except (AttributeError, IndexError):
|
| 180 |
continue
|
| 181 |
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
def anos_venais_para_revisao(registros):
|
| 25 |
+
"""Identifica anos repetidos ou com mais de uma linha de lançamento venal."""
|
| 26 |
contagem_por_ano = {}
|
| 27 |
+
anos_com_linhas_adicionais = set()
|
| 28 |
+
for ano, quantidade_linhas, _ in registros:
|
| 29 |
contagem_por_ano[ano] = contagem_por_ano.get(ano, 0) + 1
|
| 30 |
+
if quantidade_linhas > 1:
|
| 31 |
+
anos_com_linhas_adicionais.add(ano)
|
| 32 |
|
| 33 |
return [
|
| 34 |
int(ano)
|
| 35 |
for ano in contagem_por_ano
|
| 36 |
+
if contagem_por_ano[ano] > 1 or ano in anos_com_linhas_adicionais
|
| 37 |
]
|
| 38 |
|
| 39 |
|
|
|
|
| 175 |
try:
|
| 176 |
ano = re.search(r'(\d{4})', m).group(1)
|
| 177 |
valores = re.findall(r'(\d{1,3}(?:\.\d{3})*,\d{2})', m)
|
| 178 |
+
# Cada lançamento traz seis valores monetários: construção, terreno,
|
| 179 |
+
# total, alíquota, IPTU e TCL/multa. Mais de seis indica outra linha
|
| 180 |
+
# de lançamento para o mesmo exercício e exige conferência manual.
|
| 181 |
+
linhas_venais = len(valores) // 6
|
| 182 |
+
registros_venais.append((ano, linhas_venais, valores[2] if len(valores) >= 3 else None))
|
| 183 |
except (AttributeError, IndexError):
|
| 184 |
continue
|
| 185 |
|
frontend/src/App.jsx
CHANGED
|
@@ -182,7 +182,7 @@ function App() {
|
|
| 182 |
const [databaseColumns, setDatabaseColumns] = useState([]);
|
| 183 |
|
| 184 |
const [error, setError] = useState("");
|
| 185 |
-
const [
|
| 186 |
const [result, setResult] = useState(null);
|
| 187 |
|
| 188 |
useEffect(() => {
|
|
@@ -406,7 +406,7 @@ function App() {
|
|
| 406 |
|
| 407 |
setLoadingPdf(true);
|
| 408 |
setError("");
|
| 409 |
-
|
| 410 |
|
| 411 |
try {
|
| 412 |
const formData = new FormData();
|
|
@@ -439,12 +439,12 @@ function App() {
|
|
| 439 |
avisos.push(
|
| 440 |
`${anosRevisao.length === 1 ? "O ano" : "Os anos"} ${anosRevisao.join(", ")} ${
|
| 441 |
anosRevisao.length === 1 ? "aparece" : "aparecem"
|
| 442 |
-
} mais de uma vez ou
|
| 443 |
"Foi inserido como XXX.XXX,XX para revisão.",
|
| 444 |
);
|
| 445 |
}
|
| 446 |
if (avisos.length) {
|
| 447 |
-
|
| 448 |
}
|
| 449 |
} catch (err) {
|
| 450 |
setError(String(err));
|
|
@@ -478,7 +478,7 @@ function App() {
|
|
| 478 |
setForm(buildEmptyForm(options));
|
| 479 |
setDatabaseColumns([]);
|
| 480 |
setError("");
|
| 481 |
-
|
| 482 |
setResult(null);
|
| 483 |
};
|
| 484 |
|
|
@@ -787,7 +787,11 @@ function App() {
|
|
| 787 |
</button>
|
| 788 |
</div>
|
| 789 |
|
| 790 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
| 791 |
|
| 792 |
<label>
|
| 793 |
Inscrição
|
|
|
|
| 182 |
const [databaseColumns, setDatabaseColumns] = useState([]);
|
| 183 |
|
| 184 |
const [error, setError] = useState("");
|
| 185 |
+
const [pdfWarnings, setPdfWarnings] = useState([]);
|
| 186 |
const [result, setResult] = useState(null);
|
| 187 |
|
| 188 |
useEffect(() => {
|
|
|
|
| 406 |
|
| 407 |
setLoadingPdf(true);
|
| 408 |
setError("");
|
| 409 |
+
setPdfWarnings([]);
|
| 410 |
|
| 411 |
try {
|
| 412 |
const formData = new FormData();
|
|
|
|
| 439 |
avisos.push(
|
| 440 |
`${anosRevisao.length === 1 ? "O ano" : "Os anos"} ${anosRevisao.join(", ")} ${
|
| 441 |
anosRevisao.length === 1 ? "aparece" : "aparecem"
|
| 442 |
+
} mais de uma vez ou ${anosRevisao.length === 1 ? "possui" : "possuem"} mais de uma linha de valor venal. ` +
|
| 443 |
"Foi inserido como XXX.XXX,XX para revisão.",
|
| 444 |
);
|
| 445 |
}
|
| 446 |
if (avisos.length) {
|
| 447 |
+
setPdfWarnings(avisos.map((aviso) => `${aviso} Complete manualmente o campo “Valores Venais”.`));
|
| 448 |
}
|
| 449 |
} catch (err) {
|
| 450 |
setError(String(err));
|
|
|
|
| 478 |
setForm(buildEmptyForm(options));
|
| 479 |
setDatabaseColumns([]);
|
| 480 |
setError("");
|
| 481 |
+
setPdfWarnings([]);
|
| 482 |
setResult(null);
|
| 483 |
};
|
| 484 |
|
|
|
|
| 787 |
</button>
|
| 788 |
</div>
|
| 789 |
|
| 790 |
+
{pdfWarnings.map((warning) => (
|
| 791 |
+
<div className="warning-box" key={warning}>
|
| 792 |
+
{warning}
|
| 793 |
+
</div>
|
| 794 |
+
))}
|
| 795 |
|
| 796 |
<label>
|
| 797 |
Inscrição
|
tests/test_pdf_extractor.py
CHANGED
|
@@ -44,11 +44,15 @@ Documento de Origem
|
|
| 44 |
def test_marca_anos_repetidos_ou_com_linhas_extras_para_revisao(self):
|
| 45 |
registros = [
|
| 46 |
("2023", 3, "300.000,00"),
|
| 47 |
-
("2024",
|
| 48 |
("2023", 3, "300.000,00"),
|
| 49 |
]
|
| 50 |
self.assertEqual(anos_venais_para_revisao(registros), [2023, 2024])
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
if __name__ == "__main__":
|
| 54 |
unittest.main()
|
|
|
|
| 44 |
def test_marca_anos_repetidos_ou_com_linhas_extras_para_revisao(self):
|
| 45 |
registros = [
|
| 46 |
("2023", 3, "300.000,00"),
|
| 47 |
+
("2024", 2, "320.000,00"),
|
| 48 |
("2023", 3, "300.000,00"),
|
| 49 |
]
|
| 50 |
self.assertEqual(anos_venais_para_revisao(registros), [2023, 2024])
|
| 51 |
|
| 52 |
+
def test_uma_linha_venal_por_ano_nao_exige_revisao(self):
|
| 53 |
+
registros = [("2021", 1, "293.882,68"), ("2022", 1, "325.240,88")]
|
| 54 |
+
self.assertEqual(anos_venais_para_revisao(registros), [])
|
| 55 |
+
|
| 56 |
|
| 57 |
if __name__ == "__main__":
|
| 58 |
unittest.main()
|