﻿<?xml version="1.0" encoding="utf-8"?>
<ReportsExport>
  <Reports>
    <Report id="44e7f468-494b-4656-a4a5-a8f077ca1179" codekey="Pflichtschulungs-Report für Führungskräfte BE3" categoryCodekey="UserStats" name="Pflichtschulungs-Report BE3 / Mandatory training report DL3" description="&lt;p&gt;&lt;b&gt;Pflichtschulungs-Report BE3&lt;/b&gt;&lt;/p&gt;&#xD;&#xA;&lt;p&gt;Dieser Report stellt tagesaktuell und namensbezogen den Lernstand der Mitarbeiter Ihrer und aller unterstellten Organisationseinheiten für eine Pflichtschulung dar und bezieht sich nur auf Benutzer, die an der Pflichtschulung teilnehmen müssen.&lt;/p&gt;&#xD;&#xA;&lt;p&gt;Bitte wählen Sie erst eine Zielgruppe und dann einen Lernbaustein aus. Klicken Sie anschließend auf „Ausführen“ und danach auf „Export im Excel-Format“.&lt;/p&gt;&#xD;&#xA;&lt;p&gt;&lt;b&gt;Mandatory training report DL3&lt;/b&gt;&lt;/p&gt;&#xD;&#xA;&lt;p&gt;This report provides a daily updated and name-based display of the learning progress of employees in your and all subordinate organizational units for a mandatory training, and only pertains to users who are required to participate in the mandatory training.&lt;/p&gt;&#xD;&#xA;&lt;p&gt;Please first select a target group (Zielgruppe) and then a learning module (Lernbaustein). Afterwards, click on 'Execute' and then on 'Export as Excel format'.&lt;/p&gt;">
      <MetaData created="2024-05-03T11:19:04" createdBy="Kaiser, Jan-Patrick (0245527)" createdBy_user_id="101393" modified="2025-09-29T11:16:50" modifiedBy="Spielmann, Werner (0538593)" modifiedBy_user_id="2872" />
      <ExecutionDetails format="TableResult" commandType="SqlCommandOrQuery" exportHandler="" adminControl="" exportMultipleTablesToSheets="False" datesWithTime="False" extraParams="" />
      <Mandators mandatorMode="OnlyOwner" mandator_id="bfa70f6b-484c-49da-9ad7-1ccd8f0d684c" mandatorName="ERGO_e-Campus" isStandard="False" isUsedByMenu="False" />
      <Parameters>
        <Parameter id="0f6a8e2f-1c3e-4219-bcb7-b8545f9053b3" isRequired="True" allowMultiSelect="False" name="ERGO ZG Fach Bereich" contextName="Zielgruppe" defaultValue="" renderHint="Undefined" disableParameter="DontDisable" />
        <Parameter id="64fe7a5f-a0d0-4b20-9e6d-04a481851d58" isRequired="True" allowMultiSelect="False" name="ERGO WBTs von ZG Fach Bereich" contextName="Lernbaustein" defaultValue="" renderHint="Undefined" disableParameter="DontDisable" />
      </Parameters>
      <Roles>
        <Role id="74" />
        <Role id="90" />
      </Roles>
      <command>
DECLARE @themeTitle NVARCHAR(255)
SELECT  @themeTitle = ISNULL(titleForLearners, title) FROM tblItems WHERE tblItems.id = @themeFunctionalArea

DECLARE @orgUnit_id typeGuidList
INSERT INTO @orgUnit_id
SELECT organisationUnit_id -- there could be more!!!
FROM tblUsersOrganisationUnits WHERE user_id = @current_user_id  AND position = 1 

-- ERGO: Personnel Number = descUserCn; pad to 8 characters to match the reference in DVORG
-- ERGODirekt (importer_id = 2): Personnel Number = last 8 characters of employeeId
DECLARE @PERNR nvarchar(50) = (SELECT TOP 1 CASE
	WHEN importer_id IS NOT NULL AND importer_id = 2
		THEN RIGHT(employeeId, 8)
		ELSE ISNULL(REPLICATE('0', 8 - LEN(descUserCn)), '') + descUserCn
	END
FROM tableUsers u 
WHERE intUserCn = @current_user_id)

