Beispiel #1
0
    def run(record: Record) -> Dict[str, TimeEligibility]:
        """
        Evaluates the expungement eligibility of a record.
        """
        analyzable_record = Expunger._without_skippable_charges(record)
        ambiguous_charge_id_to_time_eligibility = {}
        cases = analyzable_record.cases
        for charge in analyzable_record.charges:
            eligibility_dates: List[Tuple[date, str]] = []

            other_charges = [
                c for c in analyzable_record.charges
                if c.id != charge.id and c.edit_status != EditStatus.DELETE
            ]

            other_blocking_charges = [
                c for c in other_charges if c.charge_type.blocks_other_charges
            ]

            _, convictions = Case.categorize_charges(other_charges)
            blocking_dismissals, blocking_convictions = Case.categorize_charges(
                other_blocking_charges)

            most_recent_blocking_dismissal = Expunger._most_recent_different_case_dismissal(
                charge, blocking_dismissals)
            most_recent_blocking_conviction = Expunger._most_recent_convictions(
                blocking_convictions)

            other_convictions_all_traffic = Expunger._is_other_convictions_all_traffic(
                convictions)

            if charge.convicted():
                if isinstance(
                        charge.charge_type,
                        MarijuanaUnder21) and other_convictions_all_traffic:
                    eligibility_dates.append((
                        charge.disposition.date + relativedelta(years=1),
                        "One year from date of conviction (137.226)",
                    ))
                else:
                    eligibility_dates.append((
                        charge.disposition.date + relativedelta(years=3),
                        "Three years from date of conviction (137.225(1)(a))",
                    ))
            elif charge.dismissed():
                eligibility_dates.append(
                    (charge.date, "Eligible immediately (137.225(1)(b))"))
            else:
                raise ValueError(
                    "Charge should always convicted or dismissed at this point."
                )

            if charge.type_eligibility.status == EligibilityStatus.INELIGIBLE:
                eligibility_dates.append((date.max(
                ), "Never. Type ineligible charges are always time ineligible."
                                          ))

            if charge.disposition.status == DispositionStatus.NO_COMPLAINT:
                eligibility_dates.append((
                    charge.date + relativedelta(years=1),
                    "One year from date of no-complaint arrest (137.225(1)(b))",
                ))

            if charge.convicted() and charge.probation_revoked:
                eligibility_dates.append((
                    charge.probation_revoked + relativedelta(years=10),
                    "Time-ineligible under 137.225(1)(c) (Probation Revoked). Inspect further if the case has multiple convictions on the case.",
                ))

            if most_recent_blocking_conviction:
                conviction_string = "other conviction" if charge.convicted(
                ) else "conviction"
                summary = most_recent_blocking_conviction.case(cases).summary
                potential = "potential " if not summary.closed() else ""
                eligibility_dates.append((
                    most_recent_blocking_conviction.disposition.date +
                    relativedelta(years=10),
                    f"137.225(7)(b) – Ten years from most recent {potential}{conviction_string} from case [{summary.case_number}].",
                ))

            if charge.dismissed() and most_recent_blocking_dismissal:
                eligibility_dates.append((
                    most_recent_blocking_dismissal.date +
                    relativedelta(years=3),
                    "Three years from most recent other arrest (137.225(8)(a))",
                ))

            if charge.convicted() and isinstance(charge.charge_type,
                                                 FelonyClassB):
                if Expunger._calculate_has_subsequent_charge(
                        charge, other_blocking_charges):
                    eligibility_dates.append((
                        date.max(),
                        "Never. Class B felony can have no subsequent arrests or convictions (137.225(5)(a)(A)(ii))",
                    ))
                else:
                    eligibility_dates.append((
                        charge.disposition.date + relativedelta(years=20),
                        "Twenty years from date of class B felony conviction (137.225(5)(a)(A)(i))",
                    ))

            if isinstance(charge.charge_type, MarijuanaViolation):
                date_will_be_eligible = charge.disposition.date
                reason = "Eligible immediately (475B.401)"
            else:
                date_will_be_eligible, reason = max(eligibility_dates)

            if date_will_be_eligible and date.today() >= date_will_be_eligible:
                time_eligibility = TimeEligibility(
                    status=EligibilityStatus.ELIGIBLE,
                    reason="Eligible now",
                    date_will_be_eligible=date_will_be_eligible,
                )
            else:
                time_eligibility = TimeEligibility(
                    status=EligibilityStatus.INELIGIBLE,
                    reason=reason,
                    date_will_be_eligible=date_will_be_eligible)
            ambiguous_charge_id_to_time_eligibility[
                charge.ambiguous_charge_id] = time_eligibility
        for case in cases:
            non_violation_convictions_in_case = []
            violations_in_case = []
            for charge in case.charges:
                if charge.convicted():
                    if "violation" in charge.level.lower():
                        violations_in_case.append(charge)
                    else:
                        non_violation_convictions_in_case.append(charge)
            violations_in_case.sort(key=lambda charge: charge.disposition.date,
                                    reverse=True)
            if len(non_violation_convictions_in_case
                   ) == 1 and len(violations_in_case) <= 1:
                attractor = non_violation_convictions_in_case[0]
            elif len(violations_in_case) == 1:
                attractor = violations_in_case[0]
            elif len(violations_in_case) in [2, 3]:
                attractor = violations_in_case[1]
            else:
                attractor = None

            if attractor:
                for charge in case.charges:
                    if (charge.type_eligibility.status !=
                            EligibilityStatus.INELIGIBLE
                            and charge.dismissed()
                            and ambiguous_charge_id_to_time_eligibility[
                                charge.
                                ambiguous_charge_id].date_will_be_eligible >
                            ambiguous_charge_id_to_time_eligibility[
                                attractor.
                                ambiguous_charge_id].date_will_be_eligible):
                        time_eligibility = TimeEligibility(
                            status=ambiguous_charge_id_to_time_eligibility[
                                attractor.ambiguous_charge_id].status,
                            reason=
                            'Time eligibility of the arrest matches conviction on the same case (the "friendly" rule)',
                            date_will_be_eligible=
                            ambiguous_charge_id_to_time_eligibility[
                                attractor.
                                ambiguous_charge_id].date_will_be_eligible,
                        )
                        ambiguous_charge_id_to_time_eligibility[
                            charge.ambiguous_charge_id] = time_eligibility
        return ambiguous_charge_id_to_time_eligibility
