diff --git a/src/backend/expungeservice/charge_classifier.py b/src/backend/expungeservice/charge_classifier.py index d7b28aee5..2b7f7c7d7 100644 --- a/src/backend/expungeservice/charge_classifier.py +++ b/src/backend/expungeservice/charge_classifier.py @@ -40,6 +40,7 @@ ) from expungeservice.models.disposition import DispositionStatus, Disposition from expungeservice.models.record import Question, Answer +from expungeservice.models.charge_types.lesser_charge import LesserChargeEligible, LesserChargeIneligible @dataclass @@ -67,6 +68,7 @@ def __classifications_list(self) -> Iterator[AmbiguousChargeTypeWithQuestion]: name = self.name.lower() level = self.level.lower() location = self.location.lower() + yield ChargeClassifier._lesser_charge(self.disposition) yield ChargeClassifier._juvenile_charge(self.violation_type) yield ChargeClassifier._parking_ticket(self.violation_type) yield ChargeClassifier._fare_violation(name) @@ -102,6 +104,13 @@ def _criminal_charge( yield ChargeClassifier._attempt_to_commit(name, level, statute) yield ChargeClassifier._classification_by_level(level, statute) + @staticmethod + def _lesser_charge(dispostion: Disposition): + if dispostion.lesser_charge: + question_string = "Is the convicted charge on this case that this charge was reduced to eligible?" + options = {"Yes": LesserChargeEligible(), "No": LesserChargeIneligible()} + return ChargeClassifier._build_ambiguous_charge_type_with_question(question_string, options) + @staticmethod def _juvenile_charge(violation_type: str): if "juvenile" in violation_type.lower(): diff --git a/src/backend/expungeservice/models/charge_types/lesser_charge.py b/src/backend/expungeservice/models/charge_types/lesser_charge.py new file mode 100644 index 000000000..1d0d2d969 --- /dev/null +++ b/src/backend/expungeservice/models/charge_types/lesser_charge.py @@ -0,0 +1,27 @@ +from dataclasses import dataclass + +from expungeservice.models.charge import ChargeType +from expungeservice.models.expungement_result import TypeEligibility, EligibilityStatus + + +@dataclass(frozen=True) +class LesserChargeEligible(ChargeType): + type_name: str = "Lesser Charge, Eligible" + expungement_rules: str = """A conviction that has been dismissed due to a reduction to a lesser charge is eligible if and only if the new charge is eligible.""" + + def type_eligibility(self, disposition): + return TypeEligibility( + EligibilityStatus.ELIGIBLE, + reason="Reduced to another charge; eligible because the new charge is eligible.", + ) + +@dataclass(frozen=True) +class LesserChargeIneligible(ChargeType): + type_name: str = "Lesser Charge, Ineligible" + expungement_rules: str = """A conviction that has been dismissed due to a reduction to a lesser charge is eligible if and only if the new charge is eligible.""" + + def type_eligibility(self, disposition): + return TypeEligibility( + EligibilityStatus.INELIGIBLE, + reason="Reduced to another charge; ineligible because the new charge is ineligible.", + ) diff --git a/src/backend/expungeservice/models/disposition.py b/src/backend/expungeservice/models/disposition.py index b86220a1f..cb7a9791f 100644 --- a/src/backend/expungeservice/models/disposition.py +++ b/src/backend/expungeservice/models/disposition.py @@ -21,6 +21,7 @@ class Disposition: ruling: str status: DispositionStatus amended: bool = False + lesser_charge: bool = False class DispositionCreator: @@ -31,7 +32,8 @@ def empty(): @staticmethod def create(date: date, ruling: str, amended: bool = False) -> Disposition: status = DispositionCreator.__build_status(ruling) - return Disposition(date, ruling, status, amended) + lesser_charge = "lesser charge" in ruling.lower() + return Disposition(date, ruling, status, amended, lesser_charge) @staticmethod def __build_status(ruling_string): diff --git a/src/backend/tests/models/charge_types/test_lesser_charge.py b/src/backend/tests/models/charge_types/test_lesser_charge.py new file mode 100644 index 000000000..f783d289d --- /dev/null +++ b/src/backend/tests/models/charge_types/test_lesser_charge.py @@ -0,0 +1,15 @@ +from expungeservice.models.charge_types.lesser_charge import LesserChargeEligible, LesserChargeIneligible + +from tests.factories.charge_factory import ChargeFactory +from tests.models.test_charge import Dispositions + + +def test_lesser_charge(): + charge = ChargeFactory.create_ambiguous_charge( + name="Manufacture/Delivery", + statute="4759922b", + level="Felony Class A", + disposition=Dispositions.LESSER_CHARGE, + ) + assert isinstance(charge[0].charge_type, LesserChargeEligible) + assert isinstance(charge[1].charge_type, LesserChargeIneligible) diff --git a/src/backend/tests/models/test_charge.py b/src/backend/tests/models/test_charge.py index 0b834e77a..5743d6d5e 100644 --- a/src/backend/tests/models/test_charge.py +++ b/src/backend/tests/models/test_charge.py @@ -22,6 +22,7 @@ class Dispositions: DISMISSED = DispositionCreator.create(ruling="Dismissed", date=LAST_WEEK) UNRECOGNIZED_DISPOSITION = DispositionCreator.create(ruling="Something unrecognized", date=LAST_WEEK) NO_COMPLAINT = DispositionCreator.create(ruling="No Complaint", date=LAST_WEEK) + LESSER_CHARGE = DispositionCreator.create(ruling="Convicted - Lesser Charge", date=LAST_WEEK) class TestChargeClass(unittest.TestCase):