Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I

Реализации концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint нет. Это видимо из-за наивного представления что сотрудник будет работать в той компании в которую устраивается и трудоустройство у него будет одно… но это слишком наивное представление о работе, в реальности сотрудник думает что устраивается в одну известную компанию, а оказывается что это не компания а бренд, а в этом бренде несколько компаний, оформят его рандомно в одну из них, да еще например поставят работать в головной офис, а оформят в регион потому что там зарплата меньше, но сразу скажу что дальше концепцию на регионы или проекты я продлевать не стал хотя это тоже можно сделать. В этой первой части я сосредоточусь на скелете концепции и на перетекании информации в нем. Концепция оказалась очень большой да еще и расширяющейся, поэтому будет три части:

1. Получение данных из кадрового ресурса, построение информационных связей и структуры.

2. Назначение ролей, создание AD учетки, реализация концепций Forward Ролей и nickName как роль.

3. Запрос ролей сотрудником, запрос начальником ролей для сотрудника.

Что будет работать в конце этой статьи: Из источника ресурса получим Трудоустройства, Назначения. Вкачаем в них ФИО сотрудника из его основной учетки в Midpoint, тоже самое с названием фирмы.

Реализовывать всё буду на Linked Objects в нем все нужное досконально описывать при настройки. Evolvеum имеет другой более понятный механизм Persona но он не дописан и совершенно не масштабируем, хотя подходит для создания типовых Должностей или Аккаунтов, но не больше одной на одного сотрудника потому что все привязано к ArcheType и ObjectTemplate.

Первым делом надо ответить на вопрос что есть трудоустройство User или Role?! И User и Role! Для понимания простенькая схемка что происходит

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 1

У нас есть кадровый источник где лежат Cотрудник в нем его трудоустройства, трудоустройства а в нем назначения на должность и назначения на должность. Все связано важно как запускать реконсиляцию чтобы все получилось с первого раза, если запускать беспорядочно реконсиляцию то с первого раза не получится. В ресурсе 1 сначала делаем из трудоустройства роли Role, затем привязываем сотрудников из кадрового источника к сотрудникам в Midpoint то есть к User, в этот же момент им навешивается ранее созданная роль трудоустройство. Когда сотрудник в Midpoint привязан к роли трудоустройства, в роль трудоустройство из сотрудника Midpoint перекачивается информация о имя, статус и пр — сотрудник в Midpoint становится источником этой информации для всего что будет потом. В ресурсе 2 делаем роли назначения на должность, и делаем User из трудоустройств им тут же из ресурса навешиваются роли назначений на трудоустройства созданные ранее и через Object Template на Archetype для User Трудоустройство навешиваются роли трудоустройства. Тут несколько движений информации вкачиваем в User Трудоустройство информацию из роли Трудоустройство, из ресурса 2, и перекачиваем в роли назначения на позицию. Ресурс 3 тут просто делаем User назначение на позиции им сразу навешиваются Role назначение на позицию и перекачивается информация которой просто нет в ресурсе например имя сотрудника, а нет её там хотя бы потому что мы не хотим её брать из источника назначений у нас есть доверенный всегда правильный источник а именно сотрудник в Midpoint.

Подробней о Linked Objects

Разберем это на примере карточки Компании. У нас есть роли карточки компании, в них identifier который не будет меняться никогда, и название компании которое можете менять — заходить в роль карточка Компани и менять её название, и только в этом месте и оно должно обновится во всех нужных местах. Midpoint достаточно и identifier но иногда в него будет заходить люди и им надо видеть не только identifier но и название компании.

Первым делом создадим ArcheType в ConfigurationArcheTypesAll archetypes

Для карточки компании назовём архетип POCE Company Role ArcheType

Подкрасим его, здесь и далее буду стараться все показывать кодом, а не скриншотами

Вставляем code

<archetypePolicy>
    <display>
        <icon>
            <cssClass>fa fa-city</cssClass>
            <color>#d88222</color>
        </icon>
    </display>
...
</archetypePolicy>
</archetype>

Смотрим с низу

</archetype> — значит вставляем в ArcheType

Сверху

<archetypePolicy> — значит вставляем в теги <archetypePolicy></archetypePolicy>

… — в них еще что то есть или будет но сейчас это не важно, „…“ никуда никогда не вставляем

Сюда же вставляем

<archetypePolicy>
    <display>
        <icon>
            <cssClass>fa fa-address-card</cssClass>
            <color>#d88222</color>
        </icon>
    </display>
...
</archetypePolicy>
...
<assignment id="1">
    <identifier>holderType</identifier>
    <activation>
        <effectiveStatus>enabled</effectiveStatus>
    </activation>
    <assignmentRelation id="2">
        <holderType>RoleType</holderType>
    </assignmentRelation>
</assignment>
...
</archetype>

Так и не понял как это задавать через кнопки, это определяет что это ArcheType для RoleType

Что делает Linked Objects

Он располагается в ArcheType, прекрасная масштабируемость на всё с этим архетипом. Мы в архетипе того на кого хотим получится информацию пишем — вот этот другой архетип для нас будет источником или целью(в некоторых раскладах цель это источник), а также прописываем маппинг из каких атрибутов другого архетипа брать и куда складывать. Но перекачка информации случается только если архетипы встречаются, то есть в назначение есть роль с архетипом из описанной схемы выше.

Мы будем из роли с архетипом POCE Company Role ArcheType копировать в роль с архетипом POCE Employment Role ArcheType, но только когда когда они друг другу назначены. И этот случай когда цель это источник, по смыслу мы описываем источник информации Source по пишем цель Target.
В Архетипе POCE Employment Role ArcheType добавляем в ConfigurationArcheTypeAll archetypesPOCE Employment Role ArcheTypeArcheType PolicylinksTarget link

кодом

<archetypePolicy>
...
    <targetLink id="32">
        <name>from Company to Employment</name>
        <selector>
            <type>c:RoleType</type>
            <archetypeRef oid="f44dc355-31d3-499b-9854-e0ae277a60dc" relation="org:default" type="c:ArchetypeType">
                <!-- POCE Company Role ArcheType -->
            </archetypeRef>
        </selector>
    </targetLink>
</links>
</archetypePolicy>
...
</archetype>

Тут главное name — Company to Employment поэтому name мы будем обращаться к этом источнику-цели далее в мапингах.

И добавляем маппинги в ConfigurationArcheTypeAll archetypesPOCE Employment Role ArcheTypeInducementsFocus Mappings

кодом

<inducement id="16">
    <focusMappings>
        <mapping id="7">
            <name>to costCenter</name>
            <documentation>displayName from Company Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>
linkedDATA = midpoint.findLinkedTarget('from Company to Employment')
return linkedDATA.displayName
                    </code>
                </script>
            </expression>
            <target>
                <path>costCenter</path>
            </target>
            <condition>
                <script>
                    <code>
linkedDATA = midpoint.findLinkedTarget('from Company to Employment')
if (basic.isEmpty(linkedDATA))
{return false}
else{return !basic.isEmpty(linkedDATA.displayName)}
                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
...
</archetype>

Беру из роли карточки компании атрибут displayName и кладу его в роль трудоустройство в costCenter. Тут обращаем внимание на скрипт

midpoint.findLinkedTarget — должен соответстовать тому что указано в from Company to Employment если Target Link то Targets если Source Link то Source

<condition> — это тут потому что я хочу в случае если у нас пропадает значение из источника(кто то написал пусто), чтобы оставалось последнее вменяемое.

