Showing
11 changed files
with
212 additions
and
41 deletions
1 | from django.contrib import admin | 1 | from django.contrib import admin |
2 | +from django.core.exceptions import ValidationError | ||
3 | +from django.utils import timezone | ||
2 | 4 | ||
3 | from .models import Edicto, Precio | 5 | from .models import Edicto, Precio |
4 | 6 | ||
5 | # Register your models here. | 7 | # Register your models here. |
6 | 8 | ||
7 | -admin.site.register(Precio) | 9 | + |
10 | +class PrecioAdmin(admin.ModelAdmin): | ||
11 | + def save_model(self, request, obj, form, change): | ||
12 | + precios_activos = Precio.objects.filter(vigencia_hasta__gte=timezone.now().date()) | ||
13 | + if not change: | ||
14 | + today = timezone.now().date() | ||
15 | + if obj.vigencia_desde <= today: | ||
16 | + if not precios_activos.exists(): | ||
17 | + obj.save() | ||
18 | + else: | ||
19 | + raise ValidationError("Ya existe un precio activo.") | ||
20 | + else: | ||
21 | + raise ValidationError("La fecha de inicio no es válida.") | ||
22 | + else: | ||
23 | + obj.save() | ||
24 | + | ||
25 | + | ||
26 | +admin.site.register(Precio, PrecioAdmin) | ||
8 | 27 | ||
9 | 28 | ||
10 | admin.site.register(Edicto) | 29 | admin.site.register(Edicto) |
@@ -5,11 +5,12 @@ from rest_framework.permissions import IsAuthenticated | @@ -5,11 +5,12 @@ from rest_framework.permissions import IsAuthenticated | ||
5 | from rest_framework.decorators import action | 5 | from rest_framework.decorators import action |
6 | from datetime import datetime | 6 | from datetime import datetime |
7 | 7 | ||
8 | -from .models import Edicto, Precio | ||
9 | -from .serializer import EdictoSerializer, PrecioSerializer | 8 | +from .models import Edicto, Precio, ComprobantePago |
9 | +from .serializer import EdictoSerializer, PrecioSerializer, PagoSerializer, ComprobanteSerializer | ||
10 | from .filters import EdictoFilter, PrecioFilter | 10 | from .filters import EdictoFilter, PrecioFilter |
11 | from .permissions import IsAdminOrAuthorized | 11 | from .permissions import IsAdminOrAuthorized |
12 | from .utils import contador | 12 | from .utils import contador |
13 | +from .precio import calculadora | ||
13 | 14 | ||
14 | 15 | ||
15 | class EdictoViewSet(mixins.CreateModelMixin, | 16 | class EdictoViewSet(mixins.CreateModelMixin, |
@@ -54,3 +55,42 @@ class PrecioViewSet(viewsets.ReadOnlyModelViewSet): | @@ -54,3 +55,42 @@ class PrecioViewSet(viewsets.ReadOnlyModelViewSet): | ||
54 | ordering_fields = ('usuario', ) | 55 | ordering_fields = ('usuario', ) |
55 | ordering = 'usuario' | 56 | ordering = 'usuario' |
56 | queryset = Precio.objects.all() | 57 | queryset = Precio.objects.all() |
58 | + | ||
59 | + | ||
60 | +class PagoViewSets(mixins.CreateModelMixin, | ||
61 | + mixins.RetrieveModelMixin, | ||
62 | + mixins.UpdateModelMixin, | ||
63 | + mixins.DestroyModelMixin, | ||
64 | + mixins.ListModelMixin, | ||
65 | + viewsets.GenericViewSet): | ||
66 | + serializer_class = PagoSerializer | ||
67 | + permission_classes = [IsAuthenticated, IsAdminOrAuthorized] | ||
68 | + queryset = ComprobantePago.objects.all() | ||
69 | + | ||
70 | + def perform_create(self, serializer): | ||
71 | + try: | ||
72 | + edicto = Edicto.objects.get(estado='aprobado') | ||
73 | + precio_admi = Precio.objects.latest('id') | ||
74 | + precio = Precio.objects.get(id=precio_admi.id) | ||
75 | + monto = calculadora(edicto, precio) | ||
76 | + usuario_actual = self.request.user | ||
77 | + if edicto.usuario != usuario_actual: | ||
78 | + raise UsuarioNoAutorizado | ||
79 | + serializer.validated_data['monto'] = monto | ||
80 | + serializer.validated_data['edicto'] = edicto | ||
81 | + serializer.save() | ||
82 | + except Edicto.DoesNotExist: | ||
83 | + raise EdictoNoEncontrado | ||
84 | + except Precio.DoesNotExist: | ||
85 | + raise PrecioNoEncontrado | ||
86 | + | ||
87 | + | ||
88 | +class ComprobanteViewSets(mixins.CreateModelMixin, | ||
89 | + mixins.RetrieveModelMixin, | ||
90 | + mixins.UpdateModelMixin, | ||
91 | + mixins.DestroyModelMixin, | ||
92 | + mixins.ListModelMixin, | ||
93 | + viewsets.GenericViewSet): | ||
94 | + serializer_class = ComprobanteSerializer | ||
95 | + queryset = ComprobantePago.objects.all() | ||
96 | + permission_classes = [IsAuthenticated, ] |
@@ -20,12 +20,8 @@ class PrecioFilter(filters.FilterSet): | @@ -20,12 +20,8 @@ class PrecioFilter(filters.FilterSet): | ||
20 | model = Precio | 20 | model = Precio |
21 | fields = { | 21 | fields = { |
22 | 'usuario': ['exact'], | 22 | 'usuario': ['exact'], |
23 | - 'precio': ['exact'], | 23 | + 'precio_palabra': ['exact'], |
24 | 'vigencia_desde': ['exact'], | 24 | 'vigencia_desde': ['exact'], |
25 | 'vigencia_hasta': ['exact'], | 25 | 'vigencia_hasta': ['exact'], |
26 | 'moneda': ['exact'], | 26 | 'moneda': ['exact'], |
27 | } | 27 | } |
28 | - | ||
29 | - | ||
30 | - | ||
31 | - |
1 | +# Generated by Django 4.1.9 on 2023-09-06 14:56 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | +import django.db.models.deletion | ||
5 | + | ||
6 | + | ||
7 | +class Migration(migrations.Migration): | ||
8 | + | ||
9 | + dependencies = [ | ||
10 | + ('edicto', '0010_alter_edicto_fecha_creacion'), | ||
11 | + ] | ||
12 | + | ||
13 | + operations = [ | ||
14 | + migrations.AlterField( | ||
15 | + model_name='comprobantepago', | ||
16 | + name='edicto', | ||
17 | + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='edicto.edicto'), | ||
18 | + ), | ||
19 | + ] |
1 | +# Generated by Django 4.1.9 on 2023-09-06 15:01 | ||
2 | + | ||
3 | +from django.db import migrations | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('edicto', '0011_alter_comprobantepago_edicto'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.RenameField( | ||
14 | + model_name='precio', | ||
15 | + old_name='precio', | ||
16 | + new_name='precio_palabra', | ||
17 | + ), | ||
18 | + ] |
1 | +# Generated by Django 4.1.9 on 2023-09-08 10:13 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('edicto', '0012_rename_precio_precio_precio_palabra'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.AddField( | ||
14 | + model_name='comprobantepago', | ||
15 | + name='archivo', | ||
16 | + field=models.FileField(null=True, upload_to=''), | ||
17 | + ), | ||
18 | + migrations.AlterField( | ||
19 | + model_name='edicto', | ||
20 | + name='estado', | ||
21 | + field=models.CharField(choices=[('iniciado', 'iniciado'), ('pendiente_de_pago', 'pendiente_de_pago'), ('publicado', 'publicado'), ('aprobado', 'aprobado'), ('rechazado', 'rechazado')], default='iniciado', max_length=150), | ||
22 | + ), | ||
23 | + ] |
1 | +# Generated by Django 4.1.9 on 2023-09-08 10:15 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('edicto', '0013_comprobantepago_archivo_alter_edicto_estado'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.AlterField( | ||
14 | + model_name='comprobantepago', | ||
15 | + name='fecha_pago', | ||
16 | + field=models.DateField(null=True), | ||
17 | + ), | ||
18 | + ] |
@@ -8,7 +8,7 @@ from usuario.models import Usuario | @@ -8,7 +8,7 @@ from usuario.models import Usuario | ||
8 | 8 | ||
9 | 9 | ||
10 | class Precio (models.Model): | 10 | class Precio (models.Model): |
11 | - precio = models.FloatField(max_length=50, blank=False, null=False) | 11 | + precio_palabra = models.FloatField(max_length=50, blank=False, null=False) |
12 | vigencia_desde = models.DateField() | 12 | vigencia_desde = models.DateField() |
13 | vigencia_hasta = models.DateField() | 13 | vigencia_hasta = models.DateField() |
14 | usuario = models.ForeignKey(Usuario, on_delete=models.CASCADE) | 14 | usuario = models.ForeignKey(Usuario, on_delete=models.CASCADE) |
@@ -29,7 +29,7 @@ class Edicto(models.Model): | @@ -29,7 +29,7 @@ class Edicto(models.Model): | ||
29 | archivo = models.FileField(upload_to="uploads/%Y/%m/%d/", null=False, blank=False) | 29 | archivo = models.FileField(upload_to="uploads/%Y/%m/%d/", null=False, blank=False) |
30 | dias_publicar = models.PositiveIntegerField(blank=False, null=False) | 30 | dias_publicar = models.PositiveIntegerField(blank=False, null=False) |
31 | cantidad_sellos = models.PositiveIntegerField(blank=False, null=False) | 31 | cantidad_sellos = models.PositiveIntegerField(blank=False, null=False) |
32 | - estado = models.CharField(max_length=150, choices=STATUS_CHOICE, default='inciado') | 32 | + estado = models.CharField(max_length=150, choices=STATUS_CHOICE, default='iniciado') |
33 | cantidad_palabras = models.IntegerField(blank=False, null=False) | 33 | cantidad_palabras = models.IntegerField(blank=False, null=False) |
34 | cantidad_copias = models.PositiveIntegerField(blank=False, null=False) | 34 | cantidad_copias = models.PositiveIntegerField(blank=False, null=False) |
35 | fecha_publicacion = models.DateField(blank=True, null=True) | 35 | fecha_publicacion = models.DateField(blank=True, null=True) |
@@ -42,18 +42,19 @@ class Edicto(models.Model): | @@ -42,18 +42,19 @@ class Edicto(models.Model): | ||
42 | verbose_name_plural = 'Edictos' | 42 | verbose_name_plural = 'Edictos' |
43 | 43 | ||
44 | def __str__(self): | 44 | def __str__(self): |
45 | - return self.cuerpo_edicto | 45 | + return f"{self.cuerpo_edicto} Edicto" |
46 | 46 | ||
47 | 47 | ||
48 | class ComprobantePago(models.Model): | 48 | class ComprobantePago(models.Model): |
49 | monto = models.FloatField(blank=False, null=False) | 49 | monto = models.FloatField(blank=False, null=False) |
50 | numero_comprobante = models.CharField(max_length=300, blank=False, null=True) | 50 | numero_comprobante = models.CharField(max_length=300, blank=False, null=True) |
51 | - fecha_pago = models.DateTimeField(blank=False, null=True) | ||
52 | - edicto = models.ForeignKey(Edicto, on_delete=models.CASCADE) | 51 | + fecha_pago = models.DateField(blank=False, null=True) |
52 | + edicto = models.OneToOneField(Edicto, on_delete=models.CASCADE) | ||
53 | + archivo = models.FileField(blank=False, null=True) | ||
53 | 54 | ||
54 | class Meta: | 55 | class Meta: |
55 | verbose_name = 'ComprobantePago' | 56 | verbose_name = 'ComprobantePago' |
56 | verbose_name_plural = 'ComprobantesPagos' | 57 | verbose_name_plural = 'ComprobantesPagos' |
57 | 58 | ||
58 | def __str__(self): | 59 | def __str__(self): |
59 | - return self.numero_comprobante | 60 | + return f"{self.numero_comprobante} comprobante pago de {self.edicto.cuerpo_edicto}" |
1 | +from django.db import transaction | ||
1 | from django.utils import timezone | 2 | from django.utils import timezone |
2 | -from .models import Edicto, ComprobantePago, Precio | 3 | +from datetime import datetime, time |
3 | 4 | ||
4 | 5 | ||
5 | -def contador(edicto_id, precio_id): | ||
6 | - edicto = Edicto.objects.select_related('usuario').get(id=edicto_id) | ||
7 | - organismo = edicto.usuario.organismo.es_publico | ||
8 | - | 6 | +def calculadora(edicto, precio): |
7 | + try: | ||
8 | + with transaction.atomic(): | ||
9 | + organismo = edicto.usuario.organismo | ||
10 | + es_publico = organismo.es_publico if organismo else False | ||
9 | sellos = edicto.cantidad_sellos | 11 | sellos = edicto.cantidad_sellos |
10 | palabras = edicto.cantidad_palabras | 12 | palabras = edicto.cantidad_palabras |
11 | copias = edicto.cantidad_copias | 13 | copias = edicto.cantidad_copias |
12 | publicar = edicto.dias_publicar | 14 | publicar = edicto.dias_publicar |
13 | - | ||
14 | - precio_valores = Precio.objects.values('precio', | ||
15 | - 'precio_ejemplar', | ||
16 | - 'vigencia_desde', | ||
17 | - 'vigencia_hasta',).get(id=precio_id) | ||
18 | - | ||
19 | - precio = precio_valores['precio'] | ||
20 | - precio_ejemplar = precio_valores['precio_ejemplar'] | ||
21 | - vigencia_desde = precio_valores['vigencia_desde'] | ||
22 | - vigencia_hasta = precio_valores['vigencia_hasta'] | ||
23 | - | ||
24 | - current_datetime = timezone.now() | ||
25 | - | 15 | + precio_valores = { |
16 | + 'precio_palabra': precio.precio, | ||
17 | + 'precio_ejemplar': precio.precio_ejemplar, | ||
18 | + 'vigencia_desde': precio.vigencia_desde, | ||
19 | + 'vigencia_hasta': precio.vigencia_hasta, | ||
20 | + } | ||
21 | + current_datetime = timezone.now().replace(tzinfo=None) | ||
22 | + vigencia_desde = datetime.combine(precio_valores['vigencia_desde'], time.min) | ||
23 | + vigencia_hasta = datetime.combine(precio_valores['vigencia_hasta'], time.max) | ||
26 | if not (vigencia_desde <= current_datetime <= vigencia_hasta): | 24 | if not (vigencia_desde <= current_datetime <= vigencia_hasta): |
27 | raise ValueError("El precio seleccionado no se encuentra dentro de las fechas permitidas.") | 25 | raise ValueError("El precio seleccionado no se encuentra dentro de las fechas permitidas.") |
28 | 26 | ||
29 | - result_palabra = (sellos + palabras) * precio | ||
30 | - result_ejemplar = (copias * precio_ejemplar) + (publicar * precio_ejemplar) | 27 | + result_palabra = (sellos + palabras) * precio_valores['precio'] |
28 | + result_ejemplar = \ | ||
29 | + (copias * precio_valores['precio_ejemplar']) + (publicar * precio_valores['precio_ejemplar']) | ||
31 | 30 | ||
32 | - if organismo: | 31 | + if es_publico: |
33 | resultado = result_ejemplar + result_palabra / 2 | 32 | resultado = result_ejemplar + result_palabra / 2 |
34 | else: | 33 | else: |
35 | resultado = result_ejemplar + result_palabra | 34 | resultado = result_ejemplar + result_palabra |
36 | 35 | ||
37 | - precio_resultado = ComprobantePago(edicto=edicto, resultado=resultado) | ||
38 | - precio_resultado.save() | ||
39 | - return precio_resultado | 36 | + return resultado |
37 | + except ValueError as values: | ||
38 | + | ||
39 | + raise ValueError("Los valores proporcionados son incorrectos: " + str(values)) |
@@ -3,7 +3,7 @@ from rest_framework import serializers | @@ -3,7 +3,7 @@ from rest_framework import serializers | ||
3 | 3 | ||
4 | from .constants import EXTENSIONES_VALIDAS | 4 | from .constants import EXTENSIONES_VALIDAS |
5 | 5 | ||
6 | -from .models import Edicto, Precio | 6 | +from .models import Edicto, Precio, ComprobantePago |
7 | from usuario.serializers import UsuarioListaSerializer | 7 | from usuario.serializers import UsuarioListaSerializer |
8 | 8 | ||
9 | 9 | ||
@@ -51,7 +51,7 @@ class PrecioSerializer(serializers.ModelSerializer): | @@ -51,7 +51,7 @@ class PrecioSerializer(serializers.ModelSerializer): | ||
51 | model = Precio | 51 | model = Precio |
52 | fields = ('usuario', | 52 | fields = ('usuario', |
53 | 'moneda', | 53 | 'moneda', |
54 | - 'precio', | 54 | + 'precio_palabra', |
55 | 'precio_ejemplar', | 55 | 'precio_ejemplar', |
56 | 'vigencia_desde', | 56 | 'vigencia_desde', |
57 | 'vigencia_hasta', | 57 | 'vigencia_hasta', |
@@ -60,3 +60,38 @@ class PrecioSerializer(serializers.ModelSerializer): | @@ -60,3 +60,38 @@ class PrecioSerializer(serializers.ModelSerializer): | ||
60 | included_serializers = { | 60 | included_serializers = { |
61 | 'usuario': UsuarioListaSerializer | 61 | 'usuario': UsuarioListaSerializer |
62 | } | 62 | } |
63 | + | ||
64 | + | ||
65 | +class PagoSerializer(serializers.ModelSerializer): | ||
66 | + class Meta: | ||
67 | + model = ComprobantePago | ||
68 | + fields = ('monto', | ||
69 | + 'edicto', | ||
70 | + ) | ||
71 | + read_only_fields = ('monto', ) | ||
72 | + | ||
73 | + included_serializers = { | ||
74 | + 'edicto': EdictoSerializer, | ||
75 | + } | ||
76 | + | ||
77 | + def validate(self, data): | ||
78 | + edicto = data.get('edicto') | ||
79 | + if edicto and edicto.estado != 'pendiente_de_pago': | ||
80 | + raise serializers.ValidationError( | ||
81 | + "El edicto debe estar en estado 'pendiente de pago' para visualizar el monto a pagar.") | ||
82 | + | ||
83 | + return data | ||
84 | + | ||
85 | + | ||
86 | +class ComprobanteSerializer(serializers.ModelSerializer): | ||
87 | + | ||
88 | + class Meta: | ||
89 | + model = ComprobantePago | ||
90 | + fields = ('numero_comprobante', | ||
91 | + 'fecha_pago', | ||
92 | + ) | ||
93 | + | ||
94 | + included_serializers = { | ||
95 | + 'edicto': EdictoSerializer, | ||
96 | + 'monto': 'monto.serializers.PagoSerialzer', | ||
97 | + } |
@@ -2,7 +2,7 @@ from rest_framework import routers | @@ -2,7 +2,7 @@ from rest_framework import routers | ||
2 | 2 | ||
3 | from organismo import api as organismo_api | 3 | from organismo import api as organismo_api |
4 | from usuario import api as usuario_api | 4 | from usuario import api as usuario_api |
5 | -from edicto.api import EdictoViewSet | 5 | +from edicto.api import EdictoViewSet, ComprobanteViewSets |
6 | from edicto import api as edicto_api | 6 | from edicto import api as edicto_api |
7 | # Define routes | 7 | # Define routes |
8 | router = routers.DefaultRouter() | 8 | router = routers.DefaultRouter() |
@@ -11,5 +11,7 @@ router.register(prefix='usuario', viewset=usuario_api.UsuarioViewSet) | @@ -11,5 +11,7 @@ router.register(prefix='usuario', viewset=usuario_api.UsuarioViewSet) | ||
11 | router.register(prefix='organismo', viewset=organismo_api.OrganismoViewSet) | 11 | router.register(prefix='organismo', viewset=organismo_api.OrganismoViewSet) |
12 | router.register(r'edicto', EdictoViewSet, basename='edicto') | 12 | router.register(r'edicto', EdictoViewSet, basename='edicto') |
13 | router.register(prefix='precio', viewset=edicto_api.PrecioViewSet) | 13 | router.register(prefix='precio', viewset=edicto_api.PrecioViewSet) |
14 | +router.register(prefix='pago', viewset=edicto_api.PagoViewSets) | ||
15 | +router.register(r'comprobante', ComprobanteViewSets, basename='comprobante') | ||
14 | 16 | ||
15 | 17 |
-
Please register or login to post a comment