# -*- coding: utf-8 -*-

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import uuid

from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
from django.test import TestCase
from ralph.cmdb.tests.utils import CIRelationFactory
from ralph.discovery.tests.util import DeviceFactory

from ralph_assets.licences.models import (
    AssetType,
    Licence,
)
from ralph_assets.models_assets import Asset
from ralph_assets.tests.utils import (
    ClientMixin,
)
from ralph_assets.tests.utils.assets import (
    BOAssetFactory,
    DCAssetFactory,
)
from ralph_assets.tests.utils.licences import (
    LicenceFactory,
)


class TestImport(ClientMixin, TestCase):
    # TODO: merge it with TestDataImporter?
    def setUp(self):
        self.login_as_superuser()
        self.url = reverse('xls_upload')

    def _update_asset_by_csv(self, asset, field, value):
        self.client.get(self.url)
        csv_data = '"id","{}"\n"{}","{}"'.format(field, asset.id, value)

        step1_post = {
            'upload-asset_type': AssetType.back_office.id,
            'upload-model': 'ralph_assets.asset',
            'upload-file': SimpleUploadedFile('test.csv', csv_data),
            'xls_upload_view-current_step': 'upload',
        }
        response = self.client.post(self.url, step1_post)
        self.assertContains(response, 'column_choice')
        self.assertContains(response, 'step 2/3')

        step2_post = {
            'column_choice-%s' % field: field,
            'xls_upload_view-current_step': 'column_choice',
        }
        response = self.client.post(self.url, step2_post)
        self.assertContains(response, 'step 3/3')

        step3_post = {
            'xls_upload_view-current_step': 'confirm',
        }
        response = self.client.post(self.url, step3_post)
        self.assertContains(response, 'Import done')

    def test_import_csv_asset_back_office_update(self):
        self.client.get(self.url)
        asset = BOAssetFactory()

        for field in [
            'barcode', 'invoice_no', 'order_no', 'sn', 'remarks', 'niw'
        ]:
            new_value = str(uuid.uuid1())
            self._update_asset_by_csv(asset, field, new_value)
            updated_asset = Asset.objects.get(id=asset.id)
            self.assertEqual(
                getattr(updated_asset, field), new_value
            )


class TestDataImporter(object):
    SEP = ','
    upload_model = None
    upload_asset_type = None
    Model = None
    ModelFactory = None
    base_excluded_fields = set()

    def setUp(self):
        self.login_as_superuser()
        self.url = reverse('xls_upload')
        self.excluded_fields = self.base_excluded_fields.copy()

    def _fields2choices(self, fields):
        return {'column_choice-{}'.format(f): f for f in fields}

    def _format_row(self, row):
        return self.SEP.join(['"{}"'.format(item) for item in row])

    def _get_csv_string(self, cols, vals):
        header = self._format_row(cols)
        rows_string = '\n'.join([self._format_row(row) for row in vals])
        csv_string = '\n'.join([header, rows_string])
        return csv_string

    def _get_csv_data(self, important_data={}, use_existing=True):
        """
        Return dict, where:
            *keys* are names of model fields (model is set by
                self.ModelFactory)
            *values* are just field values of model, unless field is foreign
                key. If so then *name* of related object is taken.
            Example:
                modelFactory = Asset, field = price:
                    {'price', Asset.price}
                modelFactory = Asset, field = warehouse:
                    {'warehouse', Asset.warehouse.name}
        """
        csv_data = {}
        obj = self.ModelFactory()
        for field in obj._meta.fields:
            if field.name in self.excluded_fields:
                continue
            field_value = getattr(obj, field.name)
            if field.rel:
                # foreign key, so get as string
                field_value = field_value.name
                if not use_existing:
                    field_value += '-new'
            csv_data[field.name] = field_value
        obj.delete()
        if not important_data:
            important_data = {}
        csv_data.update(important_data)
        return csv_data

    def _check_form_errors(self, response, step):
        errors = getattr(response.context['wizard']['form'], 'errors', None)
        msg = 'step {step} failed, form errors: {form_errors!r}'.format(
            form_errors=errors, step=step,
        )
        self.assertFalse(errors, msg)

    def _import_by_csv(self, fields, values):
        self.client.get(self.url)
        csv_string = self._get_csv_string(fields, values)

        step1_post = {
            'upload-asset_type': self.upload_asset_type,
            'upload-model': self.upload_model,
            'upload-file': SimpleUploadedFile('test.csv', csv_string),
            'xls_upload_view-current_step': 'upload',
        }
        response = self.client.post(self.url, step1_post)
        self._check_form_errors(response, step=1)
        self.assertContains(response, 'column_choice')
        self.assertContains(response, 'step 2/3')

        step2_post = {
            'xls_upload_view-current_step': 'column_choice',
        }
        step2_post.update(self._fields2choices(fields))
        response = self.client.post(self.url, step2_post)
        self._check_form_errors(response, step=2)
        self.assertContains(response, 'step 3/3')

        step3_post = {
            'xls_upload_view-current_step': 'confirm',
        }
        response = self.client.post(self.url, step3_post)
        self._check_form_errors(response, step=3)
        self.assertContains(response, 'Import done')

    def _check_object_against_csv(self, obj, csv_data):
        for field_name, csv_value in csv_data.iteritems():
            obj_value = getattr(obj, field_name)
            if hasattr(obj_value, 'name'):
                obj_value = getattr(obj, field_name).name
            msg = 'Incorrect field {!r} value {!r} != {!r}'.format(
                field_name, obj_value, csv_value,
            )
            self.assertEqual(obj_value, csv_value, msg)

    def test_add_by_import(self):
        """
        Uses existing foreign fields.
        """
        csv_data = self._get_csv_data()
        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        csv_data = self._get_csv_data(use_existing=False)
        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import(self):
        """
        Uses existing foreign fields.
        """
        self.excluded_fields.remove('id')
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(important_data={'id': updated_obj.id})

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)


