Пример #1
0
 def test_IncomingMailValidationCriterion(self):
     crit = IncomingMailValidationCriterion(self.portal)
     # no groups
     self.assertEqual(crit.query, {'state_group': {'query': []}})
     # in a group _n_plus_1
     api.group.create(groupname='111_n_plus_1')
     api.group.add_user(groupname='111_n_plus_1', username=TEST_USER_ID)
     # update reviewlevels because n_plus_1 level is not applied by default
     set_dms_config(['review_levels', 'dmsincomingmail'],
                    OrderedDict([('dir_general', {
                        'st': ['proposed_to_manager']
                    }),
                                 ('_n_plus_1', {
                                     'st': ['proposed_to_n_plus_1'],
                                     'org': 'treating_groups'
                                 })]))
     self.assertEqual(
         crit.query,
         {'state_group': {
             'query': ['proposed_to_n_plus_1,111']
         }})
     # in a group dir_general
     api.group.add_user(groupname='dir_general', username=TEST_USER_ID)
     self.assertEqual(
         crit.query, {
             'state_group': {
                 'query':
                 ['proposed_to_manager', 'proposed_to_n_plus_1,111']
             }
         })
Пример #2
0
    def test_state_group_index(self):
        dguid = self.pgof['direction-generale'].UID()
        imail = sub_create(
            self.portal['incoming-mail'], 'dmsincomingmail', datetime.now(),
            'id1', **{
                'title': u'test',
                'treating_groups': dguid,
                'assigned_user': u'chef'
            })
        indexer = state_group_index(imail)
        self.assertEqual(indexer(), 'created')
        api.content.transition(obj=imail, to_state='proposed_to_manager')
        self.assertEqual(indexer(), 'proposed_to_manager')
        api.content.transition(obj=imail, to_state='proposed_to_agent')
        self.assertEqual(indexer(), 'proposed_to_agent')

        task = createContentInContainer(imail, 'task', assigned_group=dguid)
        indexer = state_group_index(task)
        self.assertEqual(indexer(), 'created')
        # simulate adaptation
        add_applied_adaptation(
            'imio.dms.mail.wfadaptations.TaskServiceValidation',
            'task_workflow', False)
        api.group.create(groupname='{}_n_plus_1'.format(dguid),
                         groups=['chef'])
        api.content.transition(obj=task, transition='do_to_assign')
        self.assertEqual(indexer(), 'to_assign')
        set_dms_config(['review_states', 'task'],
                       OrderedDict([('to_assign', {
                           'group': '_n_plus_1',
                           'org': 'assigned_group'
                       })]))
        self.assertEqual(indexer(), 'to_assign,%s' % dguid)
Пример #3
0
 def test_dms_config(self):
     annot = IAnnotations(self.portal)
     set_dms_config(['a'], value='dict')
     lst = set_dms_config(['a', 'b'], value='list')
     self.assertTrue(isinstance(annot['imio.dms.mail'], PersistentDict))
     self.assertTrue(isinstance(annot['imio.dms.mail']['a'],
                                PersistentDict))
     self.assertTrue(
         isinstance(annot['imio.dms.mail']['a']['b'], PersistentList))
     lst.append(1)
     self.assertEqual(get_dms_config(['a', 'b']), [1])
     set_dms_config(['a', 'b'], value='plone')
     self.assertTrue(isinstance(annot['imio.dms.mail']['a']['b'], str))
     self.assertEqual(get_dms_config(['a', 'b']), 'plone')
Пример #4
0
 def test_highest_review_level(self):
     self.assertIsNone(highest_review_level('a_type', ""))
     self.assertIsNone(highest_review_level('dmsincomingmail', ""))
     self.assertEquals(
         highest_review_level('dmsincomingmail', "['dir_general']"),
         'dir_general')
     set_dms_config(['review_levels', 'dmsincomingmail'],
                    OrderedDict([('dir_general', {
                        'st': ['proposed_to_manager']
                    }),
                                 ('_n_plus_1', {
                                     'st': ['proposed_to_n_plus_1'],
                                     'org': 'treating_groups'
                                 })]))
     self.assertEquals(
         highest_review_level('dmsincomingmail', "['111_n_plus_1']"),
         '_n_plus_1')