<authoritative>false</authoritative> — если пропадает источник, то есть назначенная роль карточка компании, то данные не пропадают а остаются там куда были положены маппингом который уже не срабатывает.

Все что мы описали, достаточно чтобы пришли данные в случае создания-назначения роли Трудоустройства. Данные не придут в случаях изменения данных в роли карточка компании.

Для случая изменение данных в роли карточка компании

Надо переместиться в архетип POCE Company Role ArcheType роли карточки компании там же будут происходить изменения и будет посылаться команда рекомпутить всех у кого роль карточки компании. В POCE Company Role ArcheType в ConfigurationArcheTypeAll archetypesPOCE Company Role ArcheTypeArcheType PolicylinksSource link

кодом

<archetypePolicy>
...
    <links>
        <sourceLink id="43">
            <name>Company to Employment</name>
            <selector>
                <type>c:RoleType</type>
                <archetypeRef oid="3e97bf04-93de-486b-a17b-ca686f9c6a68" relation="org:default" type="c:ArchetypeType">
                    <!-- POCE Employment Role ArcheType -->
                </archetypeRef>
            </selector>
        </sourceLink>
    </links>
</archetypePolicy>
...
</archetype>

И в ConfigurationArcheTypeAll archetypesPOCE Employment Role ArcheTypeInducementsPolicy rule

кодом

<inducement id="12">
    <policyRule>
        <name>Recompute Employment Role on displayname change</name>
        <policyConstraints>
            <or id="13">
                <modification id="14">
                    <item>
                        <_value>c:displayName</_value>
                    </item>
                </modification>
            </or>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="16">
                <object>
                    <linkSource id="40">
                        <name>Company to Employment</name>
                    </linkSource>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>

Запуск по modification в displayName

И для полнейшего понимания схемкой что у нас получилось по связям

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 2

Вот так просто и главное понятно можно использовать Linked Objects в Midpoint для установки информационной связи между объектами. Идем дальше полная схема взаимодействия для архетипа POCE Employment Role ArcheType будет выглядеть так

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 3

Все кроме пока 4го архетипа надо реализовать полностью чтобы добраться до Resource 1

Добавляем пустой 4тый архетип, потому что мы уже будем на него ссылаться, назовём его POCE Employment User ArcheType и подкрасим

кодом

<archetypePolicy>
    <display>
        <icon>
            <cssClass>fa fa-address-card</cssClass>
            <color>#2d860a</color>
        </icon>
    </display>
...
</archetypePolicy>
</archetype>

Добавляем в архетип Person который у всех наших сотрудников в Midpoint идем в ConfigurationArcheTypeAll archetypesPersonArcheType PolicylinksSource link

кодом

<archetypePolicy>
	...
    <links>
        <targetLink id="17">
            <name>User info to Employment Role</name>
            <selector>
                <type>c:RoleType</type>
                <archetypeRef oid="3e97bf04-93de-486b-a17b-ca686f9c6a68" relation="org:default" type="c:ArchetypeType">
                    <!-- POCE Employment Role ArcheType -->
                </archetypeRef>
            </selector>
        </targetLink>
    </links>
</archetypePolicy>
</archetype>

В тут же добавляем политику которая будет рекомпилить роли трудоустройства если меняются данные у сотрудника Midpointa

<inducement id="12">
    <policyRule>
        <name>Recompute Employment on User data changes</name>
        <policyConstraints>
            <or id="13">
                <modification id="14">
                    <item>
                        <_value>c:givenName</_value>
                    </item>
                </modification>
                <modification id="15">
                    <item>
                        <_value>c:familyName</_value>
                    </item>
                </modification>
                <modification id="20">
                    <item>c:additionalName</item>
                </modification>
                <modification id="22">
                    <item>c:activation/c:administrativeStatus</item>
                </modification>
            </or>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="16">
                <object>
                    <linkTarget id="17">
                        <linkType>User info to Employment Role</linkType>
                    </linkTarget>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>
...
</archetype>

Если меняется имя, отчество или фамилия рекомпилим роли трудоустройства, потому что они туда тоже перекладываются.

И добавляем политики… которая при навешивании роли Трудоустройства на сотрудников Midpoint c архетипом Person будет рекомпилить эту роль Трудоустройства…

<inducement id="176">
    <policyRule>
        <name>Recompute Role Employment on User Person membershipchange</name>
        <policyConstraints>
            <alwaysTrue id="177"/>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="178">
                <object>
                    <linkTarget id="179">
                        <changeSituation>changed</changeSituation>
                        <linkType>User info to Employment Role</linkType>
                    </linkTarget>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>

…без этой политики происходит следующее — сотрудник получил роль Трудоустройства, но в роль Трудоустройства не вкачиваются его данные — нет повода! Если открыть RAW CODE любой роли Role то там нет записей о том кому эта роль выдана, то есть при выдачи роли в роль ничего не пишется нет повода рекомпутить и выкачивать данные, ничего не изменилось для роли. Запись о выданной роли есть только в User, поэтому политику рекомпилить роль мы пишем в него. И вся логика запуска тут перевернута, в том что должно запускать политику policyConstraints написано запускать всегда, а логика запуска срабатывает в месте на ком запускать policyActions object. Тут хитрое слово changeSituation выбрано changed что значит Link matches if its existence was changed. Получается запускать всегда но на привязанных ролях, которые только что привязались… или отвязались.

Почему у нас нет такой же политики на ролях, для случая получения роли, почему там перекачка инфы случается сама при назначении роли. Потому что выдать User’у роль, и выдать Role’и роль это не одно и тоже — хотя на кнопках называется также если смотреть на User и на Role! В роли кто ей assigned из ролей записано, а это запускает recompute как изменение данных. По смыслу назначения разные но поле то одно roleMembershipRef сработал принцип всё переиспользовать, которым так гордиться Evolvium.

Еще про логику, получается механизм Links только про выкачку из кого-то данных, но не про закачку!? Мы не можем захотеть и вкачать в кого данные, но мы можем захотеть и сказать ткни другого, чтобы он у нас выкачал, или сами выкачать!

Теперь в В Архетипе POCE Employment Role ArcheType добавляем ссылку на архетип Person в ConfigurationArcheTypeAll archetypesPOCE Employment Role ArcheTypeArcheType PolicylinksSource link

кодом

<archetypePolicy>
	...
    <links>
        <sourceLink id="34">
            <name>From User to Employment Role</name>
            <selector>
                <type>c:UserType</type>
                <archetypeRef oid="00000000-0000-0000-0000-000000000702" relation="org:default" type="c:ArchetypeType">
                    <!-- Person -->
                </archetypeRef>
            </selector>
        </sourceLink>
...
    </archetypePolicy>
</archetype>

И маппинги которые будут перекачивать имя отчество фамилию.

<inducement id="26">
    <focusMappings>
        <mapping id="7">
            <documentation>familyName From User to Employment Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
return linkedDATA.familyName

                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_familyName</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.familyName)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="36">
    <focusMappings>
        <mapping id="7">
            <documentation>additionalName From User to Employment Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>



linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
return linkedDATA.additionalName
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_additionalName</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.additionalName)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="46">
    <focusMappings>
        <mapping id="7">
            <documentation>personalNumber From User to Employment Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
return linkedDATA.personalNumber
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_personalNumber</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.personalNumber)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="56">
    <focusMappings>
        <mapping id="7">
            <documentation>administrativeStatus From User to Employment Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>



