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