﻿<?xml version="1.0" encoding="utf-8"?>
<ReportsExport>
  <Reports>
    <Report id="8ac8a1cb-34f9-4775-bc76-9a767b693e27" codekey="Pflichtschulungs-Report für Fachbereiche" categoryCodekey="LearningPrograms" name="Pflichtschulungs-Report für Fachbereiche/ Mandatory Training Report for Departments" description="&lt;p&gt;&lt;b&gt;Pflichtschulungs-Report für Fachbereiche&lt;/b&gt;&lt;/p&gt;&#xD;&#xA;&lt;p&gt;Dieser Report stellt tagesaktuell und anonym die Erfüllungsquote einer Pflichtschulung als Gesamtergebnis und pro Bereich dar und bezieht sich nur 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 for departments&lt;/b&gt;&lt;/p&gt;&#xD;&#xA;&lt;p&gt;This report provides a daily updated and anonymous display of the compliance rate of a mandatory training as a total result and per department, 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 '">
      <MetaData created="2024-04-17T07:24:12" createdBy="Administrator, Albrecht (Administrator)" createdBy_user_id="1" modified="2025-10-29T13:43:39" modifiedBy="Kaiser, Jan-Patrick (0245527)" modifiedBy_user_id="101393" />
      <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="61" />
        <Role id="62" />
        <Role id="63" />
        <Role id="65" />
        <Role id="66" />
        <Role id="67" />
        <Role id="68" />
        <Role id="90" />
      </Roles>
      <command>--DECLARE @current_mandator_id UNIQUEIDENTIFIER = (SELECT id FROM tblMandators WHERE name = 'ERGO_e-Campus')
--DECLARE @themeFunctionalArea UNIQUEIDENTIFIER = (SELECT id FROM tblItems WHERE title = 'ID_GLD_LP_BS_Datenschutz_Datenschutzgrundverordnung_IDD_2024')
--DECLARE @tgFunctionalArea INT = (SELECT id FROM tblTargetGroups WHERE title = 'ID_GLD_ZD_Basisschulung_Datenschutz_2024')

DECLARE @themeTitle NVARCHAR(255)
SELECT  @themeTitle = ISNULL(titleForLearners, title) FROM tblItems WHERE tblItems.id = @themeFunctionalArea

DECLARE @topLevels typeGuidList
INSERT INTO @topLevels
SELECT id
FROM tblOrganisationUnits
WHERE reportLevel = 'DB' OR reportLevel = 'DV'

-- all nodes with subnodes to consider with reportLevel = 'DB' or 'DV'
CREATE TABLE #SelectedOrgUnits(id UNIQUEIDENTIFIER, reportLevel VARCHAR(255),  topParent UNIQUEIDENTIFIER)
INSERT INTO #SelectedOrgUnits
SELECT DISTINCT subOus.id, ous.reportLevel, topLevels.orgUnit 
FROM tblOrganisationUnits AS ous
JOIN tblOrganisationUnits subOus ON subOus.orgUnitPath LIKE CONCAT('%' , ous.id , '%') 
    AND subOus.deleted IS NULL -- AND tblOrganisationUnits.reportLevel = 'DB'  -- include subOUs of reportLevel
OUTER APPLY (SELECT value AS orgUnit FROM @topLevels WHERE ous.orgUnitPath LIKE '%' + CAST(value AS VARCHAR(40)) + '%') AS topLevels
WHERE ous.deleted IS NULL AND ous.mandator_id = @current_mandator_id AND (ous.reportLevel = 'DB' OR ous.reportLevel = 'DV')

--select all users in the OUs that have assigned the Theme
DECLARE @users TABLE(user_id INT)
INSERT  INTO @users
SELECT DISTINCT userId 
FROM v_UsersChainAssignedModuleItems 
JOIN tblUsersTargetGroups ON tblUsersTargetGroups.UserCn = v_UsersChainAssignedModuleItems.userId AND targetGroup_id = @tgFunctionalArea
WHERE itemId = @themeFunctionalArea


-- now try to assign every user ONLY ONCE to the top most OU in the selected org units
CREATE TABLE #usersOrgUnits(user_id INT, orgUnit_id UNIQUEIDENTIFIER)
INSERT INTO #usersOrgUnits
SELECT DISTINCT users.user_id, selecteOUs.topParent --, title
FROM @users as users
JOIN tblUsersOrganisationUnits ON tblUsersOrganisationUnits.user_id = users.user_id
JOIN #SelectedOrgUnits AS selecteOUs ON selecteOUs.id = tblUsersOrganisationUnits.organisationUnit_id


--select * from #SelectedOrgUnits
--join tblOrganisationUnits on tblOrganisationUnits.id = #SelectedOrgUnits.id
--join 


