Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Code With Us QaQc Dashboard Dec 2023 #2097

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions app/backend/wells/serializers_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,3 +475,69 @@ class WellDetailSerializer(WellDetailSerializerV1):

class Meta(WellDetailSerializerV1.Meta):
ref_name = "well_detail_v2"


class MislocatedWellsSerializer(serializers.ModelSerializer):

class Meta:
model = Well
fields = [
'well_tag_number',
'identification_plate_number',
'street_address',
'city',
'geom', # Geographical location of the well
'work_start_date',
'created_date',
'created_by',
'notes',
]


class CrossReferencingSerializer(serializers.ModelSerializer):
work_start_date = serializers.DateField(read_only=True)
work_end_date = serializers.DateField(read_only=True)

class Meta:
model = Well
fields = [
'well_tag_number',
'well_status',
'work_start_date',
'work_end_date',
'create_user',
'create_date',
'update_date',
'update_user',
# 'natural_resource_region',
'internal_comments',
]


class RecordComplianceSerializer(serializers.ModelSerializer):
work_start_date = serializers.DateField(read_only=True)
work_end_date = serializers.DateField(read_only=True)

class Meta:
model = Well
fields = [
'well_tag_number',
'identification_plate_number',
'well_class',
'latitude',
'longitude',
'finished_well_depth',
'diameter',
'surface_seal_depth',
'surface_seal_thickness',
'aquifer_lithology',
'well_status',
'work_start_date',
'work_end_date',
'person_responsible',
'company_of_person_responsible',
'create_date',
'create_user',
# 'natural_resource_region',
'internal_comments'
]
AlexZorkin marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 12 additions & 1 deletion app/backend/wells/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,16 @@

# Well Licensing status endpoint from e-Licensing.
url(api_path_prefix() + r'/wells/licensing$',
views.well_licensing, name='well-licensing')
views.well_licensing, name='well-licensing'),

# QA/QC Endpoints
url(api_path_prefix() + r'/qaqc/crossreferencing$',
never_cache(views_v2.CrossReferencingListView.as_view()), name='qaqc-cross-referencing'),

url(api_path_prefix() + r'/qaqc/mislocatedwells$',
never_cache(views_v2.MislocatedWellsListView.as_view()), name='qaqc-mislocated-wells'),

url(api_path_prefix() + r'/qaqc/recordcompliance$',
never_cache(views_v2.RecordComplianceListView.as_view()), name='qaqc-record-compliance'),

]
155 changes: 152 additions & 3 deletions app/backend/wells/views_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.geos import GEOSException, GEOSGeometry
from django.contrib.gis.gdal import GDALException
from django.db.models import FloatField
from django.db.models.functions import Cast
from django.db.models import FloatField, Q, Case, When, F, Value, DateField