import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType
linkedSource = midpoint.findLinkedSource('From User to Employment Role')
if (basic.isEmpty(linkedSource))
{return 'NO CONNECTION'}
else
{
if (basic.isEmpty(linkedSource.activation.effectiveStatus))
{return 'UNDIFIEND'}
else
{return basic.stringify(linkedSource.activation.effectiveStatus)}

}
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_administrativeStatus</path>
            </target>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="126">
    <focusMappings>
        <mapping id="7">
            <documentation>givenName From User to Employment Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('From User to Employment Role')

return linkedDATA.givenName
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_givenName</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('From User to Employment Role')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.givenName)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
...
</archetype>

И уткнемся в архетип User трудоустройство

<sourceLink id="127">
    <name>From role to Employment User</name>
    <selector>
        <type>c:UserType</type>
        <archetypeRef oid="441f8e23-33cd-41f2-bbb6-beea20feeaee" relation="org:default" type="c:ArchetypeType">
            <!-- POCE Employment User ArcheType -->
        </archetypeRef>
    </selector>
</sourceLink>
...
</archetype>

И политика которая будет рекомпутить User трудоустройство(пока не важно но пусть сразу будет) если у нас меняются данные Role трудоустройство

<inducement id="124">
    <policyRule>
        <name>Recompute Users</name>
        <policyConstraints>
            <or id="13">
                <modification id="14">
                    <item xmlns:gen391="http://example.com/xml/ns/mySchema">c:extension/gen391:user_givenName</item>
                </modification>
                <modification id="15">
                    <item xmlns:gen694="http://example.com/xml/ns/mySchema">c:extension/gen694:user_familyName</item>
                </modification>
                <modification id="20">
                    <item xmlns:gen123="http://example.com/xml/ns/mySchema">c:extension/gen123:user_additionalName</item>
                </modification>
                <modification id="22">
                    <item xmlns:gen365="http://example.com/xml/ns/mySchema">c:extension/gen365:user_personalNumber</item>
                </modification>
                <modification id="222">
                    <item xmlns:gen365="http://example.com/xml/ns/mySchema">c:extension/gen365:user_administrativeStatus</item>
                </modification>
                <modification id="223">
                    <item>c:costCenter</item>
                </modification>
            </or>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="16">
                <object>
                    <linkSource id="131">
                        <name>From role to Employment User</name>
                    </linkSource>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>
...
</archetype>

Все с POCE Employment Role ArcheType, но нам нужен под этот архетип еще Object Teplate идем в ConfigutrationObject Templates добавляем новый под названием POCE Employment Role Object Template а в нем кодом

<item id="1">
    <ref>assignment</ref>
    <displayName>Assignment to parent form locality</displayName>
    <mapping id="9">
        <source>
            <path>locality</path>
        </source>
        <expression>
            <assignmentTargetSearch>
                <targetType>RoleType</targetType>
                <filter>
                    <q:equal>
                        <q:path>identifier</q:path>
                        <expression>
                            <path>$locality</path>
                        </expression>
                    </q:equal>
                </filter>
            </assignmentTargetSearch>
        </expression>
    </mapping>
</item>
<mapping id="2">
    <name>generate name</name>
    <strength>strong</strength>
    <source>
        <path>identifier</path>
    </source>
    <source>
        <path>costCenter</path>
    </source>
    <expression>
        <script>
            <code>
                   result = basic.stringify(identifier) + "@" + basic.stringify(costCenter) + "[FUN.OBJ DND]" 
                   return result</code>
        </script>
    </expression>
    <target>
        <path>displayName</path>
    </target>
</mapping>
...
</objectTemplate>

Тут у нас привязка к роли карточка компании из Locality и формирование страшного отталкивающего dispalyName чтобы никто никогда ничего не делал с ролью трудоустройство.

Возвращаемся в архетип POCE Employment Role ArcheType и утыкаем его в POCE Employment Role Object Template в ConfigurationArcheTypeAll archetypesPOCE Employment Role ArcheTypeArcheType PolicyObject template reference

Всё теперь займёмся Resource 1

Но для начала добавим атрибутов в Midpoint. Как обычно в папку /opt/midpoint/var/schema файл employment.xsd

кодом

<xsd:schema elementFormDefault="qualified" targetNamespace="http://example.com/xml/ns/mySchema"
    xmlns:tns="http://example.com/xml/ns/mySchema"
    xmlns:a="http://prism.evolveum.com/xml/ns/public/annotation-3"
    xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:complexType name="RoleExtensionType">
        <xsd:annotation>
            <xsd:appinfo>
                <a:extension ref="c:RoleType"/>
            </xsd:appinfo>
        </xsd:annotation>
        <xsd:sequence>
            <xsd:element name="user_givenName" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>User givenName</a:displayName>
                        <a:displayOrder>136</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_familyName" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>User familyName</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_additionalName" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>User additionalName</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_personalNumber" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>User personalNumber</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_administrativeStatus" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>User administrativeStatus</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_boss" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>User's Boss</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_you_are_boss" type="xsd:boolean" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>Your are Boss</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_employment_type" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>Employment Type</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="user_employment_parent" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>Parent Employment</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
        </xsd:sequence>
    </xsd:complexType>


    <xsd:complexType name="UserExtensionType">
        <xsd:annotation>
            <xsd:appinfo>
                <a:extension ref="c:UserType"/>
            </xsd:appinfo>
        </xsd:annotation>
        <xsd:sequence>
            <xsd:element name="person_boss" type="xsd:string" minOccurs="0" maxOccurs="unbounded">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>Your Bosses</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="person_you_are_boss" type="xsd:boolean" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>You are Boss</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="person_employment_type" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>Employment Type</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>
            <xsd:element name="person_employment_parent" type="xsd:string" minOccurs="0" maxOccurs="1">
                <xsd:annotation>
                    <xsd:appinfo>
                        <a:indexed>true</a:indexed>
                        <a:displayName>Parent Employment</a:displayName>
                        <a:displayOrder>138</a:displayOrder>
                        <a:help>ToDo</a:help>
                    </xsd:appinfo>
                </xsd:annotation>
            </xsd:element>


        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

Помним что

targetNamespace=»http://example.com/xml/ns/mySchema» должен быть уникальным для вашей установки Midpoint ну и присутсовать во всех xsd файлах. Тут у нас доп атрибуты для Role чтобы переносить информацию и для User тоже.

Всё теперь займёмся Resource 1

Хотя нет, сразу немного о данных. Кладем в папку /opt/midpoint/var/info файл POC_EMPLOYMENT_DATA.csv

Вот такие там данные все что нам надо для пример

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 4
number_poce;type_poce;main_id;parent_id;members_poce;member_of_poce;name_poce;grade_poce;title_poce;department_poce;subordinate_to_poce;status_poce;info_01;info_02;info_03
1;user;600667;;;EMP002001,EMP002002;;;;;;active;;;
2;employment;EMP002001;EMP001001;600667;POS000101;;;Основное;;;active;;;
3;employment;EMP002002;EMP001002;600667;POS000125,POS000124;;;Совместительство;;;disabled;;;
4;position;POS000101;EMP002001;;;;;Системный Администратор;;600110;active;;;
5;position;POS000125;EMP002002;;;;;Уборщик;;;disabled;;;
6;position;POS000124;EMP002002;;;;;Грузчик;;;disabled;;;

Так же у нас созданы User’ы под указанные в данных personalNumber

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 5

И карточки компании

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 6

Всё теперь займёмся Resource 1

Создадим ресурс под названием POCE 01 EMPLOYMENT Role на коннекторе ConnId com.evolveum.polygon.connector.csv.CsvConnector v2.8

