diff --git a/accounts/admin.py b/accounts/admin.py index 77300ee..15b1c65 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -40,7 +40,7 @@ from .models import IAmPrincipalLocation class IAmPrincipalLocationAdmin(admin.ModelAdmin): - list_display = ("id", "principal", "latitude", "longitude") + list_display = ("id", "principal", "latitude", "longitude", "created_on", "modified_on") search_fields = ( "principal__first_name", "principal__last_name", diff --git a/accounts/migrations/0011_alter_iamprincipallocation_principal.py b/accounts/migrations/0011_alter_iamprincipallocation_principal.py new file mode 100644 index 0000000..885aedf --- /dev/null +++ b/accounts/migrations/0011_alter_iamprincipallocation_principal.py @@ -0,0 +1,24 @@ +# Generated by Django 5.0.2 on 2024-06-20 08:17 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0010_alter_appversion_app_type"), + ] + + operations = [ + migrations.AlterField( + model_name="iamprincipallocation", + name="principal", + field=models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="principal_location", + to=settings.AUTH_USER_MODEL, + ), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index c3f5508..1bc9b89 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -419,7 +419,7 @@ class IAmPrincipalBiometric(BaseModel): class IAmPrincipalLocation(BaseModel): - principal = models.ForeignKey( + principal = models.OneToOneField( IAmPrincipal, related_name="principal_location", on_delete=models.CASCADE ) latitude = models.DecimalField(max_digits=18, decimal_places=15) @@ -432,76 +432,6 @@ class IAmPrincipalLocation(BaseModel): return f"{self.principal.first_name}:{self.latitude}, {self.longitude}" -# Excluded in migrations -# class IAmPrincipalKYCDetails(models.Model): -# # the below is the table structure from Hritik Dhanawde for KYC -# kid = -# status = -# customer_identifier = -# reference_id = -# customer_name = -# reference_id = -# customer_name = -# workflow_name = -# template_id = -# kyc_created_at = -# access_token = - -# # Regex pattern for Aadhar number with exactly 12 digits -# AADHAR_REGEX = r"^\d{12}$" -# # Regex pattern for PAN number in the format AAAAB1234C -# PAN_REGEX = r"^[A-Z]{5}[0-9]{4}[A-Z]$" -# # Regex pattern for IFSC code (11 alphanumeric characters) -# IFSC_REGEX = r"^[A-Za-z]{4}\d{7}$" - -# principal = models.OneToOneField( -# IAmPrincipal, on_delete=models.CASCADE -# ) # Assuming IAmPrincipal is the user model. -# aadhar_front_image = models.ImageField(upload_to="kyc/", blank=True, null=True) -# aadhar_back_image = models.ImageField(upload_to="kyc/", blank=True, null=True) -# aadhar_number = models.CharField( -# max_length=12, -# blank=True, -# null=True, -# validators=[ -# RegexValidator(AADHAR_REGEX, message="Aadhar number must be 12 digits.") -# ], -# ) -# pan_image = models.ImageField(upload_to="kyc/", blank=True, null=True) -# pan_number = models.CharField( -# max_length=10, -# blank=True, -# null=True, -# validators=[ -# RegexValidator( -# PAN_REGEX, message="PAN number must be in the format AAAAB1234C." -# ) -# ], -# ) -# is_aadhar_verified = models.BooleanField(default=False) -# is_pan_verified = models.BooleanField(default=False) -# account_no = models.CharField(max_length=20, blank=True, null=True) -# bank_name = models.CharField(max_length=100, blank=True, null=True) -# branch_name = models.CharField(max_length=100, blank=True, null=True) -# ifsc_code = models.CharField( -# max_length=11, -# blank=True, -# null=True, -# validators=[ -# RegexValidator( -# IFSC_REGEX, message="IFSC code must be 11 alphanumeric characters." -# ) -# ], -# ) - -# class Meta: -# db_table = "iam_principal_kyc_details" - - -# def __str__(self): -# return f"KYC Information for {self.principal.email}" - - class AppType(models.TextChoices): ANDROID = "android", "android" IOS = "ios", "ios" diff --git a/manage_events/api/serializers.py b/manage_events/api/serializers.py index 7a455ef..5bb1756 100644 --- a/manage_events/api/serializers.py +++ b/manage_events/api/serializers.py @@ -107,6 +107,8 @@ class EventDetailSerializer(serializers.ModelSerializer): "entry_type", "entry_fee", "key_guest", + "coupon_code", + "coupon_description", "age_group", "images", "is_favorited", @@ -177,6 +179,8 @@ class CreateEventSerializer(serializers.ModelSerializer): "draft", "venue", "tags", + "coupon_code", + "coupon_description", ] def create(self, validated_data): @@ -236,32 +240,6 @@ class IAmPrincipalLocationSerializer(serializers.ModelSerializer): model = IAmPrincipalLocation fields = ["latitude", "longitude"] - def create(self, validated_data): - principal = self.context["request"].user - latitude = validated_data.get("latitude") - longitude = validated_data.get("longitude") - location = get_location_info(latitude=latitude, longitude=longitude) - print("location: ", location) - city = location.get("city") - state = location.get("state") - country = location.get("country") - country_code = location.get("country_code") - - if hasattr(principal, "city"): - principal.city = city or state # Use state as city if city is not found - if hasattr(principal, "state"): - principal.state = state - if hasattr(principal, "country"): - principal.country = country - if hasattr(principal, "address_line1"): - principal.address_line1 = country_code - - # save the principal object after making changes - principal.save() - return IAmPrincipalLocation.objects.create( - principal=principal, **validated_data - ) - class PrincipalPreferenceSerializer(serializers.ModelSerializer): preferred_categories = serializers.PrimaryKeyRelatedField( diff --git a/manage_events/api/views.py b/manage_events/api/views.py index 9bc35ce..ac54d17 100644 --- a/manage_events/api/views.py +++ b/manage_events/api/views.py @@ -42,7 +42,7 @@ from manage_events.models import ( ) import requests -from manage_events.utils import haversine_one +from manage_events.utils import haversine_one, update_principal_location class CreateEventApi(APIView): @@ -112,7 +112,14 @@ class CreateVenueApi(APIView): permission_classes = [IsAuthenticated] def post(self, request): - serializer = VenueSerializer(data=request.data, context={"request": request}) + + data = request.data.copy() + + # Convert latitude and longitude to float and round to 8 decimal places + data["latitude"] = round(float(data["latitude"]), 8) + data["longitude"] = round(float(data["longitude"]), 8) + + serializer = VenueSerializer(data=data, context={"request": request}) serializer.is_valid(raise_exception=True) serializer.save(created_by=self.request.user, active=True) @@ -464,22 +471,58 @@ class IAmPrincipalLocationAPIView(APIView): ) def post(self, request, *args, **kwargs): - serializer = IAmPrincipalLocationSerializer( - data=request.data, context={"request": request} - ) - print("serializer: ", serializer) - if serializer.is_valid(): - serializer.save() + data = request.data.copy() + + # Convert latitude and longitude to float and round to 8 decimal places + latitude = round(float(data["latitude"]), 15) + longitude = round(float(data["longitude"]), 15) + + try: + principal = request.user + location = IAmPrincipalLocation.objects.get(principal=principal) + + # Update existing location + location.latitude = latitude + location.longitude = longitude + location.save() + + # Update principal fields using the utility function + update_principal_location(principal, latitude, longitude) + + serializer = IAmPrincipalLocationSerializer( + location, context={"request": request} + ) return ApiResponse.success( status=status.HTTP_200_OK, message=constants.SUCCESS, data=serializer.data, ) - return ApiResponse.error( - status=status.HTTP_400_BAD_REQUEST, - message=constants.FAILURE, - errors=serializer.errors, - ) + + except IAmPrincipalLocation.DoesNotExist: + # Create a new location object + location = IAmPrincipalLocation.objects.create( + principal=principal, latitude=latitude, longitude=longitude + ) + + # Update principal fields using the utility function + update_principal_location(principal, latitude, longitude) + + serializer = IAmPrincipalLocationSerializer( + location, context={"request": request} + ) + return ApiResponse.success( + status=status.HTTP_201_CREATED, + message=constants.SUCCESS, + data=serializer.data, + ) + + except Exception as e: + print(f"Error occurred while saving location: {e}") + return ApiResponse.error( + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + message=constants.FAILURE, + errors=str(e), + ) class PrincipalPreferenceView(APIView): diff --git a/manage_events/migrations/0012_event_coupon_code_event_coupon_description.py b/manage_events/migrations/0012_event_coupon_code_event_coupon_description.py new file mode 100644 index 0000000..4fc4935 --- /dev/null +++ b/manage_events/migrations/0012_event_coupon_code_event_coupon_description.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.2 on 2024-06-20 06:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("manage_events", "0011_alter_event_entry_type"), + ] + + operations = [ + migrations.AddField( + model_name="event", + name="coupon_code", + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name="event", + name="coupon_description", + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/manage_events/models.py b/manage_events/models.py index b9d122b..6811f2f 100644 --- a/manage_events/models.py +++ b/manage_events/models.py @@ -78,21 +78,20 @@ class Event(BaseModel): venue_capacity = models.IntegerField() video_url = models.URLField(max_length=200, blank=True, null=True) - # entry_type = models.CharField( - # max_length=100 - # ) entry_type = models.CharField( max_length=10, choices=ENTRY_TYPE_CHOICES, ) entry_fee = models.DecimalField( max_digits=14, decimal_places=2, default=0.00 - ) # Assuming it's an integer. Use DecimalField if you need to handle cents. + ) key_guest = models.TextField(blank=True, null=True) tags = TaggableManager(blank=True) age_group = models.CharField(max_length=100, blank=True, null=True) draft = models.BooleanField(default=False) social_media_shares_count = models.IntegerField(default=0) + coupon_code = models.CharField(max_length=255, blank=True, null=True) + coupon_description = models.TextField(blank=True, null=True) def increment_shares(self): self.social_media_shares_count += 1 diff --git a/manage_events/report.py b/manage_events/report.py index 5f571b4..704ce90 100644 --- a/manage_events/report.py +++ b/manage_events/report.py @@ -248,7 +248,7 @@ def generate_event_report_pdf_three(user, report_data): ] ) - table = Table(data, colWidths=[50, 200, 150, 100]) + table = Table(data, colWidths=[50, 250, 150, 100]) style = TableStyle( [ ("BACKGROUND", (0, 0), (-1, 0), colors.grey), diff --git a/manage_events/utils.py b/manage_events/utils.py index 1037987..8600c50 100644 --- a/manage_events/utils.py +++ b/manage_events/utils.py @@ -1,4 +1,5 @@ import math +from accounts.models import IAmPrincipal from manage_events.models import Event, Venue from django.utils.timezone import now import googlemaps @@ -104,3 +105,23 @@ def get_location_info(latitude, longitude): } else: return {} + + +def update_principal_location(principal, latitude, longitude): + location_data = get_location_info(latitude=latitude, longitude=longitude) + + city = location_data.get("city") + state = location_data.get("state") + country = location_data.get("country") + country_code = location_data.get("country_code") + + if hasattr(principal, "city"): + principal.city = city or state + if hasattr(principal, "state"): + principal.state = state + if hasattr(principal, "country"): + principal.country = country + if hasattr(principal, "address_line1"): + principal.address_line1 = country_code + + principal.save()