Martín Miranda

Merge branch 'feature/#51_quiero_visualizar_monto_a_pagar' into 'develop'

feature/#51_quiero_visualizar_monto_a_pagar



See merge request !65
@@ -4,7 +4,7 @@ from .models import Edicto, Precio @@ -4,7 +4,7 @@ from .models import Edicto, Precio
4 4
5 # Register your models here. 5 # Register your models here.
6 6
7 -admin.site.register(Precio)  
8 7
  8 +admin.site.register(Precio)
9 9
10 admin.site.register(Edicto) 10 admin.site.register(Edicto)
@@ -8,9 +8,9 @@ from core.serializers import ActionSerializer @@ -8,9 +8,9 @@ from core.serializers import ActionSerializer
8 from rest_framework.response import Response 8 from rest_framework.response import Response
9 9
10 from .filters import EdictoFilter, PrecioFilter 10 from .filters import EdictoFilter, PrecioFilter
11 -from .models import Edicto, Precio 11 +from .models import Edicto, Precio, ComprobantePago
12 from .permissions import IsAdminOrAuthorized 12 from .permissions import IsAdminOrAuthorized
13 -from .serializers import EdictoSerializer, PrecioSerializer 13 +from .serializers import EdictoSerializer, PrecioSerializer, ComprobanteSerializer
14 14
15 15
16 class EdictoViewSet(AuditoriaMixin, mixins.CreateModelMixin, 16 class EdictoViewSet(AuditoriaMixin, mixins.CreateModelMixin,
@@ -52,3 +52,18 @@ class PrecioViewSet(AuditoriaMixin, viewsets.ReadOnlyModelViewSet): @@ -52,3 +52,18 @@ class PrecioViewSet(AuditoriaMixin, viewsets.ReadOnlyModelViewSet):
52 ordering_fields = ('usuario',) 52 ordering_fields = ('usuario',)
53 ordering = 'usuario' 53 ordering = 'usuario'
54 queryset = Precio.objects.all() 54 queryset = Precio.objects.all()
  55 +
  56 +
  57 +class ComprobanteViewSet(mixins.UpdateModelMixin,
  58 + mixins.RetrieveModelMixin,
  59 + mixins.ListModelMixin,
  60 + viewsets.GenericViewSet,
  61 + ):
  62 +
  63 + serializer_class = ComprobanteSerializer
  64 + permission_classes = [IsAuthenticated, ]
  65 + queryset = ComprobantePago.objects.all()
  66 + ordering_fields = ('edicto',)
  67 + ordering = 'id'
  68 +
  69 +
  1 +# Generated by Django 4.1.9 on 2023-10-02 10:03
  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', '0002_remove_comprobantepago_monto_and_more'),
  11 + ]
  12 +
  13 + operations = [
  14 + migrations.AlterField(
  15 + model_name='comprobantepago',
  16 + name='edicto',
  17 + field=models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='edicto.edicto'),
  18 + ),
  19 + ]
  1 +# Generated by Django 4.1.9 on 2023-10-03 11:23
  2 +
  3 +from django.conf import settings
  4 +from django.db import migrations, models
  5 +import django.db.models.deletion
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + dependencies = [
  11 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  12 + ('edicto', '0003_alter_comprobantepago_edicto'),
  13 + ]
  14 +
  15 + operations = [
  16 + migrations.AlterField(
  17 + model_name='precio',
  18 + name='usuario',
  19 + field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
  20 + ),
  21 + ]