-- select the top highest node and assure it is only one. If more than one highest =&amp;gt; not possible to execute the report
DECLARE @maxNodeLevel INT
SELECT @maxNodeLevel = MIN(nodeLevel) FROM  tblOrganisationUnits
JOIN @orgUnit_id AS orgUnits ON orgUnits.value = tblOrganisationUnits.id

DECLARE @topLevels typeGuidList
INSERT INTO @topLevels
SELECT id
FROM tblOrganisationUnits
JOIN @orgUnit_id AS orgUnits ON orgUnits.value = id 
WHERE nodeLevel = @maxNodeLevel


-- get OU where the user is Manager and all their sub nodes in the tree
CREATE TABLE #userManagedOUs (id UNIQUEIDENTIFIER, rootNode UNIQUEIDENTIFIER, managers NVARCHAR(MAX))
-- insert all subtree from every node
;WITH tree AS
(
    SELECT value as id, value AS rootNode 
    FROM @topLevels    

    UNION ALL 

    SELECT ous.id, (SELECT value from @topLevels WHERE ous.orgUnitPath LIKE '%' + CAST(value AS VARCHAR(40)) + '%') as rootNode
    FROM tblOrganisationUnits as ous
    JOIN tree ON tree.id = ous.parent_id AND deleted IS NULL
)

INSERT INTO #userManagedOUs
SELECT id, rootNode,
       STUFF((SELECT ',' + managers.FullUserName
            FROM tblUsersOrganisationUnits AS orgUnitManagers
            JOIN v_Users AS managers ON managers.intUserCn = orgUnitManagers.user_id AND userStatus &lt;&gt; 2 -- manager
            WHERE orgUnitManagers.organisationUnit_id = id AND position = 1
            FOR XML PATH('')), 1, 1, '') AS managers
FROM tree

-- fill every node of the tree with the corresponding manager: looking for the first parent with managers and assigning them
DECLARE @nodesWithoutManager TABLE (temp_id INT PRIMARY KEY IDENTITY(1,1), orgUnit_id UNIQUEIDENTIFIER)
INSERT INTO @nodesWithoutManager
SELECT id FROM #userManagedOUs WHERE managers IS NULL

DECLARE @loopCounter INT = 0
DECLARE @nodesCount INT 
SET @nodesCount = (SELECT COUNT(*) FROM @nodesWithoutManager)
DECLARE @parent_id UNIQUEIDENTIFIER
DECLARE @currentNode UNIQUEIDENTIFIER
DECLARE @parentManagers NVARCHAR(MAX)

WHILE(@loopCounter &lt; @nodesCount)
BEGIN
    SET @loopCounter = @loopCounter + 1
    SELECT @currentNode = orgUnit_id FROM @nodesWithoutManager WHERE temp_id = @loopCounter
    SET @parent_id = @currentNode -- start in the current node
    -- find first parent with managers assigned
    WHILE(NOT EXISTS(SELECT 1 FROM tblUsersOrganisationUnits 
     JOIN v_Users AS managers ON managers.intUserCn = tblUsersOrganisationUnits.user_id AND userStatus &lt;&gt; 2
     WHERE organisationUnit_id = @parent_id AND position = 1)
     AND @parent_id IS NOT NULL)
    BEGIN
        SELECT @parent_id = parent_id FROM tblOrganisationUnits WHERE id = @parent_id
    END
    SELECT @parentManagers = STUFF((SELECT ',' + managers.FullUserName
            FROM tblUsersOrganisationUnits AS orgUnitManagers
            JOIN v_Users AS managers ON managers.intUserCn = orgUnitManagers.user_id AND userStatus &lt;&gt; 2 -- manager
            WHERE orgUnitManagers.organisationUnit_id = @parent_id AND position = 1
            FOR XML PATH('')), 1, 1, '') -- @parent_id -- this node has managers NOT NULL
    -- now update the table with the missing managers
    UPDATE #userManagedOUs SET managers = @parentManagers WHERE id = @currentNode
