OpenUpgrade API

The OpenUpgrade library contains all kinds of helper functions for your pre and post scripts, in OpenUpgrade itself or in the migration scripts of your own module (in either major or minor version upgrades). It can be installed with

pip install openupgradelib

and then used in your scripts as

from openupgradelib import openupgrade

General methods

openupgradelib.openupgrade.migrate(no_version=False, use_env=None, uid=None, context=None)

This is the decorator for the migrate() function in migration scripts.

Set argument no_version to True if the method has to be taken into account if the module is installed during a migration.

Set argument use_env if you want an v8+ environment instead of a plain cursor. Starting from version 10, this is the default

The arguments uid and context can be set when an evironment is requested. In the cursor case, they’re ignored.

The migration function’s signature must be func(cr, version) if use_env is False or not set and the version is below 10, or func(env, version) if use_env is True or not set and the version is 10 or higher.

Return when the version argument is not defined and no_version is False and log execeptions.

Retrieve debug context data from the frame above for logging purposes.

openupgradelib.openupgrade.logging(args_details=False, step=False)

This is a decorator for any sub functions called in an OpenUpgrade script. (pre or post migration script)

Decorate functions that can take time, or for debug / development purpose.

if a function is decorated, a log will be written each time the function is called.

Parameters:
  • args_details – if True, arguments details are given in the log
  • step – The log will be done only every step times.

Typical use:

@openupgrade.logging()
def migrate_stock_warehouses(cr)
    # some custom code

@openupgrade.logging(step=1000)
def migrate_partner(cr, partner):
    # some custom code

@openupgrade.migrate()
def migrate(cr, version):
    # some custom code
    migrate_stock_warehouses(cr)

    for partner in partners:
        migrate_partner(cr, partner)
openupgradelib.openupgrade.load_data(cr, module_name, filename, idref=None, mode='init')

Load an xml, csv or yml data file from your post script. The usual case for this is the occurrence of newly added essential or useful data in the module that is marked with “noupdate=‘1’” and without “forcecreate=‘1’” so that it will not be loaded by the usual upgrade mechanism. Leaving the ‘mode’ argument to its default ‘init’ will load the data from your migration script.

Theoretically, you could simply load a stock file from the module, but be careful not to reinitialize any data that could have been customized. Preferably, select only the newly added items. Copy these to a file in your migrations directory and load that file. Leave it to the user to actually delete existing resources that are marked with ‘noupdate’ (other named items will be deleted automatically).

Parameters:
  • module_name – the name of the module
  • filename – the path to the filename, relative to the module directory.
  • idref – optional hash with ?id mapping cache?
  • mode

    one of ‘init’, ‘update’, ‘demo’, ‘init_no_create’. Always use ‘init’ for adding new items from files that are marked with ‘noupdate’. Defaults to ‘init’.

    ’init_no_create’ is a hack to load data for records which have forcecreate=False set. As those records won’t be recreated during the update, standard Odoo would recreate the record if it was deleted, but this will fail in cases where there are required fields to be filled which are not contained in the data file.

openupgradelib.openupgrade.add_fields(env, field_spec)

This method adds all the needed stuff for having a new field populated in the DB (SQL column, ir.model.fields entry, ir.model.data entry…).

It’s intended for being run in pre-migration scripts for pre-populating fields that are going to be declared later in the module.

NOTE: This is not needed in >=v12, as now Odoo always add the XML-ID entry: https://github.com/odoo/odoo/blob/9201f92a4f29a53a014b462469f27b32dca8fc5a/ odoo/addons/base/models/ir_model.py#L794-L802, but you can still call this method for consistency and for avoiding to know the internal PG column type.

Param:

field_spec: List of tuples with the following expected elements for each tuple:

  • field name
  • model name
  • SQL table name: Put False if the model is already loaded in the registry and thus the SQL table name can be obtained that way.
  • field type: binary, boolean, char, date, datetime, float, html, integer, many2many, many2one, monetary, one2many, reference, selection, text, serialized. The list can vary depending on Odoo version or custom added field types.
  • SQL field type: If the field type is custom or it’s one of the special cases (see below), you need to indicate here the SQL type to use (from the valid PostgreSQL types): https://www.postgresql.org/docs/9.6/static/datatype.html
  • module name: for adding the XML-ID entry.
  • (optional) initialization value: if included in the tuple, it is set in the column for existing records.