Пример #5
0
 def test_IdmUtilsMethods_user_has_review_level(self):
     imail = sub_create(self.portal['incoming-mail'], 'dmsincomingmail',
                        datetime.now(), 'my-id')
     view = IdmUtilsMethods(imail, imail.REQUEST)
     self.assertFalse(view.user_has_review_level())
     self.assertFalse(view.user_has_review_level('dmsincomingmail'))
     api.group.create(groupname='111_n_plus_1')
     api.group.add_user(groupname='111_n_plus_1', username=TEST_USER_ID)
     set_dms_config(['review_levels', 'dmsincomingmail'],
                    OrderedDict([('dir_general', {
                        'st': ['proposed_to_manager']
                    }),
                                 ('_n_plus_1', {
                                     'st': ['proposed_to_n_plus_1'],
                                     'org': 'treating_groups'
                                 })]))
     self.assertTrue(view.user_has_review_level('dmsincomingmail'))
     api.group.remove_user(groupname='111_n_plus_1', username=TEST_USER_ID)
     self.assertFalse(view.user_has_review_level('dmsincomingmail'))
     api.group.add_user(groupname='dir_general', username=TEST_USER_ID)
     self.assertTrue(view.user_has_review_level('dmsincomingmail'))
Пример #6
0
 def test_TaskValidationCriterion(self):
     crit = TaskValidationCriterion(self.portal)
     # no groups
     self.assertEqual(crit.query, {'state_group': {'query': []}})
     # in a group _n_plus_1
     api.group.create(groupname='111_n_plus_1')
     api.group.add_user(groupname='111_n_plus_1', username=TEST_USER_ID)
     set_dms_config(['review_levels', 'task'],
                    OrderedDict([('_n_plus_1', {
                        'st': ['to_assign', 'realized'],
                        'org': 'assigned_group'
                    })]))
     self.assertEqual(
         crit.query,
         {'state_group': {
             'query': ['to_assign,111', 'realized,111']
         }})
     # in a group dir_general, but no effect for task criterion
     api.group.add_user(groupname='dir_general', username=TEST_USER_ID)
     self.assertEqual(
         crit.query,
         {'state_group': {
             'query': ['to_assign,111', 'realized,111']
         }})
Пример #7
0
 def dms_config(self):
     try:
         get_dms_config()
         return
     except KeyError:
         pass
     set_dms_config(
         ['review_levels', 'dmsincomingmail'],  # i_e ok
         OrderedDict([('dir_general', {
             'st': ['proposed_to_manager']
         }),
                      ('_validateur', {
                          'st': ['proposed_to_service_chief'],
                          'org': 'treating_groups'
                      })]))
     set_dms_config(['review_levels', 'task'],
                    OrderedDict([('_validateur', {
                        'st': ['to_assign', 'realized'],
                        'org': 'assigned_group'
                    })]))
     set_dms_config(['review_levels', 'dmsoutgoingmail'],
                    OrderedDict([('_validateur', {
                        'st': ['proposed_to_service_chief'],
                        'org': 'treating_groups'
                    })]))
     set_dms_config(
         ['review_states', 'dmsincomingmail'],  # i_e ok
         OrderedDict([('proposed_to_manager', {
             'group': 'dir_general'
         }),
                      ('proposed_to_service_chief', {
                          'group': '_validateur',
                          'org': 'treating_groups'
                      })]))
     set_dms_config(['review_states', 'task'],
                    OrderedDict([('to_assign', {
                        'group': '_validateur',
                        'org': 'assigned_group'
                    }),
                                 ('realized', {
                                     'group': '_validateur',
                                     'org': 'assigned_group'
                                 })]))
     set_dms_config(['review_states', 'dmsoutgoingmail'],
                    OrderedDict([('proposed_to_service_chief', {
                        'group': '_validateur',
                        'org': 'treating_groups'
                    })]))
