Exemple #1
0
    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)
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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)
Exemple #5
0
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
Exemple #6
0
    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)