openupgradelib.openupgrade.copy_columns(cr, column_spec)

Copy table columns. Typically called in the pre script.

Parameters:column_spec – a hash with table keys, with lists of tuples as values. Tuples consist of (old_name, new_name, type). Use None for new_name to trigger a conversion of old_name using get_legacy_name() Use None for type to use type of old field. Make sure to quote properly, if your column name coincides with a SQL directive. eg. ‘“column”’

New in version 8.0.

openupgradelib.openupgrade.copy_fields_multilang(cr, destination_model, destination_table, destination_columns, relation_column, source_model=None, source_table=None, source_columns=None, translations_only=False)

Copy field contents including translations.

Parameters:
  • destination_model (str) – Name of the destination model where the data will be copied to.
  • destination_table (str) – Name of the destination table where the data will be copied to. It must be env[destination_model]._table.
  • destination_columns (list) – List of column names in the destination_table that will receive the copied data.
  • relation_column (str) – Name of a column in destination_table which points to IDs in source_table. An INNER JOIN will be done to update the destination records with their corresponding source records only. Records where this column NULL will be skipped.
  • source_model (str) – Name of the source model where the data will be copied from. If empty, it will default to destination_table.
  • source_table (str) – Name of the source table where the data will be copied from. If empty, it will default to destination_table. It must be env[source_model]._table.
  • source_columns (list) – List of column names in the source_table that will provide the copied data. If empty, it will default to destination_columns.
  • translations_only (bool) – If True, it will only handle transferring translations. Won’t copy the raw field from source_table.

New in version 12.0.

openupgradelib.openupgrade.remove_tables_fks(cr, tables)

Remove foreign keys declared in tables.

This is useful when a table is not going to be used anymore, but you still don’t want to delete it.

If you keep FKs in that table, it will still get modifications when other tables are modified too; but if you’re keeping that table as a log, that is a problem. Also, if some of the FK has no index, it could slow down deletion in other tables, even when this one has no more use.

Hint

This method removes FKs that are declared in tables, not FKs that point to those tables.