Пример #8
0
    def test_update_transitions_levels_config(self):
        # dmsincomingmail #
        config = get_dms_config(['transitions_levels', 'dmsincomingmail'])
        self.assertSetEqual(
            set(config.keys()),
            {'created', 'proposed_to_manager', 'proposed_to_agent', 'closed'})
        self.assertEqual(config['created'], config['proposed_to_manager'])
        self.assertEqual(config['created'], config['proposed_to_agent'])
        self.assertEqual(config['created'], config['closed'])
        for state in config:
            for org in config[state]:
                self.assertEqual(config[state][org],
                                 ('propose_to_agent', 'from_states'))
        org1, org2 = get_registry_organizations()[0:2]
        # we simulate the adding of a level without user
        api.group.create('{}_n_plus_1'.format(org1), 'N+1')
        set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'],
                       [('closed', 'close'),
                        ('proposed_to_agent', 'propose_to_agent'),
                        ('proposed_to_n_plus_1', 'propose_to_n_plus_1')])
        update_transitions_levels_config(['dmsincomingmail'])
        config = get_dms_config(['transitions_levels', 'dmsincomingmail'])
        self.assertEqual(config['proposed_to_n_plus_1'][org1],
                         ('propose_to_agent', 'from_states'))
        self.assertEqual(config['proposed_to_manager'][org1],
                         ('propose_to_agent', 'from_states'))
        self.assertEqual(config['proposed_to_manager'][org2],
                         ('propose_to_agent', 'from_states'))
        self.assertEqual(config['proposed_to_agent'][org1],
                         ('propose_to_agent', 'from_states'))
        self.assertEqual(config['closed'][org1],
                         ('propose_to_agent', 'from_states'))
        # we simulate the adding of a level and a user
        update_transitions_levels_config(['dmsincomingmail'], 'add',
                                         '{}_n_plus_1'.format(org1))
        config = get_dms_config(['transitions_levels', 'dmsincomingmail'])
        self.assertEqual(config['proposed_to_n_plus_1'][org1],
                         ('propose_to_agent', 'from_states'))
        self.assertEqual(config['proposed_to_manager'][org1],
                         ('propose_to_n_plus_1', 'from_states'))
        self.assertEqual(config['proposed_to_manager'][org2],
                         ('propose_to_agent', 'from_states'))
        self.assertEqual(config['proposed_to_agent'][org1],
                         ('propose_to_agent', 'back_to_n_plus_1'))
        self.assertEqual(config['proposed_to_agent'][org2],
                         ('propose_to_agent', 'from_states'))

        # dmsoutgoingmail #
        config = get_dms_config(['transitions_levels', 'dmsoutgoingmail'])
        self.assertSetEqual(set(config.keys()),
                            {'created', 'to_be_signed', 'sent'})
        self.assertEqual(config['created'], config['to_be_signed'])
        for state in config:
            for org in config[state]:
                self.assertEqual(config[state][org], ('', ''))
        org1, org2 = get_registry_organizations()[0:2]
        # we simulate the adding of a level without user
        api.group.create('{}_n_plus_1'.format(org1), 'N+1')
        update_transitions_levels_config(['dmsoutgoingmail'])
        config = get_dms_config(['transitions_levels', 'dmsoutgoingmail'])
        self.assertEqual(config['created'][org1], ('', ''))
        self.assertEqual(config['to_be_signed'][org1], ('', ''))
        self.assertEqual(config['created'][org2], ('', ''))
        self.assertEqual(config['to_be_signed'][org2], ('', ''))
        # we simulate the adding of a level and a user
        update_transitions_levels_config(['dmsoutgoingmail'], 'add',
                                         '{}_n_plus_1'.format(org1))
        config = get_dms_config(['transitions_levels', 'dmsoutgoingmail'])
        self.assertEqual(config['created'][org1], ('propose_to_n_plus_1', ''))
        self.assertEqual(config['to_be_signed'][org1],
                         ('', 'back_to_n_plus_1'))
        self.assertEqual(config['created'][org2], ('', ''))
        self.assertEqual(config['to_be_signed'][org2], ('', ''))

        # task #
        config = get_dms_config(['transitions_levels', 'task'])
        for org in config['created']:
            self.assertEqual(config['created'][org], ('', ''))
        for org in config['to_do']:
            self.assertEqual(config['to_do'][org], ('', 'back_in_created2'))
        org1, org2 = get_registry_organizations()[0:2]
        # we simulate the adding of a level without user
        api.group.create('{}_n_plus_1'.format(org1), 'N+1')
        update_transitions_levels_config(['task'])
        config = get_dms_config(['transitions_levels', 'task'])
        self.assertEqual(config['to_do'][org1], ('', 'back_in_created2'))
        self.assertEqual(config['to_do'][org2], ('', 'back_in_created2'))
        # we simulate the adding of a level and a user
        update_transitions_levels_config(['task'], 'add',
                                         '{}_n_plus_1'.format(org1))
        config = get_dms_config(['transitions_levels', 'task'])
        self.assertEqual(config['created'][org1], ('do_to_assign', ''))
        self.assertEqual(config['to_do'][org1], ('', 'back_in_to_assign'))
        self.assertEqual(config['created'][org2], ('', ''))
        self.assertEqual(config['to_do'][org2], ('', 'back_in_created2'))
