Esempio n. 1
0
    def test_balance_due_getter_setter(self):
        case_args = [("John Doe", "1990"), "", "", ("1/1/2019", ""), ("", ""), ""]

        case_1 = CaseCreator.create(*case_args, "123.45")  # type: ignore
        assert case_1.get_balance_due() == 123.45

        case_2 = CaseCreator.create(*case_args, "2,345.67")  # type: ignore
        assert case_2.get_balance_due() == 2345.67

        case_3 = CaseCreator.create(*case_args, "0")  # type: ignore
        assert case_3.get_balance_due() == 0
Esempio n. 2
0
 def __record_case(self):
     self.cases.append(
         CaseCreator.create(
             self.info,
             self.case_number,
             self.citation_number,
             self.date_location,
             self.type_status,
             self.case_detail_link,
         ))
 def __record_case(self):
     self.cases.append(
         CaseCreator.create(
             self.info,
             self.case_number,
             "",  # district_attorney_number
             "",  # sid
             self.citation_number,
             self.date_location,
             self.type_status,
             self.case_detail_link,
         ))
Esempio n. 4
0
 def create(
     info=["John Doe", "1990"],
     case_number="1",
     citation_number=None,
     date_location=["1/1/1995", "Multnomah"],
     type_status=["Offense Misdemeanor", "Closed"],
     case_detail_link="?404",
     balance="0",
 ) -> CaseSummary:
     return CaseCreator.create(info, case_number, citation_number,
                               date_location, type_status, case_detail_link,
                               balance)
Esempio n. 5
0
 def _read_case(session: Session, case_summary: CaseSummary) -> OeciCase:
     case_parser_data = Crawler._parse_case(session, case_summary)
     balance_due_in_cents = CaseCreator.compute_balance_due_in_cents(
         case_parser_data.balance_due)
     charges: List[OeciCharge] = []
     for charge_id, charge_dict in case_parser_data.hashed_charge_data.items(
     ):
         ambiguous_charge_id = f"{case_summary.case_number}-{charge_id}"
         charge = Crawler._build_oeci_charge(charge_id, ambiguous_charge_id,
                                             charge_dict, case_parser_data,
                                             balance_due_in_cents)
         charges.append(charge)
     updated_case_summary = replace(
         case_summary, balance_due_in_cents=balance_due_in_cents)
     return OeciCase(updated_case_summary, charges=tuple(charges))
Esempio n. 6
0
class CaseFactory:
    @staticmethod
    def create(
        info=["John Doe", "1990"],
        case_number="1",
        citation_number=None,
        date_location=["1/1/1995", "Multnomah"],
        type_status=["Offense Misdemeanor", "Closed"],
        charges=[],
        case_detail_link="?404",
        balance="0",
    ) -> Case:
        case = CaseCreator.create(
            info, case_number, citation_number, date_location, type_status, charges, case_detail_link, balance
        )
        return case
Esempio n. 7
0
class RecordEditor:
    @staticmethod
    def edit_search_results(search_result_cases: List[OeciCase],
                            edits) -> Tuple[List[OeciCase], List[Charge]]:
        edited_cases: List[OeciCase] = []
        new_charges_acc: List[Charge] = []
        for case in search_result_cases:
            case_number = case.summary.case_number
            if case_number in edits.keys():
                if edits[case_number]["action"] == "edit":
                    edited_case, new_charges = RecordEditor._edit_case(
                        case, edits[case_number])
                    edited_cases.append(edited_case)
                    new_charges_acc += new_charges
                # else: if the action name for this case_number isn't "edit", assume it is "delete" and skip it
            else:
                edited_cases.append(case)
        return edited_cases, new_charges_acc

    @staticmethod
    def _edit_case(case: OeciCase,
                   case_edits) -> Tuple[OeciCase, List[Charge]]:
        if "summary" in case_edits.keys():
            case_summary_edits: Dict[str, Any] = {}
            for key, value in case_edits["summary"].items():
                if key == "date":
                    case_summary_edits["date"] = date_class.fromdatetime(
                        datetime.strptime(value, "%m/%d/%Y"))
                elif key == "balance_due":
                    case_summary_edits[
                        "balance_due_in_cents"] = CaseCreator.compute_balance_due_in_cents(
                            value)
                elif key == "birth_year":
                    case_summary_edits["birth_year"] = int(value)
                else:
                    case_summary_edits[key] = value
            edited_summary = replace(case.summary, **case_summary_edits)
        else:
            edited_summary = case.summary
        new_charges: List[Charge] = []
        if "charges" in case_edits.keys():
            edited_charges, new_charges = RecordEditor._edit_charges(
                case.summary.case_number, case.charges, case_edits["charges"])
        else:
            edited_charges = case.charges
        return OeciCase(edited_summary, edited_charges), new_charges
