'This function processes the !record tag in yaml files. It simulates the record creation through an xml
view (either specified on the !record tag or the default one for this object), including the calls to
on_change() functions, and sending only values for fields that aren\'t set as readonly.
:param model: model instance (new API)
:param fields: dictonary mapping the field names and their values
:param view_info: result of fields_view_get() called on the object
:param parent: dictionary containing the values already computed for the parent, in case of one2many fields
:param default: if True, the default values must be processed too or not
:return: dictionary mapping the field names and their values, ready to use when calling the create() function
:rtype: dict'

def _create_record(self, model, fields, view_info=None, parent={}, default=True, context=None):

    readonly_re = re.compile('("readonly"|\'readonly\'):    *true')
    class dotdict(object, ):
        "    Dictionary    class    that    allow    to    access    a    dictionary    value    by    using    '.'.\n                                                                This    is    needed    to    eval    correctly    statements    like    'parent.fieldname'    in    context.\n                                                "
        def __init__(self, d):
            self._dict = d
        def __getattr__(self, attr):
            return self._dict.get(attr, False)
    def get_field_elems(view):
        '    return    the    field    elements    from    a    view    as    an    OrderedDict    '
        def traverse(node, elems):
            if (node.tag == 'field'):
                elems[node.get('name')] = node
            else:
                for child in node:
                    traverse(child, elems)
        elems = OrderedDict()
        traverse(etree.fromstring(encode(view['arch'])), elems)
        return elems
    def is_readonly(field_elem):
        '    return    whether    a    given    field    is    readonly    '
        return readonly_re.search(field_elem.get('modifiers', '{}'))
    def get_2many_view(fg, field_name, view_type):
        "    return    a    view    of    the    given    type    for    the    given    field's    comodel    "
        fdesc = fg[field_name]
        return (fdesc['views'].get(view_type) or self.sudo_env[fdesc['relation']].fields_view_get(False, view_type))
    def process_vals(fg, vals):
        '    sanitize    the    given    field    values    '
        result = {}
        for (field_name, field_value) in vals.iteritems():
            if (field_name not in fg):
                continue
            if ((fg[field_name]['type'] == 'many2one') and isinstance(field_value, (tuple, list))):
                field_value = field_value[0]
            elif (fg[field_name]['type'] in ('one2many', 'many2many')):
                sub_fg = get_2many_view(fg, field_name, 'form')['fields']
                def process(command):
                    if (isinstance(command, (tuple, list)) and (command[0] in (0, 1))):
                        return (command[0], command[1], process_vals(sub_fg, command[2]))
                    elif isinstance(command, dict):
                        return process_vals(sub_fg, command)
                    return command
                field_value = map(process, (field_value or []))
            result[field_name] = field_value
        return result
    def post_process(fg, elems, vals):
        '    filter    out    readonly    fields    from    vals    '
        result = {}
        for (field_name, field_value) in vals.iteritems():
            if is_readonly(elems[field_name]):
                continue
            if (fg[field_name]['type'] in ('one2many', 'many2many')):
                sub_view = get_2many_view(fg, field_name, 'form')
                sub_fg = sub_view['fields']
                sub_elems = get_field_elems(sub_view)
                def process(command):
                    if (isinstance(command, (tuple, list)) and (command[0] in (0, 1))):
                        return (command[0], command[1], post_process(sub_fg, sub_elems, command[2]))
                    elif isinstance(command, dict):
                        return (0, 0, post_process(sub_fg, sub_elems, command))
                    return command
                field_value = map(process, (field_value or []))
            result[field_name] = field_value
        return result
    context = (context or {})
    fields = (fields or {})
    parent_values = ({context['field_parent']: parent} if context.get('field_parent') else {})
    if view_info:
        fg = view_info['fields']
        elems = get_field_elems(view_info)
        recs = model.sudo().with_context(**context)
        onchange_spec = recs._onchange_spec(view_info)
        record_dict = {}
        if default:
            defaults = recs.sudo(self.uid)._add_missing_default_values({})
            record_dict = dict.fromkeys(fg, False)
            record_dict.update(process_vals(fg, defaults))
            default_names = [name for name in elems if (name in record_dict)]
            result = recs.onchange(dict(record_dict, **parent_values), default_names, onchange_spec)
            record_dict.update(process_vals(fg, result.get('value', {})))
        for (field_name, field_elem) in elems.iteritems():
            assert (field_name in fg), ("The    field    '%s'    is    defined    in    the    form    view    but    not    on    the    object    '%s'!" % (field_name, model._name))
            if is_readonly(field_elem):
                continue
            if (field_name not in fields):
                continue
            ctx = dict(context)
            form_view = view_info
            if (fg[field_name]['type'] == 'one2many'):
                form_view = get_2many_view(fg, field_name, 'form')
                ctx['field_parent'] = fg[field_name]['relation_field']
            if (default and field_elem.get('context')):
                ctx.update(safe_eval(field_elem.get('context'), globals_dict={'parent': dotdict(parent)}, locals_dict=record_dict))
            field_value = self._eval_field(model, field_name, fields[field_name], form_view, parent=record_dict, default=default, context=ctx)
            record_dict.update(process_vals(fg, {field_name: field_value}))
            if (not field_elem.attrib.get('on_change', False)):
                continue
            result = recs.onchange(dict(record_dict, **parent_values), field_name, onchange_spec)
            record_dict.update(process_vals(fg, {key: val for (key, val) in result.get('value', {}).iteritems() if (key not in fields)}))
        record_dict = post_process(fg, elems, record_dict)
    else:
        record_dict = {}
    for (field_name, expression) in fields.iteritems():
        if record_dict.get(field_name):
            continue
        field_value = self._eval_field(model, field_name, expression, parent=record_dict, default=False, context=context)
        record_dict[field_name] = field_value
    return {key: val for (key, val) in record_dict.iteritems() for field in [model._fields[key].base_field] if (field.store or field.inverse)}