Пример #9
0
 def test_update_transitions_auc_config(self):
     api.portal.set_registry_record(AUC_RECORD, u'no_check')
     # no check
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertSetEqual(set(config.keys()), {'close', 'propose_to_agent'})
     self.assertTrue(all(
         config['propose_to_agent'].values()))  # can always do transition
     self.assertTrue(all(
         config['close'].values()))  # can always do transition
     # n_plus_1
     api.portal.set_registry_record(AUC_RECORD, u'n_plus_1')
     # only one transition
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertSetEqual(set(config.keys()), {'close', 'propose_to_agent'})
     self.assertTrue(all(config['propose_to_agent'].values()))
     self.assertTrue(all(config['close'].values()))
     # we simulate the adding of a level without user
     org1, org2 = get_registry_organizations()[0:2]
     api.group.create('{}_n_plus_1'.format(org1), 'N+1')
     set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'],
                    [('closed', 'close'),
                     ('proposed_to_agent', 'propose_to_agent'),
                     ('proposed_to_n_plus_1', 'propose_to_n_plus_1')])
     update_transitions_auc_config('dmsincomingmail')
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertSetEqual(
         set(config.keys()),
         {'close', 'propose_to_n_plus_1', 'propose_to_agent'})
     self.assertTrue(all(config['propose_to_n_plus_1'].values()))
     self.assertTrue(all(config['propose_to_agent'].values()))
     self.assertTrue(all(config['close'].values()))
     # we simulate the adding of a level and a user
     update_transitions_auc_config('dmsincomingmail', 'add',
                                   '{}_n_plus_1'.format(org1))
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertTrue(config['propose_to_n_plus_1'][org1])
     self.assertFalse(config['propose_to_agent']
                      [org1])  # cannot do transition because user
     self.assertTrue(config['propose_to_agent'][org2])
     # mandatory
     # reset config
     set_dms_config(['transitions_auc', 'dmsincomingmail'], value='dict')
     set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'],
                    [('closed', 'close'),
                     ('proposed_to_agent', 'propose_to_agent')])
     api.portal.set_registry_record(AUC_RECORD, 'mandatory')
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertFalse(any(
         config['propose_to_agent'].values()))  # all is False
     self.assertTrue(all(config['close'].values()))
     # we simulate the adding of a level without user
     set_dms_config(['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'],
                    [('closed', 'close'),
                     ('proposed_to_agent', 'propose_to_agent'),
                     ('proposed_to_n_plus_1', 'propose_to_n_plus_1')])
     update_transitions_auc_config('dmsincomingmail')
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertSetEqual(
         set(config.keys()),
         {'close', 'propose_to_n_plus_1', 'propose_to_agent'})
     self.assertFalse(any(
         config['propose_to_n_plus_1'].values()))  # all is False
     self.assertFalse(any(
         config['propose_to_agent'].values()))  # all is False
     self.assertTrue(all(config['close'].values()))
     # we simulate the adding of a level and a user
     update_transitions_auc_config('dmsincomingmail', 'add',
                                   '{}_n_plus_1'.format(org1))
     config = get_dms_config(['transitions_auc', 'dmsincomingmail'])
     self.assertTrue(config['propose_to_n_plus_1']
                     [org1])  # can do transition because user
     self.assertFalse(config['propose_to_n_plus_1'][org2])
     self.assertFalse(config['propose_to_agent'][org1])
     self.assertFalse(config['propose_to_agent'][org2])
