コード例 #1
0
 def retrieve(self, request, pk=None):
     """
     Get property details
     ---
     parameters:
         - name: pk
           description: The primary key of the PropertyView
           required: true
           paramType: path
         - name: organization_id
           description: The organization_id for this user's organization
           required: true
           paramType: query
     """
     result = self._get_property_view(pk)
     if result.get('status', None) != 'error':
         property_view = result.pop('property_view')
         result = {'status': 'success'}
         result.update(PropertyViewSerializer(property_view).data)
         # remove PropertyView id from result
         result.pop('id')
         result['state'] = PropertyStateSerializer(property_view.state).data
         result['taxlots'] = self._get_taxlots(property_view.pk)
         result['history'], master = self.get_history(property_view)
         result = update_result_with_master(result, master)
         return JsonResponse(result,
                             encoder=PintJSONEncoder,
                             status=status.HTTP_200_OK)
     else:
         return JsonResponse(result)
コード例 #2
0
 def retrieve(self, request, pk=None):
     """
     Get property details
     ---
     parameters:
         - name: cycle_id
           description: The cycle id for filtering the property view
           required: true
           paramType: query
         - name: organization_id
           description: The organization_id for this user's organization
           required: true
           paramType: query
     """
     cycle_pk = request.query_params.get('cycle_id', None)
     if not cycle_pk:
         return JsonResponse(
             {'status': 'error', 'message': 'Must pass in cycle_id as query parameter'})
     result = self._get_property_view(pk, cycle_pk)
     if result.get('status', None) != 'error':
         property_view = result.pop('property_view')
         result.update(PropertyViewSerializer(property_view).data)
         # remove PropertyView id from result
         result.pop('id')
         result['state'] = PropertyStateSerializer(property_view.state).data
         result['taxlots'] = self._get_taxlots(property_view.pk)
         result['history'], master = self.get_history(property_view)
         result = update_result_with_master(result, master)
         status_code = status.HTTP_200_OK
     else:
         status_code = status.HTTP_404_NOT_FOUND
     return Response(result, status=status_code)
コード例 #3
0
    def get_history(self, property_view):
        """Return history in reverse order"""

        # access the history from the property state
        history, master = property_view.state.history()

        # convert the history and master states to StateSerializers
        master['state'] = PropertyStateSerializer(master['state_data']).data
        del master['state_data']
        del master['state_id']

        for h in history:
            h['state'] = PropertyStateSerializer(h['state_data']).data
            del h['state_data']
            del h['state_id']

        return history, master
コード例 #4
0
class AnalysisPropertyViewSerializer(serializers.ModelSerializer):
    output_files = AnalysisOutputFileSerializer(
        source='analysisoutputfile_set', many=True)
    property_state = PropertyStateSerializer()

    class Meta:
        model = AnalysisPropertyView
        fields = '__all__'
コード例 #5
0
 def record_dict(log):
     filename = None if not log.import_filename else path.basename(log.import_filename)
     if filename:
         # Attempt to remove NamedTemporaryFile suffix
         name, ext = path.splitext(filename)
         pattern = re.compile('(.*?)(_[a-zA-Z0-9]{7})$')
         match = pattern.match(name)
         if match:
             filename = match.groups()[0] + ext
     return {
         'state': PropertyStateSerializer(log.state).data,
         'date_edited': convert_to_js_timestamp(log.created),
         'source': log.get_record_type_display(),
         'filename': filename,
         # 'changed_fields': json.loads(log.description) if log.record_type == AUDIT_USER_EDIT else None
     }
コード例 #6
0
    def retrieve(self, request, pk=None):
        """
        Get property details
        ---
        parameters:
            - name: pk
              description: The primary key of the PropertyView
              required: true
              paramType: path
            - name: organization_id
              description: The organization_id for this user's organization
              required: true
              paramType: query
        """
        result = self._get_property_view(pk)
        if result.get('status', None) != 'error':
            property_view = result.pop('property_view')
            result = {'status': 'success'}
            result.update(PropertyViewSerializer(property_view).data)
            # remove PropertyView id from result
            result.pop('id')

            # Grab extra_data columns to be shown in the result
            organization_id = request.query_params['organization_id']
            all_extra_data_columns = Column.objects.filter(
                organization_id=organization_id,
                is_extra_data=True,
                table_name='PropertyState').values_list('column_name',
                                                        flat=True)

            result['state'] = PropertyStateSerializer(
                property_view.state,
                all_extra_data_columns=all_extra_data_columns).data
            result['taxlots'] = self._get_taxlots(property_view.pk)
            result['history'], master = self.get_history(property_view)
            result = update_result_with_master(result, master)
            return JsonResponse(result,
                                encoder=PintJSONEncoder,
                                status=status.HTTP_200_OK)
        else:
            return JsonResponse(result)