END


DECLARE @users TABLE(user_id INT NOT NULL PRIMARY KEY)

-- add the users whose DVORG corresponds to the manager's employee number
INSERT INTO @users
SELECT user_id
FROM v_UsersChainAssignedModuleItems
JOIN tblUserCustomAttributes ca ON ca.user_id = v_UsersChainAssignedModuleItems.userId
JOIN tblUsersTargetGroups ON tblUsersTargetGroups.UserCn = ca.user_id AND targetGroup_id = @tgFunctionalArea
WHERE ca.customAttribute27 = @PERNR AND itemId = @themeFunctionalArea

--select all users in the managed OUs that have assigned the Theme
INSERT  INTO @users
SELECT DISTINCT userId 
FROM v_UsersChainAssignedModuleItems 
JOIN tblUsersOrganisationUnits ON tblUsersOrganisationUnits.user_id = v_UsersChainAssignedModuleItems.userId 
JOIN #userManagedOUs AS userManagedOUs ON userManagedOUs.id = tblUsersOrganisationUnits.organisationUnit_id -- eliminate the ones NOT in the managed OUs
JOIN tblUsersTargetGroups ON tblUsersTargetGroups.UserCn = tblUsersOrganisationUnits.user_id AND targetGroup_id = @tgFunctionalArea
WHERE itemId = @themeFunctionalArea
AND NOT EXISTS (SELECT * FROM @users WHERE user_id = v_UsersChainAssignedModuleItems.userId)

-- get date of the first version of the item where it is "certifiable"
DECLARE @itemHasRecertificationFrom DATE 
SELECT TOP 1 @itemHasRecertificationFrom = created FROM tblItemVersions
WHERE tblItemVersions.id = @themeFunctionalArea AND certificationType &gt; 0
ORDER BY created ASC

--select * from @managerOUs

DECLARE @highestDate DATE = '9999-01-01'
DECLARE @lowestDay DATE = '1753-01-01' 
DECLARE @certYearlyInterval TINYINT
DECLARE @certYearlyStartYear SMALLINT
DECLARE @overrideInitialMonths INT
DECLARE @overrideSpanMonths INT
DECLARE @certificationType INT
DECLARE @yearlyStart DATE
DECLARE @yearlyEnd DATE

SELECT @certificationType = certificationType,
    @overrideInitialMonths = overrideInitialMonths,
    @overrideSpanMonths = overrideSpanMonths,
    @certYearlyInterval =  CASE WHEN certificationType = 1 THEN NULL ELSE certYearlyInterval END,
    @certYearlyStartYear = certYearlyStartYear,
    @yearlyStart = CAST((CAST(certYearlyStartYear AS VARCHAR(4)) + '.01.01') AS DATE),
    @yearlyEnd = CAST(CAST((certYearlyStartYear + certYearlyInterval - 1) AS VARCHAR(4)) + '.12.31' AS DATE)
FROM tblItems WHERE id = @themeFunctionalArea

