Skip to content

Commit

Permalink
Separated cases with balance due in summary (#1531)
Browse files Browse the repository at this point in the history
Cases with balance due have their own sections in summary panel
  • Loading branch information
wittejm authored Jul 15, 2021
1 parent f25ca3a commit 1048587
Show file tree
Hide file tree
Showing 13 changed files with 412 additions and 305 deletions.
92 changes: 92 additions & 0 deletions src/backend/expungeservice/charges_summarizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from itertools import groupby

from expungeservice.models.charge import Charge, EditStatus
from expungeservice.models.record import Record
from expungeservice.models.record_summary import ChargesForSummaryPanel
from expungeservice.util import DateWithFuture as date
from typing import Dict, List, Tuple

class ChargesSummarizer:
@staticmethod
def build_charges_for_summary_panel(record: Record) -> ChargesForSummaryPanel:
SHOW_ALL_CHARGES_THRESHOLD = 20
if len(record.charges) <= SHOW_ALL_CHARGES_THRESHOLD:
visible_charges = record.charges
else:
visible_charges = [charge for charge in record.charges if not charge.charge_type.hidden_in_record_summary()]
eligible_charges_by_date: Dict[str, List[Tuple[str,List[Tuple[str, str]]]]] = {}
sorted_charges = sorted(sorted(visible_charges, key=ChargesSummarizer._secondary_sort, reverse=True), key=lambda charge: ChargesSummarizer._primary_sort(charge, record))
for label, charges in groupby(sorted_charges, key=lambda charge: ChargesSummarizer._get_label(charge, record)):
charges_in_section : List[Tuple[str,List[Tuple[str, str]]]]= []
for case_number, case_charges in groupby(charges, key=lambda charge: charge.case_number):
case = ChargesSummarizer._get_case_by_case_number(record, case_number)
case_info_line = ChargesSummarizer._get_case_balance_header_info_for_case(case)
charges_tuples = [
(case_charge.ambiguous_charge_id, case_charge.to_one_line())
for case_charge in case_charges
if case_charge.edit_status != EditStatus.DELETE
]
charges_in_section.append((case_info_line, charges_tuples))
eligible_charges_by_date[label] = charges_in_section
return eligible_charges_by_date

@staticmethod
def _primary_sort(charge: Charge, record: Record):
charge_eligibility = charge.expungement_result.charge_eligibility
if charge_eligibility:
label = charge_eligibility.label
no_balance = ChargesSummarizer._get_case_by_case_number(record, charge.case_number).summary.balance_due_in_cents == 0
if label == "Needs More Analysis":
return 0, label
elif label == "Ineligible":
return 1, label
elif label == "Eligible Now":
if no_balance:
return 2, label
else:
return 3, label + " If Balance Paid"
elif "Eligible Now" in label:
if no_balance:
return 4, label
else:
return 5, label + " If Balance Paid"
else:
if no_balance:
return 6, label
else:
return 7, label + " If Balance Paid"
else:
return 0, ""

@staticmethod
def _secondary_sort(charge: Charge):
charge_eligibility = charge.expungement_result.charge_eligibility
if charge_eligibility and charge_eligibility.date_to_sort_label_by:
return charge_eligibility.date_to_sort_label_by
else:
return date.max()

@staticmethod
def _get_label(charge: Charge, record: Record):
no_balance = ChargesSummarizer._get_case_by_case_number(record, charge.case_number).summary.balance_due_in_cents == 0
charge_eligibility = charge.expungement_result.charge_eligibility
if charge_eligibility:
if charge_eligibility.label == "Needs More Analysis" or charge_eligibility.label == "Ineligible" or no_balance:
return charge_eligibility.label
else:
return charge_eligibility.label + " If Balance Paid"
else:
return "" # TODO: Add error logging because this should be logged as an error

@staticmethod
def _get_case_by_case_number(record, case_number):
for case in record.cases:
if case_number == case.summary.case_number:
return case

@staticmethod
def _get_case_balance_header_info_for_case(case):
if case.summary.get_balance_due() == 0:
return ""
else:
return f'{case.summary.location} {case.summary.case_number} – ${round(case.summary.get_balance_due(),2)}'
141 changes: 136 additions & 5 deletions src/backend/expungeservice/demo_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ def build_search_results(
"case_number": "100000",
"location": "Clackamas",
"date": date_class.today() - relativedelta(years=6, days=12, months=4),
"balance_due_in_cents": 0,
},
),
charges=(
Expand Down Expand Up @@ -102,7 +101,6 @@ def build_search_results(
"case_number": "110000",
"location": "Baker",
"date": date_class.today() - relativedelta(years=7, days=26, months=7),
"balance_due_in_cents": 0,
},
),
charges=(
Expand Down Expand Up @@ -132,7 +130,6 @@ def build_search_results(
"case_number": "120000",
"location": "Baker",
"date": date_class.today() - relativedelta(years=7, days=26, months=7),
"balance_due_in_cents": 0,
},
),
charges=(
Expand Down Expand Up @@ -165,7 +162,6 @@ def build_search_results(
"case_number": "200000",
"location": "Benton",
"date": date_class.today() - relativedelta(years=3, days=12, months=4),
"balance_due_in_cents": 0,
},
),
charges=(
Expand Down Expand Up @@ -195,7 +191,6 @@ def build_search_results(
"case_number": "210000",
"location": "Baker",
"date": date_class.today() - relativedelta(years=4, days=5, months=2),
"balance_due_in_cents": 0,
},
),
charges=(
Expand Down Expand Up @@ -283,6 +278,7 @@ def build_search_results(
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=3, months=9), ruling="Convicted"
),
"balance_due_in_cents": 100000,
},
),
from_dict(
Expand All @@ -297,6 +293,7 @@ def build_search_results(
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=3, months=9), ruling="Dismissed"
),
"balance_due_in_cents": 100000,
},
),
),
Expand Down Expand Up @@ -439,4 +436,138 @@ def build_search_results(
),
),
],
Alias("more", "categories", "", ""): [
OeciCase(
summary=from_dict(
data_class=CaseSummary,
data={
**shared_case_data,
"current_status": "Closed",
"name": "John Notaperson",
"case_number": "123456",
"violation_type": "Offense Felony",
"balance_due_in_cents": 50000,

},
),
charges=(
from_dict(
data_class=OeciCharge,
data={
**shared_charge_data,
"ambiguous_charge_id": "123456-1",
"name": "Assaulting a Public Safety Officer",
"statute": "163.208",
"level": "Felony Class C",
"date": date_class.today() - relativedelta(years=2),
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=1, months=9), ruling="Convicted"
),
"balance_due_in_cents": 50000,
},
),
from_dict(
data_class=OeciCharge,
data={
**shared_charge_data,
"ambiguous_charge_id": "123456-2",
"name": "Felony Riot",
"statute": "111.111",
"level": "Felony Class C",
"date": date_class.today() - relativedelta(years=2),
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=1, months=9), ruling="Dismissed"
),
"balance_due_in_cents": 50000,
},
),
),
),
OeciCase(
summary=from_dict(
data_class=CaseSummary,
data={
**shared_case_data,
"current_status": "Closed",
"name": "John Notaperson",
"case_number": "234567",
"violation_type": "Offense Felony",
},
),
charges=(
from_dict(
data_class=OeciCharge,
data={
**shared_charge_data,
"ambiguous_charge_id": "234567-1",
"name": "Assaulting a Public Safety Officer",
"statute": "163.208",
"level": "Felony Class C",
"date": date_class.today() - relativedelta(years=5),
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=4, months=9), ruling="Convicted"
),
},
),
),
),
OeciCase(
summary=from_dict(
data_class=CaseSummary,
data={
**shared_case_data,
"current_status": "Closed",
"name": "John Notaperson",
"case_number": "333333",
"violation_type": "Offense Violation",
},
),
charges=(
from_dict(
data_class=OeciCharge,
data={
**shared_charge_data,
"ambiguous_charge_id": "333333-1",
"name": "Possession of Marijuana < 1 Ounce",
"statute": "4758643",
"level": "Violation Unclassified",
"date": date_class.today() - relativedelta(years=5),
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=4, months=9), ruling="Convicted"
),
},
),
),
),
OeciCase(
summary=from_dict(
data_class=CaseSummary,
data={
**shared_case_data,
"current_status": "Closed",
"name": "John Notaperson",
"case_number": "444444",
"violation_type": "Offense Violation",
"balance_due_in_cents": 50000,
},
),
charges=(
from_dict(
data_class=OeciCharge,
data={
**shared_charge_data,
"ambiguous_charge_id": "444444-1",
"name": "Possession of Marijuana < 1 Ounce",
"statute": "4758643",
"level": "Violation Unclassified",
"date": date_class.today() - relativedelta(years=5),
"disposition": DispositionCreator.create(
date=date_class.today() - relativedelta(years=4, months=9), ruling="Convicted"
),
"balance_due_in_cents": 50000,
},
),
),
),
],
}
3 changes: 1 addition & 2 deletions src/backend/expungeservice/models/charge.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ def to_one_line(self) -> str:
short_name = self.name.split("(")[0]
charged_date = self.date.strftime("%b %-d, %Y")
disposition = str(self.disposition.status.name)
owed = f" - $ owed" if self.balance_due_in_cents > 0 else ""
return f"{short_name} ({disposition}) Charged {charged_date}{owed}"
return f"{short_name} ({disposition}) Charged {charged_date}"

def is_qualifying_mj_conviction(self):
# See https://www.oregonlaws.org/ors/475B.401
Expand Down
3 changes: 2 additions & 1 deletion src/backend/expungeservice/models/record_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ class CountyFilingFee:
county_name: str
cases_with_eligible_convictions: int

ChargesForSummaryPanel = Dict[str, List[Tuple[str,List[Tuple[str, str]]]]]

@dataclass
class RecordSummary:
record: Record
questions: Dict[str, QuestionSummary]
total_charges: int
eligible_charges_by_date: Dict[str, List[Tuple[str, str]]]
charges_grouped_by_eligibility_and_case: ChargesForSummaryPanel
county_fines: List[CountyFines]
county_filing_fees: List[CountyFilingFee]
no_fees_reason: str
Expand Down
Loading

0 comments on commit 1048587

Please sign in to comment.