def match_merge_link(self, request, pk=None): """ Runs match merge link for an individual taxlot. Note that this method can return a view_id of None if the given -View was not involved in a merge. """ merge_count, link_count, view_id = match_merge_link(pk, 'TaxLotState') result = { 'view_id': view_id, 'match_merged_count': merge_count, 'match_link_count': link_count, } return JsonResponse(result)
def merge(self, request): """ Merge multiple tax lot records into a single new record, and run this new record through a match and merge round within it's current Cycle. """ body = request.data organization_id = int(request.query_params.get('organization_id', None)) taxlot_view_ids = body.get('taxlot_view_ids', []) taxlot_states = TaxLotView.objects.filter( id__in=taxlot_view_ids, cycle__organization_id=organization_id ).values('id', 'state_id') # get the state ids in order according to the given view ids taxlot_states_dict = {t['id']: t['state_id'] for t in taxlot_states} taxlot_state_ids = [ taxlot_states_dict[view_id] for view_id in taxlot_view_ids if view_id in taxlot_states_dict ] if len(taxlot_state_ids) != len(taxlot_view_ids): return { 'status': 'error', 'message': 'All records not found.' } # Check the number of taxlot_state_ids to merge if len(taxlot_state_ids) < 2: return JsonResponse({ 'status': 'error', 'message': 'At least two ids are necessary to merge' }, status=status.HTTP_400_BAD_REQUEST) merged_state = merge_taxlots(taxlot_state_ids, organization_id, 'Manual Match') merge_count, link_count, view_id = match_merge_link(merged_state.taxlotview_set.first().id, 'TaxLotState') result = { 'status': 'success' } result.update({ 'match_merged_count': merge_count, 'match_link_count': link_count, }) return result
def merge(self, request): """ Merge multiple tax lot records into a single new record, and run this new record through a match and merge round within it's current Cycle. --- parameters: - name: organization_id description: The organization_id for this user's organization required: true paramType: query - name: state_ids description: Array containing tax lot state ids to merge paramType: body """ body = request.data state_ids = body.get('state_ids', []) organization_id = int(request.query_params.get('organization_id', None)) # Check the number of state_ids to merge if len(state_ids) < 2: return JsonResponse( { 'status': 'error', 'message': 'At least two ids are necessary to merge' }, status=status.HTTP_400_BAD_REQUEST) merged_state = merge_taxlots(state_ids, organization_id, 'Manual Match') merge_count, link_count, view_id = match_merge_link( merged_state.taxlotview_set.first().id, 'TaxLotState') result = {'status': 'success'} result.update({ 'match_merged_count': merge_count, 'match_link_count': link_count, }) return result
def match_merge_link(self, request, pk=None): """ Runs match merge link for an individual taxlot. Note that this method can return a view_id of None if the given -View was not involved in a merge. """ org_id = request.query_params.get('organization_id', None) taxlot_view = TaxLotView.objects.get( pk=pk, cycle__organization_id=org_id ) merge_count, link_count, view_id = match_merge_link(taxlot_view.pk, 'TaxLotState') result = { 'view_id': view_id, 'match_merged_count': merge_count, 'match_link_count': link_count, } return JsonResponse(result)
def link_views(merged_views, ViewClass): """ Run each of the given -Views through a linking round. For details on the actual linking logic, please refer to the the match_merge_link() method. """ if ViewClass == PropertyView: state_class_name = "PropertyState" else: state_class_name = "TaxLotState" processed_views = [] for view in merged_views: _merge_count, _link_count, view_id = match_merge_link( view.id, state_class_name) if view_id is not None: processed_views.append(ViewClass.objects.get(pk=view_id)) else: processed_views.append(view) return processed_views
def update(self, request, pk): """ Update a taxlot and run the updated record through a match and merge round within it's current Cycle. --- parameters: - name: organization_id description: The organization_id for this user's organization required: true paramType: query """ data = request.data result = self._get_taxlot_view(pk) if result.get('status', 'error') != 'error': taxlot_view = result.pop('taxlot_view') taxlot_state_data = TaxLotStateSerializer(taxlot_view.state).data # get the taxlot state information from the request new_taxlot_state_data = data['state'] # set empty strings to None for key, val in new_taxlot_state_data.items(): if val == '': new_taxlot_state_data[key] = None changed_fields, previous_data = get_changed_fields( taxlot_state_data, new_taxlot_state_data) if not changed_fields: result.update({ 'status': 'success', 'message': 'Records are identical' }) return JsonResponse(result, status=status.HTTP_204_NO_CONTENT) else: # Not sure why we are going through the pain of logging this all right now... need to # reevaluate this. log = TaxLotAuditLog.objects.select_related().filter( state=taxlot_view.state).order_by('-id').first() # if checks above pass, create an exact copy of the current state for historical purposes if log.name == 'Import Creation': # Add new state by removing the existing ID. taxlot_state_data.pop('id') # Remove the import_file_id for the first edit of a new record # If the import file has been deleted and this value remains the serializer won't be valid taxlot_state_data.pop('import_file') new_taxlot_state_serializer = TaxLotStateSerializer( data=taxlot_state_data) if new_taxlot_state_serializer.is_valid(): # create the new property state, and perform an initial save / moving relationships new_state = new_taxlot_state_serializer.save() # then assign this state to the property view and save the whole view taxlot_view.state = new_state taxlot_view.save() TaxLotAuditLog.objects.create( organization=log.organization, parent1=log, parent2=None, parent_state1=log.state, parent_state2=None, state=new_state, name='Manual Edit', description=None, import_filename=log.import_filename, record_type=AUDIT_USER_EDIT) result.update( {'state': new_taxlot_state_serializer.data}) # save the property view so that the datetime gets updated on the property. taxlot_view.save() else: result.update({ 'status': 'error', 'message': 'Invalid update data with errors: {}'.format( new_taxlot_state_serializer.errors) }) return JsonResponse( result, status=status.HTTP_422_UNPROCESSABLE_ENTITY) # redo assignment of this variable in case this was an initial edit taxlot_state_data = TaxLotStateSerializer( taxlot_view.state).data if 'extra_data' in new_taxlot_state_data: taxlot_state_data['extra_data'].update( new_taxlot_state_data['extra_data']) taxlot_state_data.update({ k: v for k, v in new_taxlot_state_data.items() if k != 'extra_data' }) log = TaxLotAuditLog.objects.select_related().filter( state=taxlot_view.state).order_by('-id').first() if log.name in [ 'Manual Edit', 'Manual Match', 'System Match', 'Merge current state in migration' ]: # Convert this to using the serializer to save the data. This will override the # previous values in the state object. # Note: We should be able to use partial update here and pass in the changed # fields instead of the entire state_data. updated_taxlot_state_serializer = TaxLotStateSerializer( taxlot_view.state, data=taxlot_state_data) if updated_taxlot_state_serializer.is_valid(): # create the new property state, and perform an initial save / moving # relationships updated_taxlot_state_serializer.save() result.update( {'state': updated_taxlot_state_serializer.data}) # save the property view so that the datetime gets updated on the property. taxlot_view.save() Note.create_from_edit(request.user.id, taxlot_view, new_taxlot_state_data, previous_data) merge_count, link_count, view_id = match_merge_link( taxlot_view.id, 'TaxLotState') result.update({ 'view_id': view_id, 'match_merged_count': merge_count, 'match_link_count': link_count, }) return JsonResponse(result, status=status.HTTP_200_OK) else: result.update({ 'status': 'error', 'message': 'Invalid update data with errors: {}'.format( updated_taxlot_state_serializer.errors) }) return JsonResponse( result, status=status.HTTP_422_UNPROCESSABLE_ENTITY) else: result = { 'status': 'error', 'message': 'Unrecognized audit log name: ' + log.name } return JsonResponse(result, status=status.HTTP_204_NO_CONTENT) else: return JsonResponse(result, status=status.HTTP_404_NOT_FOUND)