from rest_framework import status, filters
from rest_framework.exceptions import PermissionDenied, NotFound, ValidationError
Expand All @@ -38,7 +38,8 @@
GeometryFilterBackend,
RadiusFilterBackend
)
from wells.models import Well, WellAttachment
from wells.models import Well, WellAttachment, \
WELL_STATUS_CODE_ALTERATION, WELL_STATUS_CODE_CONSTRUCTION, WELL_STATUS_CODE_DECOMMISSION
from wells.serializers_v2 import (
WellLocationSerializerV2,
WellVerticalAquiferExtentSerializerV2,
Expand All @@ -47,7 +48,10 @@
WellExportSerializerV2,
WellExportAdminSerializerV2,
WellSubsurfaceSerializer,
WellDetailSerializer
WellDetailSerializer,
MislocatedWellsSerializer,
CrossReferencingSerializer,
RecordComplianceSerializer
)
from wells.permissions import WellsEditOrReadOnly
from wells.renderers import WellListCSVRenderer, WellListExcelRenderer
Expand Down Expand Up @@ -573,3 +577,148 @@ class WellDetail(WellDetailV1):
This view is open to all, and has no permissions.
"""
serializer_class = WellDetailSerializer


class MislocatedWellsListView(ListAPIView):
"""
API view to retrieve mislocated wells.
"""
serializer_class = MislocatedWellsSerializer

def get_queryset(self):
"""
This view should return a list of all mislocated wells
for the currently authenticated user.
"""
return Well.objects.filter(Q(geom__isnull=True) | Q(incorrect_location_flag=True))

def get(self, request, *args, **kwargs):
"""
Optionally restricts the returned mislocated wells to a given user,
by filtering against a `username` query parameter in the URL.
"""
queryset = self.get_queryset()

serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)


class RecordComplianceListView(ListAPIView):
serializer_class = RecordComplianceSerializer

swagger_schema = None
permission_classes = (WellsEditOrReadOnly,)
model = Well
pagination_class = APILimitOffsetPagination

# Allow searching on name fields, names of related companies, etc.
filter_backends = (WellListFilterBackend, BoundingBoxFilterBackend,
filters.SearchFilter, WellListOrderingFilter, GeometryFilterBackend)
ordering = ('well_tag_number',)

def get_queryset(self):
"""
Retrieves wells that are missing information in any of the specified fields.
"""
queryset = Well.objects.all()

queryset = Well.objects.select_related('well_status').annotate(
work_start_date=Case(
When(well_status__well_status_code=WELL_STATUS_CODE_CONSTRUCTION, then=F('construction_start_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_ALTERATION, then=F('alteration_start_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_DECOMMISSION, then=F('decommission_start_date')),
default=Value(None),
output_field=DateField()
),
work_end_date=Case(
When(well_status__well_status_code=WELL_STATUS_CODE_CONSTRUCTION, then=F('construction_end_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_ALTERATION, then=F('alteration_end_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_DECOMMISSION, then=F('decommission_end_date')),
default=Value(None),
output_field=DateField()
)
)

# Filtering for records missing any of the specified fields
missing_info_filter = (
Q(well_tag_number__isnull=True) |
Q(identification_plate_number__isnull=True) |
Q(well_class__isnull=True) |
Q(geom__isnull=True) | # for latitude and longitude
Q(finished_well_depth__isnull=True) |
Q(surface_seal_depth__isnull=True) |
Q(surface_seal_thickness__isnull=True) |
Q(aquifer_lithology__isnull=True) |
Q(well_status__isnull=True) |
Q(work_start_date__isnull=True) |
Q(work_end_date__isnull=True) |
Q(person_responsible__isnull=True) |
Q(company_of_person_responsible__isnull=True) |
Q(create_date__isnull=True) |
Q(create_user__isnull=True)
# Q(natural_resource_region__isnull=True) |
# Q(internal_comments__isnull=True)
)

queryset = queryset.filter(missing_info_filter)

# Additional filtering based on query parameters
work_start_date = self.request.query_params.get('work_start_date')
work_end_date = self.request.query_params.get('work_end_date')

if work_start_date:
queryset = queryset.filter(work_start_date__gte=work_start_date)
if work_end_date:
queryset = queryset.filter(work_end_date__lte=work_end_date)

return queryset


class CrossReferencingListView(ListAPIView):
serializer_class = CrossReferencingSerializer

swagger_schema = None
permission_classes = (WellsEditOrReadOnly,)
model = Well
pagination_class = APILimitOffsetPagination

# Allow searching on name fields, names of related companies, etc.
filter_backends = (WellListFilterBackend, BoundingBoxFilterBackend,
filters.SearchFilter, WellListOrderingFilter, GeometryFilterBackend)
ordering = ('well_tag_number',)

def get_queryset(self):
"""
Optionally restricts the returned wells to those that have certain keywords like 'x-ref'd' or 'cross-ref'
in their internal_comments.
"""
queryset = Well.objects.all()

queryset = Well.objects.select_related('well_status').annotate(
work_start_date=Case(
When(well_status__well_status_code=WELL_STATUS_CODE_CONSTRUCTION, then=F('construction_start_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_ALTERATION, then=F('alteration_start_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_DECOMMISSION, then=F('decommission_start_date')),
default=Value(None),
output_field=DateField()
),
work_end_date=Case(
When(well_status__well_status_code=WELL_STATUS_CODE_CONSTRUCTION, then=F('construction_end_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_ALTERATION, then=F('alteration_end_date')),
When(well_status__well_status_code=WELL_STATUS_CODE_DECOMMISSION, then=F('decommission_end_date')),
default=Value(None),
output_field=DateField()
)
)

search_terms = ["x-ref'd", "x-ref", "cross-ref"]

# Build a Q object for the search terms
comments_query = Q()
for term in search_terms:
comments_query |= Q(internal_comments__icontains=term)

# Filter the queryset based on the search terms
queryset = queryset.filter(comments_query)

return queryset
AlexZorkin marked this conversation as resolved.
Show resolved Hide resolved
Loading