- Neuer Button "Ohne Produktgruppen" für flache Übernahme ohne Sections/Zwischensummen - Mehraufwand-Produktgruppe über Modul-Einstellung konfigurierbar - Standard-Bankkonto wird automatisch aus Einstellung gesetzt - "Ihr Zeichen" (ref_client) vom Auftrag übernommen - Extrafelder Angebotsnummer/Auftragsnummer vom Auftrag kopiert - Verwaiste Zwischensummen werden nach Rechnungserstellung bereinigt - Zwei neue Modul-Einstellungen: Bankkonto und Mehraufwand-Sektion Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
318 lines
14 KiB
PHP
Executable file
318 lines
14 KiB
PHP
Executable file
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* Stundenzettel - Modulkonfiguration
|
|
*/
|
|
|
|
// Load Dolibarr environment
|
|
$res = 0;
|
|
// Von /custom/stundenzettel/admin/ zu /main.inc.php = 3 Ebenen hoch
|
|
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
|
if (!$res && file_exists("../../../../main.inc.php")) $res = @include "../../../../main.inc.php";
|
|
if (!$res) die("Include of main fails");
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
|
|
|
// Load translation files
|
|
$langs->loadLangs(array("admin", "stundenzettel@stundenzettel"));
|
|
|
|
// Access control
|
|
if (!$user->admin) {
|
|
accessforbidden();
|
|
}
|
|
|
|
$action = GETPOST('action', 'aZ09');
|
|
|
|
/*
|
|
* Actions
|
|
*/
|
|
|
|
if ($action == 'setTIME_INPUT_MODE') {
|
|
$value = GETPOST('value', 'alpha');
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_TIME_INPUT_MODE', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'setDEFAULT_FILTER') {
|
|
$value = GETPOST('filter_value', 'alpha');
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_DEFAULT_FILTER', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'setDEFAULT_DATE') {
|
|
$value = GETPOST('date_value', 'alpha');
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_DEFAULT_DATE', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'setINVOICE_HOURS_MODE') {
|
|
$value = GETPOST('hours_mode_value', 'alpha');
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_INVOICE_HOURS_MODE', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'setDEFAULT_SECTIONS') {
|
|
$sections = GETPOST('default_sections', 'array');
|
|
$value = implode(',', $sections);
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_DEFAULT_SECTIONS', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'setINVOICE_BANK_ACCOUNT') {
|
|
$value = GETPOST('bank_account_value', 'int');
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_INVOICE_BANK_ACCOUNT', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
if ($action == 'setINVOICE_MEHRAUFWAND_SECTION') {
|
|
$value = GETPOST('mehraufwand_section_value', 'alpha');
|
|
if (dolibarr_set_const($db, 'STUNDENZETTEL_INVOICE_MEHRAUFWAND_SECTION', $value, 'chaine', 0, '', $conf->entity) > 0) {
|
|
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($langs->trans("Error"), null, 'errors');
|
|
}
|
|
header("Location: ".$_SERVER["PHP_SELF"]);
|
|
exit;
|
|
}
|
|
|
|
/*
|
|
* View
|
|
*/
|
|
|
|
$page_name = "StundenzettelSetup";
|
|
llxHeader('', $langs->trans($page_name), '');
|
|
|
|
// Subheader
|
|
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
|
|
print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup');
|
|
|
|
// Configuration header
|
|
$head = array();
|
|
$h = 0;
|
|
$head[$h][0] = $_SERVER["PHP_SELF"];
|
|
$head[$h][1] = $langs->trans("Settings");
|
|
$head[$h][2] = 'settings';
|
|
$h++;
|
|
|
|
print dol_get_fiche_head($head, 'settings', $langs->trans("Stundenzettel"), -1, 'clock');
|
|
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th class="titlefield">'.$langs->trans("Parameter").'</th>';
|
|
print '<th style="width: 300px;">'.$langs->trans("Value").'</th>';
|
|
print '<th class="right" style="width: 100px;"></th>';
|
|
print '</tr>';
|
|
|
|
// Zeiteingabe-Modus
|
|
$currentMode = getDolGlobalString('STUNDENZETTEL_TIME_INPUT_MODE', 'dropdown');
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("TimeInputMode").'</td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setTIME_INPUT_MODE">';
|
|
print '<select name="value" class="flat minwidth200">';
|
|
print '<option value="dropdown"'.($currentMode == 'dropdown' ? ' selected' : '').'>'.$langs->trans("TimeInputDropdown").'</option>';
|
|
print '<option value="text"'.($currentMode == 'text' ? ' selected' : '').'>'.$langs->trans("TimeInputText").'</option>';
|
|
print '</select>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
// Standard-Filter
|
|
$currentFilter = getDolGlobalString('STUNDENZETTEL_DEFAULT_FILTER', 'open');
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("DefaultFilter").'<br><small class="opacitymedium">'.$langs->trans("DefaultFilterDesc").'</small></td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setDEFAULT_FILTER">';
|
|
print '<select name="filter_value" class="flat minwidth200">';
|
|
print '<option value="open"'.($currentFilter == 'open' ? ' selected' : '').'>'.$langs->trans("FilterOpen").'</option>';
|
|
print '<option value="done"'.($currentFilter == 'done' ? ' selected' : '').'>'.$langs->trans("FilterDone").'</option>';
|
|
print '<option value="all"'.($currentFilter == 'all' ? ' selected' : '').'>'.$langs->trans("FilterAll").'</option>';
|
|
print '</select>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
// Standard-Datum für Stundenzettel
|
|
$currentDate = getDolGlobalString('STUNDENZETTEL_DEFAULT_DATE', 'today');
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("DefaultDate").'<br><small class="opacitymedium">'.$langs->trans("DefaultDateDesc").'</small></td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setDEFAULT_DATE">';
|
|
print '<select name="date_value" class="flat minwidth200">';
|
|
print '<option value="today"'.($currentDate == 'today' ? ' selected' : '').'>'.$langs->trans("DateToday").'</option>';
|
|
print '<option value="last_open"'.($currentDate == 'last_open' ? ' selected' : '').'>'.$langs->trans("DateLastOpen").'</option>';
|
|
print '</select>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
// Stunden-Übernahme Modus
|
|
$currentHoursMode = getDolGlobalString('STUNDENZETTEL_INVOICE_HOURS_MODE', 'total');
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("InvoiceHoursMode").'<br><small class="opacitymedium">'.$langs->trans("SelectInvoiceHoursMode").'</small></td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setINVOICE_HOURS_MODE">';
|
|
print '<select name="hours_mode_value" class="flat minwidth200">';
|
|
print '<option value="total"'.($currentHoursMode == 'total' ? ' selected' : '').'>'.$langs->trans("InvoiceHoursModeTotal").'</option>';
|
|
print '<option value="perday"'.($currentHoursMode == 'perday' ? ' selected' : '').'>'.$langs->trans("InvoiceHoursModePerDay").'</option>';
|
|
print '</select>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
// Standard-Bereiche anzeigen
|
|
$currentSections = getDolGlobalString('STUNDENZETTEL_DEFAULT_SECTIONS', '');
|
|
$selectedSections = !empty($currentSections) ? explode(',', $currentSections) : array();
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("DefaultSections").'<br><small class="opacitymedium">'.$langs->trans("DefaultSectionsDesc").'</small></td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setDEFAULT_SECTIONS">';
|
|
print '<div style="display: flex; flex-direction: column; gap: 5px;">';
|
|
print '<label><input type="checkbox" name="default_sections[]" value="entfaellt"'.(in_array('entfaellt', $selectedSections) ? ' checked' : '').'> '.$langs->trans("Entfaellt").'</label>';
|
|
print '<label><input type="checkbox" name="default_sections[]" value="mehraufwand"'.(in_array('mehraufwand', $selectedSections) ? ' checked' : '').'> '.$langs->trans("Mehraufwand").'</label>';
|
|
print '<label><input type="checkbox" name="default_sections[]" value="ruecknahme"'.(in_array('ruecknahme', $selectedSections) ? ' checked' : '').'> '.$langs->trans("Ruecknahme").'</label>';
|
|
print '<label><input type="checkbox" name="default_sections[]" value="merkzettel"'.(in_array('merkzettel', $selectedSections) ? ' checked' : '').'> '.$langs->trans("NotesMemo").'</label>';
|
|
print '</div>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
print '</table>';
|
|
|
|
// Rechnungsübernahme-Einstellungen
|
|
print '<br>';
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th class="titlefield">'.$langs->trans("InvoiceTransferSettings").'</th>';
|
|
print '<th style="width: 300px;">'.$langs->trans("Value").'</th>';
|
|
print '<th class="right" style="width: 100px;"></th>';
|
|
print '</tr>';
|
|
|
|
// Bankkonto für Rechnungen
|
|
$currentBankAccount = getDolGlobalString('STUNDENZETTEL_INVOICE_BANK_ACCOUNT', '0');
|
|
$sqlBankAccounts = "SELECT rowid, ref, label FROM ".MAIN_DB_PREFIX."bank_account WHERE clos = 0 ORDER BY label";
|
|
$resqlBank = $db->query($sqlBankAccounts);
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("InvoiceBankAccount").'<br><small class="opacitymedium">'.$langs->trans("InvoiceBankAccountDesc").'</small></td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setINVOICE_BANK_ACCOUNT">';
|
|
print '<select name="bank_account_value" class="flat minwidth200">';
|
|
print '<option value="0">'.$langs->trans("None").'</option>';
|
|
if ($resqlBank) {
|
|
while ($objBank = $db->fetch_object($resqlBank)) {
|
|
$selected = ($currentBankAccount == $objBank->rowid) ? ' selected' : '';
|
|
print '<option value="'.$objBank->rowid.'"'.$selected.'>'.dol_escape_htmltag($objBank->label.' ('.$objBank->ref.')').'</option>';
|
|
}
|
|
}
|
|
print '</select>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
// Mehraufwand als Produktgruppe
|
|
$currentMehraufwandSection = getDolGlobalString('STUNDENZETTEL_INVOICE_MEHRAUFWAND_SECTION', '1');
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("InvoiceMehraufwandSection").'<br><small class="opacitymedium">'.$langs->trans("InvoiceMehraufwandSectionDesc").'</small></td>';
|
|
print '<td>';
|
|
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" style="display: inline;">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="setINVOICE_MEHRAUFWAND_SECTION">';
|
|
print '<select name="mehraufwand_section_value" class="flat minwidth200">';
|
|
print '<option value="1"'.($currentMehraufwandSection == '1' ? ' selected' : '').'>'.$langs->trans("Yes").'</option>';
|
|
print '<option value="0"'.($currentMehraufwandSection == '0' ? ' selected' : '').'>'.$langs->trans("No").'</option>';
|
|
print '</select>';
|
|
print '</td>';
|
|
print '<td class="right">';
|
|
print '<input type="submit" class="button small" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
|
|
print '</table>';
|
|
|
|
// PWA Mobile App Bereich
|
|
print '<br>';
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th class="titlefield">'.$langs->trans("PWAMobileApp").'</th>';
|
|
print '<th style="width: 300px;">'.$langs->trans("Value").'</th>';
|
|
print '<th class="right" style="width: 100px;"></th>';
|
|
print '</tr>';
|
|
|
|
$pwaUrl = dol_buildpath('/stundenzettel/pwa.php', 2);
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("PWADescription").'<br><small class="opacitymedium">'.$langs->trans("PWAInstallHint").'</small></td>';
|
|
print '<td>';
|
|
print '<a href="'.$pwaUrl.'" target="_blank" class="butAction small" style="display: inline-block; text-decoration: none;">';
|
|
print $langs->trans("PWALink").' ↗';
|
|
print '</a>';
|
|
print '</td>';
|
|
print '<td></td>';
|
|
print '</tr>';
|
|
|
|
print '</table>';
|
|
|
|
print dol_get_fiche_end();
|
|
|
|
llxFooter();
|
|
$db->close();
|