コード例 #7
0
    def update(self, request, pk=None):
        """
        Update a property
        ---
        parameters:
            - name: cycle_id
              description: The cycle id for filtering the property view
              required: true
              paramType: query
        """
        cycle_pk = request.query_params.get('cycle_id', None)
        if not cycle_pk:
            return JsonResponse({
                'status':
                'error',
                'message':
                'Must pass in cycle_id as query parameter'
            })
        data = request.data
        result = self._get_property_view(pk, cycle_pk)
        if result.get('status', None) != 'error':
            property_view = result.pop('property_view')
            property_state_data = PropertyStateSerializer(
                property_view.state).data
            new_property_state_data = data['state']

            changed = True
            for key, val in new_property_state_data.iteritems():
                if val == '':
                    new_property_state_data[key] = None
            changed_fields = get_changed_fields(property_state_data,
                                                new_property_state_data)
            if not changed_fields:
                changed = False
            if not changed:
                result.update({
                    'status': 'error',
                    'message': 'Nothing to update'
                })
                status_code = 422  # status.HTTP_422_UNPROCESSABLE_ENTITY
            else:
                log = PropertyAuditLog.objects.select_related().filter(
                    state=property_view.state).order_by('-id').first()

                if 'extra_data' in new_property_state_data.keys():
                    property_state_data['extra_data'].update(
                        new_property_state_data.pop('extra_data'))
                property_state_data.update(new_property_state_data)

                if log.name == 'Import Creation':
                    # Add new state
                    property_state_data.pop('id')
                    new_property_state_serializer = PropertyStateSerializer(
                        data=property_state_data)
                    if new_property_state_serializer.is_valid():
                        new_state = new_property_state_serializer.save()
                        property_view.state = new_state
                        property_view.save()

                        PropertyAuditLog.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_property_state_serializer.validated_data
                        })
                        # Removing organization key AND import_file key because they're not JSON-serializable
                        # TODO find better solution
                        if 'organization' in result['state']:
                            result['state'].pop('organization')
                        if 'import_file' in result['state']:
                            result['state'].pop('import_file')
                        status_code = status.HTTP_201_CREATED
                    else:
                        result.update({
                            'status': 'error',
                            'message': 'Invalid Data'
                        })
                        status_code = 422  # status.HTTP_422_UNPROCESSABLE_ENTITY
                elif log.name in [
                        'Manual Edit', 'Manual Match', 'System Match',
                        'Merge current state in migration'
                ]:
                    # Override previous edit state or merge state
                    state = property_view.state
                    for key, value in new_property_state_data.iteritems():
                        setattr(state, key, value)
                    state.save()

                    result.update(
                        {'state': PropertyStateSerializer(state).data})
                    # Removing organization key AND import_file key because they're not JSON-serializable
                    # TODO find better solution
                    result['state'].pop('organization')
                    result['state'].pop('import_file')

                    status_code = status.HTTP_201_CREATED
                else:
                    result = {
                        'status': 'error',
                        'message': 'Unrecognized audit log name: ' + log.name
                    }
                    status_code = 422
                    return JsonResponse(result, status=status_code)

        else:
            status_code = status.HTTP_404_NOT_FOUND
        return JsonResponse(result, status=status_code)
コード例 #8
0
    def get_history(self, property_view):
        """Return history in reverse order."""
        history = []

        def record_dict(log):
            filename = None if not log.import_filename else path.basename(
                log.import_filename)
            if filename:
                # Attempt to remove NamedTemporaryFile suffix
                name, ext = path.splitext(filename)
                pattern = re.compile('(.*?)(_[a-zA-Z0-9]{7})$')
                match = pattern.match(name)
                if match:
                    filename = match.groups()[0] + ext
            return {
                'state': PropertyStateSerializer(log.state).data,
                'date_edited': convert_to_js_timestamp(log.created),
                'source': log.get_record_type_display(),
                'filename': filename,
                # 'changed_fields': json.loads(log.description) if log.record_type == AUDIT_USER_EDIT else None
            }

        log = PropertyAuditLog.objects.select_related(
            'state', 'parent1', 'parent2').filter(
                state_id=property_view.state_id).order_by('-id').first()
        master = {
            'state': PropertyStateSerializer(log.state).data,
            'date_edited': convert_to_js_timestamp(log.created),
        }

        # Traverse parents and add to history
        if log.name in [
                'Manual Match', 'System Match',
                'Merge current state in migration'
        ]:
            done_searching = False
            while not done_searching:
                if (log.parent1_id is None and
                        log.parent2_id is None) or log.name == 'Manual Edit':
                    done_searching = True
                elif log.name == 'Merge current state in migration':
                    record = record_dict(log.parent1)
                    history.append(record)
                    if log.parent1.name == 'Import Creation':
                        done_searching = True
                    else:
                        tree = log.parent1
                        log = tree
                else:
                    tree = None
                    if log.parent2:
                        if log.parent2.name in [
                                'Import Creation', 'Manual Edit'
                        ]:
                            record = record_dict(log.parent2)
                            history.append(record)
                        elif log.parent2.name == 'System Match' and log.parent2.parent1.name == 'Import Creation' and \
                                log.parent2.parent2.name == 'Import Creation':
                            # Handle case where an import file matches within itself, and proceeds to match with
                            # existing records
                            record = record_dict(log.parent2.parent2)
                            history.append(record)
                            record = record_dict(log.parent2.parent1)
                            history.append(record)
                        else:
                            tree = log.parent2
                    if log.parent1.name in ['Import Creation', 'Manual Edit']:
                        record = record_dict(log.parent1)
                        history.append(record)
                    else:
                        tree = log.parent1

                    if not tree:
                        done_searching = True
                    else:
                        log = tree
        elif log.name == 'Manual Edit':
            record = record_dict(log.parent1)
            history.append(record)
        elif log.name == 'Import Creation':
            record = record_dict(log)
            history.append(record)

        return history, master