-- insert users that are outside the OUs with report level DB
INSERT INTO #usersOrgUnits
SELECT DISTINCT users.user_id, NULL
FROM @users as users
JOIN tblUsersOrganisationUnits ON tblUsersOrganisationUnits.user_id = users.user_id
LEFT JOIN #SelectedOrgUnits AS selecteOUs ON selecteOUs.id = tblUsersOrganisationUnits.organisationUnit_id
WHERE selecteOUs.id IS NULL


DELETE FROM #usersOrgUnits 
WHERE orgUnit_id IS NULL 
AND EXISTS(select 1 from #usersOrgUnits as u WHERE orgUnit_id IS NOT NULL AND u.user_id = #usersOrgUnits.user_id)

-------------------------------------------------------------------
-- 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

DECLARE @highestDay 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)
CREATE TABLE #GreenStatus(user_id INT, passed INT)
INSERT INTO #GreenStatus
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)) 
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

-- mark the OUs that have a parent already with report level = DB
declare @childrenDB TABLE (child_DB UNIQUEIDENTIFIER)
insert into @childrenDB
select distinct subOus.id as child_DB 
from tblOrganisationUnits as ous
JOIN tblOrganisationUnits subOus ON subOus.orgUnitPath LIKE CONCAT('%' , ous.id , '%') 
    AND subOus.deleted IS NULL and (subOus.reportLevel = 'DB' OR subOus.reportLevel = 'DV')
where (ous.reportLevel = 'DB' OR ous.reportLevel = 'DV') and ous.mandator_id = @current_mandator_id
and ous.deleted is null
and subOus.nodeLevel &gt; ous.nodeLevel



CREATE TABLE #Counters(orgUnit UNIQUEIDENTIFIER, total INT, passed INT, inReportLevel BIT) --, hasLessThan6 BIT) 

INSERT INTO #Counters
SELECT orgUnit_id, -- this is the root node to be considered but counts users below too
    COUNT(*) AS total, 
    SUM(ISNULL(greenStatus.passed, 0)) AS passed,
    CASE 
        WHEN orgUnit_id IS NULL OR (COUNT(*) &lt; 6 AND orgUnit_id NOT IN (select * from @childrenDB)) THEN 0 ELSE 1 --
    END AS inReportLevel 
FROM #GreenStatus AS greenStatus
INNER JOIN #usersOrgUnits AS usersOrgUnits ON usersOrgUnits.user_id = greenStatus.user_id
GROUP BY orgUnit_id

-- select * from #Counters where inReportLevel = 0

DECLARE @noOU AS TABLE (user_is INT, passed INT)
INSERT INTO @noOU
SELECT users.user_id, passed
FROM @users as users
LEFT JOIN tblUsersOrganisationUnits on tblUsersOrganisationUnits.user_id = users.user_id
LEFT JOIN #GreenStatus as gs on gs.user_id = users.user_id
WHERE tblUsersOrganisationUnits.user_id IS NULL


-- add an entry in #Counters for all users that are NOT assigned to any OU
UPDATE counters
SET total = total + (SELECT COUNT(*) FROM @noOU),
passed = passed + (SELECT COUNT(*) FROM @noOU WHERE passed = 1)
FROM  #Counters AS counters
WHERE counters.orgUnit IS NULL



CREATE TABLE #Result(orgUnitTitle NVARCHAR(256), orgUnit_id UNIQUEIDENTIFIER, quote DECIMAL(12,2), total INT, passed INT, notPassed INT, inReportLevel BIT)
    --vorname NVARCHAR(255), nachname NVARCHAR(255), loginname NVARCHAR(64), mail NVARCHAR(512), office NVARCHAR(64))

INSERT INTO #Result
SELECT
   'Sonstige/ Others' AS orgUnitTitle, --'Org. Einheit',
   NULL AS orgUnit_id,
   ROUND(SUM(passed) / CAST(SUM(total) AS DECIMAL(12,2)) * 100, 2)  AS quote, -- 'Erfüllungs-Quote in %',
   SUM(total) AS total, -- 'Anzahl Teilnehmer: gesamt', 
   SUM(passed) AS passed, -- 'Anzahl Teilnehmer: Pflichtschulung erfüllt',
   (SUM(total) - SUM (passed)) AS notPassed, -- 'Anzahl Teilnehmer: Pflichtschulung nicht erfüllt',
   0 AS inReportLevel
   /*,
   '/', -- AS 'Vorname FK',
   '/', -- As 'Nachname FK', 
   '/', -- AS 'Pers.-Nr. FK',
   '/', -- AS 'E-Mail FK',
   '/' -- AS 'Dienststelle FK'*/
FROM #Counters 
WHERE inReportLevel = 0
GROUP BY inReportLevel


