All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Neuer Button "Belege scannen" im Versand-Block der Mahnungs-Karte: - Action scan_belege durchlaeuft alle Files in DOL_DATA_ROOT/mahnung/<MAHN-Ref>/ - PDFs werden via pdftotext (CLI, mit Verfuegbarkeits-Check) extrahiert - txt/html werden direkt eingelesen (HTML mit strip_tags) - Pro Datei wird MahnungTrackingPattern::detectFromText() angewendet — matched gegen alle aktiven Patterns nach priority DESC - Treffer landen in $_SESSION als Vorschlag (file, provider, nr, url, label) UX: - Vorschlags-Banner mit gruener Linke ueber dem Beleg-Bereich - Pro Vorschlag: Datei-Icon, Pattern-Label, Sendungsnummer als <code>, externer Link zur Sendungsverfolgung, "Uebernehmen"-Button - "Uebernehmen" (action=apply_tracking) speichert tracking_nr + tracking_provider an der Mahnung und leert Session - "Verwerfen" (action=dismiss_tracking) entfernt nur Session-Eintrag Fallback: - Wenn pdftotext nicht im Container verfuegbar: Warnmeldung im UI, txt/html werden trotzdem verarbeitet. OCR fuer Bilder (PNG/JPG) bewusst noch nicht enthalten — separater Schritt mit Container-Anpassung (Tesseract) wenn gewuenscht. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
520 lines
22 KiB
PHP
520 lines
22 KiB
PHP
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/**
|
|
* \file mahnung/card.php
|
|
* \ingroup mahnung
|
|
* \brief Detailansicht eines einzelnen Mahnvorgangs.
|
|
*/
|
|
|
|
$res = 0;
|
|
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
|
|
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
|
|
}
|
|
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
|
|
$tmp2 = realpath(__FILE__);
|
|
$i = strlen($tmp) - 1;
|
|
$j = strlen($tmp2) - 1;
|
|
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
|
|
$i--;
|
|
$j--;
|
|
}
|
|
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
|
|
$res = @include substr($tmp, 0, ($i + 1))."/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.'/custom/mahnung/class/mahnung.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
|
|
|
|
global $langs, $user, $db;
|
|
$langs->loadLangs(array('mahnung@mahnung', 'companies', 'bills'));
|
|
|
|
if (!$user->hasRight('mahnung', 'read')) {
|
|
accessforbidden();
|
|
}
|
|
|
|
$id = GETPOSTINT('id');
|
|
$action = GETPOST('action', 'aZ09');
|
|
|
|
$mahnung = new Mahnung($db);
|
|
if ($mahnung->fetch($id) <= 0) {
|
|
dol_print_error($db, 'Mahnung nicht gefunden');
|
|
exit;
|
|
}
|
|
|
|
// Stornieren
|
|
if ($action === 'storno' && $user->hasRight('mahnung', 'delete')) {
|
|
$mahnung->status = Mahnung::STATUS_STORNIERT;
|
|
if ($mahnung->update($user) > 0) {
|
|
setEventMessages($langs->trans('MahnungStornieren').' OK', null, 'mesgs');
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
setEventMessages($mahnung->error, null, 'errors');
|
|
}
|
|
|
|
// Dokument neu generieren
|
|
if ($action === 'regenerate_pdf' && $user->hasRight('mahnung', 'write')) {
|
|
$selectedModel = GETPOST('model', 'alphanohtml');
|
|
$result = $mahnung->generateDocument($selectedModel, $langs);
|
|
if ($result > 0) {
|
|
setEventMessages('Dokument erstellt', null, 'mesgs');
|
|
} else {
|
|
setEventMessages('Dokument-Fehler: '.$mahnung->error, null, 'errors');
|
|
}
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
|
|
// Versand-Daten speichern (Datum, Weg, optional Tracking)
|
|
if ($action === 'set_versand' && $user->hasRight('mahnung', 'write')) {
|
|
$y = GETPOSTINT('versand_year');
|
|
$m = GETPOSTINT('versand_month');
|
|
$d = GETPOSTINT('versand_day');
|
|
$dateVersand = ($y && $m && $d) ? dol_mktime(12, 0, 0, $m, $d, $y) : dol_now();
|
|
$weg = GETPOST('versandweg', 'aZ09');
|
|
$trackNr = trim((string) GETPOST('tracking_nr', 'alphanohtml'));
|
|
$trackProv = GETPOST('tracking_provider', 'aZ09');
|
|
if (empty($trackProv) && $trackNr !== '') {
|
|
$trackProv = Mahnung::defaultProviderForWeg($weg);
|
|
}
|
|
if ($mahnung->setVersand($user, $dateVersand, $weg, $trackNr ?: null, $trackProv ?: null) > 0) {
|
|
setEventMessages($langs->trans('MahnungVersandGespeichert'), null, 'mesgs');
|
|
} else {
|
|
setEventMessages($mahnung->error ?: 'Fehler beim Speichern', null, 'errors');
|
|
}
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
|
|
// Sendungsnummer aus erkanntem Vorschlag uebernehmen
|
|
if ($action === 'apply_tracking' && $user->hasRight('mahnung', 'write')) {
|
|
$nr = trim((string) GETPOST('nr', 'alphanohtml'));
|
|
$prov = GETPOST('provider', 'aZ09');
|
|
if ($nr !== '' && $prov !== '') {
|
|
$mahnung->tracking_nr = $nr;
|
|
$mahnung->tracking_provider = $prov;
|
|
if ($mahnung->update($user) > 0) {
|
|
setEventMessages($langs->trans('MahnungTrackingUebernommen'), null, 'mesgs');
|
|
}
|
|
}
|
|
// Vorschlag aus Session entfernen
|
|
unset($_SESSION['mahnung_tracking_suggestions_'.((int) $mahnung->id)]);
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
|
|
// Vorschlaege verwerfen
|
|
if ($action === 'dismiss_tracking' && $user->hasRight('mahnung', 'write')) {
|
|
unset($_SESSION['mahnung_tracking_suggestions_'.((int) $mahnung->id)]);
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
|
|
// Belege scannen: pdftotext + Pattern-Matching
|
|
if ($action === 'scan_belege' && $user->hasRight('mahnung', 'write')) {
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungtrackingpattern.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
|
|
|
$mahnungSafeRef = dol_sanitizeFileName($mahnung->ref);
|
|
$scanDir = (!empty($conf->mahnung->multidir_output[$mahnung->entity])
|
|
? $conf->mahnung->multidir_output[$mahnung->entity]
|
|
: ($conf->mahnung->dir_output ?? (DOL_DATA_ROOT.'/mahnung')))
|
|
.'/'.$mahnungSafeRef;
|
|
|
|
$patternService = new MahnungTrackingPattern($db);
|
|
$suggestions = array();
|
|
$pdftotextAvailable = null; // einmalig pruefen
|
|
|
|
if (is_dir($scanDir)) {
|
|
foreach (dol_dir_list($scanDir, 'files', 0) as $file) {
|
|
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
|
$text = '';
|
|
if ($ext === 'txt' || $ext === 'html' || $ext === 'htm') {
|
|
$text = @file_get_contents($file['fullname']);
|
|
if ($ext === 'html' || $ext === 'htm') {
|
|
$text = strip_tags((string) $text);
|
|
}
|
|
} elseif ($ext === 'pdf') {
|
|
if ($pdftotextAvailable === null) {
|
|
$check = @shell_exec('command -v pdftotext 2>/dev/null');
|
|
$pdftotextAvailable = !empty(trim((string) $check));
|
|
}
|
|
if ($pdftotextAvailable) {
|
|
$cmd = 'pdftotext -layout '.escapeshellarg($file['fullname']).' - 2>/dev/null';
|
|
$text = (string) @shell_exec($cmd);
|
|
}
|
|
}
|
|
if ($text === '') {
|
|
continue;
|
|
}
|
|
$hit = $patternService->detectFromText($text);
|
|
if ($hit !== null) {
|
|
$suggestions[] = array(
|
|
'file' => $file['name'],
|
|
'provider' => $hit['provider'],
|
|
'nr' => $hit['nr'],
|
|
'url' => $hit['url'],
|
|
'label' => $hit['label'],
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
$_SESSION['mahnung_tracking_suggestions_'.((int) $mahnung->id)] = $suggestions;
|
|
if ($pdftotextAvailable === false) {
|
|
setEventMessages($langs->trans('MahnungPdftotextMissing'), null, 'warnings');
|
|
}
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
|
|
// Versand-Daten zuruecksetzen (z.B. Korrekturmoeglichkeit)
|
|
if ($action === 'clear_versand' && $user->hasRight('mahnung', 'write')) {
|
|
$mahnung->date_versand = null;
|
|
$mahnung->versandweg = null;
|
|
$mahnung->tracking_nr = null;
|
|
$mahnung->tracking_provider = null;
|
|
// Status nicht zurueckdrehen — nur Daten loeschen
|
|
if ($mahnung->update($user) > 0) {
|
|
setEventMessages($langs->trans('MahnungVersandGeleert'), null, 'mesgs');
|
|
}
|
|
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
|
|
exit;
|
|
}
|
|
|
|
llxHeader('', $langs->trans('MahnungRef').' '.$mahnung->ref);
|
|
|
|
print load_fiche_titre($langs->trans('MahnungRef').' '.$mahnung->ref, '', 'fa-envelope-open-text');
|
|
|
|
print '<table class="border centpercent">';
|
|
print '<tr><td class="titlefield">'.$langs->trans('MahnungRef').'</td><td>'.dol_escape_htmltag($mahnung->ref).'</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungStufe').'</td><td>'.((int) $mahnung->stufe).'</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungDatum').'</td><td>'.dol_print_date($mahnung->date_mahnung, 'day').'</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungFaelligkeitAlt').'</td><td>'.dol_print_date($mahnung->date_lim_reglement_alt, 'day').'</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungFaelligkeitNeu').'</td><td>'.dol_print_date($mahnung->date_lim_reglement_neu, 'day').'</td></tr>';
|
|
|
|
// Rechnung
|
|
$facture = new Facture($db);
|
|
if ($facture->fetch((int) $mahnung->fk_facture) > 0) {
|
|
print '<tr><td>'.$langs->trans('MahnungRechnung').'</td>';
|
|
print '<td><a href="'.DOL_URL_ROOT.'/compta/facture/card.php?id='.((int) $facture->id).'">'.dol_escape_htmltag($facture->ref).'</a></td></tr>';
|
|
}
|
|
|
|
// Kunde
|
|
$societe = new Societe($db);
|
|
if ($societe->fetch((int) $mahnung->fk_soc) > 0) {
|
|
print '<tr><td>'.$langs->trans('MahnungKunde').'</td>';
|
|
print '<td><a href="'.DOL_URL_ROOT.'/societe/card.php?socid='.((int) $societe->id).'">'.dol_escape_htmltag($societe->name).'</a> ('.dol_escape_htmltag((string) $mahnung->customertype).')</td></tr>';
|
|
}
|
|
|
|
print '<tr><td>'.$langs->trans('MahnungBetragOffen').'</td><td>'.price($mahnung->betrag_offen).'</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungGebuehr').'</td><td>'.price($mahnung->mahngebuehr).'</td></tr>';
|
|
if ((float) $mahnung->pauschale_b2b > 0) {
|
|
print '<tr><td>'.$langs->trans('MahnungPauschaleB2B').'</td><td>'.price($mahnung->pauschale_b2b).'</td></tr>';
|
|
}
|
|
print '<tr><td>'.$langs->trans('MahnungVerzugszinsen').'</td><td>'.price($mahnung->verzugszinsen).' (Basiszins '.number_format((float) $mahnung->basiszins_snapshot, 2, ',', '.').' %)</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungSumme').'</td><td><strong>'.price($mahnung->summe_mahnung).'</strong></td></tr>';
|
|
print '<tr><td>Status</td><td>'.dol_escape_htmltag($mahnung->getStatusLabel()).'</td></tr>';
|
|
print '</table>';
|
|
|
|
// --- Generierte Dokumente (wie bei Rechnungen) ---
|
|
print '<br>';
|
|
print load_fiche_titre($langs->trans('Documents'), '', 'fa-file');
|
|
|
|
// Dokumente im Rechnungsordner suchen die zur Mahnung gehoeren
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
|
$docDir = '';
|
|
if ($facture->id > 0) {
|
|
$docDir = !empty($conf->facture->multidir_output[$facture->entity])
|
|
? $conf->facture->multidir_output[$facture->entity]
|
|
: $conf->facture->dir_output;
|
|
$docDir .= '/'.dol_sanitizeFileName($facture->ref);
|
|
}
|
|
|
|
$mahnungRef = dol_sanitizeFileName($mahnung->ref);
|
|
$fileList = array();
|
|
if (!empty($docDir) && is_dir($docDir)) {
|
|
$allFiles = dol_dir_list($docDir, 'files', 0, preg_quote($mahnungRef, '/'));
|
|
foreach ($allFiles as $f) {
|
|
$fileList[] = $f;
|
|
}
|
|
}
|
|
|
|
if (!empty($fileList)) {
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th>'.$langs->trans('Document').'</th>';
|
|
print '<th class="right">'.$langs->trans('Size').'</th>';
|
|
print '<th class="center">'.$langs->trans('Date').'</th>';
|
|
print '<th class="center"></th>';
|
|
print '</tr>';
|
|
foreach ($fileList as $f) {
|
|
$fname = $f['name'];
|
|
$relativePath = dol_sanitizeFileName($facture->ref).'/'.$fname;
|
|
$dlUrl = DOL_URL_ROOT.'/document.php?modulepart=facture&file='.urlencode($relativePath);
|
|
$viewUrl = $dlUrl.'&attachment=0'; // Inline-Ansicht (keine Download-Erzwingung)
|
|
$ext = strtolower(pathinfo($fname, PATHINFO_EXTENSION));
|
|
$icon = ($ext === 'pdf') ? 'pdf' : (($ext === 'odt') ? 'ooffice' : 'generic');
|
|
$filesize = !empty($f['size']) ? $f['size'] : filesize($f['fullname']);
|
|
$filedate = !empty($f['date']) ? $f['date'] : filemtime($f['fullname']);
|
|
|
|
print '<tr class="oddeven">';
|
|
// Dateiname mit Icon
|
|
print '<td class="nowraponall">';
|
|
print '<a href="'.$dlUrl.'">';
|
|
print img_picto('', $icon, 'class="pictofixedwidth"');
|
|
print dol_escape_htmltag($fname);
|
|
print '</a>';
|
|
print '</td>';
|
|
// Groesse
|
|
print '<td class="right nowraponall">'.dol_print_size($filesize, 0, 0).'</td>';
|
|
// Datum
|
|
print '<td class="center nowraponall">'.dol_print_date($filedate, 'dayhour').'</td>';
|
|
// Aktionen: Vorschau + Download
|
|
print '<td class="right nowraponall">';
|
|
if ($ext === 'pdf') {
|
|
print '<a href="'.$viewUrl.'" target="_blank" title="'.dol_escape_htmltag($langs->trans('Preview')).'">'.img_picto($langs->trans('Preview'), 'search', 'class="pictofixedwidth"').'</a> ';
|
|
}
|
|
print '<a href="'.$dlUrl.'">'.img_picto($langs->trans('Download'), 'download', 'class="pictofixedwidth"').'</a>';
|
|
print '</td>';
|
|
print '</tr>';
|
|
}
|
|
print '</table>';
|
|
} else {
|
|
print '<div class="opacitymedium">'.$langs->trans('NoDocuments').'</div>';
|
|
}
|
|
|
|
// Aktionen
|
|
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
|
|
$form = new Form($db);
|
|
$formfile = new FormFile($db);
|
|
|
|
// --- Versand & Belege ---
|
|
print '<br>';
|
|
print load_fiche_titre($langs->trans('MahnungVersandBelege'), '', 'fa-truck');
|
|
|
|
// Versandwege (Dropdown-Optionen, Label kommt aus Lang-File MahnungVersandweg*)
|
|
$versandwege = array(
|
|
'post' => $langs->trans('MahnungVersandwegPost'),
|
|
'einschreiben' => $langs->trans('MahnungVersandwegEinschreiben'),
|
|
'dhl' => $langs->trans('MahnungVersandwegDhl'),
|
|
'dpd' => $langs->trans('MahnungVersandwegDpd'),
|
|
'hermes' => $langs->trans('MahnungVersandwegHermes'),
|
|
'ups' => $langs->trans('MahnungVersandwegUps'),
|
|
'fax' => $langs->trans('MahnungVersandwegFax'),
|
|
'email' => $langs->trans('MahnungVersandwegEmail'),
|
|
'persoenlich' => $langs->trans('MahnungVersandwegPersoenlich'),
|
|
'eigen' => $langs->trans('MahnungVersandwegEigen'),
|
|
);
|
|
|
|
$editVersand = ($action === 'edit_versand') || empty($mahnung->date_versand);
|
|
$canWrite = $user->hasRight('mahnung', 'write');
|
|
|
|
if (!empty($mahnung->date_versand) && $action !== 'edit_versand') {
|
|
// Anzeige der bereits erfassten Versanddaten
|
|
print '<table class="border centpercent">';
|
|
print '<tr><td class="titlefield">'.$langs->trans('MahnungVersanddatum').'</td><td>'.dol_print_date($mahnung->date_versand, 'day').'</td></tr>';
|
|
print '<tr><td>'.$langs->trans('MahnungVersandweg').'</td><td>'
|
|
.($mahnung->versandweg && isset($versandwege[$mahnung->versandweg]) ? dol_escape_htmltag($versandwege[$mahnung->versandweg]) : dol_escape_htmltag((string) $mahnung->versandweg))
|
|
.'</td></tr>';
|
|
if (!empty($mahnung->tracking_nr)) {
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungtrackingpattern.class.php';
|
|
$trackUrl = (new MahnungTrackingPattern($db))->urlFor((string) $mahnung->tracking_provider, (string) $mahnung->tracking_nr);
|
|
print '<tr><td>'.$langs->trans('MahnungTrackingNr').'</td><td>';
|
|
print '<code>'.dol_escape_htmltag($mahnung->tracking_nr).'</code>';
|
|
if (!empty($trackUrl)) {
|
|
print ' <a href="'.dol_escape_htmltag($trackUrl).'" target="_blank" rel="noopener" class="butAction" style="margin-left:8px;">';
|
|
print img_picto('', 'fa-external-link-alt', 'class="pictofixedwidth"');
|
|
print dol_escape_htmltag($langs->trans('MahnungSendungVerfolgen')).'</a>';
|
|
}
|
|
print '</td></tr>';
|
|
}
|
|
print '</table>';
|
|
if ($canWrite) {
|
|
print '<div style="margin-top:8px;">';
|
|
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=edit_versand">'.img_picto('', 'edit').' '.dol_escape_htmltag($langs->trans('MahnungVersandBearbeiten')).'</a> ';
|
|
print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=clear_versand&token='.newToken().'" onclick="return confirm(\''.dol_escape_js($langs->trans('MahnungVersandLeerenConfirm')).'\');">'.dol_escape_htmltag($langs->trans('MahnungVersandLeeren')).'</a>';
|
|
print '</div>';
|
|
}
|
|
} elseif ($canWrite) {
|
|
// Versand-Formular (Erfassung oder Bearbeitung)
|
|
$dateInit = !empty($mahnung->date_versand) ? $mahnung->date_versand : dol_now();
|
|
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="set_versand">';
|
|
print '<table class="border centpercent">';
|
|
|
|
// Versanddatum
|
|
print '<tr><td class="titlefield">'.$langs->trans('MahnungVersanddatum').'</td><td>';
|
|
print $form->selectDate($dateInit, 'versand_', 0, 0, 0, '', 1, 0);
|
|
print '</td></tr>';
|
|
|
|
// Versandweg
|
|
print '<tr><td>'.$langs->trans('MahnungVersandweg').'</td><td>';
|
|
print '<select name="versandweg" id="versandweg">';
|
|
foreach ($versandwege as $k => $label) {
|
|
print '<option value="'.dol_escape_htmltag($k).'"'.((string) $mahnung->versandweg === $k ? ' selected' : '').'>'.dol_escape_htmltag($label).'</option>';
|
|
}
|
|
print '</select>';
|
|
print '</td></tr>';
|
|
|
|
// Tracking-Nr
|
|
print '<tr><td>'.$langs->trans('MahnungTrackingNr').'</td><td>';
|
|
print '<input type="text" name="tracking_nr" value="'.dol_escape_htmltag((string) $mahnung->tracking_nr).'" size="30" placeholder="'.dol_escape_htmltag($langs->trans('MahnungTrackingNrHint')).'">';
|
|
print ' <span class="opacitymedium">('.dol_escape_htmltag($langs->trans('MahnungTrackingProviderAuto')).')</span>';
|
|
print '</td></tr>';
|
|
|
|
// Optional: Tracking-Provider override
|
|
print '<tr><td>'.$langs->trans('MahnungTrackingProvider').'</td><td>';
|
|
print '<select name="tracking_provider">';
|
|
print '<option value="">'.dol_escape_htmltag($langs->trans('MahnungTrackingProviderAuto')).'</option>';
|
|
foreach (array('dhl' => 'DHL', 'dpag' => 'Deutsche Post', 'dpd' => 'DPD', 'hermes' => 'Hermes', 'ups' => 'UPS') as $k => $label) {
|
|
print '<option value="'.dol_escape_htmltag($k).'"'.((string) $mahnung->tracking_provider === $k ? ' selected' : '').'>'.$label.'</option>';
|
|
}
|
|
print '</select>';
|
|
print '</td></tr>';
|
|
|
|
print '</table>';
|
|
print '<div style="margin-top:8px;">';
|
|
print '<button type="submit" class="button">'.dol_escape_htmltag($langs->trans('Save')).'</button> ';
|
|
if (!empty($mahnung->date_versand)) {
|
|
print '<a class="butActionRefused" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'">'.dol_escape_htmltag($langs->trans('Cancel')).'</a>';
|
|
}
|
|
print '</div>';
|
|
print '</form>';
|
|
}
|
|
|
|
// --- Sendebelege (Beleg-Upload via Dolibarr-Standard) ---
|
|
print '<br><h3>'.$langs->trans('MahnungSendebelege').'</h3>';
|
|
print '<div class="opacitymedium" style="margin-bottom:8px;">'.$langs->trans('MahnungSendebelegeHint').'</div>';
|
|
|
|
// Tracking-Vorschlaege aus Session-Flash (vom Scan) anzeigen
|
|
$suggKey = 'mahnung_tracking_suggestions_'.((int) $mahnung->id);
|
|
$suggestions = $_SESSION[$suggKey] ?? null;
|
|
if (is_array($suggestions) && !empty($suggestions)) {
|
|
print '<div class="info" style="padding:8px; margin-bottom:8px; border-left:3px solid #2a8;">';
|
|
print '<strong>'.$langs->trans('MahnungTrackingErkannt').'</strong> <span class="opacitymedium">('.count($suggestions).')</span>';
|
|
print '<table class="noborder" style="margin-top:6px;">';
|
|
foreach ($suggestions as $sg) {
|
|
print '<tr>';
|
|
print '<td class="nowrap">'.img_picto('', 'pdf', 'class="pictofixedwidth"').dol_escape_htmltag($sg['file']).'</td>';
|
|
print '<td>'.dol_escape_htmltag($sg['label']).'</td>';
|
|
print '<td><code><strong>'.dol_escape_htmltag($sg['nr']).'</strong></code></td>';
|
|
print '<td><a href="'.dol_escape_htmltag($sg['url']).'" target="_blank" rel="noopener" class="opacitymedium">'.img_picto('', 'fa-external-link-alt').'</a></td>';
|
|
print '<td>';
|
|
if ($canWrite) {
|
|
$applyUrl = $_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=apply_tracking'
|
|
.'&nr='.urlencode((string) $sg['nr'])
|
|
.'&provider='.urlencode((string) $sg['provider'])
|
|
.'&token='.newToken();
|
|
print '<a class="button smallpaddingimp" href="'.$applyUrl.'">'.dol_escape_htmltag($langs->trans('MahnungTrackingUebernehmen')).'</a>';
|
|
}
|
|
print '</td>';
|
|
print '</tr>';
|
|
}
|
|
print '</table>';
|
|
if ($canWrite) {
|
|
print '<div style="margin-top:6px;"><a class="opacitymedium" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=dismiss_tracking&token='.newToken().'">'.dol_escape_htmltag($langs->trans('MahnungTrackingVerwerfen')).'</a></div>';
|
|
}
|
|
print '</div>';
|
|
}
|
|
|
|
// Scan-Button (Belege durchsuchen)
|
|
if ($canWrite) {
|
|
print '<div style="margin-bottom:8px;">';
|
|
print '<a class="button smallpaddingimp" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=scan_belege&token='.newToken().'">';
|
|
print img_picto('', 'fa-search', 'class="pictofixedwidth"').dol_escape_htmltag($langs->trans('MahnungBelegeScannen'));
|
|
print '</a> ';
|
|
print '<span class="opacitymedium small">'.$langs->trans('MahnungBelegeScannenHint').'</span>';
|
|
print '</div>';
|
|
}
|
|
|
|
$mahnungSafeRef = dol_sanitizeFileName($mahnung->ref);
|
|
$mahnungFileDir = (!empty($conf->mahnung->multidir_output[$mahnung->entity])
|
|
? $conf->mahnung->multidir_output[$mahnung->entity]
|
|
: $conf->mahnung->dir_output ?? (DOL_DATA_ROOT.'/mahnung'))
|
|
.'/'.$mahnungSafeRef;
|
|
// Verzeichnis bei Bedarf anlegen, damit FormFile->showdocuments() das Upload-Formular zeigt
|
|
if (!is_dir($mahnungFileDir)) {
|
|
dol_mkdir($mahnungFileDir);
|
|
}
|
|
|
|
$urlSelf = $_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id);
|
|
$formfile->showdocuments(
|
|
'mahnung', // $modulepart
|
|
$mahnungSafeRef, // $modulesubdir
|
|
$mahnungFileDir, // $filedir
|
|
$urlSelf, // $urlsource
|
|
0, // $genallowed (kein PDF-Gen-Button hier)
|
|
(int) $canWrite, // $delallowed
|
|
'', // $modelselected
|
|
1, // $allowgenifempty
|
|
0, // $forcenomultilang
|
|
0, // $iconPDF
|
|
0, // $notused
|
|
0, // $noform
|
|
'', // $param
|
|
'', // $title
|
|
'', // $buttonlabel
|
|
'', // $codelang
|
|
'', // $morepicto
|
|
$mahnung // $object
|
|
);
|
|
|
|
if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
|
|
if ($action === 'confirm_storno') {
|
|
print $form->formconfirm(
|
|
$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id),
|
|
$langs->trans('MahnungStornieren'),
|
|
$langs->trans('MahnungStornieren').' — '.dol_escape_htmltag($mahnung->ref).'?',
|
|
'storno',
|
|
'',
|
|
0,
|
|
1
|
|
);
|
|
}
|
|
}
|
|
|
|
print '<br><div class="tabsAction">';
|
|
if ($user->hasRight('mahnung', 'write')) {
|
|
// Modellauswahl
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
|
|
$modellist = ModelePDFMahnung::liste_modeles($db);
|
|
$defaultModel = getDolGlobalString('MAHNUNG_ADDON_PDF', 'standard_mahnung');
|
|
|
|
if (is_array($modellist) && count($modellist) > 1) {
|
|
print '<select name="model" id="selectmodel" style="margin-right: 5px;">';
|
|
foreach ($modellist as $k => $v) {
|
|
print '<option value="'.dol_escape_htmltag($k).'"'.($k === $defaultModel ? ' selected' : '').'>'.dol_escape_htmltag($v).'</option>';
|
|
}
|
|
print '</select>';
|
|
}
|
|
|
|
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=regenerate_pdf&token='.newToken().'" onclick="if(document.getElementById(\'selectmodel\')){this.href+=\'&model=\'+document.getElementById(\'selectmodel\').value;}">';
|
|
print $langs->trans('MahnungGenerate');
|
|
print '</a> ';
|
|
}
|
|
if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
|
|
print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=confirm_storno">';
|
|
print $langs->trans('MahnungStornieren');
|
|
print '</a>';
|
|
}
|
|
print '</div>';
|
|
|
|
llxFooter();
|
|
$db->close();
|