class TestLicenceDataImporter(TestDataImporter, ClientMixin, TestCase):

    upload_model = 'ralph_assets.licence'
    upload_asset_type = AssetType.back_office.id
    Model = Licence
    ModelFactory = LicenceFactory
    base_excluded_fields = set([
        'cache_version', 'created', 'id', 'level', 'lft', 'modified',
        'parent', 'rght', 'saving_user', 'tree_id',
    ])

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.update(['region'])
        csv_data = self._get_csv_data(use_existing=False)

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        self.excluded_fields.update(['region'])

        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)


class TestBOAssetDataImporter(TestDataImporter, ClientMixin, TestCase):

    upload_model = 'ralph_assets.asset'
    upload_asset_type = AssetType.back_office.id
    Model = Asset
    ModelFactory = BOAssetFactory
    base_excluded_fields = set([
        'cache_version', 'created', 'device_info', 'id', 'modified', 'note',
        'modified_by', 'part_info', 'saving_user', 'support_price',
        'support_period', 'support_type', 'support_void_reporting',
        # these ones can't be created through import
        'created_by', 'owner', 'user',
        # TODO: add|extend-existing test for office_info crap and remove it
        'office_info',
    ])

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        csv_data = self._get_csv_data(use_existing=False)

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)


class TestDCAssetDataImporter(TestDataImporter, ClientMixin, TestCase):

    upload_model = 'ralph_assets.asset'
    upload_asset_type = AssetType.data_center.id
    Model = Asset
    ModelFactory = DCAssetFactory
    base_excluded_fields = set([
        'cache_version', 'created', 'office_info', 'id', 'modified', 'note',
        'modified_by', 'part_info', 'saving_user', 'support_price',
        'support_period', 'support_type', 'support_void_reporting',
        # these ones can't be created through import
        'created_by', 'owner', 'user',
        # shouldn't be in device model, silence here error from there
        'hostname',
        # TODO: add|extend-existing test for device_info crap and remove it
        'device_info',
    ])

    def test_add_by_import(self):
        """
        Uses existing foreign fields.
        """
        device = DeviceFactory()
        csv_data = self._get_csv_data(
            important_data={'barcode': device.barcode},
        )
        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        device = DeviceFactory()
        service_env = CIRelationFactory()
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        csv_data = self._get_csv_data(
            important_data={
                'barcode': device.barcode,
                'device_environment': service_env.child.name,
                'service': service_env.parent.name,
            }, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)

# -*- coding: utf-8 -*-

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import uuid

from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
from django.test import TestCase
from ralph.cmdb.tests.utils import CIRelationFactory
from ralph.discovery.tests.util import DeviceFactory

from ralph_assets.licences.models import (
    AssetType,
    Licence,
)
from ralph_assets.models_assets import Asset
from ralph_assets.tests.utils import (
    ClientMixin,
)
from ralph_assets.tests.utils.assets import (
    BOAssetFactory,
    DCAssetFactory,
)
from ralph_assets.tests.utils.licences import (
    LicenceFactory,
)


