Skip to content

Commit 08d4778

Browse files
Merge pull request #35 from Kalgoc/develop
Develop
2 parents ba9ffdf + 09d8d27 commit 08d4778

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+619
-152
lines changed

.flake8

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[flake8]
22
exclude = .git,__pycache__,old,build,dist,.venv, */migrations/*
3-
ignore = E226,E302,E41,F401,F403,F405
3+
ignore = E226,E302,E41,F401,F403,F405,W503
44
max-line-length = 120
55
max-complexity = 10

AI/AI.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,28 @@
33
import os
44
from textwrap import dedent
55
from dotenv import load_dotenv
6+
from categories.models import Category
67

78

8-
def setup_api_key():
9-
env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env")
10-
load_dotenv(dotenv_path=env_path)
11-
openai.api_key = os.getenv("OPENAI_KEY")
9+
GPT_MODEL = "gpt-4-turbo"
10+
11+
12+
def get_category_name_from_description(description):
13+
classified_category = classify_text(description)
14+
cleaned_category = category_matched_with_id(classified_category)
15+
16+
if not Category.objects.filter(name=cleaned_category).exists():
17+
raise ValueError("Categoría no encontrada.")
18+
return cleaned_category
1219

1320

1421
def classify_text(texto):
22+
setup_api_key()
23+
if not openai.api_key:
24+
raise ValueError("OpenAI API key is not set. Please check your .env file.")
25+
1526
response = openai.ChatCompletion.create(
16-
model="gpt-4-turbo",
27+
model=GPT_MODEL,
1728
messages=[
1829
{
1930
"role": "system",
@@ -43,7 +54,13 @@ def classify_text(texto):
4354
return category
4455

4556

46-
def clean_category(category):
57+
def setup_api_key():
58+
env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env")
59+
load_dotenv(dotenv_path=env_path)
60+
openai.api_key = os.getenv("OPENAI_KEY")
61+
62+
63+
def category_matched_with_id(category):
4764
if category.lower().startswith("categoría: "):
4865
category = category[11:]
4966
if category.endswith("."):

AI/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# flake8: noqa
2-
from .AI import setup_api_key, classify_text, clean_category
2+
from .AI import setup_api_key, classify_text, category_matched_with_id

AI/tests.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
# flake8: noqa
22
import unittest
33
from unittest.mock import patch
4-
from AI import classify_text, clean_category
4+
from AI import classify_text, category_matched_with_id
55
from textwrap import dedent
66

77

88
class TestGastosClassifier(unittest.TestCase):
9-
109
@patch("openai.ChatCompletion.create")
1110
def test_classify_text(self, mock_create):
1211
# Configurar el mock para devolver una respuesta simulada
@@ -50,13 +49,13 @@ def test_classify_text(self, mock_create):
5049

5150
def test_clean_category(self):
5251
# Pruebas con diferentes casos
53-
self.assertEqual(clean_category("Categoría: Comida."), "Comida")
54-
self.assertEqual(clean_category("categoría: transporte"), "Transporte")
55-
self.assertEqual(clean_category("vivienda."), "Vivienda")
52+
self.assertEqual(category_matched_with_id("Categoría: Comida."), "Comida")
53+
self.assertEqual(category_matched_with_id("categoría: transporte"), "Transporte")
54+
self.assertEqual(category_matched_with_id("vivienda."), "Vivienda")
5655

5756
# Prueba de una categoría no permitida
5857
with self.assertRaises(ValueError):
59-
clean_category("Categoría: Viajes.")
58+
category_matched_with_id("Categoría: Viajes.")
6059

6160

6261
if __name__ == "__main__":

authentication/serializers.py

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ class Meta:
88
fields = ["user_id", "first_name", "phone", "email"]
99

1010

11+
class UserMinimalSerializer(serializers.ModelSerializer):
12+
class Meta:
13+
model = User
14+
fields = ["user_id", "first_name"]
15+
16+
1117
class RegisterSerializer(serializers.Serializer):
1218
name = serializers.CharField(max_length=150)
1319
phone = serializers.CharField(max_length=15)

authentication/services/cognito_service.py

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import hashlib
55
import base64
66
from django.contrib.auth import get_user_model
7+
from user_expense_type.models import UserExpenseType
78

89

910
class CognitoService:
@@ -38,6 +39,10 @@ def register_user(self, name, phone, email, password):
3839
User.objects.create_user(
3940
username=email, email=email, password=password, first_name=name, phone=phone, user_id=cognito_uuid
4041
)
42+
user_expense_type = UserExpenseType.objects.create(
43+
username=cognito_uuid, set_by_user=False, name="Personal"
44+
)
45+
user_expense_type.save()
4146
return response
4247
except ClientError as e:
4348
raise e

authentication/views.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,7 @@ def get(self, request):
7979
username = self.get_user_id_from_token(request)
8080
user = User.objects.get(user_id=username)
8181
return Response(
82-
{
83-
"user_id": user.user_id,
84-
"first_name": user.first_name,
85-
},
82+
{"user_id": user.user_id, "first_name": user.first_name, "email": user.email},
8683
status=status.HTTP_200_OK,
8784
)
8885
except User.DoesNotExist:

bankcard/__init__.py

Whitespace-only changes.

bankcard/admin.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from django.contrib import admin
2+
from .models import BankCard
3+
4+
5+
@admin.register(BankCard)
6+
class BankCardAdmin(admin.ModelAdmin):
7+
list_display = (
8+
"id",
9+
"user_id",
10+
"account_number",
11+
"bank_name",
12+
"card_type",
13+
"created_at",
14+
"updated_at",
15+
)

bankcard/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class BankCardConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "bankcard"

bankcard/migrations/0001_initial.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Generated by Django 5.0.6 on 2024-06-30 22:17
2+
3+
import django.db.models.deletion
4+
from django.conf import settings
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
initial = True
11+
12+
dependencies = [
13+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name="BankCard",
19+
fields=[
20+
("id", models.AutoField(primary_key=True, serialize=False)),
21+
("account_number", models.IntegerField()),
22+
("bank_name", models.CharField(max_length=128)),
23+
("card_type", models.CharField(max_length=128)),
24+
("created_at", models.DateTimeField(auto_now_add=True)),
25+
("updated_at", models.DateTimeField(auto_now=True)),
26+
(
27+
"user_id",
28+
models.ForeignKey(
29+
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field="user_id"
30+
),
31+
),
32+
],
33+
),
34+
]

bankcard/migrations/__init__.py

Whitespace-only changes.

bankcard/models.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.db import models
2+
from django.conf import settings
3+
4+
5+
class BankCard(models.Model):
6+
id = models.AutoField(primary_key=True)
7+
user_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, to_field="user_id")
8+
account_number = models.IntegerField()
9+
bank_name = models.CharField(max_length=128)
10+
card_type = models.CharField(max_length=128)
11+
created_at = models.DateTimeField(auto_now_add=True)
12+
updated_at = models.DateTimeField(auto_now=True)

bankcard/serializers.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from rest_framework import serializers
2+
from .models import BankCard
3+
4+
5+
class BankCardSerializer(serializers.ModelSerializer):
6+
class Meta:
7+
model = BankCard
8+
fields = "__all__"
9+
10+
def create(self, validated_data):
11+
return BankCard.objects.create(**validated_data)

bankcard/tests.py

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from django.test import TestCase
2+
from unittest.mock import patch
3+
from rest_framework.test import APIClient
4+
from rest_framework import status
5+
from authentication.services.cognito_service import CognitoService
6+
from rest_framework.response import Response
7+
from .views import BankCardViewSet
8+
9+
10+
class BankCardViewSetTestCase(TestCase):
11+
def setUp(self):
12+
self.client = APIClient()
13+
self.view = BankCardViewSet()
14+
self.card = {
15+
"account_number": 44467861,
16+
"bank_name": "Super Bank",
17+
"card_type": "credit",
18+
}
19+
20+
@patch.object(BankCardViewSet, "create")
21+
@patch.object(CognitoService, "login_user")
22+
def test_create(self, mock_login_user, mock_create):
23+
mock_login_user.return_value = {
24+
"AuthenticationResult": {"access_token": "mock_access_token", "id_token": "mock_id_token"}
25+
}
26+
mock_create.return_value = Response(status=status.HTTP_201_CREATED, data=self.card)
27+
28+
request = self.client.post("/bankcard/", self.card)
29+
request.headers["Authorization"] = "Bearer mock_access_token"
30+
31+
response = self.client.post("/bankcard/", self.card)
32+
33+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
34+
self.assertEqual(response.data["account_number"], 44467861)
35+
36+
@patch.object(BankCardViewSet, "list")
37+
@patch.object(CognitoService, "login_user")
38+
def test_list(self, mock_login_user, mock_list):
39+
mock_login_user.return_value = {
40+
"AuthenticationResult": {"access_token": "mock_access_token", "id_token": "mock_id_token"}
41+
}
42+
mock_list.return_value = Response(status=status.HTTP_200_OK, data=[self.card])
43+
44+
request = self.client.get("/bankcard/")
45+
request.headers["Authorization"] = "Bearer mock_access_token"
46+
47+
response = self.client.get("/bankcard/")
48+
49+
self.assertEqual(response.status_code, status.HTTP_200_OK)
50+
self.assertEqual(response.data[0]["account_number"], 44467861)
51+
52+
@patch.object(BankCardViewSet, "retrieve")
53+
@patch.object(CognitoService, "login_user")
54+
def test_retrieve(self, mock_login_user, mock_retrieve):
55+
mock_login_user.return_value = {
56+
"AuthenticationResult": {"access_token": "mock_access_token", "id_token": "mock_id_token"}
57+
}
58+
mock_retrieve.return_value = Response(status=status.HTTP_200_OK, data=self.card)
59+
60+
request = self.client.get("/bankcard/1/")
61+
request.headers["Authorization"] = "Bearer mock_access_token"
62+
63+
response = self.client.get("/bankcard/1/")
64+
65+
self.assertEqual(response.status_code, status.HTTP_200_OK)
66+
self.assertEqual(response.data["account_number"], 44467861)
67+
68+
@patch.object(BankCardViewSet, "destroy")
69+
@patch.object(CognitoService, "login_user")
70+
def test_destroy(self, mock_login_user, mock_destroy):
71+
mock_login_user.return_value = {
72+
"AuthenticationResult": {"access_token": "mock_access_token", "id_token": "mock_id_token"}
73+
}
74+
mock_destroy.return_value = Response(status=status.HTTP_204_NO_CONTENT)
75+
76+
request = self.client.delete("/bankcard/1/")
77+
request.headers["Authorization"] = "Bearer mock_access_token"
78+
79+
response = self.client.delete("/bankcard/1/")
80+
81+
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
82+
83+
@patch.object(BankCardViewSet, "partial_update")
84+
@patch.object(CognitoService, "login_user")
85+
def test_partial_update(self, mock_login_user, mock_partial_update):
86+
mock_login_user.return_value = {
87+
"AuthenticationResult": {"access_token": "mock_access_token", "id_token": "mock_id_token"}
88+
}
89+
update = {
90+
"account_number": 44467861,
91+
"bank_name": "Super Earth Bank",
92+
"card_type": "credit",
93+
}
94+
mock_partial_update.return_value = Response(status=status.HTTP_200_OK, data=update)
95+
96+
request = self.client.put("/bankcard/1/", {"bank_name": "Super Earth Bank"})
97+
request.headers["Authorization"] = "Bearer mock_access_token"
98+
99+
response = self.client.put("/bankcard/1/", {"bank_name": "Super Earth Bank"})
100+
101+
self.assertEqual(response.status_code, status.HTTP_200_OK)
102+
self.assertEqual(response.data["account_number"], 44467861)

bankcard/urls.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from django.urls import path
2+
from .views import BankCardViewSet
3+
4+
urlpatterns = [
5+
path(
6+
"",
7+
BankCardViewSet.as_view({"get": "list", "post": "create"}),
8+
name="bankcard",
9+
),
10+
path(
11+
"<int:pk>/",
12+
BankCardViewSet.as_view({"get": "retrieve", "delete": "destroy", "put": "partial_update"}),
13+
name="individual",
14+
),
15+
]

0 commit comments

Comments
 (0)