@@ -13,7 +13,7 @@ class Precio(models.Model): @@ -13,7 +13,7 @@ class Precio(models.Model):
13 precio = models.FloatField(max_length=50, blank=False, null=False) 13 precio = models.FloatField(max_length=50, blank=False, null=False)
14 vigencia_desde = models.DateField() 14 vigencia_desde = models.DateField()
15 vigencia_hasta = models.DateField(blank=True, null=True) 15 vigencia_hasta = models.DateField(blank=True, null=True)
16 - usuario = models.ForeignKey(Usuario, on_delete=models.CASCADE) 16 + usuario = models.ForeignKey(Usuario, on_delete=models.CASCADE, editable=False)
17 moneda = models.CharField(max_length=50, blank=False, null=False, choices=MONEDA, 17 moneda = models.CharField(max_length=50, blank=False, null=False, choices=MONEDA,
18 default='peso_argentino') 18 default='peso_argentino')
19 precio_ejemplar = models.FloatField(max_length=50, blank=False, null=False) 19 precio_ejemplar = models.FloatField(max_length=50, blank=False, null=False)
@@ -65,8 +65,8 @@ class ComprobantePago(models.Model): @@ -65,8 +65,8 @@ class ComprobantePago(models.Model):
65 monto_descuento = models.FloatField(editable=False, null=True) 65 monto_descuento = models.FloatField(editable=False, null=True)
66 numero_comprobante = models.CharField(max_length=300, blank=True, null=True) 66 numero_comprobante = models.CharField(max_length=300, blank=True, null=True)
67 fecha_pago = models.DateTimeField(blank=True, null=True) 67 fecha_pago = models.DateTimeField(blank=True, null=True)
68 - edicto = models.OneToOneField(Edicto, on_delete=models.CASCADE) 68 + edicto = models.OneToOneField(Edicto, on_delete=models.CASCADE, editable=False)
69 archivo = models.FileField(upload_to="uploads/%Y/%m/%d/", blank=True) 69 archivo = models.FileField(upload_to="uploads/%Y/%m/%d/", blank=True)
70 70
71 def __str__(self): 71 def __str__(self):
72 - return self.numero_comprobante 72 + return f"{self.numero_comprobante} - ComprobantePago"
1 -from django.utils import timezone  
2 -from .models import Edicto, ComprobantePago, Precio  
3 -  
4 -  
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 -  
9 - sellos = edicto.cantidad_sellos  
10 - palabras = edicto.cantidad_palabras  
11 - copias = edicto.cantidad_copias  
12 - 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 -  
26 - if not (vigencia_desde <= current_datetime <= vigencia_hasta):  
27 - raise ValueError("El precio seleccionado no se encuentra dentro de las fechas permitidas.")  
28 -  
29 - result_palabra = (sellos + palabras) * precio  
30 - result_ejemplar = (copias * precio_ejemplar) + (publicar * precio_ejemplar)  
31 -  
32 - if organismo:  
33 - resultado = result_ejemplar + result_palabra / 2  
34 - else:  
35 - resultado = result_ejemplar + result_palabra  
36 -  
37 - precio_resultado = ComprobantePago(edicto=edicto, resultado=resultado)  
38 - precio_resultado.save()  
39 - return precio_resultado 1 +from .models import ComprobantePago
  2 +
  3 +
  4 +def calculadora(edicto, precio):
  5 + try:
  6 + descuento = edicto.tiene_descuento
  7 + sellos = edicto.cantidad_sellos
  8 + palabras = edicto.cantidad_palabras
  9 + copias = edicto.cantidad_copias
  10 + publicar = edicto.dias_publicar
  11 + precio_valores = {
  12 + 'precio': precio.precio,
  13 + 'precio_ejemplar': precio.precio_ejemplar,
  14 + 'precio_dia': precio.precio_dia
  15 + }
  16 +
  17 + result_palabra = (sellos + palabras) * precio_valores['precio']
  18 + result_ejemplar = (copias * precio_valores['precio_ejemplar']) + (publicar * precio_valores['precio_dia'])
  19 + subtotal = result_ejemplar + result_palabra
  20 +
  21 + if descuento:
  22 + resultado = (50 * subtotal) / 100
  23 + else:
  24 + resultado = ((100 - 50) * subtotal) / 100
  25 +
  26 + comprobante = ComprobantePago(monto_total=resultado,
  27 + monto_subtotal=subtotal,
  28 + monto_descuento=resultado,
  29 + edicto=edicto)
  30 + comprobante.save()
  31 +
  32 + return comprobante
  33 +
  34 + except ValueError as values:
  35 + raise ValueError("Los valores proporcionados son incorrectos: " + str(values))
@@ -2,8 +2,9 @@ from rest_framework import serializers @@ -2,8 +2,9 @@ from rest_framework import serializers
2 2
3 from usuario.serializers import UsuarioListaSerializer 3 from usuario.serializers import UsuarioListaSerializer
4 from .constants import EXTENSIONES_VALIDAS 4 from .constants import EXTENSIONES_VALIDAS
5 -from .models import Edicto, Precio 5 +from .models import Edicto, Precio, ComprobantePago
6 from .utils import contador 6 from .utils import contador
  7 +from .precio import calculadora
