Code

Ticket #19845: models.py

File models.py, 12.1 KB (added by eltonplima@…, 17 months ago)

The models.py

Line 
1# -*- coding: utf-8 -*-
2""" Este módulo é responsável por toda a parte cadastral básica do controle
3interno.
4
5Durante o uso do sistema, este módulo pode ser considerado o "ponto de entrada"
6pois é aqui que são cadastradas todas as informações essenciais usadas pelos
7outros módulos/aplicações.
8
9.. moduleauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
10.. moduleauthor:: Fernando José Loureiro <nando_al@msn.com>
11"""
12
13from __future__ import unicode_literals
14
15import os
16import shutil
17
18from django.conf import settings
19from django.db import models
20from django.db.models import signals
21from django.db.models.loading import get_models
22
23from ci.fields import CharTitleField
24from ci.fields import CharLowerCaseField
25
26from ..models import Base
27from ..utils.utils import mkdir
28from ..utils.utils import execute_sql
29from ..utils.utils import to_ascii
30
31from .consts import VERBOSE_ANO
32from .consts import VERBOSE_ANO_PLURAL
33from .consts import VERBOSE_EMAIL
34from .consts import VERBOSE_EMAIL_PLURAL
35from .consts import VERBOSE_MES
36from .consts import VERBOSE_MES_PLURAL
37from .consts import VERBOSE_MES_CODIGO
38from .consts import VERBOSE_MES_ESPECIAL
39from .consts import VERBOSE_OPERADORA_TELEFONIA
40from .consts import VERBOSE_OPERADORA_TELEFONIA_PLURAL
41from .consts import VERBOSE_TELEFONE
42from .consts import VERBOSE_TELEFONE_PLURAL
43from ci.download.models import DownloadSemCategoria
44from ci.cadastro.consts import VERBOSE_SISTEMA, VERBOSE_SISTEMA_PLURAL
45from ci.cadastro.tipo.models import TipoHierarquiaBase
46
47
48class Ano(Base):
49    """ Cadastro de anos.
50
51    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
52    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
53    """
54    nome = models.IntegerField(unique = True,
55                               verbose_name = 'ConfigurationField.objects.get(config_name="verbose_name")',)
56
57#    def __init__(self, *args, **kwargs):
58#        super(Ano, self).__init__(*args, **kwargs)
59#        for field in self._meta.fields:
60#            print(field.verbose_name)
61#            field.verbose_name = "Teste"
62
63    class Meta:
64        ordering = ['nome',]
65        verbose_name = VERBOSE_ANO
66        verbose_name_plural = VERBOSE_ANO_PLURAL
67        db_table = "cadastro_ano"
68
69    def __unicode__(self):
70        return unicode(self.nome)
71
72
73class Mes(Base):
74    """ Cadastro de meses.
75
76    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
77    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
78    """
79    nome = CharTitleField(max_length = 32,
80                          unique = True,
81                          verbose_name = VERBOSE_MES,)
82    codigo = models.IntegerField(unique = True,
83                                 verbose_name = VERBOSE_MES_CODIGO,)
84    mes_especial = models.BooleanField(default = False,
85                                       verbose_name = VERBOSE_MES_ESPECIAL,)
86
87    class Meta:
88        ordering = ['codigo']
89        verbose_name = VERBOSE_MES
90        verbose_name_plural = VERBOSE_MES_PLURAL
91        db_table = "cadastro_mes"
92
93    def __unicode__(self):
94        return self.nome
95
96
97class OperadoraTelefonia(Base):
98    """ Cadastro de operadoras telefônicas.
99
100    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
101    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
102    """
103    nome = CharTitleField(max_length = 64,
104                          unique = True,
105                          verbose_name = VERBOSE_OPERADORA_TELEFONIA,)
106
107    class Meta:
108        ordering = ['nome',]
109        verbose_name = VERBOSE_OPERADORA_TELEFONIA
110        verbose_name_plural = VERBOSE_OPERADORA_TELEFONIA_PLURAL
111        db_table = "cadastro_operadora_telefonia"
112
113    def __unicode__(self):
114        return self.nome
115
116
117class Email(Base):
118    """ Cadastro de e-mails.
119
120    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
121    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
122    """
123    endereco = CharLowerCaseField(db_index = True,
124                                  max_length = 64,
125                                  verbose_name = VERBOSE_EMAIL,)
126
127    class Meta:
128        abstract = True
129        verbose_name = VERBOSE_EMAIL
130        verbose_name_plural = VERBOSE_EMAIL_PLURAL
131
132    def __unicode__(self):
133        return self.endereco
134
135
136class Telefone(Base):
137    """ Cadastro de números telefônicos.
138
139    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
140    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
141    """
142    numero = models.CharField(db_index = True,
143                              max_length = 9,
144                              verbose_name = VERBOSE_TELEFONE,)
145
146    class Meta:
147        abstract = True
148        verbose_name = VERBOSE_TELEFONE
149        verbose_name_plural = VERBOSE_TELEFONE_PLURAL
150
151
152class SistemaCategoria(TipoHierarquiaBase):
153    class Meta:
154        db_table = "cadastro_sistema_categoria"
155
156
157class Sistema(DownloadSemCategoria):
158    """ Cadastro de sistemas.
159
160    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
161    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
162
163    Esta classe representa um software que a Tavares & Souza pode alugar para
164    um cliente, como por exemplo um sistema de controle tributário.
165
166    Qualquer local do controle interno que precise fazer refência a um
167    sistema(e não a qualquer arquivo disponível para download) deve criar uma
168    referência para esta classe.
169
170    Poderia ter sido usada a classe DownloadSemCategoria para esta função, porém foi
171    decidido criar esta classe especializada para aumentar a flexibilidade do
172    sistema caso seja necessário incluir novas informações para um sistema.
173   
174    """
175    categoria = models.ForeignKey(SistemaCategoria)
176
177    class Meta:
178        verbose_name = VERBOSE_SISTEMA
179        verbose_name_plural = VERBOSE_SISTEMA_PLURAL
180        db_table = "cadastro_sistema"
181
182
183def mes_pre_save(signal, instance, sender, **kwargs):
184    """ Mantém a consistência dos arquivos no sistema de arquivos.
185
186    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
187    .. codeauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
188    .. codeauthor:: Fernando José Loureiro <nando_al@msn.com>
189
190    Este método garante que caso o nome ou o código de um mês seja alteração
191    os arquivos vínculados a ele sejam movidos para uma nova localização que
192    seja condizente com o nome/código do mês. Isso é feito para manter a
193    consistência do sistema de arquivos, já que o path dos arquivos é montado
194    com base no nome do mês e do código(além de outros dados).
195    """
196    if instance.id:
197        protocolos_arquivo = instance.protocolorelatorio_set.all()
198        old_full_path = None
199
200        if len(unicode(instance.codigo)) == 1:
201            mes = '0' + unicode(instance.codigo)
202        else:
203            mes = unicode(instance.codigo)
204
205        mes = mes + '_' + instance.nome
206
207        for protocolo_relatorio in protocolos_arquivo:
208            for protocolo_relatorio_arquivo in protocolo_relatorio.protocolorelatorioarquivo_set.all():
209                old_full_path = protocolo_relatorio_arquivo.protocolo_relatorio_arquivo.path
210
211                old_relative_path = protocolo_relatorio_arquivo.protocolo_relatorio_arquivo.name
212
213                novo_dst = os.path.join(old_relative_path.rsplit('/', 2)[0],
214                                        mes,
215                                        old_relative_path.rsplit('/', 1)[-1]
216                                        )
217
218                sql = 'update ' + protocolo_relatorio_arquivo._meta.db_table +\
219                ' set ' + protocolo_relatorio_arquivo.protocolo_relatorio_arquivo.field.column + '=\'' +\
220                novo_dst + '\' where id=' + unicode(protocolo_relatorio_arquivo.id)
221
222                execute_sql(sql.lower())
223
224            src = old_full_path.rsplit('/', 1)[0]
225            dst = os.path.join(old_full_path.rsplit('/', 2)[0], mes)
226            dst = to_ascii(dst)
227
228            shutil.move(src.lower(), dst.lower())
229
230
231def generate_custom_sql(**kwargs):
232    """ Cria um arquivo sql para criar esquemas no postgres.
233
234    .. sectionauthor:: Elton Pereira de Lima <eltonplima@gmail.com>
235    .. codeauthor:: Fernando José Loureiro <nando_al@msn.com>
236
237    Este método é invocado após a execução do syncdb. Ele gera um arquivo com o
238    nome que foi setado em settings.FIXTURE_FILE_NAME, dentro do diretório:
239    project_name/app_name/sql/nome_do_arquivo.
240    """
241    database_engine = settings.DATABASES['default']['ENGINE']
242
243    if database_engine.find('postgresql') != 0:
244        pass
245
246    app = kwargs['app']
247    package = app.__package__
248
249    if package is not None:
250        PROJECT_APPS = list(settings.PROJECT_APPS)
251        EXTERNAL_APPS = list(settings.EXTERNAL_APPS)
252        try:
253            app_name = package.split('.')[1]
254            package = package.split('.')[-1]
255            FIXTURE_PATH = os.path.join(settings.PROJECT_ROOT_PATH, app_name, 'sql')
256            FIXTURE_FILE = os.path.join(FIXTURE_PATH, settings.FIXTURE_FILE_NAME)
257            PRE_FIXTURE_FILE = os.path.join(FIXTURE_PATH, "pre_fixtures.sql")
258            POS_FIXTURE_FILE = os.path.join(FIXTURE_PATH, "pos_fixtures.sql")
259            PROJECT_APPS = [p.split('.')[-1] for p in PROJECT_APPS]
260            query_external_apps_move = None       
261
262            if EXTERNAL_APPS.index(package) >= 0:
263                query_external_apps_move = "select func_movetablestoschema('%s');" % package
264        except ValueError:
265            pass
266        except IndexError:
267            pass
268
269        try:
270            if PROJECT_APPS.index(package) >= 0:
271                               
272                master_apps = []
273                for p in list(settings.PROJECT_APPS):                   
274                    #coloca apenas as apps que tenham models
275                    modelos = get_models()
276                    for modelo in modelos:
277                        if modelo.__module__.startswith(p):
278                            p = p.split('.')[1]                                     
279                            if p not in master_apps:             
280                                    master_apps.append(p)                   
281               
282                apps = ', '.join(master_apps)
283                apps_audit = ''
284               
285                for app in master_apps:                   
286                    apps_audit += app + '_audit, '
287
288                apps_audit = apps_audit.rsplit(',', 1)[0]
289                query_search_path = 'alter user %s set search_path to public, django, %s, %s;' % (settings.DATABASES['default']['USER'], apps_audit, apps)
290               
291                mkdir(FIXTURE_PATH)
292                query = "select func_movetablestoschema('%s');\n" % app_name
293                query += 'select func_movetablestoschema(\'audit\' ,\'%s\', \'audit\');' % (app_name)
294                fixture_file = open(FIXTURE_FILE,"w")
295
296                # Envia o conteúdo do arquivo pre_fixtures.sql para o inicio
297                if os.path.isfile(PRE_FIXTURE_FILE):
298                    pre_fixture_file = open(PRE_FIXTURE_FILE,"r")
299
300                    for line in pre_fixture_file.readlines():
301                        fixture_file.write(line)
302
303                    pre_fixture_file.close()
304
305                fixture_file.write(query+'\n')
306
307                # Envia o conteúdo do arquivo pos_fixtures.sql para o final
308                if os.path.isfile(POS_FIXTURE_FILE):
309                    pos_fixture_file = open(POS_FIXTURE_FILE,"r")
310
311                    for line in pos_fixture_file.readlines():
312                        fixture_file.write(line)
313
314                    pos_fixture_file.close()
315
316                if query_external_apps_move is not None:
317                    fixture_file.write(query_external_apps_move + '\n')
318
319                fixture_file.write('select func_movetablestoschema(\'django\');\n')
320                fixture_file.write('select func_movetablestoschema(\'auth\' ,\'django\');\n')
321                fixture_file.write('select func_delete_foreignkey_audit();\n')
322                fixture_file.write(query_search_path + '\n')
323                fixture_file.close()
324        except ValueError:
325            pass
326
327signals.post_syncdb.connect(generate_custom_sql)
328#signals.pre_save.connect(mes_pre_save, sender=Mes, dispatch_uid='mes_pre_save')