-- insert ALL row
INSERT INTO #Result
SELECT
   'Gesamt-Auswertung / Overall evaluation' AS orgUnitTitle, --'Org. Einheit',
   NULL AS orgUnit_id,
   ROUND(CAST(SUM(passed) AS DECIMAL) / CAST(SUM(total) AS DECIMAL(12,2)) * 100, 2)  AS quote, -- 'Erfüllungs-Quote in %',
   SUM(total) AS total, -- 'Anzahl Teilnehmer: gesamt', 
   SUM(passed) AS passed, -- 'Anzahl Teilnehmer: Pflichtschulung erfüllt',
   (SUM(total) - SUM (passed)) AS notPassed, -- 'Anzahl Teilnehmer: Pflichtschulung nicht erfüllt',
   0 AS inReportLevel
   /*,
   '/', -- AS 'Vorname FK',
   '/', -- As 'Nachname FK', 
   '/', -- AS 'Pers.-Nr. FK',
   '/', -- AS 'E-Mail FK',
   '/' -- AS 'Dienststelle FK'*/
FROM #Counters 
LEFT JOIN @childrenDB as childrenDB on childrenDB.child_DB = orgUnit
WHERE child_DB IS NULL


INSERT INTO #Result
SELECT DISTINCT --tblOrganisationUnits.id,
 tblOrganisationUnits.title AS orgUnitTitle, -- 'Org. Einheit',tblOrganisationUnits.title as orgUnitTitle, 
   tblOrganisationUnits.id AS orgUnit_id,
   ROUND(CAST(passed AS DECIMAL) / CAST(total AS DECIMAL(12,2)) * 100, 2)  AS quote, -- 'Erfüllungs-Quote in %',
   total, --AS 'Anzahl Teilnehmer: gesamt', 
   passed, --AS 'Anzahl Teilnehmer: Pflichtschulung erfüllt',
   (total - passed) AS notPassed, -- 'Anzahl Teilnehmer: Pflichtschulung nicht erfüllt',
   1 AS inReportLevel
   /*,Vorname, -- AS 'Vorname FK',
   Nachname, -- As 'Nachname FK', 
   descUserCn, -- AS 'Pers.-Nr. FK',
   tblUsersContacts.email, -- AS 'E-Mail FK',
   office -- AS 'Dienststelle FK'*/
FROM #Counters 
JOIN tblOrganisationUnits ON tblOrganisationUnits.id = orgUnit
LEFT JOIN tblUsersOrganisationUnits ON tblUsersOrganisationUnits.organisationUnit_id = orgUnit AND position = 1
LEFT JOIN v_Users on v_users.intUserCn = tblUsersOrganisationUnits.user_id AND userStatus &lt;&gt; 2 -- not resigned! 
LEFT JOIN tblUsersContacts ON tblUsersContacts.user_id = v_users.intUserCn AND contactType_id = 1
WHERE inReportLevel = 1 AND total &gt;= 6  AND 
	(userStatus &lt;&gt; 2  -- not resigned! 
	OR                      -- it is not true that the only managers are resigned ones
	NOT EXISTS(SELECT 1 FROM tblUsersOrganisationUnits 
		LEFT JOIN v_Users on v_users.intUserCn = tblUsersOrganisationUnits.user_id
		WHERE tblUsersOrganisationUnits.organisationUnit_id = orgUnit 
		AND position = 1 AND userStatus &lt;&gt; 2)
)  
ORDER BY tblOrganisationUnits.title



SELECT --sum( CASE WHEN child_DB IS NULL then total else 0 end) as superTotal
 orgUnitTitle AS 'Org.-Einheit/ Org. Unit',
    CASE WHEN child_DB IS NOT NULL THEN 'Ja / Yes' ELSE 'Nein / No' END AS 'Einem Bereich untergeordnet/ Subordinate to a department',
    @themeTitle AS 'Titel des Bausteins/ Title of the module',
    IIF(total &lt; 6, NULL, quote) AS 'Erfüllungsquote in %/ Compliance rate in %',
    total AS 'Anzahl Teilnehmer/ Number of participants',
    IIF(total &lt; 6, NULL, passed) AS 'Pflichtschulung erfüllt/ Mandatory training completed',
    IIF(total &lt; 6, NULL, notPassed) AS 'Pflichtschulung nicht erfüllt/ Mandatory training not completed',
    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 = orgUnit_id AND position = 1
            FOR XML PATH('')), 1, 1, '') AS "Führungskraft / Manager"
    /*
    Vorname AS 'Vorname Führungskraft/ First name manager',
    Nachname AS 'Nachname Führungskraft/ Last name manager', 
    loginname AS 'Pers.-Nr. Führungskraft/ Employee ID manager',
    mail AS 'E-Mail Führungskraft/ Email manager',
    office  AS 'Dienststelle Führungskraft/ Office manager'*/
FROM #Result
LEFT JOIN @childrenDB as childrenDB on childrenDB.child_DB = orgUnit_id
ORDER BY inReportLevel, orgUnitTitle --, [Titel des Bausteins]

DROP TABLE #GreenStatus
DROP TABLE #SelectedOrgUnits
DROP TABLE #usersOrgUnits
DROP TABLE #Counters
DROP TABLE #Result
</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>