Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Activités des structures): Adaptation de la commande de reprise de stock pour créer les activités #1476

Merged
merged 6 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 41 additions & 14 deletions lemarche/siaes/management/commands/create_siae_activities.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import lemarche.siaes.constants as siae_constants
from lemarche.perimeters.models import Perimeter
from lemarche.siaes.models import Siae, SiaeActivity
from lemarche.siaes.utils import match_location_to_perimeter
from lemarche.utils.commands import BaseCommand
from lemarche.utils.data import reset_app_sql_sequences

Expand Down Expand Up @@ -48,8 +48,7 @@ def handle(self, *args, **options):
self.stdout_info("-" * 80)
self.stdout_info("Creating SiaeActivities")
for index, siae in enumerate(siae_qs):
siae_location: Perimeter | None = match_location_to_perimeter(siae)
self.create_siae_activities(siae, siae_location=siae_location)
self.create_siae_activities(siae)
if (index % 500) == 0:
self.stdout_info(f"{index}...")

Expand All @@ -63,10 +62,9 @@ def handle(self, *args, **options):
]
self.stdout_messages_success(msg_success)

self.stdout_warning(f"No location found for {siae} (post_code empty)")
return None

def create_siae_activities(self, siae: Siae, siae_location: Perimeter = None):
def create_siae_activities(self, siae: Siae):
"""
- sector_group / sectors: we look at the existing siae sectors, and create an activity per sector group
- presta_type: we look at the existing siae presta_types
Expand All @@ -79,14 +77,43 @@ def create_siae_activities(self, siae: Siae, siae_location: Perimeter = None):
siae_sector_group_ids = list(set(siae.sectors.values_list("group", flat=True)))
# For each SectorGroup, create a SiaeActivity
for sector_group_id in siae_sector_group_ids:
siae_activity = SiaeActivity.objects.create(
siae=siae,
sector_group_id=sector_group_id,
presta_type=siae.presta_type,
location=siae_location,
geo_range=siae.geo_range,
geo_range_custom_distance=siae.geo_range_custom_distance,
)
match siae.geo_range:
case siae_constants.GEO_RANGE_COUNTRY:
siae_activity = SiaeActivity.objects.create(
siae=siae,
sector_group_id=sector_group_id,
presta_type=siae.presta_type,
geo_range=siae_constants.GEO_RANGE_COUNTRY,
)
case siae_constants.GEO_RANGE_CUSTOM:
siae_activity = SiaeActivity.objects.create(
siae=siae,
sector_group_id=sector_group_id,
presta_type=siae.presta_type,
geo_range=siae_constants.GEO_RANGE_CUSTOM,
geo_range_custom_distance=siae.geo_range_custom_distance,
)
case siae_constants.GEO_RANGE_REGION:
siae_activity = SiaeActivity.objects.create(
siae=siae,
sector_group_id=sector_group_id,
presta_type=siae.presta_type,
geo_range=siae_constants.GEO_RANGE_ZONES,
)
region = Perimeter.objects.get(kind=Perimeter.KIND_REGION, name=siae.region)
siae_activity.locations.add(region)
case siae_constants.GEO_RANGE_DEPARTMENT:
siae_activity = SiaeActivity.objects.create(
siae=siae,
sector_group_id=sector_group_id,
presta_type=siae.presta_type,
geo_range=siae_constants.GEO_RANGE_ZONES,
)
department = Perimeter.objects.get(kind=Perimeter.KIND_DEPARTMENT, insee_code=siae.department)
siae_activity.locations.add(department)
case _:
self.stdout_warning(f"Unknown geo_range: {siae.geo_range}")
continue
siae_activity.sectors.set(siae.sectors.filter(group_id=sector_group_id))

# self.stdout_info(f"Created {len(siae_sector_group_ids)} activities for {siae}")
self.stdout_info(f"Created {len(siae_sector_group_ids)} activities for {siae}")
Empty file.
102 changes: 102 additions & 0 deletions lemarche/siaes/tests/test_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from django.core.management import call_command
from django.test import TransactionTestCase

from lemarche.perimeters.factories import PerimeterFactory
from lemarche.perimeters.models import Perimeter
from lemarche.sectors.factories import SectorFactory
from lemarche.siaes import constants as siae_constants
from lemarche.siaes.factories import SiaeFactory
from lemarche.siaes.models import SiaeActivity


class SiaeActivitiesCreateCommandTest(TransactionTestCase):
def setUp(self):
self.sector1 = SectorFactory()
self.sector2 = SectorFactory()
self.sector3 = SectorFactory()

region_name = "Collectivités d'outre-mer"

self.perimeter_department = PerimeterFactory(
name="Saint-Martin", kind=Perimeter.KIND_DEPARTMENT, insee_code="978", region_code="97"
)
self.perimeter_region = PerimeterFactory(name=region_name, kind=Perimeter.KIND_REGION, insee_code="R97")

self.siae1 = SiaeFactory(
is_active=True,
kind=siae_constants.KIND_AI,
presta_type=[siae_constants.PRESTA_PREST, siae_constants.PRESTA_BUILD],
geo_range=siae_constants.GEO_RANGE_COUNTRY,
)
self.siae1.sectors.set([self.sector1, self.sector2])

self.siae2 = SiaeFactory(
is_active=True,
kind=siae_constants.KIND_EA,
presta_type=[siae_constants.PRESTA_DISP],
geo_range=siae_constants.GEO_RANGE_CUSTOM,
)
self.siae2.sectors.set([self.sector3])

self.siae3 = SiaeFactory(
is_active=True,
kind=siae_constants.KIND_EA,
presta_type=[siae_constants.PRESTA_PREST],
geo_range=siae_constants.GEO_RANGE_REGION,
department="987",
region=region_name,
)
self.siae3.sectors.set([self.sector3])

self.siae4 = SiaeFactory(
is_active=True,
kind=siae_constants.KIND_EA,
presta_type=[siae_constants.PRESTA_DISP],
geo_range=siae_constants.GEO_RANGE_DEPARTMENT,
department="978",
region=region_name,
)
self.siae4.sectors.set([self.sector2, self.sector3])

def test_create_activities(self):
call_command("create_siae_activities", dry_run=True)
self.assertEqual(SiaeActivity.objects.count(), 0)

call_command("create_siae_activities")
self.assertEqual(SiaeActivity.objects.count(), 2 + 1 + 1 + 2)
siae1_activities = SiaeActivity.objects.filter(siae=self.siae1)
self.assertEqual(siae1_activities.count(), 2)
self.assertEqual(siae1_activities.filter(sectors__in=[self.sector1]).count(), 1)
self.assertEqual(siae1_activities.filter(sectors__in=[self.sector2]).count(), 1)
for siae_activity in siae1_activities:
with self.subTest(siae_activity=siae_activity):
self.assertEqual(siae_activity.presta_type, [siae_constants.PRESTA_PREST, siae_constants.PRESTA_BUILD])
self.assertEqual(siae_activity.geo_range, siae_constants.GEO_RANGE_COUNTRY)
self.assertEqual(siae_activity.locations.count(), 0)

siae2_activities = SiaeActivity.objects.filter(siae=self.siae2)
self.assertEqual(siae2_activities.count(), 1)
self.assertEqual(siae2_activities.first().presta_type, [siae_constants.PRESTA_DISP])
self.assertEqual(siae2_activities.first().geo_range, siae_constants.GEO_RANGE_CUSTOM)
self.assertEqual(siae2_activities.first().geo_range_custom_distance, self.siae2.geo_range_custom_distance)
self.assertEqual(siae2_activities.filter(sectors__in=[self.sector3]).count(), 1)
self.assertEqual(siae2_activities.first().locations.count(), 0)

siae3_activities = SiaeActivity.objects.filter(siae=self.siae3)
self.assertEqual(siae3_activities.count(), 1)
self.assertEqual(siae3_activities.filter(sectors__in=[self.sector3]).count(), 1)
self.assertEqual(siae3_activities.first().presta_type, [siae_constants.PRESTA_PREST])
self.assertEqual(siae3_activities.first().geo_range, siae_constants.GEO_RANGE_ZONES)
self.assertEqual(siae3_activities.first().locations.count(), 1)
self.assertEqual(siae3_activities.first().locations.first(), self.perimeter_region)

siae4_activities = SiaeActivity.objects.filter(siae=self.siae4)
self.assertEqual(siae4_activities.count(), 2)
self.assertEqual(siae4_activities.filter(sectors__in=[self.sector2]).count(), 1)
self.assertEqual(siae4_activities.filter(sectors__in=[self.sector3]).count(), 1)
for siae_activity in siae4_activities:
with self.subTest(siae_activity=siae_activity):
self.assertEqual(siae_activity.presta_type, [siae_constants.PRESTA_DISP])
self.assertEqual(siae_activity.geo_range, siae_constants.GEO_RANGE_ZONES)
self.assertEqual(siae_activity.locations.count(), 1)
self.assertEqual(siae_activity.locations.first(), self.perimeter_department)
11 changes: 0 additions & 11 deletions lemarche/siaes/tests.py → lemarche/siaes/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,17 +623,6 @@ def test_calculate_etablissement_count(self):
self.siae_with_siret_inactive = SiaeFactory(siret="12312312312347", is_active=False)
self.assertEqual(siae_utils.calculate_etablissement_count(self.siae_with_siret_1), 2)

def test_match_location_to_perimeter(self):
self.siae_grenoble_from_post_code = SiaeFactory(post_code="38000")
self.siae_grenoble_from_insee_code = SiaeFactory(post_code="38185")
self.grenoble_perimeter = PerimeterFactory(**PERIMETER_GRENOBLE)
self.assertEqual(
siae_utils.match_location_to_perimeter(self.siae_grenoble_from_post_code), self.grenoble_perimeter
)
self.assertEqual(
siae_utils.match_location_to_perimeter(self.siae_grenoble_from_insee_code), self.grenoble_perimeter
)


class SiaeActivitiesTest(TestCase):
@classmethod
Expand Down
30 changes: 0 additions & 30 deletions lemarche/siaes/utils.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,7 @@
from lemarche.perimeters.models import Perimeter
from lemarche.siaes.models import Siae


def calculate_etablissement_count(siae: Siae):
if siae.siren:
return Siae.objects.filter(is_active=True, siret__startswith=siae.siren).count()
return 0


def match_location_to_perimeter(siae: Siae):
"""
Find the Siae's location based on the post_code (and city)
- first do a post_code search
- if multiple perimeters returned, try to match with the city
- if still multiple results returned, return None
"""
if siae.post_code:
location_results_from_siae_post_code = Perimeter.objects.post_code_search(
siae.post_code, include_insee_code=True
)

if not location_results_from_siae_post_code.exists():
print(f"No location found for {siae} (with post_code {siae.post_code})")
return None
elif location_results_from_siae_post_code.count() == 1:
return location_results_from_siae_post_code.first()
else:
# found multiple locations with the post_code, try to match with the city
if siae.city:
location_results_from_siae_city = Perimeter.objects.name_search(siae.city)
if location_results_from_siae_city.count():
if location_results_from_siae_post_code.first() == location_results_from_siae_post_code.first():
return location_results_from_siae_post_code.first()
else:
print(f"Multiple locations found for {siae} (with post_code {siae.post_code})")
return None
Loading