diff --git a/clevercloud/cron.json b/clevercloud/cron.json index 3f84829f3..325a57cb9 100644 --- a/clevercloud/cron.json +++ b/clevercloud/cron.json @@ -7,6 +7,7 @@ "20 7 * * 1 $ROOT/clevercloud/siaes_update_api_entreprise_fields.sh", "30 7 * * 1 $ROOT/clevercloud/siaes_update_api_qpv_fields.sh", "40 7 * * 1 $ROOT/clevercloud/siaes_update_api_zrr_fields.sh", + "50 7 * * 1 $ROOT/clevercloud/siaes_update_count_fields.sh", "0 7 * * 2 $ROOT/clevercloud/siaes_send_completion_reminder_emails.sh", "0 8 * * * $ROOT/clevercloud/siaes_send_user_request_reminder_emails.sh", "30 8 * * * $ROOT/clevercloud/tenders_send_author_transactioned_question_emails.sh", diff --git a/clevercloud/siaes_update_count_fields.sh b/clevercloud/siaes_update_count_fields.sh new file mode 100755 index 000000000..3c7711dac --- /dev/null +++ b/clevercloud/siaes_update_count_fields.sh @@ -0,0 +1,23 @@ +#!/bin/bash -l + +# Update API ZRR fields for new siaes + +# Do not run if this env var is not set: +if [[ -z "$CRON_UPDATE_COUNT_FIELDS_ENABLED" ]]; then + echo "CRON_UPDATE_COUNT_FIELDS_ENABLED not set. Exiting..." + exit 0 +fi + +# About clever cloud cronjobs: +# https://www.clever-cloud.com/doc/tools/crons/ + +if [[ "$INSTANCE_NUMBER" != "0" ]]; then + echo "Instance number is ${INSTANCE_NUMBER}. Stop here." + exit 0 +fi + +# $APP_HOME is set by default by clever cloud. +cd $APP_HOME + +# django-admin update_count_fields +django-admin update_count_fields --fields etablissement_count diff --git a/lemarche/siaes/management/commands/update_count_fields.py b/lemarche/siaes/management/commands/update_count_fields.py new file mode 100644 index 000000000..2857ea811 --- /dev/null +++ b/lemarche/siaes/management/commands/update_count_fields.py @@ -0,0 +1,84 @@ +from lemarche.siaes import utils as siae_utils +from lemarche.siaes.models import Siae +from lemarche.utils.apis import api_slack +from lemarche.utils.commands import BaseCommand + + +SIAE_COUNT_FIELDS = [ + "user_count", + "sector_count", + "network_count", + "group_count", + "offer_count", + "client_reference_count", + "label_count", + "image_count", + "etablissement_count", +] + + +class Command(BaseCommand): + """ + Goal: update the '_count' fields of each Siae + + Note: these fields should be updated automatically on each Siae save() + + Usage: + python manage.py update_count_fields + python manage.py update_count_fields --id 1 + python manage.py update_count_fields --id 1 --fields user_count + python manage.py update_count_fields --id 1 --fields user_count --fields etablissement_count + """ + + def add_arguments(self, parser): + parser.add_argument("--id", type=int, default=None, help="Indiquer l'ID d'une structure") + parser.add_argument( + "--fields", action="append", default=[], help="Filtrer sur les champs count à mettre à jour" + ) + + def handle(self, *args, **options): + self.stdout_messages_info("Updating Siae count fields...") + + # Step 1a: build Siae queryset + siae_queryset = Siae.objects.prefetch_related( + "users", "sectors", "networks", "groups", "offers", "client_references", "labels", "images" + ).all() + if options["id"]: + siae_queryset = siae_queryset.filter(id=options["id"]) + self.stdout_messages_info(f"Found {siae_queryset.count()} Siae") + + # Step 1b: init fields to update + update_fields = options["fields"] if options["fields"] else SIAE_COUNT_FIELDS + self.stdout_messages_info(f"Fields to update: {update_fields}") + + # Step 2: loop on each Siae + progress = 0 + for index, siae in enumerate(siae_queryset): + # M2M + siae.user_count = siae.users.count() + siae.sector_count = siae.sectors.count() + siae.network_count = siae.networks.count() + siae.group_count = siae.groups.count() + # FK + siae.offer_count = siae.offers.count() + siae.client_reference_count = siae.client_references.count() + siae.label_count = siae.labels_old.count() + siae.image_count = siae.images.count() + # etablissement_count + if siae.is_active and siae.siren: + siae.etablissement_count = siae_utils.calculate_etablissement_count(siae) + + # Step 3: update count fields + siae.save(update_fields=update_fields) + + progress += 1 + if (progress % 500) == 0: + self.stdout_messages_info(f"{progress}...") + + msg_success = [ + "----- Siae count fields -----", + f"Done! Processed {siae_queryset.count()} siaes", + f"Fields updated: {update_fields}", + ] + self.stdout_messages_success(msg_success) + api_slack.send_message_to_channel("\n".join(msg_success)) diff --git a/lemarche/siaes/management/commands/update_counts.py b/lemarche/siaes/management/commands/update_counts.py deleted file mode 100644 index 7a91d3dbc..000000000 --- a/lemarche/siaes/management/commands/update_counts.py +++ /dev/null @@ -1,63 +0,0 @@ -from django.core.management.base import BaseCommand - -from lemarche.siaes.models import Siae - - -class Command(BaseCommand): - """ - Goal: update the '_count' fields of each Siae - - Note: these fields should be updated automatically on each Siae save() - - Usage: - python manage.py update_counts - python manage.py update_counts --id 1 - """ - - def add_arguments(self, parser): - parser.add_argument("--id", type=int, default=None, help="Indiquer l'ID d'une structure") - - def handle(self, *args, **options): - self.stdout.write("-" * 80) - self.stdout.write("Updating Siae count fields...") - - # Step 1: build Siae queryset - siae_queryset = Siae.objects.prefetch_related( - "users", "sectors", "networks", "groups", "offers", "client_references", "labels", "images" - ).all() - if options["id"]: - siae_queryset = siae_queryset.filter(id=options["id"]) - self.stdout.write(f"Found {siae_queryset.count()} Siae") - - # Step 2: loop on each Siae - progress = 0 - for index, siae in enumerate(siae_queryset): - # M2M - user_count = siae.users.count() - sector_count = siae.sectors.count() - network_count = siae.networks.count() - group_count = siae.groups.count() - # FK - offer_count = siae.offers.count() - client_reference_count = siae.client_references.count() - label_count = siae.labels_old.count() - image_count = siae.images.count() - - # Step 3: update count fields - # why do we use .update() instead of .save() ? To avoid updating the 'updated_at' fieldS - Siae.objects.filter(id=siae.id).update( - user_count=user_count, - sector_count=sector_count, - network_count=network_count, - group_count=group_count, - offer_count=offer_count, - client_reference_count=client_reference_count, - label_count=label_count, - image_count=image_count, - ) - - progress += 1 - if (progress % 500) == 0: - self.stdout.write(f"{progress}...") - - self.stdout.write("Done") diff --git a/lemarche/siaes/tests.py b/lemarche/siaes/tests.py index 997301543..ede52132d 100644 --- a/lemarche/siaes/tests.py +++ b/lemarche/siaes/tests.py @@ -5,7 +5,7 @@ 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 import constants as siae_constants, utils as siae_utils from lemarche.siaes.factories import SiaeFactory, SiaeGroupFactory, SiaeLabelOldFactory, SiaeOfferFactory from lemarche.siaes.models import Siae, SiaeGroup, SiaeLabel, SiaeUser from lemarche.users.factories import UserFactory @@ -469,3 +469,14 @@ def test_siae_labels_through(self): siae = SiaeFactory() SiaeLabel.objects.create(siae=siae, label=self.label_2) self.assertEqual(siae.labels.count(), 1) + + +class SiaeUtilsTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.siae_with_siret_1 = SiaeFactory(siret="12312312312345", is_active=True) + cls.siae_with_siret_2 = SiaeFactory(siret="12312312312346", is_active=True) + cls.siae_with_siret_inactive = SiaeFactory(siret="12312312312347", is_active=False) + + def test_calculate_etablissement_count(self): + self.assertEqual(siae_utils.calculate_etablissement_count(self.siae_with_siret_1, 2)) diff --git a/lemarche/siaes/utils.py b/lemarche/siaes/utils.py new file mode 100644 index 000000000..639355357 --- /dev/null +++ b/lemarche/siaes/utils.py @@ -0,0 +1,7 @@ +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 diff --git a/lemarche/utils/commands.py b/lemarche/utils/commands.py index f9690e1f2..0aeb858e0 100644 --- a/lemarche/utils/commands.py +++ b/lemarche/utils/commands.py @@ -13,14 +13,12 @@ def stdout_info(self, message): def stdout_messages_info(self, messages): self.stdout_info("-" * 80) - messages = messages if (type(messages) == list) else [messages] + messages = messages if (type(messages) is list) else [messages] for message in messages: self.stdout_info(message) - self.stdout_info("-" * 80) def stdout_messages_success(self, messages): self.stdout_success("-" * 80) - messages = messages if (type(messages) == list) else [messages] + messages = messages if (type(messages) is list) else [messages] for message in messages: self.stdout_success(message) - self.stdout_success("-" * 80)