Coding deve estar no inicio do arquivo para ser detectado
[cascardo/irpf-gui.git] / src / contribuinte.py
1 # coding=utf-8
2 #
3 #   Copyright 2013 Thadeu Lima de Souza Cascardo <cascardo@cascardo.info>
4 #
5 #   This program is free software: you can redistribute it and/or modify
6 #   it under the terms of the GNU General Public License as published by
7 #   the Free Software Foundation, either version 3 of the License, or
8 #   (at your option) any later version.
9 #
10 #   This program is distributed in the hope that it will be useful,
11 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #   GNU General Public License for more details.
14 #
15 #   You should have received a copy of the GNU General Public License
16 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 # -*- mode: python; encoding: utf-8; -*-
18 import xml.dom.minidom
19 import dirs
20 import os
21
22 class Contribuinte:
23     def __init__(self, cpf):
24         irpf_dir = dirs.get_default_irpf_dir()
25         self.cpf = self._minimize_cpf(cpf)
26
27         if not self._validate_cpf(self.cpf):
28             raise RuntimeError("Invalid CPF: " + self.cpf)
29
30         if not os.path.exists(irpf_dir.get_resource_dir()):
31             raise RuntimeError("O caminho para o resource não existe: " + \
32                     irpf_dir.get_resource_dir())
33
34         if not os.path.exists(irpf_dir.get_userdata_dir()):
35             raise RuntimeError("O caminho para os dados não existe: " + \
36                     irpf_dir.get_userdata_dir())
37
38         self.cpf_file = irpf_dir.get_userdata_file("%s/%s.xml" % (self.cpf, self.cpf))
39         self.iddecl_file = irpf_dir.get_userdata_file("iddeclaracoes.xml")
40         self.declaracao = self._find_id()
41         self.dados = xml.dom.minidom.parse(self.cpf_file)
42         self.contribuinte = self.dados.getElementsByTagName("contribuinte")[0]
43
44     def _find_id(self):
45         cpf = self._normalize_cpf(self.cpf)
46         self.declaracoes = xml.dom.minidom.parse(self.iddecl_file)
47         for i in self.declaracoes.childNodes[0].childNodes:
48             if "cpf" in i.attributes.keys():
49                 if i.attributes["cpf"].nodeValue == cpf:
50                     return i
51         return None
52
53     # CPF normalizado se parece com 000.000.000-00
54     def _normalize_cpf(self, cpf):
55         ncpf = ""
56         for i in cpf:
57             if len(ncpf) == 3 or len(ncpf) == 7:
58                 ncpf += '.'
59             if len(ncpf) == 11:
60                 ncpf += '-'
61             if len(ncpf) == 14:
62                 break
63             if ord(i) >= ord('0') and ord(i) <= ord('9'):
64                 ncpf += i
65         if len(ncpf) != 14:
66             raise RuntimeError("Invalid CPF")
67         return ncpf
68
69     # CPF minimizado se parece com 01234567890
70     def _minimize_cpf(self, cpf):
71         ncpf = bytearray(self._normalize_cpf(cpf))
72         del ncpf[11]
73         del ncpf[7]
74         del ncpf[3]
75         return str(ncpf)
76
77     def _validate_cpf(self, cpf):
78         ncpf = self._minimize_cpf(cpf)
79         if len(ncpf) != 11:
80             return False
81         v = (11 - sum(map(lambda x: x[0]*x[1], zip(range(10, 1, -1), map(lambda x: ord(x) - ord('0'), ncpf[0:9]))))) % 11
82         if v >= 10:
83             v = 0
84         if v != ord(ncpf[9]) - ord('0'):
85             return False
86         v = (11 - sum(map(lambda x: x[0]*x[1], zip(range(11, 1, -1), map(lambda x: ord(x) - ord('0'), ncpf[0:10]))))) % 11
87         if v >= 10:
88             v = 0
89         if v != ord(ncpf[10]) - ord('0'):
90             return False
91         return True
92
93     def save(self):
94         self.dados.writexml(open(self.cpf_file, "w"))
95         self.declaracoes.writexml(open(self.iddecl_file, "w"))
96     def _get_attr(self, el, attr):
97         if attr in el.attributes.keys():
98             return el.attributes[attr].nodeValue
99         return None
100
101     def _set_attr(self, el, attr, val):
102         el.attributes[attr].nodeValue = val
103
104     def get_declaracao(self, attr):
105         return self._get_attr(self.declaracao, attr)
106
107     def set_declaracao(self, attr, val):
108         self._set_attr(self.declaracao, attr, val)
109
110     def get_nome(self):
111         return self.get_declaracao("nome")
112
113     def set_nome(self, nome):
114         self.set_declaracao("nome", nome)
115
116     def get_campo_contribuinte(self, attr):
117         if attr == "nome":
118             return self.get_nome()
119         return self._get_attr(self.contribuinte, attr)
120
121     def set_campo_contribuinte(self, attr, val):
122         if attr == "nome":
123             self.set_nome(val)
124         else:
125             self._set_attr(self.contribuinte, attr, val)
126
127 contribuinte_attributes = [
128         "nome",
129         "dataNascimento",
130         "tituloEleitor",
131         "doencaDeficiencia",
132         "exterior",
133         "pais",
134         "cep",
135         "uf",
136         "cidade",
137         "municipio",
138         "tipoLogradouro",
139         "logradouro",
140         "numero",
141         "complemento",
142         "bairro",
143         "bairroExt",
144         "cepExt",
145         "logradouroExt",
146         "numeroExt",
147         "complementoExt",
148         "ocupacaoPrincipal",
149         "codigoExterior",
150         "ddd",
151         "telefone",
152         "naturezaOcupacao",
153         ]
154
155 declaracao_attributes = [
156         "dataUltimoAcesso",
157         "declaracaoRetificadora",
158         "enderecoDiferente",
159         "enderecoMACRede",
160         "exercicio",
161         "nome",
162         "numReciboDecRetif",
163         "numeroReciboDecAnterior",
164         "resultadoDeclaracao",
165         "tipoDeclaracao",
166         "tipoDeclaracaoAES",
167         "transmitida",
168         "versaoBeta"
169         ]
170
171 if __name__ == '__main__':
172     import sys
173     contribuinte = Contribuinte(sys.argv[1])
174     print "Carregando CPF " + contribuinte._normalize_cpf(sys.argv[1])
175
176     if len(sys.argv) == 4:
177         print "Valor anterior: " + contribuinte.get_campo_contribuinte(sys.argv[2])
178         contribuinte.set_campo_contribuinte(sys.argv[2], sys.argv[3])
179         print "Valor atual: " + contribuinte.get_campo_contribuinte(sys.argv[2])
180         print "Salvando..."
181         contribuinte.save()
182     elif len(sys.argv) == 3:
183         campo = sys.argv[2]
184         valor = contribuinte.get_campo_contribuinte(campo)
185         if valor:
186             print ("Valor de " + campo + ": " + valor)
187         else:
188             print ("Campo " + campo + " retornou vazio")
189     else:
190         print "\nCONTRIBUINTE:"
191         for i in contribuinte_attributes:
192             val = contribuinte.get_campo_contribuinte(i)
193             if val == None:
194                 val = ""
195             print i + ": " + val
196         print "\nDECLARACAO:"
197         for i in declaracao_attributes:
198             val = contribuinte.get_declaracao(i)
199             if val == None:
200                 val = ""
201             print i + ": " + val
202
203 # vim:tabstop=4:expandtab:smartindent