CSV у нас с мульти значениями будет, настройки ResourcePOCE 01 EMPLOYMENT RoleConnector Configuration

вот такие

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 7

Создаем в ResourcePOCE 01 EMPLOYMENT RoleSceham HandlerObject Types это POCE Employment Role

кодом

<objectType id="36">
    <kind>entitlement</kind>
    <intent>intent POCE Employment Role</intent>
    <displayName>POCE Employment Role</displayName>
    <delineation>
        <objectClass>ri:AccountObjectClass</objectClass>
        <filter>
            <q:text>attributes/type_poce = "employment"</q:text>
        </filter>
    </delineation>
    <focus>
        <type>c:RoleType</type>
        <archetypeRef oid="3e97bf04-93de-486b-a17b-ca686f9c6a68" relation="org:default" type="c:ArchetypeType">
            <!-- POCE Employment Role ArcheType -->
        </archetypeRef>
    </focus>
    <attribute id="47">
        <ref>ri:main_id</ref>
        <inbound id="48">
            <name>01</name>
            <strength>strong</strength>
            <target>
                <path>name</path>
            </target>
        </inbound>
        <inbound id="49">
            <name>02</name>
            <strength>strong</strength>
            <target>
                <path>identifier</path>
            </target>
        </inbound>
        <inbound id="4291">
            <name>04</name>
            <lifecycleState>draft</lifecycleState>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>return true</code>
                </script>
            </expression>
            <target>
                <path>indestructible</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="50">
        <ref>ri:parent_id</ref>
        <inbound id="51">
            <name>03</name>
            <strength>strong</strength>
            <target>
                <path>locality</path>
            </target>
        </inbound>
    </attribute>
    <correlation>
        <correlators>
            <items id="60">
                <item id="61">
                    <ref>identifier</ref>
                </item>
            </items>
        </correlators>
    </correlation>
    <synchronization>
        <reaction id="53">
            <situation>linked</situation>
            <actions>
                <synchronize id="54"/>
            </actions>
        </reaction>
        <reaction id="55">
            <situation>unlinked</situation>
            <actions>
                <link id="56"/>
            </actions>
        </reaction>
        <reaction id="57">
            <situation>unmatched</situation>
            <actions>
                <addFocus id="58"/>
            </actions>
        </reaction>
    </synchronization>
</objectType>
 
...
</schemaHandling>
...
</resource>

Ничего особенного, только в мапинге 04 делаю все роли Трудоустройства indestructible чтобы совсем было трудно их удалять.

Создаем в ResourcePOCE 01 EMPLOYMENT RoleSceham HandlerObject Types это POCE User

кодом

<objectType id="6">
    <kind>account</kind>
    <intent>intent POCE User</intent>
    <displayName>POCE User</displayName>
    <default>true</default>
    <delineation>
        <objectClass>ri:AccountObjectClass</objectClass>
        <filter>
            <q:text>attributes/type_poce = "user"</q:text>
        </filter>
    </delineation>
    <focus>
        <type>c:UserType</type>
        <archetypeRef oid="00000000-0000-0000-0000-000000000702" relation="org:default" type="c:ArchetypeType">
            <!-- Person -->
        </archetypeRef>
    </focus>
    <attribute id="11">
        <ref>ri:main_id</ref>
        <inbound id="12">
            <name>01 poce id</name>
            <strength>strong</strength>
            <target>
                <path>personalNumber</path>
            </target>
            <use>correlation</use>
        </inbound>
    </attribute>
    <association id="306">
        <ref>CSV members from employement to MP user</ref>
        <inbound id="478">
            <strength>normal</strength>
            <channel>http://midpoint.evolveum.com/xml/ns/public/common/channels-3#reconciliation</channel>
            <expression>
                <assignmentTargetSearch>
                    <targetType>RoleType</targetType>
                    <filter>
                        <q:equal>
                            <q:path>identifier</q:path>
                            <expression>
                                <script>
                                    <code>
                                        return basic.getAttributeValue(entitlement, 'main_id')
                                    </code>
                                </script>
                            </expression>
                        </q:equal>
                    </filter>
                </assignmentTargetSearch>
            </expression>
            <target>
                <path>assignment</path>
            </target>
        </inbound>
        <kind>entitlement</kind>
        <intent>intent POCE Employment Role</intent>
        <direction>objectToSubject</direction>
        <associationAttribute>ri:members_poce</associationAttribute>
        <valueAttribute>ri:main_id</valueAttribute>
        <explicitReferentialIntegrity>false</explicitReferentialIntegrity>
    </association>
    <correlation>
        <correlators>
            <items id="19">
                <item id="20">
                    <ref>personalNumber</ref>
                </item>
            </items>
        </correlators>
    </correlation>
    <synchronization>
        <reaction id="14">
            <situation>linked</situation>
            <actions>
                <synchronize id="15"/>
            </actions>
        </reaction>
        <reaction id="16">
            <situation>unlinked</situation>
            <actions>
                <link id="17"/>
            </actions>
        </reaction>
    </synchronization>
</objectType>
...
</schemaHandling>
...
</resource>

Тут интересно что ну никак новые associations не заработали на csv сделал по старинке. Schema Handler Objject Type для Сотрудников берет из Schema Handler Objject Type для роли Трудоустройство поле members_poce и навешивает эту роль сотрудником с таким же main_id у сотрудников в csv.

Запускаем сначала реконсиляцию ResourcePOCE 01 EMPLOYMENT RoleSceham HandlerObject TypesPOCE Employment Role

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 8

Появляются роли Трудоустройства, в них уже сработало заполнение costCentra человеческим названием и роли карточка Компании.

Теперь реконсилирую ResourcePOCE 01 EMPLOYMENT RoleSceham HandlerObject TypesPOCE User. Иду в роль и вижу что все наполнилось.

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 9

Теперь докидаю код на все остальное, чтобы у нас уже было все как в полной схеме

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 10

Архетип 4

Создаем для него Object template под именем POCE Employment User Object Template в ConfigutrationObject Templates

код

<item id="1">
    <ref>assignment</ref>
    <displayName>Assignment to Employment Role form organizationalUnit</displayName>
    <mapping id="9">
        <source>
            <path>organizationalUnit</path>
        </source>
        <expression>
            <assignmentTargetSearch>
                <targetType>RoleType</targetType>
                <filter>
                    <q:text>identifier = $organizationalUnit and archetypeRef matches (oid = "3e97bf04-93de-486b-a17b-ca686f9c6a68")</q:text>
                </filter>
            </assignmentTargetSearch>
        </expression>
    </mapping>

</item>
<mapping id="2">
    <name>generate-fullname</name>
    <description>Generate fullName for Position User</description>
    <strength>strong</strength>
    <source>
        <path>givenName</path>
    </source>
    <source>
        <path>familyName</path>
    </source>
    <source>
        <path>additionalName</path>
    </source>
    <source>
        <path>costCenter</path>
    </source>
    <source>
        <path>title</path>
    </source>
    <source>
        <path>personalNumber</path>
    </source>
    <expression>
        <script>
            <code>
                tmpGivenName = basic.stringify(givenName)?.take(1).toUpperCase()
                tmpadditionalName = basic.stringify(additionalName)?.take(1).toUpperCase()
                tmpfamilyName = basic.stringify(familyName)
                tmppersonalNumber = basic.stringify(personalNumber)
                tmpcostCenter = basic.stringify(costCenter)
                tmpEmpType = basic.getExtensionPropertyValue(user, 'http://example.com/xml/ns/mySchema', 'person_employment_type')
                result = tmppersonalNumber + " " + tmpGivenName + "." + tmpadditionalName + "." + tmpfamilyName + " трудоустройство в " + tmpcostCenter + " " + tmpEmpType
                return result 
            </code>
        </script>
    </expression>
    <target>
        <path>fullName</path>
    </target>
