Skip to content

Commit

Permalink
Merge pull request #297 from dimagi/pkv/deliver-status-view-update
Browse files Browse the repository at this point in the history
Updated Deliver Status View
  • Loading branch information
pxwxnvermx committed May 9, 2024
2 parents 271e8b7 + e69a70e commit 63c43cd
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 141 deletions.
103 changes: 45 additions & 58 deletions commcare_connect/opportunity/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db.models import Case, Count, F, Max, Min, Q, Sum, When
from django.db.models import Case, Count, F, Max, Min, Q, Sum, Value, When

from commcare_connect.opportunity.models import Opportunity, OpportunityAccess, VisitValidationStatus
from commcare_connect.opportunity.models import CompletedWorkStatus, Opportunity, OpportunityAccess


def get_annotated_opportunity_access(opportunity: Opportunity):
Expand Down Expand Up @@ -43,65 +43,52 @@ def get_annotated_opportunity_access(opportunity: Opportunity):


def get_annotated_opportunity_access_deliver_status(opportunity: Opportunity):
access_objects = (
OpportunityAccess.objects.filter(opportunity=opportunity)
.select_related("user")
.annotate(
visits_pending=Count(
"user__uservisit",
filter=Q(
user__uservisit__opportunity=opportunity,
user__uservisit__status=VisitValidationStatus.pending,
),
distinct=True,
),
visits_approved=Count(
"user__uservisit",
filter=Q(
user__uservisit__opportunity=opportunity,
user__uservisit__status=VisitValidationStatus.approved,
),
distinct=True,
),
visits_rejected=Count(
"user__uservisit",
filter=Q(
user__uservisit__opportunity=opportunity,
user__uservisit__status=VisitValidationStatus.rejected,
access_objects = []
for payment_unit in opportunity.paymentunit_set.all():
access_objects += (
OpportunityAccess.objects.filter(opportunity=opportunity)
.select_related("user")
.annotate(
payment_unit=Value(payment_unit.name),
pending=Count(
"completedwork",
filter=Q(
completedwork__opportunity_access_id=F("pk"),
completedwork__payment_unit=payment_unit,
completedwork__status=CompletedWorkStatus.pending,
),
distinct=True,
),
distinct=True,
),
visits_over_limit=Count(
"user__uservisit",
filter=Q(
user__uservisit__opportunity=opportunity,
user__uservisit__status=VisitValidationStatus.over_limit,
approved=Count(
"completedwork",
filter=Q(
completedwork__opportunity_access_id=F("pk"),
completedwork__payment_unit=payment_unit,
completedwork__status=CompletedWorkStatus.approved,
),
distinct=True,
),
distinct=True,
),
visits_duplicate=Count(
"user__uservisit",
filter=Q(
user__uservisit__opportunity=opportunity,
user__uservisit__status=VisitValidationStatus.duplicate,
rejected=Count(
"completedwork",
filter=Q(
completedwork__opportunity_access_id=F("pk"),
completedwork__payment_unit=payment_unit,
completedwork__status=CompletedWorkStatus.rejected,
),
distinct=True,
),
distinct=True,
),
visits_trial=Count(
"user__uservisit",
filter=Q(
user__uservisit__opportunity=opportunity,
user__uservisit__status=VisitValidationStatus.trial,
over_limit=Count(
"completedwork",
filter=Q(
completedwork__opportunity_access_id=F("pk"),
completedwork__payment_unit=payment_unit,
completedwork__status=CompletedWorkStatus.over_limit,
),
distinct=True,
),
distinct=True,
),
visits_completed=F("visits_approved")
+ F("visits_rejected")
+ F("visits_over_limit")
+ F("visits_pending")
+ F("visits_duplicate")
+ F("visits_trial"),
completed=F("approved") + F("rejected") + F("pending") + F("over_limit"),
)
.order_by("user__name")
)
.order_by("user__name")
)
access_objects.sort(key=lambda a: a.user.name)
return access_objects
30 changes: 14 additions & 16 deletions commcare_connect/opportunity/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,13 @@ def render_deliver_units(self, record):
class DeliverStatusTable(tables.Table):
display_name = columns.Column("Name of the User")
username = columns.Column(accessor="user__username", visible=False)
visits_completed = columns.Column("Completed Visits")
visits_approved = columns.Column("Approved Visits")
visits_pending = columns.Column("Pending Visits")
visits_rejected = columns.Column("Rejected Visits")
visits_over_limit = columns.Column("Over Limit Visits")
visits_duplicate = columns.Column("Duplicate Visits")
visits_trial = columns.Column("Trial Visits")
payment_unit = columns.Column("Name of Payment Unit")
completed = columns.Column("Delivered")
pending = columns.Column("Pending")
approved = columns.Column("Approved")
rejected = columns.Column("Rejected")
over_limit = columns.Column("Over Limit")

details = columns.LinkColumn(
"opportunity:user_visits_list",
verbose_name="",
Expand All @@ -212,19 +212,17 @@ class DeliverStatusTable(tables.Table):

class Meta:
model = OpportunityAccess
fields = ("last_visit_date",)
orderable = False
fields = ("display_name",)
sequence = (
"display_name",
"username",
"visits_completed",
"visits_approved",
"visits_pending",
"visits_rejected",
"visits_over_limit",
"visits_duplicate",
"visits_trial",
"last_visit_date",
"payment_unit",
"completed",
"pending",
"approved",
"rejected",
"over_limit",
)

def render_last_visit_date(self, record, value):
Expand Down
37 changes: 1 addition & 36 deletions commcare_connect/opportunity/tests/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@
from django.utils.timezone import now
from tablib import Dataset

from commcare_connect.opportunity.export import (
export_deliver_status_table,
export_user_status_table,
export_user_visit_data,
get_flattened_dataset,
)
from commcare_connect.opportunity.export import export_user_status_table, export_user_visit_data, get_flattened_dataset
from commcare_connect.opportunity.forms import DateRanges
from commcare_connect.opportunity.models import Opportunity, UserVisit
from commcare_connect.opportunity.tests.factories import (
Expand Down Expand Up @@ -198,33 +193,3 @@ def test_export_user_status_table_data(opportunity: Opportunity):
dataset = export_user_status_table(opportunity)
prepared_test_dataset = _get_prepared_dataset_for_user_status_test(rows)
assert prepared_test_dataset.export("csv") == dataset.export("csv")


@pytest.mark.django_db
def test_export_deliver_status_data(opportunity: Opportunity):
mobile_users = MobileUserFactory.create_batch(5)
rows = []
for mobile_user in sorted(mobile_users, key=lambda x: x.name):
access = OpportunityAccessFactory(opportunity=opportunity, user=mobile_user, accepted=True)
user_visits = UserVisitFactory.create_batch(20, opportunity=opportunity, user=mobile_user)
user_visits_count = {"approved": 0, "pending": 0, "rejected": 0, "over_limit": 0, "duplicate": 0, "trial": 0}
for user_visit in user_visits:
user_visits_count[user_visit.status.value] += 1
rows.append(
(
mobile_user.name,
mobile_user.username,
len(user_visits),
user_visits_count.get("approved", 0),
user_visits_count.get("pending", 0),
user_visits_count.get("rejected", 0),
user_visits_count.get("over_limit", 0),
user_visits_count.get("duplicate", 0),
user_visits_count.get("trial", 0),
access.last_visit_date.replace(tzinfo=None),
)
)

dataset = export_deliver_status_table(opportunity)
prepared_test_dataset = _get_dataset(data=rows, headers=dataset.headers)
assert prepared_test_dataset.export("csv") == dataset.export("csv")
62 changes: 31 additions & 31 deletions commcare_connect/opportunity/tests/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import pytest

from commcare_connect.opportunity.helpers import get_annotated_opportunity_access_deliver_status
from commcare_connect.opportunity.models import Opportunity, UserVisit
from commcare_connect.opportunity.tests.factories import OpportunityAccessFactory, UserVisitFactory
from commcare_connect.opportunity.models import Opportunity
from commcare_connect.opportunity.tests.factories import (
CompletedWorkFactory,
OpportunityAccessFactory,
PaymentUnitFactory,
)
from commcare_connect.users.tests.factories import MobileUserFactory


Expand All @@ -16,37 +20,36 @@ def test_deliver_status_query_no_visits(opportunity: Opportunity):
usernames = {user.username for user in mobile_users}
for access in access_objects:
assert access.user.username in usernames
assert access.visits_approved == 0
assert access.visits_rejected == 0
assert access.visits_pending == 0
assert access.visits_over_limit == 0
assert access.visits_completed == 0
assert access.visits_duplicate == 0
assert access.approved == 0
assert access.rejected == 0
assert access.pending == 0
assert access.completed == 0


@pytest.mark.django_db
def test_deliver_status_query(opportunity: Opportunity):
mobile_users = MobileUserFactory.create_batch(5)
user_visit_counts = {}
completed_work_counts = {}
payment_units = PaymentUnitFactory.create_batch(2, opportunity=opportunity)
for mobile_user in mobile_users:
OpportunityAccessFactory(opportunity=opportunity, user=mobile_user, accepted=True)
user_visits = UserVisitFactory.create_batch(20, opportunity=opportunity, user=mobile_user)
count_by_status = dict(approved=0, pending=0, rejected=0, over_limit=0, completed=0, duplicate=0, trial=0)
for user_visit in user_visits:
count_by_status[user_visit.status.value] += 1
count_by_status["completed"] = len(user_visits)
user_visit_counts[mobile_user.username] = count_by_status
access = OpportunityAccessFactory(opportunity=opportunity, user=mobile_user, accepted=True)
for pu in payment_units:
count_by_status = dict(approved=0, pending=0, rejected=0, completed=0, over_limit=0)
completed_works = CompletedWorkFactory.create_batch(20, opportunity_access=access, payment_unit=pu)
for cw in completed_works:
count_by_status[cw.status.value] += 1
count_by_status["completed"] = len(completed_works)
completed_work_counts[(mobile_user.username, pu.name)] = count_by_status

access_objects = get_annotated_opportunity_access_deliver_status(opportunity)
for access in access_objects:
username = access.user.username
assert username in user_visit_counts
assert user_visit_counts[username]["approved"] == access.visits_approved
assert user_visit_counts[username]["rejected"] == access.visits_rejected
assert user_visit_counts[username]["pending"] == access.visits_pending
assert user_visit_counts[username]["over_limit"] == access.visits_over_limit
assert user_visit_counts[username]["completed"] == access.visits_completed
assert user_visit_counts[username]["duplicate"] == access.visits_duplicate
assert (username, access.payment_unit) in completed_work_counts
assert completed_work_counts[(username, access.payment_unit)]["approved"] == access.approved
assert completed_work_counts[(username, access.payment_unit)]["rejected"] == access.rejected
assert completed_work_counts[(username, access.payment_unit)]["pending"] == access.pending
assert completed_work_counts[(username, access.payment_unit)]["completed"] == access.completed
assert completed_work_counts[(username, access.payment_unit)]["over_limit"] == access.over_limit


@pytest.mark.django_db
Expand All @@ -56,15 +59,12 @@ def test_deliver_status_query_visits_another_opportunity(opportunity: Opportunit
mobile_users = list(MobileUserFactory.create_batch(5))
for mobile_user in mobile_users:
OpportunityAccessFactory(opportunity=opportunity, user=mobile_user, accepted=True)
UserVisitFactory.create_batch(5, user=mobile_user)
CompletedWorkFactory.create_batch(5)
access_objects = get_annotated_opportunity_access_deliver_status(opportunity)
usernames = {user.username for user in mobile_users}
for access in access_objects:
assert UserVisit.objects.filter(user=mobile_user).count() == 5
assert access.user.username in usernames
assert access.visits_approved == 0
assert access.visits_rejected == 0
assert access.visits_pending == 0
assert access.visits_over_limit == 0
assert access.visits_completed == 0
assert access.visits_duplicate == 0
assert access.approved == 0
assert access.rejected == 0
assert access.pending == 0
assert access.completed == 0

0 comments on commit 63c43cd

Please sign in to comment.