コード例 #9
0
    def update(self, request, pk=None):
        """
        Update a property and run the updated record through a match and merge
        round within it's current Cycle.

        - looks up the property view
        - casts it as a PropertyState
        - builds a hash with all the same keys as the original property state
        - checks if any fields have changed
        - if nothing has changed, return 422 - Really?  Not sure how I feel about that one, it *is* processable
        - get the property audit log for this property state
        - if the new property state has extra_data, the original extra_data is update'd
        - and then whoa stuff about the audit log?
        - I'm going to assume 'Import Creation' is the key I'm looking for
        - create a serializer for the new property state
        - if it's valid, save this new serialized data to the db
        - assign it to the original property view and save the property view
        - create a new property audit log for this change
        - return a 200 if created

        ---
        parameters:
            - name: organization_id
              description: The organization_id for this user's organization
              required: true
              paramType: query
        """
        data = request.data

        result = self._get_property_view(pk)
        if result.get('status', None) != 'error':
            property_view = result.pop('property_view')
            property_state_data = PropertyStateSerializer(
                property_view.state).data

            # get the property state information from the request
            new_property_state_data = data['state']

            # set empty strings to None
            for key, val in new_property_state_data.items():
                if val == '':
                    new_property_state_data[key] = None

            changed_fields = get_changed_fields(property_state_data,
                                                new_property_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 = PropertyAuditLog.objects.select_related().filter(
                    state=property_view.state).order_by('-id').first()

                if 'extra_data' in new_property_state_data:
                    property_state_data['extra_data'].update(
                        new_property_state_data.pop('extra_data'))
                property_state_data.update(new_property_state_data)

                if log.name == 'Import Creation':
                    # Add new state by removing the existing ID.
                    property_state_data.pop('id')
                    new_property_state_serializer = PropertyStateSerializer(
                        data=property_state_data)
                    if new_property_state_serializer.is_valid():
                        # create the new property state, and perform an initial save / moving relationships
                        new_state = new_property_state_serializer.save()

                        # Since we are creating a new relationship when we are manually editing the Properties, then
                        # we need to move the relationships over to the new manually edited record.
                        new_state = self._move_relationships(
                            property_view.state, new_state)
                        new_state.save()

                        # then assign this state to the property view and save the whole view
                        property_view.state = new_state
                        property_view.save()

                        PropertyAuditLog.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_property_state_serializer.data})

                        # save the property view so that the datetime gets updated on the property.
                        property_view.save()

                        count, view_id = match_merge_in_cycle(
                            property_view.id, 'PropertyState')

                        if view_id is not None:
                            result.update({
                                'view_id': view_id,
                                'match_merged_count': count,
                            })

                        return JsonResponse(result,
                                            encoder=PintJSONEncoder,
                                            status=status.HTTP_200_OK)
                    else:
                        result.update({
                            'status':
                            'error',
                            'message':
                            'Invalid update data with errors: {}'.format(
                                new_property_state_serializer.errors)
                        })
                        return JsonResponse(
                            result,
                            encoder=PintJSONEncoder,
                            status=status.HTTP_422_UNPROCESSABLE_ENTITY)
                elif 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_property_state_serializer = PropertyStateSerializer(
                        property_view.state, data=property_state_data)
                    if updated_property_state_serializer.is_valid():
                        # create the new property state, and perform an initial save / moving
                        # relationships
                        updated_property_state_serializer.save()

                        result.update(
                            {'state': updated_property_state_serializer.data})

                        # save the property view so that the datetime gets updated on the property.
                        property_view.save()

                        count, view_id = match_merge_in_cycle(
                            property_view.id, 'PropertyState')

                        if view_id is not None:
                            result.update({
                                'view_id': view_id,
                                'match_merged_count': count,
                            })

                        return JsonResponse(result,
                                            encoder=PintJSONEncoder,
                                            status=status.HTTP_200_OK)
                    else:
                        result.update({
                            'status':
                            'error',
                            'message':
                            'Invalid update data with errors: {}'.format(
                                updated_property_state_serializer.errors)
                        })
                        return JsonResponse(
                            result,
                            encoder=PintJSONEncoder,
                            status=status.HTTP_422_UNPROCESSABLE_ENTITY)
                else:
                    result = {
                        'status': 'error',
                        'message': 'Unrecognized audit log name: ' + log.name
                    }
                    return JsonResponse(
                        result, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        else:
            return JsonResponse(result, status=status.HTTP_404_NOT_FOUND)