Esempio n. 8
0
 def _read_case(session: Session, case_summary: CaseSummary) -> OeciCase:
     case_parser_data = Crawler._parse_case(session, case_summary)
     district_attorney_number = case_parser_data.district_attorney_number
     sid = case_parser_data.sid
     balance_due_in_cents = CaseCreator.compute_balance_due_in_cents(case_parser_data.balance_due)
     charges: List[OeciCharge] = []
     for charge_id, charge_dict in case_parser_data.hashed_charge_data.items():
         ambiguous_charge_id = f"{case_summary.case_number}-{charge_id}"
         charge = Crawler._build_oeci_charge(
             charge_id, ambiguous_charge_id, charge_dict, case_parser_data, balance_due_in_cents
         )
         charges.append(charge)
     updated_case_summary = replace(
         case_summary,
         district_attorney_number=district_attorney_number,
         sid=sid,
         balance_due_in_cents=balance_due_in_cents,
         edit_status=EditStatus.UNCHANGED,
     )
     return OeciCase(updated_case_summary, charges=tuple(charges))
Esempio n. 9
0
 def __build_case(self, case) -> Tuple[AmbiguousCase, List[Question]]:
     case_parser_data = self.__parse_case(case)
     balance_due_in_cents = CaseCreator.compute_balance_due_in_cents(
         case_parser_data.balance_due)
     updated_case = replace(
         case,
         balance_due_in_cents=balance_due_in_cents,
         probation_revoked=case_parser_data.probation_revoked)
     ambiguous_charges: List[AmbiguousCharge] = []
     questions: List[Question] = []
     for charge_id, charge_dict in case_parser_data.hashed_charge_data.items(
     ):
         charge_dict["case_number"] = updated_case.case_number
         charge_dict["violation_type"] = updated_case.violation_type
         ambiguous_charge, question = Crawler.__build_charge(
             charge_id, charge_dict, case_parser_data)
         ambiguous_charges.append(ambiguous_charge)
         if question:
             questions.append(question)
     ambiguous_case = []
     for charges in product(*ambiguous_charges):
         possible_case = replace(updated_case, charges=tuple(charges))
         ambiguous_case.append(possible_case)
     return ambiguous_case, questions
Esempio n. 10
0
            new_charges_accumulator += new_charges
        return edited_cases, new_charges_accumulator

    @staticmethod
    def _edit_case(case: OeciCase,
                   case_edits) -> Tuple[OeciCase, List[Charge]]:
        case_summary_edits: Dict[str, Any] = {}
        for key, value in case_edits["summary"].items():
            if key == "edit_status":
                case_summary_edits["edit_status"] = EditStatus(value)
            if key == "date":
                case_summary_edits["date"] = date_class.fromdatetime(
                    datetime.strptime(value, "%m/%d/%Y"))
            elif key == "balance_due":
                case_summary_edits[
                    "balance_due_in_cents"] = CaseCreator.compute_balance_due_in_cents(
                        value)
            elif key == "birth_year":
                case_summary_edits["birth_year"] = int(value)
            else:
                case_summary_edits[key] = value
        edited_summary = replace(case.summary, **case_summary_edits)
        new_charges: List[Charge] = []
        if case_summary_edits["edit_status"] == EditStatus.DELETE:
            edited_charges = RecordEditor._mark_charges_as_deleted(
                case.charges)
        elif "charges" in case_edits.keys():
            edited_charges, new_charges = RecordEditor._edit_charges(
                case.summary.case_number, case.charges, case_edits["charges"])
        else:
            edited_charges = case.charges
        return OeciCase(edited_summary, edited_charges), new_charges