</mapping>

Архетип POCE Employment User ArcheType у нас уже создан. Утыкаем его в POCE Employment User Object Template в ArcheType PolicyObject template reference

Добавляем в архетип код

<inducement id="7">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>
linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_givenName")   
                    </code>
                </script>
            </expression>
            <target>
                <path>givenName</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_givenName"))}


                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="12">
    <policyRule>
        <name>Recompute Position Role on Employment User data changes</name>
        <policyConstraints>
            <or id="13">
                <modification id="14">
                    <item>
                        <_value>c:givenName</_value>
                    </item>
                </modification>
                <modification id="15">
                    <item>
                        <_value>c:familyName</_value>

                    </item>
                </modification>
                <modification id="20">
                    <item>c:additionalName</item>
                </modification>
                <modification id="22">
                    <item>c:activation/c:administrativeStatus</item>
                </modification>
                <modification id="3340">
                    <item>c:costCenter</item>
                </modification>
            </or>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="16">
                <object>
                    <linkTarget id="17">
                        <linkType>from me to Position role</linkType>
                    </linkTarget>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>
<inducement id="17">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <relativityMode>absolute</relativityMode>
                    <code>
linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_familyName")  
                    </code>
                </script>
            </expression>
            <target>
                <path>familyName</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_familyName"))}


                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings
    <inducement id="27">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <relativityMode>absolute</relativityMode>
                    <code>
    linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_additionalName") 
                    </code>
                </script>
            </expression>
            <target>
                <path>additionalName</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_additionalName"))}


                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="37">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <relativityMode>absolute</relativityMode>
                    <code>
    linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_personalNumber") 
                            
                    </code>
                </script>
            </expression>
            <target>
                <path>personalNumber</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_personalNumber"))}


                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="176">
    <policyRule>
        <name>Recompute Role Position on User Employment membership change</name>
        <policyConstraints>
            <alwaysTrue id="177"/>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="178">
                <object>
                    <linkTarget id="179">
                        <changeSituation>changed</changeSituation>
                        <linkType>from me to Position role</linkType>
                    </linkTarget>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>
<inducement id="372">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <relativityMode>absolute</relativityMode>
                    <code>
     linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
return linkedDATA.costCenter 
                            
                    </code>
                </script>
            </expression>
            <target>
                <path>costCenter</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(linkedDATA.costCenter)}


                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="3337">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <relativityMode>absolute</relativityMode>
                    <code>linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
                           "Employee status: " + basic.stringify(basic.getExtensionPropertyValue(linkedDATA , "http://example.com/xml/ns/mySchema", "user_administrativeStatus"))
                            
                           


                    </code>
                </script>
            </expression>
            <target>
                <path>documentation</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('from Employment Role to me')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_administrativeStatus"))}



                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="462">
    <focusMappings>
        <mapping id="7">
            <documentation>organization From User to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('from Employment User to me')
if (linkedDATA != null )
{return linkedDATA.organization}
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/documentation</path>
            </target>
        </mapping>
    </focusMappings>
</inducement>
<archetypePolicy>
       ...
    <links>
        <targetLink id="4">
            <name>from Employment Role to me</name>
            <selector>
                <type>c:RoleType</type>
                <archetypeRef oid="3e97bf04-93de-486b-a17b-ca686f9c6a68" relation="org:default" type="c:ArchetypeType">
                    <!-- POCE Employment Role ArcheType -->
                </archetypeRef>
            </selector>
        </targetLink>
        <targetLink id="3338">
            <name>from me to Position role</name>
            <selector>
                <type>c:RoleType</type>
                <archetypeRef oid="47374624-553c-4661-b116-d07952900451" relation="org:default" type="c:ArchetypeType">
                    <!-- POCE Position Role ArcheType -->
                </archetypeRef>
            </selector>
        </targetLink>
    </links>
</archetypePolicy>
</archetype>

код в links надо будет самим протыкать в ArcheType Policylinks но сохраняйте в name

Архетип 5

Создаем для него Object template под именем POCE Position Role Object Template в ConfigutrationObject Templates

код

<mapping id="4">
    <name>generate name</name>
    <strength>strong</strength>
    <source>
        <path>identifier</path>
    </source>
    <source>
        <path>costCenter</path>
    </source>
    <expression>
        <script>
            <includeNullInputs>true</includeNullInputs>
            <code>
                   result = basic.stringify(identifier) + "@" + basic.stringify(costCenter) + "[FUN.OBJ DND]" 
                   return result</code>
        </script>
    </expression>
    <target>
        <path>displayName</path>
    </target>
</mapping>

В ConfigurationArcheTypeAll archetypes создаем архетип под именем POCE Position Role ArcheType

Утыкаем его в POCE Position Role Object Template в ArcheType PolicyObject template reference

Добавляем в него код

<inducement id="16">
    <lifecycleState>active</lifecycleState>
    <focusMappings>
        <mapping id="7">
            <name>01</name>
            <documentation>costCenter</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>
linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return linkedDATA.costCenter
                    </code>
                </script>
            </expression>
            <target>
                <path>costCenter</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.costCenter)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="26">
    <focusMappings>
        <mapping id="7">
            <documentation>familyName From User to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return linkedDATA.familyName
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_familyName</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.familyName)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="36">
    <focusMappings>
        <mapping id="7">
            <documentation>additionalName From User to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return linkedDATA.additionalName

                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_additionalName</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.additionalName)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="46">
    <focusMappings>
        <mapping id="7">
            <documentation>personalNumber From User to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return linkedDATA.personalNumber
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_personalNumber</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.personalNumber)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="47">
    <focusMappings>
        <mapping id="8">
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <relativityMode>absolute</relativityMode>
                    <code>
  
linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return basic.stringify(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "person_employment_type"))
               
                            
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_employment_type</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "person_employment_type"))}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="56">
    <focusMappings>
        <mapping id="7">
            <documentation>administrativeStatus From User Position to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType
linkedSource = midpoint.findLinkedSource('from me Position Role to Position User')
if (basic.isEmpty(linkedSource))
{return 'NO CONNECTION'}
else
{
if (basic.isEmpty(linkedSource.activation.effectiveStatus))
{return 'UNDIFIEND'}
else
{return basic.stringify(linkedSource.activation.effectiveStatus)}

}
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_administrativeStatus</path>
            </target>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="124">
    <policyRule>
        <name>Recompute Position Users</name>
        <policyConstraints>
            <or id="13">
                <modification id="14">
                    <item xmlns:gen391="http://example.com/xml/ns/mySchema">c:extension/gen391:user_givenName</item>
                </modification>
                <modification id="15">
                    <item xmlns:gen694="http://example.com/xml/ns/mySchema">c:extension/gen694:user_familyName</item>
                </modification>
                <modification id="20">
                    <item xmlns:gen123="http://example.com/xml/ns/mySchema">c:extension/gen123:user_additionalName</item>
                </modification>
                <modification id="22">
                    <item xmlns:gen365="http://example.com/xml/ns/mySchema">c:extension/gen365:user_personalNumber</item>
                </modification>
                <modification id="223">
                    <item>c:costCenter</item>
                </modification>
                <modification id="224">
                    <item>c:organization</item>
                </modification>
            </or>
        </policyConstraints>
        <policyActions>
            <scriptExecution id="16">
                <object>
                    <linkSource id="131">
                        <name>from me Position Role to Position User</name>
                    </linkSource>
                </object>
                <executeScript xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
                    <s:recompute/>
                </executeScript>
            </scriptExecution>
        </policyActions>
    </policyRule>