Beispiel #2
0
def test_expunger_categorizes_charges(record_with_various_categories):
    dismissals, convictions = Case.categorize_charges(
        record_with_various_categories.charges)

    assert len(dismissals) == 5
    assert len(convictions) == 4
                )
            return pdf, warnings
        else:
            return None

    @staticmethod
    def _build_pdf_for_eligible_case(
            case: Case, eligible_charges: List[Charge],
            user_information: Dict[str, str],
            case_number_with_comments: str) -> Tuple[PdfReader, List[str]]:
        warnings: List[str] = []
        charges = case.charges
        charge_names = [charge.name.title() for charge in charges]
        arrest_dates_all = list(
            set([charge.date.strftime("%b %-d, %Y") for charge in charges]))
        dismissals, convictions = Case.categorize_charges(eligible_charges)
        dismissed_names = [charge.name.title() for charge in dismissals]
        dismissed_arrest_dates = list(
            set([charge.date.strftime("%b %-d, %Y") for charge in dismissals]))
        dismissed_dates = list(
            set([
                charge.disposition.date.strftime("%b %-d, %Y")
                for charge in dismissals
            ]))
        conviction_names = [charge.name.title() for charge in convictions]
        conviction_arrest_dates = list(
            set([charge.date.strftime("%b %-d, %Y")
                 for charge in convictions]))
        conviction_dates = list(
            set([
                charge.disposition.date.strftime("%b %-d, %Y")