7 8
8 9
9 class EdictoSerializer(serializers.ModelSerializer): 10 class EdictoSerializer(serializers.ModelSerializer):
@@ -28,7 +29,8 @@ class EdictoSerializer(serializers.ModelSerializer): @@ -28,7 +29,8 @@ class EdictoSerializer(serializers.ModelSerializer):
28 'fecha_creacion', 29 'fecha_creacion',
29 'observaciones', 30 'observaciones',
30 'fecha_publicacion', 31 'fecha_publicacion',
31 - 'fecha_modificacion' 32 + 'fecha_modificacion',
  33 + 'tiene_descuento',
32 ) 34 )
33 35
34 read_only_fields = ('fecha_publicacion',) 36 read_only_fields = ('fecha_publicacion',)
@@ -40,9 +42,24 @@ class EdictoSerializer(serializers.ModelSerializer): @@ -40,9 +42,24 @@ class EdictoSerializer(serializers.ModelSerializer):
40 if request.method == 'POST': 42 if request.method == 'POST':
41 data['creado_por'] = request.user 43 data['creado_por'] = request.user
42 44
  45 + if data['creado_por'].organismo and data['creado_por'].organismo.es_publico:
  46 + data['tiene_descuento'] = True
  47 +
  48 + else:
  49 + data['tiene_descuento'] = False
  50 +
43 data['modificado_por'] = request.user 51 data['modificado_por'] = request.user
44 return data 52 return data
45 53
  54 + def create(self, validated_data):
  55 + edicto = Edicto.objects.create(**validated_data)
  56 +
  57 + precio = Precio.objects.latest('id')
  58 + calculadora(edicto, precio)
  59 +
  60 + edicto.save()
  61 + return edicto
  62 +
46 @staticmethod 63 @staticmethod
47 def validate_archivo(value): 64 def validate_archivo(value):
48 filename, extension = value.name.rsplit(".", 1) 65 filename, extension = value.name.rsplit(".", 1)
@@ -61,6 +78,31 @@ class PrecioSerializer(serializers.ModelSerializer): @@ -61,6 +78,31 @@ class PrecioSerializer(serializers.ModelSerializer):
61 'precio_ejemplar', 78 'precio_ejemplar',
62 'vigencia_desde', 79 'vigencia_desde',
63 'vigencia_hasta', 80 'vigencia_hasta',
  81 + 'precio_dia',
64 ) 82 )
65 83
66 - included_serializers = {'usuario': UsuarioListaSerializer} 84 + included_serializers = {'usuario': UsuarioListaSerializer
  85 + }
  86 +
  87 +
  88 +class ComprobanteSerializer(serializers.ModelSerializer):
  89 + class Meta:
  90 + model = ComprobantePago
  91 + fields = (
  92 + 'edicto',
  93 + 'monto_subtotal',
  94 + 'monto_total',
  95 + 'monto_descuento',
  96 + 'numero_comprobante',
  97 + 'fecha_pago',
  98 + 'archivo',
  99 + )
  100 +
  101 + included_serializers = {'edicto': EdictoSerializer}
  102 +
  103 + @staticmethod
  104 + def validate_archivo(value):
  105 + filename, extension = value.name.rsplit(".", 1)
  106 + if extension.lower() not in EXTENSIONES_VALIDAS:
  107 + raise serializers.ValidationError("Archivos permitidos: .pdf")
  108 + return value
1 from django.test import TestCase 1 from django.test import TestCase
2 from edicto.utils import contador 2 from edicto.utils import contador
  3 +from edicto.models import Edicto
3 4
4 5
5 class ContadorTestCase(TestCase): 6 class ContadorTestCase(TestCase):
@@ -14,3 +14,4 @@ router.register(prefix='organismo', viewset=organismo_api.OrganismoViewSet) @@ -14,3 +14,4 @@ router.register(prefix='organismo', viewset=organismo_api.OrganismoViewSet)
14 router.register(r'edicto', EdictoViewSet, basename='edicto') 14 router.register(r'edicto', EdictoViewSet, basename='edicto')
15 router.register(prefix='precio', viewset=edicto_api.PrecioViewSet) 15 router.register(prefix='precio', viewset=edicto_api.PrecioViewSet)
16 router.register(prefix='auditoria', viewset=core_api.AuditoriaViewSet) 16 router.register(prefix='auditoria', viewset=core_api.AuditoriaViewSet)
  17 +router.register(prefix='comprobante', viewset= edicto_api.ComprobanteViewSet)