class TestImport(ClientMixin, TestCase):
    # TODO: merge it with TestDataImporter?
    def setUp(self):
        self.login_as_superuser()
        self.url = reverse('xls_upload')

    def _update_asset_by_csv(self, asset, field, value):
        self.client.get(self.url)
        csv_data = '"id","{}"\n"{}","{}"'.format(field, asset.id, value)

        step1_post = {
            'upload-asset_type': AssetType.back_office.id,
            'upload-model': 'ralph_assets.asset',
            'upload-file': SimpleUploadedFile('test.csv', csv_data),
            'xls_upload_view-current_step': 'upload',
        }
        response = self.client.post(self.url, step1_post)
        self.assertContains(response, 'column_choice')
        self.assertContains(response, 'step 2/3')

        step2_post = {
            'column_choice-%s' % field: field,
            'xls_upload_view-current_step': 'column_choice',
        }
        response = self.client.post(self.url, step2_post)
        self.assertContains(response, 'step 3/3')

        step3_post = {
            'xls_upload_view-current_step': 'confirm',
        }
        response = self.client.post(self.url, step3_post)
        self.assertContains(response, 'Import done')

    def test_import_csv_asset_back_office_update(self):
        self.client.get(self.url)
        asset = BOAssetFactory()

        for field in [
            'barcode', 'invoice_no', 'order_no', 'sn', 'remarks', 'niw'
        ]:
            new_value = str(uuid.uuid1())
            self._update_asset_by_csv(asset, field, new_value)
            updated_asset = Asset.objects.get(id=asset.id)
            self.assertEqual(
                getattr(updated_asset, field), new_value
            )


class TestDataImporter(object):
    SEP = ','
    upload_model = None
    upload_asset_type = None
    Model = None
    ModelFactory = None
    base_excluded_fields = set()

    def setUp(self):
        self.login_as_superuser()
        self.url = reverse('xls_upload')
        self.excluded_fields = self.base_excluded_fields.copy()

    def _fields2choices(self, fields):
        return {'column_choice-{}'.format(f): f for f in fields}

    def _format_row(self, row):
        return self.SEP.join(['"{}"'.format(item) for item in row])

    def _get_csv_string(self, cols, vals):
        header = self._format_row(cols)
        rows_string = '\n'.join([self._format_row(row) for row in vals])
        csv_string = '\n'.join([header, rows_string])
        return csv_string

    def _get_csv_data(self, important_data={}, use_existing=True):
        """
        Return dict, where:
            *keys* are names of model fields (model is set by
                self.ModelFactory)
            *values* are just field values of model, unless field is foreign
                key. If so then *name* of related object is taken.
            Example:
                modelFactory = Asset, field = price:
                    {'price', Asset.price}
                modelFactory = Asset, field = warehouse:
                    {'warehouse', Asset.warehouse.name}
        """
        csv_data = {}
        obj = self.ModelFactory()
        for field in obj._meta.fields:
            if field.name in self.excluded_fields:
                continue
            field_value = getattr(obj, field.name)
            if field.rel:
                # foreign key, so get as string
                field_value = field_value.name
                if not use_existing:
                    field_value += '-new'
            csv_data[field.name] = field_value
        obj.delete()
        if not important_data:
            important_data = {}
        csv_data.update(important_data)
        return csv_data

    def _check_form_errors(self, response, step):
        errors = getattr(response.context['wizard']['form'], 'errors', None)
        msg = 'step {step} failed, form errors: {form_errors!r}'.format(
            form_errors=errors, step=step,
        )
        self.assertFalse(errors, msg)

    def _import_by_csv(self, fields, values):
        self.client.get(self.url)
        csv_string = self._get_csv_string(fields, values)

        step1_post = {
            'upload-asset_type': self.upload_asset_type,
            'upload-model': self.upload_model,
            'upload-file': SimpleUploadedFile('test.csv', csv_string),
            'xls_upload_view-current_step': 'upload',
        }
        response = self.client.post(self.url, step1_post)
        self._check_form_errors(response, step=1)
        self.assertContains(response, 'column_choice')
        self.assertContains(response, 'step 2/3')

        step2_post = {
            'xls_upload_view-current_step': 'column_choice',
        }
        step2_post.update(self._fields2choices(fields))
        response = self.client.post(self.url, step2_post)
        self._check_form_errors(response, step=2)
        self.assertContains(response, 'step 3/3')

        step3_post = {
            'xls_upload_view-current_step': 'confirm',
        }
        response = self.client.post(self.url, step3_post)
        self._check_form_errors(response, step=3)
        self.assertContains(response, 'Import done')

    def _check_object_against_csv(self, obj, csv_data):
        for field_name, csv_value in csv_data.iteritems():
            obj_value = getattr(obj, field_name)
            if hasattr(obj_value, 'name'):
                obj_value = getattr(obj, field_name).name
            msg = 'Incorrect field {!r} value {!r} != {!r}'.format(
                field_name, obj_value, csv_value,
            )
            self.assertEqual(obj_value, csv_value, msg)

    def test_add_by_import(self):
        """
        Uses existing foreign fields.
        """
        csv_data = self._get_csv_data()
        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        csv_data = self._get_csv_data(use_existing=False)
        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import(self):
        """
        Uses existing foreign fields.
        """
        self.excluded_fields.remove('id')
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(important_data={'id': updated_obj.id})

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)


