diff --git a/greg/management/commands/change_role_end_dates.py b/greg/management/commands/change_role_end_dates.py new file mode 100644 index 0000000000000000000000000000000000000000..42b788dcc5f90a5c6cbd360cd2299144ae75ee76 --- /dev/null +++ b/greg/management/commands/change_role_end_dates.py @@ -0,0 +1,104 @@ +""" +Command for changing role end dates in batch. +""" +import csv +import logging + +from django.core.management.base import BaseCommand, CommandParser +from django.db import transaction +from django.utils.dateparse import parse_date + +from greg.models import Identity, Person, Role + +logger = logging.getLogger(__name__) + + +def handle_line(line: dict): + feide_id = line["feide_id"] + stedkode = line["legacy_stedkode"] + role_type = line["role_type"] + if not line.get("end_date"): + logger.info("No end date set: %r", line) + return + end_date_str = line.get("end_date") + assert isinstance(end_date_str, str) + end_date = parse_date(end_date_str) + assert feide_id and stedkode and role_type and end_date + try: + person = Person.objects.get( + identities__type=Identity.IdentityType.FEIDE_ID, identities__value=feide_id + ) + except Person.DoesNotExist: + logger.warning("No person with feide_id %r", feide_id) + return + logger.info("Found %s: %s", feide_id, person) + try: + role = Role.objects.get( + person=person, + type__identifier=role_type, + orgunit__identifiers__name="legacy_stedkode", + orgunit__identifiers__value=stedkode, + ) + except Role.MultipleObjectsReturned: + logger.warning( + "Multiple roles matching type=%s stedkode=%s for feide_id=%s", + role_type, + stedkode, + feide_id, + ) + return + except Role.DoesNotExist: + logger.warning( + "No role matching type=%s stedkode=%s for feide_id=%s", + role_type, + stedkode, + feide_id, + ) + return + logger.info("Found matching role %s for %s", role, feide_id) + old_end_date = role.end_date + role.end_date = end_date + changes = role.get_dirty_fields(check_relationship=True, verbose=True) + logger.info( + "Changing end_date for role_id=%d from %s to %s %r", + role.pk, + old_end_date, + end_date, + changes, + ) + role.save() + + +class Command(BaseCommand): + help = __doc__ + + def add_arguments(self, parser: CommandParser) -> None: + parser.add_argument( + "--file", + type=str, + help="Path to CSV file with new end dates", + ) + parser.add_argument( + "--commit", + default=False, + action="store_true", + help="Commit the changes done by running the import once", + ) + + def handle(self, *args, **options): + commit = options["commit"] + file_path = options["file"] + + with open(file_path, encoding="utf-8", newline="") as csv_file: + reader = csv.DictReader(csv_file) + lines = list(reader) + + with transaction.atomic(): + for line in lines: + handle_line(line) + + if not commit: + logger.info("Rolling back changes...") + transaction.set_rollback(True) + else: + logger.info("Changes committed")