</inducement>
<inducement id="262">
    <focusMappings>
        <mapping id="7">
            <name>02</name>
            <documentation>givenName From User to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return linkedDATA.givenName

                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/extension/user_givenName</path>
            </target>
            <condition>
                <script>
                    <code>linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.givenName)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<inducement id="462">
    <focusMappings>
        <mapping id="7">
            <documentation>personalNumber From User to Position Role</documentation>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>


linkedDATA = midpoint.findLinkedSource('from Employment User to me')
return basic.stringify(linkedDATA.organization)
                    </code>
                </script>
            </expression>
            <target>
                <path>$focus/documentation</path>
            </target>
            <condition>
                <script>
                    <code>
                        linkedDATA = midpoint.findLinkedSource('from Employment User to me')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else
                        {return !basic.isEmpty(linkedDATA.organization)}</code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement>
<archetypePolicy>
    <display>
        <icon>
            <cssClass>fa fa-user-tie</cssClass>
            <color>#d88222</color>
        </icon>
    </display>
    <objectTemplateRef oid="b4a0f1d5-fd79-4088-8147-d55f98b896c2" relation="org:default" type="c:ObjectTemplateType">
        <!-- POCE Position Role Object Template -->
    </objectTemplateRef>
    <links>
        <sourceLink id="3">
            <name>from Employment User to me</name>
            <selector>
                <type>c:UserType</type>
                <archetypeRef oid="441f8e23-33cd-41f2-bbb6-beea20feeaee" relation="org:default" type="c:ArchetypeType">
                    <!-- POCE Employment User ArcheType -->
                </archetypeRef>
            </selector>
        </sourceLink>
        <sourceLink id="264">
            <name>from me Position Role to Position User</name>
            <selector>
                <type>c:UserType</type>
                <archetypeRef oid="0d1b1269-0011-49e6-b9f1-e62e7827dfed" relation="org:default" type="c:ArchetypeType">
                    <!-- POCE Position User ArcheType -->
                </archetypeRef>
            </selector>
        </sourceLink>
    </links>
</archetypePolicy>
</archetype>

код в links надо будет самим протыкать в ArcheType Policylinks но сохраняйте в name

Архетип 6

Создаем для него Object template под именем POCE Position User Object Template в ConfigutrationObject Templates

код

<item id="1">
    <ref>assignment</ref>
    <displayName>Assignment to position Role</displayName>
    <mapping id="9">
        <source>
            <path>name</path>
        </source>
        <expression>
            <assignmentTargetSearch>
                <targetType>RoleType</targetType>
                <filter>
                    <q:text>identifier = $name and archetypeRef matches (oid = "47374624-553c-4661-b116-d07952900451")</q:text>
                </filter>
            </assignmentTargetSearch>
        </expression>
    </mapping>
</item>
<mapping id="2">
    <name>generate-fullname</name>
    <description>Generate fullName for Position User</description>
    <strength>strong</strength>
    <source>
        <path>givenName</path>
    </source>
    <source>
        <path>familyName</path>
    </source>
    <source>
        <path>additionalName</path>
    </source>
    <source>
        <path>costCenter</path>
    </source>
    <source>
        <path>title</path>
    </source>
    <source>
        <path>personalNumber</path>
    </source>
    <expression>
        <script>
            <code>
                tmpGivenName = basic.stringify(givenName)?.take(1).toUpperCase()
                tmpadditionalName = basic.stringify(additionalName)?.take(1).toUpperCase()
                tmpfamilyName = basic.stringify(familyName)
                tmptitle = basic.stringify(title)
                tmppersonalNumber = basic.stringify(personalNumber)
                tmpcostCenter = basic.stringify(costCenter)
                result = tmppersonalNumber + " " + tmpGivenName + "." + tmpadditionalName + "." + tmpfamilyName + " " + tmptitle + " в " + tmpcostCenter
                return result 
            </code>
        </script>
    </expression>
    <target>
        <path>fullName</path>
    </target>
</mapping>

В ConfigurationArcheTypeAll archetypes создаем архетип под именем POCE Position User ArcheType

Утыкаем его в POCE Position User Object Template в ArcheType PolicyObject template reference

Добавляем в него код

<inducement id="7">
    <focusMappings>
        <mapping id="8">
            <name>1</name>
            <authoritative>false</authoritative>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>
                           linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                           return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_givenName")
                    </code>
                </script>
            </expression>
            <target>
                <path>givenName</path>
            </target>
            <condition>
                <script>
                    <code>

linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_givenName"))}


                    </code>
                </script>
            </condition>
        </mapping>
    </focusMappings>
</inducement
    <inducement id="17">
<focusMappings>
    <mapping id="8">
        <authoritative>false</authoritative>
        <strength>strong</strength>
        <expression>
            <script>
                <code>
                           linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                           return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_familyName")
                </code>
            </script>
        </expression>
        <target>
            <path>familyName</path>
        </target>
        <condition>
            <script>
                <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_familyName"))}


                        
                </code>
            </script>
        </condition>
    </mapping>
</focusMappings>
</inducement>
<inducement id="27">
<focusMappings>
    <mapping id="8">
        <authoritative>false</authoritative>
        <strength>strong</strength>
        <expression>
            <script>
                <code>
                           linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                           return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_additionalName")
                </code>
            </script>
        </expression>
        <target>
            <path>additionalName</path>
        </target>
        <condition>
            <script>
                <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_additionalName"))}

                </code>
            </script>
        </condition>
    </mapping>
</focusMappings>
</inducement>
<inducement id="37">
<focusMappings>
    <mapping id="8">
        <authoritative>false</authoritative>
        <strength>strong</strength>
        <expression>
            <script>
                <code>
                           linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                           return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_personalNumber")
                            
                </code>
            </script>
        </expression>
        <target>
            <path>personalNumber</path>
        </target>
        <condition>
            <script>
                <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_personalNumber"))}

                </code>
            </script>
        </condition>
    </mapping>
</focusMappings>
</inducement>
<inducement id="47">
<focusMappings>
    <mapping id="8">
        <authoritative>false</authoritative>
        <strength>strong</strength>
        <expression>
            <script>
                <relativityMode>absolute</relativityMode>
                <code>
                           linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                           return basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_employment_type")
                </code>
            </script>
        </expression>
        <target>
            <path>$focus/extension/person_employment_type</path>
        </target>
        <condition>
            <script>
                <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_employment_type"))}
                </code>
            </script>
        </condition>
    </mapping>
</focusMappings>
</induceme
    <inducement id="327">
<focusMappings>
<mapping id="8">
    <authoritative>false</authoritative>
    <strength>strong</strength>
    <expression>
        <script>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
return linkedDATA.costCenter
            </code>
        </script>
    </expression>
    <target>
        <path>costCenter</path>
    </target>
    <condition>
        <script>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(linkedDATA.costCenter)}
            </code>
        </script>
    </condition>
</mapping>
</focusMappings>
</inducement>
<inducement id="417">
<focusMappings>
<mapping id="8">
    <authoritative>false</authoritative>
    <strength>strong</strength>
    <expression>
        <script>
            <relativityMode>absolute</relativityMode>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
