diff --git a/tienda_ilusion/don_confiao/api/provenance.py b/tienda_ilusion/don_confiao/api/provenance.py index f497580..cef3259 100644 --- a/tienda_ilusion/don_confiao/api/provenance.py +++ b/tienda_ilusion/don_confiao/api/provenance.py @@ -92,7 +92,7 @@ class SeedGeographyView(APIView): if created: departments_created += 1 - _, created = Municipality.objects.get_or_create( + municipality, created = Municipality.objects.get_or_create( name=municipality_data["name"], department=department, defaults={"country": country}, @@ -100,6 +100,16 @@ class SeedGeographyView(APIView): if created: municipalities_created += 1 + latitude = municipality_data.get("latitude") + longitude = municipality_data.get("longitude") + if latitude is not None or longitude is not None: + municipality.country = country + if latitude is not None: + municipality.latitude = latitude + if longitude is not None: + municipality.longitude = longitude + municipality.save() + return Response( { "country": country.name, diff --git a/tienda_ilusion/don_confiao/migrations/0054_municipality_latitude_municipality_longitude.py b/tienda_ilusion/don_confiao/migrations/0054_municipality_latitude_municipality_longitude.py new file mode 100644 index 0000000..fd89a4d --- /dev/null +++ b/tienda_ilusion/don_confiao/migrations/0054_municipality_latitude_municipality_longitude.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2026-08-16 08:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('don_confiao', '0053_country_organization_department_municipality_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='municipality', + name='latitude', + field=models.DecimalField(blank=True, decimal_places=7, max_digits=10, null=True), + ), + migrations.AddField( + model_name='municipality', + name='longitude', + field=models.DecimalField(blank=True, decimal_places=7, max_digits=10, null=True), + ), + ] diff --git a/tienda_ilusion/don_confiao/models/geography.py b/tienda_ilusion/don_confiao/models/geography.py index 277676c..6459caf 100644 --- a/tienda_ilusion/don_confiao/models/geography.py +++ b/tienda_ilusion/don_confiao/models/geography.py @@ -39,6 +39,12 @@ class Municipality(models.Model): country = models.ForeignKey( Country, on_delete=models.PROTECT, related_name="municipalities" ) + latitude = models.DecimalField( + max_digits=10, decimal_places=7, null=True, blank=True + ) + longitude = models.DecimalField( + max_digits=10, decimal_places=7, null=True, blank=True + ) class Meta: verbose_name = "Municipality" diff --git a/tienda_ilusion/don_confiao/serializers/geography.py b/tienda_ilusion/don_confiao/serializers/geography.py index e1a5abb..c53559c 100644 --- a/tienda_ilusion/don_confiao/serializers/geography.py +++ b/tienda_ilusion/don_confiao/serializers/geography.py @@ -24,7 +24,7 @@ class DepartmentBriefSerializer(serializers.ModelSerializer): class MunicipalityBriefSerializer(serializers.ModelSerializer): class Meta: model = Municipality - fields = ["id", "name"] + fields = ["id", "name", "latitude", "longitude"] class DepartmentSerializer(serializers.ModelSerializer): @@ -43,4 +43,13 @@ class MunicipalitySerializer(serializers.ModelSerializer): class Meta: model = Municipality - fields = ["id", "name", "department", "department_detail", "country", "country_detail"] + fields = [ + "id", + "name", + "department", + "department_detail", + "country", + "country_detail", + "latitude", + "longitude", + ] diff --git a/tienda_ilusion/don_confiao/tests/test_geography_models.py b/tienda_ilusion/don_confiao/tests/test_geography_models.py index eb5c77f..3712628 100644 --- a/tienda_ilusion/don_confiao/tests/test_geography_models.py +++ b/tienda_ilusion/don_confiao/tests/test_geography_models.py @@ -68,6 +68,26 @@ class TestMunicipalityModel(TestCase): self.assertEqual(municipality.department.country.name, "Colombia") self.assertEqual(str(municipality), "La Mesa") + def test_municipality_geolocation_fields(self): + municipality = Municipality.objects.create( + name="La Mesa", + department=self.department, + country=self.country, + latitude=4.63092, + longitude=-74.39152, + ) + self.assertEqual(municipality.latitude, 4.63092) + self.assertEqual(municipality.longitude, -74.39152) + + def test_municipality_geolocation_optional(self): + municipality = Municipality.objects.create( + name="La Mesa", + department=self.department, + country=self.country, + ) + self.assertIsNone(municipality.latitude) + self.assertIsNone(municipality.longitude) + def test_municipality_requires_department_and_country(self): with self.assertRaises(IntegrityError): with transaction.atomic(): diff --git a/tienda_ilusion/don_confiao/tests/test_provenance_api.py b/tienda_ilusion/don_confiao/tests/test_provenance_api.py index abcd719..2a7c5cb 100644 --- a/tienda_ilusion/don_confiao/tests/test_provenance_api.py +++ b/tienda_ilusion/don_confiao/tests/test_provenance_api.py @@ -241,6 +241,27 @@ class TestProvenanceCRUD(APITestCase, LoginMixin): self.assertEqual(data["country_detail"]["name"], "Colombia") self.assertEqual(data["country_detail"]["code"], "CO") + def test_municipality_serializer_includes_geolocation(self): + self.municipality.latitude = 4.63092 + self.municipality.longitude = -74.39152 + self.municipality.save() + response = self.client.get( + f"/don_confiao/api/municipalities/{self.municipality.id}/" + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + data = response.json() + self.assertEqual(float(data["latitude"]), 4.63092) + self.assertEqual(float(data["longitude"]), -74.39152) + + def test_municipality_serializer_geolocation_optional(self): + response = self.client.get( + f"/don_confiao/api/municipalities/{self.municipality.id}/" + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + data = response.json() + self.assertIsNone(data["latitude"]) + self.assertIsNone(data["longitude"]) + def test_link_product_to_suppliers_via_product_api(self): product = Product.objects.create(name="Panela", price=5000) supplier2 = Supplier.objects.create(name="Proveedor 2") @@ -315,6 +336,37 @@ class TestSeedGeography(APITestCase, LoginMixin): self.assertEqual(Department.objects.count(), 1) self.assertEqual(Municipality.objects.count(), 2) + def test_seed_creates_municipality_with_geolocation(self): + self.login() + payload = self._payload() + payload["municipalities"][0] = { + "name": "La Mesa", + "department": "Cundinamarca", + "latitude": 4.63092, + "longitude": -74.39152, + } + response = self.client.post(self.url, payload, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + municipality = Municipality.objects.get(name="La Mesa") + self.assertEqual(float(municipality.latitude), 4.63092) + self.assertEqual(float(municipality.longitude), -74.39152) + + def test_seed_updates_geolocation_on_reseed(self): + self.login() + self.client.post(self.url, self._payload(), format="json") + payload = self._payload() + payload["municipalities"][0] = { + "name": "La Mesa", + "department": "Cundinamarca", + "latitude": 4.63092, + "longitude": -74.39152, + } + response = self.client.post(self.url, payload, format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + municipality = Municipality.objects.get(name="La Mesa") + self.assertEqual(float(municipality.latitude), 4.63092) + self.assertEqual(float(municipality.longitude), -74.39152) + def test_seed_requires_country_name(self): self.login() response = self.client.post( diff --git a/tienda_ilusion/don_confiao/tests/test_provenance_graphs.py b/tienda_ilusion/don_confiao/tests/test_provenance_graphs.py index dd6c1de..67184ad 100644 --- a/tienda_ilusion/don_confiao/tests/test_provenance_graphs.py +++ b/tienda_ilusion/don_confiao/tests/test_provenance_graphs.py @@ -75,6 +75,23 @@ class TestProvenanceInSummaries(APITestCase, LoginMixin): self.assertEqual(supplier["department"]["name"], "Cundinamarca") self.assertEqual(supplier["country"]["name"], "Colombia") + def test_public_summary_municipality_includes_geolocation(self): + self.municipality.latitude = 4.63092 + self.municipality.longitude = -74.39152 + self.municipality.save() + sale = self._create_sale() + response = self.client.get( + f"/don_confiao/resumen_publico/{sale.code}" + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + supplier = response.json()["product_provenance"][0]["suppliers"][0] + self.assertEqual( + float(supplier["municipality"]["latitude"]), 4.63092 + ) + self.assertEqual( + float(supplier["municipality"]["longitude"]), -74.39152 + ) + def test_public_catalog_summary_includes_product_provenance(self): catalog_sale = self._create_catalog_sale() response = self.client.get(