Revision 3277b6bd
Von Moritz Bunkus vor mehr als 11 Jahren hinzugefügt
locale/de/all | ||
---|---|---|
179 | 179 |
'All changes in that file have been reverted.' => 'Alle Änderungen in dieser Datei wurden rückgängig gemacht.', |
180 | 180 |
'All database upgrades have been applied.' => 'Alle Datenbankupdates wurden eingespielt.', |
181 | 181 |
'All general ledger entries' => 'Alle Hauptbucheinträge', |
182 |
'All groups' => 'Alle Gruppen', |
|
182 | 183 |
'All of the exports you have selected were already closed.' => 'Alle von Ihnen ausgewählten Exporte sind bereits abgeschlossen.', |
183 | 184 |
'All reports' => 'Alle Berichte (Kontenübersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)', |
184 | 185 |
'All the selected exports have already been closed, or all of their items have already been executed.' => 'Alle ausgewählten Exporte sind als abgeschlossen markiert, oder für alle Einträge wurden bereits Zahlungen verbucht.', |
... | ... | |
435 | 436 |
'Cleared Balance' => 'abgeschlossen', |
436 | 437 |
'Clearing Tax Received (No 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)', |
437 | 438 |
'Click on login name to edit!' => 'Zum Bearbeiten den Benutzernamen anklicken!', |
439 |
'Client #1' => 'Mandant #1', |
|
438 | 440 |
'Client Configuration' => 'Mandantenkonfiguration', |
439 | 441 |
'Client Configuration saved!' => 'Mandantenkonfiguration gespeichert!', |
442 |
'Client name' => 'Mandantenname', |
|
440 | 443 |
'Close' => 'Übernehmen', |
441 | 444 |
'Close Books up to' => 'Die Bücher abschließen bis zum', |
442 | 445 |
'Close Flash' => 'Schließen', |
... | ... | |
450 | 453 |
'Comment' => 'Kommentar', |
451 | 454 |
'Company' => 'Firma', |
452 | 455 |
'Company Name' => 'Firmenname', |
456 |
'Company name' => 'Firmenname', |
|
453 | 457 |
'Compare to' => 'Gegenüberstellen zu', |
454 | 458 |
'Configuration' => 'Einstellungen', |
455 | 459 |
'Configuration of individual TODO items' => 'Konfiguration für die einzelnen Aufgabenlistenpunkte', |
... | ... | |
512 | 516 |
'Create new' => 'Neu erfassen', |
513 | 517 |
'Create new background job' => 'Neuen Hintergrund-Job anlegen', |
514 | 518 |
'Create new business' => 'Kunden-/Lieferantentyp erfassen', |
519 |
'Create new client #1' => 'Neuen Mandanten #1 anlegen', |
|
515 | 520 |
'Create new department' => 'Neue Abteilung erfassen', |
516 | 521 |
'Create new payment term' => 'Neue Zahlungsbedingung anlegen', |
517 | 522 |
'Create tables' => 'Tabellen anlegen', |
... | ... | |
587 | 592 |
'Database User missing!' => 'Datenbankbenutzer fehlt!', |
588 | 593 |
'Database backups and restorations are disabled in the configuration.' => 'Datenbanksicherungen und -wiederherstellungen sind in der Konfiguration deaktiviert.', |
589 | 594 |
'Database name' => 'Datenbankname', |
595 |
'Database settings' => 'Datenbankeinstellungen', |
|
590 | 596 |
'Database template' => 'Datenbankvorlage', |
591 | 597 |
'Database update error:' => 'Fehler beim Datenbankupgrade:', |
592 | 598 |
'Dataset' => 'Datenbank', |
... | ... | |
841 | 847 |
'Error in position #1: You must either assign no transfer at all or the full quantity of #2 #3.' => 'Fehler in Position #1: Sie müssen einer Position entweder gar keinen Lagerausgang oder die vollständige im Lieferschein vermerkte Menge von #2 #3 zuweisen.', |
842 | 848 |
'Error in row #1: The quantity you entered is bigger than the stocked quantity.' => 'Fehler in Zeile #1: Die angegebene Menge ist größer als die vorhandene Menge.', |
843 | 849 |
'Error message from the database driver:' => 'Fehlermeldung des Datenbanktreibers:', |
850 |
'Error message from the database: #1' => 'Fehlermeldung der Datenbank: #1', |
|
844 | 851 |
'Error when saving: #1' => 'Fehler beim Speichern: #1', |
845 | 852 |
'Error!' => 'Fehler!', |
846 | 853 |
'Error: Buchungsgruppe missing or invalid' => 'Fehler: Buchungsgruppe fehlt oder ungültig', |
... | ... | |
969 | 976 |
'General Ledger Transaction' => 'Dialogbuchung', |
970 | 977 |
'General ledger and cash' => 'Finanzbuchhaltung und Zahlungsverkehr', |
971 | 978 |
'General ledger corrections' => 'Korrekturen im Hauptbuch', |
979 |
'General settings' => 'Allgemeine Einstellungen', |
|
972 | 980 |
'Generic Tax Report' => 'USTVA Bericht', |
973 | 981 |
'Git revision: #1, #2 #3' => 'Git-Revision: #1, #2 #3', |
974 | 982 |
'Given Name' => 'Vorname', |
... | ... | |
984 | 992 |
'Group missing!' => 'Warengruppe fehlt!', |
985 | 993 |
'Group saved!' => 'Warengruppe gespeichert!', |
986 | 994 |
'Groups' => 'Warengruppen', |
995 |
'Groups that are valid for this client for access rights' => 'Gruppen, die für diesen Mandanten gültig sind', |
|
996 |
'Groups valid for this client' => 'Für Mandanten gültige Gruppen', |
|
987 | 997 |
'HTML' => 'HTML', |
988 | 998 |
'HTML Templates' => 'HTML-Vorlagen', |
989 | 999 |
'Hardcopy' => 'Seite drucken', |
... | ... | |
1069 | 1079 |
'International' => 'Ausland', |
1070 | 1080 |
'Internet' => 'Internet', |
1071 | 1081 |
'Introduction of Buchungsgruppen' => 'Einführung von Buchungsgruppen', |
1082 |
'Introduction of clients' => 'Einführung von Mandanten', |
|
1072 | 1083 |
'Introduction of units' => 'Einführung von Einheiten', |
1073 | 1084 |
'Inv. Duedate' => 'Rg. Fälligkeit', |
1074 | 1085 |
'Invalid' => 'Ungültig', |
... | ... | |
1104 | 1115 |
'Invoices, Credit Notes & AR Transactions' => 'Rechnungen, Gutschriften & Debitorenbuchungen', |
1105 | 1116 |
'Is Searchable' => 'Durchsuchbar', |
1106 | 1117 |
'Is this a summary account to record' => 'Sammelkonto für', |
1118 |
'It can be changed later but must be unique within the installation.' => 'Er ist nachträglich änderbar, muss aber im System eindeutig sein.', |
|
1107 | 1119 |
'It is not allowed that a summary account occurs in a drop-down menu!' => 'Ein Sammelkonto darf nicht in Aufklappmenüs aufgenommen werden!', |
1108 | 1120 |
'It is possible that even after such a correction there is something wrong with this transaction (e.g. taxes that don\'t match the selected taxkey). Therefore you should re-run the general ledger analysis.' => 'Auch nach einer Korrektur kann es mit dieser Buchung noch weitere Probleme geben (z.B. nicht zum Steuerschlüssel passende Steuern), weshalb ein erneutes Ausführen der Hauptbuchanalyse empfohlen wird.', |
1109 | 1121 |
'It is possible to do this automatically for some Buchungsgruppen, but not for all.' => 'Es ist möglich, dies für einige, aber nicht für alle Buchungsgruppen automatisch zu erledigen.', |
... | ... | |
1278 | 1290 |
'New Templates' => 'Erzeuge Vorlagen, Name', |
1279 | 1291 |
'New assembly' => 'Neues Erzeugnis', |
1280 | 1292 |
'New bank account' => 'Neues Bankkonto', |
1293 |
'New client #1: The database configuration fields "host", "port", "name" and "user" must not be empty.' => 'Neuer Mandant #1: Die Datenbankkonfigurationsfelder "Host", "Port" und "Name" dürfen nicht leer sein.', |
|
1294 |
'New client #1: The name must be unique and not empty.' => 'Neuer Mandant #1: Der Name darf nicht leer und muss eindeutig sein.', |
|
1281 | 1295 |
'New contact' => 'Neue Ansprechperson', |
1282 | 1296 |
'New customer' => 'Neuer Kunde', |
1283 | 1297 |
'New filter for tax accounts' => 'Neue Filter für Steuerkonten', |
... | ... | |
1375 | 1389 |
'One or more Perl modules missing' => 'Ein oder mehr Perl-Module fehlen', |
1376 | 1390 |
'Only Warnings and Errors' => 'Nur Warnungen und Fehler', |
1377 | 1391 |
'Only due follow-ups' => 'Nur fällige Wiedervorlagen', |
1392 |
'Only groups that have been configured for the client the user logs in to will be considered.' => 'Allerdings werden nur diejenigen Gruppen herangezogen, die für den Mandanten konfiguriert sind.', |
|
1378 | 1393 |
'Only shown in item mode' => 'werden nur im Artikelmodus angezeigt', |
1379 | 1394 |
'Oops. No valid action found to dispatch. Please report this case to the kivitendo team.' => 'Ups. Es wurde keine gültige Funktion zum Aufrufen gefunden. Bitte berichten Sie diesen Fall den kivitendo-Entwicklern.', |
1380 | 1395 |
'Open' => 'Offen', |
... | ... | |
1480 | 1495 |
'Please choose for which categories the taxes should be displayed (otherwise remove the ticks):' => 'Bitte wählen Sie für welche Kontoart die Steuer angezeigt werden soll (ansonsten einfach die Häkchen entfernen)', |
1481 | 1496 |
'Please contact your administrator or a service provider.' => 'Bitte kontaktieren Sie Ihren Administrator oder einen Dienstleister.', |
1482 | 1497 |
'Please contact your administrator.' => 'Bitte wenden Sie sich an Ihren Administrator.', |
1498 |
'Please correct the settings and try again or deactivate that client.' => 'Bitte korrigieren Sie die Einstellungen und versuchen Sie es erneut, oder deaktivieren Sie diesen Mandanten.', |
|
1483 | 1499 |
'Please define a taxkey for the following taxes and run the update again:' => 'Bitte definieren Sie einen Steuerschlüssel für die folgenden Steuern und starten Sie dann das Update erneut:', |
1484 | 1500 |
'Please enter a profile name.' => 'Bitte geben Sie einen Profilnamen an.', |
1485 | 1501 |
'Please enter the currency you are working with.' => 'Bitte geben Sie die Währung an, mit der Sie arbeiten.', |
... | ... | |
1504 | 1520 |
'Please select the database you want to backup' => 'Bitte wählen Sie die zu sichernde Datenbank gefunden', |
1505 | 1521 |
'Please select the destination bank account for the collections:' => 'Bitte wählen Sie das Bankkonto als Ziel für die Einzüge aus:', |
1506 | 1522 |
'Please select the source bank account for the transfers:' => 'Bitte wählen Sie das Bankkonto als Quelle für die Überweisungen aus:', |
1523 |
'Please select which client configurations you want to create.' => 'Bitte wählen Sie aus, welche Mandanten mit welchen Einstellungen angelegt werden sollen.', |
|
1507 | 1524 |
'Please seletct the dataset you want to delete:' => 'Bitte wählen Sie die zu löschende Datenbank aus:', |
1508 | 1525 |
'Please set another taxnumber for the following taxes and run the update again:' => 'Bitte wählen Sie ein anderes Steuerautomatik-Konto für die folgenden Steuern aus uns starten Sie dann das Update erneut.', |
1509 | 1526 |
'Please specify a description for the warehouse designated for these goods.' => 'Bitte geben Sie den Namen des Ziellagers für die übernommenen Daten ein.', |
... | ... | |
1547 | 1564 |
'Print dunnings' => 'Mahnungen drucken', |
1548 | 1565 |
'Print list' => 'Liste ausdrucken', |
1549 | 1566 |
'Print options' => 'Druckoptionen', |
1567 |
'Print templates' => 'Druckvorlagen', |
|
1550 | 1568 |
'Printer' => 'Drucker', |
1551 | 1569 |
'Printer Command' => 'Druckbefehl', |
1552 | 1570 |
'Printer Command missing!' => 'Druckbefehl fehlt', |
... | ... | |
1960 | 1978 |
'Text, text field and number variables: The default value will be used as-is.' => 'Textzeilen, Textfelder und Zahlenvariablen: Der Standardwert wird so wie er ist übernommen.', |
1961 | 1979 |
'That export does not exist.' => 'Dieser Export existiert nicht.', |
1962 | 1980 |
'That is why kivitendo could not find a default currency.' => 'Daher konnte kivitendo keine Standardwährung finden.', |
1981 |
'The \'name\' is the field shown to the user during login.' => 'Der \'Name\' ist derjenige, der dem Benutzer beim Login angezeigt wird.', |
|
1963 | 1982 |
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.', |
1964 | 1983 |
'The AP transaction #1 has been deleted.' => 'Die Kreditorenbuchung #1 wurde gelöscht.', |
1965 | 1984 |
'The AR transaction #1 has been deleted.' => 'Die Debitorenbuchung #1 wurde gelöscht.', |
... | ... | |
1969 | 1988 |
'The LDAP server "#1:#2" is unreachable. Please check config/kivitendo.conf.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte überprüfen Sie die Angaben in config/kivitendo.conf.', |
1970 | 1989 |
'The SEPA export has been created.' => 'Der SEPA-Export wurde erstellt', |
1971 | 1990 |
'The SEPA strings have been saved.' => 'Die bei SEPA-Überweisungen verwendeten Begriffe wurden gespeichert.', |
1991 |
'The access rights a user has within a client instance is still governed by his group membership.' => 'Welche Zugriffsrechte ein Benutzer innerhalb eines Mandanten hat, wird weiterhin über Gruppenmitgliedschaften geregelt.', |
|
1972 | 1992 |
'The access rights have been saved.' => 'Die Zugriffsrechte wurden gespeichert.', |
1973 | 1993 |
'The account 3804 already exists, the update will be skipped.' => 'Das Konto 3804 existiert schon, das Update wird übersprungen.', |
1974 | 1994 |
'The account 3804 will not be added automatically.' => 'Das Konto 3804 wird nicht automatisch hinzugefügt.', |
... | ... | |
1998 | 2018 |
'The columns "Dunning Duedate", "Total Fees" and "Interest" show data for the previous dunning created for this invoice.' => 'Die Spalten "Zahlbar bis", "Kumulierte Gebühren" und "Zinsen" zeigen Daten der letzten für diese Rechnung erzeugten Mahnung.', |
1999 | 2019 |
'The connection to the LDAP server cannot be encrypted (SSL/TLS startup failure). Please check config/kivitendo.conf.' => 'Die Verbindung zum LDAP-Server kann nicht verschlüsselt werden (Fehler bei SSL/TLS-Initialisierung). Bitte überprüfen Sie die Angaben in config/kivitendo.conf.', |
2000 | 2020 |
'The connection to the authentication database failed:' => 'Die Verbindung zur Authentifizierungsdatenbank schlug fehl:', |
2021 |
'The connection to the configured client database "#1" on host "#2:#3" failed.' => 'Die Verbindung zur konfigurierten Datenbank "#1" auf Host "#2:#3" schlug fehl.', |
|
2001 | 2022 |
'The connection to the database could not be established.' => 'Die Verbindung zur Datenbank konnte nicht hergestellt werden.', |
2002 | 2023 |
'The connection to the template database failed:' => 'Die Verbindung zur Vorlagendatenbank schlug fehl:', |
2003 | 2024 |
'The connection was established successfully.' => 'Die Verbindung zur Datenbank wurde erfolgreich hergestellt.', |
... | ... | |
2042 | 2063 |
'The following Datasets need to be updated' => 'Folgende Datenbanken müssen aktualisiert werden', |
2043 | 2064 |
'The following currencies have been used, but they are not defined:' => 'Die folgenden Währungen wurden benutzt, sind aber nicht ordnungsgemäß in der Datenbank eingetragen:', |
2044 | 2065 |
'The following drafts have been saved and can be loaded.' => 'Die folgenden Entwürfe wurden gespeichert und können geladen werden.', |
2066 |
'The following list has been generated automatically from existing users collapsing users with identical settings into a single entry.' => 'Die folgende Liste wurde automatisch aus den im System vorhandenen Benutzern zusammengestellt, wobei identische Einstellungen zu einem Eintrag zusammengefasst wurden.', |
|
2045 | 2067 |
'The following old files whose settings have to be merged manually into the new configuration file "config/kivitendo.conf" still exist:' => 'Es existieren noch die folgenden alten Dateien, deren Einstellungen manuell in die neue Konfiguratsdatei "config/kivitendo.conf" migriert werden müssen:', |
2046 | 2068 |
'The following transaction contains wrong taxes:' => 'Die folgende Buchung enthält falsche Steuern:', |
2047 | 2069 |
'The following transaction contains wrong taxkeys:' => 'Die folgende Buchung enthält falsche Steuerschlüssel:', |
... | ... | |
2123 | 2145 |
'The unit in row %d has been deleted in the meantime.' => 'Die Einheit in Zeile %d ist in der Zwischentzeit gelöscht worden.', |
2124 | 2146 |
'The unit in row %d has been used in the meantime and cannot be changed anymore.' => 'Die Einheit in Zeile %d wurde in der Zwischenzeit benutzt und kann nicht mehr geändert werden.', |
2125 | 2147 |
'The units have been saved.' => 'Die Einheiten wurden gespeichert.', |
2148 |
'The user can chose which client to connect to during login.' => 'Bei der Anmeldung kann der Benutzer auswählen, welchen Mandanten er benutzen möchte.', |
|
2126 | 2149 |
'The user is a member in the following group(s):' => 'Der Benutzer ist Mitglied in den folgenden Gruppen:', |
2127 | 2150 |
'The variable name must only consist of letters, numbers and underscores. It must begin with a letter. Example: send_christmas_present' => 'Der Variablenname darf nur aus Zeichen (keine Umlaute), Ziffern und Unterstrichen bestehen. Er muss mit einem Buchstaben beginnen. Beispiel: weihnachtsgruss_verschicken', |
2128 | 2151 |
'The warehouse could not be deleted because it has already been used.' => 'Das Lager konnte nicht gelöscht werden, da es bereits in Benutzung war.', |
... | ... | |
2160 | 2183 |
'There is nothing to do in this step.' => 'In diesem Schritt gibt es nichts mehr zu tun.', |
2161 | 2184 |
'There was an error executing the background job.' => 'Bei der Ausführung des Hintergrund-Jobs trat ein Fehler auf.', |
2162 | 2185 |
'There was an error parsing the csv file: #1 in line #2.' => 'Es gab einen Fehler beim Parsen der CSV Datei: "#1" in der Zeile "#2"', |
2186 |
'Therefore several settings that had to be made for each user in the past have been consolidated into the client configuration.' => 'Dazu wurden gewisse Einstellungen, die vorher bei jedem Benutzer vorgenommen werden mussten, in die Konfiguration eines Mandanten verschoben.', |
|
2163 | 2187 |
'Therefore the definition of "kg" with the base unit "g" and a factor of 1000 is valid while defining "g" with a base unit of "kg" and a factor of "0.001" is not.' => 'So ist die Definition von "kg" mit der Basiseinheit "g" und dem Faktor 1000 zulässig, die Definition von "g" mit der Basiseinheit "kg" und dem Faktor "0,001" hingegen nicht.', |
2164 | 2188 |
'Therefore there\'s no need to create the same article more than once if it is sold or bought in/from another tax zone.' => 'Deswegen muss man den gleichen Artikel nicht mehr mehrmals anlegen, wenn er in verschiedenen Steuerzonen gehandelt werden soll.', |
2165 | 2189 |
'These units can be based on other units so that kivitendo can convert prices when the user switches from one unit to another.' => 'Einheiten können auf anderen Einheiten basieren, sodass kivitendo Preise automatisch umrechnen kann, wenn die Benutzer zwischen solchen Einheiten umschalten.', |
... | ... | |
2287 | 2311 |
'Updated' => 'Erneuert am', |
2288 | 2312 |
'Updating existing entry in database' => 'Existierenden Eintrag in Datenbank aktualisieren', |
2289 | 2313 |
'Updating prices of existing entry in database' => 'Preis des Eintrags in der Datenbank wird aktualisiert', |
2314 |
'Updating the client fields in the database "#1" on host "#2:#3" failed.' => 'Die Aktualisierung der Mandantenfelder in der Datenbank "#1" auf Host "#2:#3" schlug fehl.', |
|
2290 | 2315 |
'Uploaded on #1, size #2 kB' => 'Am #1 hochgeladen, Größe #2 kB', |
2291 | 2316 |
'Use As New' => 'Als neu verwenden', |
2292 | 2317 |
'Use Templates' => 'Benutze Vorlagen', |
... | ... | |
2294 | 2319 |
'User' => 'Benutzer', |
2295 | 2320 |
'User Config' => 'Einstellungen', |
2296 | 2321 |
'User Login' => 'Als Benutzer anmelden', |
2322 |
'User access' => 'Benutzerzugriff', |
|
2323 |
'User data migration' => 'Benutzerdatenmigration', |
|
2297 | 2324 |
'User deleted!' => 'Benutzer gelöscht!', |
2298 | 2325 |
'User login' => 'Benutzeranmeldung', |
2299 | 2326 |
'User name' => 'Benutzername', |
2300 | 2327 |
'User saved!' => 'Benutzer gespeichert!', |
2301 | 2328 |
'Username' => 'Benutzername', |
2302 | 2329 |
'Users in this group' => 'BenutzerInnen in dieser Gruppe', |
2330 |
'Users with access' => 'Benutzer mit Zugriff', |
|
2331 |
'Users with access to this client' => 'Benutzer mit Zugriff auf diesen Mandanten', |
|
2303 | 2332 |
'Ust-IDNr' => 'USt-IdNr.', |
2333 |
'VAT ID' => 'UStdID-Nr', |
|
2304 | 2334 |
'Valid' => 'Gültig', |
2305 | 2335 |
'Valid from' => 'Gültig ab', |
2306 | 2336 |
'Valid until' => 'gültig bis', |
... | ... | |
2403 | 2433 |
'You have to enter a company name in your user preferences (see the "Program" menu, "Preferences").' => 'Sie müssen einen Firmennamen in Ihren Einstellungen angeben (siehe Menü "Programm", "Einstellungen").', |
2404 | 2434 |
'You have to enter the SEPA creditor ID in your user preferences (see the "Program" menu, "Preferences").' => 'Sie müssen die SEPA-Kreditoren-Identifikation in Ihren Einstellungen angeben (siehe Menü "Programm", "Einstellungen").', |
2405 | 2435 |
'You have to fill in at least an account number, the bank code, the IBAN and the BIC.' => 'Sie müssen zumindest die Kontonummer, die Bankleitzahl, die IBAN und den BIC angeben.', |
2436 |
'You have to grant users access to one or more clients.' => 'Benutzern muss dann Zugriff auf einzelne Mandanten gewährt werden.', |
|
2406 | 2437 |
'You have to specify a department.' => 'Sie müssen eine Abteilung wählen.', |
2407 | 2438 |
'You have to specify an execution date for each antry.' => 'Sie müssen für jeden zu buchenden Eintrag ein Ausführungsdatum angeben.', |
2408 | 2439 |
'You must chose a user.' => 'Sie müssen einen Benutzer auswählen.', |
... | ... | |
2506 | 2537 |
'kivitendo Homepage' => 'Infos zu kivitendo', |
2507 | 2538 |
'kivitendo administration' => 'kivitendo Administration', |
2508 | 2539 |
'kivitendo can fix these problems automatically.' => 'kivitendo kann solche Probleme automatisch beheben.', |
2540 |
'kivitendo has been extended to handle multiple clients within a single installation.' => 'kivitendo wurde um Mandantenfähigkeit erweitert.', |
|
2541 |
'kivitendo has been switched to group-based access restrictions.' => 'kivitendo wurde auf eine gruppenbasierte Benutzerzugriffsverwaltung umgestellt.', |
|
2509 | 2542 |
'kivitendo has found one or more problems in the general ledger.' => 'kivitendo hat ein oder mehrere Probleme im Hauptbuch gefunden.', |
2510 | 2543 |
'kivitendo is about to update the database [ #1 ].' => 'kivitendo wird gleich die Datenbank [ #1 ] aktualisieren.', |
2511 | 2544 |
'kivitendo is now able to manage warehouses instead of just tracking the amount of goods in your system.' => 'kivitendo enthält jetzt auch echte Lagerverwaultung anstatt reiner Mengenzählung.', |
sql/Pg-upgrade2-auth/clients.pl | ||
---|---|---|
1 |
# @tag: clients |
|
2 |
# @description: Einführung von Mandaten |
|
3 |
# @depends: release_3_0_0 |
|
4 |
# @ignore: 0 |
|
5 |
package SL::DBUpgrade2::clients; |
|
6 |
|
|
7 |
use strict; |
|
8 |
use utf8; |
|
9 |
|
|
10 |
use parent qw(SL::DBUpgrade2::Base); |
|
11 |
|
|
12 |
use List::MoreUtils qw(any all); |
|
13 |
use List::Util qw(first); |
|
14 |
|
|
15 |
use SL::DBConnect; |
|
16 |
use SL::DBUtils; |
|
17 |
use SL::Template; |
|
18 |
use SL::Helper::Flash; |
|
19 |
|
|
20 |
use Rose::Object::MakeMethods::Generic ( |
|
21 |
scalar => [ qw(clients) ], |
|
22 |
'scalar --get_set_init' => [ qw(users groups templates auth_db_settings data_dbhs) ], |
|
23 |
); |
|
24 |
|
|
25 |
sub init_users { |
|
26 |
my ($self) = @_; |
|
27 |
my @users = selectall_hashref_query($::form, $self->dbh, qq|SELECT * FROM auth."user" ORDER BY lower(login)|); |
|
28 |
|
|
29 |
foreach my $user (@users) { |
|
30 |
my @attributes = selectall_hashref_query($::form, $self->dbh, <<SQL, $user->{id}); |
|
31 |
SELECT cfg_key, cfg_value |
|
32 |
FROM auth.user_config |
|
33 |
WHERE user_id = ? |
|
34 |
SQL |
|
35 |
|
|
36 |
$user->{ $_->{cfg_key} } = $_->{cfg_value} for @attributes; |
|
37 |
} |
|
38 |
|
|
39 |
return \@users; |
|
40 |
} |
|
41 |
|
|
42 |
sub init_groups { |
|
43 |
my ($self) = @_; |
|
44 |
return [ selectall_hashref_query($::form, $self->dbh, qq|SELECT * FROM auth."group" ORDER BY lower(name)|) ]; |
|
45 |
} |
|
46 |
|
|
47 |
sub init_templates { |
|
48 |
my %templates = SL::Template->available_templates; |
|
49 |
return $templates{print_templates}; |
|
50 |
} |
|
51 |
|
|
52 |
sub init_auth_db_settings { |
|
53 |
my $cfg = $::lx_office_conf{'authentication/database'}; |
|
54 |
return { |
|
55 |
dbhost => $cfg->{host} || 'localhost', |
|
56 |
dbport => $cfg->{port} || 5432, |
|
57 |
dbname => $cfg->{name}, |
|
58 |
}; |
|
59 |
} |
|
60 |
|
|
61 |
sub init_data_dbhs { |
|
62 |
return []; |
|
63 |
} |
|
64 |
|
|
65 |
sub _clear_field { |
|
66 |
my ($text) = @_; |
|
67 |
|
|
68 |
$text ||= ''; |
|
69 |
$text =~ s/^\s+|\s+$//g; |
|
70 |
|
|
71 |
return $text; |
|
72 |
} |
|
73 |
|
|
74 |
sub _group_into_clients { |
|
75 |
my ($self) = @_; |
|
76 |
|
|
77 |
my @match_fields = qw(dbhost dbport dbname); |
|
78 |
my @copy_fields = (@match_fields, qw(address company co_ustid dbuser dbpasswd duns sepa_creditor_id taxnumber templates)); |
|
79 |
my @clients; |
|
80 |
|
|
81 |
# Group users into clients. Users which have identical database |
|
82 |
# settings (host, port and name) will be grouped. The other fields |
|
83 |
# like tax number etc. are taken from the first user and only filled |
|
84 |
# from user users if they're still unset. |
|
85 |
foreach my $user (@{ $self->users }) { |
|
86 |
$user->{$_} = _clear_field($user->{$_}) for @copy_fields; |
|
87 |
|
|
88 |
my $existing_client = first { my $client = $_; all { ($user->{$_} || '') eq ($client->{$_} || '') } @match_fields } @clients; |
|
89 |
|
|
90 |
if ($existing_client) { |
|
91 |
push @{ $existing_client->{users} }, $user->{id}; |
|
92 |
$existing_client->{$_} ||= $user->{$_} for @copy_fields; |
|
93 |
next; |
|
94 |
} |
|
95 |
|
|
96 |
push @clients, { |
|
97 |
map({ $_ => $user->{$_} } @copy_fields), |
|
98 |
name => $::locale->text('Client #1', scalar(@clients) + 1), |
|
99 |
users => [ $user->{id} ], |
|
100 |
groups => [ map { $_->{id} } @{ $self->groups } ], |
|
101 |
enabled => 1, |
|
102 |
}; |
|
103 |
} |
|
104 |
|
|
105 |
# Ignore users (and therefore clients) for which no database |
|
106 |
# configuration has been given. |
|
107 |
@clients = grep { my $client = $_; any { $client->{$_} } @match_fields } @clients; |
|
108 |
|
|
109 |
# If there's only one client set that one as default. |
|
110 |
$clients[0]->{is_default} = 1 if scalar(@clients) == 1; |
|
111 |
|
|
112 |
# Set a couple of defaults for database fields. |
|
113 |
my $num = 0; |
|
114 |
foreach my $client (@clients) { |
|
115 |
$num += 1; |
|
116 |
$client->{dbhost} ||= 'localhost'; |
|
117 |
$client->{dbport} ||= 5432; |
|
118 |
$client->{templates} =~ s:templates/::; |
|
119 |
} |
|
120 |
|
|
121 |
$self->clients(\@clients); |
|
122 |
} |
|
123 |
|
|
124 |
sub _analyze { |
|
125 |
my ($self, %params) = @_; |
|
126 |
|
|
127 |
$self->_group_into_clients; |
|
128 |
|
|
129 |
return $self->_do_convert if !@{ $self->clients }; |
|
130 |
|
|
131 |
print $::form->parse_html_template('dbupgrade/auth/clients', { SELF => $self }); |
|
132 |
|
|
133 |
return 2; |
|
134 |
} |
|
135 |
|
|
136 |
sub _verify_clients { |
|
137 |
my ($self) = @_; |
|
138 |
|
|
139 |
my (%names, @errors); |
|
140 |
|
|
141 |
my $num = 0; |
|
142 |
foreach my $client (@{ $self->clients }) { |
|
143 |
$num += 1; |
|
144 |
|
|
145 |
next if !$client->{enabled}; |
|
146 |
|
|
147 |
$client->{$_} = _clear_field($client->{$_}) for qw(address co_ustid company dbhost dbname dbpasswd dbport dbuser duns sepa_creditor_id taxnumber templates); |
|
148 |
|
|
149 |
if (!$client->{name} || $names{ $client->{name} }) { |
|
150 |
push @errors, $::locale->text('New client #1: The name must be unique and not empty.', $num); |
|
151 |
} |
|
152 |
|
|
153 |
$names{ $client->{name} } = 1; |
|
154 |
|
|
155 |
if (any { !$client->{$_} } qw(dbhost dbport dbname dbuser)) { |
|
156 |
push @errors, $::locale->text('New client #1: The database configuration fields "host", "port", "name" and "user" must not be empty.', $num); |
|
157 |
} |
|
158 |
} |
|
159 |
|
|
160 |
return @errors; |
|
161 |
} |
|
162 |
|
|
163 |
sub _alter_auth_database_structure { |
|
164 |
my ($self) = @_; |
|
165 |
|
|
166 |
my @queries = ( |
|
167 |
qq|CREATE TABLE auth.clients ( |
|
168 |
id SERIAL PRIMARY KEY, |
|
169 |
name TEXT NOT NULL UNIQUE, |
|
170 |
dbhost TEXT NOT NULL, |
|
171 |
dbport INTEGER NOT NULL DEFAULT 5432, |
|
172 |
dbname TEXT NOT NULL, |
|
173 |
dbuser TEXT NOT NULL, |
|
174 |
dbpasswd TEXT NOT NULL, |
|
175 |
is_default BOOLEAN NOT NULL DEFAULT FALSE, |
|
176 |
|
|
177 |
UNIQUE (dbhost, dbport, dbname) |
|
178 |
)|, |
|
179 |
qq|CREATE TABLE auth.clients_users ( |
|
180 |
client_id INTEGER NOT NULL REFERENCES auth.clients (id), |
|
181 |
user_id INTEGER NOT NULL REFERENCES auth."user" (id), |
|
182 |
|
|
183 |
PRIMARY KEY (client_id, user_id) |
|
184 |
)|, |
|
185 |
qq|CREATE TABLE auth.clients_groups ( |
|
186 |
client_id INTEGER NOT NULL REFERENCES auth.clients (id), |
|
187 |
group_id INTEGER NOT NULL REFERENCES auth."group" (id), |
|
188 |
|
|
189 |
PRIMARY KEY (client_id, group_id) |
|
190 |
)|, |
|
191 |
); |
|
192 |
|
|
193 |
$self->db_query($_, may_fail => 0) for @queries; |
|
194 |
} |
|
195 |
|
|
196 |
sub _alter_data_database_structure { |
|
197 |
my ($self, $dbh) = @_; |
|
198 |
|
|
199 |
my @queries = ( |
|
200 |
qq|ALTER TABLE defaults ADD COLUMN company TEXT|, |
|
201 |
qq|ALTER TABLE defaults ADD COLUMN address TEXT|, |
|
202 |
qq|ALTER TABLE defaults ADD COLUMN taxnumber TEXT|, |
|
203 |
qq|ALTER TABLE defaults ADD COLUMN co_ustid TEXT|, |
|
204 |
qq|ALTER TABLE defaults ADD COLUMN duns TEXT|, |
|
205 |
qq|ALTER TABLE defaults ADD COLUMN sepa_creditor_id TEXT|, |
|
206 |
qq|ALTER TABLE defaults ADD COLUMN templates TEXT|, |
|
207 |
qq|INSERT INTO schema_info (tag, login) VALUES ('clients', 'admin')|, |
|
208 |
); |
|
209 |
|
|
210 |
foreach my $query (@queries) { |
|
211 |
$dbh->do($query) || die $self->db_errstr($dbh); |
|
212 |
} |
|
213 |
} |
|
214 |
|
|
215 |
sub _create_clients_in_auth_database { |
|
216 |
my ($self) = @_; |
|
217 |
|
|
218 |
my @client_columns = qw(name dbhost dbport dbname dbuser dbpasswd is_default); |
|
219 |
my $q_client = qq|INSERT INTO auth.clients (| . join(', ', @client_columns) . qq|) VALUES (| . join(', ', ('?') x @client_columns) . qq|) RETURNING id|; |
|
220 |
my $sth_client = $self->dbh->prepare($q_client) || die $self->db_errstr; |
|
221 |
|
|
222 |
my $q_client_user = qq|INSERT INTO auth.clients_users (client_id, user_id) VALUES (?, ?)|; |
|
223 |
my $sth_client_user = $self->dbh->prepare($q_client_user) || die $self->db_errstr; |
|
224 |
|
|
225 |
my $q_client_group = qq|INSERT INTO auth.clients_groups (client_id, group_id) VALUES (?, ?)|; |
|
226 |
my $sth_client_group = $self->dbh->prepare($q_client_group) || die $self->db_errstr; |
|
227 |
|
|
228 |
foreach my $client (@{ $self->clients }) { |
|
229 |
next unless $client->{enabled}; |
|
230 |
|
|
231 |
$client->{is_default} = $client->{is_default} ? 1 : 0; |
|
232 |
|
|
233 |
$sth_client->execute(@{ $client }{ @client_columns }) || die; |
|
234 |
my $client_id = $sth_client->fetch->[0]; |
|
235 |
|
|
236 |
$sth_client_user ->execute($client_id, $_) || die for @{ $client->{users} || [] }; |
|
237 |
$sth_client_group->execute($client_id, $_) || die for @{ $client->{groups} || [] }; |
|
238 |
} |
|
239 |
|
|
240 |
$sth_client ->finish; |
|
241 |
$sth_client_user ->finish; |
|
242 |
$sth_client_group->finish; |
|
243 |
} |
|
244 |
|
|
245 |
sub _clean_auth_database { |
|
246 |
my ($self) = @_; |
|
247 |
|
|
248 |
my @keys_to_delete = qw(acs address admin anfragen angebote bestellungen businessnumber charset companies company co_ustid currency dbconnect dbdriver dbhost dbname dboptions dbpasswd dbport dbuser duns |
|
249 |
einkaufsrechnungen in_numberformat lieferantenbestellungen login pdonumber printer rechnungen role sdonumber sepa_creditor_id sid steuernummer taxnumber templates); |
|
250 |
|
|
251 |
$self->dbh->do(qq|DELETE FROM auth.user_config WHERE cfg_key IN (| . join(', ', ('?') x @keys_to_delete) . qq|)|, undef, @keys_to_delete) |
|
252 |
|| die $self->db_errstr; |
|
253 |
} |
|
254 |
|
|
255 |
sub _copy_fields_to_data_database { |
|
256 |
my ($self, $client) = @_; |
|
257 |
|
|
258 |
my $dbh = SL::DBConnect->connect('dbi:Pg:dbname=' . $client->{dbname} . ';host=' . $client->{dbhost} . ';port=' . $client->{dbport}, |
|
259 |
$client->{dbuser}, $client->{dbpasswd}, |
|
260 |
SL::DBConnect->get_options(AutoCommit => 0)); |
|
261 |
if (!$dbh) { |
|
262 |
die join("\n", |
|
263 |
$::locale->text('The connection to the configured client database "#1" on host "#2:#3" failed.', $client->{dbname}, $client->{dbhost}, $client->{dbport}), |
|
264 |
$::locale->text('Please correct the settings and try again or deactivate that client.'), |
|
265 |
$::locale->text('Error message from the database: #1', $self->db_errstr('DBI'))); |
|
266 |
} |
|
267 |
|
|
268 |
my ($has_been_applied) = $dbh->selectrow_array(qq|SELECT tag FROM schema_info WHERE tag = 'clients'|); |
|
269 |
|
|
270 |
if (!$has_been_applied) { |
|
271 |
$self->_alter_data_database_structure($dbh); |
|
272 |
} |
|
273 |
|
|
274 |
my @columns = qw(company address taxnumber co_ustid duns sepa_creditor_id templates); |
|
275 |
my $query = join ', ', map { "$_ = ?" } @columns; |
|
276 |
my @values = @{ $client }{ @columns }; |
|
277 |
|
|
278 |
if (!$dbh->do(qq|UPDATE defaults SET $query|, undef, @values)) { |
|
279 |
die join("\n", |
|
280 |
$::locale->text('Updating the client fields in the database "#1" on host "#2:#3" failed.', $client->{dbname}, $client->{dbhost}, $client->{dbport}), |
|
281 |
$::locale->text('Please correct the settings and try again or deactivate that client.'), |
|
282 |
$::locale->text('Error message from the database: #1', $self->db_errstr('DBI'))); |
|
283 |
} |
|
284 |
|
|
285 |
$self->data_dbhs([ @{ $self->data_dbhs }, $dbh ]); |
|
286 |
} |
|
287 |
|
|
288 |
sub _commit_data_database_changes { |
|
289 |
my ($self) = @_; |
|
290 |
|
|
291 |
foreach my $dbh (@{ $self->data_dbhs }) { |
|
292 |
$dbh->commit; |
|
293 |
$dbh->disconnect; |
|
294 |
} |
|
295 |
} |
|
296 |
|
|
297 |
sub _do_convert { |
|
298 |
my ($self) = @_; |
|
299 |
|
|
300 |
# Skip clients that are not enabled. Clean fields. |
|
301 |
my $num = 0; |
|
302 |
foreach my $client (@{ $self->clients }) { |
|
303 |
$num += 1; |
|
304 |
|
|
305 |
next if !$client->{enabled}; |
|
306 |
|
|
307 |
$client->{$_} = _clear_field($client->{$_}) for qw(dbhost dbport dbname dbuser dbpasswd address company co_ustid dbuser dbpasswd duns sepa_creditor_id taxnumber templates); |
|
308 |
$client->{templates} = 'templates/' . $client->{templates}; |
|
309 |
} |
|
310 |
|
|
311 |
$self->_copy_fields_to_data_database($_) for grep { $_->{enabled} } @{ $self->clients }; |
|
312 |
|
|
313 |
$self->_alter_auth_database_structure; |
|
314 |
$self->_create_clients_in_auth_database; |
|
315 |
$self->_clean_auth_database; |
|
316 |
|
|
317 |
$self->_commit_data_database_changes; |
|
318 |
|
|
319 |
return 1; |
|
320 |
} |
|
321 |
|
|
322 |
sub run { |
|
323 |
my ($self) = @_; |
|
324 |
|
|
325 |
return $self->_analyze if !$::form->{clients} || !@{ $::form->{clients} }; |
|
326 |
|
|
327 |
$self->clients($::form->{clients}); |
|
328 |
|
|
329 |
my @errors = $self->_verify_clients; |
|
330 |
|
|
331 |
return $self->_do_convert if !@errors; |
|
332 |
|
|
333 |
flash('error', @errors); |
|
334 |
|
|
335 |
print $::form->parse_html_template('dbupgrade/auth/clients', { SELF => $self }); |
|
336 |
|
|
337 |
return 1; |
|
338 |
} |
|
339 |
|
|
340 |
1; |
templates/webpages/dbupgrade/auth/clients.html | ||
---|---|---|
1 |
[%- USE LxERP -%][%- USE L -%] |
|
2 |
|
|
3 |
[%- INCLUDE 'common/flash.html' %] |
|
4 |
|
|
5 |
[% L.javascript_tag('jquery.selectboxes', 'jquery.multiselect2side') %] |
|
6 |
|
|
7 |
<h1>[%- LxERP.t8("Introduction of clients") %]</h1> |
|
8 |
|
|
9 |
<p> |
|
10 |
[% LxERP.t8("kivitendo has been extended to handle multiple clients within a single installation.") %] |
|
11 |
[% LxERP.t8("Therefore several settings that had to be made for each user in the past have been consolidated into the client configuration.") %] |
|
12 |
[% LxERP.t8("You have to grant users access to one or more clients.") %] |
|
13 |
[% LxERP.t8("The user can chose which client to connect to during login.") %] |
|
14 |
</p> |
|
15 |
|
|
16 |
<p> |
|
17 |
[% LxERP.t8("The access rights a user has within a client instance is still governed by his group membership.") %] |
|
18 |
[% LxERP.t8("Only groups that have been configured for the client the user logs in to will be considered.") %] |
|
19 |
</p> |
|
20 |
|
|
21 |
<p> |
|
22 |
[% LxERP.t8("The following list has been generated automatically from existing users collapsing users with identical settings into a single entry.") %] |
|
23 |
[% LxERP.t8("Please select which client configurations you want to create.") %] |
|
24 |
[% LxERP.t8("The 'name' is the field shown to the user during login.") %] |
|
25 |
[% LxERP.t8("It can be changed later but must be unique within the installation.") %] |
|
26 |
</p> |
|
27 |
|
|
28 |
<form method="post" action="admin.pl"> |
|
29 |
[%- FOREACH client = SELF.clients %] |
|
30 |
[%- L.hidden_tag("clients[+].dummy", 1) %] |
|
31 |
|
|
32 |
<h2>[%- L.checkbox_tag("clients[].enabled", label=LxERP.t8("Create new client #1", loop.count), checked=client.enabled) %]</h2> |
|
33 |
|
|
34 |
<table> |
|
35 |
<tr> |
|
36 |
<th colspan="6">[%- LxERP.t8("General settings") %]</th> |
|
37 |
</tr> |
|
38 |
|
|
39 |
<tr> |
|
40 |
<td align="right" valign="top">[%- LxERP.t8("Client name") %]:</td> |
|
41 |
<td valign="top">[%- L.input_tag("clients[].name", client.name) %]</td> |
|
42 |
|
|
43 |
<td align="right" valign="top">[%- LxERP.t8("Company name") %]:</td> |
|
44 |
<td valign="top">[%- L.input_tag("clients[].company", client.company) %]</td> |
|
45 |
|
|
46 |
<td align="right" valign="top">[%- LxERP.t8("Address") %]:</td> |
|
47 |
<td valign="top">[%- L.textarea_tag("clients[].address", client.address, rows=4, cols=40) %]</td> |
|
48 |
</tr> |
|
49 |
|
|
50 |
<tr> |
|
51 |
<td align="right">[%- LxERP.t8("Tax number") %]:</td> |
|
52 |
<td>[%- L.input_tag("clients[].taxnumber", client.taxnumber) %]</td> |
|
53 |
|
|
54 |
<td align="right">[%- LxERP.t8("VAT ID") %]:</td> |
|
55 |
<td>[%- L.input_tag("clients[].co_ustid", client.co_ustid) %]</td> |
|
56 |
|
|
57 |
<td align="right">[%- LxERP.t8("DUNS-Nr") %]:</td> |
|
58 |
<td>[%- L.input_tag("clients[].duns", client.duns) %]</td> |
|
59 |
</tr> |
|
60 |
|
|
61 |
<tr> |
|
62 |
<td align="right">[%- LxERP.t8("SEPA creditor ID") %]:</td> |
|
63 |
<td colspan="5">[%- L.input_tag("clients[].sepa_creditor_id", client.sepa_creditor_id) %]</td> |
|
64 |
</tr> |
|
65 |
|
|
66 |
<tr> |
|
67 |
<td align="right">[%- LxERP.t8("Print templates") %]:</td> |
|
68 |
<td colspan="5">[%- L.select_tag("clients[].templates", SELF.templates, default=client.templates) %]</td> |
|
69 |
</tr> |
|
70 |
|
|
71 |
<tr> |
|
72 |
<th colspan="6">[%- LxERP.t8("User access") %]</th> |
|
73 |
</tr> |
|
74 |
|
|
75 |
<tr> |
|
76 |
<td valign="top">[%- LxERP.t8("Users with access to this client") %]:</td> |
|
77 |
|
|
78 |
<td valign="top" colspan="6" class="clearfix"> |
|
79 |
[% L.select_tag('clients[].users[]', SELF.users, id='users_multi_' _ loop.count, value_key='id', title_key='login', default=client.users, multiple=1) %] |
|
80 |
</td> |
|
81 |
</tr> |
|
82 |
|
|
83 |
<tr> |
|
84 |
<td valign="top">[%- LxERP.t8("Groups that are valid for this client for access rights") %]:</td> |
|
85 |
|
|
86 |
<td valign="top" colspan="6" class="clearfix"> |
|
87 |
[% L.select_tag('clients[].groups[]', SELF.groups, id='groups_multi_' _ loop.count, value_key='id', title_key='name', default=client.groups, multiple=1) %] |
|
88 |
</td> |
|
89 |
</tr> |
|
90 |
|
|
91 |
<tr> |
|
92 |
<th colspan="6">[%- LxERP.t8("Database settings") %]</th> |
|
93 |
</tr> |
|
94 |
|
|
95 |
<tr> |
|
96 |
<td align="right">[%- LxERP.t8("Database Host") %]:</td> |
|
97 |
<td>[%- L.input_tag("clients[].dbhost", client.dbhost) %]</td> |
|
98 |
|
|
99 |
<td align="right">[%- LxERP.t8("Port") %]:</td> |
|
100 |
<td>[%- L.input_tag("clients[].dbport", (client.dbport || 5432)) %]</td> |
|
101 |
|
|
102 |
<td align="right">[%- LxERP.t8("Database name") %]:</td> |
|
103 |
<td>[%- L.input_tag("clients[].dbname", client.dbname) %]</td> |
|
104 |
</tr> |
|
105 |
|
|
106 |
<tr> |
|
107 |
<td align="right">[%- LxERP.t8("User") %]:</td> |
|
108 |
<td>[%- L.input_tag("clients[].dbuser", client.dbuser) %]</td> |
|
109 |
|
|
110 |
<td align="right">[%- LxERP.t8("Password") %]:</td> |
|
111 |
<td>[%- L.input_tag("clients[].dbpasswd", client.dbpasswd) %]</td> |
|
112 |
</tr> |
|
113 |
|
|
114 |
</table> |
|
115 |
|
|
116 |
[% L.multiselect2side('users_multi_' _ loop.count, labelsx => LxERP.t8('All users'), labeldx => LxERP.t8('Users with access')) %] |
|
117 |
[% L.multiselect2side('groups_multi_' _ loop.count, labelsx => LxERP.t8('All groups'), labeldx => LxERP.t8('Groups valid for this client')) %] |
|
118 |
[%- END %] |
|
119 |
|
|
120 |
<p> |
|
121 |
[%- L.hidden_tag('action', 'list_users') %] |
|
122 |
[% L.submit_tag('dummy', LxERP.t8('Continue')) %] |
|
123 |
</p> |
|
124 |
</form> |
Auch abrufbar als: Unified diff
Datenbankupgradescript für Mandanten