From 34503636b745b32b9f60506e2192f0a4b3e7700c Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 19 Mar 2019 10:49:27 -0400 Subject: [PATCH 01/79] 8087 FR allow filtering by partners --- src/etools/config/settings/base.py | 4 +--- .../libraries/monitoring/service_checks.py | 23 +++++++++++++++---- .../libraries/monitoring/tests/test_checks.py | 22 ++++++++++-------- .../libraries/monitoring/tests/test_views.py | 21 ++++++++--------- src/etools/libraries/monitoring/urls.py | 6 +++-- src/etools/libraries/monitoring/views.py | 13 +++++++---- 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/etools/config/settings/base.py b/src/etools/config/settings/base.py index 6fc0a57c02..642938ebca 100644 --- a/src/etools/config/settings/base.py +++ b/src/etools/config/settings/base.py @@ -269,7 +269,7 @@ def get_from_secrets_or_env(var_name, default=None): AUTH_USER_MODEL = 'users.User' LOGIN_REDIRECT_URL = '/' -HOST = get_from_secrets_or_env('DJANGO_ALLOWED_HOST', 'localhost:8000') +HOST = get_from_secrets_or_env('DJANGO_ALLOWED_HOST', 'http://localhost:8000/') LOGIN_URL = LOGOUT_REDIRECT_URL = get_from_secrets_or_env('LOGIN_URL', '/landing/') # CONTRIB: GIS (GeoDjango) @@ -393,8 +393,6 @@ def get_from_secrets_or_env(var_name, default=None): # https://django-tenant-schemas.readthedocs.io/en/latest/use.html#performance-considerations TENANT_LIMIT_SET_CALLS = True -HOST = get_from_secrets_or_env('DJANGO_ALLOWED_HOST', 'localhost:8000') - # django-rest-framework-jwt: http://getblimp.github.io/django-rest-framework-jwt/ JWT_AUTH = { 'JWT_ENCODE_HANDLER': diff --git a/src/etools/libraries/monitoring/service_checks.py b/src/etools/libraries/monitoring/service_checks.py index 4b749be2a7..2f42146ac5 100644 --- a/src/etools/libraries/monitoring/service_checks.py +++ b/src/etools/libraries/monitoring/service_checks.py @@ -5,6 +5,7 @@ from django.conf import settings from django.contrib.auth import get_user_model +from django.core import cache from django.db import connections from django.db.utils import OperationalError @@ -42,15 +43,27 @@ def check_db(): def check_celery(): celery = Celery() celery.config_from_object(settings) - worker_responses = celery.control.ping(timeout=10) - if not worker_responses: - return ServiceStatus(False, 'No running Celery workers were found.') + conn = celery.connection() + if conn.connected: + return ServiceStatus(True, 'Celery connected') else: - msg = 'Successfully pinged {} workers'.format(len(worker_responses)) - return ServiceStatus(True, msg) + return ServiceStatus(False, 'Celery unable to connect') + + +def check_redis(): + if 'redis' in settings.CACHES: + import redis + rc = cache.caches['redis'] + redis_api = redis.StrictRedis.from_url('%s' % rc._server) + memory = redis_api.info()['used_memory_human'] + result = rc.set('serverup_check_key', 'test', timeout=5) + return ServiceStatus(result, "Redis is up and using {} memory".format(memory)) + else: + return ServiceStatus(False, "Redis is not configured on this system!") CHECKS = { 'db': check_db, 'celery': check_celery, + # 'redis': check_redis, } diff --git a/src/etools/libraries/monitoring/tests/test_checks.py b/src/etools/libraries/monitoring/tests/test_checks.py index 2482935c6e..15a3f90d65 100644 --- a/src/etools/libraries/monitoring/tests/test_checks.py +++ b/src/etools/libraries/monitoring/tests/test_checks.py @@ -39,25 +39,27 @@ def test_users(self): class TestCheckCelery(SimpleTestCase): def test_valid(self): - mock_ping = Mock() - mock_ping.control.ping.return_value = [1, 2] - mock_celery = Mock(return_value=mock_ping) - with patch("etools.libraries.monitoring.service_checks.Celery", mock_celery): + + mock_celery = Mock() + mock_celery.connection.return_value = Mock(connected=True) + + with patch("etools.libraries.monitoring.service_checks.Celery", Mock(return_value=mock_celery)): check = check_celery() self.assertTrue(check.success) self.assertEqual( check.message, - "Successfully pinged 2 workers" + "Celery connected" ) def test_invalid(self): - mock_ping = Mock() - mock_ping.control.ping.return_value = [] - mock_celery = Mock(return_value=mock_ping) - with patch("etools.libraries.monitoring.service_checks.Celery", mock_celery): + + mock_celery = Mock() + mock_celery.connection.return_value = Mock(connected=False) + + with patch("etools.libraries.monitoring.service_checks.Celery", Mock(return_value=mock_celery)): check = check_celery() self.assertFalse(check.success) self.assertEqual( check.message, - "No running Celery workers were found." + "Celery unable to connect" ) diff --git a/src/etools/libraries/monitoring/tests/test_views.py b/src/etools/libraries/monitoring/tests/test_views.py index 1a60976f52..4967fdb69d 100644 --- a/src/etools/libraries/monitoring/tests/test_views.py +++ b/src/etools/libraries/monitoring/tests/test_views.py @@ -1,4 +1,3 @@ - from django.urls import reverse from django.test import Client @@ -13,26 +12,24 @@ class TestCheckView(BaseTenantTestCase): def setUp(self): super().setUp() self.client = Client() - self.url = reverse("monitoring:monitoring") + self.url = reverse("monitoring:app_ready") def test_get_success(self): UserFactory() - mock_ping = Mock() - mock_ping.control.ping.return_value = [1, 2] - mock_celery = Mock(return_value=mock_ping) - with patch("etools.libraries.monitoring.service_checks.Celery", mock_celery): + mock_celery = Mock() + mock_celery.connection.return_value = Mock(connected=True) + with patch("etools.libraries.monitoring.service_checks.Celery", Mock(return_value=mock_celery)): response = self.client.get(self.url) - self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.content.decode('utf-8'), "all is well (checked: celery, db)") def test_get_fail(self): - mock_ping = Mock() - mock_ping.control.ping.return_value = [] - mock_celery = Mock(return_value=mock_ping) - with patch("etools.libraries.monitoring.service_checks.Celery", mock_celery): + mock_celery = Mock() + mock_celery.connection.return_value = Mock(connected=False) + + with patch("etools.libraries.monitoring.service_checks.Celery", Mock(return_value=mock_celery)): response = self.client.get(self.url) self.assertContains( response, - "No running Celery workers were found.", + "Celery unable to connect", status_code=status.HTTP_500_INTERNAL_SERVER_ERROR ) diff --git a/src/etools/libraries/monitoring/urls.py b/src/etools/libraries/monitoring/urls.py index b699e79138..0ce5704c18 100644 --- a/src/etools/libraries/monitoring/urls.py +++ b/src/etools/libraries/monitoring/urls.py @@ -1,8 +1,10 @@ from django.conf.urls import url -from etools.libraries.monitoring.views import CheckView +from etools.libraries.monitoring.views import AppAliveView, AppReadyView app_name = 'monitoring' urlpatterns = ( - url(r'^$', CheckView.as_view(), name="monitoring"), + url(r'^app_alive/$', AppAliveView.as_view(), name="app_alive"), + url(r'^app_ready/$', AppReadyView.as_view(), name="app_ready"), + ) diff --git a/src/etools/libraries/monitoring/views.py b/src/etools/libraries/monitoring/views.py index 012119501a..44e97673b0 100644 --- a/src/etools/libraries/monitoring/views.py +++ b/src/etools/libraries/monitoring/views.py @@ -1,14 +1,17 @@ - from django.http import HttpResponse from django.views.generic import View from etools.libraries.monitoring.service_checks import CHECKS, ServiceStatus -class CheckView(View): - """ - Basic monitoring checks - """ +class AppAliveView(View): + """Checks the admin url is reachable""" + + def get(self, request): + return HttpResponse('eTools is alive', content_type='text/plain') + + +class AppReadyView(View): def get(self, request): def run_test(test): From 6b69e64bede9e3bcf180f4ca1000249bfc86cfc3 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 21 Mar 2019 12:21:41 -0400 Subject: [PATCH 02/79] clean public --- src/etools/applications/publics/admin.py | 2 +- src/etools/applications/publics/models.py | 58 +--------------- .../applications/publics/synchronizers.py | 8 +-- .../publics/tests/test_dsa_rates.py | 1 - .../publics/tests/test_ghost_data.py | 4 +- .../publics/tests/test_synchronizers.py | 5 +- src/etools/applications/tpm/models.py | 9 ++- src/etools/libraries/djangolib/models.py | 68 +++++++++++++++++-- 8 files changed, 74 insertions(+), 81 deletions(-) diff --git a/src/etools/applications/publics/admin.py b/src/etools/applications/publics/admin.py index fb6512e386..4ebe97aee4 100644 --- a/src/etools/applications/publics/admin.py +++ b/src/etools/applications/publics/admin.py @@ -2,7 +2,7 @@ from django.db.models import ForeignKey, ManyToManyField, OneToOneField from etools.applications.publics import models -from etools.applications.publics.models import EPOCH_ZERO +from etools.libraries.djangolib.models import EPOCH_ZERO class AdminListMixin(object): diff --git a/src/etools/applications/publics/models.py b/src/etools/applications/publics/models.py index a31c27f43f..53a2fe6a1c 100644 --- a/src/etools/applications/publics/models.py +++ b/src/etools/applications/publics/models.py @@ -1,68 +1,14 @@ -from datetime import date, datetime, timedelta +from datetime import date, timedelta from django.contrib.postgres.fields import JSONField from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.db.models import QuerySet -from django.db.models.query_utils import Q from django.db.utils import IntegrityError from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ -from pytz import UTC - -# UTC have to be here to be able to directly compare with the values from the db (orm always returns tz aware values) -EPOCH_ZERO = datetime(1970, 1, 1, tzinfo=UTC) - - -class ValidityQuerySet(QuerySet): - """ - Queryset which overwrites the delete method to support soft delete functionality - By default it filters out all soft deleted instances - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - if self.model: - self.add_intial_q() - - def delete(self): - self.update(deleted_at=now()) - - def add_intial_q(self): - self.query.add_q(Q(deleted_at=EPOCH_ZERO)) - - -class SoftDeleteMixin(models.Model): - """ - This is a mixin to support soft deletion for specific models. This behavior is required to keep everything in the - database but still hide it from the end users. Example: Country changes currency - the old one has to be kept but - hidden (soft deleted) - - The functionality achieved by using the SoftDeleteMixin and the ValidityQuerySet. Both of them are depending on the - `deleted_at` field, which defaults to EPOCH_ZERO to allow unique constrains in the db. - IMPORTANT: Default has to be a value - boolean field or nullable datetime would not work - IMPORTANT #2: This model does not prevent cascaded deletion - this can only happen if the soft deleted model points - to one which actually deletes the entity from the database - """ - - deleted_at = models.DateTimeField(default=EPOCH_ZERO, verbose_name='Deleted At') - - # IMPORTANT: The order of these two queryset is important. The normal queryset has to be defined first to have that - # as a default queryset - admin_objects = QuerySet.as_manager() - objects = ValidityQuerySet.as_manager() - - class Meta: - abstract = True - - def force_delete(self, using=None, keep_parents=False): - return super().delete(using, keep_parents) - - def delete(self, *args, **kwargs): - self.deleted_at = now() - self.save() +from etools.libraries.djangolib.models import SoftDeleteMixin, ValidityQuerySet class TravelAgent(SoftDeleteMixin, models.Model): diff --git a/src/etools/applications/publics/synchronizers.py b/src/etools/applications/publics/synchronizers.py index 5135049ad4..3b63918eba 100644 --- a/src/etools/applications/publics/synchronizers.py +++ b/src/etools/applications/publics/synchronizers.py @@ -4,13 +4,7 @@ from django.core.exceptions import ObjectDoesNotExist -from etools.applications.publics.models import ( - Country, - Currency, - ExchangeRate, - TravelAgent, - TravelExpenseType, -) +from etools.applications.publics.models import Country, Currency, ExchangeRate, TravelAgent, TravelExpenseType from etools.applications.vision.vision_data_synchronizer import VisionDataSynchronizer log = logging.getLogger(__name__) diff --git a/src/etools/applications/publics/tests/test_dsa_rates.py b/src/etools/applications/publics/tests/test_dsa_rates.py index 859826b970..d35b55c071 100644 --- a/src/etools/applications/publics/tests/test_dsa_rates.py +++ b/src/etools/applications/publics/tests/test_dsa_rates.py @@ -1,4 +1,3 @@ - import json from datetime import date, datetime from decimal import Decimal diff --git a/src/etools/applications/publics/tests/test_ghost_data.py b/src/etools/applications/publics/tests/test_ghost_data.py index 129338e7d7..d49fb3b848 100644 --- a/src/etools/applications/publics/tests/test_ghost_data.py +++ b/src/etools/applications/publics/tests/test_ghost_data.py @@ -1,12 +1,12 @@ - import json from django.urls import reverse from etools.applications.EquiTrack.tests.cases import BaseTenantTestCase -from etools.applications.publics.models import EPOCH_ZERO, TravelExpenseType +from etools.applications.publics.models import TravelExpenseType from etools.applications.publics.tests.factories import PublicsAirlineCompanyFactory, PublicsTravelExpenseTypeFactory from etools.applications.users.tests.factories import UserFactory +from etools.libraries.djangolib.models import EPOCH_ZERO class GhostData(BaseTenantTestCase): diff --git a/src/etools/applications/publics/tests/test_synchronizers.py b/src/etools/applications/publics/tests/test_synchronizers.py index 39a596ca75..5e73f4ff31 100644 --- a/src/etools/applications/publics/tests/test_synchronizers.py +++ b/src/etools/applications/publics/tests/test_synchronizers.py @@ -10,10 +10,7 @@ TravelAgent, TravelExpenseType, ) -from etools.applications.publics.tests.factories import ( - PublicsCountryFactory, - TravelAgentFactory, -) +from etools.applications.publics.tests.factories import PublicsCountryFactory, TravelAgentFactory from etools.applications.users.models import Country diff --git a/src/etools/applications/tpm/models.py b/src/etools/applications/tpm/models.py index c34be60ec8..3e689fbc7e 100644 --- a/src/etools/applications/tpm/models.py +++ b/src/etools/applications/tpm/models.py @@ -14,12 +14,9 @@ from unicef_djangolib.fields import CodedGenericRelation from unicef_notification.utils import send_notification_with_template -from etools.applications.EquiTrack.urlresolvers import build_frontend_url from etools.applications.action_points.models import ActionPoint from etools.applications.activities.models import Activity -from etools.libraries.djangolib.utils import get_environment -from etools.libraries.fsm.views import has_action_permission -from etools.applications.publics.models import SoftDeleteMixin +from etools.applications.EquiTrack.urlresolvers import build_frontend_url from etools.applications.tpm.tpmpartners.models import TPMPartner, TPMPartnerStaffMember from etools.applications.tpm.transitions.conditions import ( TPMVisitAssignRequiredFieldsCheck, @@ -31,7 +28,9 @@ TPMVisitCancelSerializer, TPMVisitRejectSerializer, ) -from etools.libraries.djangolib.models import GroupWrapper +from etools.libraries.djangolib.models import GroupWrapper, SoftDeleteMixin +from etools.libraries.djangolib.utils import get_environment +from etools.libraries.fsm.views import has_action_permission class TPMVisit(SoftDeleteMixin, TimeStampedModel, models.Model): diff --git a/src/etools/libraries/djangolib/models.py b/src/etools/libraries/djangolib/models.py index 9e884b5e7e..42539e1168 100644 --- a/src/etools/libraries/djangolib/models.py +++ b/src/etools/libraries/djangolib/models.py @@ -1,9 +1,17 @@ import weakref +from datetime import datetime from django.contrib.auth.models import Group -from django.db.models import Aggregate, CharField, Value +from django.db import models +from django.db.models.query import QuerySet +from django.db.models.query_utils import Q +from django.utils.timezone import now from model_utils.managers import InheritanceManager +from pytz import UTC + +# UTC have to be here to be able to directly compare with the values from the db (orm always returns tz aware values) +EPOCH_ZERO = datetime(1970, 1, 1, tzinfo=UTC) class GroupWrapper(object): @@ -58,7 +66,7 @@ def invalidate_instances(cls): instance.invalidate_cache() -class StringConcat(Aggregate): +class StringConcat(models.Aggregate): """ A custom aggregation function that returns "," separated strings """ function = 'GROUP_CONCAT' @@ -67,9 +75,9 @@ class StringConcat(Aggregate): def __init__(self, expression, separator=",", distinct=False, **extra): super().__init__( expression, - Value(separator), + models.Value(separator), distinct='DISTINCT ' if distinct else '', - output_field=CharField(), + output_field=models.CharField(), **extra ) @@ -78,7 +86,7 @@ def as_postgresql(self, compiler, connection): return super().as_sql(compiler, connection) -class DSum(Aggregate): +class DSum(models.Aggregate): function = 'SUM' template = '%(function)s(DISTINCT %(expressions)s)' name = 'Sum' @@ -98,3 +106,53 @@ def get_subclass(self): return self return manager.get_subclass(pk=self.pk) + + +class ValidityQuerySet(QuerySet): + """ + Queryset which overwrites the delete method to support soft delete functionality + By default it filters out all soft deleted instances + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if self.model: + self.add_intial_q() + + def delete(self): + self.update(deleted_at=now()) + + def add_intial_q(self): + self.query.add_q(Q(deleted_at=EPOCH_ZERO)) + + +class SoftDeleteMixin(models.Model): + """ + This is a mixin to support soft deletion for specific models. This behavior is required to keep everything in the + database but still hide it from the end users. Example: Country changes currency - the old one has to be kept but + hidden (soft deleted) + + The functionality achieved by using the SoftDeleteMixin and the ValidityQuerySet. Both of them are depending on the + `deleted_at` field, which defaults to EPOCH_ZERO to allow unique constrains in the db. + IMPORTANT: Default has to be a value - boolean field or nullable datetime would not work + IMPORTANT #2: This model does not prevent cascaded deletion - this can only happen if the soft deleted model points + to one which actually deletes the entity from the database + """ + + deleted_at = models.DateTimeField(default=EPOCH_ZERO, verbose_name='Deleted At') + + # IMPORTANT: The order of these two queryset is important. The normal queryset has to be defined first to have that + # as a default queryset + admin_objects = QuerySet.as_manager() + objects = ValidityQuerySet.as_manager() + + class Meta: + abstract = True + + def force_delete(self, using=None, keep_parents=False): + return super().delete(using, keep_parents) + + def delete(self, *args, **kwargs): + self.deleted_at = now() + self.save() From b370987a19f4e16523e6b9d705de6b0d4dcde8ef Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Fri, 22 Mar 2019 06:54:39 -0400 Subject: [PATCH 03/79] Activity date now required for Travel Activities --- .../applications/t2f/serializers/travel.py | 1 + .../t2f/tests/test_travel_details.py | 81 +++++++++++++++---- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/etools/applications/t2f/serializers/travel.py b/src/etools/applications/t2f/serializers/travel.py index ba82781d25..004f4e7e8f 100644 --- a/src/etools/applications/t2f/serializers/travel.py +++ b/src/etools/applications/t2f/serializers/travel.py @@ -100,6 +100,7 @@ class TravelActivitySerializer(PermissionBasedModelSerializer): required=False ) action_points = ActionPointBaseSerializer(source='actionpoint_set', many=True, read_only=True, required=False) + date = serializers.DateTimeField(required=True) class Meta: model = TravelActivity diff --git a/src/etools/applications/t2f/tests/test_travel_details.py b/src/etools/applications/t2f/tests/test_travel_details.py index 75a13efac8..05f56534e4 100644 --- a/src/etools/applications/t2f/tests/test_travel_details.py +++ b/src/etools/applications/t2f/tests/test_travel_details.py @@ -268,16 +268,24 @@ def test_activity_location(self): location_2 = LocationFactory() location_3 = LocationFactory() - data = {'activities': [{'is_primary_traveler': True, - 'locations': [location.id, location_2.id]}], - 'traveler': self.traveler.id} + data = { + 'activities': [{ + 'is_primary_traveler': True, + 'locations': [location.id, location_2.id], + 'date': self.travel.start_date, + }], + 'traveler': self.traveler.id, + } response = self.forced_auth_req('post', reverse('t2f:travels:list:index'), data=data, user=self.traveler) response_json = json.loads(response.rendered_content) data = response_json - data['activities'].append({'locations': [location_3.id], - 'is_primary_traveler': True}) + data['activities'].append({ + 'locations': [location_3.id], + 'is_primary_traveler': True, + 'date': self.travel.start_date, + }) response = self.forced_auth_req('patch', reverse('t2f:travels:details:index', kwargs={'travel_pk': response_json['id']}), data=data, user=self.traveler) @@ -295,7 +303,8 @@ def test_activity_results(self): 'is_primary_traveler': True, 'locations': [location.id, location_2.id], 'partner': PartnerFactory(partner_type=PartnerType.GOVERNMENT).id, - 'travel_type': TravelType.PROGRAMME_MONITORING + 'travel_type': TravelType.PROGRAMME_MONITORING, + 'date': self.travel.start_date, }], 'traveler': self.traveler.id } @@ -442,7 +451,7 @@ def test_itinerary_dsa_regions(self): def test_activity_locations(self): data = {'itinerary': [], - 'activities': [{}], + 'activities': [{'date': self.travel.start_date}], 'traveler': self.traveler.id} response = self.forced_auth_req('post', reverse('t2f:travels:list:index'), data=data, user=self.unicef_staff, expected_status_code=None) @@ -467,8 +476,11 @@ def test_reversed_itinerary_order(self): 'departure_date': '2017-01-20T23:00:01.892Z', 'arrival_date': '2017-01-27T23:00:01.905Z', 'mode_of_travel': 'car'}], - 'activities': [{'is_primary_traveler': True, - 'locations': []}], + 'activities': [{ + 'is_primary_traveler': True, + 'locations': [], + 'date': self.travel.start_date, + }], 'action_points': [], 'ta_required': True, 'international_travel': False, @@ -509,7 +521,8 @@ def test_incorrect_itinerary_order(self): 'activities': [ { 'is_primary_traveler': True, - 'locations': [] + 'locations': [], + 'date': self.travel.start_date, } ], 'action_points': [], @@ -525,10 +538,38 @@ def test_incorrect_itinerary_order(self): itinerary_origin_destination_expectation = ['Origin should match with the previous destination'] self.assertEqual(response_json['itinerary'], itinerary_origin_destination_expectation) + def test_activity_date_required(self): + data = {'itinerary': [], + 'activities': [{ + 'is_primary_traveler': True, + 'locations': [], + }], + 'action_points': [], + 'ta_required': False, + 'international_travel': False, + 'traveler': self.traveler.id, + 'mode_of_travel': []} + + # Check only if 200 + response = self.forced_auth_req( + 'post', + reverse('t2f:travels:list:index'), + data=data, + user=self.unicef_staff, + ) + self.assertEqual(response.status_code, 400) + response_json = json.loads(response.rendered_content) + self.assertEqual(response_json, { + 'activities': [{'date': ['This field is required.']}] + }) + def test_ta_not_required(self): data = {'itinerary': [], - 'activities': [{'is_primary_traveler': True, - 'locations': []}], + 'activities': [{ + 'is_primary_traveler': True, + 'locations': [], + 'date': self.travel.start_date, + }], 'action_points': [], 'ta_required': False, 'international_travel': False, @@ -544,8 +585,11 @@ def test_not_primary_traveler(self): primary_traveler = UserFactory() data = {'itinerary': [], - 'activities': [{'is_primary_traveler': False, - 'locations': []}], + 'activities': [{ + 'is_primary_traveler': False, + 'locations': [], + 'date': self.travel.start_date, + }], 'action_points': [], 'ta_required': False, 'international_travel': False, @@ -558,9 +602,12 @@ def test_not_primary_traveler(self): self.assertEqual(response_json, {'activities': [{'primary_traveler': ['This field is required.']}]}) data = {'itinerary': [], - 'activities': [{'is_primary_traveler': False, - 'primary_traveler': primary_traveler.id, - 'locations': []}], + 'activities': [{ + 'is_primary_traveler': False, + 'primary_traveler': primary_traveler.id, + 'locations': [], + 'date': self.travel.start_date, + }], 'action_points': [], 'ta_required': False, 'international_travel': False, From 6174f98e459598d22803ec2f25706d2e7e33cb5b Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 25 Mar 2019 09:48:23 -0400 Subject: [PATCH 04/79] fix sentry 952226340 --- src/etools/applications/audit/conditions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/etools/applications/audit/conditions.py b/src/etools/applications/audit/conditions.py index 945f3cc26a..f4e6455e88 100644 --- a/src/etools/applications/audit/conditions.py +++ b/src/etools/applications/audit/conditions.py @@ -13,7 +13,8 @@ def __init__(self, partner, user): self.user = user def is_satisfied(self): - return self.user.pk in self.partner.staff_members.values_list('user', flat=True) + return self.partner.staff_members.exists() and self.user.pk in self.partner.staff_members.values_list( + 'user', flat=True) class EngagementStaffMemberCondition(SimpleCondition): From 664c9bc989b9c6be70c2996492fac23e219df3b0 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 25 Mar 2019 10:15:40 -0400 Subject: [PATCH 05/79] fix sentry bug 817090414 --- src/etools/applications/hact/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/etools/applications/hact/views.py b/src/etools/applications/hact/views.py index 4dfd251631..5de7241bdc 100644 --- a/src/etools/applications/hact/views.py +++ b/src/etools/applications/hact/views.py @@ -39,7 +39,9 @@ def get_serializer_class(self): def get_renderer_context(self): context = super().get_renderer_context() - data = self.get_queryset().first().partner_values + data = {} + if self.get_queryset().exists(): + data = self.get_queryset().first().partner_values try: data = json.loads(data) except (ValueError, TypeError): From 6027ce0ee6d06ec9a19a928a5fc0c3035ff5f02b Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 25 Mar 2019 11:22:07 -0400 Subject: [PATCH 06/79] cleaning user filtering --- src/etools/applications/users/views_v3.py | 25 +++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/etools/applications/users/views_v3.py b/src/etools/applications/users/views_v3.py index 7d7faf3ed5..ae18273a55 100644 --- a/src/etools/applications/users/views_v3.py +++ b/src/etools/applications/users/views_v3.py @@ -7,6 +7,7 @@ from rest_framework.generics import ListAPIView, RetrieveAPIView from rest_framework.permissions import IsAdminUser from rest_framework.response import Response +from unicef_restlib.views import QueryStringFilterMixin from etools.applications.users import views as v1, views_v2 as v2 from etools.applications.users.serializers_v3 import ( @@ -52,27 +53,24 @@ def retrieve(self, request, pk=None): ) -class UsersListAPIView(ListAPIView): +class UsersListAPIView(QueryStringFilterMixin, ListAPIView): """ Gets a list of Unicef Staff users in the current country. Country is determined by the currently logged in user. """ model = get_user_model() + queryset = get_user_model().objects.all() serializer_class = MinimalUserSerializer permission_classes = (IsAdminUser, ) + filters = ( + ('group', 'groups__name__in'), + ) + def get_queryset(self, pk=None): - user = self.request.user - queryset = self.model.objects.filter( - profile__country=user.profile.country, is_staff=True - ).prefetch_related( - 'profile', - 'groups', - 'user_permissions' - ).order_by('first_name') + # note that if user_ids is set we do not filter by current tenant, I guess this is the expected behavior user_ids = self.request.query_params.get("values", None) - if user_ids: try: user_ids = [int(x) for x in user_ids.split(",")] @@ -84,9 +82,10 @@ def get_queryset(self, pk=None): is_staff=True ).order_by('first_name') - group = self.request.query_params.get("group", None) - if group: - queryset = queryset.filter(groups__name=group) + user = self.request.user + queryset = super().get_queryset().filter( + profile__country=user.profile.country, is_staff=True).prefetch_related( + 'profile', 'groups', 'user_permissions').order_by('first_name') return queryset From 79a48fc6dde60cd99101dde5fa7ba0707582de4a Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 26 Mar 2019 07:47:04 -0400 Subject: [PATCH 07/79] Add results framework endpoint --- Pipfile | 1 + Pipfile.lock | 69 +++++++++++++++--- .../applications/reports/serializers/v2.py | 73 ++++++++++++++++++- .../applications/reports/tests/test_views.py | 41 +++++++++++ src/etools/applications/reports/urls_v2.py | 6 ++ src/etools/applications/reports/views/v2.py | 21 +++++- 6 files changed, 198 insertions(+), 13 deletions(-) diff --git a/Pipfile b/Pipfile index 1177a242a7..3ed9a5ef46 100644 --- a/Pipfile +++ b/Pipfile @@ -127,6 +127,7 @@ unicef_notification = "==0.2.1" unicef_restlib = "==0.4" unicef_snapshot = "==0.2.3" Pillow = "==5.4.1" +unicef-rest-export = "==0.5.3" [requires] python_version = "3.6.4" diff --git a/Pipfile.lock b/Pipfile.lock index 232c21ff97..d9e377e4f1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0e4c7af8c3f8b37f1a571e5a984ac7035fe1b87e940fe3a380cf3c9f5457cbd9" + "sha256": "43ec17c5ccdd1e329b05f448413ef0865170fff6ac42927432acc0ea1bacb355" }, "pipfile-spec": 6, "requires": { @@ -65,6 +65,13 @@ "index": "pypi", "version": "==2.6.0" }, + "backports.csv": { + "hashes": [ + "sha256:1277dfff73130b2e106bf3dd347adb3c5f6c4340882289d88f31240da92cbd6d", + "sha256:21f6e09bab589e6c1f877edbc40277b65e626262a86e69a70137db714eaac5ce" + ], + "version": "==1.0.7" + }, "billiard": { "hashes": [ "sha256:42d9a227401ac4fba892918bba0a0c409def5435c4b483267ebfe821afaaba0e" @@ -570,6 +577,37 @@ "index": "pypi", "version": "==4.4.0" }, + "lxml": { + "hashes": [ + "sha256:0358b9e9642bc7d39aac5cffe9884a99a5ca68e5e2c1b89e570ed60da9139908", + "sha256:091a359c4dafebbecd3959d9013f1b896b5371859165e4e50b01607a98d9e3e2", + "sha256:1998e4e60603c64bcc35af61b4331ab3af087457900d3980e18d190e17c3a697", + "sha256:2000b4088dee9a41f459fddaf6609bba48a435ce6374bb254c5ccdaa8928c5ba", + "sha256:2afb0064780d8aaf165875be5898c1866766e56175714fa5f9d055433e92d41d", + "sha256:2d8f1d9334a4e3ff176d096c14ded3100547d73440683567d85b8842a53180bb", + "sha256:2e38db22f6a3199fd63675e1b4bd795d676d906869047398f29f38ca55cb453a", + "sha256:3181f84649c1a1ca62b19ddf28436b1b2cb05ae6c7d2628f33872e713994c364", + "sha256:37462170dfd88af8431d04de6b236e6e9c06cda71e2ca26d88ef2332fd2a5237", + "sha256:3a9d8521c89bf6f2a929c3d12ad3ad7392c774c327ea809fd08a13be6b3bc05f", + "sha256:3d0bbd2e1a28b4429f24fd63a122a450ce9edb7a8063d070790092d7343a1aa4", + "sha256:483d60585ce3ee71929cea70949059f83850fa5e12deb9c094ed1c8c2ec73cbd", + "sha256:4888be27d5cba55ce94209baef5bcd7bbd7314a3d17021a5fc10000b3a5f737d", + "sha256:64b0d62e4209170a2a0c404c446ab83b941a0003e96604d2e4f4cb735f8a2254", + "sha256:68010900898fdf139ac08549c4dba8206c584070a960ffc530aebf0c6f2794ef", + "sha256:872ecb066de602a0099db98bd9e57f4cfc1d62f6093d94460c787737aa08f39e", + "sha256:88a32b03f2e4cd0e63f154cac76724709f40b3fc2f30139eb5d6f900521b44ed", + "sha256:b1dc7683da4e67ab2bebf266afa68098d681ae02ce570f0d1117312273d2b2ac", + "sha256:b29e27ce9371810250cb1528a771d047a9c7b0f79630dc7dc5815ff828f4273b", + "sha256:ce197559596370d985f1ce6b7051b52126849d8159040293bf8b98cb2b3e1f78", + "sha256:d45cf6daaf22584eff2175f48f82c4aa24d8e72a44913c5aff801819bb73d11f", + "sha256:e2ff9496322b2ce947ba4a7a5eb048158de9d6f3fe9efce29f1e8dd6878561e6", + "sha256:f7b979518ec1f294a41a707c007d54d0f3b3e1fd15d5b26b7e99b62b10d9a72e", + "sha256:f9c7268e9d16e34e50f8246c4f24cf7353764affd2bc971f0379514c246e3f6b", + "sha256:f9c839806089d79de588ee1dde2dae05dc1156d3355dfeb2b51fde84d9c960ad", + "sha256:ff962953e2389226adc4d355e34a98b0b800984399153c6678f2367b11b4d4b8" + ], + "version": "==4.3.2" + }, "markupsafe": { "hashes": [ "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", @@ -793,6 +831,12 @@ "index": "pypi", "version": "==2.5.3" }, + "python-docx": { + "hashes": [ + "sha256:bc76ecac6b2d00ce6442a69d03a6f35c71cd72293cd8405a7472dfe317920024" + ], + "version": "==0.8.10" + }, "python-magic": { "hashes": [ "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375", @@ -1014,6 +1058,13 @@ "index": "pypi", "version": "==0.2.1" }, + "unicef-rest-export": { + "hashes": [ + "sha256:e1eca4d0a053743488d81d18b0a237c0a9a545772647874c86909babbc542c7f" + ], + "index": "pypi", + "version": "==0.5.3" + }, "unicef-restlib": { "hashes": [ "sha256:668c6fdd272a07097123ac0f74f966e91593898a4fc732935c6237b83617e1bd" @@ -1271,11 +1322,11 @@ }, "ipython": { "hashes": [ - "sha256:06de667a9e406924f97781bda22d5d76bfb39762b678762d86a466e63f65dc39", - "sha256:5d3e020a6b5f29df037555e5c45ab1088d6a7cf3bd84f47e0ba501eeb0c3ec82" + "sha256:b038baa489c38f6d853a3cfc4c635b0cda66f2864d136fe8f40c1a6e334e2a6b", + "sha256:f5102c1cd67e399ec8ea66bcebe6e3968ea25a8977e53f012963e5affeb1fe38" ], "index": "pypi", - "version": "==7.3.0" + "version": "==7.4.0" }, "ipython-genutils": { "hashes": [ @@ -1286,11 +1337,11 @@ }, "isort": { "hashes": [ - "sha256:18c796c2cd35eb1a1d3f012a214a542790a1aed95e29768bdcb9f2197eccbd0b", - "sha256:96151fca2c6e736503981896495d344781b60d18bfda78dc11b290c6125ebdb6" + "sha256:08f8e3f0f0b7249e9fad7e5c41e2113aba44969798a26452ee790c06f155d4ec", + "sha256:4e9e9c4bd1acd66cf6c36973f29b031ec752cbfd991c69695e4e259f9a756927" ], "index": "pypi", - "version": "==4.3.15" + "version": "==4.3.16" }, "jedi": { "hashes": [ @@ -1379,10 +1430,10 @@ }, "pdbpp": { "hashes": [ - "sha256:62150302a61b0c45943597258a9685eb976c4750919557724f058b4e33abb8e7" + "sha256:565a4ee4b54bd73310058ce439e245230c587774813e394c902a214c3e693d24" ], "index": "pypi", - "version": "==0.9.13" + "version": "==0.9.14" }, "pexpect": { "hashes": [ diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index ef691f955b..085cbf4e52 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -3,8 +3,9 @@ from rest_framework import serializers from rest_framework.exceptions import ValidationError +from unicef_rest_export.serializers import ExportSerializer -from etools.applications.partners.models import Intervention +from etools.applications.partners.models import Intervention, InterventionResultLink from etools.applications.reports.models import ( AppliedIndicator, Disaggregation, @@ -17,7 +18,7 @@ ResultType, SpecialReportingRequirement, ) -from etools.applications.reports.validators import value_numbers, value_none_or_numbers +from etools.applications.reports.validators import value_none_or_numbers, value_numbers class MinimalOutputListSerializer(serializers.ModelSerializer): @@ -356,3 +357,71 @@ class SpecialReportingRequirementSerializer(serializers.ModelSerializer): class Meta: model = SpecialReportingRequirement fields = "__all__" + + +class ResultFrameworkSerializer(serializers.ModelSerializer): + result = serializers.SerializerMethodField(label=_("Result")) + indicators = serializers.SerializerMethodField() + target = serializers.SerializerMethodField() + baseline = serializers.SerializerMethodField() + means_of_verification = serializers.SerializerMethodField() + locations = serializers.SerializerMethodField() + + class Meta: + model = InterventionResultLink + fields = ( + "result", + "indicators", + "target", + "baseline", + "means_of_verification", + "locations", + ) + + def get_result(self, obj): + return obj.cp_output + + def _applied_indicators(self, obj): + indicators = [] + for l in obj.ll_results.all(): + indicators += l.applied_indicators.all() + return indicators + + def _ram_indicators(self, obj): + return obj.ram_indicators.all() + + def get_indicators(self, obj): + return "\n".join([ + i.name for i in self._ram_indicators(obj) + if i.name + ]) + + def get_target(self, obj): + return "\n".join([ + x.target for x in self._ram_indicators(obj) + if x.target + ]) + + def get_baseline(self, obj): + return "\n".join([ + x.baseline for x in self._ram_indicators(obj) + if x.baseline + ]) + + def get_means_of_verification(self, obj): + return "\n".join( + [ + x.means_of_verification for x in self._applied_indicators(obj) + if x.means_of_verification + ] + ) + + def get_locations(self, obj): + locations = [] + for x in self._applied_indicators(obj): + locations += [l.name for l in x.locations.all()] + return "\n".join(set(locations)) + + +class ResultFrameworkExportSerializer(ExportSerializer): + pass diff --git a/src/etools/applications/reports/tests/test_views.py b/src/etools/applications/reports/tests/test_views.py index 60b374c0ec..ef17bd324e 100644 --- a/src/etools/applications/reports/tests/test_views.py +++ b/src/etools/applications/reports/tests/test_views.py @@ -1072,3 +1072,44 @@ def test_delete(self): self.assertFalse(SpecialReportingRequirement.objects.filter( pk=requirement.pk ).exists()) + + +class TestResultFrameworkView(BaseTenantTestCase): + @classmethod + def setUpTestData(cls): + cls.unicef_staff = UserFactory(is_staff=True) + cls.intervention = InterventionFactory() + cls.result_link = InterventionResultLinkFactory( + intervention=cls.intervention, + ) + cls.lower_result = LowerResultFactory( + result_link=cls.result_link + ) + cls.indicator = IndicatorBlueprintFactory() + cls.applied = AppliedIndicatorFactory( + indicator=cls.indicator, + lower_result=cls.lower_result + ) + + def test_get(self): + response = self.forced_auth_req( + "get", + reverse( + "reports:interventions-results-framework", + args=[self.intervention.pk], + ), + user=self.unicef_staff, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_get_docx_table(self): + response = self.forced_auth_req( + "get", + reverse( + "reports:interventions-results-framework", + args=[self.intervention.pk], + ), + user=self.unicef_staff, + data={"format": "docx_table"}, + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/src/etools/applications/reports/urls_v2.py b/src/etools/applications/reports/urls_v2.py index 1f6b0c6e81..51a5c31f11 100644 --- a/src/etools/applications/reports/urls_v2.py +++ b/src/etools/applications/reports/urls_v2.py @@ -13,6 +13,7 @@ LowerResultsListAPIView, OutputDetailAPIView, OutputListAPIView, + ResultFrameworkView, ResultIndicatorListAPIView, SpecialReportingRequirementListCreateView, SpecialReportingRequirementRetrieveUpdateDestroyView, @@ -61,5 +62,10 @@ view=SpecialReportingRequirementRetrieveUpdateDestroyView.as_view(), name="interventions-special-reporting-requirements-update", ), + url( + r'interventions/results/(?P\d+)/$', + view=ResultFrameworkView.as_view(), + name="interventions-results-framework", + ), url(r'^', include(api.urls)) ) diff --git a/src/etools/applications/reports/views/v2.py b/src/etools/applications/reports/views/v2.py index 9f6761c7bd..d2ea539125 100644 --- a/src/etools/applications/reports/views/v2.py +++ b/src/etools/applications/reports/views/v2.py @@ -20,22 +20,25 @@ from rest_framework.permissions import IsAdminUser from rest_framework.response import Response from rest_framework_csv.renderers import CSVRenderer, JSONRenderer +from unicef_rest_export.views import ExportView from unicef_restlib.views import QueryStringFilterMixin from etools.applications.EquiTrack.mixins import ExportModelMixin from etools.applications.EquiTrack.renderers import CSVFlatRenderer from etools.applications.partners.filters import PartnerScopeFilter -from etools.applications.partners.models import Intervention +from etools.applications.partners.models import Intervention, InterventionResultLink from etools.applications.partners.permissions import PartnershipManagerPermission, PartnershipManagerRepPermission from etools.applications.reports.models import ( AppliedIndicator, CountryProgramme, Disaggregation, Indicator, + IndicatorBlueprint, LowerResult, Result, + ResultType, SpecialReportingRequirement, - ResultType, IndicatorBlueprint) +) from etools.applications.reports.permissions import PMEPermission from etools.applications.reports.serializers.exports import ( AppliedIndicatorExportFlatSerializer, @@ -51,6 +54,8 @@ LowerResultSerializer, MinimalOutputListSerializer, OutputListSerializer, + ResultFrameworkExportSerializer, + ResultFrameworkSerializer, SpecialReportingRequirementSerializer, ) @@ -450,3 +455,15 @@ def destroy(self, request, *args, **kwargs): _("Cannot delete special reporting requirements in the past.") ) return super().destroy(request, *args, **kwargs) + + +class ResultFrameworkView(ExportView): + serializer_class = ResultFrameworkSerializer + export_serializer_class = ResultFrameworkExportSerializer + permission_classes = (PartnershipManagerPermission, ) + + def get_queryset(self, format=None): + qs = InterventionResultLink.objects.filter( + intervention=self.kwargs.get("pk") + ) + return qs From e5b69dde220e56617f0c22cc411fbab83915c708 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 26 Mar 2019 09:30:01 -0400 Subject: [PATCH 08/79] Convert start/end date fields to DateFields --- .../t2f/migrations/0015_auto_20190326_1326.py | 23 +++++++++++++++++++ src/etools/applications/t2f/models.py | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py diff --git a/src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py b/src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py new file mode 100644 index 0000000000..d3c1507694 --- /dev/null +++ b/src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py @@ -0,0 +1,23 @@ +# Generated by Django 2.1.7 on 2019-03-26 13:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('t2f', '0014_auto_20190123_2101'), + ] + + operations = [ + migrations.AlterField( + model_name='travel', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='End Date'), + ), + migrations.AlterField( + model_name='travel', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Start Date'), + ), + ] diff --git a/src/etools/applications/t2f/models.py b/src/etools/applications/t2f/models.py index 6bb7f8d5c2..0dc79cbcb9 100644 --- a/src/etools/applications/t2f/models.py +++ b/src/etools/applications/t2f/models.py @@ -140,8 +140,8 @@ class Travel(models.Model): 'reports.Sector', null=True, blank=True, related_name='+', verbose_name=_('Section'), on_delete=models.CASCADE, ) - start_date = models.DateTimeField(null=True, blank=True, verbose_name=_('Start Date')) - end_date = models.DateTimeField(null=True, blank=True, verbose_name=_('End Date')) + start_date = models.DateField(null=True, blank=True, verbose_name=_('Start Date')) + end_date = models.DateField(null=True, blank=True, verbose_name=_('End Date')) purpose = models.CharField(max_length=500, default='', blank=True, verbose_name=_('Purpose')) additional_note = models.TextField(default='', blank=True, verbose_name=_('Additional Note')) international_travel = models.NullBooleanField(default=False, null=True, blank=True, From 00647b831b4aef2886f0c2818ba8f80d2a759ef0 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 26 Mar 2019 10:29:16 -0400 Subject: [PATCH 09/79] remove file --- src/etools/applications/tokens/utils.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/etools/applications/tokens/utils.py diff --git a/src/etools/applications/tokens/utils.py b/src/etools/applications/tokens/utils.py deleted file mode 100644 index e69de29bb2..0000000000 From da47aaf7609fcd7891b3d6327bd9ed4cb56a50d5 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 26 Mar 2019 11:34:41 -0400 Subject: [PATCH 10/79] Update more date fields from datetime Cleaned up tests --- .../t2f/migrations/0015_auto_20190326_1326.py | 23 ----- .../t2f/migrations/0015_auto_20190326_1425.py | 38 ++++++++ src/etools/applications/t2f/models.py | 14 +-- .../applications/t2f/serializers/export.py | 8 +- .../applications/t2f/serializers/mailing.py | 4 +- .../applications/t2f/serializers/travel.py | 12 +-- .../applications/t2f/tests/factories.py | 40 ++++---- .../applications/t2f/tests/test_dashboard.py | 9 +- .../applications/t2f/tests/test_exports.py | 68 +++++++------- .../t2f/tests/test_overlapping_trips.py | 92 ++++++++++--------- .../t2f/tests/test_permission_matrix.py | 14 +-- .../t2f/tests/test_state_machine.py | 34 +++---- .../t2f/tests/test_travel_details.py | 60 ++++++------ 13 files changed, 215 insertions(+), 201 deletions(-) delete mode 100644 src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py create mode 100644 src/etools/applications/t2f/migrations/0015_auto_20190326_1425.py diff --git a/src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py b/src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py deleted file mode 100644 index d3c1507694..0000000000 --- a/src/etools/applications/t2f/migrations/0015_auto_20190326_1326.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.1.7 on 2019-03-26 13:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('t2f', '0014_auto_20190123_2101'), - ] - - operations = [ - migrations.AlterField( - model_name='travel', - name='end_date', - field=models.DateField(blank=True, null=True, verbose_name='End Date'), - ), - migrations.AlterField( - model_name='travel', - name='start_date', - field=models.DateField(blank=True, null=True, verbose_name='Start Date'), - ), - ] diff --git a/src/etools/applications/t2f/migrations/0015_auto_20190326_1425.py b/src/etools/applications/t2f/migrations/0015_auto_20190326_1425.py new file mode 100644 index 0000000000..6c4a160ae4 --- /dev/null +++ b/src/etools/applications/t2f/migrations/0015_auto_20190326_1425.py @@ -0,0 +1,38 @@ +# Generated by Django 2.1.7 on 2019-03-26 14:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('t2f', '0014_auto_20190123_2101'), + ] + + operations = [ + migrations.AlterField( + model_name='itineraryitem', + name='arrival_date', + field=models.DateField(verbose_name='Arrival Date'), + ), + migrations.AlterField( + model_name='itineraryitem', + name='departure_date', + field=models.DateField(verbose_name='Departure Date'), + ), + migrations.AlterField( + model_name='travel', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='End Date'), + ), + migrations.AlterField( + model_name='travel', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='Start Date'), + ), + migrations.AlterField( + model_name='travelactivity', + name='date', + field=models.DateField(blank=True, null=True, verbose_name='Date'), + ), + ] diff --git a/src/etools/applications/t2f/models.py b/src/etools/applications/t2f/models.py index 0dc79cbcb9..be4f22a04e 100644 --- a/src/etools/applications/t2f/models.py +++ b/src/etools/applications/t2f/models.py @@ -182,17 +182,17 @@ def check_trip_report(self): def check_trip_dates(self): if self.start_date and self.end_date: - start_date = self.start_date.date() - end_date = self.end_date.date() + start_date = self.start_date + end_date = self.end_date travel_q = Q(traveler=self.traveler) travel_q &= ~Q(status__in=[Travel.PLANNED, Travel.CANCELLED]) travel_q &= Q( - start_date__date__range=( + start_date__range=( start_date, end_date - datetime.timedelta(days=1), ) ) | Q( - end_date__date__range=( + end_date__range=( start_date + datetime.timedelta(days=1), end_date, ) @@ -345,7 +345,7 @@ class TravelActivity(models.Model): locations = models.ManyToManyField('locations.Location', related_name='+', verbose_name=_('Locations')) primary_traveler = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('Primary Traveler'), on_delete=models.CASCADE) - date = models.DateTimeField(null=True, blank=True, verbose_name=_('Date')) + date = models.DateField(null=True, blank=True, verbose_name=_('Date')) class Meta: verbose_name_plural = _("Travel Activities") @@ -393,8 +393,8 @@ class ItineraryItem(models.Model): ) origin = models.CharField(max_length=255, verbose_name=_('Origin')) destination = models.CharField(max_length=255, verbose_name=_('Destination')) - departure_date = models.DateTimeField(verbose_name=_('Departure Date')) - arrival_date = models.DateTimeField(verbose_name=_('Arrival Date')) + departure_date = models.DateField(verbose_name=_('Departure Date')) + arrival_date = models.DateField(verbose_name=_('Arrival Date')) dsa_region = models.ForeignKey( 'publics.DSARegion', related_name='+', null=True, blank=True, verbose_name=_('DSA Region'), diff --git a/src/etools/applications/t2f/serializers/export.py b/src/etools/applications/t2f/serializers/export.py index 57eafbb88a..c638cfdcd1 100644 --- a/src/etools/applications/t2f/serializers/export.py +++ b/src/etools/applications/t2f/serializers/export.py @@ -18,8 +18,8 @@ class TravelActivityExportSerializer(serializers.Serializer): pd_reference = serializers.ReadOnlyField(source='activity.partnership.number', read_only=True) results = serializers.CharField(source='activity.result.name', read_only=True) locations = serializers.SerializerMethodField() - start_date = serializers.DateTimeField(source='travel.start_date', format='%d-%b-%Y', read_only=True) - end_date = serializers.DateTimeField(source='travel.end_date', format='%d-%b-%Y', read_only=True) + start_date = serializers.DateField(source='travel.start_date', format='%d-%b-%Y', read_only=True) + end_date = serializers.DateField(source='travel.end_date', format='%d-%b-%Y', read_only=True) is_secondary_traveler = serializers.SerializerMethodField() primary_traveler_name = serializers.SerializerMethodField() hact_visit_report = serializers.SerializerMethodField( @@ -78,8 +78,8 @@ class TravelAdminExportSerializer(serializers.Serializer): status = serializers.CharField(source='travel.status', read_only=True) origin = serializers.CharField() destination = serializers.CharField() - departure_time = serializers.DateTimeField(source='departure_date', format='%d-%b-%Y %I:%M %p') - arrival_time = serializers.DateTimeField(source='arrival_date', format='%d-%b-%Y %I:%M %p') + departure_time = serializers.DateField(source='departure_date', format='%d-%b-%Y') + arrival_time = serializers.DateField(source='arrival_date', format='%d-%b-%Y') dsa_area = serializers.CharField(source='dsa_region.area_code', read_only=True) overnight_travel = serializers.BooleanField() mode_of_travel = serializers.CharField() diff --git a/src/etools/applications/t2f/serializers/mailing.py b/src/etools/applications/t2f/serializers/mailing.py index 2f4a8a24e5..b5634c694b 100644 --- a/src/etools/applications/t2f/serializers/mailing.py +++ b/src/etools/applications/t2f/serializers/mailing.py @@ -5,8 +5,8 @@ class TravelMailSerializer(serializers.Serializer): estimated_travel_cost = serializers.DecimalField(max_digits=18, decimal_places=2, required=False) supervisor = serializers.CharField(source='supervisor.get_full_name', read_only=True) traveler = serializers.CharField(source='traveler.get_full_name', read_only=True) - start_date = serializers.DateTimeField(format='%m/%d/%Y') - end_date = serializers.DateTimeField(format='%m/%d/%Y') + start_date = serializers.DateField(format='%m/%d/%Y') + end_date = serializers.DateField(format='%m/%d/%Y') currency = serializers.CharField(source='currency.code', read_only=True) location = serializers.CharField(source='itinerary.first.destination', read_only=True) reference_number = serializers.CharField() diff --git a/src/etools/applications/t2f/serializers/travel.py b/src/etools/applications/t2f/serializers/travel.py index ba82781d25..a8a1087224 100644 --- a/src/etools/applications/t2f/serializers/travel.py +++ b/src/etools/applications/t2f/serializers/travel.py @@ -220,14 +220,14 @@ def validate(self, attrs): travel_q = Q(traveler=traveler) travel_q &= ~Q(status__in=[Travel.PLANNED, Travel.CANCELLED]) travel_q &= Q( - start_date__date__range=( - start_date.date(), - end_date.date() - datetime.timedelta(days=1), + start_date__range=( + start_date, + end_date - datetime.timedelta(days=1), ) ) | Q( - end_date__date__range=( - start_date.date() + datetime.timedelta(days=1), - end_date.date(), + end_date__range=( + start_date + datetime.timedelta(days=1), + end_date, ) ) diff --git a/src/etools/applications/t2f/tests/factories.py b/src/etools/applications/t2f/tests/factories.py index 60732a25e5..057bbe36c0 100644 --- a/src/etools/applications/t2f/tests/factories.py +++ b/src/etools/applications/t2f/tests/factories.py @@ -1,5 +1,4 @@ -from django.utils import timezone - +import datetime import factory from factory import fuzzy from unicef_locations.tests.factories import LocationFactory @@ -15,14 +14,9 @@ from etools.applications.t2f import models from etools.applications.users.tests.factories import OfficeFactory, UserFactory -_FUZZY_START_DATE = timezone.datetime(timezone.now().year, 1, 1, tzinfo=timezone.now().tzinfo) -_FUZZY_END_DATE = timezone.datetime(timezone.now().year, 12, 31, tzinfo=timezone.now().tzinfo) -_FUZZY_NOW_DATE = timezone.datetime( - timezone.now().year, - timezone.now().month, - timezone.now().day, - tzinfo=timezone.now().tzinfo -) +_FUZZY_START_DATE = datetime.date(datetime.date.today().year, 1, 1) +_FUZZY_END_DATE = datetime.date(datetime.date.today().year, 12, 31) +_FUZZY_NOW_DATE = datetime.date.today() class FuzzyTravelType(factory.fuzzy.BaseFuzzyAttribute): @@ -38,7 +32,7 @@ class TravelActivityFactory(factory.django.DjangoModelFactory): partnership = factory.SubFactory(InterventionFactory) result = factory.SubFactory(ResultFactory) primary_traveler = factory.SubFactory(UserFactory) - date = factory.LazyAttribute(lambda o: timezone.now()) + date = factory.LazyAttribute(lambda o: datetime.date.today()) class Meta: model = models.TravelActivity @@ -61,13 +55,13 @@ def travels(self, create, extracted, **kwargs): class ItineraryItemFactory(factory.DjangoModelFactory): origin = fuzzy.FuzzyText(length=32) destination = fuzzy.FuzzyText(length=32) - departure_date = fuzzy.FuzzyDateTime( - start_dt=_FUZZY_START_DATE, - end_dt=_FUZZY_NOW_DATE, + departure_date = fuzzy.FuzzyDate( + start_date=_FUZZY_START_DATE, + end_date=_FUZZY_NOW_DATE, ) - arrival_date = fuzzy.FuzzyDateTime( - start_dt=_FUZZY_NOW_DATE, - end_dt=_FUZZY_END_DATE, + arrival_date = fuzzy.FuzzyDate( + start_date=_FUZZY_NOW_DATE, + end_date=_FUZZY_END_DATE, ) dsa_region = factory.SubFactory(PublicsDSARegionFactory) overnight_travel = False @@ -87,13 +81,13 @@ class TravelFactory(factory.DjangoModelFactory): supervisor = factory.SubFactory(UserFactory) office = factory.SubFactory(OfficeFactory) section = factory.SubFactory(SectionFactory) - start_date = fuzzy.FuzzyDateTime( - start_dt=_FUZZY_START_DATE, - end_dt=_FUZZY_NOW_DATE, + start_date = fuzzy.FuzzyDate( + start_date=_FUZZY_START_DATE, + end_date=_FUZZY_NOW_DATE, ) - end_date = fuzzy.FuzzyDateTime( - start_dt=_FUZZY_NOW_DATE, - end_dt=_FUZZY_END_DATE, + end_date = fuzzy.FuzzyDate( + start_date=_FUZZY_NOW_DATE, + end_date=_FUZZY_END_DATE, ) purpose = factory.Sequence(lambda n: 'Purpose #{}'.format(n)) international_travel = False diff --git a/src/etools/applications/t2f/tests/test_dashboard.py b/src/etools/applications/t2f/tests/test_dashboard.py index 78ce670796..19e43b88b8 100644 --- a/src/etools/applications/t2f/tests/test_dashboard.py +++ b/src/etools/applications/t2f/tests/test_dashboard.py @@ -1,4 +1,3 @@ - import json from django.urls import reverse @@ -76,16 +75,16 @@ def test_completed_counts(self): supervisor=self.unicef_staff) data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, diff --git a/src/etools/applications/t2f/tests/test_exports.py b/src/etools/applications/t2f/tests/test_exports.py index 45bc080727..913a870d70 100644 --- a/src/etools/applications/t2f/tests/test_exports.py +++ b/src/etools/applications/t2f/tests/test_exports.py @@ -1,6 +1,6 @@ import csv import logging -from datetime import datetime +import datetime from django.urls import reverse from django.utils import timezone @@ -92,16 +92,16 @@ def test_activity_export(self): office=office, supervisor=supervisor, section=section_health, - start_date=datetime(2017, 11, 8, tzinfo=tz), - end_date=datetime(2017, 11, 14, tzinfo=tz), + start_date=datetime.date(2017, 11, 8), + end_date=datetime.date(2017, 11, 14), ) travel_2 = TravelFactory(reference_number='2016/1211', supervisor=supervisor, traveler=user_alice_carter, office=office, section=section_education, - start_date=datetime(2017, 11, 8, tzinfo=tz), - end_date=datetime(2017, 11, 14, tzinfo=tz), + start_date=datetime.date(2017, 11, 8), + end_date=datetime.date(2017, 11, 14), ) # Do some cleanup @@ -109,7 +109,7 @@ def test_activity_export(self): # Create the activities finally activity_1 = TravelActivityFactory(travel_type=TravelType.PROGRAMME_MONITORING, - date=datetime( + date=datetime.datetime( 2016, 12, 3, tzinfo=UTC), result=result_A11, primary_traveler=user_joe_smith) @@ -120,7 +120,7 @@ def test_activity_export(self): activity_1.save() activity_2 = TravelActivityFactory(travel_type=TravelType.PROGRAMME_MONITORING, - date=datetime( + date=datetime.datetime( 2016, 12, 4, tzinfo=UTC), result=result_A21, primary_traveler=user_lenox_lewis) @@ -131,7 +131,7 @@ def test_activity_export(self): activity_2.save() activity_3 = TravelActivityFactory(travel_type=TravelType.MEETING, - date=datetime( + date=datetime.datetime( 2016, 12, 3, tzinfo=UTC), result=None, primary_traveler=user_joe_smith) @@ -142,7 +142,7 @@ def test_activity_export(self): activity_3.save() activity_4 = TravelActivityFactory(travel_type=TravelType.SPOT_CHECK, - date=datetime( + date=datetime.datetime( 2016, 12, 6, tzinfo=UTC), result=None, primary_traveler=user_alice_carter) @@ -282,9 +282,9 @@ def test_travel_admin_export(self): itinerary_item_1 = ItineraryItemFactory(travel=travel_1, origin='Origin1', destination='Origin2', - departure_date=datetime( + departure_date=datetime.datetime( 2016, 12, 3, 11, tzinfo=UTC), - arrival_date=datetime( + arrival_date=datetime.datetime( 2016, 12, 3, 12, tzinfo=UTC), mode_of_travel=ModeOfTravel.CAR, dsa_region=dsa_brd) @@ -293,9 +293,9 @@ def test_travel_admin_export(self): itinerary_item_2 = ItineraryItemFactory(travel=travel_1, origin='Origin2', destination='Origin3', - departure_date=datetime( + departure_date=datetime.datetime( 2016, 12, 5, 11, tzinfo=UTC), - arrival_date=datetime( + arrival_date=datetime.datetime( 2016, 12, 5, 12, tzinfo=UTC), mode_of_travel=ModeOfTravel.PLANE, dsa_region=dsa_lan) @@ -305,9 +305,9 @@ def test_travel_admin_export(self): itinerary_item_3 = ItineraryItemFactory(travel=travel_1, origin='Origin3', destination='Origin1', - departure_date=datetime( + departure_date=datetime.datetime( 2016, 12, 6, 11, tzinfo=UTC), - arrival_date=datetime( + arrival_date=datetime.datetime( 2016, 12, 6, 12, tzinfo=UTC), mode_of_travel=ModeOfTravel.PLANE, dsa_region=None) @@ -324,9 +324,9 @@ def test_travel_admin_export(self): itinerary_item_4 = ItineraryItemFactory(travel=travel_2, origin='Origin2', destination='Origin1', - departure_date=datetime( + departure_date=datetime.datetime( 2016, 12, 5, 11, tzinfo=UTC), - arrival_date=datetime( + arrival_date=datetime.datetime( 2016, 12, 5, 12, tzinfo=UTC), mode_of_travel=ModeOfTravel.PLANE, dsa_region=dsa_lan) @@ -336,9 +336,9 @@ def test_travel_admin_export(self): itinerary_item_5 = ItineraryItemFactory(travel=travel_2, origin='Origin3', destination='Origin1', - departure_date=datetime( + departure_date=datetime.datetime( 2016, 12, 6, 11, tzinfo=UTC), - arrival_date=datetime( + arrival_date=datetime.datetime( 2016, 12, 6, 12, tzinfo=UTC), mode_of_travel=ModeOfTravel.CAR, dsa_region=None) @@ -370,75 +370,75 @@ def test_travel_admin_export(self): 'airline']) self.assertEqual(rows[1], - ['{}/1'.format(datetime.now().year), + ['{}/1'.format(datetime.datetime.now().year), 'John Doe', 'An Office', travel_1.section.name, 'planned', 'Origin1', 'Origin2', - '03-Dec-2016 11:00 AM', - '03-Dec-2016 12:00 PM', + '03-Dec-2016', + '03-Dec-2016', 'BRD', '', 'Car', '']) self.assertEqual(rows[2], - ['{}/1'.format(datetime.now().year), + ['{}/1'.format(datetime.datetime.now().year), 'John Doe', 'An Office', travel_1.section.name, 'planned', 'Origin2', 'Origin3', - '05-Dec-2016 11:00 AM', - '05-Dec-2016 12:00 PM', + '05-Dec-2016', + '05-Dec-2016', 'LAN', '', 'Plane', 'JetStar']) self.assertEqual(rows[3], - ['{}/1'.format(datetime.now().year), + ['{}/1'.format(datetime.datetime.now().year), 'John Doe', 'An Office', travel_1.section.name, 'planned', 'Origin3', 'Origin1', - '06-Dec-2016 11:00 AM', - '06-Dec-2016 12:00 PM', + '06-Dec-2016', + '06-Dec-2016', 'NODSA', '', 'Plane', 'SpiceAir']) self.assertEqual(rows[4], - ['{}/2'.format(datetime.now().year), + ['{}/2'.format(datetime.datetime.now().year), 'Max Mustermann', 'An Office', travel_2.section.name, 'planned', 'Origin2', 'Origin1', - '05-Dec-2016 11:00 AM', - '05-Dec-2016 12:00 PM', + '05-Dec-2016', + '05-Dec-2016', 'LAN', '', 'Plane', 'JetStar']) self.assertEqual(rows[5], - ['{}/2'.format(datetime.now().year), + ['{}/2'.format(datetime.datetime.now().year), 'Max Mustermann', 'An Office', travel_2.section.name, 'planned', 'Origin3', 'Origin1', - '06-Dec-2016 11:00 AM', - '06-Dec-2016 12:00 PM', + '06-Dec-2016', + '06-Dec-2016', 'NODSA', '', 'Car', diff --git a/src/etools/applications/t2f/tests/test_overlapping_trips.py b/src/etools/applications/t2f/tests/test_overlapping_trips.py index 8fd6ff995b..a6c1d382cf 100644 --- a/src/etools/applications/t2f/tests/test_overlapping_trips.py +++ b/src/etools/applications/t2f/tests/test_overlapping_trips.py @@ -39,8 +39,8 @@ def setUpTestData(cls): cls.travel = TravelFactory(reference_number=make_travel_reference_number(), traveler=cls.traveler, supervisor=cls.unicef_staff, - start_date=datetime.datetime(2017, 4, 4, 12, 00, tzinfo=UTC), - end_date=datetime.datetime(2017, 4, 14, 16, 00, tzinfo=UTC)) + start_date=datetime.date(2017, 4, 4), + end_date=datetime.date(2017, 4, 14)) ItineraryItemFactory(travel=cls.travel) ItineraryItemFactory(travel=cls.travel) cls.travel.submit_for_approval() @@ -53,16 +53,16 @@ def test_overlapping_trips(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-07T17:06:55.821490', - 'arrival_date': '2017-04-08T17:06:55.821490', + 'departure_date': '2017-04-07', + 'arrival_date': '2017-04-08', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -73,8 +73,8 @@ def test_overlapping_trips(self): 'mode_of_travel': [ModeOfTravel.BOAT], 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, - 'start_date': '2017-04-07T15:02:13+01:00', - 'end_date': '2017-05-22T15:02:13+01:00', + 'start_date': '2017-04-07', + 'end_date': '2017-05-22', 'currency': currency.id, 'purpose': 'Purpose', 'additional_note': 'Notes'} @@ -102,16 +102,16 @@ def test_almost_overlapping_trips(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -122,8 +122,8 @@ def test_almost_overlapping_trips(self): 'mode_of_travel': [ModeOfTravel.BOAT], 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, - 'start_date': '2017-04-14T16:05:00+00:00', - 'end_date': '2017-05-22T15:02:13+00:00', + 'start_date': '2017-04-14', + 'end_date': '2017-05-22', 'currency': currency.id, 'purpose': 'Purpose', 'additional_note': 'Notes'} @@ -147,16 +147,16 @@ def test_edit_to_overlap(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -167,8 +167,8 @@ def test_edit_to_overlap(self): 'mode_of_travel': [ModeOfTravel.BOAT], 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, - 'start_date': '2017-04-14T16:05:00+00:00', - 'end_date': '2017-05-22T15:02:13+00:00', + 'start_date': '2017-04-14', + 'end_date': '2017-05-22', 'currency': currency.id, 'purpose': 'Purpose', 'additional_note': 'Notes'} @@ -195,8 +195,8 @@ def test_edit_to_overlap(self): { 'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-10T16:05:00+00:00', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-10', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -205,8 +205,8 @@ def test_edit_to_overlap(self): { 'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -226,27 +226,33 @@ def test_edit_to_overlap(self): def test_daylight_saving(self): budapest_tz = pytz.timezone('Europe/Budapest') - self.travel.end_date = budapest_tz.localize(datetime.datetime(2017, 10, 29, 2, 0), is_dst=True) + self.travel.end_date = budapest_tz.localize( + datetime.datetime(2017, 10, 29, 2, 0), + is_dst=True + ).date() self.travel.save() # Same date as the previous, but it's already after daylight saving - start_date = budapest_tz.localize(datetime.datetime(2017, 10, 29, 2, 0), is_dst=False).isoformat() + start_date = budapest_tz.localize( + datetime.datetime(2017, 10, 29, 2, 0), + is_dst=False + ).isoformat()[:10] currency = PublicsCurrencyFactory() dsa_region = PublicsDSARegionFactory() data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -258,7 +264,7 @@ def test_daylight_saving(self): 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, 'start_date': start_date, - 'end_date': '2017-05-22T15:02:13+00:00', + 'end_date': '2017-05-22', 'currency': currency.id, 'purpose': 'Purpose', 'additional_note': 'Notes'} @@ -275,16 +281,16 @@ def test_start_end_match(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-20T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-20', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -295,8 +301,8 @@ def test_start_end_match(self): 'mode_of_travel': [ModeOfTravel.BOAT], 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, - 'start_date': '2017-04-14T15:06:55+01:00', - 'end_date': '2017-05-22T15:02:13+01:00', + 'start_date': '2017-04-14', + 'end_date': '2017-05-22', 'currency': currency.id, 'purpose': 'Purpose', 'additional_note': 'Notes'} @@ -333,16 +339,16 @@ def test_end_start_match(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-03-14T17:06:55.821490', - 'arrival_date': '2017-03-20T17:06:55.821490', + 'departure_date': '2017-03-14', + 'arrival_date': '2017-03-20', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-03-25T12:06:55.821490', - 'arrival_date': '2017-04-04T12:06:55.821490', + 'departure_date': '2017-03-25', + 'arrival_date': '2017-04-04', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -353,8 +359,8 @@ def test_end_start_match(self): 'mode_of_travel': [ModeOfTravel.BOAT], 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, - 'start_date': '2017-03-14T15:06:55+01:00', - 'end_date': '2017-04-04T15:02:13+01:00', + 'start_date': '2017-03-14', + 'end_date': '2017-04-04', 'currency': currency.id, 'purpose': 'Purpose', 'additional_note': 'Notes'} diff --git a/src/etools/applications/t2f/tests/test_permission_matrix.py b/src/etools/applications/t2f/tests/test_permission_matrix.py index a1b444aa97..2da18528d1 100644 --- a/src/etools/applications/t2f/tests/test_permission_matrix.py +++ b/src/etools/applications/t2f/tests/test_permission_matrix.py @@ -174,16 +174,16 @@ def test_travel_creation(self): 'no_dsa': False}], 'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -191,14 +191,14 @@ def test_travel_creation(self): 'activities': [{'is_primary_traveler': True, 'locations': [location.id], 'travel_type': TravelType.ADVOCACY, - 'date': '2016-12-15T15:02:13+01:00'}], + 'date': '2016-12-15'}], 'ta_required': True, 'international_travel': False, 'mode_of_travel': [ModeOfTravel.BOAT], 'traveler': self.traveler.id, 'supervisor': self.unicef_staff.id, - 'start_date': '2016-12-15T15:02:13+01:00', - 'end_date': '2016-12-16T15:02:13+01:00', + 'start_date': '2016-12-15', + 'end_date': '2016-12-16', 'estimated_travel_cost': '123', 'currency': currency.id, 'purpose': purpose, diff --git a/src/etools/applications/t2f/tests/test_state_machine.py b/src/etools/applications/t2f/tests/test_state_machine.py index 9b8a2bcb6d..1c6efa02b0 100644 --- a/src/etools/applications/t2f/tests/test_state_machine.py +++ b/src/etools/applications/t2f/tests/test_state_machine.py @@ -1,6 +1,6 @@ +import datetime import json from collections import defaultdict -from datetime import datetime, timedelta from unittest.mock import Mock, patch from django.conf import settings @@ -67,16 +67,16 @@ def test_state_machine_flow(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -145,16 +145,16 @@ def test_state_machine_flow2(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -222,9 +222,9 @@ def test_ta_not_required_flow_instant_complete(self): data = {'traveler': self.traveler.id, 'ta_required': False, 'international_travel': False, - 'start_date': datetime.utcnow(), + 'start_date': datetime.date.today(), 'report': 'something', - 'end_date': datetime.utcnow() + timedelta(hours=10), + 'end_date': datetime.date.today() + datetime.timedelta(days=1), 'supervisor': self.unicef_staff.id} response = self.forced_auth_req('post', reverse('t2f:travels:list:state_change', kwargs={'transition_name': Travel.COMPLETE}), @@ -240,8 +240,8 @@ def test_ta_not_required_flow_send_for_approval(self): 'ta_required': False, 'international_travel': False, 'report': 'something', - 'start_date': datetime.utcnow(), - 'end_date': datetime.utcnow() + timedelta(hours=10), + 'start_date': datetime.date.today(), + 'end_date': datetime.date.today() + datetime.timedelta(days=1), 'supervisor': self.unicef_staff.id} response = self.forced_auth_req('post', reverse('t2f:travels:list:state_change', kwargs={'transition_name': 'save_and_submit'}), @@ -319,16 +319,16 @@ def test_expense_required_on_send_for_payment(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2017-04-14T17:06:55.821490', - 'arrival_date': '2017-04-15T17:06:55.821490', + 'departure_date': '2017-04-14', + 'arrival_date': '2017-04-15', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': []}, {'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2017-05-20T12:06:55.821490', - 'arrival_date': '2017-05-21T12:06:55.821490', + 'departure_date': '2017-05-20', + 'arrival_date': '2017-05-21', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, diff --git a/src/etools/applications/t2f/tests/test_travel_details.py b/src/etools/applications/t2f/tests/test_travel_details.py index 75a13efac8..e3a1c443ee 100644 --- a/src/etools/applications/t2f/tests/test_travel_details.py +++ b/src/etools/applications/t2f/tests/test_travel_details.py @@ -241,8 +241,8 @@ def test_airlines(self): data = {'itinerary': [{'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.PLANE, @@ -312,16 +312,16 @@ def test_itinerary_dates(self): data = {'itinerary': [{'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': [airlines.id]}, {'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2016-11-15T12:06:55.821490', - 'arrival_date': '2016-11-16T12:06:55.821490', + 'departure_date': '2016-11-15', + 'arrival_date': '2016-11-16', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -353,16 +353,16 @@ def test_itinerary_origin_destination(self): data = {'itinerary': [{'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2016-11-15T12:06:55.821490', - 'arrival_date': '2016-11-16T12:06:55.821490', + 'departure_date': '2016-11-15', + 'arrival_date': '2016-11-16', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': [airlines.id]}, {'origin': 'Something else', 'destination': 'Berlin', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -381,16 +381,16 @@ def test_itinerary_dsa_regions(self): data = {'itinerary': [{'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2016-11-15T12:06:55.821490', - 'arrival_date': '2016-11-16T12:06:55.821490', + 'departure_date': '2016-11-15', + 'arrival_date': '2016-11-16', 'dsa_region': None, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': [airlines.id]}, {'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -412,16 +412,16 @@ def test_itinerary_dsa_regions(self): # Non ta trip data = {'itinerary': [{'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2016-11-15T12:06:55.821490', - 'arrival_date': '2016-11-16T12:06:55.821490', + 'departure_date': '2016-11-15', + 'arrival_date': '2016-11-16', 'dsa_region': None, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, 'airlines': [airlines.id]}, {'origin': 'Berlin', 'destination': 'Budapest', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsaregion.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.RAIL, @@ -458,14 +458,14 @@ def test_reversed_itinerary_order(self): 'origin': 'a', 'destination': 'b', 'dsa_region': dsa_1.id, - 'departure_date': '2017-01-18T23:00:01.224Z', - 'arrival_date': '2017-01-19T23:00:01.237Z', + 'departure_date': '2017-01-18', + 'arrival_date': '2017-01-19', 'mode_of_travel': 'car'}, {'origin': 'b', 'destination': 'c', 'dsa_region': dsa_2.id, - 'departure_date': '2017-01-20T23:00:01.892Z', - 'arrival_date': '2017-01-27T23:00:01.905Z', + 'departure_date': '2017-01-20', + 'arrival_date': '2017-01-27', 'mode_of_travel': 'car'}], 'activities': [{'is_primary_traveler': True, 'locations': []}], @@ -493,16 +493,16 @@ def test_incorrect_itinerary_order(self): 'origin': 'b', 'destination': 'c', 'dsa_region': dsa_1.id, - 'departure_date': '2017-01-20T23:00:01.892Z', - 'arrival_date': '2017-01-27T23:00:01.905Z', + 'departure_date': '2017-01-20', + 'arrival_date': '2017-01-27', 'mode_of_travel': 'car' }, { 'origin': 'a', 'destination': 'b', 'dsa_region': dsa_2.id, - 'departure_date': '2017-01-18T23:00:01.224Z', - 'arrival_date': '2017-01-19T23:00:01.237Z', + 'departure_date': '2017-01-18', + 'arrival_date': '2017-01-19', 'mode_of_travel': 'car' } ], @@ -577,8 +577,8 @@ def test_ghost_data_existence(self): data = {'itinerary': [{'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.PLANE, @@ -604,8 +604,8 @@ def test_save_with_ghost_data(self): data = {'itinerary': [{'origin': 'Budapest', 'destination': 'Berlin', - 'departure_date': '2016-11-16T12:06:55.821490', - 'arrival_date': '2016-11-17T12:06:55.821490', + 'departure_date': '2016-11-16', + 'arrival_date': '2016-11-17', 'dsa_region': dsa_region.id, 'overnight_travel': False, 'mode_of_travel': ModeOfTravel.PLANE, From 5802e36cbc5c971f5997df7918dcd7456a021b0c Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 26 Mar 2019 11:40:54 -0400 Subject: [PATCH 11/79] Flake8 cleanup --- src/etools/applications/t2f/tests/test_exports.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/etools/applications/t2f/tests/test_exports.py b/src/etools/applications/t2f/tests/test_exports.py index 913a870d70..8c79862598 100644 --- a/src/etools/applications/t2f/tests/test_exports.py +++ b/src/etools/applications/t2f/tests/test_exports.py @@ -3,7 +3,6 @@ import datetime from django.urls import reverse -from django.utils import timezone from django.utils.six import StringIO from pytz import UTC @@ -44,7 +43,6 @@ def test_urls(self): self.assertEqual(export_url, '/api/t2f/travels/travel-admin-export/') def test_activity_export(self): - tz = timezone.get_default_timezone() office = OfficeFactory(name='Budapest') section_health = SectionFactory(name='Health') section_education = SectionFactory(name='Education') From 93b58d3dd0ad0c6322a7856214c9a61272beaa68 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 26 Mar 2019 12:09:31 -0400 Subject: [PATCH 12/79] Further cleanup of travel date conversions --- src/etools/applications/partners/models.py | 2 +- src/etools/applications/partners/serializers/dashboards.py | 6 +++--- .../applications/partners/tests/test_api_dashboards.py | 4 ++-- src/etools/applications/partners/tests/test_views.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/etools/applications/partners/models.py b/src/etools/applications/partners/models.py index 633cd50e61..fc48879f54 100644 --- a/src/etools/applications/partners/models.py +++ b/src/etools/applications/partners/models.py @@ -1854,7 +1854,7 @@ def days_from_last_pv(self): travels__status=Travel.COMPLETED, date__isnull=False, ).order_by('date').last() - return (timezone.now() - ta.date).days if ta else '-' + return (datetime.date.today() - ta.date).days if ta else '-' @property def cp_output_names(self): diff --git a/src/etools/applications/partners/serializers/dashboards.py b/src/etools/applications/partners/serializers/dashboards.py index 8d18086219..dd7bbba5df 100644 --- a/src/etools/applications/partners/serializers/dashboards.py +++ b/src/etools/applications/partners/serializers/dashboards.py @@ -1,4 +1,4 @@ -from django.utils import timezone +import datetime from rest_framework import serializers @@ -33,7 +33,7 @@ class InterventionDashSerializer(serializers.ModelSerializer): disbursement_percent = serializers.SerializerMethodField() days_last_pv = serializers.SerializerMethodField() - last_pv_date = serializers.DateTimeField() + last_pv_date = serializers.DateField() fr_currencies_are_consistent = serializers.SerializerMethodField() all_currencies_are_consistent = serializers.SerializerMethodField() @@ -80,7 +80,7 @@ def get_disbursement_percent(self, obj): def get_days_last_pv(self, obj): if obj.last_pv_date: - duration = timezone.now() - obj.last_pv_date + duration = datetime.date.today() - obj.last_pv_date return duration.days return None diff --git a/src/etools/applications/partners/tests/test_api_dashboards.py b/src/etools/applications/partners/tests/test_api_dashboards.py index 148f6a4f6e..60e4a72241 100644 --- a/src/etools/applications/partners/tests/test_api_dashboards.py +++ b/src/etools/applications/partners/tests/test_api_dashboards.py @@ -90,7 +90,7 @@ def test_get_last_pv_date(self): partnership=self.intervention, primary_traveler=traveler, travel_type=TravelType.PROGRAMME_MONITORING, - date=timezone.now() - datetime.timedelta(days=3), + date=datetime.date.today() - datetime.timedelta(days=3), ) travel.activities.add(travel_activity) for i in range(4): @@ -98,7 +98,7 @@ def test_get_last_pv_date(self): partnership=self.intervention, primary_traveler=traveler, travel_type=TravelType.PROGRAMME_MONITORING, - date=timezone.now() - datetime.timedelta(days=3 * (i + 2)), + date=datetime.date.today() - datetime.timedelta(days=3 * (i + 2)), ) travel.activities.add(activity) diff --git a/src/etools/applications/partners/tests/test_views.py b/src/etools/applications/partners/tests/test_views.py index 1dcdb64cd6..48c89372a0 100644 --- a/src/etools/applications/partners/tests/test_views.py +++ b/src/etools/applications/partners/tests/test_views.py @@ -1932,7 +1932,7 @@ def test_action_points(self): self.assertEqual(self.record['action_points'], 6) def test_no_recent_programmatic_visit(self): - self.assertEquals(self.record['last_pv_date'].date(), datetime.date.today() - datetime.timedelta(200)) + self.assertEquals(self.record['last_pv_date'], datetime.date.today() - datetime.timedelta(200)) self.assertEquals(self.record['days_last_pv'], 200) self.assertTrue(self.record['alert_no_recent_pv']) self.assertFalse(self.record['alert_no_pv']) From 75fe7ac249e418d58bd605563138601672cc9399 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 26 Mar 2019 12:14:48 -0400 Subject: [PATCH 13/79] flake8 cleanup --- src/etools/applications/partners/tests/test_api_dashboards.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/etools/applications/partners/tests/test_api_dashboards.py b/src/etools/applications/partners/tests/test_api_dashboards.py index 60e4a72241..a110e637e4 100644 --- a/src/etools/applications/partners/tests/test_api_dashboards.py +++ b/src/etools/applications/partners/tests/test_api_dashboards.py @@ -2,7 +2,6 @@ import json from django.urls import reverse -from django.utils import timezone from rest_framework import status From 075876562fb3d63ebfac13fac99c7892bee8a73f Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 26 Mar 2019 14:27:07 -0400 Subject: [PATCH 14/79] tpm hact visit by month --- src/etools/applications/partners/models.py | 37 ++++++---------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/src/etools/applications/partners/models.py b/src/etools/applications/partners/models.py index 633cd50e61..ba1bc13959 100644 --- a/src/etools/applications/partners/models.py +++ b/src/etools/applications/partners/models.py @@ -28,8 +28,8 @@ agreements_illegal_transition, ) from etools.applications.reports.models import CountryProgramme, Indicator, Result, Section -from etools.applications.t2f.models import Travel, TravelType, TravelActivity -from etools.applications.tpm.models import TPMVisit +from etools.applications.t2f.models import Travel, TravelActivity, TravelType +from etools.applications.tpm.models import TPMActivity, TPMVisit from etools.applications.users.models import Office from etools.libraries.djangolib.models import StringConcat from etools.libraries.pythonlib.datetime import get_current_year, get_quarter @@ -688,32 +688,13 @@ def programmatic_visits(self, event_date=None, update_one=False): pvq3 = pv_year.filter(end_date__quarter=3).count() pvq4 = pv_year.filter(end_date__quarter=4).count() - # TPM visit are counted one per month maximum - tpmv = TPMVisit.objects.filter( - tpm_activities__partner=self, status=TPMVisit.UNICEF_APPROVED, - date_of_unicef_approved__year=datetime.datetime.now().year - ).distinct() - - tpmv1 = sum([ - tpmv.filter(date_of_unicef_approved__month=1).exists(), - tpmv.filter(date_of_unicef_approved__month=2).exists(), - tpmv.filter(date_of_unicef_approved__month=3).exists() - ]) - tpmv2 = sum([ - tpmv.filter(date_of_unicef_approved__month=4).exists(), - tpmv.filter(date_of_unicef_approved__month=5).exists(), - tpmv.filter(date_of_unicef_approved__month=6).exists() - ]) - tpmv3 = sum([ - tpmv.filter(date_of_unicef_approved__month=7).exists(), - tpmv.filter(date_of_unicef_approved__month=8).exists(), - tpmv.filter(date_of_unicef_approved__month=9).exists() - ]) - tpmv4 = sum([ - tpmv.filter(date_of_unicef_approved__month=10).exists(), - tpmv.filter(date_of_unicef_approved__month=11).exists(), - tpmv.filter(date_of_unicef_approved__month=12).exists() - ]) + tpmv = TPMActivity.objects.filter(is_pv=True, partner=self, tpm_visit__status=TPMVisit.UNICEF_APPROVED, + date__year=datetime.datetime.now().year) + + tpmv1 = tpmv.filter(date__quarter=1).count() + tpmv2 = tpmv.filter(date__quarter=2).count() + tpmv3 = tpmv.filter(date__quarter=3).count() + tpmv4 = tpmv.filter(date__quarter=4).count() tpm_total = tpmv1 + tpmv2 + tpmv3 + tpmv4 From 8798228d9306d2c22f95bd9cdbac07189685a0ab Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Wed, 27 Mar 2019 09:19:44 -0400 Subject: [PATCH 15/79] Remove permission matrix yaml --- .../t2f/helpers/permission_matrix.py | 115 - .../applications/t2f/permission_matrix.yaml | 20135 ---------------- .../t2f/tests/test_permission_matrix.py | 56 - 3 files changed, 20306 deletions(-) delete mode 100644 src/etools/applications/t2f/permission_matrix.yaml diff --git a/src/etools/applications/t2f/helpers/permission_matrix.py b/src/etools/applications/t2f/helpers/permission_matrix.py index 129ce3c92e..5698f102d4 100644 --- a/src/etools/applications/t2f/helpers/permission_matrix.py +++ b/src/etools/applications/t2f/helpers/permission_matrix.py @@ -89,118 +89,3 @@ def has_permission(self, permission_type, model_name, field_name): def get_permission_dict(self): return {} - - -# TODO may remove the following code, once satisfied with above changes -def get_permission_matrix_old(): - path = os.path.join( - os.path.dirname(t2f.__file__), - "permission_matrix.yaml", - ) - with open(path) as permission_matrix_file: - permission_matrix = yaml.load(permission_matrix_file.read()) - return permission_matrix - - -def parse_permission_matrix(filename): - """Extra data from permission_matrix - - Default expected permission is; - - `edit`: False - - `view`: True - - For each record check if it is different to the default - if so, take note - - Structure of permission_matrix is; - Travel: { - "User Role": { - "Status": { - "Model": { - "edit": ..., - "view": ..., - "": { - "edit": ..., - "view": ..., - }, - }, - }, - }, - } - """ - def machine_readable(data): - # display results in machine readable format - # d = {"user": {"status": {"model": {"field": {"perm": "value"}}}}} - result = {} - state_choices = [x[0] for x in Travel.CHOICES] - for user_type, states in data.items(): - result[user_type] = {} - for state, models in states.items(): - if state not in state_choices: - continue - result[user_type][state] = defaultdict(bool) - for model, fields in models.items(): - for field, perm_types in fields.items(): - for perm_type, perm in perm_types.items(): - if field == "all": - key = (perm_type, "travel", model) - else: - key = (perm_type, model, field) - result[user_type][state][key] |= perm - - pp = pprint.PrettyPrinter(indent=4) - with open(filename, "w") as fp: - fp.write("permissions = {}".format( - pp.pformat(result).replace( - "defaultdict(,", "" - ).replace( - "})", "}" - ) - )) - - matrix = get_permission_matrix_old() - model_fields = defaultdict(set) - results = {} - for user in matrix["travel"]: - data = {} - for status in matrix["travel"][user]: - data[status] = defaultdict() - for model in matrix["travel"][user][status]: - model_key = "travel" if model == "baseDetails" else model - data[status][model_key] = defaultdict(dict) - for field in matrix["travel"][user][status][model]: - model_fields[model_key].add( - "all" if field in ["edit", "view"] else field - ) - perm_dict = matrix["travel"][user][status][model][field] - if field in ["edit", "view"]: - data[status][model_key]["all"][field] = perm_dict - else: - for perm in ["edit", "view"]: - perm_value = perm_dict[perm] - data[status][model_key][field][perm] = perm_value - results[user] = data - - machine_readable(results) - - -def convert_matrix_to_json(filename=None): - """Take old permission matrix in yaml format and convert to json""" - matrix = get_permission_matrix_old() - - # remove obsolete states - results = {"action_point": matrix["action_point"], "travel": {}} - state_choices = [x[0] for x in Travel.CHOICES] - for user, states in matrix["travel"].items(): - results["travel"][user] = {} - for state, models in states.items(): - if state in state_choices: - results["travel"][user][state] = models - - filename = filename if filename else os.path.join( - os.path.dirname(t2f.__file__), - "permission_matrix.json", - ) - - with open(filename, "w") as fp: - fp.write(json.dumps(results)) diff --git a/src/etools/applications/t2f/permission_matrix.yaml b/src/etools/applications/t2f/permission_matrix.yaml deleted file mode 100644 index 853ae190b8..0000000000 --- a/src/etools/applications/t2f/permission_matrix.yaml +++ /dev/null @@ -1,20135 +0,0 @@ ---- -travel: - Supervisor: - certification_submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - planned: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - Finance Focal Point: - certification_submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - planned: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - God: - certification_submitted: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - completed: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - rejected: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - planned: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - submitted: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - approved: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - certified: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - Anyone: - certification_submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - planned: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: false - cost_assignments: - wbs: - edit: false - view: false - grant: - edit: false - view: false - edit: false - share: - edit: false - view: false - fund: - edit: false - view: false - delegate: - edit: false - view: false - business_area: - edit: false - view: false - id: - edit: false - view: false - view: false - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: false - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: false - edit: false - account_currency: - edit: false - view: false - document_currency: - edit: false - view: false - type: - edit: false - view: false - id: - edit: false - view: false - view: false - deductions: - accomodation: - edit: false - view: false - edit: false - no_dsa: - edit: false - view: false - breakfast: - edit: false - view: false - lunch: - edit: false - view: false - dinner: - edit: false - view: false - date: - edit: false - view: false - day_of_the_week: - edit: false - view: false - id: - edit: false - view: false - view: false - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - Representative: - certification_submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - planned: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - id: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - breakfast: - edit: false - view: true - day_of_the_week: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - completed_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - edit: false - person_responsible: - edit: false - view: true - id: - edit: false - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - Travel Focal Point: - certification_submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - planned: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - submitted: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: true - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: true - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - Traveler: - certification_submitted: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: false - view: true - purpose: - edit: true - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - planned: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: false - view: true - purpose: - edit: true - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: false - view: false - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - submitted: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: false - view: true - purpose: - edit: true - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: false - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: false - view: true - purpose: - edit: true - view: true - traveler: - edit: false - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: true - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: true - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - Travel Administrator: - certification_submitted: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - certification_rejected: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - completed: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - rejected: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - planned: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - submitted: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - cancelled: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - certification_approved: - activities: - primary_traveler: - edit: false - view: true - edit: false - partnership: - edit: false - view: true - locations: - edit: false - view: true - date: - edit: false - view: true - result: - edit: false - view: true - travel_type: - edit: false - view: true - partner: - edit: false - view: true - id: - edit: false - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - approved: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true - certified: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: true - view: true - cost_assignments: - wbs: - edit: true - view: true - grant: - edit: true - view: true - edit: true - share: - edit: true - view: true - fund: - edit: true - view: true - delegate: - edit: true - view: true - business_area: - edit: true - view: true - id: - edit: true - view: true - view: true - baseDetails: - status: - edit: true - view: true - reference_number: - edit: true - view: true - supervisor: - edit: true - view: true - end_date: - edit: true - view: true - office: - edit: true - view: true - section: - edit: true - view: true - international_travel: - edit: true - view: true - id: - edit: true - view: true - ta_required: - edit: true - view: true - currency: - edit: true - view: true - purpose: - edit: true - view: true - traveler: - edit: true - view: true - start_date: - edit: true - view: true - expenses: - amount: - edit: true - view: true - edit: true - account_currency: - edit: true - view: true - document_currency: - edit: true - view: true - type: - edit: true - view: true - id: - edit: true - view: true - view: true - deductions: - accomodation: - edit: true - view: true - edit: true - no_dsa: - edit: true - view: true - breakfast: - edit: true - view: true - lunch: - edit: true - view: true - dinner: - edit: true - view: true - date: - edit: true - view: true - day_of_the_week: - edit: true - view: true - id: - edit: true - view: true - view: true - itinerary: - origin: - edit: true - view: true - arrival_date: - edit: true - view: true - mode_of_travel: - edit: true - view: true - departure_date: - edit: true - view: true - destination: - edit: true - view: true - airlines: - edit: true - view: true - edit: true - dsa_region: - edit: true - view: true - view: true - id: - edit: true - view: true - overnight_travel: - edit: true - view: true - report: - edit: true - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: true - view: true - security_clearance: - edit: true - view: true - edit: true - medical_clearance: - edit: true - view: true - id: - edit: true - view: true - view: true - sent_for_payment: - activities: - primary_traveler: - edit: true - view: true - edit: true - partnership: - edit: true - view: true - locations: - edit: true - view: true - date: - edit: true - view: true - result: - edit: true - view: true - travel_type: - edit: true - view: true - partner: - edit: true - view: true - id: - edit: true - view: true - view: true - cost_summary: - edit: false - view: true - cost_assignments: - wbs: - edit: false - view: true - grant: - edit: false - view: true - edit: false - share: - edit: false - view: true - fund: - edit: false - view: true - delegate: - edit: false - view: true - business_area: - edit: false - view: true - id: - edit: false - view: true - view: true - baseDetails: - status: - edit: false - view: true - reference_number: - edit: false - view: true - supervisor: - edit: false - view: true - end_date: - edit: false - view: true - office: - edit: false - view: true - section: - edit: false - view: true - international_travel: - edit: false - view: true - id: - edit: false - view: true - ta_required: - edit: false - view: true - currency: - edit: false - view: true - purpose: - edit: false - view: true - traveler: - edit: false - view: true - start_date: - edit: false - view: true - expenses: - amount: - edit: false - view: true - edit: false - account_currency: - edit: false - view: true - document_currency: - edit: false - view: true - type: - edit: false - view: true - id: - edit: false - view: true - view: true - deductions: - accomodation: - edit: false - view: true - edit: false - no_dsa: - edit: false - view: true - breakfast: - edit: false - view: true - lunch: - edit: false - view: true - dinner: - edit: false - view: true - date: - edit: false - view: true - day_of_the_week: - edit: false - view: true - id: - edit: false - view: true - view: true - itinerary: - origin: - edit: false - view: true - arrival_date: - edit: false - view: true - mode_of_travel: - edit: false - view: true - departure_date: - edit: false - view: true - destination: - edit: false - view: true - airlines: - edit: false - view: true - edit: false - dsa_region: - edit: false - view: true - view: true - id: - edit: false - view: true - overnight_travel: - edit: false - view: true - report: - edit: false - view: true - action_points: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: true - view: true - actions_taken: - edit: true - view: true - created_at: - edit: true - view: true - completed_at: - edit: true - view: true - comments: - edit: true - view: true - action_point_number: - edit: true - view: true - edit: true - person_responsible: - edit: true - view: true - id: - edit: true - view: true - view: true - clearances: - security_course: - edit: false - view: true - security_clearance: - edit: false - view: true - edit: false - medical_clearance: - edit: false - view: true - id: - edit: false - view: true - view: true -action_point: - PersonResponsible: - status: - edit: true - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: true - view: true - created_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - completed_at: - edit: true - view: true - person_responsible: - edit: false - view: true - id: - edit: false - view: true - PME: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: false - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - completed_at: - edit: true - view: true - person_responsible: - edit: true - view: true - id: - edit: false - view: true - Assigner: - status: - edit: true - view: true - due_date: - edit: true - view: true - description: - edit: true - view: true - follow_up: - edit: true - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - completed_at: - edit: false - view: true - person_responsible: - edit: true - view: true - id: - edit: false - view: true - Others: - status: - edit: false - view: true - due_date: - edit: false - view: true - description: - edit: false - view: true - follow_up: - edit: false - view: true - trip_reference_number: - edit: false - view: true - actions_taken: - edit: false - view: true - created_at: - edit: false - view: true - comments: - edit: false - view: true - action_point_number: - edit: false - view: true - completed_at: - edit: false - view: true - person_responsible: - edit: false - view: true - id: - edit: false - view: true diff --git a/src/etools/applications/t2f/tests/test_permission_matrix.py b/src/etools/applications/t2f/tests/test_permission_matrix.py index a1b444aa97..1b3e17bc68 100644 --- a/src/etools/applications/t2f/tests/test_permission_matrix.py +++ b/src/etools/applications/t2f/tests/test_permission_matrix.py @@ -15,10 +15,8 @@ ) from etools.applications.t2f import UserTypes from etools.applications.t2f.helpers.permission_matrix import ( - convert_matrix_to_json, FakePermissionMatrix, get_user_role_list, - parse_permission_matrix, PermissionMatrix, ) from etools.applications.t2f.models import ModeOfTravel, Travel, TravelType @@ -109,50 +107,6 @@ def test_user_type_lookup(self): UserTypes.TRAVEL_ADMINISTRATOR, UserTypes.REPRESENTATIVE]) - @skip("no longer using get_permission_matrix") - @mock.patch('etools.applications.t2f.helpers.permission_matrix.get_permission_matrix') - def test_permission_aggregation(self, permission_matrix_getter): - permission_matrix_getter.return_value = { - 'travel': { - UserTypes.TRAVELER: { - Travel.PLANNED: { - 'baseDetails': { - 'ta_required': { - 'edit': True, - 'view': True}}}}, - UserTypes.SUPERVISOR: { - Travel.PLANNED: { - 'baseDetails': { - 'ta_required': { - 'edit': False, - 'view': True}}}}}} - - travel = TravelFactory(traveler=self.traveler, - supervisor=self.unicef_staff) - - # Check traveler - permission_matrix = PermissionMatrix(travel, self.traveler) - permissions = permission_matrix.get_permission_dict() - self.assertEqual(dict(permissions), - {('edit', 'travel', 'ta_required'): True, - ('view', 'travel', 'ta_required'): True}) - - # Check supervisor - permission_matrix = PermissionMatrix(travel, self.unicef_staff) - permissions = permission_matrix.get_permission_dict() - self.assertEqual(dict(permissions), - {('edit', 'travel', 'ta_required'): False, - ('view', 'travel', 'ta_required'): True}) - - travel = TravelFactory(traveler=self.traveler, - supervisor=self.traveler) - # Check both the same time (not really possible, but good to check aggregation) - permission_matrix = PermissionMatrix(travel, self.traveler) - permissions = permission_matrix.get_permission_dict() - self.assertEqual(dict(permissions), - {('edit', 'travel', 'ta_required'): True, - ('view', 'travel', 'ta_required'): True}) - def test_travel_creation(self): dsa_region = PublicsDSARegionFactory() currency = PublicsCurrencyFactory() @@ -239,16 +193,6 @@ def test_travel_creation(self): response_json = json.loads(response.rendered_content) self.assertEqual(response_json['purpose'], purpose) - def test_convert_matrix_to_json(self): - filename = "/tmp/matrix.json" - convert_matrix_to_json(filename) - self.assertTrue(os.path.exists(filename)) - - def test_parse_permission_matrix(self): - filename = "/tmp/permission_matrix.json" - parse_permission_matrix(filename) - self.assertTrue(os.path.exists(filename)) - class TestFakePermissionMatrix(BaseTenantTestCase): @classmethod From 20e3b466979256ed56694bc3d5af2dfe1d9bd9f0 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Wed, 27 Mar 2019 10:36:26 -0400 Subject: [PATCH 16/79] flake8 cleanup --- src/etools/applications/t2f/helpers/permission_matrix.py | 4 ---- src/etools/applications/t2f/tests/test_permission_matrix.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/etools/applications/t2f/helpers/permission_matrix.py b/src/etools/applications/t2f/helpers/permission_matrix.py index 5698f102d4..e7f9896646 100644 --- a/src/etools/applications/t2f/helpers/permission_matrix.py +++ b/src/etools/applications/t2f/helpers/permission_matrix.py @@ -1,15 +1,11 @@ import json import os -import pprint from collections import defaultdict from django.core.cache import cache -import yaml - from etools.applications import t2f from etools.applications.t2f import UserTypes -from etools.applications.t2f.models import Travel from etools.applications.t2f.permissions import permissions PERMISSION_MATRIX_CACHE_KEY = 't2f_permission_matrix' diff --git a/src/etools/applications/t2f/tests/test_permission_matrix.py b/src/etools/applications/t2f/tests/test_permission_matrix.py index 1b3e17bc68..d99e0a637a 100644 --- a/src/etools/applications/t2f/tests/test_permission_matrix.py +++ b/src/etools/applications/t2f/tests/test_permission_matrix.py @@ -1,11 +1,8 @@ import json -import os -from unittest import skip from django.contrib.auth.models import Group from django.urls import reverse -import mock from unicef_locations.tests.factories import LocationFactory from etools.applications.EquiTrack.tests.cases import BaseTenantTestCase @@ -17,7 +14,6 @@ from etools.applications.t2f.helpers.permission_matrix import ( FakePermissionMatrix, get_user_role_list, - PermissionMatrix, ) from etools.applications.t2f.models import ModeOfTravel, Travel, TravelType from etools.applications.t2f.tests.factories import TravelFactory From aab2eef8edc4d8b680177483d92a0a219951d520 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 19 Mar 2019 11:00:58 -0400 Subject: [PATCH 17/79] 10241 init-demo --- .../management/commands/init-demo.py | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/etools/applications/EquiTrack/management/commands/init-demo.py diff --git a/src/etools/applications/EquiTrack/management/commands/init-demo.py b/src/etools/applications/EquiTrack/management/commands/init-demo.py new file mode 100644 index 0000000000..89bc933949 --- /dev/null +++ b/src/etools/applications/EquiTrack/management/commands/init-demo.py @@ -0,0 +1,119 @@ +import logging +import os + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.auth.hashers import make_password +from django.contrib.auth.models import Group +from django.core.management import call_command +from django.core.management.base import BaseCommand + +from etools.applications.publics.models import Currency + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = "" + + def add_arguments(self, parser): + parser.add_argument( + '--all', + action='store_true', + dest='all', + default=False, + help='select all options but `demo`') + parser.add_argument( + '--users', + action='store_true', + dest='users', + default=False, + help='') + parser.add_argument( + '--migrate', + action='store_true', + dest='migrate', + default=False, + help='select all production deployment options') + parser.add_argument( + '--fixtures', + action='store_true', + dest='fixtures', + default=False, + help='fixtures') + parser.add_argument( + '--notifications', + action='store_true', + dest='notifications', + default=False, + help='update notifications') + parser.add_argument( + '--permissions', + action='store_true', + dest='permissions', + default=False, + help='update permissions') + + def handle(self, *args, **options): + verbosity = options['verbosity'] + migrate = options['migrate'] + _all = options['all'] + + ModelUser = get_user_model() + if migrate or _all: + self.stdout.write(f"Run migrations") + call_command('migrate_schemas', verbosity=verbosity - 1) + + logger.info(f'Be sure USD is present') + Currency.objects.get_or_create(code='USD') + + if options['users'] or _all: + logger.info(f'Create Admin and Groups') + if settings.DEBUG: + pwd = '123' + admin = os.environ.get('USER', 'admin') + else: + pwd = os.environ.get('ADMIN_PASSWORD', ModelUser.objects.make_random_password()) + admin = os.environ.get('ADMIN_USERNAME', 'admin') + + self._admin_user, created = ModelUser.objects.get_or_create(username=admin, + + defaults={"email": f'{admin}@unicef.org', + "is_superuser": True, + "is_staff": True, + "password": make_password(pwd)}) + + groups_name = ['Partnership Manager', 'Travel Administrator', 'Travel Focal Point', 'UNICEF User', + 'Country Office Administrator'] + groups = [] + + logger.info(f'Setup Groups') + for group_name in groups_name: + logger.info(f'Setup {group_name}') + gr, _ = Group.objects.get_or_create(name=group_name) + groups.append(gr) + call_command('loaddata', 'audit_groups') + call_command('loaddata', 'tpm_groups') + call_command('loaddata', 'groups') + + self._admin_user.groups.set(groups) + + if created: # pragma: no cover + self.stdout.write(f"Created superuser `{admin}` with password `{pwd}`") + else: # pragma: no cover + self.stdout.write(f"Superuser `{admin}` already exists`.") + + if options['notifications'] or _all: + logger.info(f'Update Notifications') + call_command('update_notifications') + + if options['fixtures'] or _all: + logger.info(f'Update Fixtures') + call_command('loaddata', 'action_points_categories') + call_command('loaddata', 'audit_staff_organization') + + if options['permissions'] or _all: + logger.info(f'Update Permissions') + call_command('update_audit_permissions') + call_command('update_tpm_permissions') + call_command('update_action_points_permissions') From 8f2a3c6d9523228cc615507448992fdbe6ccf52f Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Wed, 27 Mar 2019 13:23:50 -0400 Subject: [PATCH 18/79] fix tests --- .../applications/partners/tests/test_models.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/etools/applications/partners/tests/test_models.py b/src/etools/applications/partners/tests/test_models.py index bda3305725..9582e3e56a 100644 --- a/src/etools/applications/partners/tests/test_models.py +++ b/src/etools/applications/partners/tests/test_models.py @@ -472,7 +472,6 @@ def test_programmatic_visits_update_tpm_visit(self): self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['total'], 0) visit = TPMVisitFactory( status=TPMVisit.UNICEF_APPROVED, - date_of_unicef_approved=datetime.datetime(datetime.datetime.today().year, 5, 1) ) visit2 = TPMVisitFactory( status=TPMVisit.UNICEF_APPROVED, @@ -481,21 +480,31 @@ def test_programmatic_visits_update_tpm_visit(self): TPMActivityFactory( tpm_visit=visit, partner=self.partner_organization, + is_pv=True, + date=datetime.datetime(datetime.datetime.today().year, 5, 1) ) TPMActivityFactory( tpm_visit=visit, partner=self.partner_organization, + is_pv=True, + date=datetime.datetime(datetime.datetime.today().year, 9, 1) + ) + TPMActivityFactory( + tpm_visit=visit, + partner=self.partner_organization, + date=datetime.datetime(datetime.datetime.today().year, 5, 1) ) TPMActivityFactory( tpm_visit=visit2, partner=self.partner_organization, + date=datetime.datetime(datetime.datetime.today().year, 5, 1) ) self.partner_organization.programmatic_visits() - self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['total'], 1) + self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['total'], 2) self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['q1'], 0) self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['q2'], 1) - self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['q3'], 0) + self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['q3'], 1) self.assertEqual(self.partner_organization.hact_values['programmatic_visits']['completed']['q4'], 0) @freeze_time("2013-12-26") From e17b9baa7f6f75cecfbea706fd0cad0aa57c6cc0 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 28 Mar 2019 11:29:09 -0400 Subject: [PATCH 19/79] 10400 allow to change engagement status in admin --- src/etools/applications/audit/admin.py | 1 - .../migrations/0016_auto_20190328_1528.py | 19 +++++++++++++++++++ src/etools/applications/audit/models.py | 3 +-- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/etools/applications/audit/migrations/0016_auto_20190328_1528.py diff --git a/src/etools/applications/audit/admin.py b/src/etools/applications/audit/admin.py index 2e35271197..a2a1b20973 100644 --- a/src/etools/applications/audit/admin.py +++ b/src/etools/applications/audit/admin.py @@ -29,7 +29,6 @@ class EngagementAdmin(admin.ModelAdmin): list_filter = [ 'status', 'start_date', 'end_date', 'status', 'engagement_type', ] - readonly_fields = ('status', ) search_fields = 'partner__name', 'agreement__auditor_firm__name', filter_horizontal = ('authorized_officers', ) diff --git a/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py b/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py new file mode 100644 index 0000000000..2acadd4702 --- /dev/null +++ b/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py @@ -0,0 +1,19 @@ +# Generated by Django 2.1.7 on 2019-03-28 15:28 + +from django.db import migrations +import django_fsm + + +class Migration(migrations.Migration): + + dependencies = [ + ('audit', '0015_auto_20190312_2010'), + ] + + operations = [ + migrations.AlterField( + model_name='engagement', + name='status', + field=django_fsm.FSMField(choices=[('partner_contacted', 'IP Contacted'), ('report_submitted', 'Report Submitted'), ('final', 'Final Report'), ('cancelled', 'Cancelled')], default='partner_contacted', max_length=30, verbose_name='Status'), + ), + ] diff --git a/src/etools/applications/audit/models.py b/src/etools/applications/audit/models.py index 933830a38f..6d65459d27 100644 --- a/src/etools/applications/audit/models.py +++ b/src/etools/applications/audit/models.py @@ -86,8 +86,7 @@ class Engagement(InheritedModelMixin, TimeStampedModel, models.Model): DISPLAY_STATUSES.cancelled: 'date_of_cancel' } - status = FSMField(verbose_name=_('Status'), max_length=30, choices=STATUSES, default=STATUSES.partner_contacted, - protected=True) + status = FSMField(verbose_name=_('Status'), max_length=30, choices=STATUSES, default=STATUSES.partner_contacted) # auditor - partner organization from agreement agreement = models.ForeignKey( From e213cb4873babab32f8027f24bc345da2c2b1400 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 7 Mar 2019 10:03:00 -0500 Subject: [PATCH 20/79] 9985 cleaned templates --- .../EquiTrack/templatetags/etools.py | 34 ++ .../tests/test_userprofile_tags.py | 8 +- .../partners/templatetags/__init__.py | 0 .../templatetags/intervention_tags.py | 48 --- .../partners/templatetags/userprofile_tags.py | 41 --- .../partners/tests/test_intervention_tags.py | 17 - .../applications/users/tests/test_views.py | 29 +- src/etools/applications/users/urls.py | 18 +- src/etools/applications/users/views.py | 42 +-- src/etools/applications/users/views_v2.py | 4 - src/etools/config/settings/base.py | 1 - src/etools/templates/404.html | 60 ++-- src/etools/templates/500.html | 117 ++----- src/etools/templates/admin/base_site.html | 2 +- src/etools/templates/admin/index.html | 2 +- .../admin/partners/assurance_table.html | 104 ------ .../admin/partners/government_funding.html | 21 -- .../admin/partners/interventions_inline.html | 32 -- .../admin/partners/interventions_table.html | 29 -- src/etools/templates/base.html | 327 ------------------ .../frontend/account/account_inactive.html | 11 - .../templates/frontend/account/base.html | 8 - .../templates/frontend/account/email.html | 73 ---- .../email/email_confirmation_message.txt | 8 - .../email_confirmation_signup_message.txt | 1 - .../email_confirmation_signup_subject.txt | 1 - .../email/email_confirmation_subject.txt | 4 - .../email/password_reset_key_message.txt | 11 - .../email/password_reset_key_subject.txt | 4 - .../frontend/account/email_confirm.html | 31 -- .../frontend/account/email_confirmed.html | 17 - .../templates/frontend/account/login.html | 136 -------- .../templates/frontend/account/logout.html | 21 -- .../messages/cannot_delete_primary_email.txt | 2 - .../messages/email_confirmation_sent.txt | 2 - .../account/messages/email_confirmed.txt | 2 - .../account/messages/email_deleted.txt | 2 - .../frontend/account/messages/logged_in.txt | 4 - .../frontend/account/messages/logged_out.txt | 2 - .../account/messages/password_changed.txt | 3 - .../account/messages/password_set.txt | 3 - .../account/messages/primary_email_set.txt | 2 - .../messages/unverified_primary_email.txt | 2 - .../frontend/account/password_change.html | 15 - .../frontend/account/password_reset.html | 24 -- .../frontend/account/password_reset_done.html | 16 - .../account/password_reset_from_key.html | 23 -- .../account/password_reset_from_key_done.html | 9 - .../frontend/account/password_set.html | 15 - .../templates/frontend/account/signup.html | 21 -- .../frontend/account/signup_closed.html | 11 - .../account/snippets/already_logged_in.html | 5 - .../frontend/account/verification_sent.html | 12 - .../account/verified_email_required.html | 23 -- .../templates/frontend/base_polymer.html | 62 ---- .../templates/frontend/choose_login.html | 106 ------ src/etools/templates/frontend/login_base.html | 49 --- .../frontend/management/management.html | 1 - .../frontend/partner_loginfailed.html | 13 - .../socialaccount/authentication_error.html | 11 - .../frontend/socialaccount/base.html | 2 - .../frontend/socialaccount/connections.html | 54 --- .../socialaccount/login_cancelled.html | 15 - .../messages/account_connected.txt | 2 - .../messages/account_connected_other.txt | 2 - .../messages/account_disconnected.txt | 2 - .../frontend/socialaccount/signup.html | 22 -- .../socialaccount/snippets/login_extra.html | 4 - .../socialaccount/snippets/provider_list.html | 21 -- src/etools/templates/hact/dashboard.html | 147 -------- src/etools/templates/no_country_found.html | 3 +- src/etools/templates/users/profile.html | 66 ---- .../templates/users/profile_change_done.html | 21 -- 73 files changed, 108 insertions(+), 1955 deletions(-) rename src/etools/applications/{partners => EquiTrack}/tests/test_userprofile_tags.py (79%) delete mode 100644 src/etools/applications/partners/templatetags/__init__.py delete mode 100644 src/etools/applications/partners/templatetags/intervention_tags.py delete mode 100644 src/etools/applications/partners/templatetags/userprofile_tags.py delete mode 100644 src/etools/applications/partners/tests/test_intervention_tags.py delete mode 100644 src/etools/templates/admin/partners/assurance_table.html delete mode 100644 src/etools/templates/admin/partners/government_funding.html delete mode 100644 src/etools/templates/admin/partners/interventions_inline.html delete mode 100644 src/etools/templates/admin/partners/interventions_table.html delete mode 100644 src/etools/templates/base.html delete mode 100644 src/etools/templates/frontend/account/account_inactive.html delete mode 100644 src/etools/templates/frontend/account/base.html delete mode 100644 src/etools/templates/frontend/account/email.html delete mode 100644 src/etools/templates/frontend/account/email/email_confirmation_message.txt delete mode 100644 src/etools/templates/frontend/account/email/email_confirmation_signup_message.txt delete mode 100644 src/etools/templates/frontend/account/email/email_confirmation_signup_subject.txt delete mode 100644 src/etools/templates/frontend/account/email/email_confirmation_subject.txt delete mode 100644 src/etools/templates/frontend/account/email/password_reset_key_message.txt delete mode 100644 src/etools/templates/frontend/account/email/password_reset_key_subject.txt delete mode 100644 src/etools/templates/frontend/account/email_confirm.html delete mode 100644 src/etools/templates/frontend/account/email_confirmed.html delete mode 100644 src/etools/templates/frontend/account/login.html delete mode 100644 src/etools/templates/frontend/account/logout.html delete mode 100644 src/etools/templates/frontend/account/messages/cannot_delete_primary_email.txt delete mode 100644 src/etools/templates/frontend/account/messages/email_confirmation_sent.txt delete mode 100644 src/etools/templates/frontend/account/messages/email_confirmed.txt delete mode 100644 src/etools/templates/frontend/account/messages/email_deleted.txt delete mode 100644 src/etools/templates/frontend/account/messages/logged_in.txt delete mode 100644 src/etools/templates/frontend/account/messages/logged_out.txt delete mode 100644 src/etools/templates/frontend/account/messages/password_changed.txt delete mode 100644 src/etools/templates/frontend/account/messages/password_set.txt delete mode 100644 src/etools/templates/frontend/account/messages/primary_email_set.txt delete mode 100644 src/etools/templates/frontend/account/messages/unverified_primary_email.txt delete mode 100644 src/etools/templates/frontend/account/password_change.html delete mode 100644 src/etools/templates/frontend/account/password_reset.html delete mode 100644 src/etools/templates/frontend/account/password_reset_done.html delete mode 100644 src/etools/templates/frontend/account/password_reset_from_key.html delete mode 100644 src/etools/templates/frontend/account/password_reset_from_key_done.html delete mode 100644 src/etools/templates/frontend/account/password_set.html delete mode 100644 src/etools/templates/frontend/account/signup.html delete mode 100644 src/etools/templates/frontend/account/signup_closed.html delete mode 100644 src/etools/templates/frontend/account/snippets/already_logged_in.html delete mode 100644 src/etools/templates/frontend/account/verification_sent.html delete mode 100644 src/etools/templates/frontend/account/verified_email_required.html delete mode 100644 src/etools/templates/frontend/base_polymer.html delete mode 100644 src/etools/templates/frontend/choose_login.html delete mode 100644 src/etools/templates/frontend/login_base.html delete mode 100755 src/etools/templates/frontend/management/management.html delete mode 100644 src/etools/templates/frontend/partner_loginfailed.html delete mode 100644 src/etools/templates/frontend/socialaccount/authentication_error.html delete mode 100644 src/etools/templates/frontend/socialaccount/base.html delete mode 100644 src/etools/templates/frontend/socialaccount/connections.html delete mode 100644 src/etools/templates/frontend/socialaccount/login_cancelled.html delete mode 100644 src/etools/templates/frontend/socialaccount/messages/account_connected.txt delete mode 100644 src/etools/templates/frontend/socialaccount/messages/account_connected_other.txt delete mode 100644 src/etools/templates/frontend/socialaccount/messages/account_disconnected.txt delete mode 100644 src/etools/templates/frontend/socialaccount/signup.html delete mode 100644 src/etools/templates/frontend/socialaccount/snippets/login_extra.html delete mode 100644 src/etools/templates/frontend/socialaccount/snippets/provider_list.html delete mode 100644 src/etools/templates/hact/dashboard.html delete mode 100644 src/etools/templates/users/profile.html delete mode 100644 src/etools/templates/users/profile_change_done.html diff --git a/src/etools/applications/EquiTrack/templatetags/etools.py b/src/etools/applications/EquiTrack/templatetags/etools.py index a142e387a9..8becbf3df2 100644 --- a/src/etools/applications/EquiTrack/templatetags/etools.py +++ b/src/etools/applications/EquiTrack/templatetags/etools.py @@ -15,3 +15,37 @@ def etools_version(): @register.simple_tag def vision_url(): return settings.VISION_URL + + +@register.simple_tag(takes_context=True) +def show_country_select(context, profile): + + if not profile: + return '' + countries = profile.countries_available.all().order_by('name') # Country.objects.all() + + if 'opts' in context and context['opts'].app_label in settings.TENANT_APPS: + countries = countries.exclude(schema_name='public') + + html = '' + for country in countries: + if country == profile.country: + html += '' + else: + html += '' + + return mark_safe('') + + +@register.simple_tag(takes_context=True) +def tenant_model_filter(context, app): + if hasattr(context.request, 'tenant'): + tenant_app_labels = [tenant_app.split('.')[-1] for tenant_app in settings.TENANT_APPS] + return not (context.request.tenant.schema_name == 'public' and app['app_label'] in tenant_app_labels) + return True + + +@register.simple_tag() +def tenant_app_filter(app): + tenant_app_labels = [tenant_app.split('.')[-1] for tenant_app in settings.TENANT_APPS] + return app['app_label'] in tenant_app_labels diff --git a/src/etools/applications/partners/tests/test_userprofile_tags.py b/src/etools/applications/EquiTrack/tests/test_userprofile_tags.py similarity index 79% rename from src/etools/applications/partners/tests/test_userprofile_tags.py rename to src/etools/applications/EquiTrack/tests/test_userprofile_tags.py index 856527aca9..c83f7d7494 100644 --- a/src/etools/applications/partners/tests/test_userprofile_tags.py +++ b/src/etools/applications/EquiTrack/tests/test_userprofile_tags.py @@ -1,7 +1,7 @@ from mock import Mock +from etools.applications.EquiTrack.templatetags.etools import show_country_select from etools.applications.EquiTrack.tests.cases import BaseTenantTestCase -from etools.applications.partners.templatetags import userprofile_tags as tags from etools.applications.users.tests.factories import ProfileFactory @@ -13,10 +13,10 @@ def setUpTestData(cls): cls.profile.countries_available.add(cls.country) def test_no_profile(self): - self.assertEqual(tags.show_country_select({}, None), "") + self.assertEqual(show_country_select({}, None), "") def test_country_single(self): - res = tags.show_country_select({}, self.profile) + res = show_country_select({}, self.profile) self.assertEqual( res, '' diff --git a/src/etools/applications/partners/templatetags/__init__.py b/src/etools/applications/partners/templatetags/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/etools/applications/partners/templatetags/intervention_tags.py b/src/etools/applications/partners/templatetags/intervention_tags.py deleted file mode 100644 index ccb4127760..0000000000 --- a/src/etools/applications/partners/templatetags/intervention_tags.py +++ /dev/null @@ -1,48 +0,0 @@ -from django import template -from django.template.loader import render_to_string -from django.utils.datastructures import OrderedDict as SortedDict - -import tablib - -from etools.applications.partners.models import Intervention - -register = template.Library() - - -@register.simple_tag -def get_interventions(partner_id): - interventions = Intervention.objects.filter(agreement__partner__pk=partner_id) - - return render_to_string('admin/partners/interventions_table.html', {'interventions': interventions}) - - -@register.simple_tag -def show_dct(value): - - if not value: - return '' - - data = tablib.Dataset() - dct_summary = [] - - row = SortedDict() - - row['FC Ref'] = '' - row['Amount'] = '' - row['Liquidation Amount'] = '' - row['Outstanding Amount'] = '' - row['Amount Less than 3 Months'] = '' - row['Amount 3 to 6 Months'] = '' - row['Amount 6 to 9 Months'] = '' - row['Amount More than 9 Months'] = '' - - dct_summary.append(row) - - if dct_summary: - data.headers = dct_summary[0].keys() - for row in dct_summary: - data.append(row.values()) - - return data.html - - return '

No FR Set

' diff --git a/src/etools/applications/partners/templatetags/userprofile_tags.py b/src/etools/applications/partners/templatetags/userprofile_tags.py deleted file mode 100644 index 1069d8b06e..0000000000 --- a/src/etools/applications/partners/templatetags/userprofile_tags.py +++ /dev/null @@ -1,41 +0,0 @@ - -from django import template -from django.conf import settings - -from django.utils.safestring import mark_safe - -register = template.Library() - - -@register.simple_tag(takes_context=True) -def show_country_select(context, profile): - - if not profile: - return '' - countries = profile.countries_available.all().order_by('name') # Country.objects.all() - - if 'opts' in context and context['opts'].app_label in settings.TENANT_APPS: - countries = countries.exclude(schema_name='public') - - html = '' - for country in countries: - if country == profile.country: - html += '' - else: - html += '' - - return mark_safe('') - - -@register.simple_tag(takes_context=True) -def tenant_model_filter(context, app): - if hasattr(context.request, 'tenant'): - tenant_app_labels = [tenant_app.split('.')[-1] for tenant_app in settings.TENANT_APPS] - return not (context.request.tenant.schema_name == 'public' and app['app_label'] in tenant_app_labels) - return True - - -@register.simple_tag() -def tenant_app_filter(app): - tenant_app_labels = [tenant_app.split('.')[-1] for tenant_app in settings.TENANT_APPS] - return app['app_label'] in tenant_app_labels diff --git a/src/etools/applications/partners/tests/test_intervention_tags.py b/src/etools/applications/partners/tests/test_intervention_tags.py deleted file mode 100644 index 07617dafaa..0000000000 --- a/src/etools/applications/partners/tests/test_intervention_tags.py +++ /dev/null @@ -1,17 +0,0 @@ - -from etools.applications.EquiTrack.tests.cases import BaseTenantTestCase -from etools.applications.partners.templatetags import intervention_tags as tags -from etools.applications.partners.tests.factories import AgreementFactory, InterventionFactory, PartnerFactory - - -class TestGetInterventions(BaseTenantTestCase): - def test_get(self): - partner = PartnerFactory() - agreement = AgreementFactory(partner=partner) - intervention_1 = InterventionFactory(agreement=agreement) - intervention_2 = InterventionFactory(agreement=agreement) - intervention_3 = InterventionFactory() - res = tags.get_interventions(partner.pk) - self.assertIn(intervention_1.number, res) - self.assertIn(intervention_2.number, res) - self.assertNotIn(intervention_3.number, res) diff --git a/src/etools/applications/users/tests/test_views.py b/src/etools/applications/users/tests/test_views.py index 2a80dca8f8..7eefa5ad59 100644 --- a/src/etools/applications/users/tests/test_views.py +++ b/src/etools/applications/users/tests/test_views.py @@ -7,15 +7,12 @@ from django.contrib.auth.models import Permission from django.urls import reverse - from rest_framework import status -from django_tenants.test.client import TenantClient from etools.applications.EquiTrack.tests.cases import BaseTenantTestCase from etools.applications.publics.tests.factories import PublicsBusinessAreaFactory from etools.applications.users.models import Group, UserProfile -from etools.applications.users.tests.factories import (CountryFactory, GroupFactory, - OfficeFactory, UserFactory,) +from etools.applications.users.tests.factories import CountryFactory, GroupFactory, OfficeFactory, UserFactory class TestUserAuthAPIView(BaseTenantTestCase): @@ -294,30 +291,6 @@ def test_get_not_found(self): self.assertEqual(response.data, {}) -class TestProfileEdit(BaseTenantTestCase): - @classmethod - def setUpTestData(cls): - cls.client = TenantClient(cls.tenant) - - def setUp(self): - super().setUp() - self.url = reverse("users:user_profile") - - def test_get_non_staff(self): - user = UserFactory() - self.client.force_login(user) - response = self.client.get(self.url) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertTemplateUsed(response, "users/profile.html") - - def test_get_staff(self): - user = UserFactory(is_staff=True) - self.client.force_login(user) - response = self.client.get(self.url) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertTemplateUsed(response, "users/profile.html") - - class TestGroupViewSet(BaseTenantTestCase): @classmethod def setUpTestData(cls): diff --git a/src/etools/applications/users/urls.py b/src/etools/applications/users/urls.py index 531e0899f6..f3adc4cba5 100644 --- a/src/etools/applications/users/urls.py +++ b/src/etools/applications/users/urls.py @@ -1,8 +1,12 @@ from django.conf.urls import url -from django.views.generic import TemplateView -from etools.applications.users.views import (ChangeUserCountryView, MyProfileAPIView, ProfileEdit, - StaffUsersView, UserAuthAPIView, UsersDetailAPIView,) +from etools.applications.users.views import ( + ChangeUserCountryView, + MyProfileAPIView, + StaffUsersView, + UserAuthAPIView, + UsersDetailAPIView, +) app_name = 'users' urlpatterns = ( @@ -12,12 +16,4 @@ url(r'^api/$', StaffUsersView.as_view()), url(r'^api/(?P\d+)/$', UsersDetailAPIView.as_view(http_method_names=['get']), name="user-detail"), url(r'^myprofile/$', MyProfileAPIView.as_view(), name="myprofile-detail"), - - # user profile - url(r'^profile_view/$', ProfileEdit.as_view(), name='user_profile'), - - url(r'^profile_view/complete/$', - TemplateView.as_view( - template_name='users/profile_change_done.html'), - name='profile_complete'), ) diff --git a/src/etools/applications/users/views.py b/src/etools/applications/users/views.py index 877ef67808..ea9cb92e58 100644 --- a/src/etools/applications/users/views.py +++ b/src/etools/applications/users/views.py @@ -3,9 +3,8 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from django.core.exceptions import ValidationError as DjangoValidationError -from django.db import connection from django.http import HttpResponseForbidden, HttpResponseRedirect -from django.views.generic import FormView, RedirectView +from django.views.generic import RedirectView from django.views.generic.detail import DetailView from rest_framework import mixins, status, viewsets @@ -17,7 +16,6 @@ from etools.applications.audit.models import Auditor from etools.applications.tpm.models import ThirdPartyMonitor -from etools.applications.users.forms import ProfileForm from etools.applications.users.models import Country, Office, UserProfile from etools.applications.users.serializers import ( CountrySerializer, @@ -200,44 +198,6 @@ def retrieve(self, request, pk=None): ) -class ProfileEdit(FormView): - - template_name = 'users/profile.html' - form_class = ProfileForm - success_url = 'complete' - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context.update({ - 'office_list': connection.tenant.offices.all().order_by('name'), - }) - return context - - def form_valid(self, form): - # This method is called when valid form data has been POSTed. - # It should return an HttpResponse. - profile, created = UserProfile.objects.get_or_create( - user=self.request.user - ) - profile.office = form.cleaned_data['office'] - profile.job_title = form.cleaned_data['job_title'] - profile.phone_number = form.cleaned_data['phone_number'] - profile.save() - return super().form_valid(form) - - def get_initial(self): - """ Returns the initial data to use for forms on this view. """ - initial = super().get_initial() - try: - profile = self.request.user.profile - initial['office'] = profile.office - initial['job_title'] = profile.job_title - initial['phone_number'] = profile.phone_number - except UserProfile.DoesNotExist: - pass - return initial - - class GroupViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, diff --git a/src/etools/applications/users/views_v2.py b/src/etools/applications/users/views_v2.py index 0f109c7ed9..97915da8ff 100644 --- a/src/etools/applications/users/views_v2.py +++ b/src/etools/applications/users/views_v2.py @@ -47,10 +47,6 @@ class UsersDetailAPIView(v1.UsersDetailAPIView): """Stub for UsersDetailAPIView""" -class ProfileEdit(v1.ProfileEdit): - """Stub for ProfileEdit""" - - class GroupViewSet(v1.GroupViewSet): """Stub for GroupViewSet""" diff --git a/src/etools/config/settings/base.py b/src/etools/config/settings/base.py index 6fc0a57c02..1f29597e78 100644 --- a/src/etools/config/settings/base.py +++ b/src/etools/config/settings/base.py @@ -225,7 +225,6 @@ def get_from_secrets_or_env(var_name, default=None): 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ normpath(join(PACKAGE_ROOT, 'templates')), - normpath(join(PACKAGE_ROOT, 'templates', 'frontend')) ], 'APP_DIRS': False, # False because we set loaders manually below 'OPTIONS': { diff --git a/src/etools/templates/404.html b/src/etools/templates/404.html index bdb63a4a9e..828d8e99e1 100644 --- a/src/etools/templates/404.html +++ b/src/etools/templates/404.html @@ -1,30 +1,30 @@ -{% extends "base.html" %} - -{% block body %} -
- -
- -
-

404

- -

Page not found

-
- -

We're having trouble loading the page you are looking for.

- {% for message in messages %} -

{{ message }}

- {% endfor %} - -
- -
- -
-
-
- -
-{% endblock %} +{% extends "base_admin.html" %} + +{% block body %} +
+ +
+ +
+

404

+ +

Page not found

+
+ +

We're having trouble loading the page you are looking for.

+ {% for message in messages %} +

{{ message }}

+ {% endfor %} + +
+ +
+ +
+
+
+ +
+{% endblock %} diff --git a/src/etools/templates/500.html b/src/etools/templates/500.html index 1e4ad2bcb1..b94ef60cbe 100644 --- a/src/etools/templates/500.html +++ b/src/etools/templates/500.html @@ -1,89 +1,28 @@ - - - - - - - - - System Error - - - - - - - - - - - - - - - - - - - - - -
- -
- -
-

500

- -

Something went wrong.

-
- -

Our engineers have have been notified and will address the issue shortly

- - -
- -
- - - - - - - - -{% extends "base.html" %} - -{% block body %} -
- -
- -
-

500

- -

Something went wrong.

-
- -

Our engineers have have been notified and will address the issue shortly

- -
- -
- -
-
-
- -
-{% endblock %} - +{% extends "base_admin.html" %} + +{% block body %} +
+ +
+ +
+

500

+ +

Something went wrong.

+
+ +

Our engineers have have been notified and will address the issue shortly

+ +
+ +
+ +
+
+
+ +
+{% endblock %} + diff --git a/src/etools/templates/admin/base_site.html b/src/etools/templates/admin/base_site.html index 324f2f51c5..c05342c1a4 100644 --- a/src/etools/templates/admin/base_site.html +++ b/src/etools/templates/admin/base_site.html @@ -1,6 +1,6 @@ {% extends "admin/base.html" %} {% load i18n static %} -{% load userprofile_tags etools %} +{% load etools %} {% block extrahead %} diff --git a/src/etools/templates/admin/index.html b/src/etools/templates/admin/index.html index 49895cdd10..dbd91d9539 100644 --- a/src/etools/templates/admin/index.html +++ b/src/etools/templates/admin/index.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_static userprofile_tags %} +{% load i18n admin_static etools %} {% block extrastyle %}{{ block.super }}{% endblock %} diff --git a/src/etools/templates/admin/partners/assurance_table.html b/src/etools/templates/admin/partners/assurance_table.html deleted file mode 100644 index 7103be6a2b..0000000000 --- a/src/etools/templates/admin/partners/assurance_table.html +++ /dev/null @@ -1,104 +0,0 @@ -{% load i18n admin_static admin_modify %} - -

HACT assurance plan overview

-
- - - - - - - - - - - - - - - - - - - - {% with reqs=original.hact_min_requirements %} - - - - - - - - - {% endwith %} - -
Cash transfersRiskProgrammatic monitoring visitsSpot-ChecksAudit
- $ cash transferred (current year) -
$ planned cash transfers (current year) -
Total cash transfers (current CP cycle) - Risk rating -
Type of assessment -
- Done -
Minimum Requirements -
- Done -
Minimum Requirements -
- Done -
Required -
- {{ original.total_ct_cy }} -
{{ original.hact_values.planned_cash_transfer }} -
{{ original.total_ct_cp }} - {{ original.rating }} -
{{ original.type_of_assessment }} -
- {{ original.hact_values.programmatic_visits }} -
{{ reqs.programme_visits }} -
- {{ original.hact_values.spot_checks }} -
{{ reqs.spot_checks }} -
- {{ original.hact_values.audits_done }} -
{{ original.hact_values.audits_mr }} -
- -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# {% for intervention in original.documents.all %}#} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# {% endfor %}#} -{# #} -{#
InterventionCash transfersProgrammatic monitoring visitsSpot-Checks
{{ intervention.reference_number }}#} -{# {{ intervention.actual_cash_transferred }}#} -{#
{{ intervention.planned_cash_transfers }}#} -{#
#} -{# {{ intervention.total_cash_transferred }}#} -{# #} -{# {{ intervention.programmatic_visits }}#} -{# #} -{# {{ intervention.spot_checks }}#} -{#
#} - -
- - \ No newline at end of file diff --git a/src/etools/templates/admin/partners/government_funding.html b/src/etools/templates/admin/partners/government_funding.html deleted file mode 100644 index 8fc220abde..0000000000 --- a/src/etools/templates/admin/partners/government_funding.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load i18n admin_static admin_modify %} -{% load intervention_tags %} - -

Intervention implementation status

-
- {% autoescape off %} {% show_government_funding object_id %}{% endautoescape %} -
- -{#

DCTs

#} -{#
#} -{# {% autoescape off %} {% show_dct object_id %}{% endautoescape %}#} -{#
#} - - \ No newline at end of file diff --git a/src/etools/templates/admin/partners/interventions_inline.html b/src/etools/templates/admin/partners/interventions_inline.html deleted file mode 100644 index e9e8326701..0000000000 --- a/src/etools/templates/admin/partners/interventions_inline.html +++ /dev/null @@ -1,32 +0,0 @@ -{% load i18n admin_static admin_modify %} -{% load intervention_tags %} - -

Interventions Inline

-
- - - - - - - - - - - - - - - - {% autoescape off %} {% get_interventions object_id %} {% endautoescape %} - -
Reference NumberStatusStart DateEnd DateSectorsTitleTotal Budget
- - -
- - \ No newline at end of file diff --git a/src/etools/templates/admin/partners/interventions_table.html b/src/etools/templates/admin/partners/interventions_table.html deleted file mode 100644 index 2705e13549..0000000000 --- a/src/etools/templates/admin/partners/interventions_table.html +++ /dev/null @@ -1,29 +0,0 @@ -{% for i in interventions %} - - - {{ i.number }} - - - {{ i.status }} - - - {{ i.start }} - - - {{ i.end }} - - - {% for s in i.sections.all %} - {{ s.section.name }}, - {% endfor %} - - - {{ i.title }} - - - {{ i.total_unicef_cash }} - - - - -{% endfor %} \ No newline at end of file diff --git a/src/etools/templates/base.html b/src/etools/templates/base.html deleted file mode 100644 index aac89902e7..0000000000 --- a/src/etools/templates/base.html +++ /dev/null @@ -1,327 +0,0 @@ -{% load userprofile_tags %} - - - - - - - - - - - - eTools - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% block extra_head %} - {% endblock %} - - - -{% block body %} - - - -
- - {% block header %} - - {% endblock %} - - - {% block sidebar %} - - {% endblock %} - - - - - {% block content %} - - {% endblock content %} - - - - {% block footer %} -
-
- -
-
- © Copyright 2015 UNICEF. All Rights Reserved. Country: {{ request.tenant.name }} -
- -
- {% endblock footer %} - - -
-{% endblock %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{% block extra_js %} -{% endblock %} - - - - diff --git a/src/etools/templates/frontend/account/account_inactive.html b/src/etools/templates/frontend/account/account_inactive.html deleted file mode 100644 index 3347f4fd8c..0000000000 --- a/src/etools/templates/frontend/account/account_inactive.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Account Inactive" %}{% endblock %} - -{% block content %} -

{% trans "Account Inactive" %}

- -

{% trans "This account is inactive." %}

-{% endblock %} diff --git a/src/etools/templates/frontend/account/base.html b/src/etools/templates/frontend/account/base.html deleted file mode 100644 index d7cefebf52..0000000000 --- a/src/etools/templates/frontend/account/base.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "base_polymer.html" %} - - -{% block toolbar %} - - - -{% endblock toolbar %} \ No newline at end of file diff --git a/src/etools/templates/frontend/account/email.html b/src/etools/templates/frontend/account/email.html deleted file mode 100644 index d68c8d631e..0000000000 --- a/src/etools/templates/frontend/account/email.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Account" %}{% endblock %} - -{% block content %} -

{% trans "E-mail Addresses" %}

-{% if user.emailaddress_set.all %} -

{% trans 'The following e-mail addresses are associated with your account:' %}

- - - -{% else %} -

{% trans 'Warning:'%} {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}

- -{% endif %} - - -

{% trans "Add E-mail Address" %}

- -
- {% csrf_token %} - {{ form.as_p}} - -
- -{% endblock %} - - -{% block extra_body %} - -{% endblock %} diff --git a/src/etools/templates/frontend/account/email/email_confirmation_message.txt b/src/etools/templates/frontend/account/email/email_confirmation_message.txt deleted file mode 100644 index 4bd4a7e797..0000000000 --- a/src/etools/templates/frontend/account/email/email_confirmation_message.txt +++ /dev/null @@ -1,8 +0,0 @@ -{% load account %}{% user_display user as user_display %}{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Hello from {{ site_name }}! - -You're receiving this e-mail because user {{ user_display }} at {{ site_domain }} has given yours as an e-mail address to connect their account. - -To confirm this is correct, go to {{ activate_url }} -{% endblocktrans %}{% endautoescape %} -{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you from {{ site_name }}! -{{ site_domain }}{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/email/email_confirmation_signup_message.txt b/src/etools/templates/frontend/account/email/email_confirmation_signup_message.txt deleted file mode 100644 index 9996f7e50d..0000000000 --- a/src/etools/templates/frontend/account/email/email_confirmation_signup_message.txt +++ /dev/null @@ -1 +0,0 @@ -{% include "account/email/email_confirmation_message.txt" %} diff --git a/src/etools/templates/frontend/account/email/email_confirmation_signup_subject.txt b/src/etools/templates/frontend/account/email/email_confirmation_signup_subject.txt deleted file mode 100644 index 4c85ebb9f8..0000000000 --- a/src/etools/templates/frontend/account/email/email_confirmation_signup_subject.txt +++ /dev/null @@ -1 +0,0 @@ -{% include "account/email/email_confirmation_subject.txt" %} diff --git a/src/etools/templates/frontend/account/email/email_confirmation_subject.txt b/src/etools/templates/frontend/account/email/email_confirmation_subject.txt deleted file mode 100644 index b0a876f5ba..0000000000 --- a/src/etools/templates/frontend/account/email/email_confirmation_subject.txt +++ /dev/null @@ -1,4 +0,0 @@ -{% load i18n %} -{% autoescape off %} -{% blocktrans %}Please Confirm Your E-mail Address{% endblocktrans %} -{% endautoescape %} diff --git a/src/etools/templates/frontend/account/email/password_reset_key_message.txt b/src/etools/templates/frontend/account/email/password_reset_key_message.txt deleted file mode 100644 index b695b67588..0000000000 --- a/src/etools/templates/frontend/account/email/password_reset_key_message.txt +++ /dev/null @@ -1,11 +0,0 @@ -{% load i18n %}{% blocktrans with site_name=site.name site_domain=site.domain %}Hello from {{ site_name }}! - -You're receiving this e-mail because you or someone else has requested a password for your user account at {{ site_domain }}. -It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %} - -{{ password_reset_url }} - -{% if username %}{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %} - -{% endif %}{% blocktrans with site_name=site.name site_domain=site.domain %}Thank you for using {{ site_name }}! -{{ site_domain }}{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/email/password_reset_key_subject.txt b/src/etools/templates/frontend/account/email/password_reset_key_subject.txt deleted file mode 100644 index aa80d11443..0000000000 --- a/src/etools/templates/frontend/account/email/password_reset_key_subject.txt +++ /dev/null @@ -1,4 +0,0 @@ -{% load i18n %} -{% autoescape off %} -{% blocktrans %}Password Reset E-mail{% endblocktrans %} -{% endautoescape %} \ No newline at end of file diff --git a/src/etools/templates/frontend/account/email_confirm.html b/src/etools/templates/frontend/account/email_confirm.html deleted file mode 100644 index ac0891b5f5..0000000000 --- a/src/etools/templates/frontend/account/email_confirm.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} - - -{% block content %} -

{% trans "Confirm E-mail Address" %}

- -{% if confirmation %} - -{% user_display confirmation.email_address.user as user_display %} - -

{% blocktrans with confirmation.email_address.email as email %}Please confirm that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktrans %}

- -
-{% csrf_token %} - -
- -{% else %} - -{% url 'account_email' as email_url %} - -

{% blocktrans %}This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request.{% endblocktrans %}

- -{% endif %} - -{% endblock %} diff --git a/src/etools/templates/frontend/account/email_confirmed.html b/src/etools/templates/frontend/account/email_confirmed.html deleted file mode 100644 index 4280c9c31d..0000000000 --- a/src/etools/templates/frontend/account/email_confirmed.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} - - -{% block content %} - -

{% trans "Confirm E-mail Address" %}

- -{% user_display confirmation.email_address.user as user_display %} - -

{% blocktrans with confirmation.email_address.email as email %}You have confirmed that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktrans %}

- -{% endblock %} diff --git a/src/etools/templates/frontend/account/login.html b/src/etools/templates/frontend/account/login.html deleted file mode 100644 index 274d06711f..0000000000 --- a/src/etools/templates/frontend/account/login.html +++ /dev/null @@ -1,136 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account socialaccount %} - -{% block head_title %}{% trans "Partner Sign In" %}{% endblock %} - -{% block extra_head %} - - -{% endblock %} - -{% block content %} - -{% get_providers as socialaccount_providers %} - -{% if socialaccount_providers %} - -
- -

{% blocktrans with site.name as site_name %}Please sign in with one - of your existing third party accounts:{% endblocktrans %}

- -
- -
    - {% include "socialaccount/snippets/provider_list.html" with process="login" %} -
-
-
-
-{% endif %} - - - -
- {% csrf_token %} - {% for error in form.non_field_errors %} - {% if error %} - - - {{ error }} - - {% endif %} - {% endfor %} - {{ form.NON_FIELD_ERRORS }} - {% for field in form %} - - - - {% if field.field.widget.input_type %} - - - - - {% else %} -
- {{ field.label }} - - {% endif %} - {% if field.help_text %} -

{{ field.help_text|safe }}

- {% endif %} - - {% endfor %} - - {% if redirect_field_value %} - - {% endif %} -
- - - -
- {% trans "Forgot Password?" %} - - {% trans "Sign In" %} -
- -
- - If you never logged in before, and you don't yet have a password, then please - Set your Password first. -
- - - - - - - - -{% endblock %} - -{% block extra_js %} - -{% endblock %} - diff --git a/src/etools/templates/frontend/account/logout.html b/src/etools/templates/frontend/account/logout.html deleted file mode 100644 index 2549a9018d..0000000000 --- a/src/etools/templates/frontend/account/logout.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Sign Out" %}{% endblock %} - -{% block content %} -

{% trans "Sign Out" %}

- -

{% trans 'Are you sure you want to sign out?' %}

- -
- {% csrf_token %} - {% if redirect_field_value %} - - {% endif %} - -
- - -{% endblock %} diff --git a/src/etools/templates/frontend/account/messages/cannot_delete_primary_email.txt b/src/etools/templates/frontend/account/messages/cannot_delete_primary_email.txt deleted file mode 100644 index de555712eb..0000000000 --- a/src/etools/templates/frontend/account/messages/cannot_delete_primary_email.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}You cannot remove your primary e-mail address ({{email}}).{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/email_confirmation_sent.txt b/src/etools/templates/frontend/account/messages/email_confirmation_sent.txt deleted file mode 100644 index 7a526f8bff..0000000000 --- a/src/etools/templates/frontend/account/messages/email_confirmation_sent.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}Confirmation e-mail sent to {{email}}.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/email_confirmed.txt b/src/etools/templates/frontend/account/messages/email_confirmed.txt deleted file mode 100644 index 3427a4d849..0000000000 --- a/src/etools/templates/frontend/account/messages/email_confirmed.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}You have confirmed {{email}}.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/email_deleted.txt b/src/etools/templates/frontend/account/messages/email_deleted.txt deleted file mode 100644 index 5cf7cf91a5..0000000000 --- a/src/etools/templates/frontend/account/messages/email_deleted.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}Removed e-mail address {{email}}.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/logged_in.txt b/src/etools/templates/frontend/account/messages/logged_in.txt deleted file mode 100644 index f49248a7da..0000000000 --- a/src/etools/templates/frontend/account/messages/logged_in.txt +++ /dev/null @@ -1,4 +0,0 @@ -{% load account %} -{% load i18n %} -{% user_display user as name %} -{% blocktrans %}Successfully signed in as {{name}}.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/logged_out.txt b/src/etools/templates/frontend/account/messages/logged_out.txt deleted file mode 100644 index 2cd4627d88..0000000000 --- a/src/etools/templates/frontend/account/messages/logged_out.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}You have signed out.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/password_changed.txt b/src/etools/templates/frontend/account/messages/password_changed.txt deleted file mode 100644 index e01766b1fb..0000000000 --- a/src/etools/templates/frontend/account/messages/password_changed.txt +++ /dev/null @@ -1,3 +0,0 @@ -{% load i18n %} -{% blocktrans %}Password successfully changed.{% endblocktrans %} - diff --git a/src/etools/templates/frontend/account/messages/password_set.txt b/src/etools/templates/frontend/account/messages/password_set.txt deleted file mode 100644 index e36cef86a1..0000000000 --- a/src/etools/templates/frontend/account/messages/password_set.txt +++ /dev/null @@ -1,3 +0,0 @@ -{% load i18n %} -{% blocktrans %}Password successfully set.{% endblocktrans %} - diff --git a/src/etools/templates/frontend/account/messages/primary_email_set.txt b/src/etools/templates/frontend/account/messages/primary_email_set.txt deleted file mode 100644 index b6a70dd6df..0000000000 --- a/src/etools/templates/frontend/account/messages/primary_email_set.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}Primary e-mail address set.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/messages/unverified_primary_email.txt b/src/etools/templates/frontend/account/messages/unverified_primary_email.txt deleted file mode 100644 index 9c9d0d8708..0000000000 --- a/src/etools/templates/frontend/account/messages/unverified_primary_email.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}Your primary e-mail address must be verified.{% endblocktrans %} diff --git a/src/etools/templates/frontend/account/password_change.html b/src/etools/templates/frontend/account/password_change.html deleted file mode 100644 index b536579171..0000000000 --- a/src/etools/templates/frontend/account/password_change.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block content %} -

{% trans "Change Password" %}

- -
- {% csrf_token %} - {{ form.as_p }} - -
-{% endblock %} diff --git a/src/etools/templates/frontend/account/password_reset.html b/src/etools/templates/frontend/account/password_reset.html deleted file mode 100644 index adb7e62954..0000000000 --- a/src/etools/templates/frontend/account/password_reset.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Password Reset" %}{% endblock %} - -{% block content %} - -

{% trans "Password Reset" %}

- {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} - -

Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it.

- -
- {% csrf_token %} - {{ form.as_p }} - -
- -

{% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}

-{% endblock %} diff --git a/src/etools/templates/frontend/account/password_reset_done.html b/src/etools/templates/frontend/account/password_reset_done.html deleted file mode 100644 index e90504f718..0000000000 --- a/src/etools/templates/frontend/account/password_reset_done.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %}{% trans "Password Reset" %}{% endblock %} - -{% block content %} -

{% trans "Password Reset" %}

- - {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} - -

{% blocktrans %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

-{% endblock %} diff --git a/src/etools/templates/frontend/account/password_reset_from_key.html b/src/etools/templates/frontend/account/password_reset_from_key.html deleted file mode 100644 index dd45b263e4..0000000000 --- a/src/etools/templates/frontend/account/password_reset_from_key.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block content %} -

{% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}

- - {% if token_fail %} - {% url 'account_reset_password' as passwd_reset_url %} -

{% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a new password reset.{% endblocktrans %}

- {% else %} - {% if form %} -
- {% csrf_token %} - {{ form.as_p }} - -
- {% else %} -

{% trans 'Your password is now changed.' %}

- {% endif %} - {% endif %} -{% endblock %} diff --git a/src/etools/templates/frontend/account/password_reset_from_key_done.html b/src/etools/templates/frontend/account/password_reset_from_key_done.html deleted file mode 100644 index 85641c2ec1..0000000000 --- a/src/etools/templates/frontend/account/password_reset_from_key_done.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% block head_title %}{% trans "Change Password" %}{% endblock %} - -{% block content %} -

{% trans "Change Password" %}

-

{% trans 'Your password is now changed.' %}

-{% endblock %} diff --git a/src/etools/templates/frontend/account/password_set.html b/src/etools/templates/frontend/account/password_set.html deleted file mode 100644 index f5615720e5..0000000000 --- a/src/etools/templates/frontend/account/password_set.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Set Password" %}{% endblock %} - -{% block content %} -

{% trans "Set Password" %}

- -
- {% csrf_token %} - {{ form.as_p }} - -
-{% endblock %} diff --git a/src/etools/templates/frontend/account/signup.html b/src/etools/templates/frontend/account/signup.html deleted file mode 100644 index 8b53b442e9..0000000000 --- a/src/etools/templates/frontend/account/signup.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Signup" %}{% endblock %} - -{% block content %} -

{% trans "Sign Up" %}

- -

{% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}

- - - -{% endblock %} diff --git a/src/etools/templates/frontend/account/signup_closed.html b/src/etools/templates/frontend/account/signup_closed.html deleted file mode 100644 index bc83950648..0000000000 --- a/src/etools/templates/frontend/account/signup_closed.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Sign Up Closed" %}{% endblock %} - -{% block content %} -

{% trans "Sign Up Closed" %}

- -

{% trans "We are sorry, but the sign up is currently closed." %}

-{% endblock %} diff --git a/src/etools/templates/frontend/account/snippets/already_logged_in.html b/src/etools/templates/frontend/account/snippets/already_logged_in.html deleted file mode 100644 index 00799f0013..0000000000 --- a/src/etools/templates/frontend/account/snippets/already_logged_in.html +++ /dev/null @@ -1,5 +0,0 @@ -{% load i18n %} -{% load account %} - -{% user_display user as user_display %} -

{% trans "Note" %}: {% blocktrans %}you are already logged in as {{ user_display }}.{% endblocktrans %}

diff --git a/src/etools/templates/frontend/account/verification_sent.html b/src/etools/templates/frontend/account/verification_sent.html deleted file mode 100644 index 5f7133194d..0000000000 --- a/src/etools/templates/frontend/account/verification_sent.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} - -{% block content %} -

{% trans "Verify Your E-mail Address" %}

- -

{% blocktrans %}We have sent an e-mail to you for verification. Follow the link provided to finalize the signup process. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

- -{% endblock %} diff --git a/src/etools/templates/frontend/account/verified_email_required.html b/src/etools/templates/frontend/account/verified_email_required.html deleted file mode 100644 index 8115c4894f..0000000000 --- a/src/etools/templates/frontend/account/verified_email_required.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} - -{% block content %} -

{% trans "Verify Your E-mail Address" %}

- -{% url 'account_email' as email_url %} - -

{% blocktrans %}This part of the site requires us to verify that -you are who you claim to be. For this purpose, we require that you -verify ownership of your e-mail address. {% endblocktrans %}

- -

{% blocktrans %}We have sent an e-mail to you for -verification. Please click on the link inside this e-mail. Please -contact us if you do not receive it within a few minutes.{% endblocktrans %}

- -

{% blocktrans %}Note: you can still change your e-mail address.{% endblocktrans %}

- - -{% endblock %} diff --git a/src/etools/templates/frontend/base_polymer.html b/src/etools/templates/frontend/base_polymer.html deleted file mode 100644 index 686b786d92..0000000000 --- a/src/etools/templates/frontend/base_polymer.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - UNICEF eTools - Partners - - - - - - - - - - - - - - - - - - -{% block extra_head %} -{% endblock %} - - - - - - - - - {% block extra_js %} - {% endblock %} - - - diff --git a/src/etools/templates/frontend/choose_login.html b/src/etools/templates/frontend/choose_login.html deleted file mode 100644 index 632247cb9f..0000000000 --- a/src/etools/templates/frontend/choose_login.html +++ /dev/null @@ -1,106 +0,0 @@ -{% extends "login_base.html" %} - - -{% block extra_head %} - -{% endblock %} - -{% block toolbar %} -
- -
Choose your login
-
-{% endblock toolbar %} - -{% block content %} -
-
- -
-
-

Partner Login is under construction.

-
-
- -
- -
-
-
-
-{% endblock content %} diff --git a/src/etools/templates/frontend/login_base.html b/src/etools/templates/frontend/login_base.html deleted file mode 100644 index bed086844a..0000000000 --- a/src/etools/templates/frontend/login_base.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - UNICEF eTools - Partners - - - - - - - - - -{% block extra_head %} -{% endblock %} - - - - - - - - {% block toolbar %} - {% endblock toolbar %} - - - {% block content %} - {% endblock content %} - {% block extra_js %} - {% endblock %} - - - diff --git a/src/etools/templates/frontend/management/management.html b/src/etools/templates/frontend/management/management.html deleted file mode 100755 index b9da3fdae1..0000000000 --- a/src/etools/templates/frontend/management/management.html +++ /dev/null @@ -1 +0,0 @@ -UNICEF eTools - Management \ No newline at end of file diff --git a/src/etools/templates/frontend/partner_loginfailed.html b/src/etools/templates/frontend/partner_loginfailed.html deleted file mode 100644 index c9446fc55b..0000000000 --- a/src/etools/templates/frontend/partner_loginfailed.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - -The email: "{{ email }}" you are trying to use is not associated with any account. -
-Please let your employer know of this issue. - - diff --git a/src/etools/templates/frontend/socialaccount/authentication_error.html b/src/etools/templates/frontend/socialaccount/authentication_error.html deleted file mode 100644 index 03002955b6..0000000000 --- a/src/etools/templates/frontend/socialaccount/authentication_error.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "socialaccount/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Social Network Login Failure" %}{% endblock %} - -{% block content %} -

{% trans "Social Network Login Failure" %}

- -

{% trans "An error occurred while attempting to login via your social network account." %}

-{% endblock %} diff --git a/src/etools/templates/frontend/socialaccount/base.html b/src/etools/templates/frontend/socialaccount/base.html deleted file mode 100644 index 18530d12e5..0000000000 --- a/src/etools/templates/frontend/socialaccount/base.html +++ /dev/null @@ -1,2 +0,0 @@ -{% extends "account/base.html" %} - diff --git a/src/etools/templates/frontend/socialaccount/connections.html b/src/etools/templates/frontend/socialaccount/connections.html deleted file mode 100644 index f7c2729f15..0000000000 --- a/src/etools/templates/frontend/socialaccount/connections.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "socialaccount/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Account Connections" %}{% endblock %} - -{% block content %} -

{% trans "Account Connections" %}

- -{% if form.accounts %} -

{% blocktrans %}You can sign in to your account using any of the following third party accounts:{% endblocktrans %}

- - -
-{% csrf_token %} - -
-{% if form.non_field_errors %} -
{{ form.non_field_errors }}
-{% endif %} - -{% for base_account in form.accounts %} -{% with base_account.get_provider_account as account %} -
- -
-{% endwith %} -{% endfor %} - -
- -
- -
- -
- -{% else %} -

{% trans 'You currently have no social network accounts connected to this account.' %}

-{% endif %} - -

{% trans 'Add a 3rd Party Account' %}

- -
    -{% include "socialaccount/snippets/provider_list.html" with process="connect" %} -
- -{% include "socialaccount/snippets/login_extra.html" %} - -{% endblock %} diff --git a/src/etools/templates/frontend/socialaccount/login_cancelled.html b/src/etools/templates/frontend/socialaccount/login_cancelled.html deleted file mode 100644 index 8d76786569..0000000000 --- a/src/etools/templates/frontend/socialaccount/login_cancelled.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "socialaccount/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Login Cancelled" %}{% endblock %} - -{% block content %} - -

{% trans "Login Cancelled" %}

- -{% url 'account_login' as login_url %} - -

{% blocktrans %}You decided to cancel logging in to our site using one of your existing accounts. If this was a mistake, please proceed to sign in.{% endblocktrans %}

- -{% endblock %} diff --git a/src/etools/templates/frontend/socialaccount/messages/account_connected.txt b/src/etools/templates/frontend/socialaccount/messages/account_connected.txt deleted file mode 100644 index be6aa60f22..0000000000 --- a/src/etools/templates/frontend/socialaccount/messages/account_connected.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}The social account has been connected.{% endblocktrans %} diff --git a/src/etools/templates/frontend/socialaccount/messages/account_connected_other.txt b/src/etools/templates/frontend/socialaccount/messages/account_connected_other.txt deleted file mode 100644 index e90f6ccc82..0000000000 --- a/src/etools/templates/frontend/socialaccount/messages/account_connected_other.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}The social account is already connected to a different account.{% endblocktrans %} diff --git a/src/etools/templates/frontend/socialaccount/messages/account_disconnected.txt b/src/etools/templates/frontend/socialaccount/messages/account_disconnected.txt deleted file mode 100644 index fd43f30e07..0000000000 --- a/src/etools/templates/frontend/socialaccount/messages/account_disconnected.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load i18n %} -{% blocktrans %}The social account has been disconnected.{% endblocktrans %} diff --git a/src/etools/templates/frontend/socialaccount/signup.html b/src/etools/templates/frontend/socialaccount/signup.html deleted file mode 100644 index caa2de2e06..0000000000 --- a/src/etools/templates/frontend/socialaccount/signup.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "socialaccount/base.html" %} - -{% load i18n %} - -{% block head_title %}{% trans "Signup" %}{% endblock %} - -{% block content %} -

{% trans "Sign Up" %}

- -

{% blocktrans with provider_name=account.get_provider.name site_name=site.name %}You are about to use your {{provider_name}} account to login to -{{site_name}}. As a final step, please complete the following form:{% endblocktrans %}

- - - -{% endblock %} diff --git a/src/etools/templates/frontend/socialaccount/snippets/login_extra.html b/src/etools/templates/frontend/socialaccount/snippets/login_extra.html deleted file mode 100644 index f2c52256e3..0000000000 --- a/src/etools/templates/frontend/socialaccount/snippets/login_extra.html +++ /dev/null @@ -1,4 +0,0 @@ -{% load socialaccount %} - -{% providers_media_js %} - diff --git a/src/etools/templates/frontend/socialaccount/snippets/provider_list.html b/src/etools/templates/frontend/socialaccount/snippets/provider_list.html deleted file mode 100644 index a5e3b02702..0000000000 --- a/src/etools/templates/frontend/socialaccount/snippets/provider_list.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load socialaccount %} - -{% get_providers as socialaccount_providers %} - -{% for provider in socialaccount_providers %} -{% if provider.id == "openid" %} -{% for brand in provider.get_brands %} -
  • - {{brand.name}} -
  • -{% endfor %} -{% endif %} -
  • - {{provider.name}} -
  • -{% endfor %} - diff --git a/src/etools/templates/hact/dashboard.html b/src/etools/templates/hact/dashboard.html deleted file mode 100644 index 808bdbec04..0000000000 --- a/src/etools/templates/hact/dashboard.html +++ /dev/null @@ -1,147 +0,0 @@ -{% extends "base.html" %} -{% load humanize %} - -{% block extra_head %} - - - - - - -{% endblock %} - -{% block content %} - - - -
    -
    -
    -
    -
    -

    HACT Dashboard {% now 'Y' %}

    -
    -
    - -
    -
    -
    -
    -

    Assurance Activites

    -
    - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% for partner in partners %} - - {% with reqs=partner.hact_min_requirements %} - - - - - - - - - - - - - - - - - - - {% endwith %} - {% endfor %} - -
    #Implementing Partner (IP)Partner TypeShared IP?Micro assessmentCash transfersRisk RatingProgrammatic visitsSpot checksAuditsFlags for follow-up?
    Planned cash transfers (current year)To be done?Total (current CP cycle), USDActual( current Year ), USDPlannedMinimum ReqDoneMinimum ReqDoneMinimum ReqDone
    {{ forloop.counter }}{{ partner.name }}{{ partner.partner_type }}{{ partner.hact_values.planned_cash_transfer|floatformat:"0"|intcomma }}{{ partner.hact_values.micro_assessment_needed }}{% if partner.total_ct_cp %} - {{ partner.total_ct_cp|floatformat:"0"|intcomma }} - {% else %} - 0 - {% endif %} - {% if partner.total_ct_cy %} - {{ partner.total_ct_cy|floatformat:"0"|intcomma }} - {% else %} - 0 - {% endif %} - {{ partner.rating }}{{ partner.hact_values.planned_visits }}{{ reqs.programme_visits }}{{ partner.hact_values.programmatic_visits }}{{ reqs.spot_checks }}{{ partner.hact_values.spot_checks }}{{ partner.hact_values.audits_mr }}{{ partner.hact_values.audits_done }}{{ partner.hact_values.follow_up_flags }}
    - -
    -
    -
    -
    - -
    -
    - -{% endblock %} - - -{% block extra_js %} - - - - - - -{% endblock %} \ No newline at end of file diff --git a/src/etools/templates/no_country_found.html b/src/etools/templates/no_country_found.html index 419b204c4f..bb9e514988 100644 --- a/src/etools/templates/no_country_found.html +++ b/src/etools/templates/no_country_found.html @@ -1,4 +1,3 @@ - {% extends "login_base.html" %} @@ -49,7 +48,7 @@

    Hi {{ user }},


    Please contact the eTools focal point within your organization to help you gain access.

    -

    Please Log Out to reflect any updates in the future

    +

    Please Log Out to reflect any updates in the future

    {% endblock content %} diff --git a/src/etools/templates/users/profile.html b/src/etools/templates/users/profile.html deleted file mode 100644 index 26a4b063f4..0000000000 --- a/src/etools/templates/users/profile.html +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "base.html" %} -{#{% load humanize %}#} - -{% block body %} -{# #} -{# {% endblock content %} diff --git a/src/etools/templates/openid/base.html b/src/etools/templates/openid/base.html deleted file mode 100644 index 671d403c80..0000000000 --- a/src/etools/templates/openid/base.html +++ /dev/null @@ -1 +0,0 @@ -{% extends "socialaccount/base.html" %} diff --git a/src/etools/templates/openid/login.html b/src/etools/templates/openid/login.html deleted file mode 100644 index b27ee3714d..0000000000 --- a/src/etools/templates/openid/login.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "openid/base.html" %} - -{% load i18n %} - -{% block head_title %}OpenID Sign In{% endblock %} - -{% block content %} - -

    {% trans 'OpenID Sign In' %}

    - - - - -{% endblock %} From 49f7fc61a2c010de0e84488c942428a99dc0bda6 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Wed, 10 Apr 2019 14:03:07 -0400 Subject: [PATCH 39/79] added libxslt-dev --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a026a11d63..80f079e9ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,7 +48,9 @@ RUN apk add postgresql-client RUN apk add openssl \ ca-certificates \ libressl2.7-libcrypto \ - libmagic + libmagic \ + libxslt-dev + RUN apk add geos \ gdal --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ From 64b4cd09cdc31469e8d59e2c42dd970fd0bac05c Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Wed, 10 Apr 2019 14:03:07 -0400 Subject: [PATCH 40/79] added libxslt --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 80f079e9ba..8967499576 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,7 @@ RUN apk add openssl \ ca-certificates \ libressl2.7-libcrypto \ libmagic \ - libxslt-dev + libxslt RUN apk add geos \ gdal --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ From b8067de623c4171cb7ef18e63b3e88dd21028bf2 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 26 Mar 2019 11:00:39 -0400 Subject: [PATCH 41/79] clean management app --- src/etools/applications/management/README.md | 93 ----- src/etools/applications/management/admin.py | 11 - .../management/issues/__init__.py | 0 .../applications/management/issues/checks.py | 156 -------- .../management/issues/exceptions.py | 8 - .../management/issues/project_checks.py | 167 -------- .../management/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/check_issues.py | 10 - .../management/commands/recheck_issues.py | 10 - .../migrations/0002_auto_20190326_1500.py | 20 + src/etools/applications/management/models.py | 79 ---- src/etools/applications/management/tasks.py | 52 --- .../management/tests/factories.py | 12 - .../management/tests/test_commands.py | 36 -- .../management/tests/test_issue_checks.py | 253 ------------ .../tests/test_issue_project_checks.py | 359 ------------------ .../management/tests/test_models.py | 51 --- .../management/tests/test_tasks.py | 35 -- src/etools/applications/management/urls.py | 2 - .../management/views/tasks_endpoints.py | 7 +- .../applications/management/views/v1.py | 5 - 22 files changed, 21 insertions(+), 1345 deletions(-) delete mode 100644 src/etools/applications/management/README.md delete mode 100644 src/etools/applications/management/admin.py delete mode 100644 src/etools/applications/management/issues/__init__.py delete mode 100644 src/etools/applications/management/issues/checks.py delete mode 100644 src/etools/applications/management/issues/exceptions.py delete mode 100644 src/etools/applications/management/issues/project_checks.py delete mode 100644 src/etools/applications/management/management/__init__.py delete mode 100644 src/etools/applications/management/management/commands/__init__.py delete mode 100644 src/etools/applications/management/management/commands/check_issues.py delete mode 100644 src/etools/applications/management/management/commands/recheck_issues.py create mode 100644 src/etools/applications/management/migrations/0002_auto_20190326_1500.py delete mode 100644 src/etools/applications/management/models.py delete mode 100644 src/etools/applications/management/tests/factories.py delete mode 100644 src/etools/applications/management/tests/test_commands.py delete mode 100644 src/etools/applications/management/tests/test_issue_checks.py delete mode 100644 src/etools/applications/management/tests/test_issue_project_checks.py delete mode 100644 src/etools/applications/management/tests/test_models.py delete mode 100644 src/etools/applications/management/tests/test_tasks.py diff --git a/src/etools/applications/management/README.md b/src/etools/applications/management/README.md deleted file mode 100644 index 91eeb44d79..0000000000 --- a/src/etools/applications/management/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# Management App - -This app is currently meant to be used to flag potential issues (either bad data or policy violations). - -## Classes involved - -The main two important categories of things are *Issue Checks* (subclasses of `BaseIssueCheck`) and -*Flagged Issues* instances of `FlaggedIssue`. -**Both of these names might change soon.** - -Issue checks represent *types* of issues that can be raised. Examples of issue checks might include -"an Agreement did not have a signed PCA attached to it" or "an Intervention failed validation". -**Issue checks live in code.** - -However, each Issue check also has an associated `IssueCheckConfig` object. -The `IssueCheckConfig` is generated automatically, and is used to turn on/off issue checks at the database level -(instead of having to deploy code to turn on/off checks). -`IssueCheckConfig` objects are editable in the admin. - -Flagged issues represent *instances* of an issue. -For example, "*This particular Agreement* did not have a signed PCA attached to it" or -"*this particular Intervention* failed validation". -Flagged issues are associated with an Issue Check by ID, and also point at an associated object in the database. - -## High level function - -There are two high-level functions - provided both as management commands and celery tasks. - -### Check issues - -`./manage.py check_issues` - -This will run all Issue Checks against the entire database and create (or update) any relevant `FlaggedIssue` objects. -In the future this could be updated to only test since the last check. - -### Recheck issues - -`./manage.py recheck_issues` - -This will re-run all checks against the current set of existing `FlaggedIssue` objects. -If the issue has been addressed the `FlaggedIssue`'s status will be set to "resolved". -Else it will stay active. - -## Adding a new check - -Adding a new check is a two step process: - -1. Create a new subclass of `BaseIssueCheck` and implement the appropriate methods -2. Add the class to the list of `ISSUE_CHECKS` in settings/base.py - -### Required methods - -The jobs a check has are to: - -1. Generate a set of potentially relevant objects that should be checked. - This is used in the code that runs all checks (`./manage.py check_issues`). -2. Check an individual object. - This is used both in the code that runs all checks (`./manage.py check_issues`) and the code that rechecks - individual issues (`./manage.py recheck_issues`). - -#### Getting relevant objects - -Generally the issue check should return the smallest possible set of potential objects to check. -The `BaseIssueCheck` class provides two ways of implementing this: either by overriding `get_queryset` -or by overriding `get_objects_to_check`. - -`get_queryset` should be overridden if the relevant set of objects can be easily represented in a single queryset, -and no additional metadata is required for the check (see below). - -`get_objects_to_check` should be overridden if the relevant set of objects to check is too complex to represent -in a single queryset, or if additional metadata is needed (see below). - -#### Checking an individual object - -All issue checks must implement `run_check`, which takes an object, (optional) metadata, and should either -do nothing (if the check is successful) or raise an `IssueFoundException` if there is something wrong. - -As mentioned above, this method is called during checking all issues as well as during rechecks. - -#### Metadata - -In some instances, the object itself is not enough information to run the check. -For example, when validating an `Intervention`'s lower result data matches the correct `CountryProgramme` -you need to know which `CountryProgramme` you are looking at. -In this scenario you should to include a dictionary of metadata with the check. - -The metadata needs to be provided in two places: - -1. In the `get_objects_to_check` function - so it can be passed during normal checks. -2. By overriding `get_object_metadata` in the issue check - so the metadata can be reconstructed from - the `FlaggedIssue` object during rechecks. - -See `PdOutputsWrongCheck` for an example of check metadata in use. diff --git a/src/etools/applications/management/admin.py b/src/etools/applications/management/admin.py deleted file mode 100644 index 78afc88489..0000000000 --- a/src/etools/applications/management/admin.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.contrib import admin - -from . import models as app_models - - -@admin.register(app_models.FlaggedIssue) -class FlaggedIssueAdmin(admin.ModelAdmin): - list_display = ['content_object', 'issue_category', 'issue_id', 'issue_status', 'date_created', - 'date_updated', 'message'] - list_filter = ['issue_category', 'issue_id', 'issue_status', 'date_created', 'date_updated'] - search_fields = ['message'] diff --git a/src/etools/applications/management/issues/__init__.py b/src/etools/applications/management/issues/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/etools/applications/management/issues/checks.py b/src/etools/applications/management/issues/checks.py deleted file mode 100644 index db75861802..0000000000 --- a/src/etools/applications/management/issues/checks.py +++ /dev/null @@ -1,156 +0,0 @@ - -import logging -from abc import ABCMeta, abstractmethod -from collections import namedtuple - -from django.conf import settings -from django.core.exceptions import ImproperlyConfigured -from django.db.models import Model - -from django.utils.module_loading import import_string - -from etools.applications.environment.models import IssueCheckConfig -from etools.applications.management.issues.exceptions import IssueCheckNotFoundException, IssueFoundException -from etools.applications.management.models import FlaggedIssue, ISSUE_STATUS_RESOLVED -from etools.libraries.tenant_support.utils import run_on_all_tenants - -ModelCheckData = namedtuple('ModelCheckData', 'object metadata') - - -class BaseIssueCheck(metaclass=ABCMeta): - """ - Base class for all Issue Checks - """ - model = None # the model class that this check runs against. - check_id = None # a unique id for the issue check type. - - def __init__(self): - if self.model is None or not issubclass(self.model, Model): - raise ImproperlyConfigured('Issue checks must define a model class that subclasses models.Model!') - if not self.check_id: - raise ImproperlyConfigured('Issue checks must define a unique ID!') - - def check_all(self): - """ - Check all objects for issues. - """ - def _inner(): - for model_instance, metadata in self.get_objects_to_check(): - try: - self.run_check(model_instance, metadata) - except IssueFoundException as e: - issue = FlaggedIssue.get_or_new(content_object=model_instance, issue_id=self.check_id) - issue.message = str(e) - issue.save() - # todo: is it always valid to run all checks against all tenants? - run_on_all_tenants(_inner) - - def get_queryset(self): - """ - The default queryset of data to be checked. - """ - return self.model.objects.all() - - def get_objects_to_check(self): - """ - An iterable returning the ModelCheckData objects over which this check should be performed. - Should return an iterable/queryset of ModelCheckData with object being an instance of self.model - and metadata being an optional dictionary of additional data needed by the check. - - The default just returns the results of self.get_queryset with empty metadata - """ - for object in self.get_queryset(): - yield ModelCheckData(object, {}) - - def get_object_metadata(self, model_instance): - """ - Return any necessary metadata associated with an object. Necessary during rechecks. - """ - return {} - - @abstractmethod - def run_check(self, model_instance, metadata): - """ - This method should raise an IssueFoundException if the check fails. - """ - - -def get_available_issue_checks(): - """ - Get all issue checks from the configured settings. - """ - check_ids = set() - for check_path in settings.ISSUE_CHECKS: - check = get_issue_check(check_path) - if check.check_id in check_ids: - raise ImproperlyConfigured( - 'Duplicate Issue Check ID {} is not allowed! See settings.ISSUE_CHECKS'.format(check.check_id) - ) - check_ids.add(check.check_id) - yield get_issue_check(check_path) - - -def get_active_issue_checks(): - """ - Get all *active* issue checks from the configured settings / database. - """ - bootstrap_checks(default_is_active=False) - active_checks = set(IssueCheckConfig.objects.filter(is_active=True).values_list('check_id', flat=True)) - for check in get_available_issue_checks(): - if check.check_id in active_checks: - yield check - - -def get_issue_check_by_id(check_id): - # todo: might make sense to cache this if it's going to be called frequently - for check in get_available_issue_checks(): - if check.check_id == check_id: - return check - raise IssueCheckNotFoundException('No issue check with ID {} found.'.format(check_id)) - - -# todo: should probably cache this with something like lru_cache -def get_issue_check(import_path): - """ - Import the issue check class described by import_path, where - import_path is the full Python path to the class. - """ - IssueCheck = import_string(import_path) - if not issubclass(IssueCheck, BaseIssueCheck): - raise ImproperlyConfigured('Issue Check "%s" is not a subclass of "%s"' % - (IssueCheck, BaseIssueCheck)) - return IssueCheck() - - -def run_all_checks(): - """ - Run all configured issue checks. Note that this function might take a long time to complete on a large - database. - """ - for issue_check in get_active_issue_checks(): - issue_check.check_all() - - -def recheck_all_open_issues(): - """ - Recheck all unresolved FlaggedIssue objects for resolution. - """ - def _check(): - for issue in FlaggedIssue.objects.exclude(issue_status=ISSUE_STATUS_RESOLVED): - try: - issue.recheck() - except IssueCheckNotFoundException as e: - # todo: should this fail hard? - logging.error(str(e)) - - # todo: is it always valid to run all checks against all tenants? - run_on_all_tenants(_check) - - -def bootstrap_checks(default_is_active=False): - """ - Bootstraps the IssueCheckConfig objects for all IssueChecks in the database. - """ - for issue_check in get_available_issue_checks(): - if not IssueCheckConfig.objects.filter(check_id=issue_check.check_id).exists(): - IssueCheckConfig.objects.create(check_id=issue_check.check_id, is_active=default_is_active) diff --git a/src/etools/applications/management/issues/exceptions.py b/src/etools/applications/management/issues/exceptions.py deleted file mode 100644 index 9e92d53b9d..0000000000 --- a/src/etools/applications/management/issues/exceptions.py +++ /dev/null @@ -1,8 +0,0 @@ - - -class IssueFoundException(Exception): - pass - - -class IssueCheckNotFoundException(Exception): - pass diff --git a/src/etools/applications/management/issues/project_checks.py b/src/etools/applications/management/issues/project_checks.py deleted file mode 100644 index 9259c40f32..0000000000 --- a/src/etools/applications/management/issues/project_checks.py +++ /dev/null @@ -1,167 +0,0 @@ -import logging - -from django.contrib.auth import get_user_model -from django.db.models import Q - -from etools.applications.management.issues.checks import BaseIssueCheck, ModelCheckData -from etools.applications.management.issues.exceptions import IssueFoundException -from etools.applications.partners.models import Agreement, AgreementAmendment, Intervention, InterventionAmendment -from etools.applications.partners.validation.interventions import InterventionValid -from etools.applications.reports.models import CountryProgramme - -# todo: these can probably move closer to the models they are associated with, but just -# starting with them here as a proof of concept - - -class ActivePCANoSignedDocCheck(BaseIssueCheck): - model = Agreement - check_id = 'active_pca_no_signed_doc' - - def get_queryset(self): - return Agreement.objects.filter(agreement_type=Agreement.PCA).exclude(status='draft') - - def run_check(self, model_instance, metadata): - if not model_instance.attached_agreement: - raise IssueFoundException( - '{} Agreement [{}] does not have a signed PCA attached'.format(model_instance.agreement_type, - model_instance.id) - ) - - -class PdOutputsWrongCheck(BaseIssueCheck): - model = Intervention - check_id = 'pd_outputs_wrong' - - def get_objects_to_check(self): - cps = CountryProgramme.objects.filter(invalid=False, wbs__contains='/A0/') - for cp in cps: - interventions = Intervention.objects.filter( - start__gte=cp.from_date, start__lte=cp.to_date - ).prefetch_related('result_links') - for intervention in interventions: - yield ModelCheckData(intervention, {'cp': cp}) - - def get_object_metadata(self, model_instance): - # todo: confirm this logic is always valid - cp = CountryProgramme.objects.filter( - invalid=False, - wbs__contains='/A0/', - from_date__lte=model_instance.start, - to_date__gte=model_instance.end, - ).first() - return {'cp': cp} - - def run_check(self, model_instance, metadata): - wrong_cp = [] - cp = metadata['cp'] - if cp is None: - logging.error( - ( - "Tried to check PD Outputs without a linked CountryProgramme for Intervention {}. " - "This will be ignored and any associated issues may be resolved." - ).format(model_instance.pk) - ) - return - for rl in model_instance.result_links.all(): - if rl.cp_output.country_programme != cp: - wrong_cp.append(rl.cp_output.wbs) - if len(wrong_cp) > 0: - raise IssueFoundException( - "PD [P{}] STATUS [{}] CP [{}] has wrongly mapped outputs {}".format( - model_instance.id, model_instance.status, cp.wbs, wrong_cp) - ) - - -class InterventionsAssociatedSSFACheck(BaseIssueCheck): - model = Intervention - check_id = 'interventions_associated_ssfa' - - def get_queryset(self): - return Intervention.objects.filter( - Q(agreement__agreement_type=Agreement.SSFA, document_type=Intervention.PD) | - Q(agreement__agreement_type=Agreement.PCA, document_type=Intervention.SSFA) - ).prefetch_related('agreement') - - def run_check(self, model_instance, metadata): - # in this case the queryset controls the issue, so all relevant objects should fail, - # but we still need the test to be inside `run_check` so that objects can be rechecked - # in the future - fails_test = ( - ( - model_instance.agreement.agreement_type == Agreement.SSFA and - model_instance.document_type == Intervention.PD - ) or ( - model_instance.agreement.agreement_type == Agreement.PCA and - model_instance.document_type == Intervention.SSFA - ) - ) - if fails_test: - raise IssueFoundException( - 'intervention {} type {} status {} has agreement type {}'.format( - model_instance.id, model_instance.document_type, - model_instance.agreement.agreement_type, model_instance.status - ) - ) - - -class InterventionsAreValidCheck(BaseIssueCheck): - model = Intervention - check_id = 'interventions_are_valid' - - @staticmethod - def _get_master_user(): - return get_user_model().objects.get(username='etools_task_admin') - - def get_objects_to_check(self): - master_user = self._get_master_user() - for intervention in Intervention.objects.filter(status__in=['draft', 'signed', 'active', 'ended']): - yield ModelCheckData(intervention, {'master_user': master_user}) - - def get_object_metadata(self, model_instance): - return {'master_user': self._get_master_user()} - - def run_check(self, model_instance, metadata): - master_user = metadata['master_user'] - validator = InterventionValid(model_instance, master_user) - if not validator.is_valid: - raise IssueFoundException( - 'intervention {} of type {} is invalid: (Status:{}), Errors: {}'.format( - model_instance.id, model_instance.document_type, model_instance.status, - ', '.join(validator.errors) - ) - ) - - -class PDAmendmentsMissingFilesCheck(BaseIssueCheck): - model = InterventionAmendment - check_id = 'interventions_amendments_no_file' - - def get_queryset(self): - return InterventionAmendment.objects.filter(signed_amendment='').prefetch_related('intervention') - - def run_check(self, model_instance, metadata): - if not model_instance.signed_amendment: - raise IssueFoundException( - 'intervention {} type {} status {} has missing amendment file'.format( - model_instance.intervention.id, - model_instance.intervention.document_type, - model_instance.intervention.status) - ) - - -class PCAAmendmentsMissingFilesCheck(BaseIssueCheck): - model = AgreementAmendment - check_id = 'agreement_amendments_no_file' - - def get_queryset(self): - return AgreementAmendment.objects.filter(signed_amendment='') - - def run_check(self, model_instance, metadata): - if not model_instance.signed_amendment: - raise IssueFoundException( - 'agreement {} type {} status {} has missing amendment file'.format( - model_instance.agreement.id, - model_instance.agreement.agreement_type, - model_instance.agreement.status - ) - ) diff --git a/src/etools/applications/management/management/__init__.py b/src/etools/applications/management/management/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/etools/applications/management/management/commands/__init__.py b/src/etools/applications/management/management/commands/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/etools/applications/management/management/commands/check_issues.py b/src/etools/applications/management/management/commands/check_issues.py deleted file mode 100644 index 5b878b0c49..0000000000 --- a/src/etools/applications/management/management/commands/check_issues.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.core.management import BaseCommand - -from etools.applications.management.issues.checks import run_all_checks - - -class Command(BaseCommand): - help = 'Run all configured issue checks' - - def handle(self, *args, **options): - run_all_checks() diff --git a/src/etools/applications/management/management/commands/recheck_issues.py b/src/etools/applications/management/management/commands/recheck_issues.py deleted file mode 100644 index 1db2234fbc..0000000000 --- a/src/etools/applications/management/management/commands/recheck_issues.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.core.management import BaseCommand - -from etools.applications.management.issues.checks import recheck_all_open_issues - - -class Command(BaseCommand): - help = 'Recheck all open FlaggedIssues' - - def handle(self, *args, **options): - recheck_all_open_issues() diff --git a/src/etools/applications/management/migrations/0002_auto_20190326_1500.py b/src/etools/applications/management/migrations/0002_auto_20190326_1500.py new file mode 100644 index 0000000000..4dfee07928 --- /dev/null +++ b/src/etools/applications/management/migrations/0002_auto_20190326_1500.py @@ -0,0 +1,20 @@ +# Generated by Django 2.1.7 on 2019-03-26 15:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('management', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='flaggedissue', + name='content_type', + ), + migrations.DeleteModel( + name='FlaggedIssue', + ), + ] diff --git a/src/etools/applications/management/models.py b/src/etools/applications/management/models.py deleted file mode 100644 index a1973dd4f9..0000000000 --- a/src/etools/applications/management/models.py +++ /dev/null @@ -1,79 +0,0 @@ - -from django.contrib.contenttypes.fields import GenericForeignKey -from django.contrib.contenttypes.models import ContentType -from django.db import models -from django.utils.translation import ugettext as _ - -from etools.applications.management.issues.exceptions import IssueFoundException - -ISSUE_CATEGORY_DATA = 'data' -ISSUE_CATEGORY_COMPLIANCE = 'compliance' -ISSUE_CATEGORY_CHOICES = ( - (ISSUE_CATEGORY_DATA, 'Data Issue'), - (ISSUE_CATEGORY_COMPLIANCE, 'Compliance Issue'), -) - -ISSUE_STATUS_NEW = 'new' -ISSUE_STATUS_PENDING = 'pending' -ISSUE_STATUS_REACTIVATED = 'reactivated' -ISSUE_STATUS_RESOLVED = 'resolved' -ISSUE_STATUS_CHOICES = ( - (ISSUE_STATUS_NEW, 'New (untriaged)'), - (ISSUE_STATUS_PENDING, 'Pending (triaged, not resolved)'), - (ISSUE_STATUS_REACTIVATED, 'Reactivated (was resolved but not fixed)'), - (ISSUE_STATUS_RESOLVED, 'Resolved'), -) - - -class FlaggedIssue(models.Model): - # generic foreign key to any object in the DB - # https://docs.djangoproject.com/en/1.11/ref/contrib/contenttypes/#generic-relations - content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, verbose_name=_('Content Type')) - object_id = models.PositiveIntegerField(db_index=True, verbose_name=_('Object ID')) - content_object = GenericForeignKey('content_type', 'object_id') - - date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Creation Date')) - date_updated = models.DateTimeField(auto_now=True, verbose_name=_('Updated Date')) - issue_category = models.CharField(max_length=32, choices=ISSUE_CATEGORY_CHOICES, default=ISSUE_CATEGORY_DATA, - db_index=True, verbose_name=_('Issue Category')) - issue_status = models.CharField(max_length=32, choices=ISSUE_STATUS_CHOICES, default=ISSUE_STATUS_NEW, - db_index=True, verbose_name=_('Issue Status')) - issue_id = models.CharField( - max_length=100, - help_text='A readable ID associated with the specific issue, e.g. "pca-no-attachment"', - db_index=True, - verbose_name=_('Issue ID') - ) - message = models.TextField(verbose_name=_('Message')) - - def recheck(self): - from etools.applications.management.issues.checks import get_issue_check_by_id # noqa - check = get_issue_check_by_id(self.issue_id) - try: - check.run_check(self.content_object, metadata=check.get_object_metadata(self.content_object)) - except IssueFoundException as e: - # don't change status unless it was marked resolved - if self.issue_status == ISSUE_STATUS_RESOLVED: - self.issue_status = ISSUE_STATUS_REACTIVATED - self.message = str(e) - self.save() - else: - self.issue_status = ISSUE_STATUS_RESOLVED - self.save() - - @classmethod - def get_or_new(cls, content_object, issue_id): - """ - Like get_or_create except doesn't actually create the object in the database, and only - allows for a limited set of fields. - """ - try: - # we can't query on content_object directly without defining a GenericRelation on every - # model, so just do it manually from the content type and id - ct = ContentType.objects.get_for_model(content_object) - return cls.objects.get(content_type=ct, object_id=content_object.pk, issue_id=issue_id) - except FlaggedIssue.DoesNotExist: - return cls(content_object=content_object, issue_id=issue_id) - - def __str__(self): - return self.message diff --git a/src/etools/applications/management/tasks.py b/src/etools/applications/management/tasks.py index 42b2724ba5..3cdd6ef02b 100644 --- a/src/etools/applications/management/tasks.py +++ b/src/etools/applications/management/tasks.py @@ -9,8 +9,6 @@ from dateutil.relativedelta import relativedelta from etools.applications.core.util_scripts import set_country -from etools.applications.audit.models import Audit, Engagement, MicroAssessment, SpecialAudit, SpotCheck -from etools.applications.management.issues.checks import recheck_all_open_issues, run_all_checks from etools.applications.partners.models import Intervention, PartnerOrganization from etools.applications.users.models import Country from etools.config.celery import app @@ -18,22 +16,6 @@ logger = logging.getLogger(__name__) -@app.task -def run_all_checks_task(): - """ - Run all configured IssueChecks against the entire database. - """ - run_all_checks() - - -@app.task -def recheck_all_open_issues_task(): - """ - Recheck all unresolved FlaggedIssue objects for resolution. - """ - recheck_all_open_issues() - - @app.task def send_test_email(*args, **kwargs): """Task which send a test email""" @@ -163,37 +145,3 @@ def pmp_indicator_report(writer, **kwargs): 'Partner Link': '{}/pmp/partners/{}/details'.format(base_url, partner.pk), 'Intervention Link': '{}/pmp/interventions/{}/details'.format(base_url, intervention.pk), }) - - -@app.task -def fam_report(writer, **kwargs): - countries = kwargs.get('countries', None) - start_date = kwargs.get('start_date', None) - if start_date: - start_date = datetime.strptime(start_date.pop(), '%Y-%m-%d') - else: - start_date = date.today() + relativedelta(months=-1) - - engagements = (SpotCheck, Audit, SpecialAudit, MicroAssessment) - fieldnames = ['Country'] + ['{}-{}'.format(model._meta.verbose_name_raw, status_display) - for model in engagements for _, status_display in Engagement.STATUSES] - dict_writer = writer(fieldnames=fieldnames) - dict_writer.writeheader() - - qs = Country.objects.exclude(schema_name__in=['public', 'uat', 'frg']) - if countries: - qs = qs.filter(schema_name__in=countries.pop().split(',')) - - for country in qs: - set_country(country.name) - row_dict = {'Country': country.name} - for model in engagements: - for status, status_display in Engagement.STATUSES: - filter_dict = { - 'status': status, - 'start_date__month': start_date.month, - 'start_date__year': start_date.year, - } - row_dict['{}-{}'.format( - model._meta.verbose_name_raw, status_display)] = model.objects.filter(**filter_dict).count() - dict_writer.writerow(row_dict) diff --git a/src/etools/applications/management/tests/factories.py b/src/etools/applications/management/tests/factories.py deleted file mode 100644 index b480b64004..0000000000 --- a/src/etools/applications/management/tests/factories.py +++ /dev/null @@ -1,12 +0,0 @@ -import factory -from factory import fuzzy - -from etools.applications.management import models - - -class FlaggedIssueFactory(factory.django.DjangoModelFactory): - class Meta: - model = models.FlaggedIssue - - issue_id = fuzzy.FuzzyText(length=50) - message = fuzzy.FuzzyText(length=100) diff --git a/src/etools/applications/management/tests/test_commands.py b/src/etools/applications/management/tests/test_commands.py deleted file mode 100644 index 9f4842916e..0000000000 --- a/src/etools/applications/management/tests/test_commands.py +++ /dev/null @@ -1,36 +0,0 @@ - -from django.core.management import call_command - -from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.management.issues import checks -from etools.applications.management.models import FlaggedIssue, ISSUE_STATUS_NEW, ISSUE_STATUS_RESOLVED -from etools.applications.management.tests.factories import FlaggedIssueFactory -from etools.applications.partners.tests.factories import InterventionAmendmentFactory -from etools.applications.users.tests.factories import UserFactory - - -class TestCheckIssuesCommand(BaseTenantTestCase): - def test_run_all_checks(self): - UserFactory(username="etools_task_admin") - qs_issue = FlaggedIssue.objects.filter( - issue_id="interventions_amendments_no_file" - ) - InterventionAmendmentFactory(signed_amendment=None) - checks.bootstrap_checks(default_is_active=True) - self.assertFalse(qs_issue.exists()) - call_command("check_issues") - self.assertTrue(qs_issue.exists()) - - -class TestRecheckIssuesCommand(BaseTenantTestCase): - def test_recheck_all_open_issues_task(self): - UserFactory(username="etools_task_admin") - amendment = InterventionAmendmentFactory() - issue = FlaggedIssueFactory( - content_object=amendment, - issue_id='interventions_amendments_no_file', - issue_status=ISSUE_STATUS_NEW, - ) - call_command("recheck_issues") - issue_updated = FlaggedIssue.objects.get(pk=issue.pk) - self.assertEqual(issue_updated.issue_status, ISSUE_STATUS_RESOLVED) diff --git a/src/etools/applications/management/tests/test_issue_checks.py b/src/etools/applications/management/tests/test_issue_checks.py deleted file mode 100644 index 0293954633..0000000000 --- a/src/etools/applications/management/tests/test_issue_checks.py +++ /dev/null @@ -1,253 +0,0 @@ -from django.core.exceptions import ImproperlyConfigured -from django.test import override_settings - -from etools.applications.environment.models import IssueCheckConfig -from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.management.issues import checks -from etools.applications.management.issues.exceptions import IssueCheckNotFoundException, IssueFoundException -from etools.applications.management.models import (FlaggedIssue, ISSUE_STATUS_NEW, - ISSUE_STATUS_REACTIVATED, ISSUE_STATUS_RESOLVED,) -from etools.applications.management.tests.factories import FlaggedIssueFactory -from etools.applications.partners.models import PartnerOrganization -from etools.applications.partners.tests.factories import PartnerFactory - - -class PartnersMustHaveShortNameTestCheck(checks.BaseIssueCheck): - model = PartnerOrganization - check_id = 'partners_must_have_short_name' - - def get_queryset(self): - return PartnerOrganization.objects.all() - - def run_check(self, model_instance, metadata): - if not model_instance.short_name: - raise IssueFoundException( - 'Partner {} must specify a short name!'.format(model_instance.name) - ) - - -class PartnersNameMustBeFooTestCheck(checks.BaseIssueCheck): - model = PartnerOrganization - check_id = 'partners_must_have_short_name' - - def get_object_metadata(self, model_instance): - return {'expected_name': 'foo'} - - def get_objects_to_check(self): - for org in PartnerOrganization.objects.all(): - yield checks.ModelCheckData(org, self.get_object_metadata(org)) - - def run_check(self, model_instance, metadata): - if model_instance.name != metadata['expected_name']: - raise IssueFoundException( - 'Partner name "{}" does not match expected name "{}"!'.format( - model_instance.name, metadata['expected_name']) - ) - - -class TestMissingRunCheck(checks.BaseIssueCheck): - model = PartnerOrganization - check_id = "must_override_run_check" - - -class TestMissingModelCheck(checks.BaseIssueCheck): - check_id = "must_override_run_check" - - def run_check(self, model_instance, metadata): - return True - - -class TestMissingCheckIDCheck(checks.BaseIssueCheck): - model = PartnerOrganization - - def run_check(self, model_instance, metadata): - return True - - -class TestInvalidSubClass(object): - """Invalid subclassing""" - - -class IssueCheckTest(BaseTenantTestCase): - - def tearDown(self): - FlaggedIssue.objects.all().delete() - IssueCheckConfig.objects.all().delete() - super().tearDown() - - @override_settings(ISSUE_CHECKS=['etools.applications.management.tests.test_issue_checks.TestMissingRunCheck']) - def test_missing_run_check(self): - with self.assertRaisesRegexp(TypeError, "with abstract methods run_check"): - checks.run_all_checks() - - @override_settings(ISSUE_CHECKS=['etools.applications.management.tests.test_issue_checks.TestMissingModelCheck']) - def test_missing_model(self): - with self.assertRaisesRegexp(ImproperlyConfigured, "Issue checks must define a model class"): - checks.run_all_checks() - - @override_settings(ISSUE_CHECKS=['etools.applications.management.tests.test_issue_checks.TestMissingCheckIDCheck']) - def test_missing_check_id(self): - with self.assertRaisesRegexp(ImproperlyConfigured, "Issue checks must define a unique ID!"): - checks.run_all_checks() - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_get_available_issue_checks(self): - check_list = list(checks.get_available_issue_checks()) - self.assertEqual(1, len(check_list)) - self.assertTrue(type(check_list[0]) == PartnersMustHaveShortNameTestCheck) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_bootstrap_checks(self): - checks.bootstrap_checks() - self.assertEqual(1, IssueCheckConfig.objects.count()) - self.assertEqual(False, - IssueCheckConfig.objects.get(check_id='partners_must_have_short_name').is_active) - # make sure rerunning doesn't recreate - checks.bootstrap_checks(default_is_active=True) - self.assertEqual(1, IssueCheckConfig.objects.count()) - # or modify existing checks - self.assertEqual(False, - IssueCheckConfig.objects.get(check_id='partners_must_have_short_name').is_active) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_get_active_issue_checks(self): - checks.bootstrap_checks(default_is_active=False) - self.assertEqual([], list(checks.get_active_issue_checks())) - check_config = IssueCheckConfig.objects.get(check_id='partners_must_have_short_name') - check_config.is_active = True - check_config.save() - check_list = list(checks.get_active_issue_checks()) - self.assertEqual(1, len(check_list)) - self.assertTrue(type(check_list[0]) == PartnersMustHaveShortNameTestCheck) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck', - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_get_available_issue_checks_disallows_duplicates(self): - with self.assertRaises(ImproperlyConfigured): - list(checks.get_available_issue_checks()) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_get_issue_check_by_id(self): - check = checks.get_issue_check_by_id(PartnersMustHaveShortNameTestCheck.check_id) - self.assertTrue(type(check) == PartnersMustHaveShortNameTestCheck) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_get_issue_check_by_id_not_found(self): - with self.assertRaises(IssueCheckNotFoundException): - checks.get_issue_check_by_id('not_found') - - @override_settings(ISSUE_CHECKS=['etools.applications.management.tests.test_issue_checks.TestInvalidSubClass']) - def test_get_issue_check_invalid(self): - with self.assertRaisesRegexp(ImproperlyConfigured, "is not a subclass"): - checks.get_issue_check('etools.applications.management.tests.test_issue_checks.TestInvalidSubClass') - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_run_all_checks(self): - PartnerFactory(short_name='A name') # make a good one as well just to ensure it's not flagging everything - partner_bad = PartnerFactory() - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertEqual(1, FlaggedIssue.objects.count()) - issue = FlaggedIssue.objects.first() - self.assertEqual(PartnersMustHaveShortNameTestCheck.check_id, issue.issue_id) - self.assertEqual(partner_bad, issue.content_object) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_recheck(self): - partner_bad = PartnerFactory() - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertEqual(1, FlaggedIssue.objects.count()) - issue = FlaggedIssue.objects.first() - self.assertEqual(PartnersMustHaveShortNameTestCheck.check_id, issue.issue_id) - self.assertEqual(partner_bad, issue.content_object) - self.assertEqual(ISSUE_STATUS_NEW, issue.issue_status) - update_date = issue.date_updated - # initial recheck should not do anything except modify timestamps - issue = FlaggedIssue.objects.get(pk=issue.pk) - issue.recheck() - self.assertEqual(ISSUE_STATUS_NEW, issue.issue_status) - self.assertNotEqual(update_date, issue.date_updated) - update_date = issue.date_updated - - # recheck after fixing the issue should update the status to resolved - partner_bad.short_name = 'Name added' - partner_bad.save() - issue = FlaggedIssue.objects.get(pk=issue.pk) - issue.recheck() - self.assertEqual(ISSUE_STATUS_RESOLVED, issue.issue_status) - self.assertNotEqual(update_date, issue.date_updated) - update_date = issue.date_updated - - # recheck after re-creating the issue should update the status to reactivated - partner_bad.short_name = '' - partner_bad.save() - issue = FlaggedIssue.objects.get(pk=issue.pk) - issue.recheck() - self.assertEqual(ISSUE_STATUS_REACTIVATED, issue.issue_status) - self.assertNotEqual(update_date, issue.date_updated) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersNameMustBeFooTestCheck']) - def test_recheck_with_metadata(self): - partner_bad = PartnerFactory(name='bar') - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertEqual(1, FlaggedIssue.objects.count()) - issue = FlaggedIssue.objects.first() - self.assertEqual(PartnersNameMustBeFooTestCheck.check_id, issue.issue_id) - self.assertEqual(partner_bad, issue.content_object) - self.assertEqual(ISSUE_STATUS_NEW, issue.issue_status) - - partner_bad.name = 'foo' - partner_bad.save() - issue = FlaggedIssue.objects.get(pk=issue.pk) - issue.recheck() - self.assertEqual(ISSUE_STATUS_RESOLVED, issue.issue_status) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.tests.test_issue_checks.PartnersMustHaveShortNameTestCheck']) - def test_recheck_all_open_issues(self): - """Check that recheck_all_open_issues call changes those issues - that are not resolved - And handles invalid issues - """ - partner = PartnerFactory(short_name='A name') - issue_resolved = FlaggedIssueFactory( - content_object=partner, - issue_id='partners_must_have_short_name', - issue_status=ISSUE_STATUS_RESOLVED, - ) - issue_new = FlaggedIssueFactory( - content_object=partner, - issue_id='partners_must_have_short_name', - issue_status=ISSUE_STATUS_NEW, - ) - issue_bad = FlaggedIssueFactory( - content_object=partner, - issue_status=ISSUE_STATUS_NEW, - ) - checks.recheck_all_open_issues() - issue_resolved_updated = FlaggedIssue.objects.get(pk=issue_resolved.pk) - self.assertEqual( - issue_resolved_updated.date_updated, - issue_resolved.date_updated - ) - issue_new_updated = FlaggedIssue.objects.get(pk=issue_new.pk) - self.assertNotEqual( - issue_new_updated.date_updated, - issue_new.date_updated - ) - issue_bad_updated = FlaggedIssue.objects.get(pk=issue_bad.pk) - self.assertEqual( - issue_bad_updated.date_updated, - issue_bad.date_updated - ) diff --git a/src/etools/applications/management/tests/test_issue_project_checks.py b/src/etools/applications/management/tests/test_issue_project_checks.py deleted file mode 100644 index 2c29fe5452..0000000000 --- a/src/etools/applications/management/tests/test_issue_project_checks.py +++ /dev/null @@ -1,359 +0,0 @@ - -import datetime -from unittest import skip - -from django.test import override_settings - -from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.management.issues import checks -from etools.applications.management.models import FlaggedIssue -from etools.applications.partners.models import Agreement, Intervention, InterventionResultLink -from etools.applications.partners.tests.factories import (AgreementAmendmentFactory, AgreementFactory, - CountryProgrammeFactory, InterventionAmendmentFactory, - InterventionFactory,) -from etools.applications.partners.validation.interventions import InterventionValid -from etools.applications.reports.tests.factories import ResultFactory -from etools.applications.users.tests.factories import UserFactory - - -class TestActivePCANoSignedDocCheck(BaseTenantTestCase): - def setUp(self): - super().setUp() - UserFactory(username="etools_task_admin") - - @override_settings(ISSUE_CHECKS=['etools.applications.management.issues.project_checks.ActivePCANoSignedDocCheck']) - def test_issue_found(self): - """Check that if no attached agreement, then an issue is raised""" - qs_issue = FlaggedIssue.objects.filter( - issue_id="active_pca_no_signed_doc" - ) - agreement = AgreementFactory(attached_agreement=None) - self.assertFalse(agreement.attached_agreement) - self.assertEqual(agreement.agreement_type, Agreement.PCA) - - self.assertFalse(qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(qs_issue.exists()) - issue = qs_issue.first() - self.assertIn("does not have a signed PCA attached", issue.message) - - @skip("skipping for now issues are not used and tests sometimes fail on second run") - def test_no_issue(self): - """Check that is attached agreement, then no issue""" - qs_issue = FlaggedIssue.objects.filter( - issue_id="active_pca_no_signed_doc" - ) - agreement = AgreementFactory() - self.assertTrue(agreement.attachment.exists()) - self.assertEqual(agreement.agreement_type, Agreement.PCA) - - self.assertFalse(qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(qs_issue.exists()) - - -class TestPdOutputsWrongCheck(BaseTenantTestCase): - def setUp(self): - super().setUp() - UserFactory(username="etools_task_admin") - - @override_settings(ISSUE_CHECKS=['etools.applications.management.issues.project_checks.PdOutputsWrongCheck']) - def test_issue_found(self): - """Check that is country programme for intervention does not - match result country programme then issue is created""" - qs_issue = FlaggedIssue.objects.filter( - issue_id="pd_outputs_wrong" - ) - start_date = datetime.date(2001, 1, 1) - end_date = datetime.date(2001, 12, 31) - country = CountryProgrammeFactory( - from_date=start_date, - to_date=end_date, - ) - intervention = InterventionFactory( - country_programme=country, - start=start_date, - ) - result = ResultFactory(country_programme=CountryProgrammeFactory()) - InterventionResultLink.objects.create( - intervention=intervention, - cp_output=result, - ) - self.assertNotEqual( - intervention.country_programme, - result.country_programme - ) - - self.assertFalse(qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(qs_issue.exists()) - issue = qs_issue.first() - self.assertIn("has wrongly mapped outputs", issue.message) - - @override_settings(ISSUE_CHECKS=['etools.applications.management.issues.project_checks.PdOutputsWrongCheck']) - def test_no_interventions(self): - """If intervention does not fit in with Country Programmes - then no issues raised - """ - qs_issue = FlaggedIssue.objects.filter( - issue_id="pd_outputs_wrong" - ) - start_date = datetime.date(2001, 1, 1) - end_date = datetime.date(2001, 12, 31) - country = CountryProgrammeFactory( - from_date=start_date, - to_date=end_date, - ) - intervention = InterventionFactory( - country_programme=country, - start=start_date - datetime.timedelta(days=1), - ) - result = ResultFactory(country_programme=CountryProgrammeFactory()) - InterventionResultLink.objects.create( - intervention=intervention, - cp_output=result, - ) - self.assertNotEqual( - intervention.country_programme, - result.country_programme - ) - - self.assertFalse(qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(qs_issue.exists()) - - @override_settings(ISSUE_CHECKS=['etools.applications.management.issues.project_checks.PdOutputsWrongCheck']) - def test_no_country_programme(self): - """Check that if intervention has no country programme - the intervention is ignored during the check - """ - qs_issue = FlaggedIssue.objects.filter( - issue_id="pd_outputs_wrong" - ) - intervention = InterventionFactory() - result = ResultFactory(country_programme=CountryProgrammeFactory()) - InterventionResultLink.objects.create( - intervention=intervention, - cp_output=result, - ) - self.assertIsNone(intervention.country_programme) - self.assertNotEqual( - intervention.country_programme, - result.country_programme - ) - - self.assertFalse(qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(qs_issue.exists()) - - @override_settings(ISSUE_CHECKS=['etools.applications.management.issues.project_checks.PdOutputsWrongCheck']) - def test_no_issue(self): - """Check that valida interventions results in no issue""" - qs_issue = FlaggedIssue.objects.filter( - issue_id="pd_outputs_wrong" - ) - start_date = datetime.date(2001, 1, 1) - end_date = datetime.date(2001, 12, 31) - country = CountryProgrammeFactory( - from_date=start_date, - to_date=end_date, - ) - intervention = InterventionFactory( - country_programme=country, - start=start_date, - ) - result = ResultFactory(country_programme=country) - InterventionResultLink.objects.create( - intervention=intervention, - cp_output=result, - ) - self.assertEqual( - intervention.country_programme, - result.country_programme - ) - - self.assertFalse(qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(qs_issue.exists()) - - -class TestInterventionsAssociatedSSFACheck(BaseTenantTestCase): - def setUp(self): - super().setUp() - self.qs_issue = FlaggedIssue.objects.filter( - issue_id="interventions_associated_ssfa" - ) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.issues.project_checks.InterventionsAssociatedSSFACheck']) - def test_document_type_pd(self): - """Check that if agreement type SSFA but document type PD - then issue is raised - """ - agreement = AgreementFactory(agreement_type=Agreement.SSFA) - InterventionFactory( - agreement=agreement, - document_type=Intervention.PD, - ) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(self.qs_issue.exists()) - issue = self.qs_issue.first() - self.assertIn("type {}".format(Intervention.PD), issue.message) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.issues.project_checks.InterventionsAssociatedSSFACheck']) - def test_document_type_ssfa(self): - """Check that if agreement type PCA but document type SSFA - then issue is raised - """ - agreement = AgreementFactory(agreement_type=Agreement.PCA) - InterventionFactory( - agreement=agreement, - document_type=Intervention.SSFA, - ) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(self.qs_issue.exists()) - issue = self.qs_issue.first() - self.assertIn("type {}".format(Intervention.SSFA), issue.message) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.issues.project_checks.InterventionsAssociatedSSFACheck']) - def test_no_issue_pd(self): - """Check that if agreement type SSFA and document type PD - then issue is NOT raised - """ - agreement = AgreementFactory(agreement_type=Agreement.SSFA) - InterventionFactory( - agreement=agreement, - document_type=Intervention.SSFA, - ) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(self.qs_issue.exists()) - - @override_settings(ISSUE_CHECKS=[ - 'etools.applications.management.issues.project_checks.InterventionsAssociatedSSFACheck']) - def test_no_issue_ssfa(self): - """Check that if agreement type PCA and document type SSFA - then issue is NOT raised - """ - agreement = AgreementFactory(agreement_type=Agreement.PCA) - InterventionFactory( - agreement=agreement, - document_type=Intervention.PD, - ) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(self.qs_issue.exists()) - - -class TestInterventionsAreValidCheck(BaseTenantTestCase): - def setUp(self): - super().setUp() - self.master_user = UserFactory(username="etools_task_admin") - self.qs_issue = FlaggedIssue.objects.filter( - issue_id="interventions_are_valid" - ) - - def test_invalid_intervention(self): - """Check if intervention fails validation, issue is raised""" - intervention = InterventionFactory( - signed_by_unicef_date=datetime.date(2001, 2, 1), - signed_by_partner_date=datetime.date(2001, 3, 1), - signed_pd_document="random.pdf", - start=datetime.date(2001, 1, 1) - ) - validator = InterventionValid(intervention, self.master_user) - self.assertFalse(validator.is_valid) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(self.qs_issue.exists()) - - def test_no_issue(self): - """Check if intervention does not fail validation, - no issue is raised - """ - intervention = InterventionFactory() - validator = InterventionValid(intervention, self.master_user) - self.assertTrue(validator.is_valid) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(self.qs_issue.exists()) - - -class TestPDAmendmentsMissingFilesCheck(BaseTenantTestCase): - def setUp(self): - super().setUp() - self.master_user = UserFactory(username="etools_task_admin") - self.qs_issue = FlaggedIssue.objects.filter( - issue_id="interventions_amendments_no_file" - ) - - def test_no_amendment_file(self): - """Check that if no amendment file, then issue is raised""" - amendment = InterventionAmendmentFactory(signed_amendment=None) - self.assertFalse(amendment.signed_amendment) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(self.qs_issue.exists()) - issue = self.qs_issue.first() - self.assertIn("has missing amendment file", issue.message) - - def test_no_issue(self): - """Check that if amendment file, then issue is NOT raised""" - amendment = InterventionAmendmentFactory() - self.assertTrue(amendment.signed_amendment) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(self.qs_issue.exists()) - - -class TestPCAAmendmentsMissingFilesCheck(BaseTenantTestCase): - def setUp(self): - super().setUp() - self.master_user = UserFactory(username="etools_task_admin") - self.qs_issue = FlaggedIssue.objects.filter( - issue_id="agreement_amendments_no_file" - ) - - def test_no_signed_amendment(self): - """Check that if agreement has no signed amendment - then issue is raised - """ - amendment = AgreementAmendmentFactory( - signed_amendment=None - ) - self.assertFalse(amendment.signed_amendment) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertTrue(self.qs_issue.exists()) - issue = self.qs_issue.first() - self.assertIn("has missing amendment file", issue.message) - - def test_no_issue(self): - """Check that if agreement has signed amendment - then issue is NOT raised - """ - amendment = AgreementAmendmentFactory(signed_amendment="random.pdf") - self.assertTrue(amendment.signed_amendment) - self.assertFalse(self.qs_issue.exists()) - checks.bootstrap_checks(default_is_active=True) - checks.run_all_checks() - self.assertFalse(self.qs_issue.exists()) diff --git a/src/etools/applications/management/tests/test_models.py b/src/etools/applications/management/tests/test_models.py deleted file mode 100644 index fd7f1791cd..0000000000 --- a/src/etools/applications/management/tests/test_models.py +++ /dev/null @@ -1,51 +0,0 @@ -from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.management.models import FlaggedIssue -from etools.applications.management.tests.factories import FlaggedIssueFactory -from etools.applications.partners.tests.factories import PartnerFactory - - -class TestStrUnicode(BaseTenantTestCase): - """Ensure calling str() on model instances returns the right text.""" - - def test_flagged_issue(self): - partner = PartnerFactory() - issue = FlaggedIssueFactory( - content_object=partner, - issue_id="321", - message='test message' - ) - self.assertEqual(str(issue), "test message") - - issue = FlaggedIssueFactory( - content_object=partner, - issue_id="321", - message="R\xe4dda Barnen" - ) - self.assertEqual(str(issue), "R\xe4dda Barnen") - - -class FlaggedIssueTest(BaseTenantTestCase): - - @classmethod - def tearDownClass(cls): - FlaggedIssue.objects.all().delete() - super().tearDownClass() - - def test_get_or_new_creates_new_unsaved(self): - partner = PartnerFactory() - issue = FlaggedIssue.get_or_new(partner, 'test-new-unsaved') - # make sure we got a new one - self.assertTrue(issue.pk is None) - - def test_get_or_new_returns_saved(self): - issue_id = 'test-return-saved' - partner = PartnerFactory() - issue = FlaggedIssueFactory( - content_object=partner, - issue_id=issue_id, - message='test message' - ) - self.assertTrue(issue.pk is not None) - issue_back = FlaggedIssue.get_or_new(partner, issue_id) - # make sure we got the same one back - self.assertEqual(issue.pk, issue_back.pk) diff --git a/src/etools/applications/management/tests/test_tasks.py b/src/etools/applications/management/tests/test_tasks.py deleted file mode 100644 index 52262e3ef9..0000000000 --- a/src/etools/applications/management/tests/test_tasks.py +++ /dev/null @@ -1,35 +0,0 @@ - -from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.management import tasks -from etools.applications.management.issues import checks -from etools.applications.management.models import FlaggedIssue, ISSUE_STATUS_NEW, ISSUE_STATUS_RESOLVED -from etools.applications.management.tests.factories import FlaggedIssueFactory -from etools.applications.partners.tests.factories import InterventionAmendmentFactory -from etools.applications.users.tests.factories import UserFactory - - -class TestRunAllChecksTask(BaseTenantTestCase): - def test_run_all_checks(self): - UserFactory(username="etools_task_admin") - qs_issue = FlaggedIssue.objects.filter( - issue_id="interventions_amendments_no_file" - ) - InterventionAmendmentFactory(signed_amendment=None) - checks.bootstrap_checks(default_is_active=True) - self.assertFalse(qs_issue.exists()) - tasks.run_all_checks_task() - self.assertTrue(qs_issue.exists()) - - -class TestRecheckAllOpenIssuesTask(BaseTenantTestCase): - def test_recheck_all_open_issues_task(self): - UserFactory(username="etools_task_admin") - amendment = InterventionAmendmentFactory() - issue = FlaggedIssueFactory( - content_object=amendment, - issue_id='interventions_amendments_no_file', - issue_status=ISSUE_STATUS_NEW, - ) - tasks.recheck_all_open_issues_task() - issue_updated = FlaggedIssue.objects.get(pk=issue.pk) - self.assertEqual(issue_updated.issue_status, ISSUE_STATUS_RESOLVED) diff --git a/src/etools/applications/management/urls.py b/src/etools/applications/management/urls.py index 6c27cf9006..a1d0b21234 100644 --- a/src/etools/applications/management/urls.py +++ b/src/etools/applications/management/urls.py @@ -3,7 +3,6 @@ from etools.applications.management.views.general import InvalidateCache, SyncCountries, SyncFRs from etools.applications.management.views.reports import LoadResultStructure from etools.applications.management.views.tasks_endpoints import ( - FamReportView, PMPIndicatorsReportView, SyncDeltaUsers, TestSendEmailAPIView, @@ -31,5 +30,4 @@ url(r'^tasks/send_test_email/$', TestSendEmailAPIView.as_view(), name='tasks_send_test_email'), url(r'^reports/users/$', UsersReportView.as_view(), name='reports_users'), url(r'^reports/pmp_indicators/$', PMPIndicatorsReportView.as_view(), name='reports_pmp_indicators'), - url(r'^reports/fam/$', FamReportView.as_view(), name='reports_fam'), ), 'management') diff --git a/src/etools/applications/management/views/tasks_endpoints.py b/src/etools/applications/management/views/tasks_endpoints.py index 9f6531748e..7e50b7caab 100644 --- a/src/etools/applications/management/views/tasks_endpoints.py +++ b/src/etools/applications/management/views/tasks_endpoints.py @@ -10,7 +10,7 @@ from unicef_restlib.permissions import IsSuperUser from etools.applications.hact.tasks import update_aggregate_hact_values, update_hact_values -from etools.applications.management.tasks import fam_report, pmp_indicator_report, send_test_email, user_report +from etools.applications.management.tasks import pmp_indicator_report, send_test_email, user_report from etools.libraries.azure_graph_api.tasks import sync_delta_users @@ -92,8 +92,3 @@ class UsersReportView(BasicReportAPIView): class PMPIndicatorsReportView(BasicReportAPIView): report_function = pmp_indicator_report base_filename = 'pmp_indicators_report' - - -class FamReportView(BasicReportAPIView): - report_function = fam_report - base_filename = 'fam_report' diff --git a/src/etools/applications/management/views/v1.py b/src/etools/applications/management/views/v1.py index 3c3aef0d20..9ad498c3cf 100644 --- a/src/etools/applications/management/views/v1.py +++ b/src/etools/applications/management/views/v1.py @@ -32,11 +32,6 @@ def get_context_data(self, **kwargs): }) return context - # def get(self, request): - # with open(settings.PACKAGE_ROOT + '/templates/frontend/management/management.html', 'r') as my_f: - # result = my_f.read() - # return HttpResponse(result) - class ActiveUsers(APIView): """ From f7253afa52c3fe5e8c7bb19e16ba9e7e2c101d9e Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 26 Mar 2019 11:18:23 -0400 Subject: [PATCH 42/79] clean issuecheck --- src/etools/applications/environment/admin.py | 8 +------- .../migrations/0003_delete_issuecheckconfig.py | 16 ++++++++++++++++ src/etools/applications/environment/models.py | 14 -------------- .../applications/environment/tests/factories.py | 7 ------- .../environment/tests/test_models.py | 12 +----------- .../applications/environment/tests/test_views.py | 2 +- .../applications/management/serializers.py | 1 - .../applications/management/views/gis_v1.py | 4 ++-- 8 files changed, 21 insertions(+), 43 deletions(-) create mode 100644 src/etools/applications/environment/migrations/0003_delete_issuecheckconfig.py diff --git a/src/etools/applications/environment/admin.py b/src/etools/applications/environment/admin.py index e3aeb0d38a..5cd2d39eb4 100644 --- a/src/etools/applications/environment/admin.py +++ b/src/etools/applications/environment/admin.py @@ -4,13 +4,7 @@ from waffle.admin import FlagAdmin, SwitchAdmin from waffle.models import Flag, Switch -from etools.applications.environment.models import IssueCheckConfig, TenantFlag, TenantSwitch - - -@admin.register(IssueCheckConfig) -class IssueCheckConfigAdmin(admin.ModelAdmin): - list_display = ['check_id', 'is_active'] - list_filter = ['is_active'] +from etools.applications.environment.models import TenantFlag, TenantSwitch class TenantFlagAdmin(FlagAdmin): diff --git a/src/etools/applications/environment/migrations/0003_delete_issuecheckconfig.py b/src/etools/applications/environment/migrations/0003_delete_issuecheckconfig.py new file mode 100644 index 0000000000..6c7c61dacf --- /dev/null +++ b/src/etools/applications/environment/migrations/0003_delete_issuecheckconfig.py @@ -0,0 +1,16 @@ +# Generated by Django 2.1.7 on 2019-03-26 15:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('environment', '0002_auto_20190122_1412'), + ] + + operations = [ + migrations.DeleteModel( + name='IssueCheckConfig', + ), + ] diff --git a/src/etools/applications/environment/models.py b/src/etools/applications/environment/models.py index 4a348b1c89..06c76ed0b9 100644 --- a/src/etools/applications/environment/models.py +++ b/src/etools/applications/environment/models.py @@ -16,20 +16,6 @@ cache = get_cache() -class IssueCheckConfig(models.Model): - """ - Used to enable/disable issue checks at runtime. - """ - check_id = models.CharField(max_length=100, unique=True, db_index=True, verbose_name=_('Check id')) - is_active = models.BooleanField(default=False, verbose_name=_('Is Active')) - - def __str__(self): - return '{}: {}'.format(self.check_id, self.is_active) - - class Meta: - verbose_name_plural = _('Issue check config') - - class TenantFlag(BaseModel): """ Associate one or more countries with a Flag. diff --git a/src/etools/applications/environment/tests/factories.py b/src/etools/applications/environment/tests/factories.py index de8cd974d3..9af375c484 100644 --- a/src/etools/applications/environment/tests/factories.py +++ b/src/etools/applications/environment/tests/factories.py @@ -5,13 +5,6 @@ from etools.applications.environment import models -class IssueCheckConfigFactory(factory.django.DjangoModelFactory): - class Meta: - model = models.IssueCheckConfig - - check_id = fuzzy.FuzzyText() - - class TenantFlagFactory(factory.django.DjangoModelFactory): class Meta: model = models.TenantFlag diff --git a/src/etools/applications/environment/tests/test_models.py b/src/etools/applications/environment/tests/test_models.py index 0ce20562ce..0333b71c69 100644 --- a/src/etools/applications/environment/tests/test_models.py +++ b/src/etools/applications/environment/tests/test_models.py @@ -4,24 +4,14 @@ from django.test import TestCase from django.test.utils import override_settings - from mock import Mock from etools.applications.environment.apps import EnvironmentConfig from etools.applications.environment.helpers import tenant_flag_is_active, tenant_switch_is_active -from etools.applications.environment.tests.factories import (IssueCheckConfigFactory, - TenantFlagFactory, TenantSwitchFactory,) +from etools.applications.environment.tests.factories import TenantFlagFactory, TenantSwitchFactory from etools.applications.users.tests.factories import CountryFactory, GroupFactory, UserFactory -class IssueCheckConfigTest(TestCase): - - def test_str_method(self): - issue_check_config = IssueCheckConfigFactory() - expected = '{}: {}'.format(issue_check_config.check_id, issue_check_config.is_active) - self.assertEqual(str(issue_check_config), expected) - - class EnvironmentConfigTest(TestCase): def test_apps(self): self.assertEqual(apps.get_app_config('environment').name, EnvironmentConfig.name) diff --git a/src/etools/applications/environment/tests/test_views.py b/src/etools/applications/environment/tests/test_views.py index 0ba6dfa2a5..c6b054a917 100644 --- a/src/etools/applications/environment/tests/test_views.py +++ b/src/etools/applications/environment/tests/test_views.py @@ -1,8 +1,8 @@ import json -from django.urls import reverse from django.db import connection +from django.urls import reverse from rest_framework import status diff --git a/src/etools/applications/management/serializers.py b/src/etools/applications/management/serializers.py index 1b12ab5127..4c31f2ee9d 100644 --- a/src/etools/applications/management/serializers.py +++ b/src/etools/applications/management/serializers.py @@ -2,7 +2,6 @@ from rest_framework import serializers from rest_framework_gis.serializers import GeoFeatureModelSerializer - from unicef_locations.models import Location diff --git a/src/etools/applications/management/views/gis_v1.py b/src/etools/applications/management/views/gis_v1.py index f620b107b5..575cc7685a 100644 --- a/src/etools/applications/management/views/gis_v1.py +++ b/src/etools/applications/management/views/gis_v1.py @@ -5,6 +5,8 @@ from unicef_locations.models import Location from unicef_restlib.permissions import IsSuperUser +from etools.applications.action_points.models import ActionPoint +from etools.applications.activities.models import Activity from etools.applications.management.serializers import ( GisLocationGeojsonSerializer, GisLocationListSerializer, @@ -14,8 +16,6 @@ from etools.applications.reports.models import AppliedIndicator from etools.applications.t2f.models import TravelActivity from etools.applications.users.models import Country -from etools.applications.activities.models import Activity -from etools.applications.action_points.models import ActionPoint class GisLocationsInUseViewset(ListAPIView): From 621c2b7b2792561e1a7d4a187c90ee0d2136320f Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Fri, 12 Apr 2019 11:09:02 -0400 Subject: [PATCH 43/79] remove clone for driver and isort --- src/etools/applications/t2f/admin.py | 2 +- src/etools/applications/t2f/helpers/clone_travel.py | 8 -------- .../t2f/migrations/0013_auto_20190103_1345.py | 1 + src/etools/applications/t2f/models.py | 2 +- src/etools/applications/t2f/serializers/travel.py | 8 +------- src/etools/applications/t2f/tests/factories.py | 3 ++- src/etools/applications/t2f/tests/test_dashboard.py | 5 +---- src/etools/applications/t2f/tests/test_exports.py | 2 +- .../applications/t2f/tests/test_permission_matrix.py | 10 ++-------- .../applications/t2f/tests/test_travel_details.py | 11 ----------- src/etools/applications/t2f/urls.py | 2 -- src/etools/applications/t2f/views/exports.py | 5 +---- src/etools/applications/t2f/views/travel.py | 8 -------- 13 files changed, 11 insertions(+), 56 deletions(-) diff --git a/src/etools/applications/t2f/admin.py b/src/etools/applications/t2f/admin.py index c4b0ebc91e..7cae4838e0 100644 --- a/src/etools/applications/t2f/admin.py +++ b/src/etools/applications/t2f/admin.py @@ -3,8 +3,8 @@ from etools.applications.action_points.admin import ActionPointAdmin from etools.applications.publics.admin import AdminListMixin from etools.applications.t2f import models -from etools.applications.t2f.models import T2FActionPoint from etools.applications.t2f.forms import T2FActionPointAdminForm +from etools.applications.t2f.models import T2FActionPoint @admin.register(models.Travel) diff --git a/src/etools/applications/t2f/helpers/clone_travel.py b/src/etools/applications/t2f/helpers/clone_travel.py index fab6820c09..2b63e23064 100644 --- a/src/etools/applications/t2f/helpers/clone_travel.py +++ b/src/etools/applications/t2f/helpers/clone_travel.py @@ -14,14 +14,6 @@ def clone_for_secondary_traveler(self, new_traveler): return new_travel - def clone_for_driver(self, new_traveler): - fk_related = ['itinerary'] - o2o_related = [] - new_travel = self._do_the_cloning(new_traveler, fk_related, o2o_related) - new_travel.is_driver = True - new_travel.save() - return new_travel - def _do_the_cloning(self, new_traveler, fk_related, o2o_related): new_travel = self._clone_model(self.travel) new_travel.traveler = new_traveler diff --git a/src/etools/applications/t2f/migrations/0013_auto_20190103_1345.py b/src/etools/applications/t2f/migrations/0013_auto_20190103_1345.py index 339c24b07f..ec2d08ab10 100644 --- a/src/etools/applications/t2f/migrations/0013_auto_20190103_1345.py +++ b/src/etools/applications/t2f/migrations/0013_auto_20190103_1345.py @@ -1,6 +1,7 @@ # Generated by Django 2.0.9 on 2019-01-03 13:45 from django.db import migrations, models + import etools.applications.t2f.models diff --git a/src/etools/applications/t2f/models.py b/src/etools/applications/t2f/models.py index 060b720d7c..f18c64a28d 100644 --- a/src/etools/applications/t2f/models.py +++ b/src/etools/applications/t2f/models.py @@ -16,8 +16,8 @@ from unicef_djangolib.fields import CodedGenericRelation from unicef_notification.utils import send_notification -from etools.applications.core.urlresolvers import build_frontend_url from etools.applications.action_points.models import ActionPoint +from etools.applications.core.urlresolvers import build_frontend_url from etools.applications.t2f.serializers.mailing import TravelMailSerializer from etools.applications.users.models import WorkspaceCounter diff --git a/src/etools/applications/t2f/serializers/travel.py b/src/etools/applications/t2f/serializers/travel.py index 983bb27a95..fa07974aeb 100644 --- a/src/etools/applications/t2f/serializers/travel.py +++ b/src/etools/applications/t2f/serializers/travel.py @@ -21,13 +21,7 @@ from etools.applications.partners.models import PartnerType from etools.applications.publics.models import AirlineCompany from etools.applications.t2f.helpers.permission_matrix import PermissionMatrix -from etools.applications.t2f.models import ( - ItineraryItem, - Travel, - TravelActivity, - TravelAttachment, - TravelType, -) +from etools.applications.t2f.models import ItineraryItem, Travel, TravelActivity, TravelAttachment, TravelType itineraryItemSortKey = operator.attrgetter('departure_date') diff --git a/src/etools/applications/t2f/tests/factories.py b/src/etools/applications/t2f/tests/factories.py index 057bbe36c0..f14bde4a2f 100644 --- a/src/etools/applications/t2f/tests/factories.py +++ b/src/etools/applications/t2f/tests/factories.py @@ -1,15 +1,16 @@ import datetime + import factory from factory import fuzzy from unicef_locations.tests.factories import LocationFactory +from etools.applications.action_points.tests.factories import ActionPointFactory from etools.applications.partners.tests.factories import InterventionFactory from etools.applications.publics.tests.factories import ( PublicsAirlineCompanyFactory, PublicsCurrencyFactory, PublicsDSARegionFactory, ) -from etools.applications.action_points.tests.factories import ActionPointFactory from etools.applications.reports.tests.factories import ResultFactory, SectionFactory from etools.applications.t2f import models from etools.applications.users.tests.factories import OfficeFactory, UserFactory diff --git a/src/etools/applications/t2f/tests/test_dashboard.py b/src/etools/applications/t2f/tests/test_dashboard.py index 6aeb222993..8cfca7a40d 100644 --- a/src/etools/applications/t2f/tests/test_dashboard.py +++ b/src/etools/applications/t2f/tests/test_dashboard.py @@ -4,10 +4,7 @@ from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import PartnerOrganization -from etools.applications.publics.tests.factories import ( - PublicsCurrencyFactory, - PublicsDSARegionFactory, -) +from etools.applications.publics.tests.factories import PublicsCurrencyFactory, PublicsDSARegionFactory from etools.applications.t2f.models import make_travel_reference_number, ModeOfTravel, Travel, TravelType from etools.applications.t2f.tests.factories import TravelActivityFactory, TravelFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/t2f/tests/test_exports.py b/src/etools/applications/t2f/tests/test_exports.py index 1ccad3762a..b6a0ff182b 100644 --- a/src/etools/applications/t2f/tests/test_exports.py +++ b/src/etools/applications/t2f/tests/test_exports.py @@ -1,6 +1,6 @@ import csv -import logging import datetime +import logging from django.urls import reverse from django.utils.six import StringIO diff --git a/src/etools/applications/t2f/tests/test_permission_matrix.py b/src/etools/applications/t2f/tests/test_permission_matrix.py index 167f4fab6f..a1caf4a9bc 100644 --- a/src/etools/applications/t2f/tests/test_permission_matrix.py +++ b/src/etools/applications/t2f/tests/test_permission_matrix.py @@ -6,15 +6,9 @@ from unicef_locations.tests.factories import LocationFactory from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.publics.tests.factories import ( - PublicsCurrencyFactory, - PublicsDSARegionFactory, -) +from etools.applications.publics.tests.factories import PublicsCurrencyFactory, PublicsDSARegionFactory from etools.applications.t2f import UserTypes -from etools.applications.t2f.helpers.permission_matrix import ( - FakePermissionMatrix, - get_user_role_list, -) +from etools.applications.t2f.helpers.permission_matrix import FakePermissionMatrix, get_user_role_list from etools.applications.t2f.models import ModeOfTravel, Travel, TravelType from etools.applications.t2f.tests.factories import TravelFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/t2f/tests/test_travel_details.py b/src/etools/applications/t2f/tests/test_travel_details.py index 43f2b397ae..491d845b36 100644 --- a/src/etools/applications/t2f/tests/test_travel_details.py +++ b/src/etools/applications/t2f/tests/test_travel_details.py @@ -38,7 +38,6 @@ def test_urls(self): ('index', '', {'travel_pk': 1}), ('attachments', 'attachments/', {'travel_pk': 1}), ('attachment_details', 'attachments/1/', {'travel_pk': 1, 'attachment_pk': 1}), - ('clone_for_driver', 'add_driver/', {'travel_pk': 1}), ('clone_for_secondary_traveler', 'duplicate_travel/', {'travel_pk': 1}), ) self.assertReversal(names_and_paths, 't2f:travels:details:', '/api/t2f/travels/1/') @@ -216,16 +215,6 @@ def test_add_attachment(self): self.assertTrue(attachment_qs.exists()) def test_duplication(self): - data = {'traveler': self.unicef_staff.id} - response = self.forced_auth_req('post', reverse('t2f:travels:details:clone_for_driver', - kwargs={'travel_pk': self.travel.id}), - data=data, user=self.unicef_staff) - response_json = json.loads(response.rendered_content) - self.assertIn('id', response_json) - - cloned_travel = Travel.objects.get(id=response_json['id']) - self.assertNotEqual(cloned_travel.reference_number, self.travel.reference_number) - data = {'traveler': self.unicef_staff.id} response = self.forced_auth_req('post', reverse('t2f:travels:details:clone_for_secondary_traveler', kwargs={'travel_pk': self.travel.id}), diff --git a/src/etools/applications/t2f/urls.py b/src/etools/applications/t2f/urls.py index 9ce135d736..efec97e1ec 100644 --- a/src/etools/applications/t2f/urls.py +++ b/src/etools/applications/t2f/urls.py @@ -30,7 +30,6 @@ travel_attachment_details = TravelAttachmentViewSet.as_view({'delete': 'destroy'}) clone_travel_for_secondary_traveler = TravelDetailsViewSet.as_view({'post': 'clone_for_secondary_traveler'}) -clone_travel_for_driver = TravelDetailsViewSet.as_view({'post': 'clone_for_driver'}) action_points_dashboard_list = ActionPointDashboardViewSet.as_view({'get': 'list'}) @@ -42,7 +41,6 @@ url(r'^attachments/(?P[0-9]+)/$', travel_attachment_details, name='attachment_details'), url(details_state_changes_pattern, travel_details_state_change, name='state_change'), url(r'duplicate_travel/$', clone_travel_for_secondary_traveler, name='clone_for_secondary_traveler'), - url(r'^add_driver/$', clone_travel_for_driver, name='clone_for_driver'), ), 'details') diff --git a/src/etools/applications/t2f/views/exports.py b/src/etools/applications/t2f/views/exports.py index 43bdaebba7..f05408504d 100644 --- a/src/etools/applications/t2f/views/exports.py +++ b/src/etools/applications/t2f/views/exports.py @@ -12,10 +12,7 @@ from etools.applications.core.renderers import FriendlyCSVRenderer from etools.applications.t2f.filters import travel_list from etools.applications.t2f.models import ItineraryItem, Travel, TravelActivity -from etools.applications.t2f.serializers.export import ( - TravelActivityExportSerializer, - TravelAdminExportSerializer, -) +from etools.applications.t2f.serializers.export import TravelActivityExportSerializer, TravelAdminExportSerializer from etools.applications.t2f.views import T2FPagePagination diff --git a/src/etools/applications/t2f/views/travel.py b/src/etools/applications/t2f/views/travel.py index 43df4a16f7..781e5e32d1 100644 --- a/src/etools/applications/t2f/views/travel.py +++ b/src/etools/applications/t2f/views/travel.py @@ -107,14 +107,6 @@ def clone_for_secondary_traveler(self, request, *args, **kwargs): serializer = CloneOutputSerializer(clone, context=self.get_serializer_context()) return Response(serializer.data, status.HTTP_201_CREATED) - @atomic - def clone_for_driver(self, request, *args, **kwargs): - traveler = self._get_traveler_for_cloning() - helper = CloneTravelHelper(self.get_object()) - clone = helper.clone_for_driver(traveler) - serializer = CloneOutputSerializer(clone, context=self.get_serializer_context()) - return Response(serializer.data, status.HTTP_201_CREATED) - def _get_traveler_for_cloning(self): parameter_serializer = CloneParameterSerializer(data=self.request.data) parameter_serializer.is_valid(raise_exception=True) From ceaf7b5c74069222a0832eca592885a8ea99ebc2 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Fri, 12 Apr 2019 12:14:41 -0400 Subject: [PATCH 44/79] rename sector to section --- .../action_points/migrations/0001_initial.py | 2 +- .../migrations/0003_auto_20180518_1610.py | 2 +- .../applications/action_points/models.py | 2 +- .../migrations/0002_auto_20180326_1605.py | 4 ++-- .../tests/test_export_intervention.py | 20 ++++++++-------- src/etools/applications/reports/admin.py | 15 +++++++++--- .../reports/migrations/0001_initial.py | 8 +++---- .../migrations/0003_make_not_nullable.py | 6 ++--- .../migrations/0007_auto_20180424_1845.py | 6 ++--- .../migrations/0008_auto_20180515_1744.py | 3 ++- .../migrations/0014_auto_20181229_0249.py | 1 + .../migrations/0016_auto_20190412_1612.py | 17 +++++++++++++ src/etools/applications/reports/models.py | 9 +++---- .../applications/reports/tests/test_models.py | 15 ++++++++---- .../reports/tests/test_serializers.py | 24 ++++++++++++------- .../reports/tests/test_synchronizers.py | 10 +++++--- .../t2f/migrations/0001_initial.py | 2 +- src/etools/applications/t2f/models.py | 2 +- .../tpm/migrations/0001_initial.py | 2 +- src/etools/applications/tpm/models.py | 2 +- 20 files changed, 98 insertions(+), 54 deletions(-) create mode 100644 src/etools/applications/reports/migrations/0016_auto_20190412_1612.py diff --git a/src/etools/applications/action_points/migrations/0001_initial.py b/src/etools/applications/action_points/migrations/0001_initial.py index 7b93d6c581..23d2e78853 100644 --- a/src/etools/applications/action_points/migrations/0001_initial.py +++ b/src/etools/applications/action_points/migrations/0001_initial.py @@ -60,7 +60,7 @@ class Migration(migrations.Migration): ('partner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='partners.PartnerOrganization', verbose_name='Partner')), ('section', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, - to='reports.Sector', verbose_name='Section')), + to='reports.Section', verbose_name='Section')), ('tpm_activity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='tpm.TPMActivity', verbose_name='TPM Activity')), ('travel_activity', models.ForeignKey(blank=True, null=True, diff --git a/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py b/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py index 796210bcbc..f0737cbcdb 100644 --- a/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py +++ b/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py @@ -39,6 +39,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='actionpoint', name='section', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='reports.Sector', verbose_name='Section'), + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='reports.Section', verbose_name='Section'), ), ] diff --git a/src/etools/applications/action_points/models.py b/src/etools/applications/action_points/models.py index d090b0f40a..70bf651d75 100644 --- a/src/etools/applications/action_points/models.py +++ b/src/etools/applications/action_points/models.py @@ -60,7 +60,7 @@ class ActionPoint(TimeStampedModel): due_date = models.DateField(verbose_name=_('Due Date'), blank=True, null=True) high_priority = models.BooleanField(default=False, verbose_name=_('High Priority')) - section = models.ForeignKey('reports.Sector', verbose_name=_('Section'), blank=True, null=True, + section = models.ForeignKey('reports.Section', verbose_name=_('Section'), blank=True, null=True, on_delete=models.CASCADE, ) office = models.ForeignKey('users.Office', verbose_name=_('Office'), blank=True, null=True, diff --git a/src/etools/applications/partners/migrations/0002_auto_20180326_1605.py b/src/etools/applications/partners/migrations/0002_auto_20180326_1605.py index 92b0b55811..556a68b8b7 100644 --- a/src/etools/applications/partners/migrations/0002_auto_20180326_1605.py +++ b/src/etools/applications/partners/migrations/0002_auto_20180326_1605.py @@ -23,7 +23,7 @@ class Migration(migrations.Migration): model_name='interventionsectorlocationlink', name='sector', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, - related_name='intervention_locations', to='reports.Sector', verbose_name='Sector'), + related_name='intervention_locations', to='reports.Section', verbose_name='Sector'), ), migrations.AddField( model_name='interventionresultlink', @@ -118,7 +118,7 @@ class Migration(migrations.Migration): model_name='intervention', name='sections', field=models.ManyToManyField(blank=True, related_name='interventions', - to='reports.Sector', verbose_name='Sections'), + to='reports.Section', verbose_name='Sections'), ), migrations.AddField( model_name='intervention', diff --git a/src/etools/applications/partners/tests/test_export_intervention.py b/src/etools/applications/partners/tests/test_export_intervention.py index 0beb0e4bf3..74c23c4967 100644 --- a/src/etools/applications/partners/tests/test_export_intervention.py +++ b/src/etools/applications/partners/tests/test_export_intervention.py @@ -389,8 +389,8 @@ def test_intervention_location_export(self): self.intervention.flat_locations.add(LocationFactory(name='Location 0'), LocationFactory(name='Location 1')) # Some sections - sec = SectionFactory(name='Sector 0') - sec1 = SectionFactory(name='Sector 1') + sec = SectionFactory(name='Section 0') + sec1 = SectionFactory(name='Section 1') self.intervention.sections.add(sec, sec1) # Some focal points @@ -409,8 +409,8 @@ def test_intervention_location_export(self): self.intervention2 = InterventionFactory( agreement=AgreementFactory(partner=PartnerFactory(name='Partner 2', vendor_number='123'))) # Sections - sec2 = SectionFactory(name='Sector 2') - sec3 = SectionFactory(name='Sector 3') + sec2 = SectionFactory(name='Section 2') + sec3 = SectionFactory(name='Section 3') self.intervention2.sections.add(sec2, sec3) # Results InterventionResultLinkFactory( @@ -453,12 +453,12 @@ def test_intervention_location_export(self): agreement_number_3 = self.intervention3.agreement.agreement_number self.assertEqual( f'Partner,Vendor Number,PD Ref Number,Agreement,Status,Location,Section,CP output,Start Date,End Date,Name of UNICEF Focal Point,Hyperlink\r\n' - f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 0,Sector 0,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' - f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 1,Sector 0,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' - f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 0,Sector 1,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' - f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 1,Sector 1,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' - f'Partner 2,123,{self.intervention2.number},{agreement_number_2},draft,,Sector 2,"Result C, Result D",,,,https://testserver/pmp/interventions/{self.intervention2.id}/details/\r\n' - f'Partner 2,123,{self.intervention2.number},{agreement_number_2},draft,,Sector 3,"Result C, Result D",,,,https://testserver/pmp/interventions/{self.intervention2.id}/details/\r\n' + f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 0,Section 0,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' + f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 1,Section 0,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' + f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 0,Section 1,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' + f'{partner_name},{partner_vendor_code},{self.intervention.number},{agreement_number_1},draft,Location 1,Section 1,"Result A, Result B",2013-01-06,2013-03-20,"Jack Bennie, Phil Silver",https://testserver/pmp/interventions/{self.intervention.id}/details/\r\n' + f'Partner 2,123,{self.intervention2.number},{agreement_number_2},draft,,Section 2,"Result C, Result D",,,,https://testserver/pmp/interventions/{self.intervention2.id}/details/\r\n' + f'Partner 2,123,{self.intervention2.number},{agreement_number_2},draft,,Section 3,"Result C, Result D",,,,https://testserver/pmp/interventions/{self.intervention2.id}/details/\r\n' f'Partner 3,456,{self.intervention3.number},{agreement_number_3},draft,Location 2,,Result Fred,,,,https://testserver/pmp/interventions/{self.intervention3.id}/details/\r\n', result, ) diff --git a/src/etools/applications/reports/admin.py b/src/etools/applications/reports/admin.py index 1a3174d8cc..edf942ff7c 100644 --- a/src/etools/applications/reports/admin.py +++ b/src/etools/applications/reports/admin.py @@ -5,9 +5,18 @@ from unicef_djangolib.forms import AutoSizeTextForm from etools.applications.reports.forms import IndicatorAdminForm -from etools.applications.reports.models import (AppliedIndicator, CountryProgramme, Disaggregation, - DisaggregationValue, Indicator, IndicatorBlueprint, - LowerResult, Result, Section, Unit,) +from etools.applications.reports.models import ( + AppliedIndicator, + CountryProgramme, + Disaggregation, + DisaggregationValue, + Indicator, + IndicatorBlueprint, + LowerResult, + Result, + Section, + Unit, +) class SectionListFilter(admin.SimpleListFilter): diff --git a/src/etools/applications/reports/migrations/0001_initial.py b/src/etools/applications/reports/migrations/0001_initial.py index 0f9c1137bb..caae0550b6 100644 --- a/src/etools/applications/reports/migrations/0001_initial.py +++ b/src/etools/applications/reports/migrations/0001_initial.py @@ -211,7 +211,7 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name='Sector', + name='Section', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', model_utils.fields.AutoCreatedField( @@ -249,7 +249,7 @@ class Migration(migrations.Migration): model_name='result', name='sector', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, - to='reports.Sector', verbose_name='Section'), + to='reports.Section', verbose_name='Section'), ), migrations.AddField( model_name='indicator', @@ -261,7 +261,7 @@ class Migration(migrations.Migration): model_name='indicator', name='sector', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, - to='reports.Sector', verbose_name='Section'), + to='reports.Section', verbose_name='Section'), ), migrations.AddField( model_name='indicator', @@ -297,7 +297,7 @@ class Migration(migrations.Migration): model_name='appliedindicator', name='section', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, - to='reports.Sector', verbose_name='Section'), + to='reports.Section', verbose_name='Section'), ), migrations.AlterUniqueTogether( name='result', diff --git a/src/etools/applications/reports/migrations/0003_make_not_nullable.py b/src/etools/applications/reports/migrations/0003_make_not_nullable.py index e8a740e87d..08a0a80550 100644 --- a/src/etools/applications/reports/migrations/0003_make_not_nullable.py +++ b/src/etools/applications/reports/migrations/0003_make_not_nullable.py @@ -111,17 +111,17 @@ class Migration(migrations.Migration): field=models.CharField(blank=True, default='', max_length=10, verbose_name='VISION ID'), ), migrations.AlterField( - model_name='sector', + model_name='section', name='alternate_name', field=models.CharField(blank=True, default='', max_length=255, verbose_name='Alternate Name'), ), migrations.AlterField( - model_name='sector', + model_name='section', name='color', field=models.CharField(blank=True, default='', max_length=7, verbose_name='Color'), ), migrations.AlterField( - model_name='sector', + model_name='section', name='description', field=models.CharField(blank=True, default='', max_length=256, verbose_name='Description'), ), diff --git a/src/etools/applications/reports/migrations/0007_auto_20180424_1845.py b/src/etools/applications/reports/migrations/0007_auto_20180424_1845.py index 735c4c533b..845bb702ac 100644 --- a/src/etools/applications/reports/migrations/0007_auto_20180424_1845.py +++ b/src/etools/applications/reports/migrations/0007_auto_20180424_1845.py @@ -106,17 +106,17 @@ class Migration(migrations.Migration): field=models.CharField(blank=True, max_length=10, null=True, verbose_name='VISION ID'), ), migrations.AlterField( - model_name='sector', + model_name='section', name='alternate_name', field=models.CharField(default='', max_length=255, null=True, verbose_name='Alternate Name'), ), migrations.AlterField( - model_name='sector', + model_name='section', name='color', field=models.CharField(blank=True, max_length=7, null=True, verbose_name='Color'), ), migrations.AlterField( - model_name='sector', + model_name='section', name='description', field=models.CharField(blank=True, max_length=256, null=True, verbose_name='Description'), ), diff --git a/src/etools/applications/reports/migrations/0008_auto_20180515_1744.py b/src/etools/applications/reports/migrations/0008_auto_20180515_1744.py index 65d5497608..5035557371 100644 --- a/src/etools/applications/reports/migrations/0008_auto_20180515_1744.py +++ b/src/etools/applications/reports/migrations/0008_auto_20180515_1744.py @@ -1,7 +1,8 @@ # Generated by Django 1.10.8 on 2018-05-15 17:44 -from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from django.db import migrations, models + import model_utils.fields diff --git a/src/etools/applications/reports/migrations/0014_auto_20181229_0249.py b/src/etools/applications/reports/migrations/0014_auto_20181229_0249.py index c299687139..c9d428b0a1 100644 --- a/src/etools/applications/reports/migrations/0014_auto_20181229_0249.py +++ b/src/etools/applications/reports/migrations/0014_auto_20181229_0249.py @@ -2,6 +2,7 @@ import django.contrib.postgres.fields.jsonb from django.db import migrations + import etools.applications.reports.models diff --git a/src/etools/applications/reports/migrations/0016_auto_20190412_1612.py b/src/etools/applications/reports/migrations/0016_auto_20190412_1612.py new file mode 100644 index 0000000000..c5a7a59356 --- /dev/null +++ b/src/etools/applications/reports/migrations/0016_auto_20190412_1612.py @@ -0,0 +1,17 @@ +# Generated by Django 2.1.7 on 2019-04-12 16:12 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reports', '0015_auto_20190208_2042'), + ] + + operations = [ + migrations.AlterModelTable( + name='section', + table='reports_sector', + ), + ] diff --git a/src/etools/applications/reports/models.py b/src/etools/applications/reports/models.py index f356789ecb..d6e9540adf 100644 --- a/src/etools/applications/reports/models.py +++ b/src/etools/applications/reports/models.py @@ -8,7 +8,6 @@ from model_utils.fields import AutoCreatedField, AutoLastModifiedField from model_utils.models import TimeStampedModel from mptt.models import MPTTModel, TreeForeignKey - from unicef_locations.models import Location @@ -130,7 +129,7 @@ def __str__(self): return self.name -class Sector(TimeStampedModel): +class Section(TimeStampedModel): """ Represents a section """ @@ -144,6 +143,7 @@ class Sector(TimeStampedModel): class Meta: ordering = ['name'] + db_table = 'reports_sector' def __str__(self): return '{} {}'.format( @@ -152,9 +152,6 @@ def __str__(self): ) -Section = Sector - - class ResultManager(models.Manager): def get_queryset(self): return super().get_queryset().select_related( @@ -172,7 +169,7 @@ class Result(MPTTModel): Represents a result, wbs is unique Relates to :model:`reports.CountryProgramme` - Relates to :model:`reports.Sector` + Relates to :model:`reports.Section` Relates to :model:`reports.ResultType` """ country_programme = models.ForeignKey( diff --git a/src/etools/applications/reports/tests/test_models.py b/src/etools/applications/reports/tests/test_models.py index 87f5ee572a..e3078a355b 100644 --- a/src/etools/applications/reports/tests/test_models.py +++ b/src/etools/applications/reports/tests/test_models.py @@ -3,14 +3,21 @@ from django.test import SimpleTestCase - from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import Agreement from etools.applications.partners.tests.factories import AgreementFactory from etools.applications.reports.models import CountryProgramme, Indicator, IndicatorBlueprint, Quarter -from etools.applications.reports.tests.factories import (CountryProgrammeFactory, IndicatorBlueprintFactory, - IndicatorFactory, LowerResultFactory, QuarterFactory, - ResultFactory, ResultTypeFactory, SectionFactory, UnitFactory,) +from etools.applications.reports.tests.factories import ( + CountryProgrammeFactory, + IndicatorBlueprintFactory, + IndicatorFactory, + LowerResultFactory, + QuarterFactory, + ResultFactory, + ResultTypeFactory, + SectionFactory, + UnitFactory, +) class TestStrUnicode(SimpleTestCase): diff --git a/src/etools/applications/reports/tests/test_serializers.py b/src/etools/applications/reports/tests/test_serializers.py index cc7d0cd5d2..9ca2ae035e 100644 --- a/src/etools/applications/reports/tests/test_serializers.py +++ b/src/etools/applications/reports/tests/test_serializers.py @@ -1,20 +1,28 @@ -from django.urls import reverse from django.test import RequestFactory +from django.urls import reverse from rest_framework.exceptions import ValidationError - -from etools.applications.core.tests.cases import BaseTenantTestCase from unicef_locations.tests.factories import LocationFactory +from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import Intervention from etools.applications.partners.tests.factories import InterventionFactory, InterventionResultLinkFactory from etools.applications.reports.models import AppliedIndicator, IndicatorBlueprint, LowerResult -from etools.applications.reports.serializers.v2 import (AppliedIndicatorSerializer, DisaggregationSerializer, - LowerResultCUSerializer, LowerResultSimpleCUSerializer,) -from etools.applications.reports.tests.factories import (AppliedIndicatorFactory, DisaggregationFactory, - DisaggregationValueFactory, IndicatorBlueprintFactory, - LowerResultFactory, SectionFactory,) +from etools.applications.reports.serializers.v2 import ( + AppliedIndicatorSerializer, + DisaggregationSerializer, + LowerResultCUSerializer, + LowerResultSimpleCUSerializer, +) +from etools.applications.reports.tests.factories import ( + AppliedIndicatorFactory, + DisaggregationFactory, + DisaggregationValueFactory, + IndicatorBlueprintFactory, + LowerResultFactory, + SectionFactory, +) class DisaggregationTest(BaseTenantTestCase): diff --git a/src/etools/applications/reports/tests/test_synchronizers.py b/src/etools/applications/reports/tests/test_synchronizers.py index 7dced2291e..a720057cb7 100644 --- a/src/etools/applications/reports/tests/test_synchronizers.py +++ b/src/etools/applications/reports/tests/test_synchronizers.py @@ -3,11 +3,15 @@ import json from etools.applications.core.tests.cases import BaseTenantTestCase +from etools.applications.reports import synchronizers from etools.applications.reports.models import CountryProgramme, Indicator, Result, ResultType -from etools.applications.reports.tests.factories import (CountryProgrammeFactory, IndicatorFactory, - ResultFactory, ResultTypeFactory,) +from etools.applications.reports.tests.factories import ( + CountryProgrammeFactory, + IndicatorFactory, + ResultFactory, + ResultTypeFactory, +) from etools.applications.users.models import Country -from etools.applications.reports import synchronizers class TestResultStructureSynchronizer(BaseTenantTestCase): diff --git a/src/etools/applications/t2f/migrations/0001_initial.py b/src/etools/applications/t2f/migrations/0001_initial.py index f258fda362..a1b3d66c86 100644 --- a/src/etools/applications/t2f/migrations/0001_initial.py +++ b/src/etools/applications/t2f/migrations/0001_initial.py @@ -177,7 +177,7 @@ class Migration(migrations.Migration): ('office', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='users.Office', verbose_name='Office')), ('sector', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, - related_name='+', to='reports.Sector', verbose_name='Section')), + related_name='+', to='reports.Section', verbose_name='Section')), ('supervisor', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Supervisor')), ('traveler', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, diff --git a/src/etools/applications/t2f/models.py b/src/etools/applications/t2f/models.py index 060b720d7c..dc5692a8c5 100644 --- a/src/etools/applications/t2f/models.py +++ b/src/etools/applications/t2f/models.py @@ -137,7 +137,7 @@ class Travel(models.Model): on_delete=models.CASCADE, ) section = models.ForeignKey( - 'reports.Sector', null=True, blank=True, related_name='+', verbose_name=_('Section'), + 'reports.Section', null=True, blank=True, related_name='+', verbose_name=_('Section'), on_delete=models.CASCADE, ) start_date = models.DateField(null=True, blank=True, verbose_name=_('Start Date')) diff --git a/src/etools/applications/tpm/migrations/0001_initial.py b/src/etools/applications/tpm/migrations/0001_initial.py index 010cc47c1f..d89fa81faa 100644 --- a/src/etools/applications/tpm/migrations/0001_initial.py +++ b/src/etools/applications/tpm/migrations/0001_initial.py @@ -56,7 +56,7 @@ class Migration(migrations.Migration): ('additional_information', models.TextField(blank=True, verbose_name='Additional Information')), ('is_pv', models.BooleanField(default=False, verbose_name='HACT Programmatic Visit')), ('section', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, - related_name='tpm_activities', to='reports.Sector', verbose_name='Section')), + related_name='tpm_activities', to='reports.Section', verbose_name='Section')), ], options={ 'ordering': ['tpm_visit', 'id'], diff --git a/src/etools/applications/tpm/models.py b/src/etools/applications/tpm/models.py index c7491b72b0..88b81e5726 100644 --- a/src/etools/applications/tpm/models.py +++ b/src/etools/applications/tpm/models.py @@ -388,7 +388,7 @@ class TPMActivity(Activity): verbose_name=_('Office(s) of UNICEF Focal Point(s)')) section = models.ForeignKey( - 'reports.Sector', related_name='tpm_activities', verbose_name=_('Section'), + 'reports.Section', related_name='tpm_activities', verbose_name=_('Section'), on_delete=models.CASCADE, ) From f8518bb6cd815a5a2cef57e6379b5f33b69a5fd1 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 11 Apr 2019 15:56:44 -0400 Subject: [PATCH 45/79] sort --- Pipfile | 4 ++-- .../action_points/tests/factories.py | 7 +++--- .../applications/tpm/tests/factories.py | 2 +- src/etools/applications/users/admin.py | 1 + .../migrations/0001_squashed_0007_user.py | 6 +++-- .../migrations/0008_auto_20190111_1525.py | 3 ++- src/etools/applications/users/models.py | 1 + .../applications/users/tests/factories.py | 2 +- .../applications/users/tests/test_csrf.py | 2 +- .../applications/users/tests/test_views.py | 13 ---------- src/etools/applications/users/urls.py | 9 +------ src/etools/applications/users/urls_v2.py | 11 ++++++--- src/etools/applications/users/urls_v3.py | 9 +++++-- src/etools/applications/users/views.py | 11 --------- src/etools/applications/users/views_v2.py | 4 ---- .../utils/common/tests/factories.py | 24 ------------------- src/etools/config/urls.py | 21 ++++++++-------- src/etools/libraries/tests/factories.py | 24 +++++++++++++++++++ 18 files changed, 67 insertions(+), 87 deletions(-) delete mode 100644 src/etools/applications/utils/common/tests/factories.py diff --git a/Pipfile b/Pipfile index cf13ddc4fb..29ff0284d1 100644 --- a/Pipfile +++ b/Pipfile @@ -4,6 +4,7 @@ url = "https://pypi.org/simple" verify_ssl = true [dev-packages] +django-debug-toolbar = "==1.11" flake8 = "*" coverage = "*" mock = "*" @@ -15,7 +16,6 @@ pdbpp = "*" tox = "*" drf-api-checker = "*" factory-boy = ">=2.11" -django-extensions = "*" sphinx = "*" [packages] @@ -31,7 +31,7 @@ django-celery-email = "==2.0.1" django_celery_results = "==1.0.4" django-contrib-comments = "==1.9.1" django-cors-headers = "==2.5" -django-debug-toolbar = "==1.11" +django-extensions = "==2.1.6" django-easy-pdf = "==0.1.1" django-filter = "==2.1" django-fsm = "==2.6" diff --git a/src/etools/applications/action_points/tests/factories.py b/src/etools/applications/action_points/tests/factories.py index b892848d93..2bc3e57f7d 100644 --- a/src/etools/applications/action_points/tests/factories.py +++ b/src/etools/applications/action_points/tests/factories.py @@ -4,16 +4,15 @@ import factory.fuzzy from django_comments.models import Comment - -from etools.applications.action_points.models import ActionPoint -from etools.applications.action_points.categories.models import Category from unicef_locations.tests.factories import LocationFactory +from etools.applications.action_points.categories.models import Category +from etools.applications.action_points.models import ActionPoint from etools.applications.partners.tests.factories import InterventionFactory, ResultFactory from etools.applications.reports.tests.factories import SectionFactory from etools.applications.users.tests.factories import UserFactory -from etools.applications.utils.common.tests.factories import StatusFactoryMetaClass from etools.libraries.djangolib.utils import get_current_site +from etools.libraries.tests.factories import StatusFactoryMetaClass class ActionPointCommentFactory(factory.DjangoModelFactory): diff --git a/src/etools/applications/tpm/tests/factories.py b/src/etools/applications/tpm/tests/factories.py index 2842f523d2..d7a2b1a512 100644 --- a/src/etools/applications/tpm/tests/factories.py +++ b/src/etools/applications/tpm/tests/factories.py @@ -16,7 +16,7 @@ from etools.applications.tpm.models import TPMActivity, TPMVisit, TPMVisitReportRejectComment from etools.applications.tpm.tpmpartners.models import TPMPartner, TPMPartnerStaffMember from etools.applications.users.tests.factories import OfficeFactory as SimpleOfficeFactory, PMEUserFactory, UserFactory -from etools.applications.utils.common.tests.factories import StatusFactoryMetaClass +from etools.libraries.tests.factories import StatusFactoryMetaClass _FUZZY_START_DATE = timezone.now().date() - datetime.timedelta(days=5) _FUZZY_END_DATE = timezone.now().date() + datetime.timedelta(days=5) diff --git a/src/etools/applications/users/admin.py b/src/etools/applications/users/admin.py index 80e88e27c8..3204577354 100644 --- a/src/etools/applications/users/admin.py +++ b/src/etools/applications/users/admin.py @@ -7,6 +7,7 @@ from django.http.response import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import reverse + from django_tenants.utils import get_public_schema_name from etools.applications.hact.tasks import update_hact_for_country, update_hact_values diff --git a/src/etools/applications/users/migrations/0001_squashed_0007_user.py b/src/etools/applications/users/migrations/0001_squashed_0007_user.py index 0075b951e1..228c72fc60 100644 --- a/src/etools/applications/users/migrations/0001_squashed_0007_user.py +++ b/src/etools/applications/users/migrations/0001_squashed_0007_user.py @@ -2,12 +2,14 @@ from __future__ import unicode_literals from decimal import Decimal -from django.conf import settings + import django.contrib.auth.models import django.core.validators -from django.db import migrations, models import django.db.migrations.operations.special import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + import django_tenants.postgresql_backend.base diff --git a/src/etools/applications/users/migrations/0008_auto_20190111_1525.py b/src/etools/applications/users/migrations/0008_auto_20190111_1525.py index d1663e7c7d..8b774727b3 100644 --- a/src/etools/applications/users/migrations/0008_auto_20190111_1525.py +++ b/src/etools/applications/users/migrations/0008_auto_20190111_1525.py @@ -1,7 +1,8 @@ # Generated by Django 2.0.9 on 2019-01-11 15:25 -from django.db import migrations import django.utils.timezone +from django.db import migrations + import model_utils.fields diff --git a/src/etools/applications/users/models.py b/src/etools/applications/users/models.py index 3d5708a19e..052c50c40b 100644 --- a/src/etools/applications/users/models.py +++ b/src/etools/applications/users/models.py @@ -9,6 +9,7 @@ from django.db.models.signals import post_save from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ + from django_tenants.models import TenantMixin from model_utils.models import TimeStampedModel diff --git a/src/etools/applications/users/tests/factories.py b/src/etools/applications/users/tests/factories.py index 588b8e3430..d921433f9a 100644 --- a/src/etools/applications/users/tests/factories.py +++ b/src/etools/applications/users/tests/factories.py @@ -7,8 +7,8 @@ from factory.fuzzy import FuzzyText from etools.applications.core.tests.cases import SCHEMA_NAME -from etools.applications.users import models from etools.applications.publics.tests.factories import PublicsCurrencyFactory +from etools.applications.users import models class GroupFactory(factory.django.DjangoModelFactory): diff --git a/src/etools/applications/users/tests/test_csrf.py b/src/etools/applications/users/tests/test_csrf.py index 794d3e1076..e71dec744d 100644 --- a/src/etools/applications/users/tests/test_csrf.py +++ b/src/etools/applications/users/tests/test_csrf.py @@ -1,5 +1,5 @@ -from django.urls import reverse from django.test import Client, TestCase +from django.urls import reverse from rest_framework import status diff --git a/src/etools/applications/users/tests/test_views.py b/src/etools/applications/users/tests/test_views.py index 4132aa319b..39037fb28a 100644 --- a/src/etools/applications/users/tests/test_views.py +++ b/src/etools/applications/users/tests/test_views.py @@ -1,4 +1,3 @@ - import json from operator import itemgetter from unittest import skip @@ -15,18 +14,6 @@ from etools.applications.users.tests.factories import CountryFactory, GroupFactory, OfficeFactory, UserFactory -class TestUserAuthAPIView(BaseTenantTestCase): - def test_get(self): - self.user = UserFactory() - response = self.forced_auth_req( - "get", - reverse("users:user-api-profile"), - user=self.user - ) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data["id"], self.user.pk) - - class TestChangeUserCountry(BaseTenantTestCase): @classmethod def setUpTestData(cls): diff --git a/src/etools/applications/users/urls.py b/src/etools/applications/users/urls.py index f3adc4cba5..1d2899454f 100644 --- a/src/etools/applications/users/urls.py +++ b/src/etools/applications/users/urls.py @@ -1,17 +1,10 @@ from django.conf.urls import url -from etools.applications.users.views import ( - ChangeUserCountryView, - MyProfileAPIView, - StaffUsersView, - UserAuthAPIView, - UsersDetailAPIView, -) +from etools.applications.users.views import ChangeUserCountryView, MyProfileAPIView, StaffUsersView, UsersDetailAPIView app_name = 'users' urlpatterns = ( # api - url(r'^api/profile/$', UserAuthAPIView.as_view(), name="user-api-profile"), url(r'^api/changecountry/$', ChangeUserCountryView.as_view(), name="country-change"), url(r'^api/$', StaffUsersView.as_view()), url(r'^api/(?P\d+)/$', UsersDetailAPIView.as_view(http_method_names=['get']), name="user-detail"), diff --git a/src/etools/applications/users/urls_v2.py b/src/etools/applications/users/urls_v2.py index 6103edf90c..6e5c761a77 100644 --- a/src/etools/applications/users/urls_v2.py +++ b/src/etools/applications/users/urls_v2.py @@ -1,11 +1,16 @@ from django.conf.urls import url -from etools.applications.users.views_v2 import (ChangeUserCountryView, CountriesViewSet, CountryView, MyProfileAPIView, - StaffUsersView, UserAuthAPIView, UsersDetailAPIView,) +from etools.applications.users.views_v2 import ( + ChangeUserCountryView, + CountriesViewSet, + CountryView, + MyProfileAPIView, + StaffUsersView, + UsersDetailAPIView, +) app_name = 'users' urlpatterns = ( - url(r'^profile/$', UserAuthAPIView.as_view()), url(r'^changecountry/$', ChangeUserCountryView.as_view(http_method_names=['post']), name="country-change"), url(r'^$', StaffUsersView.as_view()), url(r'^(?P\d)/$', UsersDetailAPIView.as_view(http_method_names=['get']), name="user-detail"), diff --git a/src/etools/applications/users/urls_v3.py b/src/etools/applications/users/urls_v3.py index 7f50e8d844..b08450320d 100644 --- a/src/etools/applications/users/urls_v3.py +++ b/src/etools/applications/users/urls_v3.py @@ -1,8 +1,13 @@ from django.conf.urls import url from etools.applications.users.views import ADUserAPIView -from etools.applications.users.views_v3 import (ChangeUserCountryView, CountryView, MyProfileAPIView, - UsersDetailAPIView, UsersListAPIView,) +from etools.applications.users.views_v3 import ( + ChangeUserCountryView, + CountryView, + MyProfileAPIView, + UsersDetailAPIView, + UsersListAPIView, +) app_name = 'users' urlpatterns = ( diff --git a/src/etools/applications/users/views.py b/src/etools/applications/users/views.py index ea9cb92e58..0acb72e0a3 100644 --- a/src/etools/applications/users/views.py +++ b/src/etools/applications/users/views.py @@ -26,23 +26,12 @@ SimpleProfileSerializer, SimpleUserSerializer, UserCreationSerializer, - UserSerializer, ) from etools.libraries.azure_graph_api.tasks import retrieve_user_info logger = logging.getLogger(__name__) -class UserAuthAPIView(RetrieveAPIView): - # TODO: Consider removing now use JWT - model = get_user_model() - serializer_class = UserSerializer - - def get_object(self, queryset=None, **kwargs): - user = self.request.user - return user - - class ADUserAPIView(DetailView): template_name = 'admin/users/user/api.html' model = get_user_model() diff --git a/src/etools/applications/users/views_v2.py b/src/etools/applications/users/views_v2.py index 97915da8ff..52013a0fe0 100644 --- a/src/etools/applications/users/views_v2.py +++ b/src/etools/applications/users/views_v2.py @@ -9,10 +9,6 @@ logger = logging.getLogger(__name__) -class UserAuthAPIView(v1.UserAuthAPIView): - """Stub for UserAuthAPIView""" - - class ChangeUserCountryView(v1.ChangeUserCountryView): """Stub for ChangeUserCountryView""" diff --git a/src/etools/applications/utils/common/tests/factories.py b/src/etools/applications/utils/common/tests/factories.py deleted file mode 100644 index 0f1e4f8818..0000000000 --- a/src/etools/applications/utils/common/tests/factories.py +++ /dev/null @@ -1,24 +0,0 @@ -from factory.base import FactoryMetaClass - - -class StatusFactoryMetaClass(FactoryMetaClass): - """ - Factory metaclass to generate object in correct status with dependent attributes. - When new object is generated, metaclass check for corresponding factory in provided status_factories - and if found, generate instance using it. - """ - - def __call__(cls, **kwargs): - status = kwargs.pop('status', None) - factory = cls._status_factories.get(status) - if factory: - return factory(**kwargs) - - return super().__call__(**kwargs) - - def __new__(mcs, class_name, bases, attrs): - # hide status_factories property to avoid it being consumed by model.create - status_factories = attrs.pop('status_factories', {}) - new_class = super().__new__(mcs, class_name, bases, attrs) - new_class._status_factories = status_factories - return new_class diff --git a/src/etools/config/urls.py b/src/etools/config/urls.py index 87045cdf3a..fc1748da6c 100644 --- a/src/etools/config/urls.py +++ b/src/etools/config/urls.py @@ -7,17 +7,19 @@ from rest_framework_nested import routers from rest_framework_swagger.renderers import OpenAPIRenderer -from etools.applications.core.views import ( - IssueJWTRedirectView, - logout_view, - MainView, -) +from etools.applications.core.schemas import get_schema_view, get_swagger_view +from etools.applications.core.views import IssueJWTRedirectView, logout_view, MainView from etools.applications.management.urls import urlpatterns as management_urls from etools.applications.partners.views.v1 import FileTypeViewSet from etools.applications.publics import urls as publics_patterns from etools.applications.publics.views import StaticDataView -from etools.applications.reports.views.v1 import IndicatorViewSet, ResultTypeViewSet, ResultViewSet, UnitViewSet, \ - SectionViewSet +from etools.applications.reports.views.v1 import ( + IndicatorViewSet, + ResultTypeViewSet, + ResultViewSet, + SectionViewSet, + UnitViewSet, +) from etools.applications.t2f.urls import urlpatterns as t2f_patterns from etools.applications.users.views import ( CountriesViewSet, @@ -26,7 +28,8 @@ OfficeViewSet, UserViewSet, ) -from etools.applications.core.schemas import get_schema_view, get_swagger_view +# these imports are used to autodiscover admin forms located outside of INSTALLED_APPS(the libraries folder for example) +from etools.libraries.locations import admin as locations_admin # noqa: ignore=F401 from etools.libraries.locations.views import ( CartoDBTablesView, LocationQuerySetView, @@ -34,8 +37,6 @@ LocationsViewSet, LocationTypesViewSet, ) -# these imports are used to autodiscover admin forms located outside of INSTALLED_APPS(the libraries folder for example) -from etools.libraries.locations import admin as locations_admin # noqa: ignore=F401 # ****************** API docs and schemas ****************************** schema_view = get_swagger_view(title='eTools API') diff --git a/src/etools/libraries/tests/factories.py b/src/etools/libraries/tests/factories.py index 626ba3102c..6673aaf4ea 100644 --- a/src/etools/libraries/tests/factories.py +++ b/src/etools/libraries/tests/factories.py @@ -1,4 +1,5 @@ import factory +from factory.base import FactoryMetaClass class InheritedTrait(factory.Trait): @@ -11,3 +12,26 @@ def __init__(self, *parents, **kwargs): overrides.update(kwargs) super().__init__(**overrides) + + +class StatusFactoryMetaClass(FactoryMetaClass): + """ + Factory metaclass to generate object in correct status with dependent attributes. + When new object is generated, metaclass check for corresponding factory in provided status_factories + and if found, generate instance using it. + """ + + def __call__(cls, **kwargs): + status = kwargs.pop('status', None) + factory = cls._status_factories.get(status) + if factory: + return factory(**kwargs) + + return super().__call__(**kwargs) + + def __new__(mcs, class_name, bases, attrs): + # hide status_factories property to avoid it being consumed by model.create + status_factories = attrs.pop('status_factories', {}) + new_class = super().__new__(mcs, class_name, bases, attrs) + new_class._status_factories = status_factories + return new_class From 21c8a00ca67131a1cc67617b6c9d5f6510406a49 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 15 Apr 2019 10:06:10 -0400 Subject: [PATCH 46/79] visit export amend --- src/etools/applications/tpm/admin.py | 2 +- src/etools/applications/tpm/export/serializers.py | 1 + .../applications/tpm/migrations/0005_tpmvisit_author.py | 2 +- .../applications/tpm/migrations/0006_auto_20180522_0736.py | 1 - src/etools/applications/tpm/serializers/attachments.py | 1 + src/etools/applications/tpm/tests/base.py | 2 +- src/etools/applications/tpm/tests/test_transitions.py | 4 ++-- src/etools/applications/tpm/views.py | 2 +- 8 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/etools/applications/tpm/admin.py b/src/etools/applications/tpm/admin.py index f0e9b08b62..3fc12e4907 100644 --- a/src/etools/applications/tpm/admin.py +++ b/src/etools/applications/tpm/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin from etools.applications.publics.admin import AdminListMixin -from etools.applications.tpm import models, forms +from etools.applications.tpm import forms, models @admin.register(models.TPMActivity) diff --git a/src/etools/applications/tpm/export/serializers.py b/src/etools/applications/tpm/export/serializers.py index 7f6e7cd5ab..325e72fb72 100644 --- a/src/etools/applications/tpm/export/serializers.py +++ b/src/etools/applications/tpm/export/serializers.py @@ -98,6 +98,7 @@ class TPMVisitExportSerializer(serializers.Serializer): report_link = serializers.SerializerMethodField() attachments = serializers.SerializerMethodField() additional_information = CommaSeparatedExportField(source='tpm_activities.additional_information', allow_null=True) + visit_information = serializers.CharField() link = serializers.CharField(source='get_object_url') def get_report_link(self, obj): diff --git a/src/etools/applications/tpm/migrations/0005_tpmvisit_author.py b/src/etools/applications/tpm/migrations/0005_tpmvisit_author.py index 0f3208ddd1..62a993e583 100644 --- a/src/etools/applications/tpm/migrations/0005_tpmvisit_author.py +++ b/src/etools/applications/tpm/migrations/0005_tpmvisit_author.py @@ -1,7 +1,7 @@ # Generated by Django 1.10.8 on 2018-05-21 14:22 +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): diff --git a/src/etools/applications/tpm/migrations/0006_auto_20180522_0736.py b/src/etools/applications/tpm/migrations/0006_auto_20180522_0736.py index bbcc144238..c7f8b9f499 100644 --- a/src/etools/applications/tpm/migrations/0006_auto_20180522_0736.py +++ b/src/etools/applications/tpm/migrations/0006_auto_20180522_0736.py @@ -3,7 +3,6 @@ from django.db import migrations - # tpm action point, action point statuses_mapping = { 'open': 'open', diff --git a/src/etools/applications/tpm/serializers/attachments.py b/src/etools/applications/tpm/serializers/attachments.py index e923291f41..ecded34f22 100644 --- a/src/etools/applications/tpm/serializers/attachments.py +++ b/src/etools/applications/tpm/serializers/attachments.py @@ -4,6 +4,7 @@ from unicef_attachments.fields import FileTypeModelChoiceField from unicef_attachments.models import AttachmentLink, FileType from unicef_attachments.serializers import AttachmentLinkSerializer, BaseAttachmentSerializer + from etools.applications.attachments.utils import get_file_type diff --git a/src/etools/applications/tpm/tests/base.py b/src/etools/applications/tpm/tests/base.py index feaf9c66a2..2615ee5944 100644 --- a/src/etools/applications/tpm/tests/base.py +++ b/src/etools/applications/tpm/tests/base.py @@ -1,7 +1,7 @@ from django.core.management import call_command from etools.applications.tpm.tests.factories import TPMPartnerFactory, TPMUserFactory -from etools.applications.users.tests.factories import UserFactory, PMEUserFactory +from etools.applications.users.tests.factories import PMEUserFactory, UserFactory from etools.libraries.djangolib.models import GroupWrapper diff --git a/src/etools/applications/tpm/tests/test_transitions.py b/src/etools/applications/tpm/tests/test_transitions.py index ccec41ea87..fe2d54f6dc 100644 --- a/src/etools/applications/tpm/tests/test_transitions.py +++ b/src/etools/applications/tpm/tests/test_transitions.py @@ -6,10 +6,10 @@ from rest_framework import status from etools.applications.core.tests.cases import BaseTenantTestCase +from etools.applications.permissions2.tests.mixins import TransitionPermissionsTestCaseMixin from etools.applications.tpm.models import TPMVisit from etools.applications.tpm.tests.base import TPMTestCaseMixin -from etools.applications.tpm.tests.factories import TPMVisitFactory, TPMUserFactory -from etools.applications.permissions2.tests.mixins import TransitionPermissionsTestCaseMixin +from etools.applications.tpm.tests.factories import TPMUserFactory, TPMVisitFactory from etools.applications.users.tests.factories import PMEUserFactory, UserFactory diff --git a/src/etools/applications/tpm/views.py b/src/etools/applications/tpm/views.py index 2a737e762a..30be67df70 100644 --- a/src/etools/applications/tpm/views.py +++ b/src/etools/applications/tpm/views.py @@ -61,8 +61,8 @@ TPMActivityAttachmentLinkSerializer, TPMAttachmentLinkSerializer, TPMPartnerAttachmentsSerializer, - TPMVisitAttachmentsSerializer, TPMVisitAttachmentLinkSerializer, + TPMVisitAttachmentsSerializer, TPMVisitReportAttachmentsSerializer, ) from etools.applications.tpm.serializers.partner import ( From 63477d8c33d2ddb7d9c7686ab95ed60b144e4643 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Fri, 12 Apr 2019 13:35:55 -0400 Subject: [PATCH 47/79] 11091 --- .../categories/migrations/0001_initial.py | 3 +- .../update_action_points_permissions.py | 9 ++++-- .../migrations/0002_auto_20180518_0835.py | 2 +- .../migrations/0003_auto_20180518_1610.py | 3 +- .../migrations/0004_auto_20180521_1052.py | 2 +- .../migrations/0005_auto_20180713_0805.py | 2 +- .../migrations/0006_auto_20180718_1439.py | 2 +- .../migrations/0007_auto_20180731_0920.py | 2 +- .../applications/action_points/models.py | 4 +-- .../action_points/tests/factories.py | 5 ++-- src/etools/applications/audit/forms.py | 1 + .../commands/update_audit_permissions.py | 23 +++++++++++---- .../migrations/0009_auto_20180521_1052.py | 1 - .../migrations/0015_auto_20190312_2010.py | 2 +- .../migrations/0016_auto_20190328_1528.py | 1 + .../audit/purchase_order/admin.py | 8 +++-- .../migrations/0002_fix_null_values.py | 1 + .../audit/purchase_order/tests/test_tasks.py | 2 +- .../applications/audit/serializers/export.py | 5 +--- src/etools/applications/audit/tests/base.py | 6 ++-- .../applications/audit/tests/factories.py | 29 +++++++++++++++---- .../applications/audit/tests/test_email.py | 2 +- .../applications/audit/tests/test_models.py | 23 ++++++++++----- .../applications/audit/tests/test_views.py | 3 +- src/etools/applications/tpm/filters.py | 1 + 25 files changed, 96 insertions(+), 46 deletions(-) diff --git a/src/etools/applications/action_points/categories/migrations/0001_initial.py b/src/etools/applications/action_points/categories/migrations/0001_initial.py index b8578ae97d..86038b7287 100644 --- a/src/etools/applications/action_points/categories/migrations/0001_initial.py +++ b/src/etools/applications/action_points/categories/migrations/0001_initial.py @@ -2,9 +2,10 @@ from __future__ import unicode_literals import django.utils.timezone -import model_utils.fields from django.db import migrations, models +import model_utils.fields + class Migration(migrations.Migration): diff --git a/src/etools/applications/action_points/management/commands/update_action_points_permissions.py b/src/etools/applications/action_points/management/commands/update_action_points_permissions.py index b2b3f55f61..bf579ad193 100644 --- a/src/etools/applications/action_points/management/commands/update_action_points_permissions.py +++ b/src/etools/applications/action_points/management/commands/update_action_points_permissions.py @@ -1,8 +1,13 @@ from django.core.management import BaseCommand from etools.applications.action_points.conditions import ( - ActionPointAssignedByCondition, ActionPointAssigneeCondition, ActionPointAuthorCondition, - ActionPointModuleCondition, RelatedActionPointCondition, UnRelatedActionPointCondition) + ActionPointAssignedByCondition, + ActionPointAssigneeCondition, + ActionPointAuthorCondition, + ActionPointModuleCondition, + RelatedActionPointCondition, + UnRelatedActionPointCondition, +) from etools.applications.action_points.models import ActionPoint, PME, UNICEFUser from etools.applications.permissions2.conditions import GroupCondition, NewObjectCondition, ObjectStatusCondition from etools.applications.permissions2.models import Permission diff --git a/src/etools/applications/action_points/migrations/0002_auto_20180518_0835.py b/src/etools/applications/action_points/migrations/0002_auto_20180518_0835.py index 1a5ddf8e38..a1efa9389b 100644 --- a/src/etools/applications/action_points/migrations/0002_auto_20180518_0835.py +++ b/src/etools/applications/action_points/migrations/0002_auto_20180518_0835.py @@ -1,6 +1,6 @@ # Generated by Django 1.10.8 on 2018-05-18 08:35 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py b/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py index 796210bcbc..4786cf1b25 100644 --- a/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py +++ b/src/etools/applications/action_points/migrations/0003_auto_20180518_1610.py @@ -1,8 +1,9 @@ # Generated by Django 1.10.8 on 2018-05-18 16:10 from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models + import model_utils.fields diff --git a/src/etools/applications/action_points/migrations/0004_auto_20180521_1052.py b/src/etools/applications/action_points/migrations/0004_auto_20180521_1052.py index 3d3678fbcb..231b235ef7 100644 --- a/src/etools/applications/action_points/migrations/0004_auto_20180521_1052.py +++ b/src/etools/applications/action_points/migrations/0004_auto_20180521_1052.py @@ -1,8 +1,8 @@ # Generated by Django 1.10.8 on 2018-05-21 10:52 from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/etools/applications/action_points/migrations/0005_auto_20180713_0805.py b/src/etools/applications/action_points/migrations/0005_auto_20180713_0805.py index 3b56209ea8..6712dd1011 100644 --- a/src/etools/applications/action_points/migrations/0005_auto_20180713_0805.py +++ b/src/etools/applications/action_points/migrations/0005_auto_20180713_0805.py @@ -1,8 +1,8 @@ # Generated by Django 1.10.8 on 2018-07-13 08:05 from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/etools/applications/action_points/migrations/0006_auto_20180718_1439.py b/src/etools/applications/action_points/migrations/0006_auto_20180718_1439.py index fb55a58cb7..ae87350ab3 100644 --- a/src/etools/applications/action_points/migrations/0006_auto_20180718_1439.py +++ b/src/etools/applications/action_points/migrations/0006_auto_20180718_1439.py @@ -1,8 +1,8 @@ # Generated by Django 1.10.8 on 2018-07-18 14:39 from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/etools/applications/action_points/migrations/0007_auto_20180731_0920.py b/src/etools/applications/action_points/migrations/0007_auto_20180731_0920.py index d238873856..c4d95823fb 100644 --- a/src/etools/applications/action_points/migrations/0007_auto_20180731_0920.py +++ b/src/etools/applications/action_points/migrations/0007_auto_20180731_0920.py @@ -1,8 +1,8 @@ # Generated by Django 1.10.8 on 2018-07-31 09:20 from __future__ import unicode_literals -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models def copy_categories(apps, schema_editor): diff --git a/src/etools/applications/action_points/models.py b/src/etools/applications/action_points/models.py index d090b0f40a..28532c599e 100644 --- a/src/etools/applications/action_points/models.py +++ b/src/etools/applications/action_points/models.py @@ -11,13 +11,13 @@ from unicef_notification.models import Notification from unicef_snapshot.models import Activity -from etools.applications.core.urlresolvers import build_frontend_url from etools.applications.action_points.categories.models import Category from etools.applications.action_points.transitions.conditions import ActionPointCompleteActionsTakenCheck from etools.applications.action_points.transitions.serializers.serializers import ActionPointCompleteSerializer +from etools.applications.core.urlresolvers import build_frontend_url +from etools.libraries.djangolib.models import GroupWrapper from etools.libraries.djangolib.utils import get_environment from etools.libraries.fsm.views import has_action_permission -from etools.libraries.djangolib.models import GroupWrapper class ActionPoint(TimeStampedModel): diff --git a/src/etools/applications/action_points/tests/factories.py b/src/etools/applications/action_points/tests/factories.py index b892848d93..575c100f20 100644 --- a/src/etools/applications/action_points/tests/factories.py +++ b/src/etools/applications/action_points/tests/factories.py @@ -4,11 +4,10 @@ import factory.fuzzy from django_comments.models import Comment - -from etools.applications.action_points.models import ActionPoint -from etools.applications.action_points.categories.models import Category from unicef_locations.tests.factories import LocationFactory +from etools.applications.action_points.categories.models import Category +from etools.applications.action_points.models import ActionPoint from etools.applications.partners.tests.factories import InterventionFactory, ResultFactory from etools.applications.reports.tests.factories import SectionFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/audit/forms.py b/src/etools/applications/audit/forms.py index 1309443684..5a7b8288a6 100644 --- a/src/etools/applications/audit/forms.py +++ b/src/etools/applications/audit/forms.py @@ -1,4 +1,5 @@ from django import forms + from etools.applications.audit.models import EngagementActionPoint diff --git a/src/etools/applications/audit/management/commands/update_audit_permissions.py b/src/etools/applications/audit/management/commands/update_audit_permissions.py index ae21cd00e1..9119003121 100644 --- a/src/etools/applications/audit/management/commands/update_audit_permissions.py +++ b/src/etools/applications/audit/management/commands/update_audit_permissions.py @@ -2,13 +2,24 @@ from django.core.management import BaseCommand from django.db.models import Q -from etools.applications.action_points.conditions import ActionPointAuthorCondition, ActionPointAssignedByCondition, \ - ActionPointAssigneeCondition +from etools.applications.action_points.conditions import ( + ActionPointAssignedByCondition, + ActionPointAssigneeCondition, + ActionPointAuthorCondition, +) from etools.applications.action_points.models import ActionPoint -from etools.applications.audit.conditions import (AuditModuleCondition, AuditStaffMemberCondition, - EngagementStaffMemberCondition,) -from etools.applications.audit.models import Auditor, Engagement, UNICEFAuditFocalPoint, UNICEFUser, \ - EngagementActionPoint +from etools.applications.audit.conditions import ( + AuditModuleCondition, + AuditStaffMemberCondition, + EngagementStaffMemberCondition, +) +from etools.applications.audit.models import ( + Auditor, + Engagement, + EngagementActionPoint, + UNICEFAuditFocalPoint, + UNICEFUser, +) from etools.applications.permissions2.conditions import GroupCondition, NewObjectCondition, ObjectStatusCondition from etools.applications.permissions2.models import Permission from etools.applications.permissions2.utils import get_model_target diff --git a/src/etools/applications/audit/migrations/0009_auto_20180521_1052.py b/src/etools/applications/audit/migrations/0009_auto_20180521_1052.py index 69808970b5..e7f6811808 100644 --- a/src/etools/applications/audit/migrations/0009_auto_20180521_1052.py +++ b/src/etools/applications/audit/migrations/0009_auto_20180521_1052.py @@ -3,7 +3,6 @@ from django.db import migrations - # engagement action point, action point statuses_mapping = { 'open': 'open', diff --git a/src/etools/applications/audit/migrations/0015_auto_20190312_2010.py b/src/etools/applications/audit/migrations/0015_auto_20190312_2010.py index 5b77415e7a..70322ce21b 100644 --- a/src/etools/applications/audit/migrations/0015_auto_20190312_2010.py +++ b/src/etools/applications/audit/migrations/0015_auto_20190312_2010.py @@ -1,7 +1,7 @@ # Generated by Django 2.1.7 on 2019-03-12 20:10 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py b/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py index 2acadd4702..e191fc29d7 100644 --- a/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py +++ b/src/etools/applications/audit/migrations/0016_auto_20190328_1528.py @@ -1,6 +1,7 @@ # Generated by Django 2.1.7 on 2019-03-28 15:28 from django.db import migrations + import django_fsm diff --git a/src/etools/applications/audit/purchase_order/admin.py b/src/etools/applications/audit/purchase_order/admin.py index 593bb96b09..79469be1a4 100644 --- a/src/etools/applications/audit/purchase_order/admin.py +++ b/src/etools/applications/audit/purchase_order/admin.py @@ -1,7 +1,11 @@ from django.contrib import admin -from etools.applications.audit.purchase_order.models import (AuditorFirm, AuditorStaffMember, - PurchaseOrder, PurchaseOrderItem,) +from etools.applications.audit.purchase_order.models import ( + AuditorFirm, + AuditorStaffMember, + PurchaseOrder, + PurchaseOrderItem, +) class AuditorStaffMemberInlineAdmin(admin.StackedInline): diff --git a/src/etools/applications/audit/purchase_order/migrations/0002_fix_null_values.py b/src/etools/applications/audit/purchase_order/migrations/0002_fix_null_values.py index 71bb8422eb..41fc75608e 100644 --- a/src/etools/applications/audit/purchase_order/migrations/0002_fix_null_values.py +++ b/src/etools/applications/audit/purchase_order/migrations/0002_fix_null_values.py @@ -1,6 +1,7 @@ from django.db import migrations + class Migration(migrations.Migration): dependencies = [ diff --git a/src/etools/applications/audit/purchase_order/tests/test_tasks.py b/src/etools/applications/audit/purchase_order/tests/test_tasks.py index fa873e5135..5596f6cdce 100644 --- a/src/etools/applications/audit/purchase_order/tests/test_tasks.py +++ b/src/etools/applications/audit/purchase_order/tests/test_tasks.py @@ -1,7 +1,7 @@ from unittest.mock import patch -from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.audit.purchase_order.tasks import update_purchase_orders +from etools.applications.core.tests.cases import BaseTenantTestCase class TestUpdatePurchaseOrders(BaseTenantTestCase): diff --git a/src/etools/applications/audit/serializers/export.py b/src/etools/applications/audit/serializers/export.py index 81003d9401..0de02aacf9 100644 --- a/src/etools/applications/audit/serializers/export.py +++ b/src/etools/applications/audit/serializers/export.py @@ -20,10 +20,7 @@ ) from etools.applications.audit.purchase_order.models import AuditorFirm, AuditorStaffMember, PurchaseOrder from etools.applications.audit.serializers.auditor import PurchaseOrderItemSerializer -from etools.applications.audit.serializers.engagement import ( - DetailedFindingInfoSerializer, - KeyInternalControlSerializer, -) +from etools.applications.audit.serializers.engagement import DetailedFindingInfoSerializer, KeyInternalControlSerializer from etools.applications.audit.serializers.risks import ( AggregatedRiskRootSerializer, KeyInternalWeaknessSerializer, diff --git a/src/etools/applications/audit/tests/base.py b/src/etools/applications/audit/tests/base.py index 9904840514..a32c7ccbb6 100644 --- a/src/etools/applications/audit/tests/base.py +++ b/src/etools/applications/audit/tests/base.py @@ -14,11 +14,13 @@ from etools.applications.audit.models import RiskBluePrint from etools.applications.audit.tests.factories import ( + AuditFocalPointUserFactory, AuditorStaffMemberFactory, + AuditorUserFactory, AuditPartnerFactory, RiskFactory, - AuditorUserFactory, AuditFocalPointUserFactory) -from etools.applications.users.tests.factories import UserFactory, SimpleUserFactory +) +from etools.applications.users.tests.factories import SimpleUserFactory, UserFactory from etools.libraries.djangolib.models import GroupWrapper diff --git a/src/etools/applications/audit/tests/factories.py b/src/etools/applications/audit/tests/factories.py index da1b4016aa..5286ae80e9 100644 --- a/src/etools/applications/audit/tests/factories.py +++ b/src/etools/applications/audit/tests/factories.py @@ -6,12 +6,29 @@ import factory from factory import fuzzy -from etools.applications.audit.models import (Audit, Auditor, DetailedFindingInfo, Engagement, - Finding, KeyInternalControl, MicroAssessment, - Risk, RiskBluePrint, RiskCategory, SpecialAudit, SpecificProcedure, - SpotCheck, UNICEFAuditFocalPoint, UNICEFUser,) -from etools.applications.audit.purchase_order.models import (AuditorFirm, AuditorStaffMember, - PurchaseOrder, PurchaseOrderItem,) +from etools.applications.audit.models import ( + Audit, + Auditor, + DetailedFindingInfo, + Engagement, + Finding, + KeyInternalControl, + MicroAssessment, + Risk, + RiskBluePrint, + RiskCategory, + SpecialAudit, + SpecificProcedure, + SpotCheck, + UNICEFAuditFocalPoint, + UNICEFUser, +) +from etools.applications.audit.purchase_order.models import ( + AuditorFirm, + AuditorStaffMember, + PurchaseOrder, + PurchaseOrderItem, +) from etools.applications.firms.tests.factories import BaseFirmFactory, BaseStaffMemberFactory from etools.applications.partners.models import PartnerOrganization from etools.applications.partners.tests.factories import AgreementFactory, InterventionFactory, PartnerFactory diff --git a/src/etools/applications/audit/tests/test_email.py b/src/etools/applications/audit/tests/test_email.py index de1bd94e8e..7aa15ac95b 100644 --- a/src/etools/applications/audit/tests/test_email.py +++ b/src/etools/applications/audit/tests/test_email.py @@ -4,9 +4,9 @@ from unicef_notification.models import EmailTemplate -from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.audit.tests.factories import AuditFocalPointUserFactory from etools.applications.audit.tests.test_transitions import MATransitionsTestCaseMixin +from etools.applications.core.tests.cases import BaseTenantTestCase class TestEmail(BaseTenantTestCase): diff --git a/src/etools/applications/audit/tests/test_models.py b/src/etools/applications/audit/tests/test_models.py index 281064c8dc..bdf664af5e 100644 --- a/src/etools/applications/audit/tests/test_models.py +++ b/src/etools/applications/audit/tests/test_models.py @@ -9,15 +9,24 @@ from django.db import connection from django.test import SimpleTestCase - from etools.applications.audit.models import Auditor, Engagement, RiskCategory from etools.applications.audit.purchase_order.models import AuditorStaffMember, PurchaseOrder, PurchaseOrderItem -from etools.applications.audit.tests.factories import (AuditFactory, AuditorStaffMemberFactory, AuditPartnerFactory, - DetailedFindingInfoFactory, - EngagementFactory, FindingFactory, MicroAssessmentFactory, - PurchaseOrderFactory, PurchaseOrderItemFactory, - RiskBluePrintFactory, RiskCategoryFactory, RiskFactory, - SpecialAuditFactory, SpotCheckFactory,) +from etools.applications.audit.tests.factories import ( + AuditFactory, + AuditorStaffMemberFactory, + AuditPartnerFactory, + DetailedFindingInfoFactory, + EngagementFactory, + FindingFactory, + MicroAssessmentFactory, + PurchaseOrderFactory, + PurchaseOrderItemFactory, + RiskBluePrintFactory, + RiskCategoryFactory, + RiskFactory, + SpecialAuditFactory, + SpotCheckFactory, +) from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.firms.tests.factories import BaseUserFactory from etools.applications.users.models import Country diff --git a/src/etools/applications/audit/tests/test_views.py b/src/etools/applications/audit/tests/test_views.py index 8f41608057..d53b0329bf 100644 --- a/src/etools/applications/audit/tests/test_views.py +++ b/src/etools/applications/audit/tests/test_views.py @@ -15,6 +15,7 @@ from etools.applications.audit.tests.base import AuditTestCaseMixin, EngagementTransitionsTestCaseMixin from etools.applications.audit.tests.factories import ( AuditFactory, + AuditorUserFactory, AuditPartnerFactory, EngagementFactory, MicroAssessmentFactory, @@ -25,7 +26,7 @@ SpotCheckFactory, StaffSpotCheckFactory, UserFactory, - AuditorUserFactory) +) from etools.applications.audit.tests.test_transitions import MATransitionsTestCaseMixin from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import PartnerType diff --git a/src/etools/applications/tpm/filters.py b/src/etools/applications/tpm/filters.py index 713b36fff9..2a09dade09 100644 --- a/src/etools/applications/tpm/filters.py +++ b/src/etools/applications/tpm/filters.py @@ -26,6 +26,7 @@ class Meta: 'tpm_activities__section': ['exact', 'in'], 'tpm_activities__partner': ['exact', 'in'], 'tpm_activities__locations': ['exact'], + 'tpm_activities__offices': ['exact'], 'tpm_activities__cp_output': ['exact', 'in'], 'tpm_activities__intervention': ['exact'], 'tpm_activities__date': ['exact', 'lte', 'gte', 'gt', 'lt'], From 437ae9b82a34eca6a051206b854addd2d3418964 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Thu, 18 Apr 2019 08:18:21 -0400 Subject: [PATCH 48/79] Add xlsx export got action points --- .../applications/action_points/serializers.py | 83 +++++++++++++++++++ .../action_points/tests/test_views.py | 41 +++++++++ .../applications/action_points/views.py | 46 +++++++--- 3 files changed, 159 insertions(+), 11 deletions(-) diff --git a/src/etools/applications/action_points/serializers.py b/src/etools/applications/action_points/serializers.py index 41ba3a12f3..a345242ccf 100644 --- a/src/etools/applications/action_points/serializers.py +++ b/src/etools/applications/action_points/serializers.py @@ -4,6 +4,7 @@ from django_comments.models import Comment from rest_framework import serializers from unicef_locations.serializers import LocationLightSerializer +from unicef_rest_export.serializers import ExportSerializer from unicef_restlib.fields import SeparatedReadWriteField from unicef_restlib.serializers import UserContextSerializerMixin, WritableNestedSerializerMixin from unicef_snapshot.models import Activity @@ -180,3 +181,85 @@ def validate_category(self, value): if value and value.module != self.instance.related_module: raise serializers.ValidationError(_('Category doesn\'t belong to selected module.')) return value + + +class ActionPointListExportSerializer(ExportSerializer): + engagement = serializers.SerializerMethodField() + tpm_activity = serializers.SerializerMethodField() + travel_activity = serializers.SerializerMethodField() + + class Meta(ActionPointListSerializer.Meta): + pass + + def get_engagement(self, obj): + return obj.engagement + + def get_tpm_activity(self, obj): + return obj.tpm_activity + + def get_travel_activity(self, obj): + return obj.travel_activity + + def get_headers(self, data): + headers = [] + for field in data[0].keys(): + headers.append(str(self.get_header_label(field))) + return headers + + def transform_cp_output(self, data): + return ",".join(["231" for x in data]) + + def transform_location(self, data): + return data.get("name", "") + + def transform_office(self, data): + return data.get("name", "") + + def transform_section(self, data): + return data.get("name", "") + + def transform_author(self, data): + return "{} {}".format( + data.get("first_name", ""), + data.get("last_name", "") + ) + + def transform_assigned_by(self, data): + return "{} {}".format( + data.get("first_name", ""), + data.get("last_name", "") + ) + + def transform_assigned_to(self, data): + return "{} {}".format( + data.get("first_name", ""), + data.get("last_name", "") + ) + + def transform_partner(self, data): + return data.get("name", "") + + def transform_intervention(self, data): + return data.get("number", "") + + def transform_category(self, data): + return data.get("module", "") + + def transform_dataset(self, dataset): + transform_fields = [ + 'category', + 'assigned_to', + 'author', + 'assigned_by', + 'section', + 'office', + 'cp_output', + 'partner', + 'intervention', + 'location', + ] + from tablib.compat import unicode + for field in transform_fields: + func = getattr(self, "transform_{}".format(field)) + dataset.add_formatter(str(self.get_header_label(field)), func) + return dataset diff --git a/src/etools/applications/action_points/tests/test_views.py b/src/etools/applications/action_points/tests/test_views.py index b12cdeeec7..56af03362a 100644 --- a/src/etools/applications/action_points/tests/test_views.py +++ b/src/etools/applications/action_points/tests/test_views.py @@ -277,11 +277,52 @@ def test_list_csv(self): self._test_export(self.pme_user, 'action-points:action-points-list-csv-export') + def test_list_xlsx(self): + ActionPointFactory(status='open', comments__count=1) + ActionPointFactory( + status='open', + comments__count=1, + engagement=MicroAssessmentFactory(), + ) + ActionPointFactory( + status='open', + comments__count=1, + tpm_activity=TPMVisitFactory( + tpm_activities__count=1 + ).tpm_activities.first(), + ) + traveler = UserFactory() + ActionPointFactory( + status='open', + travel_activity=TravelActivityFactory( + primary_traveler=traveler, + travels=[TravelFactory(traveler=traveler)] + ) + ) + + self._test_export( + self.pme_user, + 'action-points:action-points-list-xlsx-export', + ) + def test_single_csv(self): action_point = ActionPointFactory(status='open', comments__count=1, engagement=MicroAssessmentFactory()) self._test_export(self.pme_user, 'action-points:action-points-single-csv-export', args=[action_point.id]) + def test_single_xlsx(self): + action_point = ActionPointFactory( + status='open', + comments__count=1, + engagement=MicroAssessmentFactory(), + ) + + self._test_export( + self.pme_user, + 'action-points:action-points-single-xlsx-export', + args=[action_point.id], + ) + class TestActionPointsViewMetadata(ActionPointsTestCaseMixin): @classmethod diff --git a/src/etools/applications/action_points/views.py b/src/etools/applications/action_points/views.py index b053a34b77..b1a0f06d71 100644 --- a/src/etools/applications/action_points/views.py +++ b/src/etools/applications/action_points/views.py @@ -6,6 +6,8 @@ from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from unicef_rest_export.renderers import ExportExcelRenderer +from unicef_rest_export.views import ExportMixin from unicef_restlib.pagination import DynamicPageNumberPagination from unicef_restlib.views import MultiSerializerViewSetMixin, SafeTenantViewSetMixin from unicef_snapshot.views import FSMSnapshotViewMixin @@ -26,6 +28,7 @@ from etools.applications.action_points.models import ActionPoint from etools.applications.action_points.serializers import ( ActionPointCreateSerializer, + ActionPointListExportSerializer, ActionPointListSerializer, ActionPointSerializer, ) @@ -42,17 +45,18 @@ class CategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): class ActionPointViewSet( - SafeTenantViewSetMixin, - MultiSerializerViewSetMixin, - PermittedSerializerMixin, - mixins.ListModelMixin, - mixins.CreateModelMixin, - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - FSMSnapshotViewMixin, - PermittedFSMActionMixin, - viewsets.GenericViewSet + SafeTenantViewSetMixin, + MultiSerializerViewSetMixin, + PermittedSerializerMixin, + ExportMixin, + mixins.ListModelMixin, + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + FSMSnapshotViewMixin, + PermittedFSMActionMixin, + viewsets.GenericViewSet ): metadata_class = PermissionBasedMetadata pagination_class = DynamicPageNumberPagination @@ -63,6 +67,7 @@ class ActionPointViewSet( 'create': ActionPointCreateSerializer, 'list': ActionPointListSerializer, } + export_serializer_class = ActionPointListExportSerializer filter_backends = (ReferenceNumberOrderingFilter, OrderingFilter, SearchFilter, RelatedModuleFilter, DjangoFilterBackend,) @@ -112,6 +117,15 @@ def list_csv_export(self, request, *args, **kwargs): 'Content-Disposition': 'attachment;filename=action_points_{}.csv'.format(timezone.now().date()) }) + @action(detail=False, methods=['get'], url_path='export/xlsx', renderer_classes=(ExportExcelRenderer,)) + def list_xlsx_export(self, request, *args, **kwargs): + self.serializer_class = ActionPointListSerializer + action_points = self.filter_queryset(self.get_queryset().prefetch_related('comments')) + serializer = self.get_serializer(action_points, many=True) + return Response(serializer.data, headers={ + 'Content-Disposition': 'attachment;filename=action_points_{}.xlsx'.format(timezone.now().date()) + }) + @action(detail=True, methods=['get'], url_path='export/csv', renderer_classes=(ActionPointCSVRenderer,)) def single_csv_export(self, request, *args, **kwargs): serializer = ActionPointExportSerializer(self.get_object()) @@ -120,3 +134,13 @@ def single_csv_export(self, request, *args, **kwargs): self.get_object().reference_number, timezone.now().date() ) }) + + @action(detail=True, methods=['get'], url_path='export/xlsx', renderer_classes=(ExportExcelRenderer,)) + def single_xlsx_export(self, request, *args, **kwargs): + self.serializer_class = ActionPointListSerializer + serializer = self.get_serializer([self.get_object()], many=True) + return Response(serializer.data, headers={ + 'Content-Disposition': 'attachment;filename={}_{}.xlsx'.format( + self.get_object().reference_number, timezone.now().date() + ) + }) From 9653c2ec53285f97464a64a4109b958dbdbe492e Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Thu, 18 Apr 2019 08:20:05 -0400 Subject: [PATCH 49/79] flake8 cleanup --- src/etools/applications/action_points/serializers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/etools/applications/action_points/serializers.py b/src/etools/applications/action_points/serializers.py index a345242ccf..1341fd9d3c 100644 --- a/src/etools/applications/action_points/serializers.py +++ b/src/etools/applications/action_points/serializers.py @@ -258,7 +258,6 @@ def transform_dataset(self, dataset): 'intervention', 'location', ] - from tablib.compat import unicode for field in transform_fields: func = getattr(self, "transform_{}".format(field)) dataset.add_formatter(str(self.get_header_label(field)), func) From 914fd53d61dad37b4abbb7ed9a72bf0dd9759ccc Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Thu, 18 Apr 2019 08:57:07 -0400 Subject: [PATCH 50/79] Make action points xslx export more robust --- .../applications/action_points/serializers.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/etools/applications/action_points/serializers.py b/src/etools/applications/action_points/serializers.py index 1341fd9d3c..cc3f6affad 100644 --- a/src/etools/applications/action_points/serializers.py +++ b/src/etools/applications/action_points/serializers.py @@ -207,15 +207,23 @@ def get_headers(self, data): return headers def transform_cp_output(self, data): - return ",".join(["231" for x in data]) + if data is None: + return data + return data.get("result_name", "") def transform_location(self, data): + if data is None: + return data return data.get("name", "") def transform_office(self, data): + if data is None: + return data return data.get("name", "") def transform_section(self, data): + if data is None: + return data return data.get("name", "") def transform_author(self, data): @@ -237,12 +245,18 @@ def transform_assigned_to(self, data): ) def transform_partner(self, data): + if data is None: + return data return data.get("name", "") def transform_intervention(self, data): + if data is None: + return data return data.get("number", "") def transform_category(self, data): + if data is None: + return data return data.get("module", "") def transform_dataset(self, dataset): From 2ee5e792f88881e7ea4a6b0d81b914b8628e2b08 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Fri, 29 Mar 2019 08:01:45 -0400 Subject: [PATCH 51/79] Update attachment file type static results --- src/etools/applications/attachments/models.py | 7 +++++++ src/etools/applications/partners/views/v2.py | 7 ++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/etools/applications/attachments/models.py b/src/etools/applications/attachments/models.py index 69c0c0efd8..5d429f5a25 100644 --- a/src/etools/applications/attachments/models.py +++ b/src/etools/applications/attachments/models.py @@ -284,3 +284,10 @@ class AttachmentFlat(models.Model): def __str__(self): return str(self.attachment) + + @classmethod + def get_file_types(cls): + return cls.objects.exclude(file_type="").values_list( + "file_type", + flat=True + ).distinct("file_type").order_by("file_type") diff --git a/src/etools/applications/partners/views/v2.py b/src/etools/applications/partners/views/v2.py index 8f11801c77..5536c2eda4 100644 --- a/src/etools/applications/partners/views/v2.py +++ b/src/etools/applications/partners/views/v2.py @@ -11,10 +11,10 @@ from rest_framework.permissions import IsAdminUser, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from unicef_attachments.models import FileType as AttachmentFileType from unicef_djangolib.fields import CURRENCIES from unicef_locations.models import GatewayType +from etools.applications.attachments.models import AttachmentFlat from etools.applications.funds.models import FundsReservationItem from etools.applications.partners.filters import PartnerScopeFilter from etools.applications.partners.models import ( @@ -97,10 +97,7 @@ def get(self, request): # hardcoded to partners app attachments for now # once tpm and audit come online we can remove the filter # on attachment file types - attachment_types = AttachmentFileType.objects.values_list( - 'label', - flat=True - ) + attachment_types = AttachmentFlat.get_file_types() partner_file_types = FileType.objects.values_list("name", flat=True) local_currency = local_workspace.local_currency.id if local_workspace.local_currency else None From 6148ad30f95d59b758f864b568890e6ab9ea21a3 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Thu, 11 Apr 2019 04:09:51 -0400 Subject: [PATCH 52/79] Add attachment_types_active to dropdown static endpoint --- src/etools/applications/partners/views/v2.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/etools/applications/partners/views/v2.py b/src/etools/applications/partners/views/v2.py index 5536c2eda4..abd8c8a9eb 100644 --- a/src/etools/applications/partners/views/v2.py +++ b/src/etools/applications/partners/views/v2.py @@ -94,10 +94,11 @@ def get(self, request): intervention_amendment_types = choices_to_json_ready(InterventionAmendment.AMENDMENT_TYPES) location_types = GatewayType.objects.values('id', 'name', 'admin_level').order_by('id') currencies = choices_to_json_ready(CURRENCIES) - # hardcoded to partners app attachments for now - # once tpm and audit come online we can remove the filter - # on attachment file types - attachment_types = AttachmentFlat.get_file_types() + attachment_types = AttachmentFileType.objects.values_list( + "label", + flat=True, + ) + attachment_types_active = AttachmentFlat.get_file_types() partner_file_types = FileType.objects.values_list("name", flat=True) local_currency = local_workspace.local_currency.id if local_workspace.local_currency else None From 36b7cb0201a9d9618298ca209133f6d2f0833d8d Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Thu, 11 Apr 2019 04:17:51 -0400 Subject: [PATCH 53/79] Fix missing import and setting of attachment_types_active data --- src/etools/applications/partners/views/v2.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/etools/applications/partners/views/v2.py b/src/etools/applications/partners/views/v2.py index abd8c8a9eb..84d5378938 100644 --- a/src/etools/applications/partners/views/v2.py +++ b/src/etools/applications/partners/views/v2.py @@ -11,6 +11,7 @@ from rest_framework.permissions import IsAdminUser, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView +from unicef_attachments.models import FileType as AttachmentFileType from unicef_djangolib.fields import CURRENCIES from unicef_locations.models import GatewayType @@ -120,6 +121,7 @@ def get(self, request): 'local_currency': local_currency, 'location_types': location_types, 'attachment_types': attachment_types, + 'attachment_types_active': attachment_types_active, 'partner_file_types': partner_file_types, }, status=status.HTTP_200_OK From a2779b8a0d5c405d240cfc22426c615674606f0a Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Thu, 11 Apr 2019 05:10:35 -0400 Subject: [PATCH 54/79] Fix tests for attachment_types_active --- src/etools/applications/partners/tests/test_api_pmp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/etools/applications/partners/tests/test_api_pmp.py b/src/etools/applications/partners/tests/test_api_pmp.py index f3545b99a8..95782af5a0 100644 --- a/src/etools/applications/partners/tests/test_api_pmp.py +++ b/src/etools/applications/partners/tests/test_api_pmp.py @@ -64,6 +64,7 @@ def setUp(self): 'local_currency', 'location_types', 'attachment_types', + 'attachment_types_active', 'partner_file_types', 'partner_risk_rating', )) From eb0017566e9d6ae1cde5966d3b5d6acaf3d1cdc1 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 18 Apr 2019 12:02:30 -0400 Subject: [PATCH 55/79] updated pipfile --- Pipfile.lock | 142 +++++++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 67 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 21410ba3e4..da61d2af2c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "beb7919c535f514b0bcac8c651a52fdca8cfcfb5d0262a974b956d1711b7fe24" + "sha256": "ddd8d7caf5411f5c981f09778a0a8309645ba49166bd747b93df2ffa73667b61" }, "pipfile-spec": 6, "requires": { @@ -176,11 +176,11 @@ }, "defusedxml": { "hashes": [ - "sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4", - "sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20" + "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", + "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5" ], "markers": "python_version >= '3.0'", - "version": "==0.5.0" + "version": "==0.6.0" }, "diff-match-patch": { "hashes": [ @@ -259,20 +259,20 @@ "index": "pypi", "version": "==2.5" }, - "django-debug-toolbar": { + "django-easy-pdf": { "hashes": [ - "sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736", - "sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0" + "sha256:f7cb58e896791d28718219c54d2c8930e442fa1327817037e1c480bead77cddb" ], "index": "pypi", - "version": "==1.11" + "version": "==0.1.1" }, - "django-easy-pdf": { + "django-extensions": { "hashes": [ - "sha256:f7cb58e896791d28718219c54d2c8930e442fa1327817037e1c480bead77cddb" + "sha256:109004f80b6f45ad1f56addaa59debca91d94aa0dc1cb19678b9364b4fe9b6f4", + "sha256:307766e5e6c1caffe76c5d99239d8115d14ae3f7cab2cd991fcffd763dad904b" ], "index": "pypi", - "version": "==0.1.1" + "version": "==2.1.6" }, "django-filter": { "hashes": [ @@ -808,36 +808,36 @@ }, "reportlab": { "hashes": [ - "sha256:063a4b9b269883e1ad69f17319a13bce29eb64b4ea83be0ca72f3c7e16eb82c5", - "sha256:083d545873ee1d42f2489ad7a28de68ac1cd8b347f2909b58bf52e0b47c1db78", - "sha256:11f7a4f42078ed7a1555ee4ec4ce9f1ee0c693c81cbec141ed9472efeac39d72", - "sha256:2815d86bfcf113b357cae00886d94ceb84503d076d4840acdf20eb7bb18239e5", - "sha256:28d2df4e6c82eda1decc9fd5ac8a92f11e3b589466aa0dfb5eecf2a6b37cc8b1", - "sha256:348d8940ebcb3d387553a7d671621c5e191ddba54f52003d8f4762d599b8d1f1", - "sha256:35a9ef0f962fa6cf0220bcb1784e803920ca133d1ca085f34bdf61c36a537ea0", - "sha256:37c0678254aca7f9e18b8b3c60d6da19349b3149927026ce9578752b2bf831ac", - "sha256:52c0e367ee6273499f1aa29a830e2a3abceae44446398f935774cfbce0fe0b6b", - "sha256:534827c3dd5844340eb4ec61a754471a0fef3fd2e1f342ad9452b034529ce340", - "sha256:577281844053e312cb90b29ea440ec6543416b3361833773a7eaadc361a25376", - "sha256:58e4af53c64ec3b9c226d6c4e0bac5ec89a556fefc58eb058c9a5429385e4c84", - "sha256:61c89741b03b6e5f434b41d8659d1a7df38b635bf09269abae1b00ee5cc77e24", - "sha256:78f2ac8dc47c0cfbc3824aa3fc83ab8aa1e1f3a11803123f7a08170374c68b17", - "sha256:7c66fbd111fb83b760a88d1b1bef9afb77d4c940c79e1c1e119f202be75e2d99", - "sha256:8659c9fd61a042b47714dc3f637dfb3bff59396890386ae7a1c383ae3b76b206", - "sha256:92113dcb7d98aa838782510a4f5654c7f6596e3560a0a4cf8f3eff141126e95a", - "sha256:99d74fffc201a3bd4b603cc27901917c283e6deed1c8bf7c65d14ac1fb78f5e3", - "sha256:9b9bdb2a9f7e35e8ad98fb06e7609616b7cfcdd510f55dcaf0335092ecdcb2ac", - "sha256:9e6fc073ff383ef09ca67f0cc7028dfe96bd022d6117ff7d2586ea8ca7cd7a30", - "sha256:a06e5c6873b420fe644cc813c660a64fbf4237be62b01576f32a305226bccfef", - "sha256:a51c683366d4d46ae713d1395c5bc4d53f20943aa77e3590f7bbc3b374a3ff91", - "sha256:a9b8f13783a83c82b33c3d7d175ff5b06c8b61e59bc0cd63965bc12d5328fbb8", - "sha256:cdc4de4cd6041eda1624247949c689a17459394004572ff1fe14aa4ba7ad0b6a", - "sha256:cf046304bea0e8b4574f3d500e15b119149d469dd3b17fec1b8005bdb0d6b8e6", - "sha256:dc0cab2145fef216d3cf0577eca8780928fad7f021123eaa9ca2287f436754cc", - "sha256:fad3a0fe7e616b064ddf5ad9f248eeb25e17f65cde204869f8d9a8c45ef17027", - "sha256:fe276cd644e1e669613dc73fe6f7501c26e671d009d2329f774df578adc8000e" - ], - "version": "==3.5.18" + "sha256:1c228a3ac2c405f7fc16eac43ba92aec448bc25438902f30590ad021e8828097", + "sha256:2210fafd3bb06308a84876fe6d19172b645373edce2b6d7501378cb9c768f825", + "sha256:232fb2037b7c3df259685f1c5ecb7826f55742dc81f0713837b84a152307483e", + "sha256:2c4f25e63fa75f3064871cf435696a4e19b7bd4901d922b766ae58a447b5b6da", + "sha256:47951166d897b60e9e7ca349db82a2b689e6478ac6078e2c7c88ca8becbb0c7d", + "sha256:526ab1193ea8e97c4838135917890e66de5f777d04283008007229b139f3c094", + "sha256:5a9cc8470623ec5b76c7e59f56b7d1fcf0254896cd61842dbdbd278934cc50f4", + "sha256:5ddc1a4a74f225e35a7f60e2eae10de6878dddc9960dad2d9cadc49092f8850d", + "sha256:6b594f6d7d71bc5778e19adb1c699a598c69b9a7bcf97fa638d8762279f9d80a", + "sha256:6e8c89b46cfaf9ae40b7db87e9f29c9e5d32d18d25f9cd10d423a5241e8ec453", + "sha256:71f4f3e3975b91ddbfc1b36a537b46d07533ca7f31945e990a75db5f9bd7a0ba", + "sha256:763654dc346eeb66fa726a88d27f911339950d20a25303dfc098f3b59ba26614", + "sha256:7bae4b33363f44343e0fac5004c8e44576c3ed00885be4eee1f2260802c116c3", + "sha256:8a4b8a0fd0547f3b436b548284aa604ba183bfac26f41a7ffb23d0ff5db8c658", + "sha256:8b08d68e4cb498eabf85411beda5c32e591ef8d0a6d18c948c3f80ed5d2c6e31", + "sha256:9840f27948b54aefa3c6386e5ed0f124d641eb54fa2f2bc9aebcb270598487fc", + "sha256:9ae8f822370e47486ba1880f7580669058a41e64bdaa41019f4617317489f884", + "sha256:9db49197080646a113059eba1c0758161164de1bc57315e7422bbf8c86e03dcf", + "sha256:a08d23fa3f23f13a1cc6dca3b3c431d08ae48e52384e6bf47bbefb22fde58e61", + "sha256:ac111bc47733dbfa3e34d61282c91b69b1f66800b0c72b7b86dc2534faa09bef", + "sha256:bc3c69707c0bf9308193612d34ca87249d6fc91a35ce0873102321395d39024a", + "sha256:c375759a763c1c93d5b4f36620390440d9fa6dec6fcf88bce8234701d88b339c", + "sha256:c8a5988d73ec93a54f22660b64c5f3d2018163dd9ca4a5cdde8022a7e4fcb345", + "sha256:eba2bc7c28a3b2b0a3c24caff33e4d8708db008f480b03a6ea39c28661663746", + "sha256:ee187977d587b9b81929e08022f385eb11274efd75795d59d99eb23b3fa9b055", + "sha256:f3ef7616ffc27c150ffec61ac820739495f6a9ca5d8532047102756ebb27e8d1", + "sha256:f46f223fcae09c8bf2746b4eb2f351294faae04b262429cc480d34c69b133fd9", + "sha256:fd9f6429a68a246fb466696d97d1240752c889b5bfdc219fea15ae787cf366a6" + ], + "version": "==3.5.19" }, "requests": { "hashes": [ @@ -907,13 +907,6 @@ "index": "pypi", "version": "==1.7.0" }, - "sqlparse": { - "hashes": [ - "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", - "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" - ], - "version": "==0.3.0" - }, "static3": { "hashes": [ "sha256:674641c64bc75507af2eb20bef7e7e3593dca993dec6674be108fa15b42f47c8" @@ -1012,10 +1005,10 @@ }, "urllib3": { "hashes": [ - "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", - "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + "sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", + "sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3" ], - "version": "==1.24.1" + "version": "==1.24.2" }, "vine": { "hashes": [ @@ -1133,13 +1126,21 @@ ], "version": "==4.4.0" }, - "django-extensions": { + "django": { "hashes": [ - "sha256:109004f80b6f45ad1f56addaa59debca91d94aa0dc1cb19678b9364b4fe9b6f4", - "sha256:307766e5e6c1caffe76c5d99239d8115d14ae3f7cab2cd991fcffd763dad904b" + "sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade", + "sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963" ], "index": "pypi", - "version": "==2.1.6" + "version": "==2.1.7" + }, + "django-debug-toolbar": { + "hashes": [ + "sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736", + "sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0" + ], + "index": "pypi", + "version": "==1.11" }, "djangorestframework": { "hashes": [ @@ -1181,10 +1182,10 @@ }, "faker": { "hashes": [ - "sha256:00b7011757c4907546f17d0e47df098b542ea2b04c966ee0e80a493aae2c13c8", - "sha256:745ac8b9c9526e338696e07b7f2e206e5e317e5744e22fdd7c2894bf19af41f1" + "sha256:167cef2454482dc2fbd8b0ff6a5ba3dbac8d3a3ebdee6ba819d008100d9d9428", + "sha256:3f2f4570df28df2eb8f39b00520eb610081d6552975e926c6a2cbc64fd89c4c1" ], - "version": "==1.0.4" + "version": "==1.0.5" }, "fancycompleter": { "hashes": [ @@ -1482,10 +1483,10 @@ }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0d691ca8edf5995fbacfe69b191914256071a94cbad03c3688dca47385c9206c", - "sha256:e31c8271f5a8f04b620a500c0442a7d5cfc1a732fa5c10ec363f90fe72af0cb8" + "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", + "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" ], - "version": "==1.0.1" + "version": "==1.0.2" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -1508,6 +1509,13 @@ ], "version": "==1.1.3" }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, "text-unidecode": { "hashes": [ "sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d", @@ -1524,11 +1532,11 @@ }, "tox": { "hashes": [ - "sha256:69620e19de33a6b7ee8aeda5478791b3618ff58f0b869dbd0319fb71aa903deb", - "sha256:e5cdb1653aa27b3e46b5c390de6b6d51d31afcfdbd9d1222d82d76b82ad03d9b" + "sha256:1b166b93d2ce66bb7b253ba944d2be89e0c9d432d49eeb9da2988b4902a4684e", + "sha256:665cbdd99f5c196dd80d1d8db8c8cf5d48b1ae1f778bccd1bdf14d5aaf4ca0fc" ], "index": "pypi", - "version": "==3.8.6" + "version": "==3.9.0" }, "traitlets": { "hashes": [ @@ -1539,10 +1547,10 @@ }, "urllib3": { "hashes": [ - "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", - "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + "sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", + "sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3" ], - "version": "==1.24.1" + "version": "==1.24.2" }, "virtualenv": { "hashes": [ From 1f10d75818d780de6529ce562872a40f04a6b112 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 18 Apr 2019 12:58:37 -0400 Subject: [PATCH 56/79] debug toolbar in requirements --- Pipfile | 2 +- Pipfile.lock | 40 ++++++++++++++++------------------------ 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/Pipfile b/Pipfile index 92e306ef40..ce9d522f27 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,6 @@ url = "https://pypi.org/simple" verify_ssl = true [dev-packages] -django-debug-toolbar = "==1.11" flake8 = "*" coverage = "*" mock = "*" @@ -31,6 +30,7 @@ django-celery-email = "==2.0.1" django_celery_results = "==1.0.4" django-contrib-comments = "==1.9.1" django-cors-headers = "==2.5" +django-debug-toolbar = "==1.11" django-extensions = "==2.1.6" django-easy-pdf = "==0.1.1" django-filter = "==2.1" diff --git a/Pipfile.lock b/Pipfile.lock index da61d2af2c..16666c8608 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ddd8d7caf5411f5c981f09778a0a8309645ba49166bd747b93df2ffa73667b61" + "sha256": "b1872df511fe7116c492e4f6b61490861452a922bd0e6b11049c49dd0c4d1906" }, "pipfile-spec": 6, "requires": { @@ -259,6 +259,14 @@ "index": "pypi", "version": "==2.5" }, + "django-debug-toolbar": { + "hashes": [ + "sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736", + "sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0" + ], + "index": "pypi", + "version": "==1.11" + }, "django-easy-pdf": { "hashes": [ "sha256:f7cb58e896791d28718219c54d2c8930e442fa1327817037e1c480bead77cddb" @@ -907,6 +915,13 @@ "index": "pypi", "version": "==1.7.0" }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, "static3": { "hashes": [ "sha256:674641c64bc75507af2eb20bef7e7e3593dca993dec6674be108fa15b42f47c8" @@ -1126,22 +1141,6 @@ ], "version": "==4.4.0" }, - "django": { - "hashes": [ - "sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade", - "sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963" - ], - "index": "pypi", - "version": "==2.1.7" - }, - "django-debug-toolbar": { - "hashes": [ - "sha256:89d75b60c65db363fb24688d977e5fbf0e73386c67acf562d278402a10fc3736", - "sha256:c2b0134119a624f4ac9398b44f8e28a01c7686ac350a12a74793f3dd57a9eea0" - ], - "index": "pypi", - "version": "==1.11" - }, "djangorestframework": { "hashes": [ "sha256:8a435df9007c8b7d8e69a21ef06650e3c0cbe0d4b09e55dd1bd74c89a75a9fcd", @@ -1509,13 +1508,6 @@ ], "version": "==1.1.3" }, - "sqlparse": { - "hashes": [ - "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", - "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" - ], - "version": "==0.3.0" - }, "text-unidecode": { "hashes": [ "sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d", From a3cbfa55c4bdc7cd854172cbbe44f283535382fe Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 18 Apr 2019 14:42:16 -0400 Subject: [PATCH 57/79] fix intervention many 2 many issue --- .../migrations/0036_auto_20190418_1832.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/etools/applications/partners/migrations/0036_auto_20190418_1832.py diff --git a/src/etools/applications/partners/migrations/0036_auto_20190418_1832.py b/src/etools/applications/partners/migrations/0036_auto_20190418_1832.py new file mode 100644 index 0000000000..b9c7fac61f --- /dev/null +++ b/src/etools/applications/partners/migrations/0036_auto_20190418_1832.py @@ -0,0 +1,33 @@ +# Generated by Django 2.1.7 on 2019-04-18 18:32 + +from django.db import connection, migrations, ProgrammingError + + +def rename_many_to_many_key(apps, schema_editor): + + with connection.cursor() as cursor: + try: + cursor.execute('SELECT sector_id FROM partners_intervention_sections') + cursor.execute('ALTER TABLE "partners_intervention_sections" RENAME COLUMN "sector_id" TO "section_id";') + except ProgrammingError: + pass # first statement will fail since is already section_id + + +def undo_many_to_many_key(apps, schema_editor): + with connection.cursor() as cursor: + try: + cursor.execute('SELECT section_id FROM partners_intervention_sections') + cursor.execute('ALTER TABLE "partners_intervention_sections" RENAME COLUMN "section_id" TO "sector_id";') + except ProgrammingError: + pass # first statement will fail since is already sector_id + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0035_auto_20190404_0858'), + ] + + operations = [ + migrations.RunPython(rename_many_to_many_key, undo_many_to_many_key), + ] From bb5ec16f0a177a164e89613340e53fdce350ffb8 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 18 Apr 2019 21:39:26 -0400 Subject: [PATCH 58/79] 10400 admin for engagements, isort --- .isort.cfg | 1 + src/etools/applications/attachments/models.py | 3 +-- .../attachments/tests/factories.py | 1 - .../attachments/tests/test_commands.py | 1 + .../attachments/tests/test_views.py | 11 ++--------- src/etools/applications/audit/admin.py | 2 +- src/etools/applications/core/auth.py | 3 +-- src/etools/applications/core/middleware.py | 1 + .../core/migrations/0001_initial.py | 2 +- src/etools/applications/core/tests/cases.py | 6 +++--- .../applications/core/tests/test_middleware.py | 2 +- .../environment/tests/test_views.py | 2 +- .../applications/firms/tests/test_utils.py | 1 - src/etools/applications/funds/admin.py | 10 ++++++++-- src/etools/applications/funds/serializers.py | 10 ++++++++-- .../applications/funds/tests/test_api.py | 14 +++++++++----- .../applications/funds/tests/test_models.py | 11 ++++++++--- .../funds/tests/test_synchronizers.py | 18 +++++++++++++----- .../applications/funds/tests/test_views.py | 6 +----- src/etools/applications/funds/urls.py | 12 +++++++++--- .../management/commands/freeze_hact_data.py | 2 +- src/etools/applications/hact/models.py | 2 +- src/etools/applications/permissions2/models.py | 1 - src/etools/applications/vision/tasks.py | 4 ++-- .../vision/tests/test_synchronizers.py | 7 +++++-- 25 files changed, 79 insertions(+), 54 deletions(-) diff --git a/.isort.cfg b/.isort.cfg index 9a5035ac1d..4890e36deb 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -10,3 +10,4 @@ line_length = 119 balanced_wrapping = true order_by_type = false not_skip = __init__.py +skip_glob = **/migrations/** diff --git a/src/etools/applications/attachments/models.py b/src/etools/applications/attachments/models.py index 5d429f5a25..134113b584 100644 --- a/src/etools/applications/attachments/models.py +++ b/src/etools/applications/attachments/models.py @@ -5,14 +5,13 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError -from django.db import models, connection +from django.db import connection, models from django.urls import reverse from django.utils.text import slugify from django.utils.translation import ugettext as _ from model_utils.models import TimeStampedModel from ordered_model.models import OrderedModel - from unicef_attachments.models import Attachment as NewAttachment diff --git a/src/etools/applications/attachments/tests/factories.py b/src/etools/applications/attachments/tests/factories.py index 32784fa4de..4c058d4902 100644 --- a/src/etools/applications/attachments/tests/factories.py +++ b/src/etools/applications/attachments/tests/factories.py @@ -1,6 +1,5 @@ import factory.django from factory import fuzzy - from unicef_attachments.models import Attachment, AttachmentLink, FileType diff --git a/src/etools/applications/attachments/tests/test_commands.py b/src/etools/applications/attachments/tests/test_commands.py index 2113d6443f..e2849039f0 100644 --- a/src/etools/applications/attachments/tests/test_commands.py +++ b/src/etools/applications/attachments/tests/test_commands.py @@ -1,6 +1,7 @@ from django.core.management import call_command from unicef_attachments.utils import get_attachment_flat_model + from etools.applications.attachments.tests.factories import AttachmentFactory, AttachmentFileTypeFactory from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/attachments/tests/test_views.py b/src/etools/applications/attachments/tests/test_views.py index d49c4d827a..ff73dc6c28 100644 --- a/src/etools/applications/attachments/tests/test_views.py +++ b/src/etools/applications/attachments/tests/test_views.py @@ -2,10 +2,7 @@ from rest_framework import status -from etools.applications.attachments.tests.factories import ( - AttachmentFactory, - AttachmentFileTypeFactory, -) +from etools.applications.attachments.tests.factories import AttachmentFactory, AttachmentFileTypeFactory from etools.applications.audit.tests.factories import EngagementFactory from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import PartnerType @@ -19,11 +16,7 @@ InterventionResultLinkFactory, PartnerFactory, ) -from etools.applications.tpm.tests.factories import ( - SimpleTPMPartnerFactory, - TPMActivityFactory, - TPMVisitFactory, -) +from etools.applications.tpm.tests.factories import SimpleTPMPartnerFactory, TPMActivityFactory, TPMVisitFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/audit/admin.py b/src/etools/applications/audit/admin.py index a2a1b20973..9a7d969241 100644 --- a/src/etools/applications/audit/admin.py +++ b/src/etools/applications/audit/admin.py @@ -30,7 +30,7 @@ class EngagementAdmin(admin.ModelAdmin): 'status', 'start_date', 'end_date', 'status', 'engagement_type', ] search_fields = 'partner__name', 'agreement__auditor_firm__name', - filter_horizontal = ('authorized_officers', ) + filter_horizontal = ('authorized_officers', 'active_pd', 'staff_members') @admin.register(RiskCategory) diff --git a/src/etools/applications/core/auth.py b/src/etools/applications/core/auth.py index 982ca7b786..72dbae5651 100644 --- a/src/etools/applications/core/auth.py +++ b/src/etools/applications/core/auth.py @@ -10,9 +10,8 @@ from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework_jwt.settings import api_settings from rest_framework_jwt.utils import jwt_payload_handler -from social_core.pipeline import social_auth -from social_core.pipeline import user as social_core_user from social_core.backends.azuread_b2c import AzureADB2COAuth2 +from social_core.pipeline import social_auth, user as social_core_user from social_django.middleware import SocialAuthExceptionMiddleware from etools.applications.users.models import Country diff --git a/src/etools/applications/core/middleware.py b/src/etools/applications/core/middleware.py index 63c63b0b43..f788fd8bc0 100644 --- a/src/etools/applications/core/middleware.py +++ b/src/etools/applications/core/middleware.py @@ -6,6 +6,7 @@ from django.http.response import HttpResponseRedirect from django.template.response import SimpleTemplateResponse from django.urls import reverse + from django_tenants.middleware import TenantMiddleware from django_tenants.utils import get_public_schema_name diff --git a/src/etools/applications/core/migrations/0001_initial.py b/src/etools/applications/core/migrations/0001_initial.py index ba2f1ddf65..fd5a882d13 100644 --- a/src/etools/applications/core/migrations/0001_initial.py +++ b/src/etools/applications/core/migrations/0001_initial.py @@ -1,7 +1,7 @@ # Generated by Django 2.0.9 on 2018-10-16 10:47 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/src/etools/applications/core/tests/cases.py b/src/etools/applications/core/tests/cases.py index 41236bfcf8..7c9033c293 100644 --- a/src/etools/applications/core/tests/cases.py +++ b/src/etools/applications/core/tests/cases.py @@ -1,10 +1,10 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.management import call_command -from django.urls import resolve from django.db import connection -from django_tenants.test.cases import TenantTestCase -from django_tenants.utils import get_tenant_model, get_tenant_domain_model +from django.urls import resolve +from django_tenants.test.cases import TenantTestCase +from django_tenants.utils import get_tenant_domain_model, get_tenant_model from rest_framework.test import APIClient, APIRequestFactory, force_authenticate from unicef_notification.models import EmailTemplate diff --git a/src/etools/applications/core/tests/test_middleware.py b/src/etools/applications/core/tests/test_middleware.py index 340812a957..2cbb0d6095 100644 --- a/src/etools/applications/core/tests/test_middleware.py +++ b/src/etools/applications/core/tests/test_middleware.py @@ -3,8 +3,8 @@ from django.conf import settings from django.contrib.auth.models import AnonymousUser -from django.urls import reverse from django.test import override_settings, RequestFactory, TestCase +from django.urls import reverse from etools.applications.core.middleware import ANONYMOUS_ALLOWED_URL_FRAGMENTS, EToolsTenantMiddleware from etools.applications.users.tests.factories import CountryFactory, UserFactory diff --git a/src/etools/applications/environment/tests/test_views.py b/src/etools/applications/environment/tests/test_views.py index c6b054a917..e5df263a52 100644 --- a/src/etools/applications/environment/tests/test_views.py +++ b/src/etools/applications/environment/tests/test_views.py @@ -6,8 +6,8 @@ from rest_framework import status -from etools.applications.environment.tests.factories import TenantFlagFactory, TenantSwitchFactory from etools.applications.core.tests.cases import BaseTenantTestCase +from etools.applications.environment.tests.factories import TenantFlagFactory, TenantSwitchFactory from etools.applications.users.tests.factories import CountryFactory, UserFactory diff --git a/src/etools/applications/firms/tests/test_utils.py b/src/etools/applications/firms/tests/test_utils.py index 1692329b6f..2490f26791 100644 --- a/src/etools/applications/firms/tests/test_utils.py +++ b/src/etools/applications/firms/tests/test_utils.py @@ -1,7 +1,6 @@ from django.test import SimpleTestCase - from etools.applications.firms.utils import generate_username diff --git a/src/etools/applications/funds/admin.py b/src/etools/applications/funds/admin.py index a2ee585b95..294128ff72 100644 --- a/src/etools/applications/funds/admin.py +++ b/src/etools/applications/funds/admin.py @@ -1,7 +1,13 @@ from django.contrib import admin -from etools.applications.funds.models import (Donor, FundsCommitmentHeader, FundsCommitmentItem, - FundsReservationHeader, FundsReservationItem, Grant,) +from etools.applications.funds.models import ( + Donor, + FundsCommitmentHeader, + FundsCommitmentItem, + FundsReservationHeader, + FundsReservationItem, + Grant, +) class GrantAdmin(admin.ModelAdmin): diff --git a/src/etools/applications/funds/serializers.py b/src/etools/applications/funds/serializers.py index dc615e3148..33735c5787 100644 --- a/src/etools/applications/funds/serializers.py +++ b/src/etools/applications/funds/serializers.py @@ -1,8 +1,14 @@ from rest_framework import serializers -from etools.applications.funds.models import (Donor, FundsCommitmentHeader, FundsCommitmentItem, - FundsReservationHeader, FundsReservationItem, Grant,) +from etools.applications.funds.models import ( + Donor, + FundsCommitmentHeader, + FundsCommitmentItem, + FundsReservationHeader, + FundsReservationItem, + Grant, +) class FRLineItemSerializer(serializers.ModelSerializer): diff --git a/src/etools/applications/funds/tests/test_api.py b/src/etools/applications/funds/tests/test_api.py index dd4aeea1e6..30d9848d60 100644 --- a/src/etools/applications/funds/tests/test_api.py +++ b/src/etools/applications/funds/tests/test_api.py @@ -1,17 +1,21 @@ # Python imports -from django.urls import reverse from django.test import SimpleTestCase - +from django.urls import reverse from rest_framework import status from tablib.core import Dataset from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.core.tests.mixins import URLAssertionMixin -from etools.applications.funds.tests.factories import (DonorFactory, FundsCommitmentHeaderFactory, - FundsCommitmentItemFactory, FundsReservationHeaderFactory, - FundsReservationItemFactory, GrantFactory,) +from etools.applications.funds.tests.factories import ( + DonorFactory, + FundsCommitmentHeaderFactory, + FundsCommitmentItemFactory, + FundsReservationHeaderFactory, + FundsReservationItemFactory, + GrantFactory, +) from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/funds/tests/test_models.py b/src/etools/applications/funds/tests/test_models.py index d1ec13f640..e207a76740 100644 --- a/src/etools/applications/funds/tests/test_models.py +++ b/src/etools/applications/funds/tests/test_models.py @@ -2,9 +2,14 @@ from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.funds.models import FundsCommitmentItem, FundsReservationHeader, FundsReservationItem -from etools.applications.funds.tests.factories import (DonorFactory, FundsCommitmentHeaderFactory, - FundsCommitmentItemFactory, FundsReservationHeaderFactory, - FundsReservationItemFactory, GrantFactory,) +from etools.applications.funds.tests.factories import ( + DonorFactory, + FundsCommitmentHeaderFactory, + FundsCommitmentItemFactory, + FundsReservationHeaderFactory, + FundsReservationItemFactory, + GrantFactory, +) class TestStrUnicode(BaseTenantTestCase): diff --git a/src/etools/applications/funds/tests/test_synchronizers.py b/src/etools/applications/funds/tests/test_synchronizers.py index fd28dabc34..741d152baf 100644 --- a/src/etools/applications/funds/tests/test_synchronizers.py +++ b/src/etools/applications/funds/tests/test_synchronizers.py @@ -4,12 +4,20 @@ from decimal import Decimal from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.funds.models import (FundsCommitmentHeader, FundsCommitmentItem, - FundsReservationHeader, FundsReservationItem,) -from etools.applications.funds.tests.factories import (FundsCommitmentHeaderFactory, FundsCommitmentItemFactory, - FundsReservationHeaderFactory, FundsReservationItemFactory,) -from etools.applications.users.models import Country from etools.applications.funds import synchronizers +from etools.applications.funds.models import ( + FundsCommitmentHeader, + FundsCommitmentItem, + FundsReservationHeader, + FundsReservationItem, +) +from etools.applications.funds.tests.factories import ( + FundsCommitmentHeaderFactory, + FundsCommitmentItemFactory, + FundsReservationHeaderFactory, + FundsReservationItemFactory, +) +from etools.applications.users.models import Country class TestFundReservationsSynchronizer(BaseTenantTestCase): diff --git a/src/etools/applications/funds/tests/test_views.py b/src/etools/applications/funds/tests/test_views.py index 5b3391fc96..3fb30a021c 100644 --- a/src/etools/applications/funds/tests/test_views.py +++ b/src/etools/applications/funds/tests/test_views.py @@ -13,11 +13,7 @@ FundsReservationItemFactory, GrantFactory, ) -from etools.applications.partners.tests.factories import ( - AgreementFactory, - InterventionFactory, - PartnerFactory, -) +from etools.applications.partners.tests.factories import AgreementFactory, InterventionFactory, PartnerFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/funds/urls.py b/src/etools/applications/funds/urls.py index 1ad9348954..e430ab876e 100644 --- a/src/etools/applications/funds/urls.py +++ b/src/etools/applications/funds/urls.py @@ -1,9 +1,15 @@ from django.conf.urls import url -from etools.applications.funds.views import (DonorListAPIView, FRsView, FundsCommitmentHeaderListAPIView, - FundsCommitmentItemListAPIView, FundsReservationHeaderListAPIView, - FundsReservationItemListAPIView, GrantListAPIView,) +from etools.applications.funds.views import ( + DonorListAPIView, + FRsView, + FundsCommitmentHeaderListAPIView, + FundsCommitmentItemListAPIView, + FundsReservationHeaderListAPIView, + FundsReservationItemListAPIView, + GrantListAPIView, +) app_name = 'funds' urlpatterns = ( diff --git a/src/etools/applications/hact/management/commands/freeze_hact_data.py b/src/etools/applications/hact/management/commands/freeze_hact_data.py index 9524e4e920..321bc60a43 100644 --- a/src/etools/applications/hact/management/commands/freeze_hact_data.py +++ b/src/etools/applications/hact/management/commands/freeze_hact_data.py @@ -4,11 +4,11 @@ from django.core.management import BaseCommand from django.db import transaction -from etools.libraries.pythonlib.encoders import CustomJSONEncoder from etools.applications.core.util_scripts import set_country from etools.applications.hact.models import HactHistory from etools.applications.partners.models import hact_default, PartnerOrganization, PlannedEngagement from etools.applications.users.models import Country +from etools.libraries.pythonlib.encoders import CustomJSONEncoder class Command(BaseCommand): diff --git a/src/etools/applications/hact/models.py b/src/etools/applications/hact/models.py index fb088836c2..b4ccd19c29 100644 --- a/src/etools/applications/hact/models.py +++ b/src/etools/applications/hact/models.py @@ -11,9 +11,9 @@ from model_utils.models import TimeStampedModel from etools.applications.audit.models import Audit, Engagement, MicroAssessment, SpecialAudit, SpotCheck -from etools.libraries.pythonlib.encoders import CustomJSONEncoder from etools.applications.partners.models import PartnerOrganization, PartnerType from etools.libraries.pythonlib.datetime import get_current_year +from etools.libraries.pythonlib.encoders import CustomJSONEncoder class HactHistory(TimeStampedModel): diff --git a/src/etools/applications/permissions2/models.py b/src/etools/applications/permissions2/models.py index 674da9d0c3..989515836e 100644 --- a/src/etools/applications/permissions2/models.py +++ b/src/etools/applications/permissions2/models.py @@ -2,7 +2,6 @@ from django.contrib.postgres.fields import ArrayField from django.db import models - from model_utils import Choices from .conditions import BaseCondition diff --git a/src/etools/applications/vision/tasks.py b/src/etools/applications/vision/tasks.py index 7e9732df8f..da84599449 100644 --- a/src/etools/applications/vision/tasks.py +++ b/src/etools/applications/vision/tasks.py @@ -3,8 +3,8 @@ from celery.utils.log import get_task_logger -from etools.applications.funds.synchronizers import FundReservationsSynchronizer, FundCommitmentSynchronizer -from etools.applications.partners.synchronizers import PartnerSynchronizer, DirectCashTransferSynchronizer +from etools.applications.funds.synchronizers import FundCommitmentSynchronizer, FundReservationsSynchronizer +from etools.applications.partners.synchronizers import DirectCashTransferSynchronizer, PartnerSynchronizer from etools.applications.reports.synchronizers import ProgrammeSynchronizer, RAMSynchronizer from etools.applications.users.models import Country from etools.applications.vision.exceptions import VisionException diff --git a/src/etools/applications/vision/tests/test_synchronizers.py b/src/etools/applications/vision/tests/test_synchronizers.py index daeeed2358..89d8443bb2 100644 --- a/src/etools/applications/vision/tests/test_synchronizers.py +++ b/src/etools/applications/vision/tests/test_synchronizers.py @@ -9,8 +9,11 @@ from etools.applications.vision.exceptions import VisionException from etools.applications.vision.models import VisionSyncLog from etools.applications.vision.synchronizers import ManualDataLoader -from etools.applications.vision.vision_data_synchronizer import (VISION_NO_DATA_MESSAGE, VisionDataLoader, - VisionDataSynchronizer,) +from etools.applications.vision.vision_data_synchronizer import ( + VISION_NO_DATA_MESSAGE, + VisionDataLoader, + VisionDataSynchronizer, +) FAUX_VISION_URL = 'https://api.example.com/foo.svc/' FAUX_VISION_USER = 'jane_user' From 8c60b54de30883bf9178ceccf407c00a42d1218c Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 22 Apr 2019 11:09:46 -0400 Subject: [PATCH 59/79] isort --- .isort.cfg | 2 +- runtests.sh | 1 + src/etools/applications/partners/admin.py | 2 +- src/etools/applications/partners/exports.py | 2 +- .../applications/partners/permissions.py | 1 + .../partners/serializers/interventions_v2.py | 2 +- .../serializers/partner_organization_v2.py | 2 +- .../partners/serializers/prp_v1.py | 22 +++++++++++----- .../applications/partners/tests/test_admin.py | 6 +---- .../applications/partners/tests/test_api.py | 14 ++++++++--- .../partners/tests/test_api_agreements.py | 2 +- .../partners/tests/test_api_dashboards.py | 2 +- .../partners/tests/test_api_interventions.py | 4 +-- .../partners/tests/test_api_partners.py | 6 +---- .../partners/tests/test_api_pmp.py | 2 +- .../partners/tests/test_serializers.py | 13 +++++++--- .../tests/test_serializers_intervention.py | 2 +- .../applications/partners/tests/test_utils.py | 25 +++++-------------- .../tests/test_validation_agreements.py | 4 +-- .../tests/test_validation_interventions.py | 15 +++-------- src/etools/applications/partners/urls_v2.py | 2 +- .../partners/validation/agreements.py | 11 +++----- .../partners/validation/interventions.py | 12 +++------ .../partners/views/agreements_v2.py | 2 +- .../applications/partners/views/dashboards.py | 16 ++---------- .../partners/views/interventions_v2.py | 16 +++++++++++- .../partners/views/partner_organization_v2.py | 2 +- .../applications/partners/views/prp_v1.py | 12 +++++---- src/etools/applications/partners/views/v1.py | 2 +- src/etools/config/sentry.py | 7 +++--- 30 files changed, 100 insertions(+), 111 deletions(-) diff --git a/.isort.cfg b/.isort.cfg index 4890e36deb..b6def00452 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -6,7 +6,7 @@ known_django = django sections = FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER known_first_party = etools multi_line_output = 3 -line_length = 119 +line_length = 120 balanced_wrapping = true order_by_type = false not_skip = __init__.py diff --git a/runtests.sh b/runtests.sh index 27e63b366d..de46b7ebd5 100755 --- a/runtests.sh +++ b/runtests.sh @@ -15,6 +15,7 @@ python -W ignore manage.py makemigrations --dry-run --check # Check code style unless running under tox, in which case tox runs flake8 separately if [[ $RUNNING_UNDER_TOX != 1 ]] ; then time flake8 src/ + # time isort -rc src/ --check-only fi # Run unittests and coverage report diff --git a/src/etools/applications/partners/admin.py b/src/etools/applications/partners/admin.py index ca86a1306c..a0329afe79 100644 --- a/src/etools/applications/partners/admin.py +++ b/src/etools/applications/partners/admin.py @@ -13,9 +13,9 @@ from etools.applications.partners.exports import PartnerExport from etools.applications.partners.forms import ( # TODO intervention sector locations cleanup + InterventionAttachmentForm, PartnersAdminForm, PartnerStaffMemberForm, - InterventionAttachmentForm, ) from etools.applications.partners.mixins import CountryUsersAdminMixin, HiddenPartnerMixin from etools.applications.partners.models import ( # TODO intervention sector locations cleanup diff --git a/src/etools/applications/partners/exports.py b/src/etools/applications/partners/exports.py index 0988b8a908..cfe454f9bd 100644 --- a/src/etools/applications/partners/exports.py +++ b/src/etools/applications/partners/exports.py @@ -1,6 +1,6 @@ from import_export import resources -from etools.applications.partners.models import PartnerOrganization, Intervention +from etools.applications.partners.models import Intervention, PartnerOrganization class PartnerExport(resources.ModelResource): diff --git a/src/etools/applications/partners/permissions.py b/src/etools/applications/partners/permissions.py index 9ba68582e6..6800bb5c14 100644 --- a/src/etools/applications/partners/permissions.py +++ b/src/etools/applications/partners/permissions.py @@ -1,4 +1,5 @@ import datetime + from django.apps import apps from django.utils.lru_cache import lru_cache from django.utils.translation import ugettext as _ diff --git a/src/etools/applications/partners/serializers/interventions_v2.py b/src/etools/applications/partners/serializers/interventions_v2.py index b15185cc85..211ee7a5e8 100644 --- a/src/etools/applications/partners/serializers/interventions_v2.py +++ b/src/etools/applications/partners/serializers/interventions_v2.py @@ -1,4 +1,4 @@ -from datetime import datetime, date +from datetime import date, datetime from operator import itemgetter from django.db import transaction diff --git a/src/etools/applications/partners/serializers/partner_organization_v2.py b/src/etools/applications/partners/serializers/partner_organization_v2.py index f936931648..b155892d06 100644 --- a/src/etools/applications/partners/serializers/partner_organization_v2.py +++ b/src/etools/applications/partners/serializers/partner_organization_v2.py @@ -22,8 +22,8 @@ PlannedEngagement, ) from etools.applications.partners.serializers.interventions_v2 import ( - InterventionMonitorSerializer, InterventionListSerializer, + InterventionMonitorSerializer, ) diff --git a/src/etools/applications/partners/serializers/prp_v1.py b/src/etools/applications/partners/serializers/prp_v1.py index aaefeb435e..6fb6b2ea89 100644 --- a/src/etools/applications/partners/serializers/prp_v1.py +++ b/src/etools/applications/partners/serializers/prp_v1.py @@ -4,13 +4,23 @@ from rest_framework import serializers from unicef_attachments.fields import AttachmentSingleFileField - from unicef_locations.models import Location -from etools.applications.partners.models import (Intervention, InterventionAmendment, - PartnerOrganization, PartnerStaffMember,) -from etools.applications.reports.models import (AppliedIndicator, Disaggregation, - DisaggregationValue, LowerResult, Result, ReportingRequirement, - SpecialReportingRequirement) + +from etools.applications.partners.models import ( + Intervention, + InterventionAmendment, + PartnerOrganization, + PartnerStaffMember, +) +from etools.applications.reports.models import ( + AppliedIndicator, + Disaggregation, + DisaggregationValue, + LowerResult, + ReportingRequirement, + Result, + SpecialReportingRequirement, +) from etools.applications.reports.serializers.v1 import SectionSerializer diff --git a/src/etools/applications/partners/tests/test_admin.py b/src/etools/applications/partners/tests/test_admin.py index bbbe408968..42254bdbbb 100644 --- a/src/etools/applications/partners/tests/test_admin.py +++ b/src/etools/applications/partners/tests/test_admin.py @@ -5,11 +5,7 @@ from unicef_snapshot.models import Activity from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.partners.admin import ( - AgreementAdmin, - InterventionAdmin, - PartnerStaffMemberAdmin, -) +from etools.applications.partners.admin import AgreementAdmin, InterventionAdmin, PartnerStaffMemberAdmin from etools.applications.partners.models import Agreement, Intervention, PartnerStaffMember from etools.applications.partners.tests.factories import ( AgreementFactory, diff --git a/src/etools/applications/partners/tests/test_api.py b/src/etools/applications/partners/tests/test_api.py index 567e25e31c..d04a7b582d 100644 --- a/src/etools/applications/partners/tests/test_api.py +++ b/src/etools/applications/partners/tests/test_api.py @@ -3,10 +3,16 @@ from django.urls import reverse from etools.applications.core.tests.cases import BaseTenantTestCase -from etools.applications.partners.models import PartnerType, PartnerOrganization -from etools.applications.partners.tests.factories import (AgreementFactory, AgreementAmendmentFactory, PartnerFactory, InterventionFactory, - InterventionAmendmentFactory, InterventionResultLinkFactory) -from etools.libraries.tests.api_checker import ApiCheckerMixin, ViewSetChecker, AssertTimeStampedMixin +from etools.applications.partners.models import PartnerOrganization, PartnerType +from etools.applications.partners.tests.factories import ( + AgreementAmendmentFactory, + AgreementFactory, + InterventionAmendmentFactory, + InterventionFactory, + InterventionResultLinkFactory, + PartnerFactory, +) +from etools.libraries.tests.api_checker import ApiCheckerMixin, AssertTimeStampedMixin, ViewSetChecker class TestAPIAgreements(ApiCheckerMixin, AssertTimeStampedMixin, BaseTenantTestCase): diff --git a/src/etools/applications/partners/tests/test_api_agreements.py b/src/etools/applications/partners/tests/test_api_agreements.py index a074bb0ba1..74a04a28b9 100644 --- a/src/etools/applications/partners/tests/test_api_agreements.py +++ b/src/etools/applications/partners/tests/test_api_agreements.py @@ -1,10 +1,10 @@ import datetime import json -import mock from django.test import SimpleTestCase from django.urls import reverse +import mock from rest_framework import status from unicef_attachments.models import Attachment from unicef_snapshot.models import Activity diff --git a/src/etools/applications/partners/tests/test_api_dashboards.py b/src/etools/applications/partners/tests/test_api_dashboards.py index 71a6f03441..76b5d7dca9 100644 --- a/src/etools/applications/partners/tests/test_api_dashboards.py +++ b/src/etools/applications/partners/tests/test_api_dashboards.py @@ -15,7 +15,7 @@ InterventionFactory, ) from etools.applications.t2f.models import Travel, TravelType -from etools.applications.t2f.tests.factories import TravelFactory, TravelActivityFactory +from etools.applications.t2f.tests.factories import TravelActivityFactory, TravelFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/partners/tests/test_api_interventions.py b/src/etools/applications/partners/tests/test_api_interventions.py index a11a431a37..fdde3237e7 100644 --- a/src/etools/applications/partners/tests/test_api_interventions.py +++ b/src/etools/applications/partners/tests/test_api_interventions.py @@ -18,10 +18,10 @@ from etools.applications.attachments.models import AttachmentFlat from etools.applications.attachments.tests.factories import AttachmentFactory, AttachmentFileTypeFactory -from etools.applications.environment.helpers import tenant_switch_is_active -from etools.applications.environment.tests.factories import TenantSwitchFactory from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.core.tests.mixins import URLAssertionMixin +from etools.applications.environment.helpers import tenant_switch_is_active +from etools.applications.environment.tests.factories import TenantSwitchFactory from etools.applications.partners.models import Intervention, InterventionAmendment, InterventionResultLink from etools.applications.partners.permissions import InterventionPermissions from etools.applications.partners.tests.factories import ( diff --git a/src/etools/applications/partners/tests/test_api_partners.py b/src/etools/applications/partners/tests/test_api_partners.py index 668bb800a4..3d32f53d02 100644 --- a/src/etools/applications/partners/tests/test_api_partners.py +++ b/src/etools/applications/partners/tests/test_api_partners.py @@ -34,11 +34,7 @@ ) from etools.applications.partners.views.partner_organization_v2 import PartnerOrganizationAddView from etools.applications.reports.models import ResultType -from etools.applications.reports.tests.factories import ( - CountryProgrammeFactory, - ResultFactory, - ResultTypeFactory, -) +from etools.applications.reports.tests.factories import CountryProgrammeFactory, ResultFactory, ResultTypeFactory from etools.applications.t2f.tests.factories import TravelActivityFactory from etools.applications.users.tests.factories import GroupFactory, UserFactory diff --git a/src/etools/applications/partners/tests/test_api_pmp.py b/src/etools/applications/partners/tests/test_api_pmp.py index 95782af5a0..a5dba0c4ec 100644 --- a/src/etools/applications/partners/tests/test_api_pmp.py +++ b/src/etools/applications/partners/tests/test_api_pmp.py @@ -3,8 +3,8 @@ from django.test import SimpleTestCase from django.urls import reverse -from django_tenants.test.client import TenantClient +from django_tenants.test.client import TenantClient from rest_framework import status from unicef_djangolib.fields import CURRENCY_LIST from unicef_locations.tests.factories import GatewayTypeFactory diff --git a/src/etools/applications/partners/tests/test_serializers.py b/src/etools/applications/partners/tests/test_serializers.py index 32b8e87f1a..09c41999fd 100644 --- a/src/etools/applications/partners/tests/test_serializers.py +++ b/src/etools/applications/partners/tests/test_serializers.py @@ -1,16 +1,21 @@ # Python imports import datetime - from unittest import skip + from rest_framework import serializers from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import Agreement, PartnerType from etools.applications.partners.serializers.agreements_v2 import AgreementCreateUpdateSerializer from etools.applications.partners.serializers.partner_organization_v2 import PartnerOrganizationDetailSerializer -from etools.applications.partners.tests.factories import (AgreementAmendmentFactory, AgreementFactory, - InterventionFactory, PartnerFactory, PartnerStaffFactory, - PlannedEngagementFactory,) +from etools.applications.partners.tests.factories import ( + AgreementAmendmentFactory, + AgreementFactory, + InterventionFactory, + PartnerFactory, + PartnerStaffFactory, + PlannedEngagementFactory, +) from etools.applications.reports.tests.factories import CountryProgrammeFactory from etools.applications.users.tests.factories import UserFactory diff --git a/src/etools/applications/partners/tests/test_serializers_intervention.py b/src/etools/applications/partners/tests/test_serializers_intervention.py index 4e2e6ec165..7606ffbc8a 100644 --- a/src/etools/applications/partners/tests/test_serializers_intervention.py +++ b/src/etools/applications/partners/tests/test_serializers_intervention.py @@ -5,7 +5,7 @@ from etools.applications.partners.serializers.interventions_v2 import InterventionReportingRequirementCreateSerializer from etools.applications.partners.tests.factories import InterventionFactory, InterventionResultLinkFactory from etools.applications.reports.models import ReportingRequirement -from etools.applications.reports.tests.factories import (AppliedIndicatorFactory, LowerResultFactory) +from etools.applications.reports.tests.factories import AppliedIndicatorFactory, LowerResultFactory class TestInterventionReportingRequirementCreateSerializer(BaseTenantTestCase): diff --git a/src/etools/applications/partners/tests/test_utils.py b/src/etools/applications/partners/tests/test_utils.py index 84d8585def..2207591e70 100644 --- a/src/etools/applications/partners/tests/test_utils.py +++ b/src/etools/applications/partners/tests/test_utils.py @@ -1,32 +1,19 @@ import datetime -from mock import Mock, patch from django.conf import settings from django.core.management import call_command from django.utils import timezone +from mock import Mock, patch +from unicef_locations.tests.factories import GatewayTypeFactory, LocationFactory + from etools.applications.attachments.tests.factories import AttachmentFileTypeFactory from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.funds.tests.factories import FundsReservationHeaderFactory -from unicef_locations.tests.factories import GatewayTypeFactory, LocationFactory from etools.applications.partners import utils -from etools.applications.partners.models import ( - Agreement, - Intervention, - InterventionBudget, - InterventionResultLink, -) -from etools.applications.partners.tests.factories import ( - AgreementFactory, - InterventionFactory, - PartnerFactory, -) -from etools.applications.reports.models import ( - AppliedIndicator, - IndicatorBlueprint, - LowerResult, - ResultType, -) +from etools.applications.partners.models import Agreement, Intervention, InterventionBudget, InterventionResultLink +from etools.applications.partners.tests.factories import AgreementFactory, InterventionFactory, PartnerFactory +from etools.applications.reports.models import AppliedIndicator, IndicatorBlueprint, LowerResult, ResultType from etools.applications.reports.tests.factories import CountryProgrammeFactory, ResultFactory from etools.applications.users.tests.factories import GroupFactory, UserFactory diff --git a/src/etools/applications/partners/tests/test_validation_agreements.py b/src/etools/applications/partners/tests/test_validation_agreements.py index 4741304ad3..7e56764665 100644 --- a/src/etools/applications/partners/tests/test_validation_agreements.py +++ b/src/etools/applications/partners/tests/test_validation_agreements.py @@ -1,7 +1,8 @@ import datetime - from unittest import skip +from etools_validator.exceptions import BasicValidationError, TransitionError + from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.partners.models import Agreement from etools.applications.partners.tests.factories import ( @@ -13,7 +14,6 @@ from etools.applications.partners.validation import agreements from etools.applications.reports.tests.factories import CountryProgrammeFactory from etools.applications.users.tests.factories import UserFactory -from etools_validator.exceptions import BasicValidationError, TransitionError class TestAgreementTransitionToSignedValid(BaseTenantTestCase): diff --git a/src/etools/applications/partners/tests/test_validation_interventions.py b/src/etools/applications/partners/tests/test_validation_interventions.py index c01794aa44..fbaecd7a16 100644 --- a/src/etools/applications/partners/tests/test_validation_interventions.py +++ b/src/etools/applications/partners/tests/test_validation_interventions.py @@ -1,17 +1,13 @@ import datetime from unittest import skip +from etools_validator.exceptions import BasicValidationError, StateValidationError, TransitionError from mock import Mock, patch -from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.attachments.tests.factories import AttachmentFactory +from etools.applications.core.tests.cases import BaseTenantTestCase from etools.applications.funds.tests.factories import FundsReservationHeaderFactory -from etools.applications.partners.models import ( - Agreement, - FileType, - Intervention, - InterventionAmendment, -) +from etools.applications.partners.models import Agreement, FileType, Intervention, InterventionAmendment from etools.applications.partners.tests.factories import ( AgreementFactory, FileTypeFactory, @@ -35,11 +31,6 @@ transition_to_terminated, ) from etools.applications.users.tests.factories import GroupFactory, UserFactory -from etools_validator.exceptions import ( - BasicValidationError, - StateValidationError, - TransitionError, -) class TestPartnershipManagerOnly(BaseTenantTestCase): diff --git a/src/etools/applications/partners/urls_v2.py b/src/etools/applications/partners/urls_v2.py index 2b2fc488df..b667d35a36 100644 --- a/src/etools/applications/partners/urls_v2.py +++ b/src/etools/applications/partners/urls_v2.py @@ -39,8 +39,8 @@ PartnerNotProgrammaticVisitCompliant, PartnerNotSpotCheckCompliant, PartnerOrganizationAddView, - PartnerOrganizationAssessmentUpdateDeleteView, PartnerOrganizationAssessmentListCreateView, + PartnerOrganizationAssessmentUpdateDeleteView, PartnerOrganizationDashboardAPIView, PartnerOrganizationDeleteView, PartnerOrganizationDetailAPIView, diff --git a/src/etools/applications/partners/validation/agreements.py b/src/etools/applications/partners/validation/agreements.py index 34387e6673..ac48b6c852 100644 --- a/src/etools/applications/partners/validation/agreements.py +++ b/src/etools/applications/partners/validation/agreements.py @@ -3,15 +3,12 @@ from django.utils.translation import ugettext as _ -from etools.applications.partners.permissions import AgreementPermissions -from etools_validator.exceptions import ( - BasicValidationError, - StateValidationError, - TransitionError, -) -from etools_validator.utils import check_rigid_fields, check_required_fields +from etools_validator.exceptions import BasicValidationError, StateValidationError, TransitionError +from etools_validator.utils import check_required_fields, check_rigid_fields from etools_validator.validation import CompleteValidation +from etools.applications.partners.permissions import AgreementPermissions + def agreement_transition_to_signed_valid(agreement): """Returns True if it's valid for the agreement to transition to signed, otherwise raises a TransitionError. diff --git a/src/etools/applications/partners/validation/interventions.py b/src/etools/applications/partners/validation/interventions.py index 4340398065..d874f77a6e 100644 --- a/src/etools/applications/partners/validation/interventions.py +++ b/src/etools/applications/partners/validation/interventions.py @@ -1,18 +1,14 @@ import logging from datetime import date - from django.utils.translation import ugettext as _ +from etools_validator.exceptions import BasicValidationError, StateValidationError, TransitionError +from etools_validator.utils import check_required_fields, check_rigid_fields +from etools_validator.validation import CompleteValidation + from etools.applications.partners.permissions import InterventionPermissions from etools.applications.reports.models import AppliedIndicator -from etools_validator.exceptions import ( - BasicValidationError, - StateValidationError, - TransitionError, -) -from etools_validator.utils import check_rigid_fields, check_required_fields -from etools_validator.validation import CompleteValidation logger = logging.getLogger('partners.interventions.validation') diff --git a/src/etools/applications/partners/views/agreements_v2.py b/src/etools/applications/partners/views/agreements_v2.py index 46e05ff879..1a4e04fb24 100644 --- a/src/etools/applications/partners/views/agreements_v2.py +++ b/src/etools/applications/partners/views/agreements_v2.py @@ -32,8 +32,8 @@ AgreementExportFlatSerializer, AgreementExportSerializer, ) -from etools.applications.partners.validation.agreements import AgreementValid from etools.applications.partners.utils import send_agreement_suspended_notification +from etools.applications.partners.validation.agreements import AgreementValid class AgreementListAPIView(QueryStringFilterMixin, ExportModelMixin, ValidatorViewMixin, ListCreateAPIView): diff --git a/src/etools/applications/partners/views/dashboards.py b/src/etools/applications/partners/views/dashboards.py index 0bd9131d30..897d033475 100644 --- a/src/etools/applications/partners/views/dashboards.py +++ b/src/etools/applications/partners/views/dashboards.py @@ -1,19 +1,7 @@ import functools import operator -from django.db.models import ( - Case, - CharField, - Count, - F, - Max, - Min, - OuterRef, - Q, - Subquery, - Sum, - When, -) +from django.db.models import Case, CharField, Count, F, Max, Min, OuterRef, Q, Subquery, Sum, When from rest_framework.generics import ListCreateAPIView from rest_framework.permissions import IsAdminUser @@ -25,7 +13,7 @@ from etools.applications.partners.exports_v2 import PartnershipDashCSVRenderer from etools.applications.partners.models import FileType, Intervention, InterventionAttachment from etools.applications.partners.serializers.dashboards import InterventionDashSerializer -from etools.applications.t2f.models import Travel, TravelType, TravelActivity +from etools.applications.t2f.models import Travel, TravelActivity, TravelType class InterventionPartnershipDashView(QueryStringFilterMixin, ListCreateAPIView): diff --git a/src/etools/applications/partners/views/interventions_v2.py b/src/etools/applications/partners/views/interventions_v2.py index 54747e4881..49b0866ce4 100644 --- a/src/etools/applications/partners/views/interventions_v2.py +++ b/src/etools/applications/partners/views/interventions_v2.py @@ -650,7 +650,7 @@ def sort_key(self): ) -class InterventionLocationListAPIView(ListAPIView): +class InterventionLocationListAPIView(QueryStringFilterMixin, ListAPIView): """ API to export a list of intervention locations. @@ -668,6 +668,20 @@ class InterventionLocationListAPIView(ListAPIView): InterventionLocationCSVRenderer, ) + filters = ( + ('sections', 'sections__in'), + ('country_programmes', 'country_programme__in'), + ('status', 'status__in'), + ('partners', 'agreement__partner__in'), + ('offices', 'offices__in'), + ('results', 'result_links__cp_output__in'), + ('donors', 'frs__fr_items__donor__in'), + ('grants', 'frs__fr_items__grant_number__in'), + ('unicef_focal_points', 'unicef_focal_points__in'), + ('interventions', 'pk__in'), + ('clusters', 'result_links__ll_results__applied_indicators__cluster_name__icontains'), + ) + def list(self, request, *args, **kwargs): rows = [] for intervention in self.get_queryset(): diff --git a/src/etools/applications/partners/views/partner_organization_v2.py b/src/etools/applications/partners/views/partner_organization_v2.py index 2c636100ba..a5fe6bd299 100644 --- a/src/etools/applications/partners/views/partner_organization_v2.py +++ b/src/etools/applications/partners/views/partner_organization_v2.py @@ -72,8 +72,8 @@ from etools.applications.partners.synchronizers import PartnerSynchronizer from etools.applications.partners.views.helpers import set_tenant_or_fail from etools.applications.t2f.models import Travel, TravelActivity, TravelType -from etools.libraries.djangolib.models import StringConcat from etools.applications.vision.utils import get_data_from_insight +from etools.libraries.djangolib.models import StringConcat class PartnerOrganizationListAPIView(QueryStringFilterMixin, ExportModelMixin, ListCreateAPIView): diff --git a/src/etools/applications/partners/views/prp_v1.py b/src/etools/applications/partners/views/prp_v1.py index 6fae616e7e..d498783589 100644 --- a/src/etools/applications/partners/views/prp_v1.py +++ b/src/etools/applications/partners/views/prp_v1.py @@ -3,17 +3,19 @@ from django.db.models import Q -from rest_framework.generics import ListAPIView, get_object_or_404 +from rest_framework.generics import get_object_or_404, ListAPIView +from rest_framework.pagination import LimitOffsetPagination from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework.pagination import LimitOffsetPagination - from etools.applications.partners.filters import PartnerScopeFilter from etools.applications.partners.models import Intervention, PartnerOrganization from etools.applications.partners.permissions import ListCreateAPIMixedPermission, ReadOnlyAPIUser -from etools.applications.partners.serializers.prp_v1 import PRPInterventionListSerializer, \ - PRPPartnerOrganizationListSerializer, InterventionPDFileSerializer +from etools.applications.partners.serializers.prp_v1 import ( + InterventionPDFileSerializer, + PRPInterventionListSerializer, + PRPPartnerOrganizationListSerializer, +) from etools.applications.partners.views.helpers import set_tenant_or_fail diff --git a/src/etools/applications/partners/views/v1.py b/src/etools/applications/partners/views/v1.py index 9a21cceda8..bd70801100 100644 --- a/src/etools/applications/partners/views/v1.py +++ b/src/etools/applications/partners/views/v1.py @@ -1,10 +1,10 @@ from collections import namedtuple from django.conf import settings +from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpResponse from django.utils.http import urlsafe_base64_decode from django.views.generic import TemplateView, View -from django.contrib.auth.mixins import LoginRequiredMixin from easy_pdf.views import PDFTemplateView from rest_framework import mixins, viewsets diff --git a/src/etools/config/sentry.py b/src/etools/config/sentry.py index 43274527ed..a7f92dd158 100644 --- a/src/etools/config/sentry.py +++ b/src/etools/config/sentry.py @@ -1,12 +1,11 @@ -import sentry_sdk +from django.conf import settings +from django.db import connection +import sentry_sdk from sentry_sdk import configure_scope from sentry_sdk.integrations.celery import CeleryIntegration from sentry_sdk.integrations.django import DjangoIntegration -from django.db import connection -from django.conf import settings - if hasattr(settings, 'SENTRY_DSN'): def before_send(event, hint): with configure_scope() as scope: From 220c9456d25a3e0bf59c582113652d067dddc4c3 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 23 Apr 2019 11:44:09 -0400 Subject: [PATCH 60/79] added missing filters --- .../partners/views/interventions_v2.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/etools/applications/partners/views/interventions_v2.py b/src/etools/applications/partners/views/interventions_v2.py index 49b0866ce4..a8f3f023ee 100644 --- a/src/etools/applications/partners/views/interventions_v2.py +++ b/src/etools/applications/partners/views/interventions_v2.py @@ -669,17 +669,24 @@ class InterventionLocationListAPIView(QueryStringFilterMixin, ListAPIView): ) filters = ( + ('status', 'status__in'), + ('document_type', 'document_type__in'), ('sections', 'sections__in'), + ('office', 'offices__in'), ('country_programmes', 'country_programme__in'), - ('status', 'status__in'), - ('partners', 'agreement__partner__in'), - ('offices', 'offices__in'), - ('results', 'result_links__cp_output__in'), ('donors', 'frs__fr_items__donor__in'), ('grants', 'frs__fr_items__grant_number__in'), + ('results', 'result_links__cp_output__in'), ('unicef_focal_points', 'unicef_focal_points__in'), ('interventions', 'pk__in'), - ('clusters', 'result_links__ll_results__applied_indicators__cluster_name__icontains'), + ('cp_outputs', 'result_links__cp_output__in'), + ('cluster', 'result_links__ll_results__applied_indicators__cluster_indicator_title__icontains'), + ('unicef_focal_points', 'unicef_focal_points__in'), + ('start', 'start__gte'), + ('end', 'end__lte'), + ('end_after', 'end__gte'), + ('location', 'result_links__ll_results__applied_indicators__locations__name__icontains'), + ('partners', 'agreement__partner__in'), ) def list(self, request, *args, **kwargs): From 2eb7d0eb3ed415940d7cf77f8cd6d88fbe08ec2e Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 23 Apr 2019 11:04:22 -0400 Subject: [PATCH 61/79] admin audit staff member allow to filter by email --- src/etools/applications/audit/purchase_order/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etools/applications/audit/purchase_order/admin.py b/src/etools/applications/audit/purchase_order/admin.py index 79469be1a4..0c73fd5e58 100644 --- a/src/etools/applications/audit/purchase_order/admin.py +++ b/src/etools/applications/audit/purchase_order/admin.py @@ -50,4 +50,4 @@ class PurchaseOrderAdmin(admin.ModelAdmin): class AuditorStaffAdmin(admin.ModelAdmin): list_display = ['user', 'auditor_firm', 'hidden'] list_filter = ['auditor_firm', 'hidden'] - search_fields = ['user__username', 'user__first_name', 'user__last_name', 'auditor_firm__name', ] + search_fields = ['user__username', 'user__email', 'user__first_name', 'user__last_name', 'auditor_firm__name', ] From ac32f95eb418adbd2228988ab53e33dce59e10ac Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 23 Apr 2019 10:59:10 -0400 Subject: [PATCH 62/79] Change yaml load to safe_load to prevent warning --- src/etools/config/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etools/config/settings/base.py b/src/etools/config/settings/base.py index 35ecdfec1f..744d430b5d 100644 --- a/src/etools/config/settings/base.py +++ b/src/etools/config/settings/base.py @@ -47,7 +47,7 @@ def str2bool(value): try: with open(SECRETS_FILE_LOCATION, 'r') as secrets_file: - SECRETS = yaml.load(secrets_file)['ENVIRONMENT'] + SECRETS = yaml.safe_load(secrets_file)['ENVIRONMENT'] except FileNotFoundError: # pass, for now we default trying to get the secrets from env vars as well SECRETS = {} From e71ee7e75f3a84a12943f1cdf68bad7c379b3c33 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 23 Apr 2019 11:00:49 -0400 Subject: [PATCH 63/79] Update django to 2.1.8 and psycopg2 to 2.8.2 --- Pipfile | 4 +- Pipfile.lock | 142 +++++++++++++++++++++++++-------------------------- 2 files changed, 72 insertions(+), 74 deletions(-) diff --git a/Pipfile b/Pipfile index ce9d522f27..30ad470709 100644 --- a/Pipfile +++ b/Pipfile @@ -23,7 +23,7 @@ carto = "==1.4" celery = "==4.3" dj-database-url = "==0.5" dj-static = "==0.0.6" -Django = "==2.1.7" +Django = "==2.1.8" django-appconf = "==1.0.3" django_celery_beat = "==1.4" django-celery-email = "==2.0.1" @@ -63,7 +63,7 @@ GDAL = "==2.4.0" gunicorn = "==19.9" newrelic = "==2.94.0.79" Pillow = "==5.4.1" -psycopg2-binary = "==2.7.7" +psycopg2-binary = "==2.8.2" sentry-sdk = "==0.7.10" redis = "==3.2" requests = "==2.21" diff --git a/Pipfile.lock b/Pipfile.lock index 16666c8608..1756d1f8ec 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b1872df511fe7116c492e4f6b61490861452a922bd0e6b11049c49dd0c4d1906" + "sha256": "ebd440f956d33b04dc1801186a9be40fd9a9cf9158152a12858cab0c3d50d778" }, "pipfile-spec": 6, "requires": { @@ -32,10 +32,10 @@ }, "azure-common": { "hashes": [ - "sha256:5cb223c1b52deb8ff9304387201bab83950787be9ca2e8733220726740cc40d0", - "sha256:5fd62ae10b1add97d3c69af970328ec3bd869184396bcf6bfa9c7bc94d688424" + "sha256:14722caf6c3ed81d2cfdd3e448635fdc78f214dc6f17558dd1ca5b87bccc0631", + "sha256:622d9360a1b61172b4c0d1cc58f939c68402aa19ca44872ab3d224d913aa6d0c" ], - "version": "==1.1.18" + "version": "==1.1.19" }, "azure-nspkg": { "hashes": [ @@ -98,36 +98,36 @@ }, "cffi": { "hashes": [ - "sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f", - "sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11", - "sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d", - "sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891", - "sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf", - "sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c", - "sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed", - "sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b", - "sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a", - "sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585", - "sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea", - "sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f", - "sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33", - "sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145", - "sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a", - "sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3", - "sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f", - "sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd", - "sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804", - "sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d", - "sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92", - "sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f", - "sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84", - "sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb", - "sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7", - "sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7", - "sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35", - "sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889" - ], - "version": "==1.12.2" + "sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774", + "sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d", + "sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90", + "sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b", + "sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63", + "sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45", + "sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25", + "sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3", + "sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b", + "sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647", + "sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016", + "sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4", + "sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb", + "sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753", + "sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7", + "sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9", + "sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f", + "sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8", + "sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f", + "sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc", + "sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42", + "sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3", + "sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909", + "sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45", + "sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d", + "sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512", + "sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff", + "sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201" + ], + "version": "==1.12.3" }, "chardet": { "hashes": [ @@ -205,11 +205,11 @@ }, "django": { "hashes": [ - "sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade", - "sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963" + "sha256:0fd54e4f27bc3e0b7054a11e6b3a18fa53f2373f6b2df8a22e8eadfe018970a5", + "sha256:f3b28084101d516f56104856761bc247f85a2a5bbd9da39d9f6197ff461b3ee4" ], "index": "pypi", - "version": "==2.1.7" + "version": "==2.1.8" }, "django-appconf": { "hashes": [ @@ -690,39 +690,37 @@ }, "psycopg2-binary": { "hashes": [ - "sha256:19a2d1f3567b30f6c2bb3baea23f74f69d51f0c06c2e2082d0d9c28b0733a4c2", - "sha256:2b69cf4b0fa2716fd977aa4e1fd39af6110eb47b2bb30b4e5a469d8fbecfc102", - "sha256:2e952fa17ba48cbc2dc063ddeec37d7dc4ea0ef7db0ac1eda8906365a8543f31", - "sha256:348b49dd737ff74cfb5e663e18cb069b44c64f77ec0523b5794efafbfa7df0b8", - "sha256:3d72a5fdc5f00ca85160915eb9a973cf9a0ab8148f6eda40708bf672c55ac1d1", - "sha256:4957452f7868f43f32c090dadb4188e9c74a4687323c87a882e943c2bd4780c3", - "sha256:5138cec2ee1e53a671e11cc519505eb08aaaaf390c508f25b09605763d48de4b", - "sha256:587098ca4fc46c95736459d171102336af12f0d415b3b865972a79c03f06259f", - "sha256:5b79368bcdb1da4a05f931b62760bea0955ee2c81531d8e84625df2defd3f709", - "sha256:5cf43807392247d9bc99737160da32d3fa619e0bfd85ba24d1c78db205f472a4", - "sha256:676d1a80b1eebc0cacae8dd09b2fde24213173bf65650d22b038c5ed4039f392", - "sha256:6b0211ecda389101a7d1d3df2eba0cf7ffbdd2480ca6f1d2257c7bd739e84110", - "sha256:79cde4660de6f0bb523c229763bd8ad9a93ac6760b72c369cf1213955c430934", - "sha256:7aba9786ac32c2a6d5fb446002ed936b47d5e1f10c466ef7e48f66eb9f9ebe3b", - "sha256:7c8159352244e11bdd422226aa17651110b600d175220c451a9acf795e7414e0", - "sha256:945f2eedf4fc6b2432697eb90bb98cc467de5147869e57405bfc31fa0b824741", - "sha256:96b4e902cde37a7fc6ab306b3ac089a3949e6ce3d824eeca5b19dc0bedb9f6e2", - "sha256:9a7bccb1212e63f309eb9fab47b6eaef796f59850f169a25695b248ca1bf681b", - "sha256:a3bfcac727538ec11af304b5eccadbac952d4cca1a551a29b8fe554e3ad535dc", - "sha256:b19e9f1b85c5d6136f5a0549abdc55dcbd63aba18b4f10d0d063eb65ef2c68b4", - "sha256:b664011bb14ca1f2287c17185e222f2098f7b4c857961dbcf9badb28786dbbf4", - "sha256:bde7959ef012b628868d69c474ec4920252656d0800835ed999ba5e4f57e3e2e", - "sha256:cb095a0657d792c8de9f7c9a0452385a309dfb1bbbb3357d6b1e216353ade6ca", - "sha256:d16d42a1b9772152c1fe606f679b2316551f7e1a1ce273e7f808e82a136cdb3d", - "sha256:d444b1545430ffc1e7a24ce5a9be122ccd3b135a7b7e695c5862c5aff0b11159", - "sha256:d93ccc7bf409ec0a23f2ac70977507e0b8a8d8c54e5ee46109af2f0ec9e411f3", - "sha256:df6444f952ca849016902662e1a47abf4fa0678d75f92fd9dd27f20525f809cd", - "sha256:e63850d8c52ba2b502662bf3c02603175c2397a9acc756090e444ce49508d41e", - "sha256:ec43358c105794bc2b6fd34c68d27f92bea7102393c01889e93f4b6a70975728", - "sha256:f4c6926d9c03dadce7a3b378b40d2fea912c1344ef9b29869f984fb3d2a2420b" - ], - "index": "pypi", - "version": "==2.7.7" + "sha256:007ca0df127b1862fc010125bc4100b7a630efc6841047bd11afceadb4754611", + "sha256:03c49e02adf0b4d68f422fdbd98f7a7c547beb27e99a75ed02298f85cb48406a", + "sha256:0a1232cdd314e08848825edda06600455ad2a7adaa463ebfb12ece2d09f3370e", + "sha256:131c80d0958c89273d9720b9adf9df1d7600bb3120e16019a7389ab15b079af5", + "sha256:2de34cc3b775724623f86617d2601308083176a495f5b2efc2bbb0da154f483a", + "sha256:2eddc31500f73544a2a54123d4c4b249c3c711d31e64deddb0890982ea37397a", + "sha256:484f6c62bdc166ee0e5be3aa831120423bf399786d1f3b0304526c86180fbc0b", + "sha256:4c2d9369ed40b4a44a8ccd6bc3a7db6272b8314812d2d1091f95c4c836d92e06", + "sha256:70f570b5fa44413b9f30dbc053d17ef3ce6a4100147a10822f8662e58d473656", + "sha256:7a2b5b095f3bd733aab101c89c0e1a3f0dfb4ebdc26f6374805c086ffe29d5b2", + "sha256:804914a669186e2843c1f7fbe12b55aad1b36d40a28274abe6027deffad9433d", + "sha256:8520c03172da18345d012949a53617a963e0191ccb3c666f23276d5326af27b5", + "sha256:90da901fc33ea393fc644607e4a3916b509387e9339ec6ebc7bfded45b7a0ae9", + "sha256:a582416ad123291a82c300d1d872bdc4136d69ad0b41d57dc5ca3df7ef8e3088", + "sha256:ac8c5e20309f4989c296d62cac20ee456b69c41fd1bc03829e27de23b6fa9dd0", + "sha256:b2cf82f55a619879f8557fdaae5cec7a294fac815e0087c4f67026fdf5259844", + "sha256:b59d6f8cfca2983d8fdbe457bf95d2192f7b7efdb2b483bf5fa4e8981b04e8b2", + "sha256:be08168197021d669b9964bd87628fa88f910b1be31e7010901070f2540c05fd", + "sha256:be0f952f1c365061041bad16e27e224e29615d4eb1fb5b7e7760a1d3d12b90b6", + "sha256:c1c9a33e46d7c12b9c96cf2d4349d783e3127163fd96254dcd44663cf0a1d438", + "sha256:d18c89957ac57dd2a2724ecfe9a759912d776f96ecabba23acb9ecbf5c731035", + "sha256:d7e7b0ff21f39433c50397e60bf0995d078802c591ca3b8d99857ea18a7496ee", + "sha256:da0929b2bf0d1f365345e5eb940d8713c1d516312e010135b14402e2a3d2404d", + "sha256:de24a4962e361c512d3e528ded6c7480eab24c655b8ca1f0b761d3b3650d2f07", + "sha256:e45f93ff3f7dae2202248cf413a87aeb330821bf76998b3cf374eda2fc893dd7", + "sha256:f046aeae1f7a845041b8661bb7a52449202b6c5d3fb59eb4724e7ca088811904", + "sha256:f1dc2b7b2748084b890f5d05b65a47cd03188824890e9a60818721fd492249fb", + "sha256:fcbe7cf3a786572b73d2cd5f34ed452a5f5fac47c9c9d1e0642c457a148f9f88" + ], + "index": "pypi", + "version": "==2.8.2" }, "pycparser": { "hashes": [ @@ -1337,10 +1335,10 @@ }, "pdbpp": { "hashes": [ - "sha256:3936ed6c145d9bebad9f532a20796d7022fc251ad6b041adc56b67839efd5173" + "sha256:ee7eab02ecf32d92bd66b45eedb9bda152fa13f7be0dceb7050413a52cbbc4dd" ], "index": "pypi", - "version": "==0.9.15" + "version": "==0.10.0" }, "pexpect": { "hashes": [ From f980debb6d322e047a349e03477a5d7ecd9f1653 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 23 Apr 2019 14:27:37 -0400 Subject: [PATCH 64/79] 10968 fix sentry logging --- src/etools/config/sentry.py | 22 ---------------------- src/etools/config/settings/base.py | 23 +++++++++++++++++++++++ src/etools/config/settings/production.py | 3 --- 3 files changed, 23 insertions(+), 25 deletions(-) delete mode 100644 src/etools/config/sentry.py diff --git a/src/etools/config/sentry.py b/src/etools/config/sentry.py deleted file mode 100644 index a7f92dd158..0000000000 --- a/src/etools/config/sentry.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.conf import settings -from django.db import connection - -import sentry_sdk -from sentry_sdk import configure_scope -from sentry_sdk.integrations.celery import CeleryIntegration -from sentry_sdk.integrations.django import DjangoIntegration - -if hasattr(settings, 'SENTRY_DSN'): - def before_send(event, hint): - with configure_scope() as scope: - scope.set_extra("tenant", connection.tenant.schema_name) - - return event - - sentry_sdk.init( - dsn=settings.SENTRY_DSN, - # by default this is False, must be set to True so the library attaches the request data to the event - send_default_pii=True, - integrations=[DjangoIntegration(), CeleryIntegration()], - before_send=before_send, - ) diff --git a/src/etools/config/settings/base.py b/src/etools/config/settings/base.py index 744d430b5d..7435cad390 100644 --- a/src/etools/config/settings/base.py +++ b/src/etools/config/settings/base.py @@ -17,8 +17,14 @@ import os from os.path import abspath, basename, dirname, join, normpath +from django.db import connection + import dj_database_url +import sentry_sdk import yaml +from sentry_sdk import configure_scope +from sentry_sdk.integrations.celery import CeleryIntegration +from sentry_sdk.integrations.django import DjangoIntegration import etools @@ -424,6 +430,23 @@ def get_from_secrets_or_env(var_name, default=None): 'JWT_AUTH_HEADER_PREFIX': 'JWT', } +SENTRY_DSN = get_from_secrets_or_env('SENTRY_DSN') # noqa: F405 + +if SENTRY_DSN: + def before_send(event, hint): + with configure_scope() as scope: + scope.set_extra("tenant", connection.tenant.schema_name) + + return event + + sentry_sdk.init( + dsn=SENTRY_DSN, + # by default this is False, must be set to True so the library attaches the request data to the event + send_default_pii=True, + integrations=[DjangoIntegration(), CeleryIntegration()], + before_send=before_send, + ) + # eTools settings ################################ diff --git a/src/etools/config/settings/production.py b/src/etools/config/settings/production.py index a9ecbcba0d..4bfe367c90 100644 --- a/src/etools/config/settings/production.py +++ b/src/etools/config/settings/production.py @@ -5,9 +5,6 @@ from etools.config.settings.base import * # noqa: F403 -# sentry-sdk: https://github.com/getsentry/sentry-python -SENTRY_DSN = get_from_secrets_or_env('SENTRY_DSN'), # noqa: F405 - # Security settings for production ALLOWED_HOSTS = [ # Nope, regular expressions are not supported for this setting From addce56b10ba3427a04ee582f7cd2f63f59e3376 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Tue, 23 Apr 2019 15:00:47 -0400 Subject: [PATCH 65/79] country_available_for_new_countries --- .../users/management/commands/add_country.py | 3 ++ .../migrations/0010_auto_20190423_1920.py | 28 +++++++++++++++++++ src/etools/applications/users/models.py | 6 ++-- 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/etools/applications/users/migrations/0010_auto_20190423_1920.py diff --git a/src/etools/applications/users/management/commands/add_country.py b/src/etools/applications/users/management/commands/add_country.py index 9600b6161e..ac6ffdf768 100644 --- a/src/etools/applications/users/management/commands/add_country.py +++ b/src/etools/applications/users/management/commands/add_country.py @@ -1,3 +1,4 @@ +from django.contrib.auth import get_user_model from django.core.management import call_command from django.core.management.base import BaseCommand, CommandError from django.db import connection @@ -30,5 +31,7 @@ def handle(self, *args, **options): connection.set_schema(slug) call_command('loaddata', 'attachments_file_types') call_command('loaddata', 'audit_risks_blueprints') + for user in get_user_model().objects.filter(is_superuser=True): + user.profile.countries_available.add(country) except Exception as exp: raise CommandError(*exp.args) diff --git a/src/etools/applications/users/migrations/0010_auto_20190423_1920.py b/src/etools/applications/users/migrations/0010_auto_20190423_1920.py new file mode 100644 index 0000000000..292f3b3f8d --- /dev/null +++ b/src/etools/applications/users/migrations/0010_auto_20190423_1920.py @@ -0,0 +1,28 @@ +# Generated by Django 2.1.8 on 2019-04-23 19:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0009_auto_20190122_1412'), + ] + + operations = [ + migrations.AlterField( + model_name='country', + name='offices', + field=models.ManyToManyField(blank=True, related_name='offices', to='users.Office', verbose_name='Offices'), + ), + migrations.AlterField( + model_name='country', + name='threshold_tae_usd', + field=models.DecimalField(blank=True, decimal_places=4, max_digits=20, null=True, verbose_name='Threshold TAE (USD)'), + ), + migrations.AlterField( + model_name='country', + name='threshold_tre_usd', + field=models.DecimalField(blank=True, decimal_places=4, max_digits=20, null=True, verbose_name='Threshold TRE (USD)'), + ), + ] diff --git a/src/etools/applications/users/models.py b/src/etools/applications/users/models.py index 052c50c40b..96be817b30 100644 --- a/src/etools/applications/users/models.py +++ b/src/etools/applications/users/models.py @@ -109,11 +109,11 @@ class Country(TenantMixin): blank=True) # TODO: rename the related name as it's inappropriate for relating offices to countries.. should be office_countries - offices = models.ManyToManyField('Office', related_name='offices', verbose_name=_('Offices')) + offices = models.ManyToManyField('Office', related_name='offices', verbose_name=_('Offices'), blank=True) - threshold_tre_usd = models.DecimalField(max_digits=20, decimal_places=4, default=None, null=True, + threshold_tre_usd = models.DecimalField(max_digits=20, decimal_places=4, blank=True, null=True, verbose_name=_('Threshold TRE (USD)')) - threshold_tae_usd = models.DecimalField(max_digits=20, decimal_places=4, default=None, null=True, + threshold_tae_usd = models.DecimalField(max_digits=20, decimal_places=4, blank=True, null=True, verbose_name=_('Threshold TAE (USD)')) def __str__(self): From f59ebe3ca3d5099188b2358045967ee334e6e6a4 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Wed, 24 Apr 2019 09:15:57 -0400 Subject: [PATCH 66/79] Add specific date requirement check on traevl activities --- .../applications/t2f/serializers/travel.py | 4 ++++ .../t2f/tests/test_travel_details.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/etools/applications/t2f/serializers/travel.py b/src/etools/applications/t2f/serializers/travel.py index fa07974aeb..9795d893a2 100644 --- a/src/etools/applications/t2f/serializers/travel.py +++ b/src/etools/applications/t2f/serializers/travel.py @@ -106,6 +106,10 @@ def validate(self, attrs): if not attrs.get('is_primary_traveler'): if not attrs.get('primary_traveler'): raise ValidationError({'primary_traveler': serializers.Field.default_error_messages['required']}) + if not attrs.get('date'): + raise ValidationError({ + 'date': serializers.Field.default_error_messages['required'] + }) partner = attrs.get('partner', getattr(self.instance, 'partner', None)) travel_type = attrs.get('travel_type', getattr(self.instance, 'travel_type', None)) diff --git a/src/etools/applications/t2f/tests/test_travel_details.py b/src/etools/applications/t2f/tests/test_travel_details.py index 491d845b36..7c378aa389 100644 --- a/src/etools/applications/t2f/tests/test_travel_details.py +++ b/src/etools/applications/t2f/tests/test_travel_details.py @@ -283,6 +283,23 @@ def test_activity_location(self): self.assertCountEqual(response_json['activities'][0]['locations'], [location.id, location_2.id]) self.assertEqual(response_json['activities'][1]['locations'], [location_3.id]) + def test_activity_patch_no_date(self): + data = { + 'activities': [{'is_primary_traveler': True}], + 'traveler': self.traveler.pk, + } + response = self.forced_auth_req( + 'patch', + reverse('t2f:travels:details:index', args=[self.travel.pk]), + data=data, + user=self.traveler, + ) + response_json = json.loads(response.rendered_content) + self.assertEqual( + response_json, + {'activities': [{'date': ['This field is required.']}]}, + ) + def test_activity_results(self): location = LocationFactory() location_2 = LocationFactory() From a8d2c04a2fa00eec4d2ab48a6754757542822801 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Wed, 24 Apr 2019 10:13:36 -0400 Subject: [PATCH 67/79] 10666 tpm export --- src/etools/applications/tpm/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etools/applications/tpm/views.py b/src/etools/applications/tpm/views.py index 30be67df70..e81b87c45c 100644 --- a/src/etools/applications/tpm/views.py +++ b/src/etools/applications/tpm/views.py @@ -409,7 +409,7 @@ def get_obj_permission_context(self, obj): @action(detail=False, methods=['get'], url_path='activities/export', renderer_classes=(TPMActivityCSVRenderer,)) def activities_export(self, request, *args, **kwargs): tpm_activities = TPMActivity.objects.filter( - tpm_visit__in=self.get_queryset(), + tpm_visit__in=self.filter_queryset(self.get_queryset()), ).prefetch_related( 'tpm_visit', 'section', 'locations', 'cp_output' ).order_by('tpm_visit', 'id') @@ -421,7 +421,7 @@ def activities_export(self, request, *args, **kwargs): @action(detail=False, methods=['get'], url_path='locations/export', renderer_classes=(TPMLocationCSVRenderer,)) def locations_export(self, request, *args, **kwargs): tpm_locations = TPMActivity.locations.through.objects.filter( - activity__in=self.get_queryset().values_list('tpm_activities__id', flat=True), + activity__in=self.filter_queryset(self.get_queryset()).values_list('tpm_activities__id', flat=True), ).prefetch_related( 'activity', 'location', 'activity__tpmactivity__tpm_visit', 'activity__tpmactivity__section', 'activity__cp_output' From 29df3dde673afb9de9c19587d51ccca2ef202bf7 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Thu, 25 Apr 2019 09:37:23 -0400 Subject: [PATCH 68/79] Merge pull request #60 from unicef/staging Staging Merge pull request #60 from unicef/staging Staging Merge pull request #60 from unicef/staging Staging restored template --- src/etools/templates/login_base.html | 71 +++++++++++++++++++++ src/etools/templates/no_country_found.html | 45 ++----------- src/etools/templates/removed_workspace.html | 54 ++++------------ 3 files changed, 91 insertions(+), 79 deletions(-) create mode 100644 src/etools/templates/login_base.html diff --git a/src/etools/templates/login_base.html b/src/etools/templates/login_base.html new file mode 100644 index 0000000000..d88da6c9d2 --- /dev/null +++ b/src/etools/templates/login_base.html @@ -0,0 +1,71 @@ + + + + + + + + + + + UNICEF eTools + + + + +{% block extra_head %} + + + + + {% endblock %} + + + + + {% block toolbar %} + {% endblock toolbar %} + + + {% block content %} + {% endblock content %} + {% block extra_js %} + {% endblock %} + + + diff --git a/src/etools/templates/no_country_found.html b/src/etools/templates/no_country_found.html index d460ca8ad6..b17fae1c10 100644 --- a/src/etools/templates/no_country_found.html +++ b/src/etools/templates/no_country_found.html @@ -1,53 +1,22 @@ {% extends "login_base.html" %} - -{% block extra_head %} - - - - - {% endblock %} {% block toolbar %} -
    - -
    Country workspace not found on user
    -
    +
    + +
    Country workspace not found on user
    +
    {% endblock toolbar %} {% block content %}

    Hi {{ user }},

    - Your user profile does not have a country workspace associated with it... + Your user profile does not have a country workspace associated with it.
    Please contact the eTools focal point within your organization to help you gain access.

    + Go to Staging environment +

    Please Log Out to reflect any updates in the future

    {% endblock content %} diff --git a/src/etools/templates/removed_workspace.html b/src/etools/templates/removed_workspace.html index f69509cbce..d6f7c1f235 100644 --- a/src/etools/templates/removed_workspace.html +++ b/src/etools/templates/removed_workspace.html @@ -1,49 +1,21 @@ {% extends "login_base.html" %} -{% block extra_head %} - - - - -{% endblock %} {% block toolbar %} -
    - -
    +
    + +
    {% endblock toolbar %} {% block content %} -
    -

    Hi {{ user }},

    -

    - Your workspace is currently inactive +

    +

    Hi {{ user }},

    +

    + Your workspace is currently inactive +
    + Please contact the eTools focal point within your organization with any questions. +

    + Go to Staging environment
    - Please contact the eTools focal point within your organization with any questions. -

    - Go to Staging environment -
    -

    Log Out

    -
    +

    Log Out

    +
    {% endblock content %} \ No newline at end of file From f2a39c03acf2bf6f2d61df0cadbab8299bb7880a Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Fri, 26 Apr 2019 10:29:00 -0400 Subject: [PATCH 69/79] Update action point export renderer format --- src/etools/applications/action_points/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/etools/applications/action_points/views.py b/src/etools/applications/action_points/views.py index b1a0f06d71..ff809f7963 100644 --- a/src/etools/applications/action_points/views.py +++ b/src/etools/applications/action_points/views.py @@ -6,7 +6,7 @@ from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from unicef_rest_export.renderers import ExportExcelRenderer +from unicef_rest_export.renderers import ExportOpenXMLRenderer from unicef_rest_export.views import ExportMixin from unicef_restlib.pagination import DynamicPageNumberPagination from unicef_restlib.views import MultiSerializerViewSetMixin, SafeTenantViewSetMixin @@ -117,7 +117,7 @@ def list_csv_export(self, request, *args, **kwargs): 'Content-Disposition': 'attachment;filename=action_points_{}.csv'.format(timezone.now().date()) }) - @action(detail=False, methods=['get'], url_path='export/xlsx', renderer_classes=(ExportExcelRenderer,)) + @action(detail=False, methods=['get'], url_path='export/xlsx', renderer_classes=(ExportOpenXMLRenderer,)) def list_xlsx_export(self, request, *args, **kwargs): self.serializer_class = ActionPointListSerializer action_points = self.filter_queryset(self.get_queryset().prefetch_related('comments')) @@ -135,7 +135,7 @@ def single_csv_export(self, request, *args, **kwargs): ) }) - @action(detail=True, methods=['get'], url_path='export/xlsx', renderer_classes=(ExportExcelRenderer,)) + @action(detail=True, methods=['get'], url_path='export/xlsx', renderer_classes=(ExportOpenXMLRenderer,)) def single_xlsx_export(self, request, *args, **kwargs): self.serializer_class = ActionPointListSerializer serializer = self.get_serializer([self.get_object()], many=True) From 9c4ea659de5eda919f73dbe4445aee7153c99b50 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 29 Apr 2019 12:21:30 -0400 Subject: [PATCH 70/79] 10459 tpm export amend --- src/etools/applications/tpm/export/renderers.py | 13 ++++++++----- src/etools/applications/tpm/export/serializers.py | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/etools/applications/tpm/export/renderers.py b/src/etools/applications/tpm/export/renderers.py index 2c973829cc..e2c036b845 100644 --- a/src/etools/applications/tpm/export/renderers.py +++ b/src/etools/applications/tpm/export/renderers.py @@ -7,8 +7,8 @@ class TPMActivityCSVRenderer(CSVRenderer): header = ['ref', 'visit', 'visit_status', 'activity', 'section', 'cp_output', 'partner', 'intervention', 'pd_ssfa', - 'locations', 'date', 'unicef_focal_points', 'offices', 'tpm_focal_points', 'additional_information', - 'link'] + 'locations', 'date', 'unicef_focal_points', 'offices', 'tpm_focal_points', 'visit_information', + 'additional_information', 'link'] labels = { 'ref': _('Visit Ref. #'), 'visit': _('Visit'), @@ -24,6 +24,7 @@ class TPMActivityCSVRenderer(CSVRenderer): 'unicef_focal_points': _('Name of UNICEF Focal Point'), 'offices': _('Offices'), 'tpm_focal_points': _('Name of TPM Focal Point'), + 'visit_information': _('Visit Information'), 'additional_information': _('Additional Information'), 'link': _('Hyperlink'), } @@ -31,8 +32,8 @@ class TPMActivityCSVRenderer(CSVRenderer): class TPMLocationCSVRenderer(CSVRenderer): header = ['ref', 'visit', 'visit_status', 'activity', 'section', 'cp_output', 'partner', 'intervention', 'pd_ssfa', - 'location', 'date', 'unicef_focal_points', 'offices', 'tpm_focal_points', 'additional_information', - 'link'] + 'location', 'date', 'unicef_focal_points', 'offices', 'tpm_focal_points', 'visit_information', + 'additional_information', 'link'] labels = { 'ref': _('Visit Ref. #'), 'visit': _('Visit'), @@ -48,6 +49,7 @@ class TPMLocationCSVRenderer(CSVRenderer): 'unicef_focal_points': _('Name of UNICEF Focal Point'), 'offices': _('Offices'), 'tpm_focal_points': _('Name of TPM Focal Point'), + 'visit_information': _('Visit Information'), 'additional_information': _('Additional Information'), 'link': _('Hyperlink'), } @@ -81,7 +83,7 @@ class TPMVisitCSVRenderer(CSVRenderer): 'ref', 'visit', 'status', 'activities', 'sections', 'partners', 'interventions', 'pd_ssfa', 'locations', 'start_date', 'end_date', 'unicef_focal_points', - 'tpm_partner_focal_points', 'report_link', 'attachments', 'additional_information', + 'tpm_partner_focal_points', 'report_link', 'attachments', 'visit_information', 'additional_information', 'link', ] labels = { @@ -100,6 +102,7 @@ class TPMVisitCSVRenderer(CSVRenderer): 'tpm_partner_focal_points': _('Name of TPM focal Point'), 'report_link': _('Report Hyperlink'), 'attachments': _('Attachment Type - Hyperlink'), + 'visit_information': _('Visit Information'), 'additional_information': _('Additional Information'), 'link': _('Visit Hyperlink'), } diff --git a/src/etools/applications/tpm/export/serializers.py b/src/etools/applications/tpm/export/serializers.py index 325e72fb72..2a92d2677f 100644 --- a/src/etools/applications/tpm/export/serializers.py +++ b/src/etools/applications/tpm/export/serializers.py @@ -21,6 +21,7 @@ def to_representation(self, value): class TPMActivityExportSerializer(serializers.Serializer): ref = serializers.CharField(source='tpm_visit.reference_number') visit = serializers.CharField(source='tpm_visit') + visit_information = serializers.CharField(source='tpm_visit.visit_information') visit_status = serializers.CharField(source='tpm_visit.get_status_display') activity = serializers.SerializerMethodField() section = serializers.CharField() @@ -51,6 +52,7 @@ class TPMLocationExportSerializer(serializers.Serializer): intervention = serializers.CharField(source='activity.tpmactivity.intervention.reference_number', allow_null=True) pd_ssfa = serializers.CharField(source='activity.tpmactivity.intervention.title', allow_null=True) location = serializers.CharField() + visit_information = serializers.CharField(source='activity.tpmactivity.tpm_visit.visit_information') date = serializers.DateField(source='activity.tpmactivity.date', format='%d/%m/%Y') unicef_focal_points = UsersExportField(source='activity.tpmactivity.unicef_focal_points') offices = CommaSeparatedExportField(source='activity.tpmactivity.offices') From 0bb74eae97f8c6eb7be0bdd49a21eb138227ecc7 Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Wed, 1 May 2019 15:01:40 -0400 Subject: [PATCH 71/79] 10400 engagement: allow null on PDs for government partners --- .../migrations/0017_auto_20190501_1858.py | 18 ++++++++++++++++++ src/etools/applications/audit/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/etools/applications/audit/migrations/0017_auto_20190501_1858.py diff --git a/src/etools/applications/audit/migrations/0017_auto_20190501_1858.py b/src/etools/applications/audit/migrations/0017_auto_20190501_1858.py new file mode 100644 index 0000000000..9cfafa9301 --- /dev/null +++ b/src/etools/applications/audit/migrations/0017_auto_20190501_1858.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.8 on 2019-05-01 18:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('audit', '0016_auto_20190328_1528'), + ] + + operations = [ + migrations.AlterField( + model_name='engagement', + name='active_pd', + field=models.ManyToManyField(blank=True, to='partners.Intervention', verbose_name='Active PDs'), + ), + ] diff --git a/src/etools/applications/audit/models.py b/src/etools/applications/audit/models.py index 2f6a3cfbd3..6061400f8d 100644 --- a/src/etools/applications/audit/models.py +++ b/src/etools/applications/audit/models.py @@ -165,7 +165,7 @@ class Engagement(InheritedModelMixin, TimeStampedModel, models.Model): cancel_comment = models.TextField(blank=True, verbose_name=_('Cancel Comment')) - active_pd = models.ManyToManyField('partners.Intervention', verbose_name=_('Active PDs')) + active_pd = models.ManyToManyField('partners.Intervention', verbose_name=_('Active PDs'), blank=True) authorized_officers = models.ManyToManyField( PartnerStaffMember, verbose_name=_('Authorized Officers'), blank=True, related_name="engagement_authorizations" From 7d671fa07b4d476c350deb9cca183a61eabdf71d Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Fri, 26 Apr 2019 11:24:13 -0400 Subject: [PATCH 72/79] Update result framework serializer to use baseline, target from applied indicators --- src/etools/applications/reports/serializers/v2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index 085cbf4e52..dc54d16609 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -398,13 +398,13 @@ def get_indicators(self, obj): def get_target(self, obj): return "\n".join([ - x.target for x in self._ram_indicators(obj) + x.target for x in self._applied_indicators(obj) if x.target ]) def get_baseline(self, obj): return "\n".join([ - x.baseline for x in self._ram_indicators(obj) + x.baseline for x in self._applied_indicators(obj) if x.baseline ]) From 9a440dc1fdd861a11ecac5d7d8adbfffd9f15503 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Fri, 26 Apr 2019 12:09:38 -0400 Subject: [PATCH 73/79] Correct ordering of columns And graceful handling of baseline and target data --- src/etools/applications/reports/serializers/v2.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index dc54d16609..88e6636d54 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -372,10 +372,10 @@ class Meta: fields = ( "result", "indicators", - "target", + "locations", "baseline", + "target", "means_of_verification", - "locations", ) def get_result(self, obj): @@ -398,13 +398,13 @@ def get_indicators(self, obj): def get_target(self, obj): return "\n".join([ - x.target for x in self._applied_indicators(obj) + str(x.target) for x in self._applied_indicators(obj) if x.target ]) def get_baseline(self, obj): return "\n".join([ - x.baseline for x in self._applied_indicators(obj) + str(x.baseline) for x in self._applied_indicators(obj) if x.baseline ]) From 7f15426973d35b06854518871475d0b173e2fd86 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Fri, 26 Apr 2019 12:44:22 -0400 Subject: [PATCH 74/79] Separate rows for applied and result link records in framework --- .../applications/reports/serializers/v2.py | 56 ++++++++----------- src/etools/applications/reports/views/v2.py | 9 ++- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index 88e6636d54..b5ceb18cf3 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -359,7 +359,7 @@ class Meta: fields = "__all__" -class ResultFrameworkSerializer(serializers.ModelSerializer): +class ResultFrameworkSerializer(serializers.Serializer): result = serializers.SerializerMethodField(label=_("Result")) indicators = serializers.SerializerMethodField() target = serializers.SerializerMethodField() @@ -368,7 +368,6 @@ class ResultFrameworkSerializer(serializers.ModelSerializer): locations = serializers.SerializerMethodField() class Meta: - model = InterventionResultLink fields = ( "result", "indicators", @@ -379,48 +378,37 @@ class Meta: ) def get_result(self, obj): - return obj.cp_output - - def _applied_indicators(self, obj): - indicators = [] - for l in obj.ll_results.all(): - indicators += l.applied_indicators.all() - return indicators - - def _ram_indicators(self, obj): - return obj.ram_indicators.all() + if hasattr(obj, "cp_output"): + return obj.cp_output + return obj.label def get_indicators(self, obj): - return "\n".join([ - i.name for i in self._ram_indicators(obj) - if i.name - ]) + if hasattr(obj, "ram_indicators"): + return "\n".join([ + i.name for i in obj.ram_indicators.all() + if i.name + ]) + return obj.measurement_specifications def get_target(self, obj): - return "\n".join([ - str(x.target) for x in self._applied_indicators(obj) - if x.target - ]) + if hasattr(obj, "target"): + return obj.target_display + return "" def get_baseline(self, obj): - return "\n".join([ - str(x.baseline) for x in self._applied_indicators(obj) - if x.baseline - ]) + if hasattr(obj, "baseline"): + return obj.baseline_display + return "" def get_means_of_verification(self, obj): - return "\n".join( - [ - x.means_of_verification for x in self._applied_indicators(obj) - if x.means_of_verification - ] - ) + if hasattr(obj, "means_of_verification"): + return obj.means_of_verification + return "" def get_locations(self, obj): - locations = [] - for x in self._applied_indicators(obj): - locations += [l.name for l in x.locations.all()] - return "\n".join(set(locations)) + if hasattr(obj, "locations"): + return "\n".join(set([l.name for l in obj.locations.all()])) + return "" class ResultFrameworkExportSerializer(ExportSerializer): diff --git a/src/etools/applications/reports/views/v2.py b/src/etools/applications/reports/views/v2.py index a3a38f2aa0..df211c667a 100644 --- a/src/etools/applications/reports/views/v2.py +++ b/src/etools/applications/reports/views/v2.py @@ -466,7 +466,12 @@ def get_queryset(self, format=None): qs = InterventionResultLink.objects.filter( intervention=self.kwargs.get("pk") ) - return qs + data = [] + for result_link in qs: + data.append(result_link) + for l in result_link.ll_results.all(): + data += l.applied_indicators.all() + return data def finalize_response(self, request, response, *args, **kwargs): response = super().finalize_response( @@ -476,7 +481,7 @@ def finalize_response(self, request, response, *args, **kwargs): **kwargs, ) if response.accepted_renderer.format == "docx_table": - intervention = self.get_queryset().first().intervention + intervention = self.get_queryset()[0].intervention response["content-disposition"] = "attachment; filename={}_results.docx".format( intervention.reference_number ) From b174d2e11d7e981ae13ff59594e2d85ede767cab Mon Sep 17 00:00:00 2001 From: Domenico Date: Fri, 26 Apr 2019 13:03:58 -0400 Subject: [PATCH 75/79] Update v2.py --- src/etools/applications/reports/serializers/v2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index b5ceb18cf3..bff6ac0d3f 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -5,7 +5,7 @@ from rest_framework.exceptions import ValidationError from unicef_rest_export.serializers import ExportSerializer -from etools.applications.partners.models import Intervention, InterventionResultLink +from etools.applications.partners.models import Intervention from etools.applications.reports.models import ( AppliedIndicator, Disaggregation, From 027fa476a4b5d26752f264e2ffd7e8da9775fba1 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Mon, 29 Apr 2019 09:25:42 -0400 Subject: [PATCH 76/79] Correct name used in export --- src/etools/applications/reports/serializers/v2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index bff6ac0d3f..90f8fef57a 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -380,7 +380,7 @@ class Meta: def get_result(self, obj): if hasattr(obj, "cp_output"): return obj.cp_output - return obj.label + return obj.lower_result.name def get_indicators(self, obj): if hasattr(obj, "ram_indicators"): From 90e4687c7c26c76e03cdd090d2b1d9853e72af00 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Mon, 29 Apr 2019 09:34:29 -0400 Subject: [PATCH 77/79] Use indicator title in export --- src/etools/applications/reports/serializers/v2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index 90f8fef57a..39fdf1c932 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -388,7 +388,7 @@ def get_indicators(self, obj): i.name for i in obj.ram_indicators.all() if i.name ]) - return obj.measurement_specifications + return obj.indicator.title def get_target(self, obj): if hasattr(obj, "target"): From 88d28f2f7a5278efad12a995f15d03706c319b98 Mon Sep 17 00:00:00 2001 From: Greg Reinbach Date: Tue, 30 Apr 2019 13:31:52 -0400 Subject: [PATCH 78/79] Add custom renderer for ResultFrameworkView --- src/etools/applications/reports/renderers.py | 73 +++++++++++++++++++ .../applications/reports/serializers/v2.py | 2 +- .../applications/reports/tests/test_views.py | 4 + src/etools/applications/reports/views/v2.py | 2 + 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/etools/applications/reports/renderers.py diff --git a/src/etools/applications/reports/renderers.py b/src/etools/applications/reports/renderers.py new file mode 100644 index 0000000000..c7e77f7fa3 --- /dev/null +++ b/src/etools/applications/reports/renderers.py @@ -0,0 +1,73 @@ +from io import BytesIO + +from docx import Document +from docx.oxml import parse_xml +from docx.oxml.ns import nsdecls +from unicef_rest_export.renderers import ExportDocxTableRenderer + +from etools.applications.reports.models import LowerResult + + +class ResultFrameworkRenderer(ExportDocxTableRenderer): + def export_set(self, formatted, headers): + stream = BytesIO() + doc = Document() + + if not headers: + doc.add_paragraph("No data provided.") + else: + table = doc.add_table( + rows=1, + cols=len(headers), + style="Table Grid", + ) + + # set heading text + header_cells = table.rows[0].cells + for i, heading in enumerate(headers): + header_cells[i].text = heading + shader = parse_xml( + r''.format(nsdecls('w')) + ) + header_cells[i]._tc.get_or_add_tcPr().append(shader) + + # set data + record_previous = None + row_previous = None + is_lowerresult = False + for record in formatted: + row = table.add_row().cells + for i, key in enumerate(record): + if is_lowerresult or isinstance(record[key], LowerResult): + is_lowerresult = True + if key == "Result": + result_previous = record_previous[key] + if isinstance(result_previous, LowerResult): + if result_previous.pk == record[key].pk: + # merge cells + row_previous[i].merge(row[i]) + continue + row[i].text = str(record[key].name) + else: + row[i].text = str(record[key]) + else: + is_lowerresult = False + if i < 2: + shader = parse_xml( + r''.format( + nsdecls('w') + ) + ) + else: + shader = parse_xml( + r''.format( + nsdecls('w') + ) + ) + row[i]._tc.get_or_add_tcPr().append(shader) + row[i].text = str(record[key]) + record_previous = record + row_previous = row + + doc.save(stream) + return stream.getvalue() diff --git a/src/etools/applications/reports/serializers/v2.py b/src/etools/applications/reports/serializers/v2.py index 39fdf1c932..95a74cd39c 100644 --- a/src/etools/applications/reports/serializers/v2.py +++ b/src/etools/applications/reports/serializers/v2.py @@ -380,7 +380,7 @@ class Meta: def get_result(self, obj): if hasattr(obj, "cp_output"): return obj.cp_output - return obj.lower_result.name + return obj.lower_result def get_indicators(self, obj): if hasattr(obj, "ram_indicators"): diff --git a/src/etools/applications/reports/tests/test_views.py b/src/etools/applications/reports/tests/test_views.py index 505032aa14..b24cd58466 100644 --- a/src/etools/applications/reports/tests/test_views.py +++ b/src/etools/applications/reports/tests/test_views.py @@ -1090,6 +1090,10 @@ def setUpTestData(cls): indicator=cls.indicator, lower_result=cls.lower_result ) + cls.applied_another = AppliedIndicatorFactory( + indicator=IndicatorBlueprintFactory(), + lower_result=cls.lower_result + ) def test_get(self): response = self.forced_auth_req( diff --git a/src/etools/applications/reports/views/v2.py b/src/etools/applications/reports/views/v2.py index df211c667a..fc89fb24df 100644 --- a/src/etools/applications/reports/views/v2.py +++ b/src/etools/applications/reports/views/v2.py @@ -40,6 +40,7 @@ SpecialReportingRequirement, ) from etools.applications.reports.permissions import PMEPermission +from etools.applications.reports.renderers import ResultFrameworkRenderer from etools.applications.reports.serializers.exports import ( AppliedIndicatorExportFlatSerializer, AppliedIndicatorExportSerializer, @@ -461,6 +462,7 @@ class ResultFrameworkView(ExportView): serializer_class = ResultFrameworkSerializer export_serializer_class = ResultFrameworkExportSerializer permission_classes = (PartnershipManagerPermission, ) + renderer_classes = (ResultFrameworkRenderer, ) def get_queryset(self, format=None): qs = InterventionResultLink.objects.filter( From d52d63411fb63729e50b1fc06341ebc8b372137d Mon Sep 17 00:00:00 2001 From: Domenico DiNicola Date: Mon, 29 Apr 2019 11:20:57 -0400 Subject: [PATCH 79/79] 11606 allow to change locations in the admin panel --- src/etools/applications/environment/admin.py | 2 +- src/etools/applications/partners/admin.py | 4 +++- src/etools/applications/reports/admin.py | 4 ++++ src/etools/applications/t2f/admin.py | 7 +++++++ src/etools/applications/tpm/admin.py | 8 ++++++++ src/etools/applications/tpm/tpmpartners/admin.py | 1 + 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/etools/applications/environment/admin.py b/src/etools/applications/environment/admin.py index 5cd2d39eb4..c9f91af12f 100644 --- a/src/etools/applications/environment/admin.py +++ b/src/etools/applications/environment/admin.py @@ -8,7 +8,7 @@ class TenantFlagAdmin(FlagAdmin): - filter_horizontal = ['countries'] + filter_horizontal = ['countries', 'groups'] class TenantSwitchAdmin(SwitchAdmin): diff --git a/src/etools/applications/partners/admin.py b/src/etools/applications/partners/admin.py index a0329afe79..c6250ca1c9 100644 --- a/src/etools/applications/partners/admin.py +++ b/src/etools/applications/partners/admin.py @@ -281,7 +281,8 @@ class InterventionAdmin( filter_horizontal = ( 'sections', 'unicef_focal_points', - 'partner_focal_points' + 'partner_focal_points', + 'flat_locations' ) fieldsets = ( (_('Intervention Details'), { @@ -297,6 +298,7 @@ class InterventionAdmin( 'country_programme', 'submission_date', 'sections', + 'flat_locations', 'metadata', ) }), diff --git a/src/etools/applications/reports/admin.py b/src/etools/applications/reports/admin.py index edf942ff7c..3f13d07c53 100644 --- a/src/etools/applications/reports/admin.py +++ b/src/etools/applications/reports/admin.py @@ -181,6 +181,10 @@ class AppliedIndicatorAdmin(admin.ModelAdmin): 'lower_result', 'context_code' ) + filter_horizontal = ( + 'disaggregation', + 'locations' + ) class DisaggregationAdmin(admin.ModelAdmin): diff --git a/src/etools/applications/t2f/admin.py b/src/etools/applications/t2f/admin.py index 7cae4838e0..251c0f7f45 100644 --- a/src/etools/applications/t2f/admin.py +++ b/src/etools/applications/t2f/admin.py @@ -54,6 +54,10 @@ class TravelActivityAdmin(admin.ModelAdmin): raw_id_fields = ( 'primary_traveler', ) + filter_horizontal = ( + 'locations', + 'travels', + ) @admin.register(models.ItineraryItem) @@ -75,6 +79,9 @@ class ItineraryItemAdmin(admin.ModelAdmin): 'origin', 'destination' ) + filter_horizontal = ( + 'airlines', + ) @admin.register(models.TravelAttachment) diff --git a/src/etools/applications/tpm/admin.py b/src/etools/applications/tpm/admin.py index 3fc12e4907..474b6e6a07 100644 --- a/src/etools/applications/tpm/admin.py +++ b/src/etools/applications/tpm/admin.py @@ -13,6 +13,11 @@ class TPMActivityInline(admin.ModelAdmin): 'tpm_visit__author__username', 'tpm_visit__tpm_partner__name', ) + filter_horizontal = ( + 'locations', + 'unicef_focal_points', + 'offices', + ) @admin.register(models.TPMVisit) @@ -22,6 +27,9 @@ class TPMVisitAdmin(AdminListMixin, admin.ModelAdmin): list_filter = ( 'status', ) + filter_horizontal = ( + 'tpm_partner_focal_points', + ) def __init__(self, model, admin_site): super().__init__(model, admin_site) diff --git a/src/etools/applications/tpm/tpmpartners/admin.py b/src/etools/applications/tpm/tpmpartners/admin.py index 3697c5803a..cc6c8d5832 100644 --- a/src/etools/applications/tpm/tpmpartners/admin.py +++ b/src/etools/applications/tpm/tpmpartners/admin.py @@ -20,6 +20,7 @@ class TPMPartnerAdmin(admin.ModelAdmin): inlines = [ TPMPartnerStaffMemberInlineAdmin, ] + filter_horizontal = ('countries', ) def countries_list(self, obj): return ', '.join(obj.countries.values_list('name', flat=True))