Skip to content

Commit

Permalink
Handle ali links during import (#4519)
Browse files Browse the repository at this point in the history
* Make match_merge_link take state

* Change link_views to link_states

* Communicate links in import process

* WIP

* Fix function name
  • Loading branch information
haneslinger authored Feb 14, 2024
1 parent 212a356 commit ab5d530
Show file tree
Hide file tree
Showing 11 changed files with 619 additions and 156 deletions.
254 changes: 187 additions & 67 deletions seed/data_importer/match.py

Large diffs are not rendered by default.

259 changes: 258 additions & 1 deletion seed/data_importer/tests/test_AH_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"""


from datetime import datetime

from seed.data_importer.match import (
match_and_link_incoming_properties_and_taxlots
)
Expand All @@ -19,8 +21,10 @@
PropertyView
)
from seed.test_helpers.fake import (
FakeCycleFactory,
FakePropertyFactory,
FakePropertyStateFactory
FakePropertyStateFactory,
FakePropertyViewFactory
)
from seed.tests.util import DataMappingBaseTestCase

Expand All @@ -31,6 +35,7 @@ def setUp(self):
self.user, self.org, self.import_file, self.import_record, self.cycle = selfvars
self.import_file.mapping_done = True
self.import_file.save()
self.cycle_factory = FakeCycleFactory(organization=self.org, user=self.user)

# create tree
self.org.access_level_names = ["1st Gen", "2nd Gen", "3rd Gen"]
Expand Down Expand Up @@ -692,3 +697,255 @@ def test_match_incoming_error_and_no_access_to_existing(self):
assert PropertyView.objects.count() == 1
pv = PropertyView.objects.first()
assert pv.state.city is None


class TestAHImportMatchExistingDifferentCycle(TestAHImportFile):
def setUp(self):
super().setUp()

self.property_view_factory = FakePropertyViewFactory(organization=self.org)

# this causes all the states to match
self.base_details["ubid"] = '86HJPCWQ+2VV-1-3-2-3'
self.base_details["no_default_data"] = False

self.state = self.property_state_factory.get_property_state(**self.base_details)
self.state.data_state = DATA_STATE_MATCHING
self.state.save()
self.existing_property = self.property_factory.get_property(access_level_instance=self.me_ali)
self.other_cycle = self.cycle_factory.get_cycle(start=datetime(2010, 10, 10))
self.view = PropertyView.objects.create(
property=self.existing_property,
cycle=self.other_cycle,
state=self.state
)

def test_has_ali_merges_and_links(self):
# Set Up - create view for merge
self.property_view_factory.get_property_view(prprty=self.existing_property, cycle=self.cycle)

# Set Up - update new state info
self.base_details["raw_access_level_instance_id"] = self.me_ali.id
self.base_details['city'] = 'Denver' # so not duplicate
self.property_state_factory.get_property_state(**self.base_details)

# Action
results = match_and_link_incoming_properties_and_taxlots(*self.action_args)

# Assert - results
self.blank_result['property_initial_incoming'] = 1
self.blank_result['property_merges_against_existing'] = 1
self.blank_result['property_links_against_existing'] = 0 # not 1 cause the view it merged into was already linked
self.blank_result['property_new'] = 0 # not 1 cause the property already exists
self.assertDictContainsSubset(self.blank_result, results)

# one Property in right ali
self.assertEqual(Property.objects.count(), 1)
p = Property.objects.first()
assert p.access_level_instance == self.me_ali

# 3 in a little merge tree, 1 in the other cycle
assert PropertyState.objects.count() == 4

# city changed in the correct view
assert PropertyView.objects.count() == 2
view_info = PropertyView.objects.values("property_id", "cycle_id", "state__city")
assert list(view_info) == [
{
"property_id": self.existing_property.id,
"cycle_id": self.other_cycle.id,
"state__city": None,
},
{
"property_id": self.existing_property.id,
"cycle_id": self.cycle.id,
"state__city": "Denver",
},
]

def test_no_ali_merges_and_links(self):
# Set Up - create view for merge
self.property_view_factory.get_property_view(prprty=self.existing_property, cycle=self.cycle)

# Set Up - update new state info
self.base_details["raw_access_level_instance_error"] = "uh oh"
self.base_details['city'] = 'Denver' # so not duplicate
self.property_state_factory.get_property_state(**self.base_details)

# Action
results = match_and_link_incoming_properties_and_taxlots(*self.action_args)

# Assert - results
self.blank_result['property_initial_incoming'] = 1
self.blank_result['property_merges_against_existing'] = 1
self.blank_result['property_links_against_existing'] = 0 # not 1 cause the view it merged into was already linked
self.blank_result['property_new'] = 0 # not 1 cause the property already exists
self.assertDictContainsSubset(self.blank_result, results)

# one Property in right ali
self.assertEqual(Property.objects.count(), 1)
p = Property.objects.first()
assert p.access_level_instance == self.me_ali

# 3 in a little merge tree, 1 in the other cycle
assert PropertyState.objects.count() == 4

# city changed in the correct view
assert PropertyView.objects.count() == 2
view_info = PropertyView.objects.values("property_id", "cycle_id", "state__city")

assert list(view_info) == [
{
"property_id": self.existing_property.id,
"cycle_id": self.other_cycle.id,
"state__city": None,
},
{
"property_id": self.existing_property.id,
"cycle_id": self.cycle.id,
"state__city": "Denver",
},
]

def test_has_ali_links(self):
# Set Up - update new state info
self.base_details["raw_access_level_instance_id"] = self.me_ali.id
self.base_details['city'] = 'Denver' # so not duplicate
self.property_state_factory.get_property_state(**self.base_details)

# Action
results = match_and_link_incoming_properties_and_taxlots(*self.action_args)

# Assert - results
self.blank_result['property_initial_incoming'] = 1
self.blank_result['property_links_against_existing'] = 1
self.blank_result['property_new'] = 0 # not 1 cause the property already exists
self.assertDictContainsSubset(self.blank_result, results)

# 1 in each cycle
assert PropertyState.objects.count() == 2

# city changed in the correct view
assert PropertyView.objects.count() == 2
view_info = PropertyView.objects.values("property_id", "property__access_level_instance_id", "cycle_id", "state__city")
assert list(view_info) == [
{
"property_id": self.existing_property.id,
"property__access_level_instance_id": self.me_ali.id,
"cycle_id": self.other_cycle.id,
"state__city": None,
},
{
"property_id": self.existing_property.id,
"property__access_level_instance_id": self.me_ali.id,
"cycle_id": self.cycle.id,
"state__city": "Denver",
},
]

def test_has_ali_links_different_ali(self):
# Set Up - update existing state ali
self.existing_property.access_level_instance = self.sister
self.existing_property.save()

# Set Up - update new state info
self.base_details["raw_access_level_instance_id"] = self.me_ali.id # different ali
self.base_details['city'] = 'Denver' # so not duplicate
self.property_state_factory.get_property_state(**self.base_details)

# Action
results = match_and_link_incoming_properties_and_taxlots(*self.action_args)

# Assert - results
self.blank_result['property_initial_incoming'] = 1
self.blank_result['property_links_against_existing_errors'] = 1
self.assertDictContainsSubset(self.blank_result, results)

# theres two Properties and two PropertyStates, but one of each is abandoned
self.assertEqual(Property.objects.count(), 2)
assert PropertyState.objects.count() == 2

# no change
assert PropertyView.objects.count() == 1
view_info = PropertyView.objects.values("property_id", "property__access_level_instance_id", "cycle_id", "state__city")
assert list(view_info) == [
{
"property_id": self.existing_property.id,
"property__access_level_instance_id": self.sister.id,
"cycle_id": self.other_cycle.id,
"state__city": None,
},
]

def test_no_ali_links(self):
# Set Up - update new state info
self.base_details["raw_access_level_instance_error"] = "uh oh"
self.base_details['city'] = 'Denver' # so not duplicate
self.property_state_factory.get_property_state(**self.base_details)

# Action
results = match_and_link_incoming_properties_and_taxlots(*self.action_args)

# Assert - results
self.blank_result['property_initial_incoming'] = 1
self.blank_result['property_links_against_existing'] = 1
self.blank_result['property_new'] = 0 # not 1 cause the property already exists
self.assertDictContainsSubset(self.blank_result, results)

# two properties, but one abandoned
self.assertEqual(Property.objects.count(), 2)

# 1 in each cycle
assert PropertyState.objects.count() == 2

# city changed in the correct view
assert PropertyView.objects.count() == 2
view_info = PropertyView.objects.values("property_id", "cycle_id", "state__city")
assert list(view_info) == [
{
"property_id": self.existing_property.id,
"cycle_id": self.other_cycle.id,
"state__city": None,
},
{
"property_id": self.existing_property.id,
"cycle_id": self.cycle.id,
"state__city": "Denver",
},
]

def test_no_ali_links_no_access(self):
# Set Up - file and existing property have different alis
self.existing_property.access_level_instance = self.sister
self.existing_property.save()
self.import_record.access_level_instance = self.me_ali
self.import_record.save()

# update new state info
self.base_details["raw_access_level_instance_error"] = "uh oh"
self.base_details['city'] = 'Denver' # so not duplicate
self.property_state_factory.get_property_state(**self.base_details)

# Action
results = match_and_link_incoming_properties_and_taxlots(*self.action_args)

# Assert - results
self.blank_result['property_initial_incoming'] = 1
self.blank_result['property_links_against_existing_errors'] = 1
self.assertDictContainsSubset(self.blank_result, results)

# one Property in right ali
self.assertEqual(Property.objects.count(), 1)
p = Property.objects.first()
assert p.access_level_instance == self.sister

# no change
assert PropertyView.objects.count() == 1
view_info = PropertyView.objects.values("property_id", "cycle_id", "state__city")
assert list(view_info) == [
{
"property_id": self.existing_property.id,
"cycle_id": self.other_cycle.id,
"state__city": None,
},
]
8 changes: 8 additions & 0 deletions seed/data_importer/tests/test_match_incoming.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,8 @@ def test_properties(self):
'property_initial_incoming': 10,
'property_merges_against_existing': 1,
'property_merges_against_existing_errors': 0,
'property_links_against_existing': 0,
'property_links_against_existing_errors': 0,
'property_merges_between_existing': 0,
'property_merges_within_file': 2,
'property_merges_within_file_errors': 0,
Expand All @@ -894,6 +896,8 @@ def test_properties(self):
'tax_lot_initial_incoming': 0,
'tax_lot_merges_against_existing': 0,
'tax_lot_merges_against_existing_errors': 0,
'tax_lot_links_against_existing': 0,
'tax_lot_links_against_existing_errors': 0,
'tax_lot_merges_between_existing': 0,
'tax_lot_merges_within_file': 0,
'tax_lot_merges_within_file_errors': 0,
Expand Down Expand Up @@ -1036,6 +1040,8 @@ def test_taxlots(self):
'property_merges_between_existing': 0,
'property_merges_within_file': 0,
'property_merges_within_file_errors': 0,
'property_links_against_existing': 0,
'property_links_against_existing_errors': 0,
'property_new': 0,
'property_new_errors': 0,
'tax_lot_duplicates_against_existing': 1,
Expand All @@ -1044,6 +1050,8 @@ def test_taxlots(self):
'tax_lot_initial_incoming': 10,
'tax_lot_merges_against_existing': 1,
'tax_lot_merges_against_existing_errors': 0,
'tax_lot_links_against_existing': 0,
'tax_lot_links_against_existing_errors': 0,
'tax_lot_merges_between_existing': 0,
'tax_lot_merges_within_file': 2,
'tax_lot_merges_within_file_errors': 0,
Expand Down
Loading

0 comments on commit ab5d530

Please sign in to comment.