return linkedDATA.locality
                            
            </code>
        </script>
    </expression>
    <target>
        <path>$focus/extension/person_employment_parent</path>
    </target>
    <condition>
        <script>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(linkedDATA.locality)}
            </code>
        </script>
    </condition>
</mapping>
</focusMappings>
</inducement>
<inducement id="418">
<focusMappings>
<mapping id="8">
    <authoritative>false</authoritative>
    <strength>strong</strength>
    <expression>
        <script>
            <relativityMode>absolute</relativityMode>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
return basic.stringify(linkedDATA.documentation)
                            
            </code>
        </script>
    </expression>
    <target>
        <path>$focus/organization</path>
    </target>
    <condition>
        <script>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                        if (basic.isEmpty(linkedDATA))
                        {return false}
                        else{return !basic.isEmpty(linkedDATA.documentation)}
            </code>
        </script>
    </condition>
</mapping>
</focusMappings>
</inducement>
<inducement id="3337">
<focusMappings>
<mapping id="8">
    <strength>strong</strength>
    <expression>
        <script>
            <code>
                           linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
                            "Employment status: " + basic.stringify(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_administrativeStatus") )
                                          
                                      
            </code>
        </script>
    </expression>
    <target>
        <path>documentation</path>
    </target>
    <condition>
        <script>
            <code>
linkedDATA = midpoint.findLinkedTarget('From Position Role to Position User')
if (basic.isEmpty(linkedDATA))
{return false}
else
{return !basic.isEmpty(basic.getExtensionPropertyValue(linkedDATA, "http://example.com/xml/ns/mySchema", "user_administrativeStatus"))}
            </code>
        </script>
    </condition>
</mapping>
</focusMappings>
</inducement>
<archetypePolicy>
<display>
<icon>
    <cssClass>fa fa-user-tie</cssClass>
    <color>#2d860a</color>
</icon>
</display>
<objectTemplateRef oid="9af76493-714f-41e6-9864-34eb5ea469ea" relation="org:default" type="c:ObjectTemplateType">
<!-- POCE Position User Object Template -->
</objectTemplateRef>
<links>
<targetLink id="3">
    <name>From Position Role to Poistion User</name>
    <selector>
        <type>c:RoleType</type>
        <archetypeRef oid="47374624-553c-4661-b116-d07952900451" relation="org:default" type="c:ArchetypeType">
            <!-- POCE Position Role ArcheType -->
        </archetypeRef>
    </selector>
</targetLink>
</links>
</archetypePolicy>
</archetype>

код в links надо будет самим протыкать в ArcheType Policylinks но сохраняйте в name

Теперь Ресурсы

Ресурс 1

Создан ранее

Ресурс 2

Делаем Dublicate первого ресурса POCE 01 EMPLOYMENT Role назовем его POCE 02 EMPLOYMENT User + POSITIONS Role

Удаляем все в Sceham HandlerObject Types и создаем свои:

POCE Employment as user

кодом

<objectType id="74">
    <kind>account</kind>
    <intent>intent POCE Employment as user</intent>
    <displayName>POCE Employment as user</displayName>
    <default>false</default>
    <delineation>
        <objectClass>ri:AccountObjectClass</objectClass>
        <filter>
            <_metadata id="4282">
                <provenance>
                    <acquisition id="4283">
                        <actorRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType">
                            <!-- administrator -->
                        </actorRef>
                        <channel>http://midpoint.evolveum.com/xml/ns/public/common/channels-3#user</channel>
                        <timestamp>2025-03-15T06:06:59.344Z</timestamp>
                    </acquisition>
                </provenance>
            </_metadata>
            <q:text>attributes/type_poce = "employment"</q:text>
        </filter>
    </delineation>
    <focus>
        <type>c:UserType</type>
        <archetypeRef oid="441f8e23-33cd-41f2-bbb6-beea20feeaee" relation="org:default" type="c:ArchetypeType">
            <!-- POCE Employment User ArcheType -->
        </archetypeRef>
    </focus>
    <attribute id="75">
        <ref>ri:main_id</ref>
        <inbound id="157">
            <name>03</name>
            <strength>strong</strength>
            <target>
                <path>organizationalUnit</path>
            </target>
        </inbound>
        <inbound id="4286">
            <name>04</name>
            <strength>strong</strength>
            <target>
                <path>name</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="125">
        <ref>ri:members_poce</ref>
        <inbound id="126">
            <name>01 poce id</name>
            <strength>strong</strength>
            <target>
                <path>personalNumber</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="127">
        <ref>ri:parent_id</ref>
        <inbound id="128">
            <name>02 parent id</name>
            <strength>strong</strength>
            <target>
                <path>organization</path>
            </target>
            <use>synchronization</use>
        </inbound>
    </attribute>
    <attribute id="4300">
        <ref>ri:status_poce</ref>
        <inbound id="4301">
            <name>05 status</name>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType;


if (input == 'disabled')
{return ActivationStatusType.DISABLED}
else
{return null}</code>
                </script>
            </expression>
            <target>
                <path>activation/administrativeStatus</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="4306">
        <ref>ri:title_poce</ref>
        <inbound id="4307">
            <name>06</name>
            <strength>strong</strength>
            <target>
                <path>extension/person_employment_type</path>
            </target>
        </inbound>
    </attribute>
    <association id="3026">
        <ref>CSV position to employment</ref>
        <inbound id="4278">
            <strength>normal</strength>
            <channel>http://midpoint.evolveum.com/xml/ns/public/common/channels-3#reconciliation</channel>
            <expression>
                <assignmentTargetSearch>
                    <targetType>RoleType</targetType>
                    <filter>
                        <q:equal>
                            <q:path>identifier</q:path>
                            <expression>
                                <script>
                                    <code>
                                                return basic.getAttributeValue(entitlement, 'main_id')
                                    </code>
                                </script>
                            </expression>
                        </q:equal>
                    </filter>
                </assignmentTargetSearch>
            </expression>
            <target>
                <path>assignment</path>
            </target>
        </inbound>
        <kind>entitlement</kind>
        <intent>intent POCE Position Role</intent>
        <direction>objectToSubject</direction>
        <associationAttribute>ri:parent_id</associationAttribute>
        <valueAttribute>ri:main_id</valueAttribute>
        <explicitReferentialIntegrity>false</explicitReferentialIntegrity>
    </association>
    <correlation>
        <correlators>
            <items id="81">
                <item id="82">
                    <ref>name</ref>
                </item>
            </items>
        </correlators>
    </correlation>
    <synchronization>
        <reaction id="83">
            <situation>linked</situation>
            <actions>
                <synchronize id="84"/>
            </actions>
        </reaction>
        <reaction id="85">
            <situation>unlinked</situation>
            <actions>
                <link id="86"/>
            </actions>
        </reaction>
        <reaction id="4288">
            <situation>unmatched</situation>
            <actions>
                <addFocus id="4289"/>
            </actions>
        </reaction>
    </synchronization>
</objectType>
...
</schemaHandling>
...
</resource>

и

POCE Position Role

код

<objectType id="87">
    <kind>entitlement</kind>
    <intent>intent POCE Position Role</intent>
    <displayName>POCE Position Role</displayName>
    <lifecycleState>active</lifecycleState>
    <delineation>
        <objectClass>ri:AccountObjectClass</objectClass>
        <filter>
            <_metadata id="4296">
                <provenance>
                    <acquisition id="4297">
                        <actorRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType">
                            <!-- administrator -->
                        </actorRef>
                        <channel>http://midpoint.evolveum.com/xml/ns/public/common/channels-3#user</channel>
                        <timestamp>2025-03-15T06:40:49.686Z</timestamp>
                    </acquisition>
                </provenance>
            </_metadata>
            <q:text>attributes/type_poce = "position"</q:text>
        </filter>
    </delineation>
    <focus>
        <type>c:RoleType</type>
        <archetypeRef oid="47374624-553c-4661-b116-d07952900451" relation="org:default" type="c:ArchetypeType">
            <!-- POCE Position Role ArcheType -->
        </archetypeRef>
    </focus>
    <attribute id="88">
        <ref>ri:main_id</ref>
        <inbound id="89">
            <name>01</name>
            <strength>strong</strength>
            <target>
                <path>name</path>
            </target>
        </inbound>
        <inbound id="90">
            <name>02</name>
            <strength>strong</strength>
            <target>
                <path>identifier</path>
            </target>
        </inbound>
        <inbound id="4303">
            <name>05</name>
            <lifecycleState>draft</lifecycleState>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>return true</code>
                </script>
            </expression>
            <target>
                <path>indestructible</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="91">
        <ref>ri:parent_id</ref>
        <inbound id="92">
            <name>03</name>
            <strength>strong</strength>
            <target>
                <path>locality</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="150">
        <ref>ri:title_poce</ref>
        <inbound id="151">
            <name>04</name>
            <strength>strong</strength>
            <target>
                <path>locale</path>
            </target>
        </inbound>
    </attribute>
    <correlation>
        <correlators>
            <items id="93">
                <item id="94">
                    <ref>identifier</ref>
                </item>
            </items>
        </correlators>
    </correlation>
    <synchronization>
        <reaction id="95">
            <situation>linked</situation>
            <actions>
                <synchronize id="96"/>
            </actions>
        </reaction>
        <reaction id="97">
            <situation>unlinked</situation>
            <actions>
                <link id="98"/>
            </actions>
        </reaction>
        <reaction id="99">
            <situation>unmatched</situation>
            <actions>
                <addFocus id="100"/>
            </actions>
        </reaction>
    </synchronization>
</objectType>
...
</schemaHandling>
...
</resource>

Ресурс 3

Делаем Dublicate первого ресурса POCE 01 EMPLOYMENT Role назовем его POCE 03 POSITIONS USER

Удаляем все в Sceham HandlerObject Types и создаем свой

POCE Positions to user in MP

кодом

<objectType id="208">
    <kind>account</kind>
    <intent>intent POCE Positions to user in MP</intent>
    <displayName>POCE Positions to user in MP</displayName>
    <default>true</default>
    <delineation>
        <objectClass>ri:AccountObjectClass</objectClass>
        <filter>
            <_metadata id="227">
                <provenance>
                    <acquisition id="228">
                        <actorRef oid="00000000-0000-0000-0000-000000000002" relation="org:default" type="c:UserType">
                            <!-- administrator -->
                        </actorRef>
                        <channel>http://midpoint.evolveum.com/xml/ns/public/common/channels-3#user</channel>
                        <timestamp>2025-03-14T09:52:02.628Z</timestamp>
                    </acquisition>
                </provenance>
            </_metadata>
            <q:text>attributes/type_poce = "position"</q:text>
        </filter>
    </delineation>
    <focus>
        <type>c:UserType</type>
        <archetypeRef oid="0d1b1269-0011-49e6-b9f1-e62e7827dfed" relation="org:default" type="c:ArchetypeType">
            <!-- POCE Position User ArcheType -->
        </archetypeRef>
    </focus>
    <attribute id="211">
        <ref>ri:main_id</ref>
        <inbound id="212">
            <name>01</name>
            <strength>strong</strength>
            <target>
                <path>name</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="214">
        <ref>ri:title_poce</ref>
        <inbound id="215">
            <name>03</name>
            <strength>strong</strength>
            <target>
                <path>title</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="232">
        <ref>ri:status_poce</ref>
        <inbound id="233">
            <name>02 status</name>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType;


if (input == 'disabled')
{return ActivationStatusType.DISABLED}
else
{return null}</code>
                </script>
            </expression>
            <target>
                <path>activation/administrativeStatus</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="241">
        <ref>ri:subordinate_to_poce</ref>
        <inbound id="242">
            <name>04</name>
            <strength>strong</strength>
            <target>
                <path>extension/person_boss</path>
            </target>
        </inbound>
    </attribute>
    <attribute id="243">
        <ref>ri:info_03</ref>
        <inbound id="244">
            <name>05</name>
            <strength>strong</strength>
            <expression>
                <script>
                    <code>if (input == "YES")
{return true}
else
{return false}</code>
                </script>
            </expression>
            <target>
                <path>extension/person_you_are_boss</path>
            </target>
        </inbound>
    </attribute>
    <correlation>
        <correlators>
            <items id="224">
                <item id="225">
                    <ref>name</ref>
                </item>
            </items>
        </correlators>
    </correlation>
    <synchronization>
        <reaction id="217">
            <situation>unmatched</situation>
            <actions>
                <addFocus id="218"/>
            </actions>
        </reaction>
        <reaction id="219">
            <situation>linked</situation>
            <actions>
                <synchronize id="220"/>
            </actions>
        </reaction>
        <reaction id="221">
            <situation>unlinked</situation>
            <actions>
                <link id="222"/>
            </actions>
        </reaction>
    </synchronization>
</objectType>
...
</schemaHandling>
...
</resource>

Всё по настройке.

Запускаем реконсиляцию

Ресурс 1

— POCE Employment Role

Созданы роли Employment, в них от User сотрудник пусто

— POCE User

Ничего не создано. Midpoint привязал к User сотрудник, проекцию в Ресурсе и вот тут уже выдал роли Employment, которые положены по Ресурсу, это триггернуло наполнение данными роли Employment.

Ресурс 2

— POCE Position Role

Созданы роли Position, в них от User сотрудник пусто

— POCE Employment as user

Созданы User Employment, по Object Template навешаны роли Employment

из ресурса им навешались роли Employment роли Position, во всех перетекли данные из User сотрудник по цепочке.

Ресурс 3

— Recon Position User

Созданы User Position, по Object Template навешаны роли Position, перетекли данные User сотрудник.

Смотрим роли переносчики, поиском по кастомному атрибуту User personalNumber

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 11

Смотрим User поиск по personalNumber

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 12

Вот они все и на них всех можно запрашивать роли. Зеленый человечек сотрудник как пользователь Midpoint, зеленый пропуск его трудоустройства, а зеленые человечки в галстуке его назначения на должность.

Откроем 600667 А.В.Кот Системный Администратор в ООО «ОДИН»

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 13

В нем мы не видим откуда но информация пришла

из роль карточка компании

— CostCenter

из пользователь Midpoint архетип Person

— Given Name

— Family Name

— Additional Name

из пользователь трудоустройство

— Documentation (статус в Midpoint пользователя трудоустройство)

— Employment Type (из ресурса 2)

— Parent Employment

из ресурс 3

— Titel

— Your Bosses

— You are Boss

— administrativeStatus(если в ресурсе заблокирован то в MP тоже.

Теперь самое главное меняем в роли карточка компании название, а в пользователе Midpoint фамилию!

Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I - 14

Всё поменялось автоматически из первоисточника.

Вот так можно быстро, а главное просто, в Midpoint выстроить структуру трудоустройств и назначений!

Автор: AlexandrBu

Источник

Обсуждение закрыто.