-- get green status for all users that is after the first period (exclude any green status before the item was certifiable at all)
; WITH greenStatus(user_id, passed, startPeriod, endPeriod, lastGreen, firstGreen)
AS (
SELECT users.user_id, 
    MAX(IIF((@certificationType = 1 AND @itemHasRecertificationFrom IS NOT NULL AND periods.firstPeriodStart IS NOT NULL 
               AND periods.firstPeriodStart &gt;= @itemHasRecertificationFrom AND startDate &gt;= periods.firstPeriodStart)
          OR (@certificationType = 2 AND startDate &gt;= CAST((CAST(@certYearlyStartYear AS VARCHAR(4)) + '.01.01') AS DATE)) 
          OR (@certificationType = 3 AND startDate &gt;= @yearlyStart), 1, 0)), -- passed
    MIN(IIF((@certificationType = 1 AND @itemHasRecertificationFrom IS NOT NULL AND periods.firstPeriodStart IS NOT NULL AND periods.firstPeriodStart &gt;= @itemHasRecertificationFrom)
            OR @certificationType &gt; 1, -- calendar yearly 2 recurrent or 3 only once
        CASE WHEN @certificationType = 1 THEN CAST(ISNULL(periods.firstPeriodStart, @highestDate) AS DATE) -- first period of all if any for fix interval!!!
             WHEN @certificationType = 2 THEN CAST((CAST(ISNULL(YEAR(startDate) ,@certYearlyStartYear) AS VARCHAR(4)) + '.01.01') AS DATE) 
             ELSE @yearlyStart -- start first period 
        END, @highestDate)), -- (if any, otherwise long in the future...)
    MIN(IIF((@certificationType = 1 AND @itemHasRecertificationFrom IS NOT NULL AND periods.firstPeriodStart IS NOT NULL AND periods.firstPeriodStart &gt;= @itemHasRecertificationFrom) 
            OR  @certificationType &gt; 1, -- calendar yearly 2 recurrent or 3 only once
        CASE WHEN @certificationType = 1 THEN IIF(periods.firstPeriodStart IS NULL, @highestDate, CAST(DATEADD(mm, ISNULL(@overrideInitialMonths,@overrideSpanMonths), periods.firstPeriodStart) AS DATE)) -- always initial months as end of period for Fix Intervall!!!!
             WHEN @certificationType = 2 THEN CAST((CAST((ISNULL(YEAR(startDate) ,@certYearlyStartYear) + @certYearlyInterval - 1) AS VARCHAR(4)) + '.12.31') AS DATE) 
             ELSE @yearlyEnd -- only once only calendar yearly considered here!! @certificationType = 3 
        END 
        ,@highestDate)), -- end first period (if any, otherwise long long in the future...)
    MAX(CAST(ISNULL(startDate, @lowestDay) AS DATE)), -- last green status if any otherwise @lowestDay 
    MIN(CAST(ISNULL(startDate, @highestDate) AS DATE))   --  first green status if any otherwise @highestDate
FROM @users AS users 
LEFT JOIN tblStatusUserItemHistory ON users.user_id = tblStatusUserItemHistory.user_id 
    AND item_id = @themeFunctionalArea AND status = 2 
OUTER APPLY (SELECT MIN(periodStart) AS firstPeriodStart FROM tblUserItemPeriodHistory -- this only applys for fix interval recertification =&gt; can be ignored for calendar yearly
    WHERE @certificationType = 1 AND tblUserItemPeriodHistory.user_id = users.user_id AND tblUserItemPeriodHistory.item_id = @themeFunctionalArea --AND isInitialPeriod = 1 
    GROUP BY tblUserItemPeriodHistory.user_id, tblUserItemPeriodHistory.item_id) AS periods -- initial period only!
GROUP BY users.user_id
)

--select user_id, item_id, count(*), min(periodStart) as minPeriod, max(periodStart) as maxPeriod  from tblUserItemPeriodHistory where isInitialPeriod = 1 group by user_id, item_id having count(*) &gt; 1


-- enum OrganisationUnitPosition : int
    --{
    --    Employee = 0,
    --    Manager = 1,
    --    Delegate = 2
    --}

