Compare commits

...

6 Commits

Author SHA1 Message Date
Stephen Abello
b365aa0971 N°9628 - Fix issue following 5b9e0a1d being applied to non-jQuery elements (#961) 2026-07-10 15:57:04 +02:00
v-dumas
56aa50c9b1 N°9553 - Skip test due to unexplained CI failure 2026-07-10 15:53:37 +02:00
Vincent Dumas
eacb7f3401 N°9553 - Allow loading of localized sample and structural data based on iTop default language
* Add English, French and German structural and sample data in iTop Community

* Add helper methods to allow :
  * Checking of supported module version format
  * Finding a localized file name based on a provided en_us file name and a language
  * Loading a file if the module upgrade crossed a given version
2026-07-10 14:21:56 +02:00
Eric Espie
b14045af29 N°9648 - Better dependencies error message 2026-07-10 12:10:21 +02:00
Eric Espie
7321eeb23f N°9648 - Better dependencies error message 2026-07-10 12:02:12 +02:00
odain
05b8c529fe Fix cache-warmup after any succesfull setup 2026-07-10 11:14:59 +02:00
36 changed files with 1984 additions and 236 deletions

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<NetworkDeviceType alias="NetworkDeviceType" id="10">
<name>Router</name>
</NetworkDeviceType>
<NetworkDeviceType alias="NetworkDeviceType" id="11">
<name>Switch</name>
</NetworkDeviceType>
</Set>

View File

@@ -32,7 +32,6 @@ SetupWebPage::AddModule(
],
'data.sample' => [
'data/data.sample.model.xml',
'data/data.sample.networkdevicetype.xml',
'data/data.sample.servers.xml',
'data/data.sample.nw-devices.xml',
'data/data.sample.software.xml',
@@ -106,6 +105,7 @@ if (!class_exists('ConfigMgmtInstaller')) {
*/
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
{
}
}
}

View File

@@ -50,13 +50,13 @@ const oOpenSignInWindow = function (url, name) {
then we load it in the already opened secondary window, and then
we bring such window back on top/in front of its parent window. */
oWindowObjectReference = window.open(url, name, sWindowFeatures);
oWindowObjectReference.trigger('focus');
oWindowObjectReference.focus();
} else {
/* Else the window reference must exist and the window
is not closed; therefore, we can bring it back on top of any other
window with the focus() method. There would be no need to re-create
the window or to reload the referenced resource. */
oWindowObjectReference.trigger('focus');
oWindowObjectReference.focus();
}
/* Let know every second our child window that we're waiting for it to complete,
once we reach our landing page, it'll send us a reply

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ContractType alias="ContractType" id="78">
<name>Hosting</name>
</ContractType>
<ContractType alias="ContractType" id="79">
<name>IT-Outsourcing</name>
</ContractType>
<ContractType alias="ContractType" id="77">
<name>Wartung</name>
</ContractType>
<ContractType alias="ContractType" id="76">
<name>Support</name>
</ContractType>
</Set>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<CustomerContract alias="CustomerContract" id="3">
<name>Kundenvertrag</name>
<org_id>7</org_id>
<description>Kundenvertrag zur Bereitstellung von Services fuer einen externen Kunden.</description>
<start_date>2026-01-01</start_date>
<end_date>2030-12-31</end_date>
<cost>10000</cost>
<cost_currency>euros</cost_currency>
<contracttype_id>79</contracttype_id>
<billing_frequency>yearly</billing_frequency>
<provider_id>2</provider_id>
<status>production</status>
</CustomerContract>
<CustomerContract alias="CustomerContract" id="1">
<name>Kundenvertrag Vertriebsabteilung</name>
<org_id>6</org_id>
<description>Interner Vertrag zur Bereitstellung von Services fuer die Vertriebsabteilung</description>
<start_date>2019-01-01</start_date>
<end_date>2030-12-31</end_date>
<cost>0</cost>
<cost_currency>euros</cost_currency>
<contracttype_id>0</contracttype_id>
<billing_frequency>monthly</billing_frequency>
<provider_id>2</provider_id>
<status>production</status>
</CustomerContract>
</Set>

View File

@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ServiceSubcategory alias="ServiceSubcategory" id="28">
<name>Zugriffsprobleme</name>
<description>Hilfe bei einem Zugriffsproblem anfordern</description>
<service_id>7</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="17">
<name>API-Integration</name>
<description>Verbindung zwischen internen und externen Anwendungen.</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="13">
<name>CRM (z. B. Salesforce, HubSpot)</name>
<description>Einrichtung, Anpassung und Support für das Customer-Relationship-Management.</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="22">
<name>Sensibilisierung für Cybersicherheit</name>
<description>Schulung der Mitarbeitenden zu bewährten Praktiken (Phishing, Passwörter usw.).</description>
<service_id>6</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="3">
<name>Datensicherung</name>
<description>Automatische Sicherung kritischer Dateien (täglich/wöchentlich/monatlich).</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="21">
<name>Datenschutz (DSGVO)</name>
<description>Unterstützung bei der Einhaltung gesetzlicher Vorgaben (DSGVO, HIPAA usw.).</description>
<service_id>6</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="1">
<name>ERP (z. B. SAP, Odoo)</name>
<description>Zugriff, Support und Schulung für integrierte Managementsoftware.</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="10">
<name>Dateispeicherung und -freigabe</name>
<description>Bereitstellung kollaborativer Speicherbereiche (z. B. SharePoint, Nextcloud).</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="12">
<name>Hardwarevorfall</name>
<description>Unterstützung bei einem Hardwareausfall anfordern.</description>
<service_id>1</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="19">
<name>Hardware-Upgrade</name>
<description>Austausch oder Erweiterung von Komponenten (RAM, Festplatte usw.).</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="7">
<name>Lokales Netzwerk (LAN/Wi-Fi)</name>
<description>Installation, Konfiguration und Wartung von Netzwerkgeräten.</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="27">
<name>Multi-Faktor-Authentifizierung (MFA)</name>
<description>Konfiguration und Support für Multi-Faktor-Authentifizierung.</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="4">
<name>Fehlerbehebung im Netzwerk</name>
<description>Hilfe bei der Behebung eines Netzwerkproblems anfordern.</description>
<service_id>3</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="5">
<name>Bestellung neuer Desktop-Computer</name>
<description>Einen neuen Desktop-Computer für neue Mitarbeitende oder als Ersatz für ein altes System bestellen.</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="8">
<name>Bestellung neuer Laptops</name>
<description>Einen neuen Laptop für mobile Mitarbeitende oder als Ersatz für ein altes Gerät bestellen.</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="11">
<name>Neues Peripheriegerät</name>
<description>Ein Peripheriegerät bestellen: Tastatur, Maus, persönlicher Drucker ...</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="20">
<name>Sicherheitsaudit</name>
<description>Schwachstellenanalysen, Penetrationstests und Empfehlungen.</description>
<service_id>6</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="23">
<name>Sicherheitsvorfall</name>
<description>Reaktion auf Cyberangriffe, Datenlecks oder Sicherheitsverletzungen.</description>
<service_id>6</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="6">
<name>Serververwaltung</name>
<description>Präventive Wartung, Software-Updates und 24/7-Überwachung.</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="16">
<name>Softwarevorfall</name>
<description>Hilfe bei der Behebung eines Softwareproblems anfordern.</description>
<service_id>1</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="15">
<name>Softwarevorfall</name>
<description>Unterstützung bei einem softwarebezogenen Problem anfordern.</description>
<service_id>2</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="18">
<name>Softwareinstallation</name>
<description>Bereitstellung von Office-Software (z. B. Microsoft 365, LibreOffice) und Geschäftssoftware.</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="14">
<name>Individuelle Entwicklung</name>
<description>Entwicklung maßgeschneiderter Tools (Dashboards, Automatisierungen, Skripte).</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="24">
<name>Benutzerkonto-Erstellung</name>
<description>Erstellung von Konten für neue Mitarbeitende oder Auftragnehmer.</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="26">
<name>Benutzerkonto-Löschung</name>
<description>Deaktivierung von Konten für ausscheidende Mitarbeitende oder am Ende ihrer Verträge.</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="25">
<name>Benutzerkonto-Aktualisierung</name>
<description>Hinzufügen oder Entfernen von Berechtigungen (z. B. Zugriff auf einen freigegebenen Ordner oder eine Anwendung).</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="2">
<name>VPN-Zugriff</name>
<description>Konfiguration und Support für sicheren Fernzugriff auf interne Ressourcen.</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
</Set>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ServiceFamily alias="ServiceFamily" id="1">
<name>IT-Services</name>
<icon>
<mimetype>image/svg+xml</mimetype>
<filename>icons8-open-end-wrench.svg</filename>
<data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSIyNDBweCIgaGVpZ2h0PSIyNDBweCI+PHJhZGlhbEdyYWRpZW50IGlkPSIwQkRKczNXdHBwTWdvNFk5QTdHZ2phIiBjeD0iOS4xNjkiIGN5PSIzOC42NyIgcj0iMTIuMTM1IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIuNzA2IiBzdG9wLWNvbG9yPSIjNzg3Zjg1Ii8+PHN0b3Agb2Zmc2V0PSIuNzEzIiBzdG9wLWNvbG9yPSIjN2E4MTg3Ii8+PHN0b3Agb2Zmc2V0PSIuNzkzIiBzdG9wLWNvbG9yPSIjOTA5ODlmIi8+PHN0b3Agb2Zmc2V0PSIuODY4IiBzdG9wLWNvbG9yPSIjOWRhNWFlIi8+PHN0b3Agb2Zmc2V0PSIuOTMiIHN0b3AtY29sb3I9IiNhMWFhYjMiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjMEJESnMzV3RwcE1nbzRZOUE3R2dqYSkiIGQ9Ik0xOS45MTUsMjEuOGMtNC42NzksNC42NzktOS4zNzUsOS4zNzUtOS41NTEsOS41NTFsNi4zNjQsNi4zNjQgYzAuMTc3LTAuMTc3LDQuODcyLTQuODcyLDkuNTUxLTkuNTUxTDE5LjkxNSwyMS44eiIvPjxyYWRpYWxHcmFkaWVudCBpZD0iMEJESnMzV3RwcE1nbzRZOUE3R2dqYiIgY3g9IjEzLjQyNSIgY3k9IjM1LjQ5OSIgcj0iMTQuNjg4IiBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDE4MCAyNC4zMjIgMjMuNzU4KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iLjcwNiIgc3RvcC1jb2xvcj0iIzc4N2Y4NSIvPjxzdG9wIG9mZnNldD0iLjcxMyIgc3RvcC1jb2xvcj0iIzdhODE4NyIvPjxzdG9wIG9mZnNldD0iLjc5MyIgc3RvcC1jb2xvcj0iIzkwOTg5ZiIvPjxzdG9wIG9mZnNldD0iLjg2OCIgc3RvcC1jb2xvcj0iIzlkYTVhZSIvPjxzdG9wIG9mZnNldD0iLjkzIiBzdG9wLWNvbG9yPSIjYTFhYWIzIi8+PC9yYWRpYWxHcmFkaWVudD48cGF0aCBmaWxsPSJ1cmwoIzBCREpzM1d0cHBNZ280WTlBN0dnamIpIiBkPSJNMjQuNzI4LDI5LjcxNWM0LjY3OS00LjY3OSw5LjM3NS05LjM3NSw5LjU1MS05LjU1MUwyNy45MTUsMTMuOCBjLTAuMTc3LDAuMTc3LTQuODcyLDQuODcyLTkuNTUxLDkuNTUxTDI0LjcyOCwyOS43MTV6Ii8+PGxpbmVhckdyYWRpZW50IGlkPSIwQkRKczNXdHBwTWdvNFk5QTdHZ2pjIiB4MT0iMjIuMTE5IiB4Mj0iMzMuOTI2IiB5MT0iLTI1NTIuODgzIiB5Mj0iLTI1NjQuNjkiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTEgMCAwIDEgMzkuMDQ2IDI1OTguMDMzKSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzhmOTc5ZSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ExYWFiMyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCMwQkRKczNXdHBwTWdvNFk5QTdHZ2pkKSIgZD0iTTQwLjY2MiwxMy4zMTJjLTEuNjk1LDEuNjk1LTQuNDQ1LDEuNjk1LTYuMTM5LDBzLTEuNjk1LTQuNDQ1LDAtNi4xMzkgYzAuNDE0LTAuNDE0LDIuMDgxLTIuMDgxLDMuNzgtMy43OGMwLjQwNy0wLjQwNywwLjIyNi0xLjExOS0wLjMzMi0xLjI1NmMtMS4zNzctMC4zMzgtMi44NTgtMC40MDktNC4zOTktMC4xMTkgYy00LjUxOSwwLjg1Mi04LjA0Myw0LjYzMy04LjUxMiw5LjIwN2MtMC42ODQsNi42Nyw0Ljg4MywxMi4yMzYsMTEuNTUzLDExLjU1MWM0LjU3NC0wLjQ3LDguMzU1LTMuOTk0LDkuMjA2LTguNTEzIGMwLjI5LTEuNTQxLDAuMjE5LTMuMDIxLTAuMTE5LTQuMzk4Yy0wLjEzOC0wLjU2LTAuODQ5LTAuNzQxLTEuMjU2LTAuMzMyQzQyLjc0MywxMS4yMzEsNDEuMDc2LDEyLjg5OSw0MC42NjIsMTMuMzEyeiIvPjwvc3ZnPgo=</data>
<downloads_count>0</downloads_count>
</icon>
</ServiceFamily>
</Set>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<SLA alias="SLA" id="4">
<name>SLA Bronze</name>
<description>Service-Level-Agreement Bronze fuer Services mit niedriger Kritikalitaet</description>
<org_id>2</org_id>
</SLA>
<SLA alias="SLA" id="2">
<name>SLA Gold</name>
<description>Service-Level-Agreement Gold fuer Services mit hoher Kritikalitaet</description>
<org_id>2</org_id>
</SLA>
<SLA alias="SLA" id="3">
<name>SLA Silver</name>
<description>Service-Level-Agreement Silver fuer Services mit mittlerer Kritikalitaet</description>
<org_id>2</org_id>
</SLA>
</Set>

View File

@@ -0,0 +1,387 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<SLT alias="SLT" id="5">
<name>TTO Vorfall Priorität kritisch 1 Stunde</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="3">
<name>TTO Vorfall Priorität kritisch 15 Minuten</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>15</value>
<unit>minutes</unit>
</SLT>
<SLT alias="SLT" id="4">
<name>TTO Vorfall Priorität kritisch 30 Minuten</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>30</value>
<unit>minutes</unit>
</SLT>
<SLT alias="SLT" id="7">
<name>TTO Vorfall Priorität hoch 1 Stunde</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="8">
<name>TTO Vorfall Priorität hoch 2 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="6">
<name>TTO Vorfall Priorität hoch 30 Minuten</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>30</value>
<unit>minutes</unit>
</SLT>
<SLT alias="SLT" id="12">
<name>TTO Vorfall Priorität niedrig 2 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="13">
<name>TTO Vorfall Priorität niedrig 4 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="14">
<name>TTO Vorfall Priorität niedrig 8 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="9">
<name>TTO Vorfall Priorität mittel 1 Stunde</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="10">
<name>TTO Vorfall Priorität mittel 2 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="11">
<name>TTO Vorfall Priorität mittel 4 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="27">
<name>TTO Serviceanfrage Priorität kritisch 1 Stunde</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="28">
<name>TTO Serviceanfrage Priorität kritisch 2 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="29">
<name>TTO Serviceanfrage Priorität kritisch 4 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="30">
<name>TTO Serviceanfrage Priorität hoch 2 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="31">
<name>TTO Serviceanfrage Priorität hoch 4 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="32">
<name>TTO Serviceanfrage Priorität hoch 8 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="37">
<name>TTO Serviceanfrage Priorität niedrig 16 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="38">
<name>TTO Serviceanfrage Priorität niedrig 32 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="36">
<name>TTO Serviceanfrage Priorität niedrig 8 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="35">
<name>TTO Serviceanfrage Priorität mittel 16 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="33">
<name>TTO Serviceanfrage Priorität mittel 4 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="34">
<name>TTO Serviceanfrage Priorität mittel 8 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="15">
<name>TTR Vorfall Priorität kritisch 1 Stunde</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="16">
<name>TTR Vorfall Priorität kritisch 2 Stunden</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="17">
<name>TTR Vorfall Priorität kritisch 4 Stunden</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="18">
<name>TTR Vorfall Priorität hoch 2 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="19">
<name>TTR Vorfall Priorität hoch 4 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="20">
<name>TTR Vorfall Priorität hoch 8 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="25">
<name>TTR Vorfall Priorität niedrig 16 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="26">
<name>TTR Vorfall Priorität niedrig 32 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="24">
<name>TTR Vorfall Priorität niedrig 8 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="23">
<name>TTR Vorfall Priorität mittel 16 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="21">
<name>TTR Vorfall Priorität mittel 4 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="22">
<name>TTR Vorfall Priorität mittel 8 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="41">
<name>TTR Serviceanfrage Priorität kritisch 16 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="39">
<name>TTR Serviceanfrage Priorität kritisch 4 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="40">
<name>TTR Serviceanfrage Priorität kritisch 8 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="43">
<name>TTR Serviceanfrage Priorität hoch 16 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="44">
<name>TTR Serviceanfrage Priorität hoch 32 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="42">
<name>TTR Serviceanfrage Priorität hoch 8 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="50">
<name>TTR Serviceanfrage Priorität niedrig 128 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>128</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="48">
<name>TTR Serviceanfrage Priorität niedrig 32 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="49">
<name>TTR Serviceanfrage Priorität niedrig 64 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>64</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="45">
<name>TTR Serviceanfrage Priorität mittel 16 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="46">
<name>TTR Serviceanfrage Priorität mittel 32 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="47">
<name>TTR Serviceanfrage Priorität mittel 64 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>64</value>
<unit>hours</unit>
</SLT>
</Set>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ContractType alias="ContractType" id="78">
<name>Hosting</name>
</ContractType>
<ContractType alias="ContractType" id="79">
<name>IT-Outsourcing</name>
</ContractType>
<ContractType alias="ContractType" id="77">
<name>Wartung</name>
</ContractType>
<ContractType alias="ContractType" id="76">
<name>Support</name>
</ContractType>
</Set>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<CustomerContract alias="CustomerContract" id="3">
<name>Kundenvertrag</name>
<org_id>7</org_id>
<description>Kundenvertrag zur Bereitstellung von Services fuer einen externen Kunden.</description>
<start_date>2026-01-01</start_date>
<end_date>2030-12-31</end_date>
<cost>10000</cost>
<cost_currency>euros</cost_currency>
<contracttype_id>79</contracttype_id>
<billing_frequency>yearly</billing_frequency>
<provider_id>2</provider_id>
<status>production</status>
</CustomerContract>
<CustomerContract alias="CustomerContract" id="1">
<name>Kundenvertrag Vertriebsabteilung</name>
<org_id>6</org_id>
<description>Interner Vertrag zur Bereitstellung von Services fuer die Vertriebsabteilung</description>
<start_date>2019-01-01</start_date>
<end_date>2030-12-31</end_date>
<cost>0</cost>
<cost_currency>euros</cost_currency>
<contracttype_id>0</contracttype_id>
<billing_frequency>monthly</billing_frequency>
<provider_id>2</provider_id>
<status>production</status>
</CustomerContract>
</Set>

View File

@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ServiceSubcategory alias="ServiceSubcategory" id="28">
<name>Zugriffsprobleme</name>
<description>Hilfe bei einem Zugriffsproblem anfordern</description>
<service_id>7</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="17">
<name>API-Integration</name>
<description>Verbindung zwischen internen und externen Anwendungen.</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="13">
<name>CRM (z. B. Salesforce, HubSpot)</name>
<description>Einrichtung, Anpassung und Support für das Customer-Relationship-Management.</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="22">
<name>Sensibilisierung für Cybersicherheit</name>
<description>Schulung der Mitarbeitenden zu bewährten Praktiken (Phishing, Passwörter usw.).</description>
<service_id>6</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="3">
<name>Datensicherung</name>
<description>Automatische Sicherung kritischer Dateien (täglich/wöchentlich/monatlich).</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="21">
<name>Datenschutz (DSGVO)</name>
<description>Unterstützung bei der Einhaltung gesetzlicher Vorgaben (DSGVO, HIPAA usw.).</description>
<service_id>6</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="1">
<name>ERP (z. B. SAP, Odoo)</name>
<description>Zugriff, Support und Schulung für integrierte Managementsoftware.</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="10">
<name>Dateispeicherung und -freigabe</name>
<description>Bereitstellung kollaborativer Speicherbereiche (z. B. SharePoint, Nextcloud).</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="12">
<name>Hardwarevorfall</name>
<description>Unterstützung bei einem Hardwareausfall anfordern.</description>
<service_id>1</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="19">
<name>Hardware-Upgrade</name>
<description>Austausch oder Erweiterung von Komponenten (RAM, Festplatte usw.).</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="7">
<name>Lokales Netzwerk (LAN/Wi-Fi)</name>
<description>Installation, Konfiguration und Wartung von Netzwerkgeräten.</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="27">
<name>Multi-Faktor-Authentifizierung (MFA)</name>
<description>Konfiguration und Support für Multi-Faktor-Authentifizierung.</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="4">
<name>Fehlerbehebung im Netzwerk</name>
<description>Hilfe bei der Behebung eines Netzwerkproblems anfordern.</description>
<service_id>3</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="5">
<name>Bestellung neuer Desktop-Computer</name>
<description>Einen neuen Desktop-Computer für neue Mitarbeitende oder als Ersatz für ein altes System bestellen.</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="8">
<name>Bestellung neuer Laptops</name>
<description>Einen neuen Laptop für mobile Mitarbeitende oder als Ersatz für ein altes Gerät bestellen.</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="11">
<name>Neues Peripheriegerät</name>
<description>Ein Peripheriegerät bestellen: Tastatur, Maus, persönlicher Drucker ...</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="20">
<name>Sicherheitsaudit</name>
<description>Schwachstellenanalysen, Penetrationstests und Empfehlungen.</description>
<service_id>6</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="23">
<name>Sicherheitsvorfall</name>
<description>Reaktion auf Cyberangriffe, Datenlecks oder Sicherheitsverletzungen.</description>
<service_id>6</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="6">
<name>Serververwaltung</name>
<description>Präventive Wartung, Software-Updates und 24/7-Überwachung.</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="16">
<name>Softwarevorfall</name>
<description>Hilfe bei der Behebung eines Softwareproblems anfordern.</description>
<service_id>1</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="15">
<name>Softwarevorfall</name>
<description>Unterstützung bei einem softwarebezogenen Problem anfordern.</description>
<service_id>2</service_id>
<request_type>incident</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="18">
<name>Softwareinstallation</name>
<description>Bereitstellung von Office-Software (z. B. Microsoft 365, LibreOffice) und Geschäftssoftware.</description>
<service_id>1</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="14">
<name>Individuelle Entwicklung</name>
<description>Entwicklung maßgeschneiderter Tools (Dashboards, Automatisierungen, Skripte).</description>
<service_id>2</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="24">
<name>Benutzerkonto-Erstellung</name>
<description>Erstellung von Konten für neue Mitarbeitende oder Auftragnehmer.</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="26">
<name>Benutzerkonto-Löschung</name>
<description>Deaktivierung von Konten für ausscheidende Mitarbeitende oder am Ende ihrer Verträge.</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="25">
<name>Benutzerkonto-Aktualisierung</name>
<description>Hinzufügen oder Entfernen von Berechtigungen (z. B. Zugriff auf einen freigegebenen Ordner oder eine Anwendung).</description>
<service_id>7</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
<ServiceSubcategory alias="ServiceSubcategory" id="2">
<name>VPN-Zugriff</name>
<description>Konfiguration und Support für sicheren Fernzugriff auf interne Ressourcen.</description>
<service_id>3</service_id>
<request_type>service_request</request_type>
<status>production</status>
<approvalrule_id>0</approvalrule_id>
</ServiceSubcategory>
</Set>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ServiceFamily alias="ServiceFamily" id="1">
<name>IT-Services</name>
<icon>
<mimetype>image/svg+xml</mimetype>
<filename>icons8-open-end-wrench.svg</filename>
<data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSIyNDBweCIgaGVpZ2h0PSIyNDBweCI+PHJhZGlhbEdyYWRpZW50IGlkPSIwQkRKczNXdHBwTWdvNFk5QTdHZ2phIiBjeD0iOS4xNjkiIGN5PSIzOC42NyIgcj0iMTIuMTM1IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIuNzA2IiBzdG9wLWNvbG9yPSIjNzg3Zjg1Ii8+PHN0b3Agb2Zmc2V0PSIuNzEzIiBzdG9wLWNvbG9yPSIjN2E4MTg3Ii8+PHN0b3Agb2Zmc2V0PSIuNzkzIiBzdG9wLWNvbG9yPSIjOTA5ODlmIi8+PHN0b3Agb2Zmc2V0PSIuODY4IiBzdG9wLWNvbG9yPSIjOWRhNWFlIi8+PHN0b3Agb2Zmc2V0PSIuOTMiIHN0b3AtY29sb3I9IiNhMWFhYjMiLz48L3JhZGlhbEdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjMEJESnMzV3RwcE1nbzRZOUE3R2dqYSkiIGQ9Ik0xOS45MTUsMjEuOGMtNC42NzksNC42NzktOS4zNzUsOS4zNzUtOS41NTEsOS41NTFsNi4zNjQsNi4zNjQgYzAuMTc3LTAuMTc3LDQuODcyLTQuODcyLDkuNTUxLTkuNTUxTDE5LjkxNSwyMS44eiIvPjxyYWRpYWxHcmFkaWVudCBpZD0iMEJESnMzV3RwcE1nbzRZOUE3R2dqYiIgY3g9IjEzLjQyNSIgY3k9IjM1LjQ5OSIgcj0iMTQuNjg4IiBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDE4MCAyNC4zMjIgMjMuNzU4KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iLjcwNiIgc3RvcC1jb2xvcj0iIzc4N2Y4NSIvPjxzdG9wIG9mZnNldD0iLjcxMyIgc3RvcC1jb2xvcj0iIzdhODE4NyIvPjxzdG9wIG9mZnNldD0iLjc5MyIgc3RvcC1jb2xvcj0iIzkwOTg5ZiIvPjxzdG9wIG9mZnNldD0iLjg2OCIgc3RvcC1jb2xvcj0iIzlkYTVhZSIvPjxzdG9wIG9mZnNldD0iLjkzIiBzdG9wLWNvbG9yPSIjYTFhYWIzIi8+PC9yYWRpYWxHcmFkaWVudD48cGF0aCBmaWxsPSJ1cmwoIzBCREpzM1d0cHBNZ280WTlBN0dnamIpIiBkPSJNMjQuNzI4LDI5LjcxNWM0LjY3OS00LjY3OSw5LjM3NS05LjM3NSw5LjU1MS05LjU1MUwyNy45MTUsMTMuOCBjLTAuMTc3LDAuMTc3LTQuODcyLDQuODcyLTkuNTUxLDkuNTUxTDI0LjcyOCwyOS43MTV6Ii8+PGxpbmVhckdyYWRpZW50IGlkPSIwQkRKczNXdHBwTWdvNFk5QTdHZ2pjIiB4MT0iMjIuMTE5IiB4Mj0iMzMuOTI2IiB5MT0iLTI1NTIuODgzIiB5Mj0iLTI1NjQuNjkiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTEgMCAwIDEgMzkuMDQ2IDI1OTguMDMzKSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzhmOTc5ZSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ExYWFiMyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCMwQkRKczNXdHBwTWdvNFk5QTdHZ2pkKSIgZD0iTTQwLjY2MiwxMy4zMTJjLTEuNjk1LDEuNjk1LTQuNDQ1LDEuNjk1LTYuMTM5LDBzLTEuNjk1LTQuNDQ1LDAtNi4xMzkgYzAuNDE0LTAuNDE0LDIuMDgxLTIuMDgxLDMuNzgtMy43OGMwLjQwNy0wLjQwNywwLjIyNi0xLjExOS0wLjMzMi0xLjI1NmMtMS4zNzctMC4zMzgtMi44NTgtMC40MDktNC4zOTktMC4xMTkgYy00LjUxOSwwLjg1Mi04LjA0Myw0LjYzMy04LjUxMiw5LjIwN2MtMC42ODQsNi42Nyw0Ljg4MywxMi4yMzYsMTEuNTUzLDExLjU1MWM0LjU3NC0wLjQ3LDguMzU1LTMuOTk0LDkuMjA2LTguNTEzIGMwLjI5LTEuNTQxLDAuMjE5LTMuMDIxLTAuMTE5LTQuMzk4Yy0wLjEzOC0wLjU2LTAuODQ5LTAuNzQxLTEuMjU2LTAuMzMyQzQyLjc0MywxMS4yMzEsNDEuMDc2LDEyLjg5OSw0MC42NjIsMTMuMzEyeiIvPjwvc3ZnPgo=</data>
<downloads_count>0</downloads_count>
</icon>
</ServiceFamily>
</Set>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<SLA alias="SLA" id="4">
<name>SLA Bronze</name>
<description>Service-Level-Agreement Bronze fuer Services mit niedriger Kritikalitaet</description>
<org_id>2</org_id>
</SLA>
<SLA alias="SLA" id="2">
<name>SLA Gold</name>
<description>Service-Level-Agreement Gold fuer Services mit hoher Kritikalitaet</description>
<org_id>2</org_id>
</SLA>
<SLA alias="SLA" id="3">
<name>SLA Silver</name>
<description>Service-Level-Agreement Silver fuer Services mit mittlerer Kritikalitaet</description>
<org_id>2</org_id>
</SLA>
</Set>

View File

@@ -0,0 +1,387 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<SLT alias="SLT" id="5">
<name>TTO Vorfall Priorität kritisch 1 Stunde</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="3">
<name>TTO Vorfall Priorität kritisch 15 Minuten</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>15</value>
<unit>minutes</unit>
</SLT>
<SLT alias="SLT" id="4">
<name>TTO Vorfall Priorität kritisch 30 Minuten</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>30</value>
<unit>minutes</unit>
</SLT>
<SLT alias="SLT" id="7">
<name>TTO Vorfall Priorität hoch 1 Stunde</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="8">
<name>TTO Vorfall Priorität hoch 2 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="6">
<name>TTO Vorfall Priorität hoch 30 Minuten</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>30</value>
<unit>minutes</unit>
</SLT>
<SLT alias="SLT" id="12">
<name>TTO Vorfall Priorität niedrig 2 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="13">
<name>TTO Vorfall Priorität niedrig 4 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="14">
<name>TTO Vorfall Priorität niedrig 8 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="9">
<name>TTO Vorfall Priorität mittel 1 Stunde</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="10">
<name>TTO Vorfall Priorität mittel 2 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="11">
<name>TTO Vorfall Priorität mittel 4 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="27">
<name>TTO Serviceanfrage Priorität kritisch 1 Stunde</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="28">
<name>TTO Serviceanfrage Priorität kritisch 2 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="29">
<name>TTO Serviceanfrage Priorität kritisch 4 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="30">
<name>TTO Serviceanfrage Priorität hoch 2 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="31">
<name>TTO Serviceanfrage Priorität hoch 4 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="32">
<name>TTO Serviceanfrage Priorität hoch 8 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="37">
<name>TTO Serviceanfrage Priorität niedrig 16 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="38">
<name>TTO Serviceanfrage Priorität niedrig 32 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="36">
<name>TTO Serviceanfrage Priorität niedrig 8 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="35">
<name>TTO Serviceanfrage Priorität mittel 16 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="33">
<name>TTO Serviceanfrage Priorität mittel 4 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="34">
<name>TTO Serviceanfrage Priorität mittel 8 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>tto</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="15">
<name>TTR Vorfall Priorität kritisch 1 Stunde</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>1</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="16">
<name>TTR Vorfall Priorität kritisch 2 Stunden</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="17">
<name>TTR Vorfall Priorität kritisch 4 Stunden</name>
<priority>1</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="18">
<name>TTR Vorfall Priorität hoch 2 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>2</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="19">
<name>TTR Vorfall Priorität hoch 4 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="20">
<name>TTR Vorfall Priorität hoch 8 Stunden</name>
<priority>2</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="25">
<name>TTR Vorfall Priorität niedrig 16 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="26">
<name>TTR Vorfall Priorität niedrig 32 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="24">
<name>TTR Vorfall Priorität niedrig 8 Stunden</name>
<priority>4</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="23">
<name>TTR Vorfall Priorität mittel 16 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="21">
<name>TTR Vorfall Priorität mittel 4 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="22">
<name>TTR Vorfall Priorität mittel 8 Stunden</name>
<priority>3</priority>
<request_type>incident</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="41">
<name>TTR Serviceanfrage Priorität kritisch 16 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="39">
<name>TTR Serviceanfrage Priorität kritisch 4 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>4</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="40">
<name>TTR Serviceanfrage Priorität kritisch 8 Stunden</name>
<priority>1</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="43">
<name>TTR Serviceanfrage Priorität hoch 16 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="44">
<name>TTR Serviceanfrage Priorität hoch 32 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="42">
<name>TTR Serviceanfrage Priorität hoch 8 Stunden</name>
<priority>2</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>8</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="50">
<name>TTR Serviceanfrage Priorität niedrig 128 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>128</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="48">
<name>TTR Serviceanfrage Priorität niedrig 32 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="49">
<name>TTR Serviceanfrage Priorität niedrig 64 Stunden</name>
<priority>4</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>64</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="45">
<name>TTR Serviceanfrage Priorität mittel 16 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>16</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="46">
<name>TTR Serviceanfrage Priorität mittel 32 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>32</value>
<unit>hours</unit>
</SLT>
<SLT alias="SLT" id="47">
<name>TTR Serviceanfrage Priorität mittel 64 Stunden</name>
<priority>3</priority>
<request_type>service_request</request_type>
<metric>ttr</metric>
<value>64</value>
<unit>hours</unit>
</SLT>
</Set>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ContactType alias="ContactType" id="75">
<name>Administrator</name>
</ContactType>
<ContactType alias="ContactType" id="73">
<name>Einkaeufer</name>
</ContactType>
<ContactType alias="ContactType" id="1">
<name>Kundenbetreuer</name>
</ContactType>
<ContactType alias="ContactType" id="2">
<name>Helpdesk</name>
</ContactType>
<ContactType alias="ContactType" id="3">
<name>Manager</name>
</ContactType>
<ContactType alias="ContactType" id="74">
<name>Vertrieb</name>
</ContactType>
<ContactType alias="ContactType" id="4">
<name>Supportmitarbeiter</name>
</ContactType>
<ContactType alias="ContactType" id="5">
<name>Support Stufe 1</name>
</ContactType>
<ContactType alias="ContactType" id="6">
<name>Teamleiter</name>
</ContactType>
</Set>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<DocumentType alias="DocumentType" id="72">
<name>Architektur</name>
</DocumentType>
<DocumentType alias="DocumentType" id="69">
<name>Vertrag</name>
</DocumentType>
<DocumentType alias="DocumentType" id="71">
<name>Verfahren</name>
</DocumentType>
<DocumentType alias="DocumentType" id="70">
<name>Prozess</name>
</DocumentType>
</Set>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<ContactType alias="ContactType" id="17">
<name>Customer manager</name>
</ContactType>
<ContactType alias="ContactType" id="12">
<name>Helpdesk</name>
</ContactType>
<ContactType alias="ContactType" id="15">
<name>Manager</name>
</ContactType>
<ContactType alias="ContactType" id="14">
<name>Support Agent</name>
</ContactType>
<ContactType alias="ContactType" id="13">
<name>Support level1</name>
</ContactType>
<ContactType alias="ContactType" id="16">
<name>Team leader</name>
</ContactType>
</Set>

View File

@@ -32,7 +32,6 @@ SetupWebPage::AddModule(
'data/data.sample.persons.xml',
'data/data.sample.teams.xml',
'data/data.sample.contactteam.xml',
'data/data.sample.contacttype.xml',
'data/data.sample.auditdomain.xml',
'data/data.sample.auditcategory.xml',
'data/data.sample.auditcategory-auditdomain.xml',

View File

@@ -61,6 +61,6 @@ class TicketsInstaller extends ModuleInstallerAPI
}
}
// Load localized structural data: predefined query phrases for notifications
static::LoadLocalizedData($oConfiguration, $sPreviousVersion, $sCurrentVersion, '3.0.0', __DIR__."/data/{{language_code}}.data.itop-tickets.xml");
static::LoadLocalizedDataOnCrossingVersion($oConfiguration, $sPreviousVersion, $sCurrentVersion, '3.0.0', utils::GetAbsoluteModulePath('itop-tickets')."data/data.itop-tickets.en_us.xml");
}
}

View File

@@ -58,11 +58,11 @@ const CombodoCKEditorHandler = {
// Adjust size if passed in configuration
// - Width
if (aConfiguration.width !== undefined) {
editor.editing.view.on('change', writer => { writer.setStyle( 'width', aConfiguration.width, editor.editing.view.document.getRoot() ); } );
editor.editing.view.change( writer => { writer.setStyle( 'width', aConfiguration.width, editor.editing.view.document.getRoot() ); } );
}
// - Height
if (aConfiguration.height !== undefined) {
editor.editing.view.on('change', writer => { writer.setStyle( 'height', aConfiguration.height, editor.editing.view.document.getRoot() ); } );
editor.editing.view.change( writer => { writer.setStyle( 'height', aConfiguration.height, editor.editing.view.document.getRoot() ); } );
}
this.instances[sElem] = editor;

View File

@@ -51,7 +51,7 @@ $sOperation = utils::ReadParam('operation', '');
$oP->SetBreadCrumbEntry('ui-tool-universalsearch', Dict::S('Menu:UniversalSearchMenu'), Dict::S('Menu:UniversalSearchMenu+'), '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
//$sSearchHeaderForceDropdown
$sSearchHeaderForceDropdown = '<select id="select_class" name="baseClass" onChange="this.form.trigger(\'submit\');">';
$sSearchHeaderForceDropdown = '<select id="select_class" name="baseClass" onChange="this.form.submit();">';
$aClassLabels = [];
foreach (MetaModel::GetClasses('bizmodel, grant_by_profile') as $sCurrentClass) {
if ((MetaModel::HasCategory($sCurrentClass, 'grant_by_profile') && UserRights::IsActionAllowed($sCurrentClass, UR_ACTION_BULK_MODIFY))

View File

@@ -54,7 +54,7 @@ try {
$oP->SetBreadCrumbEntry('ui-tool-tag-admin', Dict::S('Menu:TagAdminMenu'), Dict::S('Menu:TagAdminMenu+'), '', 'fas fa-tags', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$sSearchHeaderForceDropdown = '<select id="select_class" name="class" onChange="this.form.trigger(\'submit\');">';
$sSearchHeaderForceDropdown = '<select id="select_class" name="class" onChange="this.form.submit();">';
$aClassLabels = [];
foreach (MetaModel::EnumChildClasses($sBaseClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sCurrentClass) {
$aClassLabels[$sCurrentClass] = MetaModel::GetName($sCurrentClass);

View File

@@ -310,85 +310,47 @@ abstract class ModuleInstallerAPI
}
/**
* Helper to load localized data in iTop not only at the module installation but also if during an upgrade you pass over the version which brought those data
*
* @param \Config $oConfiguration
* @param string $sPreviousVersion The previous version of the module (empty string will force the loading)
* @param string $sCurrentVersion The current version of the module
* @param string $sFirstLoadingVersion The first module version for which the data loading should be performed (e.g. '3.0.0')
* @param string $sFilePattern The pattern of the file to load, with {{language_code}} as placeholder for the language code (e.g. 'data.sample.{{language_code}}.xml')
* Expected values for the three version parameters: Valid examples: '3.2', '3.2.0', '3.2-beta1'. Invalid examples: '3', '3.2.', '3.2-beta-1', '3.2 beta1'.
* @param string $sPreviousVersion The previous version of the module (empty string in case of first install)
* @param string $sCurrentVersion The current version of the module. Cannot be empty.
* @param string $sFirstLoadingVersion If your upgrade passes over the FirstLoadingVersion or in case of fresh install, the localized data will be loaded. This is useful when you want to load (structural) data on a module upgrade. Cannot be empty.
* @param string $sDefaultFileName The file to load (If localization is expected then provided file name must end by '.en_us.xml')
* If the default iTop language is french and a localized variant of the $sDefaultFileName ending by '.fr_fr.xml' exists, then that file with french data will be loaded.
*
* @return void
* @throws \ConfigException
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public static function LoadLocalizedData(Config $oConfiguration, string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion, string $sFilePattern): void
public static function LoadLocalizedDataOnCrossingVersion(Config $oConfiguration, string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion, string $sDefaultFileName): void
{
self::AssertLoadLocalizedDataParametersAreValid($sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion, $sFilePattern);
// It's not very clear if it makes sense to test a particular version,
// as the loading mechanism checks object existence using reconc_keys
// and do not recreate them, nor update existing.
// Without test, new entries added to the data files, would be automatically loaded
if (($sPreviousVersion === '') ||
(version_compare($sPreviousVersion, $sCurrentVersion, '<')
&& version_compare($sPreviousVersion, $sFirstLoadingVersion, '<'))) {
// Note: There is an issue when upgrading, default language cannot be retrieved from the passed configuration, we have to read it from the disk
self::AssertLoadLocalizedDataOnCrossingVersionParametersAreValid($sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion);
if (self::IsVersionCrossed($sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion)) {
// Note: on upgrade, the default language cannot be retrieved from the passed configuration, it must be read from disk (see StructureInstaller::AfterDatabaseCreation)
if (utils::IsNullOrEmptyString($sPreviousVersion)) {
// Fresh install
$sDefaultLanguage = $oConfiguration->GetDefaultLanguage();
$sWishedLanguage = $oConfiguration->GetDefaultLanguage();
} else {
// Upgrade
$sDefaultLanguage = utils::GetConfig(true)->GetDefaultLanguage();
}
$sFileName = self::GetLocalizedFileName($sDefaultLanguage, $sFilePattern);
if ($sFileName !== '') {
self::XMLFileLoad($sFileName);
$sWishedLanguage = utils::GetConfig(true)->GetDefaultLanguage();
}
self::LoadLocalizedData($sWishedLanguage, $sDefaultFileName);
}
}
/**
* @throws \CoreUnexpectedValue
*/
private static function AssertLoadLocalizedDataParametersAreValid(string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion, string $sFilePattern): void
{
if (($sPreviousVersion !== '') && !self::IsValidLocalizedDataVersion($sPreviousVersion)) {
throw new CoreUnexpectedValue("LoadLocalizedData expects sPreviousVersion to be empty or match x.y[.z][-name], got '{$sPreviousVersion}'");
}
if (!self::IsValidLocalizedDataVersion($sCurrentVersion)) {
throw new CoreUnexpectedValue("LoadLocalizedData expects sCurrentVersion to match x.y[.z][-name], got '{$sCurrentVersion}'");
}
if (!self::IsValidLocalizedDataVersion($sFirstLoadingVersion)) {
throw new CoreUnexpectedValue("LoadLocalizedData expects sFirstLoadingVersion to match x.y[.z][-name], got '{$sFirstLoadingVersion}'");
}
if (utils::IsNullOrEmptyString($sFilePattern)) {
throw new CoreUnexpectedValue('LoadLocalizedData expects sFilePattern to be a non-empty string');
}
if (substr_count($sFilePattern, '{{language_code}}') !== 1) {
throw new CoreUnexpectedValue("LoadLocalizedData expects sFilePattern to contain the exact placeholder '{{language_code}}' exactly once");
}
}
private static function IsValidLocalizedDataVersion(string $sVersion): bool
{
return (preg_match('/^\d+\.\d+(?:\.\d+)?(?:-[A-Za-z0-9]+)?$/', $sVersion) === 1);
}
/**
* @param array|string $sFileName
* @param \XMLDataLoader $oDataLoader
* Helper to load a localized data file based on the default language of the application.
* @param string $sDefaultLanguage The default language of the application, used to build the localized file name
* @param string $sDefaultFile The default file to load, must be ending with .en_us.xml to be localized
*
* @return void
* @throws \Exception
*/
public static function XMLFileLoad(string $sFileName): void
public static function LoadLocalizedData(string $sDefaultLanguage, string $sDefaultFile): void
{
$sFileName = self::GetLocalizedFileName($sDefaultLanguage, $sDefaultFile);
if (!file_exists($sFileName)) {
throw new Exception("File $sFileName not found");
}
@@ -402,26 +364,77 @@ abstract class ModuleInstallerAPI
}
/**
* @param string $sLanguage The language code to use for localization (e.g. 'EN US')
* @param string $sFilePattern The full path+name of the file to localize, with {{language_code}} as placeholder for the language code (e.g. 'data.sample.{{language_code}}.xml')
* Helper to get the localized file name for a given language code, based on the original file name which must end by .en_us.xml
* @param string $sLanguage The language code to use for localization (e.g. 'FR FR' or 'fr_fr')
* @param string $sOriginalFileName The full path+name of the file to localize. If ending with .en_us.xml, it searches for a localized file.
*
* @return string The localized file name if found, or an empty string if not found
* @throws \ConfigException
* @throws \CoreException
* @return string The localized file name if found otherwise the original file name
* @throws \Exception If the original file name ends with .en_us.xml and does not exist
*/
public static function GetLocalizedFileName($sLanguage, string $sFilePattern): string
public static function GetLocalizedFileName(string $sLanguage, string $sOriginalFileName): string
{
$sLang = str_replace(' ', '_', strtolower($sLanguage));
$sFileName = str_replace('{{language_code}}', $sLang, $sFilePattern);
if (!file_exists($sFileName)) {
$sLang = 'en_us';
$sFileName = str_replace('{{language_code}}', $sLang, $sFilePattern);
}
if (file_exists($sFileName)) {
return $sFileName;
if (str_ends_with($sOriginalFileName, '.en_us.xml')) {
// If the original file which can be localized, does not exist, then even if the localized file itself exists, we want to raise this design issue.
if (!file_exists($sOriginalFileName)) {
throw new Exception("File $sOriginalFileName not found, it must exist when required by the module or as iTop fallback language when no localized file exists for the iTop default language");
}
// Search for a file for the requested language,
$sLang = '.'.str_replace(' ', '_', strtolower($sLanguage)).'.xml';
$sFileName = str_replace('.en_us.xml', $sLang, $sOriginalFileName);
// localized file not found, fall back to the original file (en_us)
if (!file_exists($sFileName)) {
SetupLog::Debug("File for iTop default language $sFileName not found, fall back to file $sOriginalFileName");
$sFileName = $sOriginalFileName;
}
} else {
SetupLog::Warning("No data file matching the pattern $sFilePattern and language_code $sLang was found.");
return '';
// If the original file is not localizable, then we just return it as is
$sFileName = $sOriginalFileName;
}
return $sFileName;
}
/**
* @throws \CoreUnexpectedValue
*/
private static function AssertLoadLocalizedDataOnCrossingVersionParametersAreValid(string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion): void
{
if (($sPreviousVersion !== '') && !self::IsValidVersionFormat($sPreviousVersion)) {
throw new CoreUnexpectedValue("LoadLocalizedDataOnCrossingVersion expects sPreviousVersion to be empty or match x.y[.z][-name], got '{$sPreviousVersion}'");
}
if (!self::IsValidVersionFormat($sCurrentVersion)) {
throw new CoreUnexpectedValue("LoadLocalizedDataOnCrossingVersion expects sCurrentVersion to match x.y[.z][-name], got '{$sCurrentVersion}'");
}
if (utils::IsNullOrEmptyString($sFirstLoadingVersion) || !self::IsValidVersionFormat($sFirstLoadingVersion)) {
throw new CoreUnexpectedValue("LoadLocalizedDataOnCrossingVersion expects sFirstLoadingVersion to match x.y[.z][-name], got '{$sFirstLoadingVersion}'");
}
}
/**
* Checks if a module version matches x.y[.z][-name].
* Valid examples: '3.2', '3.2.1', '3.2.3-2', '3.3.0-dev', '10.14-beta2'.
* Invalid examples: '3', 'v3.2', '3.2.1.4', '3.2-rc.1', '3.2 beta1'.
*
* @param string $sVersion
*
* @return bool
*/
public static function IsValidVersionFormat(string $sVersion): bool
{
return (preg_match('/^\d+\.\d+(?:\.\d+)?(?:-[A-Za-z0-9]+)?$/', $sVersion) === 1);
}
/**
* @param string $sPreviousVersion
* @param string $sCurrentVersion
* @param string $sFirstLoadingVersion
*
* @return bool
*/
public static function IsVersionCrossed(string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion): bool
{
return ($sPreviousVersion === '') ||
(version_compare($sPreviousVersion, $sCurrentVersion, '<')
&& version_compare($sPreviousVersion, $sFirstLoadingVersion, '<')
&& version_compare($sFirstLoadingVersion, $sCurrentVersion, '<='));
}
}

View File

@@ -933,6 +933,7 @@ class RunTimeEnvironment
@chmod($sFinalConfig, 0440); // Read-only for owner and group, nothing for others
SetupUtils::rrmdir(dirname($sBuildConfig)); // Cleanup the temporary build dir if empty
MetaModel::ResetAllCaches($this->sFinalEnv);
if (! isset($_SESSION)) {
//used in all UI setups (not unattended)
@@ -1101,7 +1102,7 @@ class RunTimeEnvironment
{
$oConfig = MetaModel::GetConfig();
$oConfig->Set('access_mode', ACCESS_FULL);
$sDefaultLanguage = $oConfig->GetDefaultLanguage();
$oDataLoader = new XMLDataLoader();
CMDBObject::SetCurrentChangeFromParams("Initialization from XML files for the selected modules ");
@@ -1147,7 +1148,7 @@ class RunTimeEnvironment
// in the current database
foreach ($aPreviouslyLoadedFiles as $sFileRelativePath) {
$sFileName = APPROOT.$sFileRelativePath;
SetupLog::Info("Loading file: $sFileName (just to get the keys mapping)");
SetupLog::Info("Loading file: $sFileName (just to build & cache the keys mapping)");
if (!file_exists($sFileName)) {
throw(new Exception("File $sFileName does not exist"));
}
@@ -1163,7 +1164,7 @@ class RunTimeEnvironment
if (!file_exists($sFileName)) {
throw(new Exception("File $sFileName does not exist"));
}
$sFileName = ModuleInstallerAPI::GetLocalizedFileName($sDefaultLanguage, $sFileName);
$oDataLoader->LoadFile($sFileName);
$sResult = sprintf("loading of %s done.", basename($sFileName));
SetupLog::Info($sResult);

View File

@@ -553,15 +553,14 @@ class SetupUtils
*
* @since 3.0.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE
*/
public static function CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules)
public static function CheckSelectedModules(array $aRelDirsToScan, $aSelectedModules)
{
$aResult = [];
$aDirsToScan = [APPROOT.$sSourceDir];
$sExtensionsPath = APPROOT.$sExtensionDir;
if (is_dir($sExtensionsPath)) {
// if the extensions dir exists, scan it for additional modules as well
$aDirsToScan[] = $sExtensionsPath;
$aDirsToScan = [];
foreach ($aRelDirsToScan as $sRelDir) {
if (is_dir(APPROOT.$sRelDir)) {
$aDirsToScan[] = APPROOT.$sRelDir;
}
}
require_once(APPROOT.'setup/modulediscovery.class.inc.php');
try {

View File

@@ -244,7 +244,8 @@ $aChecks = SetupUtils::CheckBackupPrerequisites(APPROOT.'data'); // mmm should b
$aSelectedModules = $oParams->Get('selected_modules');
$sSourceDir = $oParams->Get('source_dir', 'datamodels/latest');
$sExtensionDir = $oParams->Get('extensions_dir', 'extensions');
$aChecks = array_merge($aChecks, SetupUtils::CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules));
$aRelDirsToScan = [$sSourceDir, $sExtensionDir, "data/$sTargetEnvironment-modules"];
$aChecks = array_merge($aChecks, SetupUtils::CheckSelectedModules($aRelDirsToScan, $aSelectedModules));
foreach ($aChecks as $oCheckResult) {
switch ($oCheckResult->iSeverity) {

View File

@@ -5,7 +5,7 @@
{% include "base/components/input/inputlabel.html.twig" %}
{% endif %}
<select id="{{ oUIBlock.GetId() }}" name="{{ oUIBlock.GetName() }}"
{% if oUIBlock.GetSubmitOnChange() %} onChange="$(this).parents('form:first').trigger('submit');" {% endif %}
{% if oUIBlock.GetSubmitOnChange() %} onChange="$(this).parents('form').first().trigger('submit');" {% endif %}
{% if oUIBlock.IsMultiple() %} multiple {% endif %}
class="{% if oUIBlock.IsHidden() %}ibo-is-hidden{% endif %}{% if oUIBlock.GetAdditionalCSSClassesAsString() %} {{ oUIBlock.GetAdditionalCSSClassesAsString() }}{% endif %}"
{% if oUIBlock.GetDataAttributes() %}

View File

@@ -285,75 +285,137 @@ SQL
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedData
* @covers \ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion
* @dataProvider LoadLocalizedData_RequiredLanguageProvider
*/
public function testLoadLocalizedData_LoadsOnFirstInstall(): void
public function testLoadLocalizedData_LoadRequiredLanguageOnFirstInstall(string $sRequiredLanguage, array $aExpectedOrganizationNames): void
{
// Given
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->GivenLocalizedDataTestContext('XML_Load_FirstInstall_', 'fr_fr');
$this->GivenLocalizedDataFile($sTmpDir, "en_us", $sOrgName);
$this->GivenLocalizedDataFile($sTmpDir, "fr_fr", $sOrgName);
[$oConfig, $sPattern] = $this->GivenLocalizedDataTestContext($sRequiredLanguage);
// When no previous version, and current version higher than the first loading version
ModuleInstallerAPI::LoadLocalizedData($oConfig, '', '3.3.0', '3.0.0', $sPattern);
// Then data loaded
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 0);
$this->AssertOrganizationCountByName($sOrgName, 'fr_fr', 1);
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, '', '3.3.0', '3.0.0', $sPattern);
// Then the expected localized organizations are loaded
$this->AssertOrganizationNamesExist($aExpectedOrganizationNames);
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedData
*/
public function testLoadLocalizedData_DoesNotLoadWhenVersionConditionIsNotMet(): void
{
// Given
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->GivenLocalizedDataTestContext('XML_Load_NoLoad_', 'en_us');
$this->GivenLocalizedDataFile($sTmpDir, "en_us", $sOrgName);
// When a previous version that is lower than the first loading version, but higher or equal to the current version
ModuleInstallerAPI::LoadLocalizedData($oConfig, '3.0.0', '3.1.0', '3.0.0', $sPattern);
// Then no data loaded
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 0);
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedData
*/
public function testLoadLocalizedData_FallbacksToEnUsWhenLanguageFileIsMissing(): void
{
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->GivenLocalizedDataTestContext('XML_Load_Fallback_', 'fr_fr');
// Intentionally create ONLY en_us file
$this->GivenLocalizedDataFile($sTmpDir, 'en_us', $sOrgName);
// When loading localized data in fr_fr, but only en_us file exists
ModuleInstallerAPI::LoadLocalizedData($oConfig, '', '3.3.0', '3.0.0', $sPattern);
$this->AssertOrganizationCountByName($sOrgName, 'fr_fr', 0);
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 1);
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedData
* @dataProvider LoadLocalizedData_ValidVersionFormatsProvider
*/
public function testLoadLocalizedData_AcceptsSupportedVersionFormats(string $sCurrentVersion, string $sFirstLoadingVersion): void
{
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->GivenLocalizedDataTestContext('XML_Load_ValidVersion_', 'en_us');
$this->GivenLocalizedDataFile($sTmpDir, 'en_us', $sOrgName);
ModuleInstallerAPI::LoadLocalizedData($oConfig, '', $sCurrentVersion, $sFirstLoadingVersion, $sPattern);
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 1);
}
public function LoadLocalizedData_ValidVersionFormatsProvider(): array
public function LoadLocalizedData_RequiredLanguageProvider(): array
{
return [
'Current version with suffix' => ['3.2-dev', '3.0.0'],
'Current version x.y.z' => ['1.2.4', '1.0'],
'Current version x.y.z-suffix' => ['2.3.3-beta', '2.0.0'],
'Current version x.y.z-1' => ['1.2.4-1', '1.0.3-2'],
'Required fr_fr and file exists' => [
'required language' => 'fr_fr',
'expected organization names' => ['Client (Test)', 'Département informatique (Test)'],
],
'Required en_us and file exists' => [
'required language' => 'en_us',
'expected organization names' => ['Customer (Test)', 'IT Department (Test)'],
],
'Required de_de but fallback to en_us' => [
'required language' => 'de_de',
'expected organization names' => ['Customer (Test)', 'IT Department (Test)'],
],
];
}
/**
* @covers \ModuleInstallerAPI::IsVersionCrossed
* @dataProvider IsVersionCrossedProvider
*/
public function testIsVersionCrossed_ReturnsExpectedValue(string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion, bool $bExpected): void
{
$bIsVersionCrossed = ModuleInstallerAPI::IsVersionCrossed($sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion);
$this->assertSame($bExpected, $bIsVersionCrossed);
}
public function IsVersionCrossedProvider(): array
{
return [
'First install always crosses' => ['', '3.2.0', '3.0.0', true],
'Upgrade crosses first loading version' => ['3.0.0', '3.2.0', '3.1.0', true],
'Upgrade but first loading version already passed' => ['3.1.0', '3.2.0', '3.0.0', false],
'Reinstall same version does not cross' => ['3.1.0', '3.1.0', '3.0.0', false],
'Downgrade does not cross' => ['3.2.0', '3.1.0', '3.0.0', false],
'First install with suffixed current version' => ['', '3.2-dev', '3.0.0', true],
'Upgrade with suffixed current version crosses' => ['1.0.3-2', '1.2.4-1', '1.1.0', true],
'Upgrade with suffixed current version below threshold does not cross' => ['1.0.0', '1.2.0-beta', '1.2.0', false],
];
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion
*/
public function testLoadLocalizedData_LoadsWhenVersionCrossingIsTrue(): void
{
$this->markTestSkipped('Test skipped because failing in CI. Investigation required, cf Bug N°9787');
[$oConfig, $sPattern] = $this->GivenLocalizedDataTestContext('FR FR', 'data.sample.organizations.en_us.xml');
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, '3.0.0', '3.2.0', '3.1.0', $sPattern);
$this->AssertOrganizationNamesExist(['Client (Test)', 'Département informatique (Test)']);
}
/**
* Test that loading a file twice (because of the version conditions) does not create duplicates (idempotent loading).
* @covers \ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion
*/
public function testLoadLocalizedData_IdempotentLoading(): void
{
// Given
[$oConfig, $sPattern] = $this->GivenLocalizedDataTestContext('en_us', 'data.sample.organizations.en_us.xml');
// When LoadLocalizedData is called twice with conditions that would load the file both times
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, '', '3.0.1', '3.0.0', $sPattern);
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, '3.0.1', '3.1.0', '3.0.2', $sPattern);
// Then no duplicated data load side effect and values remain stable
foreach (['Customer (Test)', 'IT Department (Test)'] as $sExpectedName) {
$oSet = new \DBObjectSet(\DBSearch::FromOQL("SELECT Organization WHERE name = :org_name"), [], ['org_name' => $sExpectedName]);
$this->assertSame(1, $oSet->Count(), "Expected exactly one Organization named '{$sExpectedName}' after loading twice (idempotency)");
}
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion
*/
public function testLoadLocalizedData_LoadsRequestedNonEnUsFileWhenItExists(): void
{
[$oConfig, $sPattern] = $this->GivenLocalizedDataTestContext('en_us', 'data.sample.organizations.fr_fr.xml');
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, '', '3.3.0', '3.0.0', $sPattern);
$this->AssertOrganizationNamesExist(['Client (Test)', 'Département informatique (Test)']);
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion
*/
public function testLoadLocalizedData_ThrowsWhenRequestedEnUsFileDoesNotExist(): void
{
[$oConfig, $sPattern] = $this->GivenLocalizedDataTestContext('en_us', 'data.sample.missing-file.en_us.xml', false);
$this->expectException(\Exception::class);
$this->expectExceptionMessage("File $sPattern not found");
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, '', '3.3.0', '3.0.0', $sPattern);
}
/**
* @covers \ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion
* @dataProvider LoadLocalizedData_InvalidParametersProvider
*/
public function testLoadLocalizedData_ThrowsOnInvalidParameters(string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion, string $sPattern, string $sExpectedMessage): void
{
$oConfig = MetaModel::GetConfig();
$this->assertNotNull($oConfig);
$this->expectException(\CoreUnexpectedValue::class);
$this->expectExceptionMessage($sExpectedMessage);
ModuleInstallerAPI::LoadLocalizedDataOnCrossingVersion($oConfig, $sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion, $sPattern);
}
public function LoadLocalizedData_InvalidParametersProvider(): array
{
$sTmpDir = static::CreateTmpdir();
@@ -364,93 +426,59 @@ SQL
'previous' => 'v3.2',
'current' => '3.2.0',
'first' => '3.0.0',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.{{language_code}}.xml',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.en_us.xml',
'message' => 'sPreviousVersion',
],
'Invalid current version format' => [
'previous' => '',
'current' => '3',
'first' => '3.0.0',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.{{language_code}}.xml',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.en_us.xml',
'message' => 'sCurrentVersion',
],
'Invalid first loading version format' => [
'previous' => '',
'current' => '3.2.0',
'first' => '3.0.0-beta.1',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.{{language_code}}.xml',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.en_us.xml',
'message' => 'sFirstLoadingVersion',
],
'Missing strict placeholder' => [
'previous' => '',
'current' => '3.2.0',
'first' => '3.0.0',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'data.{{LANGUAGE_CODE}}.xml',
'message' => "{{language_code}}",
],
'Parent directory does not exist' => [
'previous' => '',
'current' => '3.2.0',
'first' => '3.0.0',
'pattern' => $sTmpDir.DIRECTORY_SEPARATOR.'missing'.DIRECTORY_SEPARATOR.'data.{{language_code}}.xml',
'message' => 'parent directory',
],
];
}
/**
* Prepare common context for LoadLocalizedData tests.
*
* @return array{0: Config, 1: string, 2: string, 3: string, 4: string}
* @return array{0: Config, 1: string}
*/
private function GivenLocalizedDataTestContext(string $sOrgNamePrefix, string $sLanguage): array
private function GivenLocalizedDataTestContext(string $sLanguage, string $sDataFileName = 'data.sample.organizations.en_us.xml', bool $bAssertFileExists = true): array
{
$oConfig = MetaModel::GetConfig();
$oConfig->SetDefaultLanguage($sLanguage);
$this->assertNotNull($oConfig);
$sOrgName = $sOrgNamePrefix.uniqid();
$sPattern = __DIR__.DIRECTORY_SEPARATOR.'resources2'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'load-localized-data'.DIRECTORY_SEPARATOR.$sDataFileName;
if ($bAssertFileExists) {
$this->assertFileExists($sPattern);
}
$sTmpDir = static::CreateTmpdir();
$this->aFileToClean[] = $sTmpDir;
$sPattern = $sTmpDir.DIRECTORY_SEPARATOR.'data.{{language_code}}.xml';
return [$oConfig, $sOrgName, $sTmpDir, $sPattern];
return [$oConfig, $sPattern];
}
private function GivenLocalizedDataFile(string $sDir, string $sLang, string $sOrgName): string
private function AssertOrganizationNamesExist(array $aExpectedOrganizationNames): void
{
$sFilePath = $sDir.DIRECTORY_SEPARATOR.'data.'.$sLang.'.xml';
file_put_contents($sFilePath, $this->BuildOrganizationXml($sOrgName, $sLang));
return $sFilePath;
foreach ($aExpectedOrganizationNames as $sExpectedName) {
$this->AssertOrganizationNameExists($sExpectedName);
}
}
private function BuildOrganizationXml(string $sOrgName, string $sLang): string
{
$iId = random_int(100000, 999999);
$sOrgNameXml = htmlspecialchars($sOrgName, ENT_XML1);
return <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<Organization alias="Organization" id="{$iId}">
<name>{$sOrgNameXml}</name>
<code>{$sLang}</code>
<status>active</status>
</Organization>
</Set>
XML;
}
private function AssertOrganizationCountByName(string $sOrgName, string $sLanguage, int $iExpectedCount): void
private function AssertOrganizationNameExists(string $sExpectedName): void
{
$oSet = new \DBObjectSet(
\DBSearch::FromOQL("SELECT Organization WHERE name = :org_name AND code = :language"),
\DBSearch::FromOQL("SELECT Organization WHERE name = :org_name"),
[],
['org_name' => $sOrgName, 'language' => $sLanguage]
['org_name' => $sExpectedName]
);
$iCount = $oSet->Count();
$this->assertEquals($iExpectedCount, $iCount, "Found $iCount changes for objects with name '{$sOrgName}' and language '{$sLanguage}', expected {$iExpectedCount}");
$this->assertEquals(1, $oSet->Count(), "Expected exactly one Organization named '{$sExpectedName}'");
}
}