def perform_match_postprocessing(
            self, matched_persons: List[schema.StatePerson]):
        """Performs the following ID specific postprocessing on the provided |matched_persons| directly after they have
        been entity matched:
            - Moves supervising_officer from StatePerson onto open SupervisionPeriods.
            - Moves incarceration and supervision periods onto non-placeholder sentences by date.
            - Moves supervision violations onto supervision periods by date.
            - Moves supervision contacts onto supervision periods by date.
        """
        logging.info(
            '[Entity matching] Moving supervising officer onto open supervision periods'
        )
        add_supervising_officer_to_open_supervision_periods(matched_persons)

        logging.info('[Entity matching] Move periods onto sentences by date.')
        move_periods_onto_sentences_by_date(matched_persons)

        logging.info(
            '[Entity matching] Move supervision violations onto supervision periods by date.'
        )
        move_violations_onto_supervision_periods_for_person(
            matched_persons, self.get_region_code())

        logging.info(
            '[Entity matching] Move supervision contacts onto supervision periods by date.'
        )
        move_contacts_onto_supervision_periods_for_person(
            matched_persons, self.get_region_code())
    def test_associatePeriodsWithSentence_doNotMovePlaceholderPeriods(self):
        # Arrange
        placeholder_sp = StateSupervisionPeriod.new_with_defaults()
        placeholder_ip = StateIncarcerationPeriod.new_with_defaults()

        inc_s_2 = StateIncarcerationSentence.new_with_defaults(
            external_id=_EXTERNAL_ID,
            start_date=_DATE_1,
            completion_date=_DATE_8)

        inc_s = StateIncarcerationSentence.new_with_defaults(
            external_id=_EXTERNAL_ID_2,
            start_date=_DATE_1,
            completion_date=_DATE_8,
            incarceration_periods=[placeholder_ip],
            supervision_periods=[placeholder_sp])

        sg = StateSentenceGroup.new_with_defaults(
            incarceration_sentences=[inc_s, inc_s_2])

        state_person = StatePerson.new_with_defaults(sentence_groups=[sg])

        # Should remain unchanged - placeholder period should not get attached to any other sentences
        expected_person = attr.evolve(state_person)

        # Act
        input_people = converter.convert_entity_people_to_schema_people(
            [state_person])
        move_periods_onto_sentences_by_date(input_people)

        # Assert
        self.assert_people_match([expected_person], input_people)
    def test_associatePeriodsWithSentence_doNotMatchSentenceWithNoStart(self):
        # Arrange
        placeholder_sp = StateSupervisionPeriod.new_with_defaults()

        sp = StateSupervisionPeriod.new_with_defaults(
            external_id=_EXTERNAL_ID_3,
            start_date=_DATE_2,
            termination_date=_DATE_3)
        ip = StateIncarcerationPeriod.new_with_defaults(
            external_id=_EXTERNAL_ID_3,
            admission_date=_DATE_2,
            release_date=_DATE_3)

        inc_s_no_dates = StateIncarcerationSentence.new_with_defaults(
            external_id=_EXTERNAL_ID, supervision_periods=[placeholder_sp])

        placeholder_inc_s = StateIncarcerationSentence.new_with_defaults(
            incarceration_periods=[ip], supervision_periods=[sp])

        sg = StateSentenceGroup.new_with_defaults(
            incarceration_sentences=[inc_s_no_dates, placeholder_inc_s])

        state_person = StatePerson.new_with_defaults(sentence_groups=[sg])

        # Should remain unchanged - the non-placeholder period should not get moved onto sentence with an id
        # but no start date
        expected_person = attr.evolve(state_person)

        # Act
        input_people = converter.convert_entity_people_to_schema_people(
            [state_person])
        move_periods_onto_sentences_by_date(input_people)

        # Assert
        self.assert_people_match([expected_person], input_people)
    def test_associatePeriodsWithSentence_periodNoLongerMatches(self):
        # Arrange
        sp_which_no_longer_overlaps = StateSupervisionPeriod.new_with_defaults(
            supervision_period_id=_ID,
            external_id=_EXTERNAL_ID,
            state_code=_STATE_CODE,
            start_date=_DATE_6)
        ip_which_no_longer_overlaps = StateIncarcerationPeriod.new_with_defaults(
            incarceration_period_id=_ID,
            external_id=_EXTERNAL_ID,
            state_code=_STATE_CODE,
            admission_date=_DATE_6)

        # This sentence, which has already been written to the DB, has presumably been updated so that the date range no
        # longer overlaps with the attached periods.
        inc_s_updated_dates = StateIncarcerationSentence.new_with_defaults(
            incarceration_sentence_id=_ID_2,
            external_id=_EXTERNAL_ID,
            state_code=_STATE_CODE,
            start_date=_DATE_3,
            completion_date=_DATE_5,
            incarceration_periods=[ip_which_no_longer_overlaps],
            supervision_periods=[sp_which_no_longer_overlaps])

        sg = StateSentenceGroup.new_with_defaults(
            sentence_group_id=_ID_3,
            state_code=_STATE_CODE,
            incarceration_sentences=[inc_s_updated_dates])

        state_person = StatePerson.new_with_defaults(person_id=_ID,
                                                     sentence_groups=[sg])

        expected_sp = attr.evolve(sp_which_no_longer_overlaps)
        expected_ip = attr.evolve(ip_which_no_longer_overlaps)
        expected_is = attr.evolve(inc_s_updated_dates,
                                  incarceration_periods=[],
                                  supervision_periods=[])

        # We expect that a new placeholder supervision sentence has been created to hold on to the orphaned periods
        expected_placeholder_ss = StateSupervisionSentence.new_with_defaults(
            state_code=_STATE_CODE,
            status=StateSentenceStatus.PRESENT_WITHOUT_INFO,
            incarceration_periods=[expected_ip],
            supervision_periods=[expected_sp])
        expected_sg = attr.evolve(
            sg,
            incarceration_sentences=[expected_is],
            supervision_sentences=[expected_placeholder_ss])
        expected_person = attr.evolve(state_person,
                                      sentence_groups=[expected_sg])

        # Act
        input_people = converter.convert_entity_people_to_schema_people(
            [state_person])
        move_periods_onto_sentences_by_date(input_people)

        # Assert
        self.assert_people_match([expected_person], input_people)
    def test_associatedPeriodsWithSentences_doNotAssociateToClosedButUnterminatedSentences(
            self):
        # Arrange
        sp_1 = StateSupervisionPeriod.new_with_defaults(
            external_id=_EXTERNAL_ID,
            start_date=_DATE_6,
            termination_date=None)

        ip_1 = StateIncarcerationPeriod.new_with_defaults(
            external_id=_EXTERNAL_ID,
            admission_date=_DATE_6,
            release_date=None)

        placeholder_ss = StateSupervisionSentence.new_with_defaults(
            supervision_periods=[sp_1], incarceration_periods=[ip_1])
        ss = StateSupervisionSentence.new_with_defaults(
            external_id=_EXTERNAL_ID,
            status=StateSentenceStatus.COMPLETED,
            start_date=_DATE_4,
            completion_date=None)
        inc_s = StateIncarcerationSentence.new_with_defaults(
            external_id=_EXTERNAL_ID,
            status=StateSentenceStatus.COMPLETED,
            start_date=_DATE_4,
            completion_date=None)

        sg = StateSentenceGroup.new_with_defaults(
            incarceration_sentences=[inc_s],
            supervision_sentences=[ss, placeholder_ss])

        state_person = StatePerson.new_with_defaults(sentence_groups=[sg])

        expected_sp_1 = attr.evolve(sp_1)
        expected_ip_1 = attr.evolve(ip_1)

        expected_placeholder_ss = attr.evolve(
            placeholder_ss,
            supervision_periods=[expected_sp_1],
            incarceration_periods=[expected_ip_1])
        expected_inc_s = attr.evolve(inc_s)
        expected_ss = attr.evolve(ss)
        expected_sg = attr.evolve(
            sg,
            supervision_sentences=[expected_ss, expected_placeholder_ss],
            incarceration_sentences=[expected_inc_s])
        expected_person = attr.evolve(state_person,
                                      sentence_groups=[expected_sg])

        # Act
        input_people = converter.convert_entity_people_to_schema_people(
            [state_person])
        move_periods_onto_sentences_by_date(input_people)

        # Assert
        self.assert_people_match([expected_person], input_people)
    def perform_match_postprocessing(
            self, matched_persons: List[schema.StatePerson]):
        logging.info('[Entity matching] Move supervision periods onto sentences by date.')
        move_periods_onto_sentences_by_date(matched_persons, period_filter=schema.StateSupervisionPeriod)

        logging.info('[Entity matching] Set current / last supervising officer from supervision periods.')
        set_current_supervising_officer_from_supervision_periods(matched_persons)

        logging.info(
            "[Entity matching] Post-processing: Move SupervisionViolationResponses onto SupervisionPeriods by date.")
        move_violations_onto_supervision_periods_for_sentence(matched_persons)
    def test_associatedPeriodsWithSentences_oneDayPeriodOverlapsWithStartOfSentence(
            self):
        sp = StateSupervisionPeriod.new_with_defaults(external_id=_EXTERNAL_ID,
                                                      start_date=_DATE_2,
                                                      termination_date=_DATE_2)
        placeholder_ss = StateSupervisionSentence.new_with_defaults(
            supervision_periods=[sp])

        ss = StateSupervisionSentence.new_with_defaults(
            external_id=_EXTERNAL_ID,
            start_date=_DATE_2,
            completion_date=_DATE_3,
            status=StateSentenceStatus.SERVING)

        sg = StateSentenceGroup.new_with_defaults(
            supervision_sentences=[ss, placeholder_ss])

        state_person = StatePerson.new_with_defaults(sentence_groups=[sg])

        expected_sp = attr.evolve(sp)

        expected_placeholder_ss = attr.evolve(placeholder_ss,
                                              supervision_periods=[],
                                              incarceration_periods=[])
        expected_ss = attr.evolve(ss, supervision_periods=[expected_sp])
        expected_sg = attr.evolve(
            sg, supervision_sentences=[expected_ss, expected_placeholder_ss])
        expected_person = attr.evolve(state_person,
                                      sentence_groups=[expected_sg])

        # Act
        input_people = converter.convert_entity_people_to_schema_people(
            [state_person])
        move_periods_onto_sentences_by_date(input_people)

        # Assert
        self.assert_people_match([expected_person], input_people)