Реализация концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint part I
Реализации концепции Сотрудник-Трудоустройство-Назначение на должность в IDM Midpoint нет. Это видимо из-за наивного представления что сотрудник будет работать в той компании в которую устраивается и трудоустройство у него будет одно… но это слишком наивное представление о работе, в реальности сотрудник думает что устраивается в одну известную компанию, а оказывается что это не компания а бренд, а в этом бренде несколько компаний, оформят его рандомно в одну из них, да еще например поставят работать в головной офис, а оформят в регион потому что там зарплата меньше, но сразу скажу что дальше концепцию на регионы или проекты я продлевать не стал хотя это тоже можно сделать. В этой первой части я сосредоточусь на скелете концепции и на перетекании информации в нем. Концепция оказалась очень большой да еще и расширяющейся, поэтому будет три части:
1. Получение данных из кадрового ресурса, построение информационных связей и структуры.
2. Назначение ролей, создание AD учетки, реализация концепций Forward Ролей и nickName как роль.
3. Запрос ролей сотрудником, запрос начальником ролей для сотрудника.
Что будет работать в конце этой статьи: Из источника ресурса получим Трудоустройства, Назначения. Вкачаем в них ФИО сотрудника из его основной учетки в Midpoint, тоже самое с названием фирмы.
Реализовывать всё буду на Linked Objects в нем все нужное досконально описывать при настройки. Evolvеum имеет другой более понятный механизм Persona но он не дописан и совершенно не масштабируем, хотя подходит для создания типовых Должностей или Аккаунтов, но не больше одной на одного сотрудника потому что все привязано к ArcheType и ObjectTemplate.
Первым делом надо ответить на вопрос что есть трудоустройство User или Role?! И User и Role! Для понимания простенькая схемка что происходит

У нас есть кадровый источник где лежат 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
И для полнейшего понимания схемкой что у нас получилось по связям

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

Все кроме пока 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
Вот такие там данные все что нам надо для пример

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

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

Всё теперь займёмся Resource 1
Создадим ресурс под названием POCE 01 EMPLOYMENT Role на коннекторе ConnId com.evolveum.polygon.connector.csv.CsvConnector v2.8
CSV у нас с мульти значениями будет, настройки ResourcePOCE 01 EMPLOYMENT RoleConnector Configuration
вот такие

Создаем в 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

Появляются роли Трудоустройства, в них уже сработало заполнение costCentra человеческим названием и роли карточка Компании.
Теперь реконсилирую ResourcePOCE 01 EMPLOYMENT RoleSceham HandlerObject TypesPOCE User. Иду в роль и вижу что все наполнилось.

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

Архетип 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

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

Вот они все и на них всех можно запрашивать роли. Зеленый человечек сотрудник как пользователь Midpoint, зеленый пропуск его трудоустройства, а зеленые человечки в галстуке его назначения на должность.
Откроем 600667 А.В.Кот Системный Администратор в ООО «ОДИН»

В нем мы не видим откуда но информация пришла
из роль карточка компании
— 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 фамилию!

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