1 | import logging
|
---|
2 | from datetime import date
|
---|
3 |
|
---|
4 | from django.contrib.postgres.indexes import GinIndex
|
---|
5 | from django.contrib.postgres.search import SearchVectorField
|
---|
6 | from django.core import serializers
|
---|
7 | from django.db import connection, models
|
---|
8 | from django.db.models.constraints import UniqueConstraint
|
---|
9 | from django.db.models.signals import post_save
|
---|
10 | from django.dispatch import receiver
|
---|
11 | from django.utils import timezone
|
---|
12 | from django.utils.translation import gettext as _
|
---|
13 | from mpublico.choices import *
|
---|
14 |
|
---|
15 | from . import helpers
|
---|
16 | from .stop_words import STOP_WORDS
|
---|
17 | logger = logging.getLogger(__name__)
|
---|
18 |
|
---|
19 | class Empresa(models.Model):
|
---|
20 | created_at = models.DateTimeField(
|
---|
21 | _('Fecha'), default=timezone.now, blank=True)
|
---|
22 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
23 | CodigoEmpresa = models.CharField(_('Código empresa'), unique=True)
|
---|
24 | NombreEmpresa = models.CharField(_('Razón social'), max_length=1000)
|
---|
25 |
|
---|
26 | class Meta:
|
---|
27 | verbose_name = 'Empresa'
|
---|
28 | verbose_name_plural = 'Empresa'
|
---|
29 |
|
---|
30 | class Meta:
|
---|
31 | indexes = [
|
---|
32 | models.Index(fields=['NombreEmpresa', 'CodigoEmpresa']),
|
---|
33 | models.Index(fields=['NombreEmpresa']),
|
---|
34 | ]
|
---|
35 |
|
---|
36 | def __str__(self):
|
---|
37 | return self.NombreEmpresa
|
---|
38 |
|
---|
39 | class Licitacion(models.Model):
|
---|
40 | created_at = models.DateTimeField(
|
---|
41 | _('Fecha'), default=timezone.now, blank=True)
|
---|
42 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
43 | CodigoExterno = models.CharField(_('Código externo'), unique=True)
|
---|
44 | CodigoEstado = models.IntegerField(
|
---|
45 | _('Código estado'), choices=ESTADO_LICITACION_CHOICES, blank=True, null=True)
|
---|
46 | FechaCierre = models.DateTimeField(
|
---|
47 | _('Fecha Cierre'), blank=True, null=True)
|
---|
48 | Nombre = models.CharField(_('Nombre Producto'), blank=True, null=True)
|
---|
49 | date = models.DateField(_("Fecha Publicación"), blank=True, null=True)
|
---|
50 | empresa = models.ForeignKey(
|
---|
51 | Empresa, on_delete=models.CASCADE, blank=True, null=True)
|
---|
52 |
|
---|
53 | class Meta:
|
---|
54 | verbose_name = 'Licitacion Base'
|
---|
55 | verbose_name_plural = 'Licitacion Base'
|
---|
56 |
|
---|
57 | def __str__(self):
|
---|
58 | return self.CodigoExterno
|
---|
59 |
|
---|
60 | class LicitacionDetalle(models.Model):
|
---|
61 | licitacion = models.ForeignKey(
|
---|
62 | Licitacion, on_delete=models.CASCADE, related_name='licitacion_detalle')
|
---|
63 | created_at = models.DateTimeField(
|
---|
64 | _('Fecha'), default=timezone.now, blank=True)
|
---|
65 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
66 | active = models.BooleanField(default=True)
|
---|
67 | CodigoExterno = models.CharField()
|
---|
68 | CodigoEstado = models.IntegerField(
|
---|
69 | _('Código estado'), choices=ESTADO_LICITACION_CHOICES)
|
---|
70 | Descripcion = models.CharField(
|
---|
71 | _('Descripción de la Licitación u objetode la contratación'), null=True, blank=True)
|
---|
72 | Estado = models.CharField(
|
---|
73 | _('Estado en el que se encuentra la Licitación'), null=True, blank=True)
|
---|
74 | Informada = models.BooleanField(
|
---|
75 | _('Indica si la Licitación es Informada'), null=True, blank=True)
|
---|
76 | DiasCierreLicitacion = models.IntegerField(
|
---|
77 | _('cantidad de días para el cierre de la Licitación'), null=True, blank=True)
|
---|
78 | CodigoTipo = models.IntegerField(
|
---|
79 | _('Tipo Licitación'), choices=CODIGO_TIPO_LICITACION_CHOICES, null=True, blank=True)
|
---|
80 | Tipo = models.CharField(
|
---|
81 | _('Tipo de Licitación de Mercado Publico'), choices=TIPO_LICITACION_CHOICES, null=True, blank=True)
|
---|
82 | TipoConvocatoria = models.IntegerField(
|
---|
83 | _('Tipo Convocatoria'), choices=TIPO_CONVOCATORIA_CHOICES, null=True, blank=True)
|
---|
84 | Moneda = models.CharField(
|
---|
85 | _('Código de la moneda en la Licitación'), choices=MONEDA_CHOICES, null=True, blank=True)
|
---|
86 | MontoEstimado = models.FloatField(
|
---|
87 | _('Monto estimado que maneja el Organismo o Institución para licitar'), null=True, blank=True)
|
---|
88 |
|
---|
89 | def __str__(self):
|
---|
90 | return str(self.CodigoExterno)
|
---|
91 |
|
---|
92 | class Meta:
|
---|
93 | verbose_name = 'Licitacion Detalle'
|
---|
94 | verbose_name_plural = 'Licitacion Detalle'
|
---|
95 |
|
---|
96 | indexes = [
|
---|
97 | models.Index(
|
---|
98 | fields=['MontoEstimado', 'licitacion', 'CodigoExterno', 'active']),
|
---|
99 | models.Index(fields=['MontoEstimado', 'licitacion']),
|
---|
100 | models.Index(fields=['MontoEstimado']),
|
---|
101 | models.Index(fields=['Adjudicacion_UrlActa']),
|
---|
102 | models.Index(fields=['active', 'CodigoExterno']),
|
---|
103 | models.Index(fields=['active']),
|
---|
104 | ]
|
---|
105 |
|
---|
106 |
|
---|
107 | class Proveedor(models.Model):
|
---|
108 | created_at = models.DateTimeField(
|
---|
109 | _('Fecha'), default=timezone.now, blank=True)
|
---|
110 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
111 | RutProveedor = models.CharField()
|
---|
112 | NombreProveedor = models.CharField()
|
---|
113 |
|
---|
114 | def __str__(self):
|
---|
115 | return self.NombreProveedor
|
---|
116 |
|
---|
117 | class Meta:
|
---|
118 | constraints = [
|
---|
119 | models.UniqueConstraint(
|
---|
120 | fields=['RutProveedor', 'NombreProveedor'], name='unique_proovedor')
|
---|
121 | ]
|
---|
122 | verbose_name = 'Proveedor'
|
---|
123 | verbose_name_plural = 'Proveedor'
|
---|
124 |
|
---|
125 | indexes = [
|
---|
126 | models.Index(fields=['RutProveedor', 'NombreProveedor']),
|
---|
127 | models.Index(fields=['NombreProveedor']),
|
---|
128 | ]
|
---|
129 |
|
---|
130 |
|
---|
131 | class LicitacionItem(models.Model):
|
---|
132 | created_at = models.DateTimeField(
|
---|
133 | _('Fecha'), default=timezone.now, blank=True)
|
---|
134 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
135 | licitacion = models.ForeignKey(
|
---|
136 | Licitacion, on_delete=models.CASCADE, related_name='licitacion_items')
|
---|
137 | licitacion_detalle = models.ForeignKey(
|
---|
138 | LicitacionDetalle, on_delete=models.CASCADE, related_name='licitacion_detalle_items')
|
---|
139 | producto = models.ForeignKey(
|
---|
140 | 'Producto', on_delete=models.CASCADE, blank=True, null=True)
|
---|
141 | categoria = models.ForeignKey(
|
---|
142 | 'Categoria', on_delete=models.CASCADE, blank=True, null=True)
|
---|
143 | proveedor = models.ForeignKey(
|
---|
144 | Proveedor, on_delete=models.CASCADE, null=True, blank=True)
|
---|
145 | CodigoExterno = models.CharField()
|
---|
146 | Descripcion = models.CharField(blank=True, null=True)
|
---|
147 | UnidadMedida = models.CharField(_('Unidad Medida'), blank=True, null=True)
|
---|
148 | Cantidad = models.FloatField(_('Cantidad Licitada'), blank=True, null=True)
|
---|
149 | Adjudicacion_Cantidad = models.FloatField(
|
---|
150 | _('Cantidad Adjudicada'), blank=True, null=True)
|
---|
151 | Adjudicacion_MontoUnitario = models.FloatField(
|
---|
152 | _('Monto Unitario Adjudicación'), blank=True, null=True)
|
---|
153 | active = models.BooleanField(_('Vigencia Item'), default=True)
|
---|
154 | Correlativo = models.IntegerField(blank=True, null=True)
|
---|
155 | analizado = models.BooleanField(default=False)
|
---|
156 | touch = models.BooleanField(default=False)
|
---|
157 | search = SearchVectorField(
|
---|
158 | null=True,
|
---|
159 | help_text="used to store all searchable info",
|
---|
160 | )
|
---|
161 |
|
---|
162 | def __str__(self):
|
---|
163 | return self.Descripcion
|
---|
164 |
|
---|
165 | class Meta:
|
---|
166 | verbose_name = 'Licitacion Items Seguimiento Diario'
|
---|
167 | verbose_name_plural = 'Licitacion Items Seguimiento Diario'
|
---|
168 | indexes = [
|
---|
169 | models.Index(fields=['Descripcion', 'active', 'Cantidad']),
|
---|
170 | models.Index(fields=['Cantidad', 'licitacion']),
|
---|
171 | models.Index(fields=['active', 'CodigoExterno']),
|
---|
172 | models.Index(fields=['Descripcion', 'licitacion']),
|
---|
173 | models.Index(fields=['Cantidad']),
|
---|
174 | models.Index(fields=['Descripcion']),
|
---|
175 | models.Index(fields=['active']),
|
---|
176 | GinIndex(fields=["search"]),
|
---|
177 | ]
|
---|
178 |
|
---|
179 | def update_search_vector(self):
|
---|
180 | """
|
---|
181 | Update SearchVector field of SearchModel using raw SQL
|
---|
182 | search field is used to store SearchVector
|
---|
183 | """
|
---|
184 | db_table = self._meta.db_table
|
---|
185 |
|
---|
186 | # first get anything interesting out of the media
|
---|
187 | # that needs to be searchable
|
---|
188 |
|
---|
189 | if self.id:
|
---|
190 |
|
---|
191 | items = []
|
---|
192 | if self.Descripcion:
|
---|
193 | items.append(str(self.Descripcion))
|
---|
194 |
|
---|
195 | if self.proveedor:
|
---|
196 | if self.proveedor.NombreProveedor:
|
---|
197 | items.append(str(self.proveedor.NombreProveedor))
|
---|
198 |
|
---|
199 | if self.categoria:
|
---|
200 | if self.categoria.Categoria:
|
---|
201 | items.append(str(self.categoria.Categoria))
|
---|
202 |
|
---|
203 | if self.licitacion:
|
---|
204 | if self.licitacion.Nombre:
|
---|
205 | items.append(str(self.licitacion.Nombre))
|
---|
206 |
|
---|
207 | items = [item for item in items if item]
|
---|
208 | text = " ".join(items)
|
---|
209 | text = " ".join([token for token in text.lower().split(
|
---|
210 | " ") if token not in STOP_WORDS])
|
---|
211 |
|
---|
212 | text = helpers.clean_query(text)
|
---|
213 |
|
---|
214 | sql_code = """
|
---|
215 | UPDATE {db_table} SET search = to_tsvector(
|
---|
216 | '{config}', '{text}'
|
---|
217 | ) WHERE {db_table}.id = {id}
|
---|
218 | """.format(
|
---|
219 | db_table=db_table, config="simple", text=text, id=self.id
|
---|
220 | )
|
---|
221 |
|
---|
222 | try:
|
---|
223 | with connection.cursor() as cursor:
|
---|
224 | cursor.execute(sql_code)
|
---|
225 | except BaseException as e:
|
---|
226 | logger.error(f': LicitacionItem {str(e)}')
|
---|
227 | pass
|
---|
228 | return True
|
---|
229 |
|
---|
230 | class Categoria(models.Model):
|
---|
231 | created_at = models.DateTimeField(
|
---|
232 | _('Fecha'), default=timezone.now, blank=True)
|
---|
233 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
234 | Categoria = models.CharField()
|
---|
235 | CodigoCategoria = models.CharField()
|
---|
236 |
|
---|
237 | def __str__(self):
|
---|
238 | return str(self.Categoria)
|
---|
239 |
|
---|
240 | class Meta:
|
---|
241 | constraints = [
|
---|
242 | models.UniqueConstraint(
|
---|
243 | fields=['Categoria', 'CodigoCategoria'], name='unique_categoria')
|
---|
244 | ]
|
---|
245 | verbose_name = 'Categoria'
|
---|
246 | verbose_name_plural = 'Categoria'
|
---|
247 |
|
---|
248 | indexes = [
|
---|
249 | models.Index(fields=['CodigoCategoria', 'Categoria']),
|
---|
250 | models.Index(fields=['Categoria']),
|
---|
251 | ]
|
---|
252 |
|
---|
253 | class Producto(models.Model):
|
---|
254 | created_at = models.DateTimeField(
|
---|
255 | _('Fecha'), default=timezone.now, blank=True)
|
---|
256 | updated_at = models.DateTimeField(auto_now=True, null=True)
|
---|
257 | NombreProducto = models.CharField()
|
---|
258 | CodigoProducto = models.CharField()
|
---|
259 | categoria = models.ForeignKey(
|
---|
260 | Categoria, on_delete=models.CASCADE, blank=True, null=True)
|
---|
261 |
|
---|
262 | def __str__(self):
|
---|
263 | return self.NombreProducto
|
---|
264 |
|
---|
265 | class Meta:
|
---|
266 | constraints = [
|
---|
267 | models.UniqueConstraint(
|
---|
268 | fields=['NombreProducto', 'CodigoProducto'], name='unique_producto')
|
---|
269 | ]
|
---|
270 |
|
---|
271 | verbose_name = 'Producto'
|
---|
272 | verbose_name_plural = 'Producto'
|
---|
273 |
|
---|
274 | indexes = [
|
---|
275 | models.Index(fields=['NombreProducto',
|
---|
276 | 'categoria', 'CodigoProducto']),
|
---|
277 | models.Index(fields=['NombreProducto', 'categoria']),
|
---|
278 | models.Index(fields=['NombreProducto']),
|
---|
279 | ]
|
---|