3d8e847b1bd9b47c1c7970689421a49fb6157422
[cascardo/irpf-gui.git] / src / contribuinte.py
1 # coding=utf-8
2 #
3 #   Copyright 2013-2014 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 import form
22 import ocupacoes
23
24 class OcupacaoForm(form.OptionsForm):
25     def __init__(self, ocupacoes, contribuinte):
26         g = ocupacoes.groups()
27         l = []
28         for i in sorted(g):
29             l.extend(g[i])
30         o = map(lambda x: (x[0], x[3]), l)
31         form.OptionsForm.__init__(self, u"Ocupações", o, contribuinte.get_campo_contribuinte("ocupacaoPrincipal"))
32         self.ocupacoes = ocupacoes
33         self.contribuinte = contribuinte
34     def set_value(self, value):
35         form.OptionsForm.set_value(self, value)
36         self.contribuinte.set_campo_contribuinte("ocupacaoPrincipal", value)
37
38 class ContribuinteForm(form.StringForm):
39     def __init__(self, name, attr, contribuinte):
40         self.contribuinte = contribuinte
41         self.attr = attr
42         form.StringForm.__init__(self, name, self.contribuinte.get_campo_contribuinte(self.attr))
43     def set_value(self, value):
44         form.StringForm.set_value(self, value)
45         self.contribuinte.set_campo_contribuinte(self.attr, value)
46
47 class Contribuinte:
48     def __init__(self, cpf):
49         irpf_dir = dirs.get_default_irpf_dir()
50         self.cpf = self._minimize_cpf(cpf)
51
52         if not self._validate_cpf(self.cpf):
53             raise RuntimeError("Invalid CPF: " + self.cpf)
54
55         if not os.path.exists(irpf_dir.get_resource_dir()):
56             raise RuntimeError("O caminho para o resource não existe: " + \
57                     irpf_dir.get_resource_dir())
58
59         if not os.path.exists(irpf_dir.get_userdata_dir()):
60             raise RuntimeError("O caminho para os dados não existe: " + \
61                     irpf_dir.get_userdata_dir())
62
63         self.cpf_file = irpf_dir.get_userdata_file("%s/%s.xml" % (self.cpf, self.cpf))
64         self.iddecl_file = irpf_dir.get_userdata_file("iddeclaracoes.xml")
65         self.declaracao = self._find_id()
66         self.dados = xml.dom.minidom.parse(self.cpf_file)
67         self.contribuinte = self.dados.getElementsByTagName("contribuinte")[0]
68
69     def _find_id(self):
70         cpf = self._normalize_cpf(self.cpf)
71         self.declaracoes = xml.dom.minidom.parse(self.iddecl_file)
72         for i in self.declaracoes.getElementsByTagName("item"):
73             if "cpf" in i.attributes.keys():
74                 if i.attributes["cpf"].nodeValue == cpf:
75                     return i
76         return None
77
78     # CPF normalizado se parece com 000.000.000-00
79     def _normalize_cpf(self, cpf):
80         ncpf = ""
81         for i in cpf:
82             if len(ncpf) == 3 or len(ncpf) == 7:
83                 ncpf += '.'
84             if len(ncpf) == 11:
85                 ncpf += '-'
86             if len(ncpf) == 14:
87                 break
88             if ord(i) >= ord('0') and ord(i) <= ord('9'):
89                 ncpf += i
90         if len(ncpf) != 14:
91             raise RuntimeError("Invalid CPF")
92         return ncpf
93
94     # CPF minimizado se parece com 01234567890
95     def _minimize_cpf(self, cpf):
96         return self._minimize_valor(cpf)
97
98     def _minimize_valor(self, valor):
99         nvalor = ''.join(e for e in valor if e.isalnum())
100         return str(nvalor)
101
102     def _validate_cpf(self, cpf):
103         if len(cpf) != 11:
104             return False
105         return self._validate_generico(cpf)
106
107     def _validate_generico(self, valor):
108         def calcula_digito_verificador(numero):
109             n = len(numero) + 1
110
111             soma = 0
112             for i in range(n):
113                 if i > len(numero) - 1:
114                     break
115                 soma = soma + int(numero[i]) * ( n - i)
116
117             dv =  soma % 11
118
119             if dv < 2:
120                 dv = 0
121             else:
122                 dv = 11 - dv
123
124             return numero + str(dv)
125
126         mcpf = self._minimize_valor(valor)
127         cpf_sem_dv = mcpf[:-2]
128
129         primeiro_dv = str(calcula_digito_verificador(cpf_sem_dv))
130         segundo_dv = calcula_digito_verificador(primeiro_dv)
131
132         return segundo_dv == mcpf
133
134     def save(self):
135         self.dados.writexml(open(self.cpf_file, "w"))
136         self.declaracoes.writexml(open(self.iddecl_file, "w"))
137
138     def _get_attr(self, el, attr):
139         if attr in el.attributes.keys():
140             return el.attributes[attr].nodeValue
141         return None
142
143     def _set_attr(self, el, attr, val):
144         el.attributes[attr].nodeValue = val
145
146     def get_declaracao(self, attr):
147         return self._get_attr(self.declaracao, attr)
148
149     def set_declaracao(self, attr, val):
150         self._set_attr(self.declaracao, attr, val)
151
152     def get_nome(self):
153         return self.get_declaracao("nome")
154
155     def set_nome(self, nome):
156         self.set_declaracao("nome", nome)
157
158     def get_campo_contribuinte(self, attr):
159         if attr == "nome":
160             return self.get_nome()
161         return self._get_attr(self.contribuinte, attr)
162
163     def set_campo_contribuinte(self, attr, val):
164         if attr == "nome":
165             self.set_nome(val)
166         else:
167             self._set_attr(self.contribuinte, attr, val)
168
169     def form(self):
170         form = []
171         ocup = ocupacoes.Ocupacoes()
172         form.append(ContribuinteForm("Nome", "nome", self))
173         form.append(OcupacaoForm(ocup, self))
174         for i in contribuinte_attributes:
175             form.append(ContribuinteForm(i, i, self))
176         return form
177
178 contribuinte_attributes = [
179         "nome",
180         "dataNascimento",
181         "tituloEleitor",
182         "doencaDeficiencia",
183         "exterior",
184         "pais",
185         "cep",
186         "uf",
187         "cidade",
188         "municipio",
189         "tipoLogradouro",
190         "logradouro",
191         "numero",
192         "complemento",
193         "bairro",
194         "bairroExt",
195         "cepExt",
196         "logradouroExt",
197         "numeroExt",
198         "complementoExt",
199         "ocupacaoPrincipal",
200         "codigoExterior",
201         "ddd",
202         "telefone",
203         "naturezaOcupacao",
204         ]
205
206 declaracao_attributes = [
207         "dataUltimoAcesso",
208         "declaracaoRetificadora",
209         "enderecoDiferente",
210         "enderecoMACRede",
211         "exercicio",
212         "nome",
213         "numReciboDecRetif",
214         "numeroReciboDecAnterior",
215         "resultadoDeclaracao",
216         "tipoDeclaracao",
217         "tipoDeclaracaoAES",
218         "transmitida",
219         "versaoBeta"
220         ]
221
222 if __name__ == '__main__':
223     import sys
224     contribuinte = Contribuinte(sys.argv[1])
225     print "Carregando CPF " + contribuinte._normalize_cpf(sys.argv[1])
226
227     if len(sys.argv) == 4:
228         print "Valor anterior: " + contribuinte.get_campo_contribuinte(sys.argv[2])
229         contribuinte.set_campo_contribuinte(sys.argv[2], sys.argv[3])
230         print "Valor atual: " + contribuinte.get_campo_contribuinte(sys.argv[2])
231         print "Salvando..."
232         contribuinte.save()
233     elif len(sys.argv) == 3:
234         campo = sys.argv[2]
235         valor = contribuinte.get_campo_contribuinte(campo)
236         if valor:
237             print ("Valor de " + campo + ": " + valor)
238         else:
239             print ("Campo " + campo + " retornou vazio")
240     else:
241         print "\nCONTRIBUINTE:"
242         for i in contribuinte_attributes:
243             val = contribuinte.get_campo_contribuinte(i)
244             if val == None:
245                 val = ""
246             print i + ": " + val
247         print "\nDECLARACAO:"
248         for i in declaracao_attributes:
249             val = contribuinte.get_declaracao(i)
250             if val == None:
251                 val = ""
252             print i + ": " + val
253
254 # vim:tabstop=4:expandtab:smartindent