diff --git a/tigacrafting/views.py b/tigacrafting/views.py index 315e58e51..51477b363 100644 --- a/tigacrafting/views.py +++ b/tigacrafting/views.py @@ -1310,20 +1310,7 @@ def get_reports_unfiltered_sites_other(reports_imbornal): return new_reports_unfiltered_sites_other def get_reports_imbornal(): - reports_imbornal = ReportResponse.objects.filter( - Q(question='Is this a storm drain or sewer?', answer='Yes') | Q(question=u'\xc9s un embornal o claveguera?', - answer=u'S\xed') | Q( - question=u'\xbfEs un imbornal o alcantarilla?', answer=u'S\xed') | Q(question='Selecciona lloc de cria', - answer='Embornals') | Q( - question='Selecciona lloc de cria', answer='Embornal o similar') | Q(question='Tipo de lugar de cría', - answer='Sumidero o imbornal') | Q( - question='Tipo de lugar de cría', answer='Sumideros') | Q(question='Type of breeding site', - answer='Storm drain') | Q( - question='Type of breeding site', answer='Storm drain or similar receptacle')).values('report').distinct() - - reports_imbornal_new = ReportResponse.objects.filter(question_id=12).filter(answer_id=121).values('report').distinct() - - return reports_imbornal | reports_imbornal_new + return Report.objects.filter(breeding_site_type=Report.BREEDING_SITE_TYPE_STORM_DRAIN) def get_reports_unfiltered_adults_except_being_validated(): new_reports_unfiltered_adults = Report.objects.exclude(creation_time__year=2014).exclude(type='site').exclude(note__icontains='#345').exclude(photos=None).annotate(n_annotations=Count('expert_report_annotations')).filter(n_annotations=0).order_by('-server_upload_time') diff --git a/tigamap/templates/tigamap/report_map.html b/tigamap/templates/tigamap/report_map.html index f25502349..e1aefac0d 100644 --- a/tigamap/templates/tigamap/report_map.html +++ b/tigamap/templates/tigamap/report_map.html @@ -110,7 +110,7 @@ '{{ report.tigaprob_text }}cc score:{{ score|floatformat:2 }}lat:{{ lat }}lon:{{ lon }}{{ report.get_validated_photo_html | safe }}'; {% else %} popup_text = '
{% trans 'type' %}:'+ - '{{ report.site_type_trans }}
cc score:{{ score|floatformat:2 }}
lat:{{ lat }}
lon:{{ report.lon }}
{{ report.get_validated_photo_html | safe }}'; + '{{ report.breeding_site_type }}cc score:{{ score|floatformat:2 }}lat:{{ lat }}lon:{{ report.lon }}{{ report.get_validated_photo_html | safe }}'; {% endif %} {% endwith %} @@ -123,7 +123,7 @@ '{{ report.tigaprob_text }}lat:{{ lat }}lon:{{ lon }}'; {% else %} popup_text = '
{% trans 'type' %}:'+ - '{{ report.site_type_trans }}
lat:{{ lat }}
lon:{{ report.lon }}
'; + '{{ report.breeding_site_type }}lat:{{ lat }}lon:{{ report.lon }}'; {% endif %} {% endif %} {% if detailed == 'detailed' %} diff --git a/tigascoring/xp_scoring.py b/tigascoring/xp_scoring.py index 5574b36b4..e88bd642c 100644 --- a/tigascoring/xp_scoring.py +++ b/tigascoring/xp_scoring.py @@ -22,23 +22,12 @@ SITE_STORM_DRAIN_REWARD = 4 BREEDING_SITE_MOSQUITO_REWARD = 3 -MOSQUITO_HOW_LOOKS_QUESTION_ID = 7 -MOSQUITO_THORAX_ANSWER_IDS = [711, 712, 713, 714] -MOSQUITO_ABDOMEN_ANSWER_IDS = [721, 722, 723, 724] -MOSQUITO_LEG_ANSWER_IDS = [731, 732, 733, 734] - MOSQUITO_BITE_QUESTION_ID = 8 MOSQUITO_BITE_ANSWER_ID = 101 BREEDING_SITE_MOSQUITO_QUESTION_ID = 11 BREEDING_SITE_MOSQUITO_ANSWER_ID = 101 -SITE_WATER_QUESTION_ID = 10 -SITE_WATER_ANSWER_IDS = [81, 101] - -STORM_DRAIN_QUESTION_ID = 12 -STORM_DRAIN_ANSWER_ID = 121 - CULEX_CATEGORY_ID = 10 AEDES_CATEGORY_IDS = [4, 5, 6, 7] @@ -88,53 +77,31 @@ def is_thorax_answered(report): - for response in report.responses.all(): - if response.question_id == MOSQUITO_HOW_LOOKS_QUESTION_ID and response.answer_id in MOSQUITO_THORAX_ANSWER_IDS: - return True - return False + return report.user_perceived_mosquito_thorax is not None def is_abdomen_answered(report): - for response in report.responses.all(): - if response.question_id == MOSQUITO_HOW_LOOKS_QUESTION_ID and response.answer_id in MOSQUITO_ABDOMEN_ANSWER_IDS: - return True - return False + return report.user_perceived_mosquito_abdomen is not None def is_leg_answered(report): - for response in report.responses.all(): - if response.question_id == MOSQUITO_HOW_LOOKS_QUESTION_ID and response.answer_id in MOSQUITO_LEG_ANSWER_IDS: - return True - return False + return report.user_perceived_mosquito_legs is not None def is_water_answered(report): - for response in report.responses.all(): - if response.question_id == SITE_WATER_QUESTION_ID and response.answer_id in SITE_WATER_ANSWER_IDS: - return True - return False + return report.breeding_site_has_water is not None def is_bite_report_followed(report): - for response in report.responses.all(): - if response.question_id == MOSQUITO_BITE_QUESTION_ID and response.answer_id == MOSQUITO_BITE_ANSWER_ID: - return True - return False + return report.responses.filter(question_id=MOSQUITO_BITE_QUESTION_ID, answer_id=MOSQUITO_BITE_ANSWER_ID).exists() def is_mosquito_report_followed(report): - for response in report.responses.all(): - if response.question_id == BREEDING_SITE_MOSQUITO_QUESTION_ID and response.answer_id == BREEDING_SITE_MOSQUITO_ANSWER_ID: - return True - return False + return report.responses.filter(question_id=BREEDING_SITE_MOSQUITO_QUESTION_ID, answer_id=BREEDING_SITE_MOSQUITO_ANSWER_ID).exists() def is_storm_drain(report): - for response in report.responses.all(): - if response.question_id == STORM_DRAIN_QUESTION_ID and response.answer_id == STORM_DRAIN_ANSWER_ID: - return True - return False - + return report.breeding_site_type == Report.BREEDING_SITE_TYPE_STORM_DRAIN def is_culex(validation_result): if validation_result['category'] is not None: diff --git a/tigaserver_app/admin.py b/tigaserver_app/admin.py index 47ca08c34..5af5c615e 100644 --- a/tigaserver_app/admin.py +++ b/tigaserver_app/admin.py @@ -7,6 +7,7 @@ from django.utils.encoding import smart_str from django.http.response import HttpResponse from django.utils.html import mark_safe +from django.utils.translation import ugettext_lazy as _ def export_full_csv(modeladmin, request, queryset): @@ -116,16 +117,147 @@ class PhotoInline(admin.StackedInline): class ReportAdmin(admin.ModelAdmin): - list_display = ('version_UUID', 'report_id', 'deleted', 'user', 'version_number', 'creation_time', 'version_time', 'type', 'mission', - 'package_version', 'os', 'n_photos', 'map_link', 'movelab_score', 'crowd_score') - inlines = [ReportResponseInline, PhotoInline] - ordering = ('creation_time', 'report_id', 'version_number') - readonly_fields = ('deleted', 'version_UUID', 'user', 'report_id', 'version_number', 'other_versions_of_this_report', 'creation_time', 'version_time', 'server_upload_time', 'updated_at', 'datetime_fix_offset', 'phone_upload_time', 'type', 'mission', 'location_choice', 'current_location_lon', 'current_location_lat', 'selected_location_lon', 'selected_location_lat', 'note', 'package_name', 'package_version', 'device_manufacturer', 'device_model', 'os', 'os_version', 'os_language', 'app_language', 'n_photos', 'lon', 'lat', 'tigaprob', 'tigaprob_text', 'site_type', 'site_type_trans', 'embornals', 'fonts', 'basins', 'buckets', 'wells', 'other', 'masked_lat', 'masked_lon', 'map_link', 'movelab_score', 'crowd_score') - fields = ('hide', 'deleted', 'map_link', 'version_UUID', 'user', 'report_id', 'version_number', 'other_versions_of_this_report', ('creation_time', 'version_time', 'datetime_fix_offset'), ('server_upload_time','phone_upload_time'), 'updated_at', 'type', 'mission', 'location_choice', 'current_location_lon', 'current_location_lat', 'selected_location_lon', 'selected_location_lat', 'note', 'package_name', 'package_version', 'device_manufacturer', 'device_model', 'os', 'os_version', 'os_language', 'app_language', 'n_photos', 'lon', 'lat', 'tigaprob', 'tigaprob_text', 'site_type', 'site_type_trans', 'embornals', 'fonts', 'basins', 'buckets', 'wells', 'other', 'masked_lat', 'masked_lon', 'movelab_score', 'crowd_score') - search_fields = ('version_UUID',) + list_display = ( + 'version_UUID', 'report_id', 'deleted', 'user', 'version_number', 'creation_time', 'version_time', 'type', 'mission', + 'package_version', 'os', 'n_photos' + ) list_filter = ['os', 'type', 'mission', 'package_name', 'package_version'] + search_fields = ('version_UUID',) + + inlines = [ReportResponseInline, PhotoInline] actions = [export_full_csv, export_full_csv_sc] + readonly_fields = [ + "deleted", + "report_id", + "version_number", + "type", + "user", + "mission", + "session", + "server_upload_time", + "updated_at", + "version_time", + "phone_upload_time", + "creation_time", + "other_versions_of_this_report" + ] + + fieldsets = [ + ( + _('General info'), + { + "fields": [ + ("report_id", "version_number"), + ("hide", "deleted"), + "type", + "user", + ("mission","session"), + "other_versions_of_this_report", + ("server_upload_time", "updated_at"), + ("version_time", "datetime_fix_offset"), + ("creation_time", "phone_upload_time") + ] + } + ), + ( + _("Location information"), + { + "fields": [ + ("country", "nuts_2", "nuts_3"), + "location_choice", + "point" + ] + } + ), + ( + _("Other"), + { + "fields": [ + ("package_name", "package_version", "app_language"), + ("device_manufacturer", "device_model"), + ("os", "os_version", "os_language"), + "note" + ], + "classes": ["collapse",] + } + ) + ] + + def get_readonly_fields(self, request, obj=None): + # Only allow to edit 'hide' field. + result = super().get_readonly_fields(request, obj) + + readonly_fields = [field.name for field in self.model._meta.get_fields()] + allow_edit_fields = ['hide',] + + for field_name in readonly_fields: + if not field_name in allow_edit_fields: + result.append(field_name) + + return result + + def get_fieldsets(self, request, obj = None): + result = super().get_fieldsets(request, obj) + + if not obj: + return result + + extra_fieldsets = [] + if obj.type == Report.TYPE_ADULT: + extra_fieldsets.append( + ( + _("Classification"), + { + "fields": [ + "ia_filter_1", "ia_filter_2" + ] + } + ) + ) + extra_fieldsets.append( + ( + _("Specific information"), + { + "fields": [ + ("event_environment", "event_moment"), + "user_perceived_mosquito_specie", + ("user_perceived_mosquito_thorax", "user_perceived_mosquito_abdomen", "user_perceived_mosquito_legs") + ] + } + ) + ) + elif obj.type == Report.TYPE_BITE: + extra_fieldsets.append( + ( + _("Specific information"), + { + "fields": [ + ("event_environment", "event_moment"), + "bite_count", + ("head_bite_count", "left_arm_bite_count", "right_arm_bite_count", "chest_bite_count", "left_leg_bite_count", "right_leg_bite_count") + ] + } + ) + ) + elif obj.type == Report.TYPE_SITE: + extra_fieldsets.append( + ( + _("Specific information"), + { + "fields": [ + "breeding_site_type", + "breeding_site_has_water", + "breeding_site_in_public_area", + "breeding_site_has_near_mosquitoes", + "breeding_site_has_larvae" + ] + } + ) + ) + + return result + extra_fieldsets + def has_add_permission(self, request): return False @@ -133,26 +265,15 @@ def has_delete_permission(self, request, obj=None): return False def other_versions_of_this_report(self, obj): - result = [] + result = "" for this_version in obj.other_versions: result += 'Version %s ' % ( this_version.version_UUID, this_version.version_number, ) - return result + return mark_safe(result) other_versions_of_this_report.allow_tags = True - def movelab_score(self, obj): - return obj.movelab_score - - def crowd_score(self, obj): - return obj.crowd_score - - def map_link(self, obj): - return 'Show map' % obj.version_UUID - map_link.allow_tags = True - - def export_csv_photo(modeladmin, request, queryset): response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = 'attachment; filename=tigatrapp_photos.csv' @@ -247,7 +368,7 @@ def other_report_versions(self, obj): this_version.version_UUID, this_version.version_number, ) - return result + return mark_safe(result) other_report_versions.allow_tags = True def map_link(self, obj): diff --git a/tigaserver_app/migrations/0048_report_responses_to_column.py b/tigaserver_app/migrations/0048_report_responses_to_column.py new file mode 100644 index 000000000..c69fdf5c1 --- /dev/null +++ b/tigaserver_app/migrations/0048_report_responses_to_column.py @@ -0,0 +1,103 @@ +# Generated by Django 2.2.7 on 2024-02-12 15:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tigaserver_app', '0047_merge_20240813_1025'), + ] + + operations = [ + migrations.AddField( + model_name='report', + name='breeding_site_has_larvae', + field=models.BooleanField(help_text='Either if the user perceived larvaes the breeding site.', null=True), + ), + migrations.AddField( + model_name='report', + name='breeding_site_has_near_mosquitoes', + field=models.BooleanField(help_text='Either if the user perceived mosquitoes near the breeding site (less than 10 meters).', null=True), + ), + migrations.AddField( + model_name='report', + name='breeding_site_has_water', + field=models.BooleanField(help_text='Either if the user perceived water in the breeding site.', null=True), + ), + migrations.AddField( + model_name='report', + name='breeding_site_in_public_area', + field=models.BooleanField(help_text='Either if the breeding site is found in a public area.', null=True), + ), + migrations.AddField( + model_name='report', + name='breeding_site_type', + field=models.CharField(choices=[('basin', 'Basin'), ('bucket', 'Bucket'), ('fountain', 'Fountain'), ('small_container', 'Small container'), ('storm_drain', 'Storm Drain'), ('well', 'Well'), ('other', 'Other')], help_text='Breeding site type.', max_length=32, null=True), + ), + migrations.AddField( + model_name='report', + name='chest_bite_count', + field=models.PositiveSmallIntegerField(help_text='Number of bites reported in the chest.', null=True), + ), + migrations.AddField( + model_name='report', + name='event_environment', + field=models.CharField(choices=[('indoors', 'Indoors'), ('outdoors', 'Outdoors'), ('vehicle', 'Inside vehicle')], help_text='The environment where the event took place.', max_length=16, null=True), + ), + migrations.AddField( + model_name='report', + name='event_moment', + field=models.CharField(choices=[('now', 'Now'), ('last_morning', 'Last morning'), ('last_midday', 'Last midday'), ('last_afternoon', 'Last afternoon'), ('last_night', 'Last night')], help_text='The moment of the day when the event took place.', max_length=32, null=True), + ), + migrations.AddField( + model_name='report', + name='head_bite_count', + field=models.PositiveSmallIntegerField(help_text='Number of bites reported in the head.', null=True), + ), + migrations.AddField( + model_name='report', + name='left_arm_bite_count', + field=models.PositiveSmallIntegerField(help_text='Number of bites reported in the left arm.', null=True), + ), + migrations.AddField( + model_name='report', + name='left_leg_bite_count', + field=models.PositiveSmallIntegerField(help_text='Number of bites reported in the left leg.', null=True), + ), + migrations.AddField( + model_name='report', + name='right_arm_bite_count', + field=models.PositiveSmallIntegerField(help_text='Number of bites reported in the right arm.', null=True), + ), + migrations.AddField( + model_name='report', + name='right_leg_bite_count', + field=models.PositiveSmallIntegerField(help_text='Number of bites reported in the right leg.', null=True), + ), + migrations.AddField( + model_name='report', + name='user_perceived_mosquito_abdomen', + field=models.CharField(choices=[('albopictus', 'Aedes albopictus'), ('aegypti', 'Aedes aegypti'), ('japonicus', 'Aedes japonicus'), ('koreicus', 'Aedes koreicus'), ('culex', 'Culex pipiens'), ('other', 'Other')], help_text='The species of mosquito that the abdomen resembles, according to the user.', max_length=16, null=True), + ), + migrations.AddField( + model_name='report', + name='user_perceived_mosquito_legs', + field=models.CharField(choices=[('albopictus', 'Aedes albopictus'), ('aegypti', 'Aedes aegypti'), ('japonicus', 'Aedes japonicus'), ('koreicus', 'Aedes koreicus'), ('culex', 'Culex pipiens'), ('other', 'Other')], help_text='The species of mosquito that the leg resembles, according to the user.', max_length=16, null=True), + ), + migrations.AddField( + model_name='report', + name='user_perceived_mosquito_thorax', + field=models.CharField(choices=[('albopictus', 'Aedes albopictus'), ('aegypti', 'Aedes aegypti'), ('japonicus', 'Aedes japonicus'), ('koreicus', 'Aedes koreicus'), ('culex', 'Culex pipiens'), ('other', 'Other')], help_text='The species of mosquito that the thorax resembles, according to the user.', max_length=16, null=True), + ), + migrations.AddField( + model_name='report', + name='user_perceived_mosquito_specie', + field=models.CharField(choices=[('albopictus', 'Aedes albopictus'), ('aegypti', 'Aedes aegypti'), ('japonicus', 'Aedes japonicus'), ('koreicus', 'Aedes koreicus'), ('culex', 'Culex pipiens'), ('other', 'Other')], help_text='The mosquito specie perceived by the user.', max_length=16, null=True), + ), + migrations.AddField( + model_name='report', + name='bite_count', + field=models.PositiveSmallIntegerField(editable=False, help_text='Total number of bites reported.', null=True), + ), + ] diff --git a/tigaserver_app/migrations/0049_populate_responses_column.py b/tigaserver_app/migrations/0049_populate_responses_column.py new file mode 100644 index 000000000..b5c4f90fb --- /dev/null +++ b/tigaserver_app/migrations/0049_populate_responses_column.py @@ -0,0 +1,649 @@ +# Generated by Django 2.2.7 on 2024-02-12 15:12 + +from typing import Tuple +from django.db import migrations, models +from django.db.models.functions import Cast, Coalesce + + +def update_field_based_on_responses(apps, fieldname, responses: Tuple[str, str], value): + def responses_list_to_Q(responses: Tuple[str, str], connector: str =models.Q.OR): + return models.Q( + *[ + models.Q(question=question, answer=answer) + for question, answer in responses + ], + _connector=connector + ) + + # Loading models + Report = apps.get_model("tigaserver_app", "Report") + ReportResponse = apps.get_model("tigaserver_app", "ReportResponse") + + responses_subquery = ReportResponse.objects.filter(report=models.OuterRef('pk')).values('report') + + subquery = responses_subquery.filter(responses_list_to_Q(responses=responses)) + Report.objects.filter(pk__in=models.Subquery(subquery)).update(**{fieldname: value}) + +def update_boolean_field_based_on_responses(apps, fieldname, responses_dict): + + if False in responses_dict.keys(): + update_field_based_on_responses(apps=apps, fieldname=fieldname, responses=responses_dict[False], value=False) + + if True in responses_dict.keys(): + update_field_based_on_responses(apps=apps, fieldname=fieldname, responses=responses_dict[True], value=True) + +def populate_breeding_site_has_larvae_field(apps, schema_editor): + responses_dict = { + True: [ + ("¿Contiene agua estancada y/o larvas de mosquito?", "Hay agua y veo larvas de mosquito"), + ("Contiene agua estancada y/o larvas o pupas de mosquito (cualquier especie)?", "Sí, agua y larvas o pupas."), + ("Conté aigua estancada i/o larves de mosquit?", "Hi ha aigua i veig larves de mosquit"), + ("Does it contain stagnant water and/or mosquito larvae?", "Has stagnant water with larvae"), + ("¿Contiene larvas o pupas de mosquito (de cualquier especie)?", "Sí"), + ("Conté larves o pupes de mosquit (de qualsevol espècie)?", "Sí"), + ("Conté aigua estancada y/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua i larves o pupes."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Yes, stagnant water with larvae or pupae."), + ("Conté aigua estancada i/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua i larves o pupes."), + ("Have you seen mosquito larvae (not necessarily tiger mosquito) inside?", "Yes"), + ], + False: [ + ("¿Contiene agua estancada y/o larvas de mosquito?", "Hay agua pero no veo larvas de mosquito"), + ("Conté aigua estancada i/o larves de mosquit?", "Hi ha aigua però no veig larves de mosquit"), + ("Contiene agua estancada y/o larvas o pupas de mosquito (cualquier especie)?", "Sí, agua sin larvas ni pupas."), + ("Does it contain stagnant water and/or mosquito larvae?", "Has stagnant water, but with no larvae"), + ("Have you seen mosquito larvae (not necessarily tiger mosquito) inside?", "No"), + ("Conté aigua estancada y/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua sense larves ni pupes."), + ("Conté aigua estancada y/o larves o pupes de mosquit (qualsevol espècie)?", "No, ni aigua ni larves o pupes."), + ("¿Contiene larvas o pupas de mosquito (de cualquier especie)?", "No"), + ("這繁殖地有沒有藏有積水,和/或任何蚊子品種旳幼蟲或蛹?", "有積水,但沒有幼蟲或蛹"), + ("Conté larves o pupes de mosquit (de qualsevol espècie)?", "No"), + ("Conté aigua estancada i/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua sense larves ni pupes."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "No, neither stagnant water nor larve nor pupae."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Has stagnant water, but no larvae or pupae."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Yes, stagnant water, but no larvae or pupae."), + ("這繁殖地有沒有藏有積水,和/或任何蚊子品種旳幼蟲或蛹?", "有積水,但沒有幼蟲或蛹。"), + ] + } + + update_boolean_field_based_on_responses( + apps=apps, + fieldname='breeding_site_has_larvae', + responses_dict=responses_dict + ) + + +def populate_breeding_site_has_near_mosquitoes(apps, schema_editor): + responses_dict = { + True: [ + ("¿Has visto mosquitos cerca (a menos de 10 metros)?", "Sí"), + ("¿Has visto mosquitos cerca (a <10 metros)?", "Sí"), + ("Has vist mosquits a prop (a menys de 10 metres)?", "Sí"), + ("Have you seen mosquitoes nearby (<10 meters)?", "Yes"), + ("Has vist mosquits a prop (a <10metres)?", "Sí"), + ("Have you seen adult mosquitoes nearby (<10 meters)?", "Yes"), + ("你有否在周遭地方見到成年蚊子(少於十米內)?", "是"), + ], + False: [ + ("¿Has visto mosquitos cerca (a menos de 10 metros)?", "No"), + ("Has vist mosquits a prop (a menys de 10 metres)?", "No"), + ("Have you seen mosquitoes nearby (<10 meters)?", "No"), + ("¿Has visto mosquitos cerca (a <10 metros)?", "No"), + ("Has vist mosquits a prop (a <10metres)?", "No"), + ("Have you seen adult mosquitoes nearby (<10 meters)?", "No"), + ("你有否在周遭地方見到成年蚊子(少於十米內)?", "否"), + ("Have you seen adult mosquitoes around the breeding site?", "No"), + ], + } + + update_boolean_field_based_on_responses( + apps=apps, + fieldname='breeding_site_has_near_mosquitoes', + responses_dict=responses_dict + ) + +def populate_breeding_site_has_water(apps, schema_editor): + responses_dict = { + True: [ + ("question_10", "question_10_answer_101"), + ("question_17", "question_10_answer_101"), + ("¿Contiene agua estancada y/o larvas de mosquito?", "Hay agua pero no veo larvas de mosquito"), + ("¿Contiene agua estancada y/o larvas de mosquito?", "Hay agua y veo larvas de mosquito"), + ("Conté aigua estancada i/o larves de mosquit?", "Hi ha aigua però no veig larves de mosquit"), + ("Contiene agua estancada y/o larvas o pupas de mosquito (cualquier especie)?", "Sí, agua y larvas o pupas."), + ("¿Contiene agua estancada?", "Sí"), + ("Conté aigua estancada i/o larves de mosquit?", "Hi ha aigua i veig larves de mosquit"), + ("Contiene agua estancada y/o larvas o pupas de mosquito (cualquier especie)?", "Sí, agua sin larvas ni pupas."), + ("Does it contain stagnant water and/or mosquito larvae?", "Has stagnant water with larvae"), + ("Does it contain stagnant water and/or mosquito larvae?", "Has stagnant water, but with no larvae"), + ("Conté aigua estancada?", "Sí"), + ("Does it have stagnant water inside?", "Yes"), + ("Conté aigua estancada y/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua i larves o pupes."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Yes, stagnant water with larvae or pupae."), + ("Conté aigua estancada i/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua i larves o pupes."), + ("Conté aigua estancada y/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua sense larves ni pupes."), + ("這繁殖地有沒有藏有積水,和/或任何蚊子品種旳幼蟲或蛹?", "有積水,但沒有幼蟲或蛹"), + ("Conté aigua estancada i/o larves o pupes de mosquit (qualsevol espècie)?", "Sí, aigua sense larves ni pupes."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Has stagnant water, but no larvae or pupae."), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Yes, stagnant water, but no larvae or pupae."), + ("¿Contiene agua?", "Sí"), + ("這繁殖地有沒有藏有積水,和/或任何蚊子品種旳幼蟲或蛹?", "有積水,但沒有幼蟲或蛹。"), + ], + False: [ + ("Conté aigua estancada y/o larves o pupes de mosquit (qualsevol espècie)?", "No, ni aigua ni larves o pupes."), + ("Conté aigua estancada i/o larves o pupes de mosquit (qualsevol espècie)?", "No, no conté aigua."), + ("這繁殖地有沒有藏有積水,和/或任何蚊子品種旳幼蟲或蛹?", "沒有積水"), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "No, neither stagnant water nor larve nor pupae."), + ("Conté aigua estancada?", "No"), + ("Does it have stagnant water inside?", "No"), + ("Does it contain stagnant water and/or mosquito larvae or pupae (any mosquito species)?", "Does not contain stagnant water."), + ("¿Contiene agua estancada y/o larvas de mosquito?", "No hay agua"), + ("¿Contiene agua estancada?", "No"), + ("Conté aigua estancada i/o larves de mosquit?", "No hi ha aigua"), + ("Contiene agua estancada y/o larvas o pupas de mosquito (cualquier especie)?", "No, no contiene agua."), + ("Does it contain stagnant water and/or mosquito larvae?", "Does not contain stagnant water"), + ("question_10", "question_10_answer_102"), + ("question_17", "question_10_answer_102"), + ], + } + + update_boolean_field_based_on_responses( + apps=apps, + fieldname='breeding_site_has_water', + responses_dict=responses_dict + ) + +def populate_breeding_site_in_public_area(apps, schema_editor): + responses_dict = { + True: [ + ("¿Se encuentra en la vía pública?", "Sí"), + ("Es troba a la via pública?", "Sí"), + ("Is it in a public area?", "Yes"), + ("這繁殖地是否公共空間?", "是"), + ], + False: [ + ("¿Se encuentra en la vía pública?", "No"), + ("Es troba a la via pública?", "No"), + ("Is it in a public area?", "No"), + ("這繁殖地是否公共空間?", "否"), + ], + } + + update_boolean_field_based_on_responses( + apps=apps, + fieldname='breeding_site_in_public_area', + responses_dict=responses_dict + ) + +def populate_breeding_site_type(apps, schema_editor): + + from tigaserver_app.models import Report + + # Basin + basin_responses = [ + ("Selecciona lloc de cria", "Basses artificials petites"), + ("Selecciona lloc de cria", "Bassa petita o similar"), + ("Tipo de lugar de cría", "Balsa pequeña o similar"), + ("Tipo de lugar de cría", "Pequeñas balsas artificiales"), + ("Type of breeding site", "Basin"), + ("Type of breeding site", "Small basin or similar receptacle"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=basin_responses, value=Report.BREEDING_SITE_TYPE_BASIN) + + # Bucket + bucket_responses = [ + ("Tipo de lugar de cría", "Bidones"), + ("Selecciona lloc de cria", "Bidons"), + ("Type of breeding site", "Bucket"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=bucket_responses, value=Report.BREEDING_SITE_TYPE_BUCKET) + + # Fountain + fountain_responses = [ + ("Tipo de lugar de cría", "Fuente ornamental"), + ("Tipo de lugar de cría", "Fuentes"), + ("Selecciona lloc de cria", "Font ornamental"), + ("Selecciona lloc de cria", "Fonts"), + ("Type of breeding site", "Fountain"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=fountain_responses, value=Report.BREEDING_SITE_TYPE_FOUNTAIN) + + # other + other_responses = [ + ("question_12","question_12_answer_122"), + ("¿Es un imbornal o alcantarilla?","Otros"), + ("Tipo de lugar de cría","Otros"), + ("¿Es un imbornal o alcantarilla?","No"), + ("És un embornal o claveguera?","Altres"), + ("Is this a storm drain or sewer?","Other"), + ("Selecciona lloc de cria","Altres"), + ("Is this a storm drain or sewer?","No"), + ("És un embornal o claveguera?","No"), + ("Type of breeding site ","Other"), + ("這繁殖地是否排水渠或下水道?","其他"), + ("這繁殖地是否排水渠或下水道?","否"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=other_responses, value=Report.BREEDING_SITE_TYPE_OTHER) + + # small_container + small_container_responses = [ + ("Tipo de lugar de cría","Recipiente pequeño"), + ("Selecciona lloc de cria","Recipient petit"), + ("Type of breeding site","Small container"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=small_container_responses, value=Report.BREEDING_SITE_TYPE_SMALL_CONTAINER) + + # storm drain + storm_drain_responses = [ + ("question_12","question_12_answer_121"), + ("¿Es un imbornal o alcantarilla?","Sí"), + ("És un embornal o claveguera?","Sí"), + ("Is this a storm drain or sewer?","Yes"), + ("Tipo de lugar de cría","Sumidero o imbornal"), + ("Tipo de lugar de cría","Sumideros"), + ("Selecciona lloc de cria","Embornal o similar"), + ("Selecciona lloc de cria","Embornals"), + ("Type of breeding site","Storm drain"), + ("Type of breeding site","Storm drain or similar receptacle"), + ("這繁殖地是否排水渠或下水道?","是"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=storm_drain_responses, value=Report.BREEDING_SITE_TYPE_STORM_DRAIN) + + # well + well_responses = [ + ("Tipo de lugar de cría","Pozos"), + ("Selecciona lloc de cria","Pous"), + ] + update_field_based_on_responses(apps=apps, fieldname='breeding_site_type', responses=well_responses, value=Report.BREEDING_SITE_TYPE_WELL) + +def populate_event_environment(apps, schema_editor): + from tigaserver_app.models import Report + + # indoors + indoors_responses = [ + ("question_13","question_13_answer_132"), + ("question_4","question_4_answer_42"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_environment', responses=indoors_responses, value=Report.EVENT_ENVIRONMENT_INDOORS) + + # outdoors + outdoors_responses = [ + ("question_13","question_13_answer_133"), + ("question_4","question_4_answer_43"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_environment', responses=outdoors_responses, value=Report.EVENT_ENVIRONMENT_OUTDOORS) + + # vehicle + vehicle_responses = [ + ("question_13","question_13_answer_131"), + ("question_4","question_4_answer_41"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_environment', responses=vehicle_responses, value=Report.EVENT_ENVIRONMENT_VEHICLE) + +def populate_event_moment(apps, schema_editor): + from tigaserver_app.models import Report + + # now + now_responses = [ + ("question_5","question_5_answer_51"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_moment', responses=now_responses, value=Report.EVENT_MOMENT_NOW) + + # last night + last_night_responses = [ + ("question_3","question_3_answer_34"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_moment', responses=last_night_responses, value=Report.EVENT_MOMENT_LAST_NIGHT) + + # last afternoon + last_afternoon_responses = [ + ("question_3","question_3_answer_33"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_moment', responses=last_afternoon_responses, value=Report.EVENT_MOMENT_LAST_AFTERNOON) + + # last midday + last_midday_responses = [ + ("question_3","question_3_answer_32"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_moment', responses=last_midday_responses, value=Report.EVENT_MOMENT_LAST_MIDDAY) + + # last morning + last_morning_responses = [ + ("question_3","question_3_answer_31"), + ] + update_field_based_on_responses(apps=apps, fieldname='event_moment', responses=last_morning_responses, value=Report.EVENT_MOMENT_LAST_MORNING) + + +def populate_user_perceived_mosquito_abdomen(apps, schema_editor): + from tigaserver_app.models import Report + + # albopictus responses + albopictus_responses = [ + ("question_7","question_7_answer_721"), + ("¿Tiene rayas blancas en el abdomen y en las patas?", "Sí"), + ("¿Cómo es el abdomen del mosquito? Consulta el botón (i) y selecciona una respuesta:","Con líneas y manchas blancas finas"), + ("Com és l’abdomen del mosquit? Consulta el botó (i) i selecciona una resposta:","Amb línies i taques blanques fines"), + ("What does the abdomen of your mosquito look like? Check the (i) button and select an answer:","With white lines and thin white spots"), + ("¿Cómo es el abdomen de tu mosquito? Consulta el botón (i) y selecciona una respuesta:","Abdomen como Ae. albopictus"), + ("Does it have white stripes on the abdomen and legs?","Yes"), + ("¿Como era el mosquito?","question_7_answer_721"), + ("Com és l’abdomen del teu mosquit? Consulta el botó (i) i selecciona una resposta:","Abdomen com Ae. albopictus"), + ("What does the abdomen of your mosquito look like? Check the (i) button and select an answer:","Abdomen like a Ae. albopictus"), + ("蚊子的腹部是什麼樣子?檢查(i)按鈕,然後選擇一個答案:","有白色條紋和小斑點。"), + ("¿Como era el mosquito?","question_7_answer_721"), + ("蚊子的腹部是什麼樣子?檢查(i)按鈕,然後選擇一個答案:","有白色條紋和小斑點"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_abdomen', responses=albopictus_responses, value=Report.SPECIE_ALBOPICTUS) + + # aegypti responses + aegypti_responses = [ + ("question_7","question_7_answer_722"), + ("¿Cómo es el abdomen del mosquito? Consulta el botón (i) y selecciona una respuesta:","Con líneas y manchas blancas gruesas"), + ("Com és l’abdomen del mosquit? Consulta el botó (i) i selecciona una resposta:","Amb línies i taques blanques gruixudes"), + ("¿Cómo es el abdomen del mosquito? Consulta el botón (i) y selecciona una respuesta:","Con líneas y manchas blancas gruesas"), + ("What does the abdomen of your mosquito look like? Check the (i) button and select an answer:","With white lines and thick white spots"), + ("¿Cómo es el abdomen de tu mosquito? Consulta el botón (i) y selecciona una respuesta:","Abdomen como Ae. aegypti"), + ("¿Como era el mosquito?","question_7_answer_722"), + ("What does the abdomen of your mosquito look like? Check the (i) button and select an answer:","Abdomen like Ae. aegypti"), + ("Com és l’abdomen del teu mosquit? Consulta el botó (i) i selecciona una resposta:","Abdomen com Ae. aegypti"), + ("¿Como era el mosquito?","question_7_answer_722"), + ("蚊子的腹部是什麼樣子?檢查(i)按鈕,然後選擇一個答案:","有白色條紋和大斑點"), + ("蚊子的腹部是什麼樣子?檢查(i)按鈕,然後選擇一個答案:","有白色條紋和大斑點。"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_abdomen', responses=aegypti_responses, value=Report.SPECIE_AEGYPTI) + + # japonicus responses + japonicus_responses = [ + ("question_7","question_7_answer_723"), + ("¿Como era el mosquito?","question_7_answer_723"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_abdomen', responses=japonicus_responses, value=Report.SPECIE_JAPONICUS) + + # koreicus responses + koreicus_responses = [ + ("question_7","question_7_answer_724"), + ("¿Como era el mosquito?","question_7_answer_724"), + ("¿Como era el mosquito?","question_7_answer_724"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_abdomen', responses=koreicus_responses, value=Report.SPECIE_KOREICUS) + + # other species responses + other_species_responses = [ + ("¿Cómo es el abdomen de tu mosquito? Consulta el botón (i) y selecciona una respuesta:","Ninguno de los dos"), + ("¿Cómo es el abdomen del mosquito? Consulta el botón (i) y selecciona una respuesta:","No tiene líneas ni manchas blancas"), + ("What does the abdomen of your mosquito look like? Check the (i) button and select an answer:","Neither"), + ("蚊子的腹部是什麼樣子?檢查(i)按鈕,然後選擇一個答案:","皆不是") + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_abdomen', responses=other_species_responses, value=Report.SPECIE_OTHER) + +def populate_user_perceived_mosquito_legs(apps, schema_editor): + from tigaserver_app.models import Report + + # albopictus responses + albopictus_responses = [ + ("question_7", "question_7_answer_731"), + ("¿Como era el mosquito?", "question_7_answer_731"), + ("¿Como era el mosquito?", "question_7_answer_731"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_legs', responses=albopictus_responses, value=Report.SPECIE_ALBOPICTUS) + + # aegypti responses + aegypti_responses = [ + ("question_7", "question_7_answer_732"), + ("¿Como era el mosquito?", "question_7_answer_732"), + ("¿Como era el mosquito?", "question_7_answer_732"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_legs', responses=aegypti_responses, value=Report.SPECIE_AEGYPTI) + + # japonicus responses + japonicus_responses = [ + ("question_7", "question_7_answer_733"), + ("¿Como era el mosquito?", "question_7_answer_733"), + ("¿Como era el mosquito?", "question_7_answer_733"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_legs', responses=japonicus_responses, value=Report.SPECIE_JAPONICUS) + + # koreicus responses + koreicus_responses = [ + ("question_7", "question_7_answer_734"), + ("¿Como era el mosquito?", "question_7_answer_734"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_legs', responses=koreicus_responses, value=Report.SPECIE_KOREICUS) + +def populate_user_perceived_mosquito_thorax(apps, schema_editor): + from tigaserver_app.models import Report + + # albopictus responses + albopictus_responses = [ + ("question_7", "question_7_answer_711"), + ("Mira justo después de su cabeza, en el tórax. ¿Tiene una sola línea blanca? Consulta el botón (i) y selecciona una respuesta:", "Sí"), + ("¿Tiene una raya blanca en la cabeza y en el tórax?", "Sí"), + ("Mira just després del seu cap, al tòrax. Té una sola línia blanca? Consulta el botó (i) i selecciona una resposta:", "Sí"), + ("Té una ratlla blanca al cap i al tòrax?", "Sí"), + ("Look right after the head, at the thorax. Does it have a single white line? Check the (i) button and select an answer:", "Yes"), + ("¿Cómo es el tórax de tu mosquito? Consulta el botón (i) y selecciona una respuesta:", "Tórax like Ae. albopictus"), + ("¿Como era el mosquito?", "question_7_answer_711"), + ("Does it have a white stripe on the head and thorax?", "Yes"), + ("Com és el tòrax del teu mosquit? Consulta el botó (i) i selecciona una resposta:", "Tórax com Ae. albopictus"), + ("What does the thorax of your mosquito look like? Check the (i) button and select an answer:", "Thorax like Ae. albopictus"), + ("¿Como era el mosquito?", "question_7_answer_711"), + ("蚊子的胸部是什麼樣子?是否帶有一條白色條紋?檢查(i)按鈕,然後選擇答案:", "是"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_thorax', responses=albopictus_responses, value=Report.SPECIE_ALBOPICTUS) + + # aegypti responses + aegypti_responses = [ + ("question_7", "question_7_answer_712"), + ("Mira justo después de su cabeza, en el tórax. ¿Tiene una sola línea blanca? Consulta el botón (i) y selecciona una respuesta:", "No, tiene 4 en forma de lira"), + ("Look right after the head, at the thorax. Does it have a single white line? Check the (i) button and select an answer:", "No, it has 4 in a lyre-shaped pattern"), + ("Mira just després del seu cap, al tòrax. Té una sola línia blanca? Consulta el botó (i) i selecciona una resposta:", "No, en té 4 en forma de lira"), + ("¿Cómo es el tórax de tu mosquito? Consulta el botón (i) y selecciona una respuesta:", "Tórax como Ae. aegypti"), + ("¿Como era el mosquito?", "question_7_answer_712"), + ("What does the thorax of your mosquito look like? Check the (i) button and select an answer:", "Thorax like Ae. aegypti"), + ("Com és el tòrax del teu mosquit? Consulta el botó (i) i selecciona una resposta:", "Tórax com Ae. aegypti"), + ("蚊子的胸部是什麼樣子?是否帶有一條白色條紋?檢查(i)按鈕,然後選擇答案:", "否,蚊子有成豎琴形的四條白色條紋。"), + ("蚊子的胸部是什麼樣子?是否帶有一條白色條紋?檢查(i)按鈕,然後選擇答案:", "否,蚊子有四條白色條紋組成豎琴形"), + ("¿Como era el mosquito?", "question_7_answer_712"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_thorax', responses=aegypti_responses, value=Report.SPECIE_AEGYPTI) + + # japonicus responses + japonicus_responses = [ + ("question_7", "question_7_answer_713"), + ("¿Como era el mosquito?", "question_7_answer_713"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_thorax', responses=japonicus_responses, value=Report.SPECIE_JAPONICUS) + + # koreicus responses + koreicus_responses = [ + ("question_7", "question_7_answer_714"), + ("¿Como era el mosquito?", "question_7_answer_714"), + ("¿Como era el mosquito?", "question_7_answer_714"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_thorax', responses=koreicus_responses, value=Report.SPECIE_KOREICUS) + + # other species responses + other_species_responses = [ + ("¿Cómo es el tórax de tu mosquito? Consulta el botón (i) y selecciona una respuesta:","Ninguno de los dos"), + ("Com és el tòrax del teu mosquit? Consulta el botó (i) i selecciona una resposta:","Cap dels dos"), + ("What does the thorax of your mosquito look like? Check the (i) button and select an answer:","Neither"), + ("Mira just després del seu cap, al tòrax. Té una sola línia blanca? Consulta el botó (i) i selecciona una resposta:","Cap dels dos"), + ("Mira justo después de su cabeza, en el tórax. ¿Tiene una sola línea blanca? Consulta el botón (i) y selecciona una respuesta:","Ninguno de los dos"), + ("Look right after the head, at the thorax. Does it have a single white line? Check the (i) button and select an answer:","Neither"), + ("蚊子的胸部是什麼樣子?是否帶有一條白色條紋?檢查(i)按鈕,然後選擇答案:","皆不是") + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_thorax', responses=other_species_responses, value=Report.SPECIE_OTHER) + +def populate_user_perceived_mosquito_specie(apps, schema_editor): + from tigaserver_app.models import Report + + # albopictus responses + albopictus_responses = [ + ("question_6", "question_6_answer_61"), + ("¿Es pequeño y negro con rayas blancas?", "Sí"), + ("¿De qué color es? Consulta el botón (i) y selecciona una respuesta:", "Negro con líneas blancas en cuerpo y patas"), + ("De quin color és? Consulta el botó (i) i selecciona una resposta:", "Negre amb línies blanques al cos i les potes"), + ("What color is your mosquito? Check the (i) button and select an answer:", "Black with white lines on the body and the legs"), + ("És petit i negre amb ratlles blanques?", "Sí"), + ("¿De qué color es? Consulta el botón (i) y selecciona una respuesta:", "Negro con líneas blancas en cuerpo y patas"), + ("¿Cómo es tu mosquito? Consulta el botón (i) y selecciona una respuesta:", "Como Ae. albopictus"), + ("Is it small and black with white stripes?", "Yes"), + ("Com és el teu mosquit? Consulta el botó (i) i selecciona una resposta:", "Com Ae. albopictus"), + ("What does your mosquito look like? Check the (i) button and select an answer:", "Like Ae. albopictus"), + ("你的蚊子是什麼顏色?檢查(i)按鈕,然後選擇一個答案:", "黑色身軀,並且在腹部和腿部有白色條紋"), + ("你的蚊子是什麼顏色?檢查(i)按鈕,然後選擇一個答案:", "黑色身軀,並且在腹部和腿部有白色條紋。"), + ("What color is your mosquito? Check the (i) button and select an answer:", "Black with with white lines on the body and the legs"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_specie', responses=albopictus_responses, value=Report.SPECIE_ALBOPICTUS) + + # aegypti responses + aegypti_responses = [ + ("¿Cómo es tu mosquito? Consulta el botón (i) y selecciona una respuesta:", "Como Ae. aegypti"), + ("What does your mosquito look like? Check the (i) button and select an answer:", "Like Ae. aegypti"), + ("Com és el teu mosquit? Consulta el botó (i) i selecciona una resposta:", "Com Ae. aegypti"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_specie', responses=aegypti_responses, value=Report.SPECIE_AEGYPTI) + + + # culex responses + culex_responses = [ + ("question_6", "question_6_answer_62"), + ("¿De qué color es? Consulta el botón (i) y selecciona una respuesta:", "Marrón con líneas blancas en cuerpo y patas"), + ("De quin color és? Consulta el botó (i) i selecciona una resposta:", "Marró amb línies blanques al cos i les potes"), + ("What color is your mosquito? Check the (i) button and select an answer:", "Brown with white lines on the body and the legs"), + ("你的蚊子是什麼顏色?檢查(i)按鈕,然後選擇一個答案:", "棕色身軀,並且在腹部和腿部有白色條紋"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_specie', responses=culex_responses, value=Report.SPECIE_CULEX) + + # other specie responses + other_specie_responses = [ + ("question_6", "question_6_answer_63"), + ("¿Cómo es tu mosquito? Consulta el botón (i) y selecciona una respuesta:", "None of them"), + ("Com és el teu mosquit? Consulta el botó (i) i selecciona una resposta:", "Cap dels dos"), + ("What does your mosquito look like? Check the (i) button and select an answer:", "Neither"), + ("¿De qué color es? Consulta el botón (i) y selecciona una respuesta:", "Ninguno de los dos"), + ("De quin color és? Consulta el botó (i) i selecciona una resposta:", "Cap dels dos"), + ("What color is your mosquito? Check the (i) button and select an answer:", "Neither"), + ("你的蚊子是什麼顏色?檢查(i)按鈕,然後選擇一個答案:", "皆不是"), + ] + + update_field_based_on_responses(apps=apps, fieldname='user_perceived_mosquito_specie', responses=other_specie_responses, value=Report.SPECIE_OTHER) + + +def populate_bite_count(apps, schema_editor): + + def update_bite_body_part(apps, fieldname, answer_id): + # Loading models + Report = apps.get_model("tigaserver_app", "Report") + ReportResponse = apps.get_model("tigaserver_app", "ReportResponse") + + subquery = ReportResponse.objects.filter( + report=models.OuterRef('pk'), + question_id=2, + answer_id=answer_id + ).values('answer_value')[:1] + + Report.objects.update( + **{f"{fieldname}": Cast( + models.Subquery(subquery), + output_field=Report._meta.get_field(fieldname).__class__() + )} + ) + + from tigaserver_app.models import Report as ModelReport + + # Ensure bite report field are set to 0 as default. + Report.objects.filter( + type=ModelReport.TYPE_BITE, + **{f"{fieldname}__isnull": True} + ).update(**{f"{fieldname}": 0}) + + # Loading models + Report = apps.get_model("tigaserver_app", "Report") + + update_bite_body_part( + apps=apps, + fieldname="chest_bite_count", + answer_id=24 + ) + + update_bite_body_part( + apps=apps, + fieldname="head_bite_count", + answer_id=21 + ) + + update_bite_body_part( + apps=apps, + fieldname="left_arm_bite_count", + answer_id=22 + ) + + update_bite_body_part( + apps=apps, + fieldname="right_arm_bite_count", + answer_id=23 + ) + + update_bite_body_part( + apps=apps, + fieldname="left_leg_bite_count", + answer_id=25 + ) + + update_bite_body_part( + apps=apps, + fieldname="right_leg_bite_count", + answer_id=26 + ) + + # NOTE: bite count must be the last. + Report.objects.update( + bite_count=models.ExpressionWrapper( + Coalesce(models.F('head_bite_count'), 0) + + Coalesce(models.F('left_arm_bite_count'), 0) + + Coalesce(models.F('right_arm_bite_count'), 0) + + Coalesce(models.F('chest_bite_count'), 0) + + Coalesce(models.F('left_leg_bite_count'), 0) + + Coalesce(models.F('right_leg_bite_count'), 0), + output_field=models.PositiveSmallIntegerField() + ) + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('tigaserver_app', '0048_report_responses_to_column'), + ] + + operations = [ + migrations.RunPython(populate_breeding_site_has_larvae_field, migrations.RunPython.noop), + migrations.RunPython(populate_breeding_site_has_near_mosquitoes, migrations.RunPython.noop), + migrations.RunPython(populate_breeding_site_has_water, migrations.RunPython.noop), + migrations.RunPython(populate_breeding_site_in_public_area, migrations.RunPython.noop), + migrations.RunPython(populate_breeding_site_type, migrations.RunPython.noop), + migrations.RunPython(populate_event_environment, migrations.RunPython.noop), + migrations.RunPython(populate_event_moment, migrations.RunPython.noop), + migrations.RunPython(populate_user_perceived_mosquito_abdomen, migrations.RunPython.noop), + migrations.RunPython(populate_user_perceived_mosquito_legs, migrations.RunPython.noop), + migrations.RunPython(populate_user_perceived_mosquito_thorax, migrations.RunPython.noop), + migrations.RunPython(populate_user_perceived_mosquito_specie, migrations.RunPython.noop), + migrations.RunPython(populate_bite_count, migrations.RunPython.noop), + ] diff --git a/tigaserver_app/models.py b/tigaserver_app/models.py index 206dea653..133e1c165 100644 --- a/tigaserver_app/models.py +++ b/tigaserver_app/models.py @@ -24,6 +24,7 @@ from django.db.models import Count, Q from django.db.models.signals import post_save from django.dispatch import receiver +from django.forms.models import model_to_dict from django.template.loader import render_to_string, TemplateDoesNotExist from django.urls import reverse from django.utils import translation @@ -700,6 +701,142 @@ class Report(TimeZoneModelMixin, models.Model): ''' ) + # Attributes - user responses - Optional + EVENT_ENVIRONMENT_INDOORS = 'indoors' + EVENT_ENVIRONMENT_OUTDOORS = 'outdoors' + EVENT_ENVIRONMENT_VEHICLE = 'vehicle' + + EVENT_ENVIRONMENT_CHOICES = ( + (EVENT_ENVIRONMENT_INDOORS, _("Indoors")), + (EVENT_ENVIRONMENT_OUTDOORS, _("Outdoors")), + (EVENT_ENVIRONMENT_VEHICLE, _("Inside vehicle")), + ) + + event_environment = models.CharField( + max_length=16, choices=EVENT_ENVIRONMENT_CHOICES, null=True, + help_text=_("The environment where the event took place.") + ) + + EVENT_MOMENT_NOW = 'now' + EVENT_MOMENT_LAST_MORNING = 'last_morning' + EVENT_MOMENT_LAST_MIDDAY = 'last_midday' + EVENT_MOMENT_LAST_AFTERNOON = 'last_afternoon' + EVENT_MOMENT_LAST_NIGHT = 'last_night' + EVENT_MOMENT_CHOICES = ( + (EVENT_MOMENT_NOW, _("Now")), + (EVENT_MOMENT_LAST_MORNING, _("Last morning")), + (EVENT_MOMENT_LAST_MIDDAY, _("Last midday")), + (EVENT_MOMENT_LAST_AFTERNOON, _("Last afternoon")), + (EVENT_MOMENT_LAST_NIGHT, _("Last night")), + ) + + event_moment = models.CharField( + max_length=32, choices=EVENT_MOMENT_CHOICES, null=True, + help_text=_("The moment of the day when the event took place.") + ) + + bite_count = models.PositiveSmallIntegerField( + null=True, editable=False, + help_text=_("Total number of bites reported.") + ) + + head_bite_count = models.PositiveSmallIntegerField( + null=True, + help_text=_("Number of bites reported in the head.") + ) + left_arm_bite_count = models.PositiveSmallIntegerField( + null=True, + help_text=_("Number of bites reported in the left arm.") + ) + right_arm_bite_count = models.PositiveSmallIntegerField( + null=True, + help_text=_("Number of bites reported in the right arm.") + ) + chest_bite_count = models.PositiveSmallIntegerField( + null=True, + help_text=_("Number of bites reported in the chest.") + ) + left_leg_bite_count = models.PositiveSmallIntegerField( + null=True, + help_text=_("Number of bites reported in the left leg.") + ) + right_leg_bite_count = models.PositiveSmallIntegerField( + null=True, + help_text=_("Number of bites reported in the right leg.") + ) + + SPECIE_ALBOPICTUS = "albopictus" + SPECIE_AEGYPTI = "aegypti" + SPECIE_JAPONICUS = "japonicus" + SPECIE_KOREICUS = "koreicus" + SPECIE_CULEX = "culex" + SPECIE_OTHER = "other" + + MOSQUITO_SPECIE_CHOICES = ( + (SPECIE_ALBOPICTUS, "Aedes albopictus"), + (SPECIE_AEGYPTI, "Aedes aegypti"), + (SPECIE_JAPONICUS, "Aedes japonicus"), + (SPECIE_KOREICUS, "Aedes koreicus"), + (SPECIE_CULEX, "Culex pipiens"), + (SPECIE_OTHER, _("Other")), + ) + + user_perceived_mosquito_specie = models.CharField( + max_length=16, choices=MOSQUITO_SPECIE_CHOICES, null=True, + help_text=_("The mosquito specie perceived by the user.") + ) + + user_perceived_mosquito_thorax = models.CharField( + max_length=16, choices=MOSQUITO_SPECIE_CHOICES, null=True, + help_text=_("The species of mosquito that the thorax resembles, according to the user.") + ) + user_perceived_mosquito_abdomen = models.CharField( + max_length=16, choices=MOSQUITO_SPECIE_CHOICES, null=True, + help_text=_("The species of mosquito that the abdomen resembles, according to the user.") + ) + user_perceived_mosquito_legs = models.CharField( + max_length=16, choices=MOSQUITO_SPECIE_CHOICES, null=True, + help_text=_("The species of mosquito that the leg resembles, according to the user.") + ) + + BREEDING_SITE_TYPE_BASIN = 'basin' + BREEDING_SITE_TYPE_BUCKET = 'bucket' + BREEDING_SITE_TYPE_FOUNTAIN = 'fountain' + BREEDING_SITE_TYPE_SMALL_CONTAINER = 'small_container' + BREEDING_SITE_TYPE_STORM_DRAIN = 'storm_drain' + BREEDING_SITE_TYPE_WELL = 'well' + BREEDING_SITE_TYPE_OTHER = 'other' + + BREEDING_SITE_TYPE_CHOICES = ( + (BREEDING_SITE_TYPE_BASIN, _('Basin')), + (BREEDING_SITE_TYPE_BUCKET, _('Bucket')), + (BREEDING_SITE_TYPE_FOUNTAIN, _('Fountain')), + (BREEDING_SITE_TYPE_SMALL_CONTAINER, _('Small container')), + (BREEDING_SITE_TYPE_STORM_DRAIN, _('Storm Drain')), + (BREEDING_SITE_TYPE_WELL, _('Well')), + (BREEDING_SITE_TYPE_OTHER, _('Other')) + ) + + breeding_site_type = models.CharField( + max_length=32, choices=BREEDING_SITE_TYPE_CHOICES, null=True, + help_text=_("Breeding site type.") + ) + breeding_site_has_water = models.BooleanField( + null=True, + help_text=_("Either if the user perceived water in the breeding site.") + ) + breeding_site_in_public_area = models.BooleanField( + null=True, + help_text=_("Either if the breeding site is found in a public area.") + ) + breeding_site_has_near_mosquitoes = models.BooleanField( + null=True, + help_text=_("Either if the user perceived mosquitoes near the breeding site (less than 10 meters).") + ) + breeding_site_has_larvae = models.BooleanField( + null=True, + help_text=_("Either if the user perceived larvaes the breeding site.") + ) # Object Manager objects = ReportManager() @@ -1057,124 +1194,27 @@ def crowd_score(self): # Custom properties related to breeding sites @property def basins(self) -> bool: - result = False - for this_response in self.responses.all(): - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - ): - result = ( - this_response.answer.startswith("Basin") - or this_response.answer.startswith("Basses") - or this_response.answer.startswith("Balsa") - or this_response.answer.startswith("Bassa") - or this_response.answer.startswith("Small basin") - or "balsas" in this_response.answer - ) - return result + return self.breeding_site_type == self.BREEDING_SITE_TYPE_BASIN @property def buckets(self) -> bool: - result = False - for this_response in self.responses.all(): - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - ): - result = ( - this_response.answer.startswith("Bucket") - or this_response.answer.startswith("Small container") - or this_response.answer.startswith("Bidones") - or this_response.answer.startswith("Recipiente") - or this_response.answer.startswith("Recipient") - or this_response.answer.startswith("Bidons") - ) - return result + return self.breeding_site_type == self.BREEDING_SITE_TYPE_BUCKET @property def embornals(self) -> bool: - result = False - for this_response in self.responses.all(): - if this_response.question_id == 12 and this_response.answer_id == 121: - return True - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - or this_response.question.startswith("Is this a storm drain") - or this_response.question.startswith("\xc9s un embornal") - or this_response.question.startswith("\xbfEs un imbornal") - ): - result = ( - this_response.answer.startswith("Embornal") - or this_response.answer.startswith("Sumidero") - or this_response.answer.startswith("Storm") - or this_response.answer.startswith("Yes") - or this_response.answer.startswith("S\xed") - ) - return result + return self.breeding_site_type == self.BREEDING_SITE_TYPE_STORM_DRAIN @property def fonts(self) -> bool: - result = False - for this_response in self.responses.all(): - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - ): - result = ( - this_response.answer.startswith("Font") - or this_response.answer.startswith("Fountain") - or this_response.answer.startswith("Fuente") - ) - return result + return self.breeding_site_type == self.BREEDING_SITE_TYPE_FOUNTAIN @property def other(self) -> bool: - result = False - for this_response in self.responses.all(): - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - ): - result = ( - this_response.answer == "Other" - or this_response.answer == "Altres" - or this_response.answer == "Otros" - ) - return result + return self.breeding_site_type == self.BREEDING_SITE_TYPE_OTHER @property def wells(self) -> bool: - result = False - for this_response in self.responses.all(): - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - ): - result = ( - this_response.answer == "Well" - or this_response.answer == "Pozos" - or this_response.answer == "Pous" - ) - return result - - @property - def site_type(self) -> str: - result = "" - for this_response in self.responses.all(): - if ( - this_response.question.startswith("Tipo") - or this_response.question.startswith("Selecciona") - or this_response.question.startswith("Type") - ): - result = this_response.answer - return result + return self.breeding_site_type == self.BREEDING_SITE_TYPE_WELL @property def site_cat(self) -> int: @@ -1191,19 +1231,6 @@ def site_cat(self) -> int: else: return 5 - @property - def site_type_trans(self) -> str: - if self.embornals: - return _("storm-drain") - if self.fonts: - return _("Fountain") - if self.basins: - return _("Basin") - if self.wells: - return _("Well") - if self.other: - return _("Other") - # Other properties @property def tiger_responses_text(self) -> Optional[dict]: @@ -1538,6 +1565,25 @@ def save(self, *args, **kwargs): self.user.language_iso2 = self.app_language self.user.save(update_fields=['language_iso2']) + bite_fieldnames = [ + 'head_bite_count', + 'left_arm_bite_count', + 'right_arm_bite_count', + 'chest_bite_count', + 'left_leg_bite_count', + 'right_leg_bite_count' + ] + + if self.type == self.TYPE_BITE: + # Make sure all bites are set to 0 if none. + for bite_fieldname in bite_fieldnames: + if getattr(self, bite_fieldname) is None: + setattr(self, bite_fieldname, 0) + + self.bite_count = sum( + getattr(self, fname) for fname in bite_fieldnames + ) + super(Report, self).save(*args, **kwargs) # Meta and String @@ -2525,6 +2571,128 @@ class ReportResponse(models.Model): answer = models.CharField(max_length=1000, help_text='Answer that user selected.') answer_value = models.CharField(max_length=1000, blank=True, null=True, help_text='The value right now can contain 2 things: an integer representing the number or bites, or either a WKT representation of a point for a location answer. In all other cases, it will be blank') + def _update_report_value(self, commit: bool = True): + report_obj = self.report + + # Convert the original state of the object to a dictionary + original_report_state = model_to_dict(report_obj) + + if self.question_id == 2: + if self.answer_id == 21: + report_obj.head_bite_count = int(self.answer_value) + elif self.answer_id == 22: + report_obj.left_arm_bite_count = int(self.answer_value) + elif self.answer_id == 23: + report_obj.right_arm_bite_count = int(self.answer_value) + elif self.answer_id == 24: + report_obj.chest_bite_count = int(self.answer_value) + elif self.answer_id == 25: + report_obj.left_leg_bite_count = int(self.answer_value) + elif self.answer_id == 26: + report_obj.right_leg_bite_count = int(self.answer_value) + elif self.question_id == 3: + if self.answer_id == 31: + report_obj.event_moment = Report.EVENT_MOMENT_LAST_MORNING + elif self.answer_id == 32: + report_obj.event_moment = Report.EVENT_MOMENT_LAST_MIDDAY + elif self.answer_id == 33: + report_obj.event_moment = Report.EVENT_MOMENT_LAST_AFTERNOON + elif self.answer_id == 34: + report_obj.event_moment = Report.EVENT_MOMENT_LAST_NIGHT + elif self.question_id == 4: + if self.answer_id == 41: + report_obj.event_environment = Report.EVENT_ENVIRONMENT_VEHICLE + elif self.answer_id == 42: + report_obj.event_environment = Report.EVENT_ENVIRONMENT_INDOORS + elif self.answer_id == 43: + report_obj.event_environment = Report.EVENT_ENVIRONMENT_OUTDOORS + elif self.answer_id == 44: + report_obj.event_environment = None + elif self.question_id == 5: + if self.answer_id == 51: + report_obj.event_moment = Report.EVENT_MOMENT_NOW + elif self.question == 'question_6': + # NOTE: using question since question_id '6' not present in DB. + if self.answer_id == 61: + report_obj.user_perceived_mosquito_specie = Report.SPECIE_ALBOPICTUS + elif self.answer_id == 62: + report_obj.user_perceived_mosquito_specie = Report.SPECIE_CULEX + elif self.answer_id == 63: + report_obj.user_perceived_mosquito_specie = Report.SPECIE_OTHER + elif self.answer_id == 64: + report_obj.user_perceived_mosquito_specie = None + elif self.question_id == 7 or self.question == 'question_7': + # Thorax + if self.answer_id == 711: + report_obj.user_perceived_mosquito_thorax = Report.SPECIE_ALBOPICTUS + elif self.answer_id == 712: + report_obj.user_perceived_mosquito_thorax = Report.SPECIE_AEGYPTI + elif self.answer_id == 713: + report_obj.user_perceived_mosquito_thorax = Report.SPECIE_JAPONICUS + elif self.answer_id == 714: + report_obj.user_perceived_mosquito_thorax = Report.SPECIE_KOREICUS + + # Abdomen + if self.answer_id == 721: + report_obj.user_perceived_mosquito_abdomen = Report.SPECIE_ALBOPICTUS + elif self.answer_id == 722: + report_obj.user_perceived_mosquito_abdomen = Report.SPECIE_AEGYPTI + elif self.answer_id == 723: + report_obj.user_perceived_mosquito_abdomen = Report.SPECIE_JAPONICUS + elif self.answer_id == 724: + report_obj.user_perceived_mosquito_abdomen = Report.SPECIE_KOREICUS + + # Legs + if self.answer_id == 731: + report_obj.user_perceived_mosquito_legs = Report.SPECIE_ALBOPICTUS + elif self.answer_id == 732: + report_obj.user_perceived_mosquito_legs = Report.SPECIE_AEGYPTI + elif self.answer_id == 733: + report_obj.user_perceived_mosquito_legs = Report.SPECIE_JAPONICUS + elif self.answer_id == 734: + report_obj.user_perceived_mosquito_legs = Report.SPECIE_KOREICUS + elif self.question_id == 10: + if self.answer_id == 81 or self.answer_id == 102: + report_obj.breeding_site_has_water = False + elif self.answer_id == 101: + report_obj.breeding_site_has_water = True + elif self.question_id == 12: + if self.answer_id == 121: + report_obj.breeding_site_type = Report.BREEDING_SITE_TYPE_STORM_DRAIN + elif self.answer_id == 122: + report_obj.breeding_site_type = Report.BREEDING_SITE_TYPE_OTHER + elif self.question_id == 13: + if self.answer_id == 131: + report_obj.event_environment = Report.EVENT_ENVIRONMENT_VEHICLE + elif self.answer_id == 132: + report_obj.event_environment = Report.EVENT_ENVIRONMENT_INDOORS + elif self.answer_id == 133: + report_obj.event_environment = Report.EVENT_ENVIRONMENT_OUTDOORS + elif self.question_id == 17: + if self.answer_id == 81 or self.answer_id == 102: + self.breeding_site_has_water = False + elif self.answer_id == 101: + self.breeding_site_has_water = True + + # Check if any field has changed + if commit and any(getattr(report_obj, field) != original_report_state[field] for field in original_report_state.keys()): + # Save the object only if there are changes, not to trigger auto_now fields. + report_obj.save() + + def save(self, skip_report_update: bool = False, *args, **kwargs): + # NOTE: this is needed to ensure question_id/answer_id are integers. + # _update_report_value works as expected. + if self.question_id is not None: + self.question_id = int(self.question_id) + + if self.answer_id is not None: + self.answer_id = int(self.answer_id) + + super().save(*args, **kwargs) + + if not skip_report_update: + self._update_report_value() + def __unicode__(self): return str(self.id) diff --git a/tigaserver_app/serializers.py b/tigaserver_app/serializers.py index 5a6e6b6af..7d0b2ccfe 100644 --- a/tigaserver_app/serializers.py +++ b/tigaserver_app/serializers.py @@ -273,9 +273,25 @@ def validate_type(self, attrs): def create(self,validated_data): responses_data = validated_data.pop('responses') - report = Report.objects.create(**validated_data) + report = Report(**validated_data) + + # Create the report response and updating report fields + # without saving. We want to save all changes at once. + responses = [] for response in responses_data: - ReportResponse.objects.create(report=report, **response) + report_responses = ReportResponse( + report=report, **response + ) + report_responses._update_report_value( + commit=False + ) + responses.append(report_responses) + + # Saving reports (already updated) + responses. + report.save() + for response in responses: + response.save(skip_report_update=True) + return report class Meta: diff --git a/tigaserver_app/tests/tests.py b/tigaserver_app/tests/tests.py index 528255fbe..40c4f186c 100644 --- a/tigaserver_app/tests/tests.py +++ b/tigaserver_app/tests/tests.py @@ -1125,6 +1125,8 @@ def test_flip_site_to_site(self): self.assertTrue(n_responses == 2, "Number of responses should be 2, is {0}".format(n_responses)) self.assertTrue(r_site_reloaded.flipped, "Report should be marked as flipped") self.assertTrue(r_site_reloaded.flipped_to == 'site#site',"Report should be marked as flipped from site to site, field has value of {0}".format(r_site_reloaded.flipped_to)) + self.assertEqual(r_site_reloaded.breeding_site_type, Report.BREEDING_SITE_TYPE_STORM_DRAIN) + self.assertTrue(r_site_reloaded.breeding_site_has_water) def test_flip(self): u = User.objects.get(pk=25) @@ -1143,7 +1145,10 @@ def test_flip(self): response = self.client.patch('/api/flip_report/', data=data) self.assertEqual(response.status_code, 200, "Response should be 200, is {0}".format(response.status_code)) adult_reloaded = Report.objects.get(pk=r_adult.version_UUID) - self.assertTrue(adult_reloaded.type=='site',"Report type should have changed to site, is {0}".format(adult_reloaded.type)) + self.assertTrue(adult_reloaded.type==Report.TYPE_SITE,"Report type should have changed to site, is {0}".format(adult_reloaded.type)) + self.assertEqual(adult_reloaded.breeding_site_type, Report.BREEDING_SITE_TYPE_STORM_DRAIN) + self.assertTrue(adult_reloaded.breeding_site_has_water) + n_responses = ReportResponse.objects.filter(report=adult_reloaded).count() self.assertTrue( n_responses == 2, "Number of responses should be 2, is {0}".format(n_responses) ) self.assertTrue( adult_reloaded.flipped, "Report should be marked as flipped" ) @@ -1164,7 +1169,8 @@ def test_flip(self): response = self.client.patch('/api/flip_report/', data=data) self.assertEqual(response.status_code, 200, "Response should be 200, is {0}".format(response.status_code)) site_reloaded = Report.objects.get(pk=r_site.version_UUID) - self.assertTrue(site_reloaded.type == 'adult', "Report type should have changed to adult, is {0}".format(site_reloaded.type)) + self.assertTrue(site_reloaded.type == Report.TYPE_ADULT, "Report type should have changed to adult, is {0}".format(site_reloaded.type)) + n_responses = ReportResponse.objects.filter(report=site_reloaded).count() self.assertTrue(n_responses == 0, "Number of responses should be 0, is {0}".format(n_responses)) self.assertTrue(site_reloaded.flipped, "Report should be marked as flipped") diff --git a/tigaserver_app/views.py b/tigaserver_app/views.py index bb53cf0cc..4195e9a80 100644 --- a/tigaserver_app/views.py +++ b/tigaserver_app/views.py @@ -2256,16 +2256,16 @@ def flip_report(request): return Response(data={'message': 'success', 'opcode': -1}, status=status.HTTP_400_BAD_REQUEST) if flip_to_type == '': # adult | site raise ParseError(detail='flip_to_type param is mandatory') - if flip_to_type not in ['adult', 'site']: + if flip_to_type not in [Report.TYPE_ADULT, Report.TYPE_SITE]: raise ParseError(detail='value not allowed, possible values are \'adult\', \'site\'') - if flip_to_type == 'site': + if flip_to_type == Report.TYPE_SITE: if flip_to_subtype == '': raise ParseError(detail='flip_to_subtype param is mandatory if type is site') else: if flip_to_subtype not in ['storm_drain_water','storm_drain_dry', 'other_water', 'other_dry']: raise ParseError(detail='value not allowed, possible values are \'storm_drain_water\',\'storm_drain_dry\', \'other_water\', \'other_dry\' ') - if report.type == 'adult' and flip_to_type == 'adult': + if report.type == Report.TYPE_ADULT and flip_to_type == Report.TYPE_ADULT: return Response( data={'message': 'Type is already adult, doing nothing', 'opcode': -2}, status=status.HTTP_400_BAD_REQUEST) # delete questions and answers ? @@ -2278,15 +2278,15 @@ def flip_report(request): # id 4ada4a1b-c438-4fcc-87e7-eb4696c1466f question_10 question_10_answer_101 101 10 -> Water with transaction.atomic(): ReportResponse.objects.filter(report=report).delete() - rr_type_stormdrain = ReportResponse(report=report,question='question_12',answer='question_12_answer_121',question_id='12',answer_id='121') - rr_type_other = ReportResponse(report=report, question='question_12', answer='question_12_answer_122', question_id='12', answer_id='122') - rr_yes_water = ReportResponse(report=report, question='question_10', answer='question_10_answer_101', question_id='10', answer_id='101') - rr_no_water = ReportResponse(report=report, question='question_10', answer='question_10_answer_102', question_id='10', answer_id='102') - if flip_to_type == 'site': - report.flipped = True - report.flipped_on = timezone.now() + rr_type_stormdrain = ReportResponse(report=report,question='question_12',answer='question_12_answer_121',question_id=12,answer_id=121) + rr_type_other = ReportResponse(report=report, question='question_12', answer='question_12_answer_122', question_id=12, answer_id=122) + rr_yes_water = ReportResponse(report=report, question='question_10', answer='question_10_answer_101', question_id=10, answer_id=101) + rr_no_water = ReportResponse(report=report, question='question_10', answer='question_10_answer_102', question_id=10, answer_id=102) + report.flipped = True + report.flipped_on = timezone.now() + if flip_to_type == Report.TYPE_SITE: report.flipped_to = report.type + '#site' - report.type = 'site' + report.type = Report.TYPE_SITE report.save() if flip_to_subtype == 'storm_drain_water': rr_type_stormdrain.save() @@ -2304,11 +2304,9 @@ def flip_report(request): rr_type_other.save() rr_yes_water.save() message = "Report changed to Site - Other, Water" - elif flip_to_type == 'adult': - report.flipped = True - report.flipped_on = timezone.now() + elif flip_to_type == Report.TYPE_ADULT: report.flipped_to = report.type + '#adult' - report.type = 'adult' + report.type = Report.TYPE_ADULT report.save() message = "Report changed to Adult"