SELECT v_Users.Vorname AS "Vorname/ First name",
    v_Users.Nachname AS "Nachname/ Last name",
    v_Users.descUserCn AS 'Pers.-Nr./ Employee ID',
    tblUsersContacts.email AS 'E-Mail/ Email',
    v_Users.office AS "Dienststelle/ Office",
    userOrgUnit.title + CASE userOrgUnit.position WHEN 0 THEN ' (M)'
                                               WHEN 1 THEN ' (F)'
                                               WHEN 2 THEN ' (V)'
                                 END AS 'Org.-Einheit/ Position/ Org. Unit/ Position', -- tblOrganisationUnits.nodeLevel,
    v_Users.companyAD AS "Gesellschaft/ Company",
    @themeTitle AS 'Titel des Bausteins/ Title of module',
    CASE startPeriod WHEN @highestDate THEN NULL ELSE CONVERT(VARCHAR(10), startPeriod, 104) END AS 'Start der Zertifizierungs-Periode/ Start of the certification period',
    CASE endPeriod WHEN @highestDate THEN NULL ELSE CONVERT(VARCHAR(10), endPeriod, 104) END AS 'Ende der Zertifizierungs-Periode/ End of the certification period',
    CASE passed WHEN 1 THEN 'Erfüllt / Completed' ELSE 'Nicht erfüllt / Not completed' END AS 'Status der Pflichschulung/ Status of mandatory training',
    CASE lastGreen WHEN @lowestDay THEN NULL ELSE CONVERT(VARCHAR(10), lastGreen, 104) END AS 'Zuletzt erfolgreich bearbeitet/ Last successfully edited',
    CASE firstGreen WHEN @highestDate THEN NULL ELSE CONVERT(VARCHAR(10), firstGreen, 104) END AS 'Zuerst erfolgreich bearbeitet/ First successfully edited',
    managerOUs.managers  AS 'Führungskraft der Org.-Einheit/ Manager of Org. Unit' -- comma separated list if more!!
FROM greenStatus 
JOIN v_Users  ON greenStatus.user_id = intUserCn
LEFT JOIN tblUsersContacts ON tblUsersContacts.user_id = intUserCn AND contactType_id = 1
OUTER APPLY (SELECT TOP 1 organisationUnit_id, title, position 
            FROM tblUsersOrganisationUnits
            JOIN tblOrganisationUnits ON tblOrganisationUnits.id = organisationUnit_id
            WHERE tblUsersOrganisationUnits.user_id = intUserCn 
            ORDER BY nodeLevel, title) AS userOrgUnit -- only one OU per User
LEFT JOIN #userManagedOUs AS managerOUs ON managerOUs.id = userOrgUnit.organisationUnit_id
ORDER BY Nachname, Vorname

DROP TABLE #userManagedOUs
</command>
    </Report>
  </Reports>
  <Parameters>
    <Parameter id="0f6a8e2f-1c3e-4219-bcb7-b8545f9053b3" mandator_id="bfa70f6b-484c-49da-9ad7-1ccd8f0d684c" isSystem="False" name="ERGO ZG Fach Bereich" reportParameterType_id="48f90555-35e9-4548-9d5a-01b626e68895" queryParameterName="@tgFunctionalArea" />
    <Parameter id="64fe7a5f-a0d0-4b20-9e6d-04a481851d58" mandator_id="bfa70f6b-484c-49da-9ad7-1ccd8f0d684c" isSystem="False" name="ERGO WBTs von ZG Fach Bereich" reportParameterType_id="58872e3f-2da3-4b72-8450-af4577e2af07" queryParameterName="@themeFunctionalArea" />
  </Parameters>
  <ParameterTypes>
    <ParameterType id="48f90555-35e9-4548-9d5a-01b626e68895" mandator_id="bfa70f6b-484c-49da-9ad7-1ccd8f0d684c" isSystem="False" name="ERGO ZG Fachbereich" datatype="IntegerDDL" dataValueField="id" dataTextField="title">
      <query>-- get role of @current_user_id
DECLARE @userRole INT
SELECT @userRole = SecurityID FROM v_Users where intUserCn = @current_user_id