Пример #10
0
def reset_dms_config():
    set_dms_config(
        ['wf_from_to', 'dmsincomingmail', 'n_plus', 'from'],  # i_e ok
        [('created', 'back_to_creation'),
         ('proposed_to_manager', 'back_to_manager')])
    set_dms_config(
        ['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'],  # i_e ok
        [('proposed_to_agent', 'propose_to_agent')])
    set_dms_config(['wf_from_to', 'dmsoutgoingmail', 'n_plus', 'from'],
                   [('created', 'back_to_creation')])
    set_dms_config(['wf_from_to', 'dmsoutgoingmail', 'n_plus', 'to'],
                   [('to_be_signed', 'propose_to_be_signed')])
    set_dms_config(
        ['review_levels', 'dmsincomingmail'],  # i_e ok
        OrderedDict([('dir_general', {
            'st': ['proposed_to_manager']
        })]))
    set_dms_config(['review_levels', 'task'], OrderedDict())
    set_dms_config(['review_levels', 'dmsoutgoingmail'], OrderedDict())
    set_dms_config(
        ['review_states', 'dmsincomingmail'],  # i_e ok
        OrderedDict([('proposed_to_manager', {
            'group': 'dir_general'
        })]))
    set_dms_config(['review_states', 'task'], OrderedDict())
    set_dms_config(['review_states', 'dmsoutgoingmail'], OrderedDict())
    set_dms_config(['transitions_auc', 'dmsincomingmail'],
                   OrderedDict())  # i_e ok
    set_dms_config(['transitions_levels', 'dmsincomingmail'],
                   OrderedDict())  # i_e ok
    set_dms_config(['transitions_levels', 'dmsoutgoingmail'], OrderedDict())
    set_dms_config(['transitions_levels', 'task'], OrderedDict())
Пример #11
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 2.3...')

        # check if oo port or solr port must be changed
        update_solr_config()
        update_oo_config()

        # add new dms config used in update_transitions_levels_config
        if 'wf_from_to' not in get_dms_config():
            set_dms_config(
                ['wf_from_to', 'dmsincomingmail', 'n_plus', 'from'],  # i_e ok
                [('created', 'back_to_creation'),
                 ('proposed_to_manager', 'back_to_manager')])
            set_dms_config(
                ['wf_from_to', 'dmsincomingmail', 'n_plus', 'to'],  # i_e ok
                [('proposed_to_agent', 'propose_to_agent')])
            set_dms_config(['wf_from_to', 'dmsoutgoingmail', 'n_plus', 'from'],
                           [('created', 'back_to_creation')])
            set_dms_config(['wf_from_to', 'dmsoutgoingmail', 'n_plus', 'to'],
                           [('to_be_signed', 'propose_to_be_signed')])

        self.cleanRegistries()

        self.correct_actions()
        auc_stored = self.registry[AUC_RECORD]

        self.upgradeProfile('collective.contact.plonegroup:default')
        self.install(
            ['collective.contact.importexport', 'collective.fontawesome'])
        self.runProfileSteps('plonetheme.imioapps',
                             steps=['viewlets'])  # to hide messages-viewlet
        if not self.portal.portal_quickinstaller.isProductInstalled(
                'collective.wfadaptations'):
            self.install(['collective.wfadaptations'])
        self.runProfileSteps('imio.dms.mail',
                             steps=['actions', 'plone.app.registry'],
                             run_dependencies=False)

        # add new task collection
        createTaskCollections(self.portal['tasks']['task-searches'])

        # migrate assigned_user_check
        self.update_assigned_user_check(auc_stored)

        # remove service_chief related
        self.remove_service_chief()

        # do various global adaptations
        self.update_site()

        # update daterange criteria
        self.update_dashboards()

        # update templates
        self.runProfileSteps('imio.dms.mail',
                             steps=['imiodmsmail-update-templates'],
                             profile='singles')

        # upgrade all except 'imio.dms.mail:default'. Needed with bin/upgrade-portals
        self.upgradeAll(omit=['imio.dms.mail:default'])

        self.runProfileSteps('imio.dms.mail',
                             steps=['cssregistry', 'jsregistry'])

        # set jqueryui autocomplete to False. If not, contact autocomplete doesn't work
        self.registry[
            'collective.js.jqueryui.controlpanel.IJQueryUIPlugins.ui_autocomplete'] = False

        for prod in [
                'collective.contact.core', 'collective.contact.widget',
                'collective.dms.batchimport', 'collective.dms.mailcontent',
                'collective.eeafaceted.batchactions',
                'collective.eeafaceted.collectionwidget',
                'collective.eeafaceted.dashboard',
                'collective.eeafaceted.z3ctable', 'collective.fingerpointing',
                'collective.messagesviewlet', 'collective.wfadaptations',
                'collective.z3cform.datetimewidget', 'communesplone.layout',
                'eea.facetednavigation', 'eea.jquery', 'imio.actionspanel',
                'imio.dashboard', 'imio.dms.mail', 'imio.history',
                'plone.formwidget.autocomplete',
                'plone.formwidget.contenttree', 'plonetheme.classic',
                'plonetheme.imio.apps'
        ]:
            mark_last_version(self.portal, product=prod)

        # self.refreshDatabase()
        self.finish()