Parameters:..] tables ([str,) – List of tables where the FKs were declared, and where they will be removed too. If a table doesn’t exist, it is skipped.
openupgradelib.openupgrade.rename_columns(cr, column_spec)

Rename table columns. Typically called in the pre script.

Parameters:column_spec – a hash with table keys, with lists of tuples as values. Tuples consist of (old_name, new_name). Use None for new_name to trigger a conversion of old_name using get_legacy_name()
openupgradelib.openupgrade.rename_fields(env, field_spec, no_deep=False)

Rename fields. Typically called in the pre script. WARNING: If using this on base module, pass the argument no_deep with True value for avoiding the using of the environment (which is not yet loaded).

This, in contrast of rename_columns, performs all the steps for completely rename a field from one name to another. This is needed for making a complete renaming of a field with all their side features: translations, filters, exports…

Call this method whenever you are not performing a pure SQL column renaming for other purposes (preserve a value for example).

This method performs also the SQL column renaming, so only one call is needed.

Parameters:
  • env – Environment/pool variable. The database cursor is the only thing needed, but added in prevision of TODO tasks for not breaking API later.
  • field_spec – a list of tuples with the following elements: * Model name. The name of the Odoo model * Table name. The name of the SQL table for the model. * Old field name. The name of the old field. * New field name. The name of the new field.
  • no_deep – If True, avoids to perform any operation that involves the environment. Not used for now.
openupgradelib.openupgrade.rename_tables(cr, table_spec)

Rename tables. Typically called in the pre script. This function also renames the id sequence if it exists and if it is not modified in the same run.

Parameters:table_spec – a list of tuples (old table name, new table name). Use None for new_name to trigger a conversion of old_name to the result of get_legacy_name()
openupgradelib.openupgrade.rename_models(cr, model_spec)

Rename models. Typically called in the pre script. :param model_spec: a list of tuples (old model name, new model name).

Use case: if a model changes name, but still implements equivalent functionality you will want to update references in for instance relation fields.

WARNING: This method doesn’t rename the associated tables. For that, you need to call rename_tables method.

openupgradelib.openupgrade.rename_xmlids(cr, xmlids_spec)

Rename XML IDs. Typically called in the pre script. One usage example is when an ID changes module. In OpenERP 6 for example, a number of res_groups IDs moved to module base from other modules ( although they were still being defined in their respective module).

Parameters:xmlids_spec – a list of tuples (old module.xmlid, new module.xmlid).
openupgradelib.openupgrade.add_xmlid(cr, module, xmlid, model, res_id, noupdate=False)

Adds an entry in ir_model_data. Typically called in the pre script. One usage example is when an entry has been add in the XML and there is a high probability that the user has already created the entry manually. For example, a currency was added in the XML data of the base module in OpenERP 6 but the user had already created this missing currency by hand in it’s 5.0 database. In order to avoid having 2 identical currencies (which is in fact blocked by an sql_constraint), you have to add the entry in ir_model_data before the upgrade.

openupgradelib.openupgrade.chunked(records, single=True)

Memory and performance friendly method to iterate over a potentially large number of records. Yields either a whole chunk or a single record at the time. Don’t nest calls to this method.

openupgradelib.openupgrade.drop_columns(cr, column_spec)

Drop columns but perform an additional check if a column exists. This covers the case of function fields that may or may not be stored. Consider that this may not be obvious: an additional module can govern a function fields’ store properties.

Parameters:column_spec – a list of (table, column) tuples
openupgradelib.openupgrade.delete_model_workflow(cr, model, drop_indexes=False)

Forcefully remove active workflows for obsolete models, to prevent foreign key issues when the orm deletes the model.

Parameters:
  • cr – DB cursor.
  • model (str) – Model name.
  • drop_indexes (bool) – Do I drop indexes after finishing? If False, those will be dropped by a subsequent update of the workflow module in normal Odoo probably.
openupgradelib.openupgrade.update_field_multilang(records, field, method)

Update a field in all available languages in the database.

Parameters:
  • records – Recordset to be updated.
  • field (str) – Field to be updated.
  • method (callable) –

    Method to execute to update the field.

    It will be called with: (old_value, lang_code, record)

openupgradelib.openupgrade.update_workflow_workitems(cr, pool, ref_spec_actions)

Find all the workflow items from the target state to set them to the wanted state.

When a workflow action is removed, from model, the objects whose states are in these actions need to be set to another to be able to continue the workflow properly.

Run in pre-migration

Parameters:ref_spec_actions – list of tuples with couple of workflow.action’s external ids. The first id is replaced with the second.
Returns:None

New in version 7.0.

openupgradelib.openupgrade.warn_possible_dataloss(cr, pool, old_module, fields)

Use that function in the following case: if a field of a model was moved from a ‘A’ module to a ‘B’ module. (‘B’ depend on ‘A’), This function will test if ‘B’ is installed. If not, count the number of different value and possibly warn the user. Use orm, so call from the post script.

Parameters:
  • old_module – name of the old module
  • fields – list of dictionary with the following keys: ‘table’ : name of the table where the field is. ‘field’ : name of the field that are moving. ‘new_module’ : name of the new module

New in version 7.0.

openupgradelib.openupgrade.set_defaults(cr, pool, default_spec, force=False, use_orm=False)

Set default value. Useful for fields that are newly required. Uses orm, so call from the post script.

Parameters:
  • pool – you can pass ‘env’ as well.
  • default_spec – a hash with model names as keys. Values are lists of tuples (field, value). None as a value has a special meaning: it assigns the default value. If this value is provided by a function, the function is called as the user that created the resource.
  • force – overwrite existing values. To be used for assigning a non- default value (presumably in the case of a new column). The ORM assigns the default value as declared in the model in an earlier stage of the process. Beware of issues with resources loaded from new data that actually do require the model’s default, in combination with the post script possible being run multiple times.
  • use_orm – If set to True, the write operation of the default value will be triggered using ORM instead on an SQL clause (default).
openupgradelib.openupgrade.logged_query(cr, query, args=None, skip_no_result=False)

Logs query and affected rows at level DEBUG.

Parameters:
  • query – a query string suitable to pass to cursor.execute()
  • args – a list, tuple or dictionary passed as substitution values to cursor.execute().
  • skip_no_result – If True, then logging details are only shown if there are affected records.
openupgradelib.openupgrade.column_exists(cr, table, column)

Check whether a certain column exists

openupgradelib.openupgrade.table_exists(cr, table)

Check whether a certain table or view exists

openupgradelib.openupgrade.update_module_moved_fields(cr, model, moved_fields, old_module, new_module)

Update module for field definition in general tables that have been moved from one module to another.

NOTE: This is not strictly needed in >=v12, as now Odoo always adds the XML-ID entry: https://github.com/odoo/odoo/blob/9201f92a4f29a53a014b462469f27b32dca8fc5a/ odoo/addons/base/models/ir_model.py#L794-L802 (https://git.io/fjzqz), but we can call it for completion and for the translation part.

Parameters:
  • cr – Database cursor
  • model – model name
  • moved_fields – list of moved fields
  • old_module – previous module of the fields
  • new_module – new module of the fields
openupgradelib.openupgrade.update_module_names(cr, namespec, merge_modules=False)

Deal with changed module names, making all the needed changes on the related tables, like XML-IDs, translations, and so on.

Parameters:
  • namespec – list of tuples of (old name, new name)
  • merge_modules – Specify if the operation should be a merge instead of just a renaming.
openupgradelib.openupgrade.add_ir_model_fields(cr, columnspec)

Typically, new columns on ir_model_fields need to be added in a very early stage in the upgrade process of the base module, in raw sql as they need to be in place before any model gets initialized. Do not use for fields with additional SQL constraints, such as a reference to another table or the cascade constraint, but craft your own statement taking them into account.

Parameters:columnspec – tuple of (column name, column type)
openupgradelib.openupgrade.get_legacy_name(original_name)

Returns a versioned name for legacy tables/columns/etc Use this function instead of some custom name to avoid collisions with future or past legacy tables/columns/etc

Parameters:
  • original_name – the original name of the column
  • version – current version as passed to migrate()
openupgradelib.openupgrade.m2o_to_x2m(cr, model, table, field, source_field)

Transform many2one relations into one2many or many2many. Use rename_columns in your pre-migrate script to retain the column’s old value, then call m2o_to_x2m in your post-migrate script.

WARNING: If converting to one2many, there can be data loss, because only one inverse record can be mapped in a one2many, but you can have multiple many2one pointing to the same target. Use it when the use case allows this conversion.

Parameters:
  • model – The target model registry object
  • table – The source table
  • field – The new field name on the target model
  • source_field – the (renamed) many2one column on the source table.

New in version 8.0.

openupgradelib.openupgrade.float_to_integer(cr, table, field)

Change column type from float to integer. It will just truncate the float value (It won’t round it)

Parameters:
  • table – The table
  • field – The field name for which we want to change the type

New in version 8.0.

openupgradelib.openupgrade.message(cr, module, table, column, message, *args, **kwargs)

Log handler for non-critical notifications about the upgrade. To be extended with logging to a table for reporting purposes.

Parameters:
  • module – the module name that the message concerns
  • table – the model that this message concerns (may be False, but preferably not if ‘column’ is defined)
  • column – the column that this message concerns (may be False)

New in version 7.0.

openupgradelib.openupgrade.check_values_selection_field(cr, table_name, field_name, allowed_values)
check if the field selection ‘field_name’ of the table ‘table_name’ has only the values ‘allowed_values’. If not return False and log an error. If yes, return True.

New in version 8.0.

openupgradelib.openupgrade.move_field_m2o(cr, pool, registry_old_model, field_old_model, m2o_field_old_model, registry_new_model, field_new_model, quick_request=True, compute_func=None, binary_field=False)

Use that function in the following case: A field moves from a model A to the model B with : A -> m2o -> B. (For exemple product_product -> product_template) This function manage the migration of this field. available on post script migration. :param registry_old_model: registry of the model A; :param field_old_model: name of the field to move in model A; :param m2o_field_old_model: name of the field of the table of the model A that link model A to model B; :param registry_new_model: registry of the model B; :param field_new_model: name of the field to move in model B; :param quick_request: Set to False, if you want to use write function to update value; Otherwise, the function will use UPDATE SQL request; :param compute_func: This a function that receives 4 parameters: cr, pool: common args; id: id of the instance of Model B vals: list of different values. This function must return a unique value that will be set to the instance of Model B which id is ‘id’ param; If compute_func is not set, the algorithm will take the value that is the most present in vals. :binary_field: Set to True if the migrated field is a binary field

New in version 8.0.

openupgradelib.openupgrade.convert_field_to_html(cr, table, field_name, html_field_name)

Convert field value to HTML value.

New in version 7.0.

openupgradelib.openupgrade.map_values(cr, source_column, target_column, mapping, model=None, table=None, write='sql')

Map old values to new values within the same model or table. Old values presumably come from a legacy column. You will typically want to use it in post-migration scripts.

Parameters:
  • cr – The database cursor
  • source_column – the database column that contains old values to be mapped
  • target_column – the database column, or model field (if ‘write’ is ‘orm’) that the new values are written to
  • mapping – list of tuples [(old value, new value)] Old value True represents “is set”, False “is not set”.
  • model – used for writing if ‘write’ is ‘orm’, or to retrieve the table if ‘table’ is not given.
  • table – the database table used to query the old values, and write the new values (if ‘write’ is ‘sql’)
  • write – Either ‘orm’ or ‘sql’. Note that old ids are always identified by an sql read.

This method does not support mapping m2m, o2m or property fields. For o2m you can migrate the inverse field’s column instead.

New in version 8.0.

openupgradelib.openupgrade.deactivate_workflow_transitions(cr, model, transitions=None)

Disable workflow transitions for workflows on a given model. This can be necessary for automatic workflow transitions when writing to an object via the ORM in the post migration step. Returns a dictionary to be used on reactivate_workflow_transitions

Parameters:
  • model – the model for which workflow transitions should be deactivated
  • transitions – a list of (‘module’, ‘name’) xmlid tuples of transitions to be deactivated. Don’t pass this if there’s no specific reason to do so, the default is to deactivate all transitions

New in version 7.0.

openupgradelib.openupgrade.reactivate_workflow_transitions(cr, transition_conditions)

Reactivate workflow transition previously deactivated by deactivate_workflow_transitions.

Parameters:transition_conditions – a dictionary returned by deactivate_workflow_transitions

New in version 7.0.

Deprecated since version 11.0: Workflows were removed from Odoo as of version 11.0

openupgradelib.openupgrade.date_to_datetime_tz(cr, table_name, user_field_name, date_field_name, datetime_field_name)

Take the related user’s timezone into account when converting date field to datetime in a given table. This function must be call in post migration script.

:param table_name : Name of the table where the field is; :param user_field_name : The name of the user field (res.users); :param date_field_name : The name of the old date field; (Typically a legacy name, set in pre-migration script) :param datetime_field_name : The name of the new date field;

New in version 8.0.

openupgradelib.openupgrade.lift_constraints(cr, table, column)

Lift all constraints on column in table. Typically, you use this in a pre-migrate script where you adapt references for many2one fields with changed target objects. If everything went right, the constraints will be recreated

openupgradelib.openupgrade.rename_property(cr, model, old_name, new_name)

Rename property old_name owned by model to new_name. This should happen in a pre-migration script.

openupgradelib.openupgrade.delete_record_translations(cr, module, xml_ids)

Cleanup translations of specific records in a module.

Parameters:
  • module – module name
  • xml_ids – a tuple or list of xml record IDs
openupgradelib.openupgrade.disable_invalid_filters(env)

It analyzes all the existing active filters to check if they are still correct. If not, they are disabled for avoiding errors when clicking on them, or worse, if they are default filters when opening the model/action.

To be run at the base end-migration script for having a general scope. Only assured to work on > v8.

Parameters:env – Environment parameter.
openupgradelib.openupgrade.delete_records_safely_by_xml_id(env, xml_ids)

This removes in the safest possible way the records whose XML-IDs are passed as argument.

Parameters:xml_ids – List of XML-ID string identifiers of the records to remove.
openupgradelib.openupgrade.set_xml_ids_noupdate_value(env, module, xml_ids, value)

Set the xml_ids noupdate values in a module.

Parameters:
  • module – module name
  • xml_ids – a tuple or list of xml record IDs
  • value (bool) – True or False.
openupgradelib.openupgrade.convert_to_company_dependent(env, model_name, origin_field_name, destination_field_name, model_table_name=None)

For each row in a given table, the value of a given field is set in another ‘company dependant’ field of the same table. Useful in cases when from one version to another one, some field in a model becomes a ‘company dependent’ field.

This method must be executed in post-migration scripts after the field is created, or in pre-migration if you have previously executed add_fields openupgradelib method.

Parameters:
  • model_name – Name of the model.
  • origin_field_name – Name of the field from which the values will be obtained.
  • destination_field_name – Name of the ‘company dependent’ field where the values obtained from origin_field_name will be set.
  • model_table_name – Name of the table. Optional. If not provided the table name is taken from the model (so the model must be registered previously).

Methods for OpenUpgrade 7.0

The following specific methods for 7.0 are available. These have been developed to cover specific needs as per data model changes in that release.

openupgradelib.openupgrade_70.get_partner_id_from_user_id(cr, user_id)

Get the new partner_id from user_id. :param user_id : user previously used.

openupgradelib.openupgrade_70.set_partner_id_from_partner_address_id(cr, pool, model_name, partner_field, address_field, table=None)

Set the new partner_id on any table with migrated contact ids

Parameters:
  • model_name – the model name of the target table
  • partner_field – the column in the target model’s table that will store the new partner when found
  • address_field – the legacy field in the model’s table that contains the old address in the model’s table
  • table – override the target model’s table name in case it was renamed
Returns:

nothing

Methods for OpenUpgrade 8.0

The following specific methods for 8.0 are available. These have been developed to cover specific needs as per data model changes in that release.

openupgradelib.openupgrade_80.get_last_post_for_model(cr, uid, ids, model_pool)

Given a set of ids and a model pool, return a dict of each object ids with their latest message date as a value. To be called in post-migration scripts

Parameters:
  • cr – database cursor
  • uid – user id, assumed to be openerp.SUPERUSER_ID
  • ids – ids of the model in question to retrieve ids
  • model_pool – orm model pool, assumed to be from pool.get()
Returns:

a dict with ids as keys and with dates as values

openupgradelib.openupgrade_80.set_message_last_post(cr, uid, pool, models)

Given a list of models, set their ‘message_last_post’ fields to an estimated last post datetime. To be called in post-migration scripts

Parameters:
  • cr – database cursor
  • uid – user id, assumed to be openerp.SUPERUSER_ID
  • pool – orm pool, assumed to be openerp.pooler.get_pool(cr.dbname)
  • models – a list of model names for which ‘message_last_post’ needs to be filled
Returns:

openupgradelib.openupgrade_80.update_aliases(cr, registry, model_name, set_parent_thread_id, alias_defaults=None, defaults_id_key=False)

Update a model’s aliases according to how they are configured in the model’s create() method.

Parameters:
  • model_name – The name of the model whose aliases are to be updated. The model_id is also set as the aliases’ alias_parent_model_id.
  • set_parent_thread_id' – When set, set the ids of the resources as their alias’ alias_parent_thread_id
  • alias_defaults – Static dictionary, recorded as a string on each alias
  • defaults_id_key – When defined, add this key to each alias’ defaults dictionary with the resource id as its value.

Methods for OpenUpgrade 9.0

The following specific methods for 9.0 are available. These have been developed to cover specific needs as per data model changes in that release.

This module provides simple tools for OpenUpgrade migration, specific for the 8.0 -> 9.0 migration.

openupgradelib.openupgrade_90.convert_binary_field_to_attachment(env, field_spec)

This method converts the 8.0 binary fields to attachments like Odoo 9.0 makes with the new attachment=True attribute. It has to be called on post-migration script, as there’s a call to get the res_name of the target model, which is not yet loaded on pre-migration.

You need to rename the involved column in pre-migration script if you don’t want to lose your data in the process.

This method also removes after the conversion the source column for avoiding data duplication.

This is done through Odoo ORM, because there’s a lot of logic associated with guessing MIME type, format and length, file saving in store… that is doesn’t worth to recreate it via SQL as there’s not too much performance problem.

Parameters:
  • env – Odoo environment
  • field_spec

    A dictionary with the ORM model name as key, and as dictionary values a tuple with:

    • field name to be converted as attachment as first element.
    • SQL column name that contains actual data as second element. If the second element is None, then the column name is taken calling get_legacy_name method, which is the typical technique.
openupgradelib.openupgrade_90.replace_account_types(env, type_spec, unlink=True)

Replace old account types with their replacements. The old account type is allowed not to exist anymore, except when running unit tests. :param type_spec: list of tuples (xmlid of old account.account.type, xmlid of new account.account.type) :param unlink: attempt to unlink the old account type