--1) Fachbereich Verhaltenskodex= 61
--2) Fachbereich Datenschutz
--3) Fachbereich Informationssicherheit
--4) Fachbereich Geldwäsche
--5) Fachbereich PeopleDL
--6) Fachbereich Kartellrecht
--7) Fachbereich Gesetzl. Anforderungen
--8) Fachbereich IT-Administration = 68
DECLARE @relationalAreas  TABLE(areaName NVARCHAR(128), role_id INT)
INSERT INTO @relationalAreas VALUES
('Verhaltenskodex',61),('Datenschutz',62),('Infosicherheit',63),('Geldwäsche',64),('PeopleDL',65),
('Kartellrecht',66),('Gesetzl. Anforderungen',67),('IT-Administration',68)

DECLARE @userRelationalArea NVARCHAR(128)
SELECT @userRelationalArea = areaName FROM @relationalAreas WHERE role_id = @userRole

SET @userRelationalArea = ISNULL(@userRelationalArea, '') -- this assures correct pattern for roles above 68

-- get TGs: for roles from 61 till 68
--*_ZG_BS_$Fachbereich_*
--*_ZG_FS_$Fachbereich_*
--$Fachbereich = Der 2. Teil der Rollenbezeichnung. Bei der Rolle "Fachbereichsleiter Geldwäsche" wäre dies "Geldwäsche".
-- for roles above 68 it will be
-- *_ZG_BS_*
-- *_ZG_FS_*


SELECT id,IIF(titleForLearners IS NULL OR LEN(titleForLearners) = 0, title, titleForLearners)  AS title
FROM tblTargetGroups
WHERE mandator_id = @current_mandator_id
AND @userRole &gt; 60
AND (
title like '%' + '[_]ZD_Basisschulung[_]'  + @userRelationalArea + '%'
OR
title like '%' + '[_]ZD_Fokusschulung[_]'  + @userRelationalArea + '%'
OR
title like '%' + '[_]ZG_Basisschulung[_]'  + @userRelationalArea + '%'
OR
title like '%' + '[_]ZG_Fokusschulung[_]'  + @userRelationalArea + '%'
)
OR (
    @userRole = 63
    AND title like 'ID_IRM_ZD_Fokusschulung_CyberSec_' + '%'
    OR title like 'ID_IRM_ZG_Cybersecurity_2025_nach_Test_löschen_V2'
)
ORDER BY IIF(titleForLearners IS NULL OR LEN(titleForLearners) = 0, title, titleForLearners)
</query>
    </ParameterType>
    <ParameterType id="58872e3f-2da3-4b72-8450-af4577e2af07" mandator_id="bfa70f6b-484c-49da-9ad7-1ccd8f0d684c" isSystem="False" name="ERGO WBTs von ZG Fach Bereich" datatype="GuidDDL" dataValueField="id" dataTextField="title">
      <query>
        SELECT DISTINCT tblItems.id, IIF(titleForLearners IS NULL OR LEN(titleForLearners) = 0, title, titleForLearners) AS title 
FROM tblItems 
JOIN tblModuleItems ON tblModuleItems.item_id = tblItems.id 
JOIN tblEduOffersModules ON tblEduOffersModules.module_id = tblModuleItems.module_id 
JOIN tblEduOffersTargetGroups ON tblEduOffersTargetGroups.eduOffer_id = tblEduOffersModules.eduOffer_id 
WHERE tblEduOffersTargetGroups.targetGroup_id = @tgFunctionalArea
AND tblItems.itemType_id = 1 and deleted IS NULL 
AND (tblItems.title like '%' + '[_]BS[_]%' OR tblItems.title like '%' + '[_]FS[_]%')
ORDER BY IIF(titleForLearners IS NULL OR LEN(titleForLearners) = 0, title, titleForLearners)
      </query>
      <Parameters>
        <Parameter id="0f6a8e2f-1c3e-4219-bcb7-b8545f9053b3" isRequired="False" allowMultiSelect="False" name="ERGO ZG Fach Bereich" contextName="ERGO ZG Fach Bereich" defaultValue="" renderHint="Undefined" disableParameter="DontDisable" />
      </Parameters>
    </ParameterType>
  </ParameterTypes>
</ReportsExport>