diff --git a/castellum/subjects/migrations/0033_subject_updated_at.py b/castellum/subjects/migrations/0033_subject_updated_at.py new file mode 100644 index 0000000000000000000000000000000000000000..179a9ae09aa30e01a92e4baaadb863a88038e92e --- /dev/null +++ b/castellum/subjects/migrations/0033_subject_updated_at.py @@ -0,0 +1,51 @@ +from django.db import migrations, models + + +def migrate_data(apps, schema_editor): + Subject = apps.get_model('subjects', 'Subject') + Contact = apps.get_model('contacts', 'Contact') + + # re-implementation of constants from model Participation + UNSUITABLE = 2 + INVITED = 3 + FOLLOWUP_APPOINTED = 4 + + subjects = Subject.objects.filter( + deceased=False, blocked=False + ).annotate( + participation_updated_at=models.Max( + 'participation__updated_at', + filter=models.Q( + participation__status__in=[INVITED, UNSUITABLE, FOLLOWUP_APPOINTED], + participation__excluded_by_cleanup=False, + ) + ) + ) + + for subject in subjects: + contact = Contact.objects.filter(subject_uuid=subject.pk).first() + if contact: + contact_updated_at = contact.updated_at + else: + contact_updated_at = None + + dates = [subject.updated_at, contact_updated_at, subject.participation_updated_at.date()] + most_recent_contact = max(date for date in dates if date) + + if most_recent_contact != subject.updated_at: + # needs to be update() in order not to set Subject.updated_at to now + Subject.objects.filter(uuid=subject.uuid).update(updated_at=most_recent_contact) + + +class Migration(migrations.Migration): + + dependencies = [ + ('subjects', '0032_subject_uuid_foreign_key'), + + # this dependency is ineffective because it is about the other database + ('contacts', '0015_contactcreationrequest_message'), + ] + + operations = [ + migrations.RunPython(migrate_data), + ] diff --git a/tests/subjects/migrations/test_0033_subject_updated_at.py b/tests/subjects/migrations/test_0033_subject_updated_at.py new file mode 100644 index 0000000000000000000000000000000000000000..f269b0cd88ab4bdb8e21a62eb08723e496270b65 --- /dev/null +++ b/tests/subjects/migrations/test_0033_subject_updated_at.py @@ -0,0 +1,29 @@ +import pytest +from model_bakery import baker +from freezegun import freeze_time +from tests.markers import skip_old_migration + + +@pytest.mark.django_db(databases=['default', 'contacts']) +@skip_old_migration('0.70') +def test_keep_uuid(migrator): + old_state = migrator.apply_initial_migration(('subjects', '0032_subject_uuid_foreign_key')) + Subject = old_state.apps.get_model('subjects', 'Subject') + Study = old_state.apps.get_model('studies', 'Study') + Participation = old_state.apps.get_model('recruitment', 'Participation') + # re-implementation of constant from model Participation + INVITED = 3 + + with freeze_time("1970-01-01 12:00"): + subject = baker.make(Subject) + study = baker.make(Study) + with freeze_time("2000-01-01 12:00"): + participation = baker.make(Participation, subject=subject, study=study, status=INVITED) + + new_state = migrator.apply_tested_migration(('subjects', '0033_subject_updated_at')) + Subject = new_state.apps.get_model('subjects', 'Subject') + subject = Subject.objects.first() + + assert subject.updated_at == participation.updated_at.date() + + migrator.reset()