def test_property_existing_in_multiple_cycles_can_have_meters_and_readings_associated_to_it( self): property_details = FakePropertyStateFactory( organization=self.org).get_details() property_details['organization_id'] = self.org.id # new state to be associated to new cycle using the same pm_property_id as state in old cycle property_details['pm_property_id'] = self.state_1.pm_property_id state = PropertyState(**property_details) state.save() new_property_state = PropertyState.objects.get(pk=state.id) new_cycle_factory = FakeCycleFactory(organization=self.org, user=self.user) new_cycle = new_cycle_factory.get_cycle( start=datetime(2010, 10, 10, tzinfo=get_current_timezone())) # new state and cycle associated to old property PropertyView.objects.create(property=self.property_1, cycle=new_cycle, state=new_property_state) url = reverse("api:v3:import_files-start-save-data", args=[self.import_file.id]) url += f'?organization_id={self.org.pk}' post_params = { 'cycle_id': self.cycle.pk, } self.client.post(url, post_params) refreshed_property_1 = Property.objects.get(pk=self.property_1.id) self.assertEqual(refreshed_property_1.meters.all().count(), 2)
def setUp(self): self.user_details = { 'username': '******', 'password': '******', } self.user = User.objects.create_superuser(email='*****@*****.**', **self.user_details) self.org, _, _ = create_organization(self.user) self.property_state_factory = FakePropertyStateFactory( organization=self.org) property_details = self.property_state_factory.get_details() self.pm_property_id = '12345' property_details['pm_property_id'] = self.pm_property_id property_details['organization_id'] = self.org.id state = PropertyState(**property_details) state.save() self.state = PropertyState.objects.get(pk=state.id) self.cycle_factory = FakeCycleFactory(organization=self.org, user=self.user) self.cycle = self.cycle_factory.get_cycle( start=datetime(2010, 10, 10, tzinfo=get_current_timezone())) self.property_factory = FakePropertyFactory(organization=self.org) self.property = self.property_factory.get_property() self.property_view = PropertyView.objects.create( property=self.property, cycle=self.cycle, state=self.state) self.tz_obj = timezone(TIME_ZONE)
def merge_state(merged_state, state1, state2, priorities): """ Set attributes on our Canonical model, saving differences. :param merged_state: PropertyState/TaxLotState model inst. :param state1: PropertyState/TaxLotState model inst. Left parent. :param state2: PropertyState/TaxLotState model inst. Right parent. :param priorities: dict, column names with favor new or existing :return: inst(``merged_state``), updated. """ # Calculate the difference between the two states and save into a dictionary can_attrs = get_state_attrs([state1, state2]) default = state2 for attr in can_attrs: # Do we have any differences between these fields? - Check if not None instead of if value. attr_values = [ value for value in list(can_attrs[attr].values()) if value is not None ] attr_values = [v for v in attr_values if v is not None] attr_value = None # Two, differing values are set. if len(attr_values) > 1: # If we have more than one value for this field, choose based on the column priority col_prior = priorities.get(attr, 'Favor New') if col_prior == 'Favor New': attr_value = can_attrs[attr][state2] else: # favor the existing field attr_value = can_attrs[attr][state1] # No values are set elif len(attr_values) < 1: attr_value = None # There is only one value set. else: attr_value = attr_values.pop() if callable(attr): # This callable will be responsible for setting the attribute value, not just returning it. attr(merged_state, default) else: setattr(merged_state, attr, attr_value) merged_state.extra_data = _merge_extra_data(state1.extra_data, state2.extra_data, priorities['extra_data']) # merge measures, scenarios, simulations if isinstance(merged_state, PropertyState): PropertyState.merge_relationships(merged_state, state1, state2) return merged_state
def merge_state(merged_state, state1, state2, can_attrs, default=None): """ Set attributes on our Canonical model, saving differences. :param merged_state: PropertyState/TaxLotState model inst. :param state1: PropertyState/TaxLotState model inst. Left parent. :param state2: PropertyState/TaxLotState model inst. Right parent. :param can_attrs: dict of dicts, {'attr_name': {'dataset1': 'value'...}}. :param default: (optional), which dataset's value to default to. :return: inst(``merged_state``), updated. """ default = default or state2 changes = [] for attr in can_attrs: # Do we have any differences between these fields? - Check if not None instead of if value. attr_values = list( set([ value for value in can_attrs[attr].values() if value is not None ])) attr_values = [v for v in attr_values if v is not None] attr_value = None # Two, differing values are set. if len(attr_values) > 1: # If we have more than one value for this field, save each of the field options in the DB, # but opt for the default when there is a difference. attr_value = can_attrs[attr][default] # No values are set elif len(attr_values) < 1: attr_value = None # There is only one value set. else: attr_value = attr_values.pop() if callable(attr): # This callable will be responsible for setting the attribute value, not just returning it. attr(merged_state, default) else: setattr(merged_state, attr, attr_value) merged_extra_data, merged_extra_data_sources = _merge_extra_data( state1, state2, default=default) merged_state.extra_data = merged_extra_data # merge measures, scenarios, simulations if isinstance(merged_state, PropertyState): PropertyState.merge_relationships(merged_state, state1, state2) return merged_state, changes
def test_hash(self): self.assertEqual( tasks.hash_state_object(PropertyState()), tasks.hash_state_object(PropertyState(organization=self.org))) self.assertEqual( tasks.hash_state_object(TaxLotState()), tasks.hash_state_object(TaxLotState(organization=self.org))) ps1 = PropertyState(address_line_1='123 fake st', extra_data={"a": "100"}) ps2 = PropertyState(address_line_1='123 fake st', extra_data={"a": "200"}) ps3 = PropertyState(extra_data={"a": "200"}) ps4 = PropertyState(extra_data={"a": "100"}) ps5 = PropertyState(address_line_1='123 fake st') self.assertEqual( len(set(map(tasks.hash_state_object, [ps1, ps2, ps3, ps4, ps5]))), 5) # large PropertyState objects -- make sure size is still 32 (why wouldn't it be?) extra_data = {} for i in range(1000): extra_data["entry_%s" % i] = "Value as string %s" % i ps6 = PropertyState(address_line_1='123 fake st', extra_data=extra_data) hash_res = tasks.hash_state_object(ps6) self.assertEqual(len(hash_res), 32)
def setUp(self): self.user_details = { 'username': '******', 'password': '******', } self.user = User.objects.create_superuser(email='*****@*****.**', **self.user_details) self.org, _, _ = create_organization(self.user) self.client.login(**self.user_details) self.property_state_factory = FakePropertyStateFactory( organization=self.org) property_details = self.property_state_factory.get_details() property_details['organization_id'] = self.org.id state_1 = PropertyState(**property_details) state_1.save() self.state_1 = PropertyState.objects.get(pk=state_1.id) self.cycle_factory = FakeCycleFactory(organization=self.org, user=self.user) self.cycle = self.cycle_factory.get_cycle( start=datetime(2010, 10, 10, tzinfo=get_current_timezone())) self.property_factory = FakePropertyFactory(organization=self.org) self.property_1 = self.property_factory.get_property() self.property_view_1 = PropertyView.objects.create( property=self.property_1, cycle=self.cycle, state=self.state_1) self.import_record = ImportRecord.objects.create( owner=self.user, last_modified_by=self.user, super_organization=self.org) filename = "example-GreenButton-data.xml" filepath = os.path.dirname( os.path.abspath(__file__)) + "/data/" + filename self.import_file = ImportFile.objects.create( import_record=self.import_record, source_type="GreenButton", uploaded_filename=filename, file=SimpleUploadedFile(name=filename, content=open(filepath, 'rb').read()), cycle=self.cycle, matching_results_data={"property_id": self.property_1.id}) self.tz_obj = timezone(TIME_ZONE)
def test_hash(self): # tasks.hash_state_object(TaxLotState()) # tasks.hash_state_object(TaxLotState(organization=self.org)) self.assertEqual( tasks.hash_state_object(PropertyState()), tasks.hash_state_object(PropertyState(organization=self.org))) self.assertEqual( tasks.hash_state_object(TaxLotState()), tasks.hash_state_object(TaxLotState(organization=self.org))) ps1 = PropertyState(address_line_1='123 fake st', extra_data={"a": "100"}) ps2 = PropertyState(address_line_1='123 fake st', extra_data={"a": "200"}) ps3 = PropertyState(extra_data={"a": "200"}) ps4 = PropertyState(extra_data={"a": "100"}) ps5 = PropertyState(address_line_1='123 fake st') self.assertEqual( len(set(map(tasks.hash_state_object, [ps1, ps2, ps3, ps4, ps5]))), 5) return
def test_pm_property_id_existing_across_two_different_orgs_wont_lead_to_misassociated_meters( self): new_org, _, _ = create_organization(self.user) property_details = FakePropertyStateFactory( organization=new_org).get_details() property_details['organization_id'] = new_org.id # new state to be associated to property of different organization but has the same pm_property_id property_details['pm_property_id'] = self.state_1.pm_property_id state = PropertyState(**property_details) state.save() new_property_state = PropertyState.objects.get(pk=state.id) new_cycle_factory = FakeCycleFactory(organization=new_org, user=self.user) new_cycle = new_cycle_factory.get_cycle( start=datetime(2010, 10, 10, tzinfo=get_current_timezone())) new_property = self.property_factory.get_property() PropertyView.objects.create(property=new_property, cycle=new_cycle, state=new_property_state) url = reverse("api:v3:import_files-start-save-data", args=[self.import_file.id]) url += f'?organization_id={self.org.pk}' post_params = { 'cycle_id': self.cycle.pk, } self.client.post(url, post_params) # self.property_1 is associated to self.org, so according to post request, it should have 2 meters refreshed_property_1 = Property.objects.get( pk=self.property_1.id, organization_id__exact=self.org.pk) self.assertEqual(refreshed_property_1.meters.all().count(), 2) refreshed_new_property = Property.objects.get(pk=new_property.id) self.assertEqual(refreshed_new_property.meters.count(), 0)
def test_meters_and_readings_are_associated_to_every_record_across_all_cycles_with_a_given_pm_property_id( self): # new, in-cycle state NOT associated to existing record but has same PM Property ID property_details_1 = FakePropertyStateFactory( organization=self.org).get_details() property_details_1['organization_id'] = self.org.id property_details_1['pm_property_id'] = self.state_1.pm_property_id property_details_1['custom_id_1'] = "values that forces non-match" new_property_1 = PropertyState(**property_details_1) new_property_1.save() property_3 = self.property_factory.get_property() PropertyView.objects.create(property=property_3, cycle=self.cycle, state=new_property_1) # new, out-cycle state NOT associated to existing record but has same PM Property ID property_details_2 = FakePropertyStateFactory( organization=self.org).get_details() property_details_2['organization_id'] = self.org.id property_details_2['pm_property_id'] = self.state_1.pm_property_id property_details_2[ 'custom_id_1'] = "second value that forces non-match" new_property_2 = PropertyState(**property_details_2) new_property_2.save() new_cycle = self.cycle_factory.get_cycle( start=datetime(2011, 10, 10, tzinfo=get_current_timezone())) property_4 = self.property_factory.get_property() PropertyView.objects.create(property=property_4, cycle=new_cycle, state=new_property_2) url = reverse("api:v3:import_files-start-save-data", args=[self.import_file.id]) url += f'?organization_id={self.org.pk}' post_params = { 'cycle_id': self.cycle.pk, } self.client.post(url, post_params) refreshed_property_1 = Property.objects.get(pk=self.property_1.id) self.assertEqual(refreshed_property_1.meters.all().count(), 2) refreshed_property_3 = Property.objects.get(pk=property_3.id) self.assertEqual(refreshed_property_3.meters.all().count(), 2) refreshed_property_4 = Property.objects.get(pk=property_4.id) self.assertEqual(refreshed_property_4.meters.all().count(), 2)
def test_coparent(self): # find a state id # get a specific test case with coparents property_state = PropertyState.objects.filter( use_description='Pizza House', import_file_id=self.import_file_2, data_state__in=[DATA_STATE_MAPPING, DATA_STATE_MATCHING], merge_state__in=[MERGE_STATE_UNKNOWN, MERGE_STATE_NEW]).first() coparent, count = PropertyState.coparent(property_state.id) self.assertEqual(count, 1) expected = PropertyState.objects.filter( use_description='Retail', address_line_1=property_state.address_line_1, import_file_id=self.import_file, data_state__in=[DATA_STATE_MAPPING, DATA_STATE_MATCHING], merge_state__in=[MERGE_STATE_UNKNOWN, MERGE_STATE_NEW]).first() self.assertEqual(expected.pk, coparent[0]['id'])
def create_models(data, import_file, cycle): """ Create a PropertyState and a Meter. Then, create TimeSeries models for each meter reading in data. :param data: dict, building data from a Green Button XML file from xml_importer.building_data :param import_file: ImportFile, reference to Green Button XML file :param cycle: Cycle, the cycle from which the property view will be attached :returns: PropertyState """ # cache data on import_file; this is a proof of concept and we # only have two example files available so we hardcode the only # heading present. # NL: Yuck, not sure that this makes much sense here, or anywhere in this method import_file.cached_first_row = ROW_DELIMITER.join(["address"]) import_file.cached_second_to_fifth_row = ROW_DELIMITER.join( [data['address']]) import_file.save() property_state = PropertyState() property_state.import_file = import_file property_state.organization = import_file.import_record.super_organization property_state.address_line_1 = data['address'] property_state.source_type = GREEN_BUTTON_BS # TODO: Green Button Fix -- prob can be removed property_state.save() pv = property_state.promote(cycle) # create meter for this dataset (each dataset is a single energy type) e_type = energy_type(data['service_category']) e_type_string = next(pair[1] for pair in Meter.ENERGY_TYPES if pair[0] == e_type) m_name = "gb_{0}[{1}]".format(str(property_state.id), e_type_string) m_energy_units = energy_units(data['meter']['uom']) meter = Meter.objects.create(name=m_name, energy_type=e_type, energy_units=m_energy_units, property_view=pv) meter.save() # now time series data for the meter for reading in data['interval']['readings']: # how to deal with timezones? start_time = int(reading['start_time']) duration = int(reading['duration']) begin_time = datetime.fromtimestamp(start_time, tz=timezone.get_current_timezone()) end_time = datetime.fromtimestamp(start_time + duration, tz=timezone.get_current_timezone()) value = reading['value'] cost = reading['cost'] new_ts = TimeSeries.objects.create( begin_time=begin_time, end_time=end_time, reading=value, cost=cost, meter=meter, ) new_ts.save() return pv
def merge_state(merged_state, state1, state2, priorities, ignore_merge_protection=False): """ Set attributes on our Canonical model, saving differences. :param merged_state: PropertyState/TaxLotState model inst. :param state1: PropertyState/TaxLotState model inst. Left parent. :param state2: PropertyState/TaxLotState model inst. Right parent. :param priorities: dict, column names with favor new or existing :return: inst(``merged_state``), updated. """ # Calculate the difference between the two states and save into a dictionary can_attrs = get_state_attrs([state1, state2]) # Handle geocoding results first so that recognize_empty logic is not processed on them. _merge_geocoding_results(merged_state, state1, state2, priorities, can_attrs, ignore_merge_protection) recognize_empty_columns = state2.organization.column_set.filter( table_name=state2.__class__.__name__, recognize_empty=True, is_extra_data=False ).values_list('column_name', flat=True) default = state2 for attr in can_attrs: recognize_empty = attr in recognize_empty_columns attr_values = [ value for value in list(can_attrs[attr].values()) if value is not None or recognize_empty ] attr_value = None # Two, differing values are set. if len(attr_values) > 1: # If we have more than one value for this field, choose based on the column priority col_prior = priorities.get(attr, 'Favor New') if ignore_merge_protection or col_prior == 'Favor New': attr_value = can_attrs[attr][state2] else: # favor the existing field attr_value = can_attrs[attr][state1] # No values are set elif len(attr_values) < 1: attr_value = None # There is only one value set. else: attr_value = attr_values.pop() if callable(attr): # This callable will be responsible for setting the attribute value, not just returning it. attr(merged_state, default) else: setattr(merged_state, attr, attr_value) recognize_empty_ed_columns = state2.organization.column_set.filter( table_name=state2.__class__.__name__, recognize_empty=True, is_extra_data=True ).values_list('column_name', flat=True) merged_state.extra_data = _merge_extra_data( state1.extra_data, state2.extra_data, priorities['extra_data'], recognize_empty_ed_columns, ignore_merge_protection ) # merge measures, scenarios, simulations if isinstance(merged_state, PropertyState): PropertyState.merge_relationships(merged_state, state1, state2) return merged_state
def test_parse_meter_details_creates_entries_for_multiple_records_with_same_pm_property_id( self): property_details = self.property_state_factory.get_details() property_details['pm_property_id'] = self.pm_property_id property_details['custom_id_1'] = 'Force unmatched' property_details['organization_id'] = self.org.id state = PropertyState(**property_details) state.save() state_2 = PropertyState.objects.get(pk=state.id) property_2 = self.property_factory.get_property() PropertyView.objects.create(property=property_2, cycle=self.cycle, state=state_2) raw_meters = [{ 'Portfolio Manager ID': self.pm_property_id, 'Portfolio Manager Meter ID': '123-PMMeterID', 'Start Date': '2016-03-01 00:00:00', 'End Date': '2016-04-01 00:00:00', 'Meter Type': 'Electric - Grid', 'Usage Units': 'kBtu (thousand Btu)', 'Usage/Quantity': 100, }, { 'Portfolio Manager ID': self.pm_property_id, 'Portfolio Manager Meter ID': '123-PMMeterID', 'Start Date': '2016-03-01 00:00:00', 'End Date': '2016-04-01 00:00:00', 'Meter Type': 'Natural Gas', 'Usage Units': 'kBtu (thousand Btu)', 'Usage/Quantity': 200, }] expected = [{ 'property_id': self.property.id, 'source': Meter.PORTFOLIO_MANAGER, 'source_id': '123-PMMeterID', 'type': Meter.ELECTRICITY_GRID, 'readings': [{ 'start_time': make_aware(datetime(2016, 3, 1, 0, 0, 0), timezone=self.tz_obj), 'end_time': make_aware(datetime(2016, 4, 1, 0, 0, 0), timezone=self.tz_obj), 'reading': 100, 'source_unit': 'kBtu (thousand Btu)', 'conversion_factor': 1 }] }, { 'property_id': property_2.id, 'source': Meter.PORTFOLIO_MANAGER, 'source_id': '123-PMMeterID', 'type': Meter.ELECTRICITY_GRID, 'readings': [{ 'start_time': make_aware(datetime(2016, 3, 1, 0, 0, 0), timezone=self.tz_obj), 'end_time': make_aware(datetime(2016, 4, 1, 0, 0, 0), timezone=self.tz_obj), 'reading': 100, 'source_unit': 'kBtu (thousand Btu)', 'conversion_factor': 1 }] }, { 'property_id': self.property.id, 'source': Meter.PORTFOLIO_MANAGER, 'source_id': '123-PMMeterID', 'type': Meter.NATURAL_GAS, 'readings': [{ 'start_time': make_aware(datetime(2016, 3, 1, 0, 0, 0), timezone=self.tz_obj), 'end_time': make_aware(datetime(2016, 4, 1, 0, 0, 0), timezone=self.tz_obj), 'reading': 200, 'source_unit': 'kBtu (thousand Btu)', 'conversion_factor': 1 }] }, { 'property_id': property_2.id, 'source': Meter.PORTFOLIO_MANAGER, 'source_id': '123-PMMeterID', 'type': Meter.NATURAL_GAS, 'readings': [{ 'start_time': make_aware(datetime(2016, 3, 1, 0, 0, 0), timezone=self.tz_obj), 'end_time': make_aware(datetime(2016, 4, 1, 0, 0, 0), timezone=self.tz_obj), 'reading': 200, 'source_unit': 'kBtu (thousand Btu)', 'conversion_factor': 1 }] }] meters_parser = MetersParser(self.org.id, raw_meters) self.assertEqual(meters_parser.meter_and_reading_objs, expected)
def test_the_response_contains_expected_and_actual_reading_counts_by_property_id_even_in_the_same_cycle( self): property_details = FakePropertyStateFactory( organization=self.org).get_details() property_details['organization_id'] = self.org.id # Create new state NOT associated to existing record but has same PM Property ID property_details['pm_property_id'] = self.state_1.pm_property_id property_details['custom_id_1'] = "values that forces non-match" state = PropertyState(**property_details) state.save() new_property_state = PropertyState.objects.get(pk=state.id) # new state in cycle associated to old property property_3 = self.property_factory.get_property() PropertyView.objects.create(property=property_3, cycle=self.cycle, state=new_property_state) url = reverse("api:v3:import_files-start-save-data", args=[self.import_file.id]) url += f'?organization_id={self.org.pk}' post_params = { 'cycle_id': self.cycle.pk, } response = self.client.post(url, post_params) result = json.loads(response.content) expectation = [ { "property_id": self.property_1.id, "cycles": self.cycle.name, "pm_property_id": "5766973", "source_id": "5766973-0", "type": "Electric - Grid", "incoming": 2, "successfully_imported": 2, }, { "property_id": property_3.id, "cycles": self.cycle.name, "pm_property_id": "5766973", "source_id": "5766973-0", "type": "Electric - Grid", "incoming": 2, "successfully_imported": 2, }, { "property_id": self.property_1.id, "cycles": self.cycle.name, "pm_property_id": "5766973", "source_id": "5766973-1", "type": "Natural Gas", "incoming": 2, "successfully_imported": 2, }, { "property_id": property_3.id, "cycles": self.cycle.name, "pm_property_id": "5766973", "source_id": "5766973-1", "type": "Natural Gas", "incoming": 2, "successfully_imported": 2, }, { "property_id": self.property_2.id, "cycles": self.cycle.name, "pm_property_id": "5766975", "source_id": "5766975-0", "type": "Electric - Grid", "incoming": 2, "successfully_imported": 2, }, { "property_id": self.property_2.id, "cycles": self.cycle.name, "pm_property_id": "5766975", "source_id": "5766975-1", "type": "Natural Gas", "incoming": 2, "successfully_imported": 2, }, ] self.assertCountEqual(result['message'], expectation)
def test_the_response_contains_expected_and_actual_reading_counts_across_cycles_for_linked_properties( self): property_details = FakePropertyStateFactory( organization=self.org).get_details() property_details['organization_id'] = self.org.id # new state will be linked to existing record and has same PM Property ID property_details['pm_property_id'] = self.state_1.pm_property_id state = PropertyState(**property_details) state.save() new_property_state = PropertyState.objects.get(pk=state.id) new_cycle = self.cycle_factory.get_cycle( start=datetime(2011, 10, 10, tzinfo=get_current_timezone())) PropertyView.objects.create(property=self.property_1, cycle=new_cycle, state=new_property_state) url = reverse("api:v3:import_files-start-save-data", args=[self.import_file.id]) url += f'?organization_id={self.org.pk}' post_params = { 'cycle_id': self.cycle.pk, } response = self.client.post(url, post_params) result = json.loads(response.content) expectation = [ { "property_id": self.property_1.id, "cycles": self.cycle.name + ", " + new_cycle.name, "pm_property_id": "5766973", "source_id": "5766973-0", "type": "Electric - Grid", "incoming": 2, "successfully_imported": 2, }, { "property_id": self.property_1.id, "cycles": self.cycle.name + ", " + new_cycle.name, "pm_property_id": "5766973", "source_id": "5766973-1", "type": "Natural Gas", "incoming": 2, "successfully_imported": 2, }, { "property_id": self.property_2.id, "cycles": self.cycle.name, "pm_property_id": "5766975", "source_id": "5766975-0", "type": "Electric - Grid", "incoming": 2, "successfully_imported": 2, }, { "property_id": self.property_2.id, "cycles": self.cycle.name, "pm_property_id": "5766975", "source_id": "5766975-1", "type": "Natural Gas", "incoming": 2, "successfully_imported": 2, }, ] self.assertCountEqual(result['message'], expectation)
def setUp(self): self.user_details = { 'username': '******', 'password': '******', } self.user = User.objects.create_superuser(email='*****@*****.**', **self.user_details) self.org, _, _ = create_organization(self.user) self.client.login(**self.user_details) self.property_state_factory = FakePropertyStateFactory( organization=self.org) property_details = self.property_state_factory.get_details() property_details['organization_id'] = self.org.id # pm_property_ids must match those within example-monthly-meter-usage.xlsx self.pm_property_id_1 = '5766973' self.pm_property_id_2 = '5766975' property_details['pm_property_id'] = self.pm_property_id_1 state_1 = PropertyState(**property_details) state_1.save() self.state_1 = PropertyState.objects.get(pk=state_1.id) property_details['pm_property_id'] = self.pm_property_id_2 state_2 = PropertyState(**property_details) state_2.save() self.state_2 = PropertyState.objects.get(pk=state_2.id) self.cycle_factory = FakeCycleFactory(organization=self.org, user=self.user) self.cycle = self.cycle_factory.get_cycle( start=datetime(2010, 10, 10, tzinfo=get_current_timezone())) self.property_factory = FakePropertyFactory(organization=self.org) self.property_1 = self.property_factory.get_property() self.property_2 = self.property_factory.get_property() self.property_view_1 = PropertyView.objects.create( property=self.property_1, cycle=self.cycle, state=self.state_1) self.property_view_2 = PropertyView.objects.create( property=self.property_2, cycle=self.cycle, state=self.state_2) self.import_record = ImportRecord.objects.create( owner=self.user, last_modified_by=self.user, super_organization=self.org) # This file has multiple tabs filename = "example-pm-monthly-meter-usage.xlsx" filepath = os.path.dirname( os.path.abspath(__file__)) + "/data/" + filename self.import_file = ImportFile.objects.create( import_record=self.import_record, source_type="PM Meter Usage", uploaded_filename=filename, file=SimpleUploadedFile(name=filename, content=open(filepath, 'rb').read()), cycle=self.cycle) self.tz_obj = timezone(TIME_ZONE)