Skip to content

Commit

Permalink
Remove the question from Multnomah violations and make them all Needs…
Browse files Browse the repository at this point in the history
… More Analysis
  • Loading branch information
wittejm committed Nov 28, 2023
1 parent aeb57fd commit 3894de2
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 91 deletions.
10 changes: 2 additions & 8 deletions src/backend/expungeservice/charge_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from expungeservice.models.charge_types.misdemeanor_class_bc import MisdemeanorClassBC
from expungeservice.models.charge_types.violation import Violation
from expungeservice.models.charge_types.reduced_to_violation import ReducedToViolation
from expungeservice.models.charge_types.possible_traffic_violation import PossibleTrafficViolation
from expungeservice.models.charge_types.parking_ticket import ParkingTicket
from expungeservice.models.charge_types.fare_violation import FareViolation
from expungeservice.models.charge_types.person_felony import PersonFelonyClassB
Expand Down Expand Up @@ -110,14 +111,7 @@ def _juvenile_charge(violation_type: str):
def _violation(level, name, location):
if "violation" in level:
if location == "multnomah":
if "reduced" in name or "treated as" in name:
question_string = "Was the underlying charge traffic-related?"
options = {"Yes": TrafficViolation(), "No": ReducedToViolation()}
return ChargeClassifier._build_ambiguous_charge_type_with_question(question_string, options)
else:
question_string = "Was the underlying charge traffic-related?"
options = {"Yes": TrafficViolation(), "No": Violation()}
return ChargeClassifier._build_ambiguous_charge_type_with_question(question_string, options)
return AmbiguousChargeTypeWithQuestion([PossibleTrafficViolation()])
else:
if "reduced" in name or "treated as" in name:
return AmbiguousChargeTypeWithQuestion([ReducedToViolation()])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from dataclasses import dataclass

from expungeservice.models.charge import ChargeType
from expungeservice.models.charge import ChargeUtil
from expungeservice.models.expungement_result import TypeEligibility, EligibilityStatus


@dataclass(frozen=True)
class PossibleTrafficViolation(ChargeType):
type_name: str = "Possible Traffic Violation"
expungement_rules: str = """Violations and misdemeanors reduced to violations in Multnomah County may be considered traffic violations that have insufficient identifying information in OECI. Traffic violation convictions are ineligible under 137.225(7)(a). Other violation or reduced-to-violation convictions are generally eligible however, and if this charge is not traffic-related then the user should Enable Editing to update the charge type to Violation or ReducedToViolation."""
blocks_other_charges: bool = False
severity_level: str = "Violation"

def type_eligibility(self, disposition):
if ChargeUtil.dismissed(disposition):
return TypeEligibility(
EligibilityStatus.NEEDS_MORE_ANALYSIS,
reason="Dismissed violations are eligible under 137.225(1)(b) but administrative reasons may make this difficult to expunge.",
)
elif ChargeUtil.convicted(disposition):
return TypeEligibility(
EligibilityStatus.NEEDS_MORE_ANALYSIS,
reason="Either ineligible under 137.225(7)(a) or eligible under 137.225(5)(c)"
)
else:
return TypeEligibility(
EligibilityStatus.NEEDS_MORE_ANALYSIS,
reason="A possibly-traffic-related violation with indeterminate disposition needs more information to determine eligibility.",
)

def hidden_in_record_summary(self, disposition):
return False
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from expungeservice.models.expungement_result import EligibilityStatus
from expungeservice.models.charge_types.violation import Violation
from expungeservice.record_merger import RecordMerger
from expungeservice.models.charge_types.traffic_violation import TrafficViolation
from expungeservice.models.charge_types.possible_traffic_violation import PossibleTrafficViolation

from tests.factories.charge_factory import ChargeFactory
from tests.models.test_charge import Dispositions


def test_violation_multnomah_convicted():
charge = ChargeFactory.create(
name="Viol Treatment",
statute="1615662",
level="Violation Unclassified",
disposition=Dispositions.CONVICTED,
location="Multnomah",
)

assert isinstance(charge.charge_type, PossibleTrafficViolation)
assert charge.type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert charge.type_eligibility.reason == "Either ineligible under 137.225(7)(a) or eligible under 137.225(5)(c)"


def test_violation_multnomah_dismissed():
charge = ChargeFactory.create(
name="Misdemeanor Treated as a Violation",
statute="161.566(1)",
level="Violation Class A",
disposition=Dispositions.DISMISSED,
location="Multnomah",
)

assert isinstance(charge.charge_type, PossibleTrafficViolation)
assert charge.type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert (
charge.type_eligibility.reason
== "Dismissed violations are eligible under 137.225(1)(b) but administrative reasons may make this difficult to expunge."
)


def test_violation_multnomah_unrecognized_disposition():
charge = ChargeFactory.create(
name="(Reduced - DA Elected)",
statute="164045",
level="Violation Class A",
disposition=Dispositions.UNRECOGNIZED_DISPOSITION,
location="Multnomah",
)