class TestLicenceDataImporter(TestDataImporter, ClientMixin, TestCase):

    upload_model = 'ralph_assets.licence'
    upload_asset_type = AssetType.back_office.id
    Model = Licence
    ModelFactory = LicenceFactory
    base_excluded_fields = set([
        'cache_version', 'created', 'id', 'level', 'lft', 'modified',
        'parent', 'rght', 'saving_user', 'tree_id',
    ])

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.update(['region'])
        csv_data = self._get_csv_data(use_existing=False)

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        self.excluded_fields.update(['region'])

        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)


class TestBOAssetDataImporter(TestDataImporter, ClientMixin, TestCase):

    upload_model = 'ralph_assets.asset'
    upload_asset_type = AssetType.back_office.id
    Model = Asset
    ModelFactory = BOAssetFactory
    base_excluded_fields = set([
        'cache_version', 'created', 'device_info', 'id', 'modified', 'note',
        'modified_by', 'part_info', 'saving_user', 'support_price',
        'support_period', 'support_type', 'support_void_reporting',
        # these ones can't be created through import
        'created_by', 'owner', 'user',
        # TODO: add|extend-existing test for office_info crap and remove it
        'office_info',
    ])

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        csv_data = self._get_csv_data(use_existing=False)

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)


class TestDCAssetDataImporter(TestDataImporter, ClientMixin, TestCase):

    upload_model = 'ralph_assets.asset'
    upload_asset_type = AssetType.data_center.id
    Model = Asset
    ModelFactory = DCAssetFactory
    base_excluded_fields = set([
        'cache_version', 'created', 'office_info', 'id', 'modified', 'note',
        'modified_by', 'part_info', 'saving_user', 'support_price',
        'support_period', 'support_type', 'support_void_reporting',
        # these ones can't be created through import
        'created_by', 'owner', 'user',
        # shouldn't be in device model, silence here error from there
        'hostname',
        # TODO: add|extend-existing test for device_info crap and remove it
        'device_info',
    ])

    def test_add_by_import(self):
        """
        Uses existing foreign fields.
        """
        device = DeviceFactory()
        csv_data = self._get_csv_data(
            important_data={'barcode': device.barcode},
        )
        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_add_by_import_with_new_foreign_keys(self):
        """
        Creates foreign fields from text values.
        """
        device = DeviceFactory()
        service_env = CIRelationFactory()
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        csv_data = self._get_csv_data(
            important_data={
                'barcode': device.barcode,
                'device_environment': service_env.child.name,
                'service': service_env.parent.name,
            }, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        added_obj = self.Model.objects.latest('id')
        self._check_object_against_csv(added_obj, csv_data)

    def test_update_by_import_with_new_foreign_fields(self):
        """
        Creates foreign fields from text values.
        """
        self.excluded_fields.remove('id')
        self.excluded_fields.update(
            ['service', 'device_environment', 'region'],
        )
        updated_obj = self.ModelFactory()
        csv_data = self._get_csv_data(
            important_data={'id': updated_obj.id}, use_existing=False,
        )

        self._import_by_csv(csv_data.keys(), [csv_data.values()])
        updated_obj = self.Model.objects.get(pk=updated_obj.id)
        self._check_object_against_csv(updated_obj, csv_data)

# -*- coding: utf-8 -*- # TODO: merge it with TestDataImporter? Return dict, where:             *keys* are names of model fields (model is set by                 self.ModelFactory)             *values* are just field values of model, unless field is foreign                 key. If so then *name* of related object is taken.             Example:                 modelFactory = Asset, field = price:                     {'price', Asset.price}                 modelFactory = Asset, field = warehouse:                     {'warehouse', Asset.warehouse.name} # foreign key, so get as string Uses existing foreign fields. Creates foreign fields from text values. Uses existing foreign fields. Creates foreign fields from text values. Creates foreign fields from text values. Creates foreign fields from text values. # these ones can't be created through import # TODO: add|extend-existing test for office_info crap and remove it Creates foreign fields from text values. Creates foreign fields from text values. # these ones can't be created through import # shouldn't be in device model, silence here error from there # TODO: add|extend-existing test for device_info crap and remove it Uses existing foreign fields. Creates foreign fields from text values. Creates foreign fields from text values.