class RecordCreator:
    @staticmethod
    def build_record(
        search: Callable,
        username: str,
        password: str,
        aliases: Tuple[Alias, ...],
        edits: Dict[str, Dict[str, Any]],
    ) -> Tuple[Record, AmbiguousRecord, Dict[str, Question], List[str]]:
        search_results, errors = search(username, password, aliases)
        if errors:
            record = Record((), tuple(errors))
            ambiguous_record = [record]
            return record, ambiguous_record, {}, []
        else:
            cases_with_unique_case_number: List[OeciCase] = [
                list(group)[0] for key, group in groupby(
                    sorted(search_results,
                           key=lambda case: case.summary.case_number),
                    lambda case: case.summary.case_number,
                )
            ]
            unknown_dispositions = RecordCreator._find_unknown_dispositions(
                cases_with_unique_case_number)
            user_edited_search_results = RecordCreator._edit_search_results(
                cases_with_unique_case_number, edits)
            ambiguous_record, questions = RecordCreator.build_ambiguous_record(
                user_edited_search_results)
            record = RecordCreator.analyze_ambiguous_record(ambiguous_record)
            questions_as_dict = dict(
                list(map(lambda q: (q.ambiguous_charge_id, q), questions)))
            return record, ambiguous_record, questions_as_dict, unknown_dispositions

    @staticmethod
    @lru_cache(maxsize=4)
    def build_search_results(
            username: str, password: str,
            aliases: Tuple[Alias, ...]) -> Tuple[List[OeciCase], List[str]]:
        errors = []
        search_results: List[OeciCase] = []
        for alias in aliases:
            session = requests.Session()
            try:
                login_response = Crawler.attempt_login(session, username,
                                                       password)
                alias_search_result = Crawler.search(
                    session,
                    login_response,
                    alias.first_name,
                    alias.last_name,
                    alias.middle_name,
                    alias.birth_date,
                )
                search_results += alias_search_result
            except InvalidOECIUsernamePassword as e:
                error(401, str(e))
            except OECIUnavailable as e:
                error(404, str(e))
            except Exception as e:
                errors.append(str(e))
            finally:
                session.close()
        return search_results, errors

    @staticmethod
    def build_ambiguous_record(
        search_result: List[OeciCase]
    ) -> Tuple[AmbiguousRecord, List[Question]]:
        ambiguous_record: AmbiguousRecord = []
        questions_accumulator: List[Question] = []
        ambiguous_cases: List[AmbiguousCase] = []
        for oeci_case in search_result:
            ambiguous_case, questions = RecordCreator._build_case(oeci_case)
            questions_accumulator += questions
            ambiguous_cases.append(ambiguous_case)
        for cases in product(*ambiguous_cases):
            ambiguous_record.append(Record(tuple(cases)))
        return ambiguous_record, questions_accumulator

    @staticmethod
    def analyze_ambiguous_record(ambiguous_record: AmbiguousRecord):
        charge_id_to_time_eligibilities = []
        ambiguous_record_with_errors = []
        for record in ambiguous_record:
            record_with_errors = replace(record,
                                         errors=tuple(
                                             ErrorChecker.check(record)))
            charge_id_to_time_eligibility = Expunger.run(record_with_errors)
            charge_id_to_time_eligibilities.append(
                charge_id_to_time_eligibility)
            ambiguous_record_with_errors.append(record_with_errors)
        record = RecordMerger.merge(ambiguous_record_with_errors,
                                    charge_id_to_time_eligibilities)
        sorted_record = RecordCreator.sort_record_by_case_date(record)
        return sorted_record

    @staticmethod
    def sort_record_by_case_date(record):
        sorted_cases = sorted(record.cases,
                              key=lambda case: case.summary.date,
                              reverse=True)
        return replace(record, cases=tuple(sorted_cases))

    @staticmethod
    def _build_case(
            oeci_case: OeciCase) -> Tuple[AmbiguousCase, List[Question]]:
        ambiguous_charges: List[AmbiguousCharge] = []
        questions: List[Question] = []
        for oeci_charge in oeci_case.charges:
            ambiguous_charge_id = oeci_charge.ambiguous_charge_id
            charge_dict = {
                "name": oeci_charge.name,
                "statute": oeci_charge.statute,
                "level": oeci_charge.level,
                "date": oeci_charge.date,
                "disposition": oeci_charge.disposition,
                "probation_revoked": oeci_charge.probation_revoked,
                "case_number": oeci_case.summary.case_number,
                "violation_type": oeci_case.summary.violation_type,
                "birth_year": oeci_case.summary.birth_year,
            }
            ambiguous_charge, question = ChargeCreator.create(
                ambiguous_charge_id, **charge_dict)
            ambiguous_charges.append(ambiguous_charge)
            if question:
                questions.append(question)
        ambiguous_case: AmbiguousCase = []
        for charges in product(*ambiguous_charges):
            possible_case = Case(oeci_case.summary, charges=tuple(charges))
            ambiguous_case.append(possible_case)
        return ambiguous_case, questions

    @staticmethod
    def _edit_search_results(search_result_cases: List[OeciCase],
                             edits) -> List[OeciCase]:
        edited_cases: List[OeciCase] = []
        for case in search_result_cases:
            case_number = case.summary.case_number
            if case_number in edits.keys():
                if edits[case_number]["action"] == "edit":
                    edited_cases.append(
                        RecordCreator._edit_case(case, edits[case_number]))
                # else: if the action name for this case_number isn't "edit", assume it is "delete" and skip it
            else:
                edited_cases.append(case)
        return edited_cases

    @staticmethod
    def _edit_case(case: OeciCase, edits):
        if "summary" in edits.keys():
            case_summary_edits: Dict[str, Any] = {}
            for key, value in edits["summary"].items():
                if key == "date":
                    case_summary_edits["date"] = datetime.date(
                        datetime.strptime(value, "%m/%d/%Y"))
                elif key == "balance_due":
                    case_summary_edits[
                        "balance_due_in_cents"] = CaseCreator.compute_balance_due_in_cents(
                            value)
                elif key == "birth_year":
                    case_summary_edits["birth_year"] = int(value)
                else:
                    case_summary_edits[key] = value
            edited_summary = replace(case.summary, **case_summary_edits)
        else:
            edited_summary = case.summary
        if "charges" in edits.keys():
            edited_charges = RecordCreator._edit_charges(
                case.charges, edits["charges"])
        else:
            edited_charges = case.charges
        return OeciCase(edited_summary, edited_charges)