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