assert isinstance(charge.charge_type, PossibleTrafficViolation)
assert charge.type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert (
charge.type_eligibility.reason
== "A possibly-traffic-related violation with indeterminate disposition needs more information to determine eligibility."
)
54 changes: 0 additions & 54 deletions src/backend/tests/models/charge_types/test_reduced_to_violation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,60 +33,6 @@ def test_reduced_to_violation_dismissed():
assert charge.type_eligibility.reason == "Dismissed criminal charge eligible under 137.225(1)(b)"


def test_reduced_to_violation_multnomah_convicted():
charge = ChargeFactory.create_ambiguous_charge(
name="Theft in the Second Degree (Reduced - DA Elected)",
statute="164045",
level="Violation Class A",
disposition=Dispositions.CONVICTED,
location="Multnomah"
)[1]

assert isinstance(charge.charge_type, ReducedToViolation)
assert charge.type_eligibility.status is EligibilityStatus.ELIGIBLE
assert charge.type_eligibility.reason == "Eligible under 137.225(5)(d)"


def test_reduced_to_violation_multnomah_dismissed():
charges = ChargeFactory.create_ambiguous_charge(
name="Misdemeanor Treated as a Violation",
statute="161.566(1)",
level="Violation Class A",
disposition=Dispositions.DISMISSED,
location="Multnomah"
)

type_eligibility = RecordMerger.merge_type_eligibilities(charges)

assert type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert (
type_eligibility.reason
== "Traffic Violation – Dismissed violations are eligible under 137.225(1)(b) but administrative reasons may make this difficult to expunge. OR Reduced to Violation – Dismissed criminal charge eligible under 137.225(1)(b)"
)
assert isinstance(charges[0].charge_type, TrafficViolation)
assert isinstance(charges[1].charge_type, ReducedToViolation)


def test_reduced_to_violation_multnomah_unrecognized_disposition():
charges = ChargeFactory.create_ambiguous_charge(
name="Theft in the Second Degree (Reduced - DA Elected)",
statute="164045",
level="Violation Class A",
disposition=Dispositions.UNRECOGNIZED_DISPOSITION,
location="Multnomah"

)
type_eligibility = RecordMerger.merge_type_eligibilities(charges)

assert type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert (
type_eligibility.reason
== "Traffic Violation – Always ineligible under 137.225(7)(a) (for convictions) or by omission from statute (for dismissals) OR Reduced to Violation – Reduced Violations are always eligible under 137.225(5)(d) for convictions, or 137.225(1)(b) for dismissals"
)
assert isinstance(charges[0].charge_type, TrafficViolation)
assert isinstance(charges[1].charge_type, ReducedToViolation)


def test_reduced_violation_ineligible_under_other_criterion():
charge = ChargeFactory.create(
name="Criminal Driving While Suspended\n (Reduced - DA Elected)", statute="8111824", level="Violation Class A",
Expand Down
31 changes: 2 additions & 29 deletions src/backend/tests/models/charge_types/test_violation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from expungeservice.models.charge_types.violation import Violation
from expungeservice.record_merger import RecordMerger
from expungeservice.models.charge_types.traffic_violation import TrafficViolation
from expungeservice.models.charge_types.possible_traffic_violation import PossibleTrafficViolation

from tests.factories.charge_factory import ChargeFactory
from tests.models.test_charge import Dispositions


def test_violation_convicted():
charge = ChargeFactory.create(
name="Viol Treatment", statute="1615662", level="Violation Unclassified", disposition=Dispositions.CONVICTED
Expand All @@ -24,32 +26,3 @@ def test_violation_dismissed():
assert isinstance(charge.charge_type, Violation)
assert charge.type_eligibility.status is EligibilityStatus.ELIGIBLE
assert charge.type_eligibility.reason == "Eligible under 137.225(1)(b)"

def test_violation_multnomah_convicted():
charges = ChargeFactory.create_ambiguous_charge(
name="Viol Treatment", statute="1615662", level="Violation Unclassified", disposition=Dispositions.CONVICTED, location="Multnomah"
)
type_eligibility = RecordMerger.merge_type_eligibilities(charges)

assert type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert (
type_eligibility.reason
== "Traffic Violation – Ineligible under 137.225(7)(a) OR Violation – Eligible under 137.225(5)(c)"
)
assert isinstance(charges[0].charge_type, TrafficViolation)
assert isinstance(charges[1].charge_type, Violation)


def test_violation_multnomah_dismissed():
charges = ChargeFactory.create_ambiguous_charge(
name="Viol Treatment", statute="1615662", level="Violation Unclassified", disposition=Dispositions.DISMISSED, location="Multnomah"
)
type_eligibility = RecordMerger.merge_type_eligibilities(charges)

assert type_eligibility.status is EligibilityStatus.NEEDS_MORE_ANALYSIS
assert (
type_eligibility.reason
== "Traffic Violation – Dismissed violations are eligible under 137.225(1)(b) but administrative reasons may make this difficult to expunge. OR Violation – Eligible under 137.225(1)(b)"
)
assert isinstance(charges[0].charge_type, TrafficViolation)
assert isinstance(charges[1].charge_type, Violation)

0 comments on commit 3894de2

Please sign in to comment.