Пример #12
0
    def remove_service_chief(self):
        # remove collection
        logger.info('Modifying workflows')
        for folder in (self.imf['mail-searches'], self.omf['mail-searches']):
            if 'searchfor_proposed_to_service_chief' in folder:
                api.content.delete(
                    obj=folder['searchfor_proposed_to_service_chief'])

        # clean dms config
        for ptype in ('dmsincomingmail', 'dmsoutgoingmail', 'task'):  # i_e ok
            config = get_dms_config(['review_levels', ptype])
            if '_validateur' in config:
                del config['_validateur']
                set_dms_config(keys=['review_levels', ptype], value=config)
            config = get_dms_config(['review_states', ptype])
            if 'proposed_to_service_chief' in config:
                del config['proposed_to_service_chief']
                set_dms_config(keys=['review_states', ptype], value=config)

        def remove_localrole_validateur(dic1):
            for state1 in dic1:
                if 'validateur' in dic1[state1]:
                    del dic1[state1]['validateur']

        # clean local roles
        for ptype in ('dmsincomingmail', 'dmsoutgoingmail'):  # i_e ok
            fti = getUtility(IDexterityFTI, name=ptype)
            lr = getattr(fti, 'localroles')
            lrg = lr['static_config']
            if 'proposed_to_service_chief' in lrg:
                del lrg['proposed_to_service_chief']
                remove_localrole_validateur(lrg)
            lrg = lr['treating_groups']
            if 'proposed_to_service_chief' in lrg:
                del lrg['proposed_to_service_chief']
                remove_localrole_validateur(lrg)
            lrg = lr['recipient_groups']
            if 'proposed_to_service_chief' in lrg:
                del lrg['proposed_to_service_chief']
                remove_localrole_validateur(lrg)
            lr._p_changed = True
        # on task
        fti = getUtility(IDexterityFTI, name='task')
        lr = getattr(fti, 'localroles')
        lrg = lr['assigned_group']
        if 'validateur' in lrg['to_do']:
            remove_localrole_validateur(lrg)
        lrg = lr['parents_assigned_groups']
        if 'validateur' in lrg['to_do']:
            remove_localrole_validateur(lrg)
        lr._p_changed = True

        # update registry
        lst = api.portal.get_registry_record(
            'imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'
        )
        for entry in ('dmsincomingmail.back_to_service_chief|',
                      'dmsoutgoingmail.back_to_service_chief|'):
            if entry not in lst:
                break
            lst.remove(entry)
        else:
            api.portal.set_registry_record(
                'imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions',
                lst)

        # update remark states
        for attr in ('imail_remark_states', 'omail_remark_states'):
            lst = (api.portal.get_registry_record(
                'imio.dms.mail.browser.settings.IImioDmsMailConfig.{}'.format(
                    attr)) or [])
            if 'proposed_to_service_chief' in lst:
                lst.remove('proposed_to_service_chief')
                api.portal.set_registry_record(
                    'imio.dms.mail.browser.settings.IImioDmsMailConfig.{}'.
                    format(attr), lst)

        # Manage workflows and wfadaptations
        functions = get_registry_functions()
        if 'validateur' not in [fct['fct_id'] for fct in functions]:
            return  # apply the following only once

        def remove_adaptation_from_registry(name):
            record = api.portal.get_registry_record(RECORD_NAME)
            api.portal.set_registry_record(
                RECORD_NAME, [d for d in record if d['adaptation'] != name])

        # reset workflows
        self.runProfileSteps('imio.dms.mail', steps=['workflow'])
        # self.portal.portal_workflow.updateRoleMappings()  # done later

        # Apply workflow adaptations if necessary
        applied_wfa = [dic['adaptation'] for dic in get_applied_adaptations()]
        n_plus_1_params = {
            'validation_level': 1,
            'state_title': u'À valider par le chef de service',
            'forward_transition_title': u'Proposer au chef de service',
            'backward_transition_title': u'Renvoyer au chef de service',
            'function_title': u'N+1'
        }
        task_adapt = True
        for wkf, acr in (('incomingmail_workflow', 'IM'),
                         ('outgoingmail_workflow', 'OM')):
            if u'imio.dms.mail.wfadaptations.{}SkipProposeToServiceChief'.format(
                    acr) in applied_wfa:
                remove_adaptation_from_registry(
                    u'imio.dms.mail.wfadaptations.{}SkipProposeToServiceChief'.
                    format(acr))
                task_adapt = False
                if acr == 'OM':
                    folder = self.omf['mail-searches']
                    if folder['to_validate'].enabled:
                        folder['to_validate'].enabled = False
                        folder['to_validate'].reindexObject()
            else:
                logger.info(
                    'Applying {}ServiceValidation wf adaptation'.format(acr))
                sva = getattr(wfadaptations,
                              '{}ServiceValidation'.format(acr))()
                sva.reapply = True
                adapt_is_applied = sva.patch_workflow(wkf, **n_plus_1_params)
                if adapt_is_applied:
                    add_applied_adaptation(
                        'imio.dms.mail.wfadaptations.{}ServiceValidation'.
                        format(acr), wkf, True, **n_plus_1_params)

        # update task_workflow
        update_task_workflow(self.portal)
        if task_adapt:
            tsva = TaskServiceValidation()
            adapt_is_applied = tsva.patch_workflow('task_workflow', **{})
            if adapt_is_applied:
                add_applied_adaptation(
                    'imio.dms.mail.wfadaptations.TaskServiceValidation',
                    'task_workflow', False)
        else:
            # update collections
            folder = self.portal['tasks']['task-searches']
            for cid in ('to_assign', 'to_close'):
                if folder[cid].enabled:
                    folder[cid].enabled = False
                    folder[cid].reindexObject()

        invalidate_cachekey_volatile_for(
            'collective.eeafaceted.collectionwidget.cachedcollectionvocabulary'
        )

        # replace EmergencyZoneAdaptation
        im_workflow = self.wtool['incomingmail_workflow']
        if u'imio.dms.mail.wfadaptations.EmergencyZone' in applied_wfa:
            state = im_workflow.states['proposed_to_manager']
            state.title = u'À valider par le CZ'.encode('utf8')
            for tr, tit in (('back_to_manager', u'Renvoyer au CZ'),
                            ('propose_to_manager', u'Proposer au CZ')):
                transition = im_workflow.transitions[tr]
                transition.title = tit.encode('utf8')
            logger.info('Removing EmergencyZone wf adaptation')
            remove_adaptation_from_registry(
                u'imio.dms.mail.wfadaptations.EmergencyZone')

        # redo OMToPrintAdaptation
        if u'imio.dms.mail.wfadaptations.OMToPrint' in applied_wfa:
            logger.info('Applying OMToPrint wf adaptation')
            tpa = OMToPrintAdaptation()
            tpa.patch_workflow('outgoingmail_workflow')

        # redo IMPreManagerValidation
        if u'imio.dms.mail.wfadaptations.IMPreManagerValidation' in applied_wfa:
            logger.info('Applying IMPreManagerValidation wf adaptation')
            params = [
                dic['parameters'] for dic in get_applied_adaptations()
                if dic['adaptation'] ==
                u'imio.dms.mail.wfadaptations.IMPreManagerValidation'
            ][0]
            remove_adaptation_from_registry(
                u'imio.dms.mail.wfadaptations.IMPreManagerValidation')
            del params['collection_title']
            pmva = IMPreManagerValidation()
            adapt_is_applied = pmva.patch_workflow('incomingmail_workflow',
                                                   **params)
            if adapt_is_applied:
                add_applied_adaptation(
                    'imio.dms.mail.wfadaptations.IMPreManagerValidation',
                    'incoming_mail', False, **params)

        # update wf history to replace review_state and correct history
        config = {
            'dmsincomingmail': {
                'wf': 'incomingmail_workflow',  # i_e ok
                'st': {
                    'proposed_to_service_chief': 'proposed_to_n_plus_1'
                },
                'tr': {
                    'propose_to_service_chief': 'propose_to_n_plus_1',
                    'back_to_service_chief': 'back_to_n_plus_1'
                }
            },
            'dmsoutgoingmail': {
                'wf': 'outgoingmail_workflow',
                'st': {
                    'proposed_to_service_chief': 'proposed_to_n_plus_1'
                },
                'tr': {
                    'propose_to_service_chief': 'propose_to_n_plus_1',
                    'back_to_service_chief': 'back_to_n_plus_1'
                }
            }
        }
        for pt in config:
            logger.info('Updating history and indexes of {} type'.format(pt))
            for i, brain in enumerate(self.catalog(portal_type=pt), 1):
                obj = brain.getObject()
                if i % 10000 == 0:
                    logger.info('On brain {}'.format(i))
                # update history
                wfh = []
                wkf = self.wtool[config[pt]['wf']]
                for status in obj.workflow_history.get(config[pt]['wf']):
                    # replace old state by new one
                    if status['review_state'] in config[pt]['st']:
                        status['review_state'] = config[pt]['st'][
                            status['review_state']]
                    # replace old transition by new one
                    if status['action'] in config[pt]['tr']:
                        status['action'] = config[pt]['tr'][status['action']]
                    wfh.append(status)
                obj.workflow_history[config[pt]['wf']] = tuple(wfh)
                # update permissions and roles
                wkf.updateRoleMappingsFor(obj)
                # update state_group (use dms_config), permissions, state
                obj.reindexObject(idxs=[
                    'allowedRolesAndUsers', 'review_state', 'state_group'
                ])
                for child in obj.objectValues():
                    child.reindexObject(idxs=['allowedRolesAndUsers'])

        # migrate plone groups
        # First unregister group deletion handlers
        globalSiteManager.unregisterHandler(pg_group_deleted,
                                            (IGroupDeletedEvent, ))
        globalSiteManager.unregisterHandler(group_deleted,
                                            (IGroupDeletedEvent, ))
        globalSiteManager.unregisterHandler(group_assignment,
                                            (IPrincipalAddedToGroupEvent, ))
        globalSiteManager.unregisterHandler(
            group_unassignment, (IPrincipalRemovedFromGroupEvent, ))
        # move users from _validateur to _n_plus_1
        for group in api.group.get_groups():
            if group.id.endswith('_validateur'):
                org = group.id.split('_')[0]
                np1group = api.group.get('{}_n_plus_1'.format(org))
                if np1group:
                    for user in api.user.get_users(group=group):
                        api.group.add_user(group=np1group, user=user)
                        api.group.remove_user(group=group, user=user)
                api.group.delete(group=group)
        # register again group deletion handlers
        globalSiteManager.registerHandler(pg_group_deleted,
                                          (IGroupDeletedEvent, ))
        globalSiteManager.registerHandler(group_deleted,
                                          (IGroupDeletedEvent, ))
        globalSiteManager.registerHandler(group_assignment,
                                          (IPrincipalAddedToGroupEvent, ))
        globalSiteManager.registerHandler(group_unassignment,
                                          (IPrincipalRemovedFromGroupEvent, ))

        # remove validateur function
        functions = get_registry_functions()
        if 'validateur' in [fct['fct_id'] for fct in functions]:
            set_registry_functions(
                [fct for fct in functions if fct['fct_id'] != 'validateur'])