i18n: Alle Texte über $langs->trans() — ~100 neue Sprachschlüssel de_DE + en_US [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s

Umlaute in allen lang-Dateien korrigiert. Alle hardcodierten deutschen Strings
in 22 PHP-Dateien durch $langs->trans('Key') ersetzt. Neue Schlüssel für
Cron-Meldungen, Dokument-Aktionen, Bonität, Vorschlag-Status, Template-Vars u.a.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-05-13 16:25:50 +02:00
parent 80d92042bc
commit 10cf41a687
24 changed files with 706 additions and 360 deletions

View file

@ -10,7 +10,7 @@
/**
* \file mahnung/admin/setup.php
* \ingroup mahnung
* \brief Setup: Mahnstufen, Basiszins, B2C/B2B-Aufschlaege, Pauschale, Ntfy-Topic.
* \brief Setup: Mahnstufen, Basiszins, B2C/B2B-Aufschläge, Pauschale, Ntfy-Topic.
*/
$res = 0;
@ -55,7 +55,7 @@ if (!$user->admin && !$user->hasRight('mahnung', 'setup')) {
accessforbidden();
}
// Schema-Migration bei jedem Setup-Aufruf (idempotent — fehlende Spalten ergaenzen)
// Schema-Migration bei jedem Setup-Aufruf (idempotent — fehlende Spalten ergänzen)
(new modMahnung($db))->migrateVersandFelder();
// Tracking-Pattern-Tabelle anlegen (falls noch nicht da) + Default-Patterns seeden
@ -196,7 +196,7 @@ function loadStufeById($db, $id, $entity)
}
// ---------------------------------------------------------------
// ODT-Upload / Template-Loeschen (actions_setmoduleoptions.inc.php)
// ODT-Upload / Template-Löschen (actions_setmoduleoptions.inc.php)
// Muss vor llxHeader() stehen, da es header()-Redirects macht.
// ---------------------------------------------------------------
include_once DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
@ -294,7 +294,7 @@ print '<tr class="liste_titre"><th colspan="2">'.$langs->trans('MahnungStufe').'
foreach ($stufen as $s) {
$prefix = 'stufe_'.$s->stufe.'_';
print '<tr class="liste_titre_filter"><th colspan="2">'.dol_escape_htmltag('Stufe '.$s->stufe).' ';
print '<tr class="liste_titre_filter"><th colspan="2">'.dol_escape_htmltag($langs->trans('MahnungStufe').' '.$s->stufe).' ';
print '<input type="checkbox" name="'.$prefix.'active" value="1"'.($s->active ? ' checked' : '').'> '.$langs->trans('Active');
print '</th></tr>';
@ -346,7 +346,7 @@ print '</form>';
// --- Block: Dokumentenmodelle -----------------------------------------------------------
print '<br><br>';
print load_fiche_titre($langs->trans('MahnungDokumentModelle'), '<a href="templatevars.php" class="button smallpaddingimp">Verfuegbare Template-Variablen</a>', '');
print load_fiche_titre($langs->trans('MahnungDokumentModelle'), '<a href="templatevars.php" class="button smallpaddingimp">'.$langs->trans('MahnungSetupTemplateVars').'</a>', '');
// Dokumentenmodelle auflisten
$def = array();
@ -359,7 +359,7 @@ if ($resql) {
$db->free($resql);
}
// Verfuegbare Modelle scannen (aus den doc/-Klassen)
// Verfügbare Modelle scannen (aus den doc/-Klassen)
$dirmodels = array(
DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/doc/',
);

View file

@ -8,7 +8,7 @@
/**
* \file mahnung/admin/templatevars.php
* \ingroup mahnung
* \brief Uebersicht aller verfuegbaren Variablen fuer ODT-Templates.
* \brief Übersicht aller verfügbaren Variablen r ODT-Templates.
*/
$res = 0;
@ -43,37 +43,37 @@ if (!$user->admin && !$user->hasRight('mahnung', 'setup')) {
accessforbidden();
}
llxHeader('', 'Mahnung — Template-Variablen');
llxHeader('', $langs->trans('MahnungTemplateVarsTitle'));
print load_fiche_titre('Verfuegbare Variablen fuer ODT-Templates', '<a href="setup.php">Zurueck zum Setup</a>', 'fa-envelope-open-text');
print load_fiche_titre($langs->trans('MahnungTemplateVarsHeader'), '<a href="setup.php">'.$langs->trans('MahnungTemplateVarsBackToSetup').'</a>', 'fa-envelope-open-text');
print '<div class="opacitymedium" style="margin-bottom: 15px;">';
print 'Diese Variablen koennen in ODT-Templates mit geschweiften Klammern verwendet werden, z.B. <code>{mahnung_ref}</code>.<br>';
print 'Stufen-spezifische Templates: <code>mahnung_stufe1.odt</code>, <code>mahnung_stufe2.odt</code>, <code>mahnung_stufe3.odt</code> — Fallback: beliebiges <code>.odt</code> im Template-Verzeichnis.';
print $langs->trans('MahnungTemplateVarsIntro').'<br>';
print $langs->trans('MahnungTemplateVarsIntro2');
print '</div>';
// Mahnung-Variablen
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="3">Mahnung</th></tr>';
print '<tr class="liste_titre"><th>Variable</th><th>Beschreibung</th><th>Beispiel</th></tr>';
print '<tr class="liste_titre"><th colspan="3">'.$langs->trans('MahnungTemplateVarsGrpMahnung').'</th></tr>';
print '<tr class="liste_titre"><th>'.$langs->trans('MahnungTemplateVarsColVariable').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeschreibung').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeispiel').'</th></tr>';
$mahnungVars = array(
array('{mahnung_ref}', 'Mahnung-Referenznummer', 'MAHN2026-0001'),
array('{mahnung_stufe}', 'Mahnstufe (Nummer)', '1'),
array('{mahnung_stufe_label}', 'Bezeichnung der Mahnstufe', 'Zahlungserinnerung'),
array('{mahnung_date}', 'Datum der Mahnung', '10.05.2026'),
array('{mahnung_date_lim_alt}', 'Urspruengliches Faelligkeitsdatum der Rechnung', '25.04.2026'),
array('{mahnung_date_lim_neu}', 'Neue Zahlungsfrist', '24.05.2026'),
array('{mahnung_betrag_offen}', 'Offener Rechnungsbetrag', '131,34'),
array('{mahnung_mahngebuehr}', 'Mahngebuehr dieser Stufe', '5,00'),
array('{mahnung_pauschale_b2b}', 'B2B-Pauschale nach BGB §288 Abs. 5', '40,00'),
array('{mahnung_verzugszinsen}', 'Berechnete Verzugszinsen', '1,23'),
array('{mahnung_summe}', 'Gesamtforderung (offen + Gebuehren + Zinsen)', '177,57'),
array('{mahnung_basiszins}', 'BGB-Basiszinssatz (Snapshot bei Erstellung)', '1,27'),
array('{mahnung_zinssatz}', 'Effektiver Zinssatz (Basis + Aufschlag)', '6,27'),
array('{mahnung_kundentyp}', 'Kundentyp', 'B2C oder B2B'),
array('{mahnung_versandart}', 'Versandart', 'pdf, mail, druck, none'),
array('{mahnung_pdf_intro}', 'Einleitungstext der Mahnstufe (aus Setup oder Default)', 'unsere unten aufgefuehrte Rechnung...'),
array('{mahnung_ref}', $langs->trans('MahnungTemplateVarMahnungRef'), 'MAHN2026-0001'),
array('{mahnung_stufe}', $langs->trans('MahnungTemplateVarMahnungStufe'), '1'),
array('{mahnung_stufe_label}', $langs->trans('MahnungTemplateVarMahnungStufeLabel'), 'Zahlungserinnerung'),
array('{mahnung_date}', $langs->trans('MahnungTemplateVarMahnungDate'), '10.05.2026'),
array('{mahnung_date_lim_alt}', $langs->trans('MahnungTemplateVarMahnungDateLimAlt'), '25.04.2026'),
array('{mahnung_date_lim_neu}', $langs->trans('MahnungTemplateVarMahnungDateLimNeu'), '24.05.2026'),
array('{mahnung_betrag_offen}', $langs->trans('MahnungTemplateVarMahnungBetragOffen'), '131,34'),
array('{mahnung_mahngebuehr}', $langs->trans('MahnungTemplateVarMahnungMahngebuehr'), '5,00'),
array('{mahnung_pauschale_b2b}', $langs->trans('MahnungTemplateVarMahnungPauschale'), '40,00'),
array('{mahnung_verzugszinsen}', $langs->trans('MahnungTemplateVarMahnungVerzugszinsen'), '1,23'),
array('{mahnung_summe}', $langs->trans('MahnungTemplateVarMahnungSumme'), '177,57'),
array('{mahnung_basiszins}', $langs->trans('MahnungTemplateVarMahnungBasiszins'), '1,27'),
array('{mahnung_zinssatz}', $langs->trans('MahnungTemplateVarMahnungZinssatz'), '6,27'),
array('{mahnung_kundentyp}', $langs->trans('MahnungTemplateVarMahnungKundentyp'), $langs->trans('MahnungTemplateVarMahnungKundentypBsp')),
array('{mahnung_versandart}', $langs->trans('MahnungTemplateVarMahnungVersandart'), $langs->trans('MahnungTemplateVarMahnungVersandartBsp')),
array('{mahnung_pdf_intro}', $langs->trans('MahnungTemplateVarMahnungPdfIntro'), $langs->trans('MahnungTemplateVarMahnungPdfIntroBsp')),
);
foreach ($mahnungVars as $v) {
@ -88,17 +88,17 @@ print '</table>';
// Rechnungs-Variablen
print '<br>';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="3">Verknuepfte Rechnung</th></tr>';
print '<tr class="liste_titre"><th>Variable</th><th>Beschreibung</th><th>Beispiel</th></tr>';
print '<tr class="liste_titre"><th colspan="3">'.$langs->trans('MahnungTemplateVarsGrpRechnung').'</th></tr>';
print '<tr class="liste_titre"><th>'.$langs->trans('MahnungTemplateVarsColVariable').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeschreibung').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeispiel').'</th></tr>';
$factureVars = array(
array('{facture_ref}', 'Rechnungsnummer', 'IN2604-0036'),
array('{facture_date}', 'Rechnungsdatum', '01.04.2026'),
array('{facture_date_lim}', 'Original-Faelligkeitsdatum', '25.04.2026'),
array('{facture_total_ht}', 'Nettobetrag der Rechnung', '110,37'),
array('{facture_total_ttc}', 'Bruttobetrag der Rechnung', '131,34'),
array('{facture_total_tva}', 'MwSt-Betrag', '20,97'),
array('{facture_already_paid}', 'Bereits gezahlter Betrag', '0,00'),
array('{facture_ref}', $langs->trans('MahnungTemplateVarFactureRef'), 'IN2604-0036'),
array('{facture_date}', $langs->trans('MahnungTemplateVarFactureDate'), '01.04.2026'),
array('{facture_date_lim}', $langs->trans('MahnungTemplateVarFactureDateLim'), '25.04.2026'),
array('{facture_total_ht}', $langs->trans('MahnungTemplateVarFactureTotalHt'), '110,37'),
array('{facture_total_ttc}', $langs->trans('MahnungTemplateVarFactureTotalTtc'), '131,34'),
array('{facture_total_tva}', $langs->trans('MahnungTemplateVarFactureTotalTva'), '20,97'),
array('{facture_already_paid}', $langs->trans('MahnungTemplateVarFactureAlreadyPaid'), '0,00'),
);
foreach ($factureVars as $v) {
@ -113,23 +113,23 @@ print '</table>';
// Firmen-Variablen (Absender)
print '<br>';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="3">Eigene Firma (Absender)</th></tr>';
print '<tr class="liste_titre"><th>Variable</th><th>Beschreibung</th><th>Beispiel</th></tr>';
print '<tr class="liste_titre"><th colspan="3">'.$langs->trans('MahnungTemplateVarsGrpFirma').'</th></tr>';
print '<tr class="liste_titre"><th>'.$langs->trans('MahnungTemplateVarsColVariable').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeschreibung').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeispiel').'</th></tr>';
$mysocVars = array(
array('{mycompany_name}', 'Firmenname', 'Alles Watt Laeuft'),
array('{mycompany_address}', 'Strasse', 'Musterstrasse 1'),
array('{mycompany_zip}', 'PLZ', '24536'),
array('{mycompany_town}', 'Ort', 'Neumuenster'),
array('{mycompany_country}', 'Land', 'Deutschland'),
array('{mycompany_phone}', 'Telefonnummer', '04321 1234567'),
array('{mycompany_fax}', 'Faxnummer', ''),
array('{mycompany_email}', 'E-Mail-Adresse', 'info@example.de'),
array('{mycompany_web}', 'Webseite', 'www.example.de'),
array('{mycompany_idprof1}', 'Handelsregisternummer', ''),
array('{mycompany_idprof2}', 'SIRET/Steuernummer', ''),
array('{mycompany_capital}', 'Stammkapital', ''),
array('{mycompany_logo}', 'Firmenlogo (wird als Bild eingefuegt)', '(Bilddatei)'),
array('{mycompany_name}', $langs->trans('MahnungTemplateVarFirmaName'), 'Alles Watt Läuft'),
array('{mycompany_address}', $langs->trans('MahnungTemplateVarFirmaStrasse'), 'Musterstrasse 1'),
array('{mycompany_zip}', $langs->trans('MahnungTemplateVarFirmaPlz'), '24536'),
array('{mycompany_town}', $langs->trans('MahnungTemplateVarFirmaOrt'), 'Neumünster'),
array('{mycompany_country}', $langs->trans('MahnungTemplateVarFirmaLand'), 'Deutschland'),
array('{mycompany_phone}', $langs->trans('MahnungTemplateVarFirmaTelefon'), '04321 1234567'),
array('{mycompany_fax}', $langs->trans('MahnungTemplateVarFirmaFax'), ''),
array('{mycompany_email}', $langs->trans('MahnungTemplateVarFirmaEmail'), 'info@example.de'),
array('{mycompany_web}', $langs->trans('MahnungTemplateVarFirmaWeb'), 'www.example.de'),
array('{mycompany_idprof1}', $langs->trans('MahnungTemplateVarFirmaHr'), ''),
array('{mycompany_idprof2}', $langs->trans('MahnungTemplateVarFirmaSteuernr'), ''),
array('{mycompany_capital}', $langs->trans('MahnungTemplateVarFirmaKapital'), ''),
array('{mycompany_logo}', $langs->trans('MahnungTemplateVarFirmaLogo'), $langs->trans('MahnungTemplateVarFirmaLogoBsp')),
);
foreach ($mysocVars as $v) {
@ -144,22 +144,22 @@ print '</table>';
// Kunden-Variablen
print '<br>';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="3">Kunde (Empfaenger)</th></tr>';
print '<tr class="liste_titre"><th>Variable</th><th>Beschreibung</th><th>Beispiel</th></tr>';
print '<tr class="liste_titre"><th colspan="3">'.$langs->trans('MahnungTemplateVarsGrpKunde').'</th></tr>';
print '<tr class="liste_titre"><th>'.$langs->trans('MahnungTemplateVarsColVariable').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeschreibung').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeispiel').'</th></tr>';
$companyVars = array(
array('{company_name}', 'Kundenname', 'Brigitte Ladewig'),
array('{company_alias}', 'Kurzname/Alias', ''),
array('{company_address}', 'Strasse', 'Beispielweg 5'),
array('{company_zip}', 'PLZ', '24534'),
array('{company_town}', 'Ort', 'Neumuenster'),
array('{company_country}', 'Land', 'Deutschland'),
array('{company_phone}', 'Telefon', '04321 9876543'),
array('{company_email}', 'E-Mail', 'b.ladewig@example.de'),
array('{company_idprof1}', 'Handelsregister', ''),
array('{company_idprof2}', 'Steuernummer', ''),
array('{company_vatnumber}', 'USt-IdNr.', 'DE123456789'),
array('{company_note_public}', 'Oeffentliche Notiz des Kunden', ''),
array('{company_name}', $langs->trans('MahnungTemplateVarKundeName'), 'Brigitte Ladewig'),
array('{company_alias}', $langs->trans('MahnungTemplateVarKundeAlias'), ''),
array('{company_address}', $langs->trans('MahnungTemplateVarKundeStrasse'), 'Beispielweg 5'),
array('{company_zip}', $langs->trans('MahnungTemplateVarKundePlz'), '24534'),
array('{company_town}', $langs->trans('MahnungTemplateVarKundeOrt'), 'Neumünster'),
array('{company_country}', $langs->trans('MahnungTemplateVarKundeLand'), 'Deutschland'),
array('{company_phone}', $langs->trans('MahnungTemplateVarKundeTelefon'), '04321 9876543'),
array('{company_email}', $langs->trans('MahnungTemplateVarKundeEmail'), 'b.ladewig@example.de'),
array('{company_idprof1}', $langs->trans('MahnungTemplateVarKundeHr'), ''),
array('{company_idprof2}', $langs->trans('MahnungTemplateVarKundeSteuernr'), ''),
array('{company_vatnumber}', $langs->trans('MahnungTemplateVarKundeUstIdNr'), 'DE123456789'),
array('{company_note_public}', $langs->trans('MahnungTemplateVarKundeNotiz'), ''),
);
foreach ($companyVars as $v) {
@ -174,13 +174,13 @@ print '</table>';
// Bank-Variablen
print '<br>';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="3">Bankverbindung</th></tr>';
print '<tr class="liste_titre"><th>Variable</th><th>Beschreibung</th><th>Beispiel</th></tr>';
print '<tr class="liste_titre"><th colspan="3">'.$langs->trans('MahnungTemplateVarsGrpBank').'</th></tr>';
print '<tr class="liste_titre"><th>'.$langs->trans('MahnungTemplateVarsColVariable').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeschreibung').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeispiel').'</th></tr>';
$bankVars = array(
array('{mahnung_bank_label}', 'Name der Bank', 'Sparkasse Suedholstein'),
array('{mahnung_bank_iban}', 'IBAN', 'DE89 3704 0044 0532 0130 00'),
array('{mahnung_bank_bic}', 'BIC/SWIFT', 'COBADEFFXXX'),
array('{mahnung_bank_label}', $langs->trans('MahnungTemplateVarBankName'), 'Sparkasse Südholstein'),
array('{mahnung_bank_iban}', $langs->trans('MahnungTemplateVarBankIban'), 'DE89 3704 0044 0532 0130 00'),
array('{mahnung_bank_bic}', $langs->trans('MahnungTemplateVarBankBic'), 'COBADEFFXXX'),
);
foreach ($bankVars as $v) {
@ -195,16 +195,16 @@ print '</table>';
// Dolibarr-Standard-Variablen
print '<br>';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="3">Dolibarr-Standard (Auswahl)</th></tr>';
print '<tr class="liste_titre"><th>Variable</th><th>Beschreibung</th><th>Beispiel</th></tr>';
print '<tr class="liste_titre"><th colspan="3">'.$langs->trans('MahnungTemplateVarsGrpStandard').'</th></tr>';
print '<tr class="liste_titre"><th>'.$langs->trans('MahnungTemplateVarsColVariable').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeschreibung').'</th><th>'.$langs->trans('MahnungTemplateVarsColBeispiel').'</th></tr>';
$stdVars = array(
array('{__FROM_NAME__}', 'Absender-Name', 'Alles Watt Laeuft'),
array('{__FROM_EMAIL__}', 'Absender-E-Mail', 'info@example.de'),
array('{__DATE__}', 'Aktuelles Datum', '10.05.2026'),
array('{myuser_lastname}', 'Nachname des eingeloggten Users', 'Wisch'),
array('{myuser_firstname}', 'Vorname des eingeloggten Users', 'Eduard'),
array('{myuser_email}', 'E-Mail des eingeloggten Users', 'data@example.de'),
array('{__FROM_NAME__}', $langs->trans('MahnungTemplateVarAbsenderName'), 'Alles Watt Läuft'),
array('{__FROM_EMAIL__}', $langs->trans('MahnungTemplateVarAbsenderEmail'), 'info@example.de'),
array('{__DATE__}', $langs->trans('MahnungTemplateVarDatum'), '10.05.2026'),
array('{myuser_lastname}', $langs->trans('MahnungTemplateVarUserNachname'), 'Wisch'),
array('{myuser_firstname}', $langs->trans('MahnungTemplateVarUserVorname'), 'Eduard'),
array('{myuser_email}', $langs->trans('MahnungTemplateVarUserEmail'), 'data@example.de'),
);
foreach ($stdVars as $v) {

View file

@ -10,7 +10,7 @@
/**
* \file mahnung/admin/tracking_patterns.php
* \ingroup mahnung
* \brief Konfigurations-Seite fuer Tracking-Pattern (Regex + URL-Template).
* \brief Konfigurations-Seite für Tracking-Pattern (Regex + URL-Template).
* Live-Vorschau via /custom/mahnung/ajax/regex_preview.php.
*/
@ -56,7 +56,7 @@ if (($action === 'save_new' || $action === 'save_edit') && $user->hasRight('mahn
$p = new MahnungTrackingPattern($db);
if ($action === 'save_edit' && $rowid > 0) {
if ($p->fetch($rowid) <= 0) {
setEventMessages('Pattern nicht gefunden', null, 'errors');
setEventMessages($langs->trans('MahnungPatternNichtGefunden'), null, 'errors');
header('Location: '.$_SERVER['PHP_SELF']);
exit;
}
@ -97,12 +97,12 @@ if (($action === 'save_new' || $action === 'save_edit') && $user->hasRight('mahn
header('Location: '.$_SERVER['PHP_SELF']);
exit;
} else {
setEventMessages($p->error ?: 'Speichern fehlgeschlagen', null, 'errors');
setEventMessages($p->error ?: $langs->trans('MahnungSpeichernFehlgeschlagen'), null, 'errors');
}
}
}
// POST/GET: Loeschen
// POST/GET: Löschen
if ($action === 'delete' && $rowid > 0 && $user->hasRight('mahnung', 'setup')) {
$p = new MahnungTrackingPattern($db);
if ($p->fetch($rowid) > 0 && $p->delete() > 0) {
@ -309,7 +309,7 @@ print <<<EOT
el.addEventListener('input', update);
el.addEventListener('change', update);
});
// Initial-Preview falls Sample schon befuellt
// Initial-Preview falls Sample schon befüllt
update();
}
})();

View file

@ -71,12 +71,12 @@ function respond($success, $message, $extra = array())
// 1) CSRF
$postedToken = GETPOST('token', 'alphanohtml');
if (empty($postedToken) || empty($_SESSION['newtoken']) || $postedToken !== $_SESSION['newtoken']) {
respond(false, 'Token-Verifikation fehlgeschlagen (CSRF).', array('code' => 'csrf'));
respond(false, $langs->trans('MahnungCsrfFehler'), array('code' => 'csrf'));
}
// 2) Permission
if (!$user->hasRight('mahnung', 'write')) {
respond(false, $langs->transnoentities('NotEnoughPermissions') ?: 'Nicht berechtigt.', array('code' => 'forbidden'));
respond(false, $langs->transnoentities('NotEnoughPermissions') ?: $langs->trans('MahnungNichtBerechtigt'), array('code' => 'forbidden'));
}
// 3) Input
@ -92,7 +92,7 @@ $factureIds = array_filter($factureIds, function ($v) {
return $v > 0;
});
if (empty($factureIds)) {
respond(false, 'Keine Rechnungen ausgewaehlt.', array('code' => 'noinput'));
respond(false, $langs->trans('MahnungKeineRechnungenAusgewaehlt'), array('code' => 'noinput'));
}
$forceStufe = GETPOSTINT('stufe');
@ -116,7 +116,7 @@ foreach ($factureIds as $fid) {
}
}
if ($row === null) {
// Keine offene Mahnungs-Empfehlung — z.B. weil Wartefrist noch laeuft
// Keine offene Mahnungs-Empfehlung — z.B. weil Wartefrist noch läuft
$skipped++;
continue;
}
@ -124,7 +124,7 @@ foreach ($factureIds as $fid) {
$stufeNr = $forceStufe ?: (int) $row['vorgeschlagene_stufe'];
$stufe = $service->getStufe($stufeNr);
if ($stufe === null) {
$failed[] = 'Rechnung #'.$fid.': Stufe '.$stufeNr.' nicht konfiguriert';
$failed[] = $langs->trans('MahnungStufeNichtKonfiguriert', $fid, $stufeNr);
continue;
}
@ -140,7 +140,7 @@ foreach ($factureIds as $fid) {
$mahnung->basiszins_snapshot = $basiszins;
$mahnung->versandart = $stufe->versandart_default ?: Mahnung::VERSAND_PDF;
// Gebuehren + Pauschale
// Gebühren + Pauschale
$mahnung->mahngebuehr = $stufe->getMahngebuehr($mahnung->customertype);
// §288 Abs. 5 Pauschale: nur einmal pro Rechnung B2B (in Stufe mit pauschale_b2b_einmalig=1)
@ -179,18 +179,18 @@ foreach ($factureIds as $fid) {
$created++;
}
$msg = $created.' Mahnung(en) erstellt';
$msg = $langs->trans('MahnungMahnungErstellt', $created);
if ($skipped > 0) {
$msg .= ', '.$skipped.' uebersprungen (Wartefrist)';
$msg .= $langs->trans('MahnungUebersprungen2', $skipped);
}
if (!empty($failed)) {
$msg .= ' — Fehler: '.implode(' | ', $failed);
$msg .= $langs->trans('MahnungFehlerLabel', implode(' | ', $failed));
respond(false, $msg, array('created' => $created, 'failed' => $failed));
}
respond(true, $msg, array('created' => $created, 'skipped' => $skipped));
/**
* Prueft, ob fuer eine Rechnung bereits in einer aktiven Mahnung die §288-B2B-Pauschale gesetzt wurde.
* Prüft, ob r eine Rechnung bereits in einer aktiven Mahnung die §288-B2B-Pauschale gesetzt wurde.
*
* @param DoliDB $db
* @param int $factureId

View file

@ -7,7 +7,7 @@
/**
* \file htdocs/custom/mahnung/ajax/regex_preview.php
* \ingroup mahnung
* \brief AJAX-Endpoint: Live-Vorschau fuer Tracking-Regex auf der Setup-Seite.
* \brief AJAX-Endpoint: Live-Vorschau für Tracking-Regex auf der Setup-Seite.
*
* POST: regex (string), sample (string, max 10 KB), url_template (string)
* Response (JSON): { valid: bool, match: string|null, preview_url: string|null, error: string|null }

View file

@ -7,7 +7,7 @@
/**
* \file htdocs/custom/mahnung/ajax/sammelbrief.php
* \ingroup mahnung
* \brief AJAX/Form-Endpoint: Sammelbrief fuer eine Auswahl von Rechnungen
* \brief AJAX/Form-Endpoint: Sammelbrief für eine Auswahl von Rechnungen
* Mahnungen erzeugen und alle Einzel-PDFs in EIN PDF zusammenfassen.
*
* POST:
@ -39,7 +39,7 @@ if (empty($postedToken) || empty($_SESSION['newtoken']) || $postedToken !== $_SE
while (ob_get_level() > 0) {
ob_end_clean();
}
httpExitError(403, 'Token-Verifikation fehlgeschlagen.');
httpExitError(403, $langs->trans('MahnungSammelbriefCsrfFehler'));
}
// Permission
@ -47,7 +47,7 @@ if (!$user->hasRight('mahnung', 'send') && !$user->hasRight('mahnung', 'write'))
while (ob_get_level() > 0) {
ob_end_clean();
}
httpExitError(403, 'Nicht berechtigt.');
httpExitError(403, $langs->trans('MahnungSammelbriefNichtBerechtigt'));
}
$factureIds = GETPOST('facture_ids', 'array:int');
@ -58,7 +58,7 @@ if (empty($factureIds)) {
while (ob_get_level() > 0) {
ob_end_clean();
}
httpExitError(400, 'Keine Rechnungen ausgewaehlt.');
httpExitError(400, $langs->trans('MahnungKeineRechnungenAusgewaehlt'));
}
$forceStufe = GETPOSTINT('stufe');
@ -126,11 +126,11 @@ if (empty($paths)) {
while (ob_get_level() > 0) {
ob_end_clean();
}
httpExitError(500, 'Keine PDFs erzeugt — pruefe ob die Rechnungen mahnreif sind.');
httpExitError(500, $langs->trans('MahnungSammelbriefKeinePdfs'));
}
// Wenn TCPDI verfuegbar, Seiten aller PDFs in EIN Dokument importieren.
// Andernfalls ZIP-Fallback wuerde sich anbieten — wir liefern stattdessen
// Wenn TCPDI verfügbar, Seiten aller PDFs in EIN Dokument importieren.
// Andernfalls ZIP-Fallback würde sich anbieten — wir liefern stattdessen
// eine PDF-Konkatenation via TCPDI (Bestandteil von tecnickcom/tc-lib-pdf
// und Dolibarr-Tcpdi-Wrapper).
$absOut = this_buildSammelbriefPdf($paths);
@ -138,7 +138,7 @@ if ($absOut === null || !file_exists($absOut)) {
while (ob_get_level() > 0) {
ob_end_clean();
}
httpExitError(500, 'Sammelbrief-PDF konnte nicht erzeugt werden.');
httpExitError(500, $langs->trans('MahnungSammelbriefFehler'));
}
while (ob_get_level() > 0) {
@ -154,7 +154,7 @@ exit;
// ----------------------------------------------------------------
/**
* Konkateniert mehrere PDF-Dateien zu einer Datei. Gibt absoluten Pfad zurueck
* Konkateniert mehrere PDF-Dateien zu einer Datei. Gibt absoluten Pfad zurück
* oder null bei Fehler.
*
* @param string[] $paths
@ -163,14 +163,14 @@ exit;
function this_buildSammelbriefPdf(array $paths)
{
if (!class_exists('TCPDI')) {
// Dolibarr liefert TCPDI ueber tcpdf/tcpdi.php aus
// Dolibarr liefert TCPDI über tcpdf/tcpdi.php aus
$tcpdiPath = DOL_DOCUMENT_ROOT.'/includes/tcpdf/tcpdi.php';
if (file_exists($tcpdiPath)) {
require_once $tcpdiPath;
}
}
if (!class_exists('TCPDI')) {
dol_syslog('Mahnung Sammelbrief: TCPDI-Klasse nicht verfuegbar — nur erstes PDF wird zurueckgeliefert', LOG_WARNING);
dol_syslog('Mahnung Sammelbrief: TCPDI-Klasse nicht verfügbar — nur erstes PDF wird zurückgeliefert', LOG_WARNING);
return $paths[0] ?? null;
}
@ -195,7 +195,7 @@ function this_buildSammelbriefPdf(array $paths)
}
/**
* Prueft, ob fuer eine Rechnung bereits §288-B2B-Pauschale gesetzt wurde.
* Prüft, ob r eine Rechnung bereits §288-B2B-Pauschale gesetzt wurde.
*
* @param DoliDB $db
* @param int $factureId

View file

@ -48,34 +48,34 @@ function jsonExit($success, $message)
// CSRF
$postedToken = GETPOST('token', 'alphanohtml');
if (empty($postedToken) || empty($_SESSION['newtoken']) || $postedToken !== $_SESSION['newtoken']) {
jsonExit(false, 'CSRF-Token ungueltig.');
jsonExit(false, $langs->trans('MahnungCsrfTokenUngueltig'));
}
if (!$user->hasRight('mahnung', 'send')) {
jsonExit(false, 'Nicht berechtigt (mahnung.send).');
jsonExit(false, $langs->trans('MahnungNichtBerechtigtSend'));
}
$mahnungId = GETPOSTINT('mahnung_id');
if ($mahnungId <= 0) {
jsonExit(false, 'mahnung_id fehlt.');
jsonExit(false, $langs->trans('MahnungIdFehlt'));
}
$mahnung = new Mahnung($db);
if ($mahnung->fetch($mahnungId) <= 0) {
jsonExit(false, 'Mahnung '.$mahnungId.' nicht gefunden.');
jsonExit(false, $langs->trans('MahnungNichtGefunden', $mahnungId));
}
if (empty($mahnung->pdf_path) || !file_exists($mahnung->pdf_path)) {
jsonExit(false, 'PDF zur Mahnung '.$mahnung->ref.' fehlt — bitte zuerst Mahnung erzeugen.');
jsonExit(false, $langs->trans('MahnungPdfFehlt', $mahnung->ref));
}
$societe = new Societe($db);
if ($societe->fetch((int) $mahnung->fk_soc) <= 0) {
jsonExit(false, 'Kunde nicht ladbar.');
jsonExit(false, $langs->trans('MahnungKundeNichtLadbar'));
}
$toEmail = trim((string) ($societe->email ?? ''));
if (empty($toEmail)) {
jsonExit(false, 'Kunde hat keine E-Mail-Adresse hinterlegt.');
jsonExit(false, $langs->trans('MahnungKundeKeineEmail'));
}
$facture = new Facture($db);
@ -93,7 +93,7 @@ $replacements = array(
'{kunde}' => $societe->name ?? '',
);
$subject = strtr($stufeObj->email_subject ?: 'Mahnung {stufe} zu Rechnung {rechnung}', $replacements);
$subject = strtr($stufeObj->email_subject ?: $langs->trans('MahnungEmailDefaultSubject'), $replacements);
$body = strtr($stufeObj->email_body ?: defaultMailBody((int) $mahnung->stufe), $replacements);
$fromEmail = $mysoc->email ?? getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
@ -122,10 +122,10 @@ if (!$mailFile->error) {
if ($mailFile->sendfile()) {
$mahnung->status = Mahnung::STATUS_VERSENDET;
$mahnung->update($user);
jsonExit(true, 'E-Mail an '.$toEmail.' gesendet.');
jsonExit(true, $langs->trans('MahnungEmailGesendet', $toEmail));
}
}
jsonExit(false, 'E-Mail-Versand fehlgeschlagen: '.$mailFile->error);
jsonExit(false, $langs->trans('MahnungEmailFehlgeschlagen', $mailFile->error));
/**
* Default-Body je Stufe.
@ -135,20 +135,15 @@ jsonExit(false, 'E-Mail-Versand fehlgeschlagen: '.$mailFile->error);
*/
function defaultMailBody($stufe)
{
global $langs;
$langs->load('mahnung@mahnung');
switch ((int) $stufe) {
case 1:
return "Sehr geehrter Kunde,\n\nanbei senden wir Ihnen eine freundliche Zahlungserinnerung zu Rechnung {rechnung}.\n"
. "Offener Betrag inkl. evtl. Zinsen: {summe}.\n"
. "Wir bitten um Begleichung bis spaetestens {frist}.\n\n"
. "Mit freundlichen Gruessen";
return $langs->trans('MahnungEmailDefaultBody1');
case 2:
return "Sehr geehrter Kunde,\n\nanbei die 1. Mahnung zur Rechnung {rechnung}.\n"
. "Bitte ueberweisen Sie {summe} bis zum {frist}.\n\n"
. "Mit freundlichen Gruessen";
return $langs->trans('MahnungEmailDefaultBody2');
case 3:
default:
return "Sehr geehrter Kunde,\n\nanbei die letzte Mahnung zur Rechnung {rechnung}.\n"
. "Falls der Betrag von {summe} nicht bis zum {frist} eingeht, leiten wir gerichtliche Schritte ein.\n\n"
. "Mit freundlichen Gruessen";
return $langs->trans('MahnungEmailDefaultBody3');
}
}

View file

@ -51,7 +51,7 @@ $action = GETPOST('action', 'aZ09');
$mahnung = new Mahnung($db);
if ($mahnung->fetch($id) <= 0) {
dol_print_error($db, 'Mahnung nicht gefunden');
dol_print_error($db, $langs->trans('MahnungNichtGefunden', $id));
exit;
}
@ -71,15 +71,15 @@ 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');
setEventMessages($langs->trans('MahnungDokumentErstellt'), null, 'mesgs');
} else {
setEventMessages('Dokument-Fehler: '.$mahnung->error, null, 'errors');
setEventMessages($langs->trans('MahnungDokumentFehler').': '.$mahnung->error, null, 'errors');
}
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
exit;
}
// Generiertes Dokument loeschen
// Generiertes Dokument löschen
if ($action === 'delete_doc' && $user->hasRight('mahnung', 'write')) {
$docfile = GETPOST('file', 'alphanohtml');
if (!empty($docfile) && !empty($mahnung->fk_facture)) {
@ -95,7 +95,7 @@ if ($action === 'delete_doc' && $user->hasRight('mahnung', 'write')) {
dol_delete_file($fullpath);
setEventMessages($langs->trans('FileWasRemoved'), null, 'mesgs');
} else {
setEventMessages('Datei nicht gefunden oder nicht zugehoerig', null, 'errors');
setEventMessages($langs->trans('MahnungDateiNichtGefunden'), null, 'errors');
}
}
}
@ -118,19 +118,19 @@ if ($action === 'set_versand' && $user->hasRight('mahnung', 'write')) {
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');
setEventMessages($mahnung->error ?: $langs->trans('MahnungFehlerSpeichern'), null, 'errors');
}
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
exit;
}
// Rechnung als uneinbringlich klassifizieren (close_code='badcustomer')
// — endgueltiger Schritt nach erfolglosem Mahnverfahren / Vollstreckung.
// — endgültiger Schritt nach erfolglosem Mahnverfahren / Vollstreckung.
if ($action === 'confirm_uneinbringlich' && $user->hasRight('mahnung', 'delete')) {
require_once DOL_DOCUMENT_ROOT.'/core/class/commoninvoice.class.php';
$note = trim((string) GETPOST('uneinbringlich_note', 'nohtml'));
if ($note === '') {
$note = 'Mahnverfahren erfolglos abgeschlossen am '.dol_print_date(dol_now(), 'day');
$note = $langs->trans('MahnungVerfahrenErfolglos').' '.dol_print_date(dol_now(), 'day');
}
$facReload = new Facture($db);
@ -140,20 +140,20 @@ if ($action === 'confirm_uneinbringlich' && $user->hasRight('mahnung', 'delete')
if ($ret > 0) {
// Mahnung mitstornieren — Vorgang ist damit fachlich abgeschlossen
$mahnung->status = Mahnung::STATUS_STORNIERT;
$mahnung->note_private = trim(($mahnung->note_private ? $mahnung->note_private."\n\n" : '').'Uneinbringlich klassifiziert ('.dol_print_date(dol_now(), 'day').'): '.$note);
$mahnung->note_private = trim(($mahnung->note_private ? $mahnung->note_private."\n\n" : '').$langs->trans('MahnungUneinbringlichKlassifiziert').' ('.dol_print_date(dol_now(), 'day').'): '.$note);
$mahnung->update($user);
setEventMessages($langs->trans('MahnungUneinbringlichErfolg'), null, 'mesgs');
} else {
setEventMessages($facReload->error ?: 'Fehler beim Klassifizieren', null, 'errors');
setEventMessages($facReload->error ?: $langs->trans('MahnungFehlerKlassifizieren'), null, 'errors');
}
} else {
setEventMessages('Rechnung nicht ladbar', null, 'errors');
setEventMessages($langs->trans('MahnungRechnungNichtLadbar'), null, 'errors');
}
header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
exit;
}
// Sendungsnummer aus erkanntem Vorschlag uebernehmen
// Sendungsnummer aus erkanntem Vorschlag übernehmen
if ($action === 'apply_tracking' && $user->hasRight('mahnung', 'write')) {
$nr = trim((string) GETPOST('nr', 'alphanohtml'));
$prov = GETPOST('provider', 'aZ09');
@ -170,7 +170,7 @@ if ($action === 'apply_tracking' && $user->hasRight('mahnung', 'write')) {
exit;
}
// Vorschlaege verwerfen
// Vorschläge 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));
@ -185,7 +185,7 @@ if ($action === 'scan_belege' && $user->hasRight('mahnung', 'write')) {
$patternService = new MahnungTrackingPattern($db);
$suggestions = array();
$pdftotextAvailable = null; // einmalig pruefen
$pdftotextAvailable = null; // einmalig prüfen
if (is_dir($scanDir)) {
foreach (dol_dir_list($scanDir, 'files', 0) as $file) {
@ -201,6 +201,7 @@ if ($action === 'scan_belege' && $user->hasRight('mahnung', 'write')) {
$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);
@ -230,13 +231,13 @@ if ($action === 'scan_belege' && $user->hasRight('mahnung', 'write')) {
exit;
}
// Versand-Daten zuruecksetzen (z.B. Korrekturmoeglichkeit)
// Versand-Daten zurücksetzen (z.B. Korrekturmöglichkeit)
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
// Status nicht zurückdrehen — nur Daten löschen
if ($mahnung->update($user) > 0) {
setEventMessages($langs->trans('MahnungVersandGeleert'), null, 'mesgs');
}
@ -244,7 +245,7 @@ if ($action === 'clear_versand' && $user->hasRight('mahnung', 'write')) {
exit;
}
// Upload-Verzeichnis fuer Sendebelege (muss VOR llxHeader stehen fuer actions_linkedfiles)
// Upload-Verzeichnis für Sendebelege (muss VOR llxHeader stehen für actions_linkedfiles)
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
$mahnungSafeRef = dol_sanitizeFileName($mahnung->ref);
$upload_dir = (!empty($conf->mahnung->multidir_output[$mahnung->entity])
@ -290,7 +291,7 @@ if ((float) $mahnung->pauschale_b2b > 0) {
}
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 '<tr><td>'.$langs->trans('Status').'</td><td>'.dol_escape_htmltag($mahnung->getStatusLabel()).'</td></tr>';
print '</table>';
// --- Generierte Dokumente (wie bei Rechnungen) ---
@ -348,7 +349,7 @@ if (!empty($fileList)) {
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: Download + Loeschen
// Aktionen: Download + Löschen
print '<td class="right nowraponall">';
print '<a href="'.$dlUrl.'">'.img_picto($langs->trans('Download'), 'download').'</a>';
if ($canDeleteDoc) {
@ -470,7 +471,7 @@ if (!empty($mahnung->date_versand) && $action !== 'edit_versand') {
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
// Tracking-Vorschläge aus Session-Flash (vom Scan) anzeigen
$suggKey = 'mahnung_tracking_suggestions_'.((int) $mahnung->id);
$suggestions = $_SESSION[$suggKey] ?? null;
if (is_array($suggestions) && !empty($suggestions)) {
@ -512,6 +513,29 @@ if ($canWrite) {
}
$urlSelf = $_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id);
// Upload-Formular (Durchsuchen + Upload-Button)
$formfile->form_attach_new_file(
$urlSelf,
'', // title
0, // addcancel
0, // sectionid
(int) $canWrite, // perm
50, // size
$mahnung, // object
'', // options
1, // useajax
'', // savingdocmask
0, // linkfiles
'formuserfile', // htmlname
'', // accept
'', // sectiondir
0, // usewithoutform
0, // capture
0 // disablemulti
);
// Dateiliste der bereits hochgeladenen Belege
$formfile->showdocuments(
'mahnung', // $modulepart
$mahnungSafeRef, // $modulesubdir
@ -520,7 +544,7 @@ $formfile->showdocuments(
0, // $genallowed (kein PDF-Gen-Button hier)
(int) $canWrite, // $delallowed
'', // $modelselected
1, // $allowgenifempty
0, // $allowgenifempty
0, // $forcenomultilang
0, // $iconPDF
0, // $notused
@ -530,7 +554,8 @@ $formfile->showdocuments(
'', // $buttonlabel
'', // $codelang
'', // $morepicto
$mahnung // $object
$mahnung, // $object
1 // $hideifempty (Liste nur zeigen wenn Dateien vorhanden)
);
if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
@ -546,13 +571,13 @@ if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung',
);
}
if ($action === 'ask_uneinbringlich') {
// Bestaetigungsdialog mit Eingabefeld fuer Begruendung
// Bestätigungsdialog mit Eingabefeld für Begründung
$formquestion = array(
array(
'type' => 'textarea',
'name' => 'uneinbringlich_note',
'label' => $langs->trans('MahnungUneinbringlichBegruendung'),
'value' => 'Mahnverfahren erfolglos abgeschlossen am '.dol_print_date(dol_now(), 'day'),
'value' => $langs->trans('MahnungVerfahrenErfolglos').' '.dol_print_date(dol_now(), 'day'),
'morecss' => 'minwidth500 quatrevingtpercent',
),
);
@ -588,7 +613,7 @@ if ($user->hasRight('mahnung', 'write')) {
print $langs->trans('MahnungGenerate');
print '</a> ';
}
// "Als uneinbringlich klassifizieren" — nur fuer Stufe-3-Mahnungen mit
// "Als uneinbringlich klassifizieren" — nur für Stufe-3-Mahnungen mit
// Status >= ERSTELLT (also nicht im Entwurf) und nicht bereits storniert.
// Setzt die Rechnung auf STATUS_ABANDONED mit close_code='badcustomer'.
if ($mahnung->status !== Mahnung::STATUS_STORNIERT
@ -596,7 +621,7 @@ if ($mahnung->status !== Mahnung::STATUS_STORNIERT
&& (int) $mahnung->status >= Mahnung::STATUS_ERSTELLT
&& $user->hasRight('mahnung', 'delete')
) {
// Pruefen ob Rechnung schon abandoned ist — dann Button verstecken
// Prüfen ob Rechnung schon abandoned ist — dann Button verstecken
$facStatus = 0;
$facRes = $db->query("SELECT fk_statut, close_code FROM ".MAIN_DB_PREFIX."facture WHERE rowid = ".((int) $mahnung->fk_facture));
if ($facRes && ($facObj = $db->fetch_object($facRes))) {

View file

@ -29,7 +29,7 @@ class ActionsMahnung
* @param CommonObject $object Facture
* @param string $action
* @param HookManager $hookmanager
* @return int 0 = weiter, 1 = ueberschreiben
* @return int 0 = weiter, 1 = überschreiben
*/
public function addMoreActionsButtons($parameters, &$object, &$action, $hookmanager)
{
@ -44,7 +44,7 @@ class ActionsMahnung
return 0;
}
// Nur fuer normale Kundenrechnungen
// Nur für normale Kundenrechnungen
if (!isset($object->type) || (int) $object->type !== 0) {
return 0;
}
@ -101,7 +101,7 @@ class ActionsMahnung
}
// complete_head_from_modules() wird pro Karte mehrfach aufgerufen
// (mode='add' fuer 'core' UND 'external', plus mode='remove').
// (mode='add' für 'core' UND 'external', plus mode='remove').
// Genau einmal feuern: nur add/external.
if (($parameters['mode'] ?? '') !== 'add') {
return 0;
@ -154,8 +154,8 @@ class ActionsMahnung
}
/**
* Hook tabContentViewThirdparty: rendert eine prominente Bonitaets-Warnbox auf
* der Kundenkarte, wenn fuer diesen Kunden uneinbringliche Forderungen existieren
* Hook tabContentViewThirdparty: rendert eine prominente Bonitäts-Warnbox auf
* der Kundenkarte, wenn für diesen Kunden uneinbringliche Forderungen existieren
* (fk_statut=3 abandoned + close_code='badcustomer').
*
* @param array $parameters
@ -200,10 +200,10 @@ class ActionsMahnung
/**
* Hook addMoreActionsButtons: Warning-Banner bei der Aktions-Leiste falls
* der Kunde Forderungsausfaelle hat. Wird sowohl bei Auftrag (ordercard) als
* der Kunde Forderungsausfälle hat. Wird sowohl bei Auftrag (ordercard) als
* auch bei Rechnung (invoicecard) gezeigt.
*
* Ergaenzt addMoreActionsButtons (Mahnung-erstellen-Button) wird vor
* Ergänzt addMoreActionsButtons (Mahnung-erstellen-Button) wird vor
* jenem Block ausgegeben.
*
* @param array $parameters
@ -250,7 +250,7 @@ class ActionsMahnung
/**
* Liefert Anzahl, Summe und Datum der letzten als 'badcustomer' abandonierten
* Rechnungen fuer einen Kunden.
* Rechnungen für einen Kunden.
*
* @param DoliDB $db
* @param int $socid

View file

@ -8,13 +8,13 @@
/**
* \file htdocs/custom/mahnung/class/mahnung.class.php
* \ingroup mahnung
* \brief CRUD-Klasse fuer Mahnvorgaenge (llx_mahnung_mahnung).
* \brief CRUD-Klasse für Mahnvorgänge (llx_mahnung_mahnung).
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* Klasse Mahnung repraesentiert einen Mahnvorgang zu einer Kundenrechnung.
* Klasse Mahnung repräsentiert einen Mahnvorgang zu einer Kundenrechnung.
*/
class Mahnung extends CommonObject
{
@ -107,7 +107,7 @@ class Mahnung extends CommonObject
/** @var string Rohe Sendungsnummer wie ausgedruckt */
public $tracking_nr;
/** @var string dhl|dpag|hermes|dpd|ups|custom — fuer URL-Template */
/** @var string dhl|dpag|hermes|dpd|ups|custom — für URL-Template */
public $tracking_provider;
/** @var int Unix-Zeit */
@ -133,7 +133,7 @@ class Mahnung extends CommonObject
}
/**
* Naechste freie Mahnungs-Referenz fuer das aktuelle Jahr.
* Nächste freie Mahnungs-Referenz r das aktuelle Jahr.
* Format: MAHN<YYYY>-<NNNN>
*
* @return string
@ -269,7 +269,7 @@ class Mahnung extends CommonObject
$this->fk_user_creat = $obj->fk_user_creat;
$this->fk_user_modif = $obj->fk_user_modif;
// Alias fuer CommonObject::fetch_thirdparty()
// Alias für CommonObject::fetch_thirdparty()
$this->socid = $this->fk_soc;
$this->db->free($resql);
@ -277,7 +277,7 @@ class Mahnung extends CommonObject
}
/**
* Dokument generieren ueber das Dolibarr-Dokumentenmodell-System.
* Dokument generieren über das Dolibarr-Dokumentenmodell-System.
*
* @param string $modele Modellname ('standard_mahnung', 'generic_mahnung_odt')
* @param Translate $outputlangs Ausgabesprache
@ -314,7 +314,7 @@ class Mahnung extends CommonObject
* @param string $sortorder
* @param int $limit
* @param int $offset
* @param array $filter Schluessel: fk_facture, fk_soc, stufe, status, ref_like
* @param array $filter Schlüssel: fk_facture, fk_soc, stufe, status, ref_like
* @param string $mode 'list' | 'count'
* @return Mahnung[]|int Liste, Anzahl oder -1 bei Fehler
*/
@ -423,7 +423,7 @@ class Mahnung extends CommonObject
}
/**
* Mahnvorgang loeschen. Verknuepftes PDF wird mitgeloescht falls vorhanden.
* Mahnvorgang löschen. Verknüpftes PDF wird mitgelöscht falls vorhanden.
*
* @param User $user Loeschender User
* @return int <0 bei Fehler, sonst 1
@ -509,7 +509,7 @@ class Mahnung extends CommonObject
*
* @param string $provider dhl|dpag|hermes|dpd|ups|custom
* @param string $nr
* @return string Vollstaendige URL oder leer bei unbekanntem Provider
* @return string Vollständige URL oder leer bei unbekanntem Provider
*/
public static function trackingUrl($provider, $nr)
{
@ -553,7 +553,7 @@ class Mahnung extends CommonObject
}
/**
* Letzten Mahnvorgang zu einer Rechnung holen (hoechste Stufe, neuestes Datum).
* Letzten Mahnvorgang zu einer Rechnung holen (höchste Stufe, neuestes Datum).
*
* @param int $factureId
* @return Mahnung|null

View file

@ -8,7 +8,7 @@
/**
* \file htdocs/custom/mahnung/class/mahnungcron.class.php
* \ingroup mahnung
* \brief Cron-Job: Vorschlagsliste ueberfaelliger Rechnungen einsammeln,
* \brief Cron-Job: Vorschlagsliste überfälliger Rechnungen einsammeln,
* Ntfy-Push mit Kennzahl an Eddy.
*/
@ -41,7 +41,7 @@ class MahnungCron
}
/**
* Sucht ueberfaellige Rechnungen, ermittelt Vorschlaege je Stufe,
* Sucht überfällige Rechnungen, ermittelt Vorschläge je Stufe,
* sendet Ntfy-Push mit Anzahl je Stufe und Gesamtwert.
*
* @return int 0 bei Erfolg, < 0 bei Fehler
@ -66,22 +66,27 @@ class MahnungCron
$summe = round($summe, 2);
if ($count === 0) {
// Alte Notifications raeumen — es gibt nichts mehr zu tun
// Alte Notifications räumen — es gibt nichts mehr zu tun
self::clearGlobalNotify();
$this->output = 'Keine ueberfaelligen Rechnungen mit faelliger Mahnung.';
global $langs;
$langs->load('mahnung@mahnung');
$this->output = $langs->trans('MahnungCronKeineUeberfaellige');
$this->lastresult = 0;
return 0;
}
global $langs;
$langs->load('mahnung@mahnung');
$dolUrl = trim((string) getDolGlobalString('MAIN_INFO_SOCIETE_NOM', ''));
$relPath = '/custom/mahnung/list.php?mainmenu=billing&leftmenu=mahnung&mode=vorschlag';
$absUrl = self::buildAbsoluteUrl($relPath);
$title = 'Mahnwesen: '.$count.' offene Vorschlaege';
$message = "Stufe 1 (Erinnerung): {$counts[1]}\n";
$message .= "Stufe 2 (Mahnung): {$counts[2]}\n";
$message .= "Stufe 3 (Letzte Mahnung): {$counts[3]}\n";
$message .= 'Offener Betrag: '.number_format($summe, 2, ',', '.').' EUR';
$title = $langs->trans('MahnungCronOffeneVorschlaege', $count);
$message = $langs->trans('MahnungCronStufe1Erinnerung', $counts[1])."\n";
$message .= $langs->trans('MahnungCronStufe2Mahnung', $counts[2])."\n";
$message .= $langs->trans('MahnungCronStufe3LetzteMahnung', $counts[3])."\n";
$message .= $langs->trans('MahnungCronOffenerBetrag', number_format($summe, 2, ',', '.'));
MahnungNtfy::send($title, $message, $absUrl, array('envelope_with_arrow', 'warning'));
@ -96,10 +101,10 @@ class MahnungCron
if (class_exists('GlobalNotify')) {
GlobalNotify::actionRequired(
'mahnung',
'Mahnwesen: '.$count.' Vorschlaege',
$langs->trans('MahnungCronVorschlaege', $count),
$message,
$relPath,
'Vorschlagsliste oeffnen'
$langs->trans('MahnungCronVorschlagslisteOeffnen')
);
}
@ -109,8 +114,8 @@ class MahnungCron
}
/**
* Raeumt alle GlobalNotify-Notifications fuer das Mahnung-Modul auf.
* Wird aufgerufen wenn keine offenen Vorschlaege mehr existieren.
* Räumt alle GlobalNotify-Notifications r das Mahnung-Modul auf.
* Wird aufgerufen wenn keine offenen Vorschläge mehr existieren.
*
* @return void
*/
@ -172,31 +177,34 @@ class MahnungCron
}
$this->db->free($resql);
global $langs;
$langs->load('mahnung@mahnung');
if (empty($pending)) {
$this->output = 'Keine Mahnungen unversendet > '.$tageSchwelle.' Tage.';
$this->output = $langs->trans('MahnungCronKeineUnversendet', $tageSchwelle);
$this->lastresult = 0;
return 0;
}
$relPath = '/custom/mahnung/list.php?mainmenu=billing&leftmenu=mahnung&mode=archiv';
$absUrl = self::buildAbsoluteUrl($relPath);
$title = 'Mahnwesen: '.count($pending).' Mahnung(en) unversendet';
$title = $langs->trans('MahnungCronUnversendetTitel', count($pending));
$lines = array();
foreach ($pending as $p) {
$tage = (int) floor((time() - strtotime((string) $p->datec)) / 86400);
$lines[] = $p->ref.' (Stufe '.$p->stufe.', '.$tage.' Tage alt) — '.$p->soc_nom;
$lines[] = $langs->trans('MahnungCronStufeAlter', $p->ref, $p->stufe, $tage, $p->soc_nom);
}
// Auf 8 Zeilen kuerzen, Rest als "+N weitere"
// Auf 8 Zeilen kürzen, Rest als "+N weitere"
if (count($lines) > 8) {
$rest = count($lines) - 8;
$lines = array_slice($lines, 0, 8);
$lines[] = '+ '.$rest.' weitere';
$lines[] = $langs->trans('MahnungCronWeitere', $rest);
}
$message = implode("\n", $lines);
MahnungNtfy::send($title, $message, $absUrl, array('envelope_with_arrow', 'warning'));
// Optional: GlobalNotify-Badge — relativer Pfad fuer Browser-Kontext
// Optional: GlobalNotify-Badge — relativer Pfad für Browser-Kontext
if (isModEnabled('globalnotify') && !class_exists('GlobalNotify')) {
$gnPath = DOL_DOCUMENT_ROOT.'/custom/globalnotify/class/globalnotify.class.php';
if (file_exists($gnPath)) {
@ -209,11 +217,11 @@ class MahnungCron
$title,
$message,
$relPath,
'Archiv oeffnen'
$langs->trans('MahnungCronArchivOeffnen')
);
}
$this->output = $title.' — '.count($pending).' Eintraege';
$this->output = $langs->trans('MahnungCronEintraege', $title, count($pending));
$this->lastresult = count($pending);
return 0;
}

View file

@ -8,10 +8,10 @@
/**
* \file htdocs/custom/mahnung/class/mahnungntfy.class.php
* \ingroup mahnung
* \brief Schmaler Ntfy-Push fuer das Mahnwesen-Modul.
* \brief Schmaler Ntfy-Push für das Mahnwesen-Modul.
*
* Phase 3: standalone Ntfy.
* Phase 7: wird durch GlobalNotify-Integration ergaenzt/ersetzt (notify-Skill).
* Phase 7: wird durch GlobalNotify-Integration ergänzt/ersetzt (notify-Skill).
*
* Konfig-Konstanten (Setup-Seite):
* MAHNUNG_NTFY_TOPIC Default 'vk-builds'
@ -58,7 +58,7 @@ class MahnungNtfy
}
if (!function_exists('curl_init')) {
dol_syslog('MahnungNtfy: cURL nicht verfuegbar', LOG_WARNING);
dol_syslog('MahnungNtfy: cURL nicht verfügbar', LOG_WARNING);
return false;
}
@ -82,7 +82,7 @@ class MahnungNtfy
}
/**
* Header-Werte muessen Single-Line sein. Newlines + Steuerzeichen entfernen.
* Header-Werte müssen Single-Line sein. Newlines + Steuerzeichen entfernen.
*
* @param string $value
* @return string

View file

@ -8,13 +8,13 @@
/**
* \file htdocs/custom/mahnung/class/mahnungstufe.class.php
* \ingroup mahnung
* \brief Konfigurations-Klasse fuer Mahnstufen (llx_mahnung_stufe).
* \brief Konfigurations-Klasse für Mahnstufen (llx_mahnung_stufe).
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* Eine Mahnstufe (1..3): Frist-Konfiguration, Gebuehren, optionaler Zinssatz-Override,
* Eine Mahnstufe (1..3): Frist-Konfiguration, Gebühren, optionaler Zinssatz-Override,
* Versandart-Default, E-Mail-/PDF-Templates.
*/
class MahnungStufe extends CommonObject
@ -34,7 +34,7 @@ class MahnungStufe extends CommonObject
/** @var string */
public $label;
/** @var int Tage nach Faelligkeit (Stufe 1) bzw. nach Vorgaengerstufe (>1) */
/** @var int Tage nach Fälligkeit (Stufe 1) bzw. nach Vorgängerstufe (>1) */
public $frist_tage = 0;
/** @var int Neue Zahlungsfrist im Mahnschreiben (Tage) */
@ -175,7 +175,7 @@ class MahnungStufe extends CommonObject
}
/**
* Mahngebuehr fuer einen Kundentyp aus dieser Stufe lesen.
* Mahngebühr r einen Kundentyp aus dieser Stufe lesen.
*
* @param string $kundentyp 'B2C'|'B2B'
* @return float
@ -188,7 +188,7 @@ class MahnungStufe extends CommonObject
}
/**
* Override-Zinssatz fuer einen Kundentyp (oder null falls Default gewuenscht).
* Override-Zinssatz für einen Kundentyp (oder null falls Default gewünscht).
*
* @param string $kundentyp
* @return float|null

View file

@ -8,7 +8,7 @@
/**
* \file htdocs/custom/mahnung/class/mahnungtrackingpattern.class.php
* \ingroup mahnung
* \brief CRUD + Lookup fuer konfigurierbare Tracking-Patterns (Regex + URL-Template).
* \brief CRUD + Lookup für konfigurierbare Tracking-Patterns (Regex + URL-Template).
*
* Patterns werden in llx_mahnung_trackingpattern gehalten. Beim Upload eines
* Sendebelegs werden alle aktiven Patterns nach priority DESC durchprobiert;
@ -38,7 +38,7 @@ class MahnungTrackingPattern
/** @var string URL-Template mit Platzhalter {nr}, z.B. 'https://www.dhl.de/...?piececode={nr}' */
public $url_template;
/** @var int hoeher = wichtiger (zuerst geprueft) */
/** @var int höher = wichtiger (zuerst geprüft) */
public $priority = 100;
/** @var int 0/1 */
@ -155,7 +155,7 @@ class MahnungTrackingPattern
}
/**
* Pattern loeschen.
* Pattern löschen.
*
* @return int <0 Fehler, sonst 1
*/
@ -237,7 +237,7 @@ class MahnungTrackingPattern
/**
* Robuste Regex-Validierung (kein ReDoS-Schutz, aber Syntax-Check).
* Erlaubt nur Delimiter /, #, ~. URL-Template wird hier NICHT geprueft.
* Erlaubt nur Delimiter /, #, ~. URL-Template wird hier NICHT geprüft.
*
* @param string $regex
* @return bool
@ -252,7 +252,7 @@ class MahnungTrackingPattern
if (!in_array($first, array('/', '#', '~'), true)) {
return false;
}
// @ unterdrueckt Warning, false bei ungueltigem Regex
// @ unterdrückt Warning, false bei ungültigem Regex
$ret = @preg_match($regex, '');
return $ret !== false;
}
@ -293,7 +293,7 @@ class MahnungTrackingPattern
global $conf;
$entity = (int) $conf->entity;
// Anzahl bestehender Patterns pruefen
// Anzahl bestehender Patterns prüfen
$resql = $db->query("SELECT COUNT(*) AS nb FROM ".MAIN_DB_PREFIX."mahnung_trackingpattern WHERE entity = ".$entity);
if (!$resql) {
return 0;
@ -301,10 +301,10 @@ class MahnungTrackingPattern
$obj = $db->fetch_object($resql);
$db->free($resql);
if ((int) $obj->nb > 0) {
return 0; // Schon befuellt
return 0; // Schon befüllt
}
// Defaults — priority hoeher = spezifischer (zuerst gepruef)
// Defaults — priority höher = spezifischer (zuerst geprüft)
$defaults = array(
array('dhl', 'DHL Paket (20-stellig)', '/\b(\d{20})\b/', 'https://www.dhl.de/de/privatkunden/dhl-sendungsverfolgung.html?piececode={nr}', 90),
array('dpag', 'Deutsche Post Einschreiben', '/\b(R[A-Z]\d{9}DE)\b/', 'https://www.deutschepost.de/sendung/simpleQuery.html?form.sendungsnummer={nr}', 85),

View file

@ -8,8 +8,8 @@
/**
* \file htdocs/custom/mahnung/class/mahnungvorschlag.class.php
* \ingroup mahnung
* \brief Service: ueberfaellige Rechnungen einsammeln und je Rechnung
* die naechste vorgeschlagene Mahnstufe ermitteln.
* \brief Service: überfällige Rechnungen einsammeln und je Rechnung
* die nächste vorgeschlagene Mahnstufe ermitteln.
*
* Geteilte Logik zwischen Cron-Job (Ntfy-Push) und Vorschlagslisten-UI.
*/
@ -39,10 +39,10 @@ class MahnungVorschlag
}
/**
* Liefert pro ueberfaelliger Rechnung einen Vorschlag (oder ueberspringt sie,
* wenn alle Stufen bereits durchlaufen sind oder die Wartefrist noch laeuft).
* Liefert pro überfälliger Rechnung einen Vorschlag (oder überspringt sie,
* wenn alle Stufen bereits durchlaufen sind oder die Wartefrist noch läuft).
*
* Rueckgabe-Schluessel je Eintrag:
* Rückgabe-Schlüssel je Eintrag:
* facture_id, facture_ref, facture_date_lim_reglement (Unix), facture_total_ttc,
* soc_id, soc_nom, soc_tva_intra,
* kundentyp ('B2C'|'B2B'),
@ -116,8 +116,8 @@ class MahnungVorschlag
}
/**
* Liefert alle ueberfaelligen Rechnungen, fuer die aktuell KEIN Vorschlag passt,
* inkl. Begruendung (skip_reason). Diagnose-Hilfe fuer das UI.
* Liefert alle überfälligen Rechnungen, r die aktuell KEIN Vorschlag passt,
* inkl. Begründung (skip_reason). Diagnose-Hilfe für das UI.
*
* @param array $filter (siehe getVorschlaege)
* @return array
@ -135,8 +135,8 @@ class MahnungVorschlag
}
/**
* Liefert sowohl vorgeschlagene als auch uebersprungene Rechnungen in einem Durchlauf.
* Result-Schluessel je Eintrag wie bei getVorschlaege(), zusaetzlich:
* Liefert sowohl vorgeschlagene als auch übersprungene Rechnungen in einem Durchlauf.
* Result-Schlüssel je Eintrag wie bei getVorschlaege(), zusätzlich:
* skip_reason (string|null)
*
* @param array $filter
@ -196,11 +196,11 @@ class MahnungVorschlag
}
/**
* Berechnet fuer eine einzelne Rechnung, ob/wozu eine Mahnung vorgeschlagen wird.
* Berechnet für eine einzelne Rechnung, ob/wozu eine Mahnung vorgeschlagen wird.
*
* @param object $factureObj DB-Reihe aus facture+societe
* @param int $today Unix-Zeit
* @param bool $includeSkipped true = liefert auch uebersprungene mit skip_reason
* @param bool $includeSkipped true = liefert auch übersprungene mit skip_reason
* @return array|null
*/
private function buildVorschlag($factureObj, $today, $includeSkipped = false)
@ -219,30 +219,33 @@ class MahnungVorschlag
// Letzte aktive Mahnung zur Rechnung holen
$lastMahnung = (new Mahnung($this->db))->fetchLastByFacture((int) $factureObj->facture_id);
// Naechste Stufe ermitteln
// Nächste Stufe ermitteln
$proposedStufe = null;
$skipReason = null;
global $langs;
$langs->load('mahnung@mahnung');
if ($lastMahnung === null) {
$frist1 = isset($this->stufen[1]) ? (int) $this->stufen[1]->frist_tage : 0;
if (!isset($this->stufen[1])) {
$skipReason = 'Stufe 1 nicht konfiguriert';
$skipReason = $langs->trans('MahnungVorschlagStufeNichtKonfiguriert');
} elseif ($tageVerzug >= $frist1) {
$proposedStufe = 1;
} else {
$skipReason = 'Frist Stufe 1 ('.$frist1.' Tage) noch nicht erreicht (Verzug '.$tageVerzug.' Tage)';
$skipReason = $langs->trans('MahnungVorschlagFristNichtErreicht', $frist1, $tageVerzug);
}
} else {
$lastStufe = (int) $lastMahnung->stufe;
$nextStufe = $lastStufe + 1;
if ($lastStufe >= 3 || !isset($this->stufen[$nextStufe])) {
$skipReason = 'Alle Mahnstufen ausgeschoepft (zuletzt Stufe '.$lastStufe.')';
$skipReason = $langs->trans('MahnungVorschlagAlleStufenAusgeschoepft', $lastStufe);
} else {
$wartefrist = isset($this->stufen[$lastStufe]) ? (int) $this->stufen[$lastStufe]->neue_frist_tage : 7;
$tageSeitMahnung = (int) floor(($today - $lastMahnung->date_mahnung) / 86400);
if ($tageSeitMahnung >= $wartefrist) {
$proposedStufe = $nextStufe;
} else {
$skipReason = 'Wartefrist nach Stufe '.$lastStufe.' laeuft noch ('.$tageSeitMahnung.'/'.$wartefrist.' Tage)';
$skipReason = $langs->trans('MahnungVorschlagWartefristLaeuft', $lastStufe, $tageSeitMahnung, $wartefrist);
}
}
}
@ -254,7 +257,7 @@ class MahnungVorschlag
return null;
}
$proposedStufe = null;
$skipReason = 'Offener Betrag <= 0 (vermutl. komplett bezahlt, paye-Flag noch nicht gesetzt)';
$skipReason = $langs->trans('MahnungVorschlagBetragNull');
}
if ($proposedStufe === null && !$includeSkipped) {
@ -320,7 +323,7 @@ class MahnungVorschlag
}
/**
* Gibt die geladene MahnungStufe (1..3) zurueck oder null.
* Gibt die geladene MahnungStufe (1..3) zurück oder null.
*
* @param int $stufe
* @return MahnungStufe|null

View file

@ -148,16 +148,15 @@ class box_mahnung_offen extends ModeleBoxes
$late = img_warning(sprintf($l_due_date, dol_print_date($datelimit, 'day', 'tzuserrel')));
}
// Mahnstufe-Badge (mit Link zur Mahnung) oder Strich fuer keine Mahnung
// Mahnstufe-Badge (mit Link zur Mahnung) oder Strich für keine Mahnung
$mahnCell = '<span class="opacitymedium">—</span>';
if (!empty($objp->mahnstufe)) {
$stufe = (int) $objp->mahnstufe;
$colors = array(1 => '#4a90d9', 2 => '#e68a00', 3 => '#cc3333');
$labels = array(1 => 'Stufe 1', 2 => 'Stufe 2', 3 => 'Stufe 3');
$color = $colors[$stufe] ?? '#666';
$label = $labels[$stufe] ?? 'Stufe '.$stufe;
$label = $langs->trans('MahnungBoxStufe', $stufe);
$mahnDatum = $objp->mahndatum ? dol_print_date($this->db->jdate($objp->mahndatum), 'day') : '';
$tooltip = $label.($mahnDatum ? ' vom '.$mahnDatum : '');
$tooltip = $mahnDatum ? $langs->trans('MahnungBoxStufeVom', $stufe, $mahnDatum) : $label;
$badge = '<span class="badge" style="background-color:'.$color.';color:#fff;font-size:0.75em;" title="'.dol_escape_htmltag($tooltip).'">'.$label.'</span>';
if (!empty($objp->mahnid)) {
$mahnCell = '<a href="'.DOL_URL_ROOT.'/custom/mahnung/card.php?id='.((int) $objp->mahnid).'">'.$badge.'</a>';
@ -187,7 +186,7 @@ class box_mahnung_offen extends ModeleBoxes
'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
);
// Spalte 4: Faelligkeitsdatum
// Spalte 4: Fälligkeitsdatum
$this->info_box_contents[$line][] = array(
'td' => 'class="center nowraponall" title="'.dol_escape_htmltag($langs->trans("DateDue").': '.dol_print_date($datelimit, 'day', 'tzuserrel')).'"',
'text' => dol_print_date($datelimit, 'day', 'tzuserrel'),

View file

@ -8,7 +8,7 @@
/**
* \file htdocs/custom/mahnung/core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php
* \ingroup mahnung
* \brief ODT-Template-Generator fuer Mahnschreiben.
* \brief ODT-Template-Generator für Mahnschreiben.
*
* Stufen-spezifische Templates: mahnung_stufe1.odt, mahnung_stufe2.odt, mahnung_stufe3.odt
* Fallback: beliebiges hochgeladenes .odt Template.
@ -25,7 +25,7 @@ require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
/**
* ODT-Template-basierter Dokumentengenerator fuer Mahnungen.
* ODT-Template-basierter Dokumentengenerator für Mahnungen.
*/
class doc_generic_mahnung_odt extends ModelePDFMahnung
{
@ -70,7 +70,7 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
}
/**
* Beschreibung und Template-Upload-Formular fuer die Admin-Seite.
* Beschreibung und Template-Upload-Formular für die Admin-Seite.
*
* @param Translate $langs
* @return string
@ -157,7 +157,7 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
$texte .= '<code>mahnung_stufe1.odt</code> = Zahlungserinnerung (Stufe 1)<br>';
$texte .= '<code>mahnung_stufe2.odt</code> = 1. Mahnung (Stufe 2)<br>';
$texte .= '<code>mahnung_stufe3.odt</code> = Letzte Mahnung (Stufe 3)<br>';
$texte .= '<code>mahnung.odt</code> = Fallback fuer alle Stufen';
$texte .= '<code>mahnung.odt</code> = Fallback für alle Stufen';
$texte .= '</div>';
// Upload-Feld
@ -227,7 +227,7 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
$this->error = 'Kunde '.((int) $mahnung->fk_soc).' nicht ladbar.';
return -1;
}
// Fuer die Standard-Substitution-Arrays
// Für die Standard-Substitution-Arrays
$mahnung->thirdparty = $societe;
$stufeObj = new MahnungStufe($this->db);
@ -310,7 +310,7 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
// Mahnung-spezifische Tags
$array_mahnung = $this->getMahnungSubstitutionArray($mahnung, $facture, $stufeObj, $outputlangs);
// Alles zusammenfuehren
// Alles zusammenführen
$tmparray = array_merge($substitutionarray, $array_common, $array_object_from_properties, $array_user, $array_soc, $array_thirdparty, $array_objet, $array_other, $array_mahnung);
complete_substitutions_array($tmparray, $outputlangs, $mahnung);
@ -335,7 +335,7 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
}
}
// Uebersetzungs-Labels
// Übersetzungs-Labels
$tmparray2 = $outputlangs->get_translations_for_substitutions();
foreach ($tmparray2 as $key => $value) {
try {
@ -379,7 +379,7 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
/**
* Sucht ein stufen-spezifisches Template (mahnung_stufe{N}.odt).
* Fallback: das uebergebene generische Template.
* Fallback: das übergebene generische Template.
*
* @param string $srctemplatepath Generisches Template (von commonGenerateDocument)
* @param int $stufe Mahnstufe 1-3
@ -486,19 +486,16 @@ class doc_generic_mahnung_odt extends ModelePDFMahnung
*/
private function defaultIntro($stufe)
{
global $langs;
$langs->load('mahnung@mahnung');
switch ((int) $stufe) {
case 1:
return 'unsere unten aufgefuehrte Rechnung ist trotz Ablauf der Zahlungsfrist noch nicht beglichen. '
. 'Vielleicht ist Ihnen dies entgangen — wir bitten Sie hoeflich, den ausstehenden Betrag zeitnah zu ueberweisen.';
return $langs->trans('MahnungPdfDefaultIntro1');
case 2:
return 'leider mussten wir feststellen, dass die unten aufgefuehrte Rechnung trotz unserer '
. 'Zahlungserinnerung weiterhin offen ist. Wir bitten Sie nun nachdruecklich um Begleichung '
. 'des offenen Betrags zuzueglich Verzugszinsen und Mahnkosten.';
return $langs->trans('MahnungPdfDefaultIntro2');
case 3:
default:
return 'wir haben Sie bereits zweimal an die Begleichung der unten aufgefuehrten Rechnung erinnert. '
. 'Sollte der offene Betrag inkl. Verzugszinsen und Mahnkosten nicht innerhalb der angegebenen Frist '
. 'auf unserem Konto eingehen, sehen wir uns gezwungen, weitere rechtliche Schritte einzuleiten.';
return $langs->trans('MahnungPdfDefaultIntro3');
}
}
}

View file

@ -8,7 +8,7 @@
/**
* \file htdocs/custom/mahnung/core/modules/mahnung/doc/pdf_standard_mahnung.modules.php
* \ingroup mahnung
* \brief Standard-PDF-Generator (TCPDF, DIN-5008) fuer Mahnschreiben.
* \brief Standard-PDF-Generator (TCPDF, DIN-5008) für Mahnschreiben.
*/
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
@ -19,7 +19,7 @@ require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
/**
* Standard-PDF-Generator fuer Mahnungen (DIN-5008 Form A, TCPDF).
* Standard-PDF-Generator für Mahnungen (DIN-5008 Form A, TCPDF).
*/
class pdf_standard_mahnung extends ModelePDFMahnung
{
@ -66,26 +66,26 @@ class pdf_standard_mahnung extends ModelePDFMahnung
// Rechnung + Kunde laden
$facture = new Facture($this->db);
if ($facture->fetch((int) $mahnung->fk_facture) <= 0) {
$this->error = 'Rechnung '.((int) $mahnung->fk_facture).' nicht ladbar.';
$this->error = $outputlangs->trans('MahnungPdfRechnungNichtLadbar', (int) $mahnung->fk_facture);
return -1;
}
$societe = new Societe($this->db);
if ($societe->fetch((int) $mahnung->fk_soc) <= 0) {
$this->error = 'Kunde '.((int) $mahnung->fk_soc).' nicht ladbar.';
$this->error = $outputlangs->trans('MahnungPdfKundeNichtLadbar', (int) $mahnung->fk_soc);
return -1;
}
$stufeObj = new MahnungStufe($this->db);
if ($stufeObj->fetchByStufe((int) $mahnung->stufe) <= 0) {
$this->error = 'Mahnstufe '.((int) $mahnung->stufe).' nicht konfiguriert.';
$this->error = $outputlangs->trans('MahnungPdfStufeNichtKonfiguriert', (int) $mahnung->stufe);
return -1;
}
// Ziel-Verzeichnis
$dirOutput = $this->getOutputDir($mahnung, $facture);
if (dol_mkdir($dirOutput) < 0) {
$this->error = 'Kann Verzeichnis nicht anlegen: '.$dirOutput;
$this->error = $outputlangs->trans('MahnungPdfVerzeichnisFehler', $dirOutput);
return -1;
}
$filename = 'mahnung-'.((int) $mahnung->stufe).'-'.dol_sanitizeFileName($mahnung->ref).'.pdf';
@ -167,7 +167,7 @@ class pdf_standard_mahnung extends ModelePDFMahnung
}
/**
* Anrede, Intro, Tabelle, Gebuehrenblock, Gesamtsumme, neue Frist.
* Anrede, Intro, Tabelle, Gebührenblock, Gesamtsumme, neue Frist.
*/
private function renderBody($pdf, $facture, $societe, $mahnung, $stufe, $outputlangs)
{
@ -176,7 +176,7 @@ class pdf_standard_mahnung extends ModelePDFMahnung
$pdf->SetFont('helvetica', '', 11);
$pdf->SetXY(25, 110);
$pdf->Cell(0, 5, 'Sehr geehrte Damen und Herren,', 0, 1, 'L');
$pdf->Cell(0, 5, $outputlangs->trans('MahnungPdfAnrede'), 0, 1, 'L');
$pdf->SetX(25);
$pdf->Ln(2);
@ -207,7 +207,7 @@ class pdf_standard_mahnung extends ModelePDFMahnung
$pdf->Cell(30, 6, price((float) $mahnung->betrag_offen).' EUR', 0, 1, 'R');
$pdf->Ln(3);
// Gebuehrenblock
// Gebührenblock
$pdf->SetX(25);
$pdf->SetFont('helvetica', '', 10);
$pdf->Cell(130, 6, $outputlangs->trans('MahnungBetragOffen'), 0, 0, 'L');
@ -247,13 +247,13 @@ class pdf_standard_mahnung extends ModelePDFMahnung
$pdf->SetFont('helvetica', '', 11);
$frist = $mahnung->date_lim_reglement_neu ? dol_print_date($mahnung->date_lim_reglement_neu, 'day') : '';
$fristText = empty($frist)
? 'Wir bitten Sie um umgehende Begleichung.'
: 'Wir bitten Sie, den ausstehenden Betrag bis spaetestens '.$frist.' auf das unten genannte Konto zu ueberweisen.';
? $outputlangs->trans('MahnungPdfFristUmgehend')
: $outputlangs->trans('MahnungPdfFristBis', $frist);
$pdf->MultiCell(160, 5, $fristText, 0, 'L');
$pdf->Ln(4);
$pdf->SetX(25);
$pdf->Cell(0, 5, 'Mit freundlichen Gruessen', 0, 1, 'L');
$pdf->Cell(0, 5, $outputlangs->trans('MahnungPdfGruss'), 0, 1, 'L');
$pdf->SetX(25);
$pdf->Cell(0, 5, (string) $mysoc->name, 0, 1, 'L');
}
@ -263,17 +263,18 @@ class pdf_standard_mahnung extends ModelePDFMahnung
*/
private function renderFooter($pdf)
{
global $mysoc;
global $mysoc, $langs;
$langs->load('mahnung@mahnung');
$pdf->SetY(-30);
$pdf->SetFont('helvetica', 'I', 8);
$lines = array();
$lines[] = trim(($mysoc->name ?? '').' · '.($mysoc->address ?? '').' · '.($mysoc->zip ?? '').' '.($mysoc->town ?? ''));
if (!empty($mysoc->email)) {
$lines[] = 'E-Mail: '.$mysoc->email;
$lines[] = $langs->trans('MahnungPdfFooterEmail', $mysoc->email);
}
if (!empty($mysoc->phone)) {
$lines[] = 'Tel: '.$mysoc->phone;
$lines[] = $langs->trans('MahnungPdfFooterTel', $mysoc->phone);
}
$bankLine = $this->getDefaultBankLine();
if (!empty($bankLine)) {
@ -312,20 +313,16 @@ class pdf_standard_mahnung extends ModelePDFMahnung
*/
private function defaultIntro($stufe)
{
global $langs;
$langs->load('mahnung@mahnung');
switch ((int) $stufe) {
case 1:
return 'unsere unten aufgefuehrte Rechnung ist trotz Ablauf der Zahlungsfrist noch nicht beglichen. '
. 'Vielleicht ist Ihnen dies entgangen — wir bitten Sie hoeflich, den ausstehenden Betrag zeitnah '
. 'zu ueberweisen.';
return $langs->trans('MahnungPdfDefaultIntro1');
case 2:
return 'leider mussten wir feststellen, dass die unten aufgefuehrte Rechnung trotz unserer '
. 'Zahlungserinnerung weiterhin offen ist. Wir bitten Sie nun nachdruecklich um Begleichung '
. 'des offenen Betrags zuzueglich Verzugszinsen und Mahnkosten.';
return $langs->trans('MahnungPdfDefaultIntro2');
case 3:
default:
return 'wir haben Sie bereits zweimal an die Begleichung der unten aufgefuehrten Rechnung erinnert. '
. 'Sollte der offene Betrag inkl. Verzugszinsen und Mahnkosten nicht innerhalb der angegebenen Frist '
. 'auf unserem Konto eingehen, sehen wir uns gezwungen, weitere rechtliche Schritte einzuleiten.';
return $langs->trans('MahnungPdfDefaultIntro3');
}
}

View file

@ -8,7 +8,7 @@
/**
* \file htdocs/custom/mahnung/core/modules/mahnung/modules_mahnung.php
* \ingroup mahnung
* \brief Abstrakte Basis-Klasse fuer Mahnung-Dokumentengeneratoren.
* \brief Abstrakte Basis-Klasse für Mahnung-Dokumentengeneratoren.
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php';
@ -20,10 +20,10 @@ abstract class ModelePDFMahnung extends CommonDocGenerator
{
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Gibt die Liste der aktiven Dokumentenmodelle zurueck.
* Gibt die Liste der aktiven Dokumentenmodelle zurück.
*
* @param DoliDB $db Datenbank-Handler
* @param int $maxfilenamelength Max Laenge
* @param int $maxfilenamelength Max Länge
* @return array|int
*/
public static function liste_modeles($db, $maxfilenamelength = 0)

View file

@ -22,7 +22,7 @@
include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
/**
* Beschreibungs- und Aktivierungsklasse fuer Modul Mahnung
* Beschreibungs- und Aktivierungsklasse für Modul Mahnung
*/
class modMahnung extends DolibarrModules
{
@ -40,7 +40,7 @@ class modMahnung extends DolibarrModules
// 500037 ist durch Eplan belegt, daher 500038.
$this->numero = 500038;
// Schluessel fuer Rechte und Menues
// Schlüssel für Rechte und Menüs
$this->rights_class = 'mahnung';
$this->family = 'financial';
@ -51,7 +51,7 @@ class modMahnung extends DolibarrModules
$this->description = 'MahnungDescription';
$this->descriptionlong = 'MahnungDescription';
$this->editor_name = 'Alles Watt laeuft';
$this->editor_name = 'Alles Watt läuft';
$this->editor_url = '';
$this->version = '0.2.0';
@ -118,7 +118,7 @@ class modMahnung extends DolibarrModules
'MAHNUNG_BASISZINS',
'chaine',
'1.27',
'BGB-Basiszins in Prozent (manuell halbjaehrlich pflegen)',
'BGB-Basiszins in Prozent (manuell halbjährlich pflegen)',
0,
'allentities',
1,
@ -127,7 +127,7 @@ class modMahnung extends DolibarrModules
'MAHNUNG_NTFY_TOPIC',
'chaine',
'vk-builds',
'Ntfy-Topic fuer Mahnungs-Benachrichtigungen',
'Ntfy-Topic für Mahnungs-Benachrichtigungen',
0,
'current',
1,
@ -163,7 +163,7 @@ class modMahnung extends DolibarrModules
'MAHNUNG_ADDON_PDF',
'chaine',
'standard_mahnung',
'Standard-Dokumentenmodell fuer Mahnungen',
'Standard-Dokumentenmodell für Mahnungen',
0,
'current',
1,
@ -172,7 +172,7 @@ class modMahnung extends DolibarrModules
'MAHNUNG_ADDON_PDF_ODT_PATH',
'chaine',
'DOL_DATA_ROOT/doctemplates/mahnung',
'Verzeichnis fuer ODT-Templates',
'Verzeichnis für ODT-Templates',
0,
'current',
1,
@ -196,7 +196,7 @@ class modMahnung extends DolibarrModules
),
);
// Cron-Job: Vorschlagsliste taeglich 06:00
// Cron-Job: Vorschlagsliste täglich 06:00
$this->cronjobs = array(
0 => array(
'label' => 'MahnungCronBuildVorschlag',
@ -205,7 +205,7 @@ class modMahnung extends DolibarrModules
'objectname' => 'MahnungCron',
'method' => 'buildVorschlagsliste',
'parameters' => '',
'comment' => 'Sucht ueberfaellige Rechnungen, ermittelt vorgeschlagene Mahnstufen, sendet Ntfy-Push',
'comment' => 'MahnungCronCommentBuild',
'frequency' => 1,
'unitfrequency' => 86400,
'status' => 1,
@ -219,7 +219,7 @@ class modMahnung extends DolibarrModules
'objectname' => 'MahnungCron',
'method' => 'versandReminder',
'parameters' => '',
'comment' => 'Erinnert per Ntfy an Mahnungen mit Status ERSTELLT, die seit > N Tagen nicht versendet wurden (MAHNUNG_VERSAND_REMINDER_DAYS, Default 2)',
'comment' => 'MahnungCronCommentReminder',
'frequency' => 1,
'unitfrequency' => 86400,
'status' => 1,
@ -316,7 +316,7 @@ class modMahnung extends DolibarrModules
}
/**
* Aufruf bei Modul-Aktivierung: Tabellen anlegen, Konstanten/Rechte/Menues schreiben.
* Aufruf bei Modul-Aktivierung: Tabellen anlegen, Konstanten/Rechte/Menüs schreiben.
*
* @param string $options Optionen ('', 'noboxes')
* @return int<-1,1> 1 = OK, <=0 = Fehler
@ -331,7 +331,7 @@ class modMahnung extends DolibarrModules
return -1;
}
// Migration: Versand-Felder ergaenzen, falls Tabelle aus alter Version stammt
// Migration: Versand-Felder ergänzen, falls Tabelle aus alter Version stammt
$this->migrateVersandFelder();
// Default-Tracking-Patterns seeden (idempotent — nur beim ersten Mal)
@ -365,9 +365,9 @@ class modMahnung extends DolibarrModules
}
/**
* Ergaenzt Versand- und Tracking-Felder an llx_mahnung_mahnung, wenn sie
* in einer aelteren Schema-Version noch fehlen. Idempotent fehlende
* Spalten werden geprueft via SHOW COLUMNS und nur dann hinzugefuegt.
* Ergänzt Versand- und Tracking-Felder an llx_mahnung_mahnung, wenn sie
* in einer älteren Schema-Version noch fehlen. Idempotent fehlende
* Spalten werden geprüft via SHOW COLUMNS und nur dann hinzugefügt.
*
* @return void
*/

View file

@ -10,7 +10,7 @@
/**
* \file core/triggers/interface_99_modMahnung_MahnungTriggers.class.php
* \ingroup mahnung
* \brief Trigger: setzt offene Mahnvorgaenge nach Zahlungseingang auf "erledigt".
* \brief Trigger: setzt offene Mahnvorgänge nach Zahlungseingang auf "erledigt".
*
* Klassenname: Interface<Suffix>Triggers Suffix muss zu Dateinamen passen.
* Datei muss in core/triggers/ liegen, wird durch DolibarrModules->loadtriggers
@ -28,7 +28,7 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
{
parent::__construct($db);
$this->family = 'financial';
$this->description = 'Mahnung-Trigger: erledigt offene Mahnvorgaenge bei Zahlungseingang.';
$this->description = 'MahnungTriggerBeschreibung';
$this->version = self::VERSIONS['dev'];
$this->picto = 'fa-envelope-open-text';
}
@ -59,7 +59,7 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
return 0;
case 'PAYMENT_CUSTOMER_CREATE':
// $object ist Paiement; eventuell auch ohne paye=1 Status — pro betroffener Rechnung pruefen
// $object ist Paiement; eventuell auch ohne paye=1 Status — pro betroffener Rechnung prüfen
return $this->onPaiementErzeugt($object, $user);
default:
@ -68,7 +68,7 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
}
/**
* Setzt alle offenen Mahnvorgaenge zur Rechnung auf STATUS_ERLEDIGT.
* Setzt alle offenen Mahnvorgänge zur Rechnung auf STATUS_ERLEDIGT.
*
* @param int $factureId
* @param User $user
@ -96,8 +96,8 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
}
$this->db->free($resql);
// Wenn Mahnungen erledigt wurden: pruefen ob noch offene uebrig sind.
// Falls nicht, GlobalNotify-Badge raeumen.
// Wenn Mahnungen erledigt wurden: prüfen ob noch offene übrig sind.
// Falls nicht, GlobalNotify-Badge räumen.
if ($count > 0 && !$this->hatOffeneMahnungen()) {
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungcron.class.php';
MahnungCron::clearGlobalNotify();
@ -107,10 +107,10 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
}
/**
* Bei Zahlungs-Erzeugung: alle betroffenen Rechnungen pruefen, ob sie nun
* vollstaendig bezahlt sind. paye-Flag wird in Dolibarr typischerweise erst
* gesetzt, wenn Summe der Zahlungen >= total_ttc wir pruefen pessimistisch:
* sobald ueberhaupt eine Zahlung kommt + offene Mahnung existiert -> erledigen,
* Bei Zahlungs-Erzeugung: alle betroffenen Rechnungen prüfen, ob sie nun
* vollständig bezahlt sind. paye-Flag wird in Dolibarr typischerweise erst
* gesetzt, wenn Summe der Zahlungen >= total_ttc wir prüfen pessimistisch:
* sobald überhaupt eine Zahlung kommt + offene Mahnung existiert -> erledigen,
* wenn die Zahlung den offenen Betrag deckt.
*
* @param CommonObject $payment
@ -128,7 +128,7 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
if ($factureId <= 0) {
continue;
}
// Pruefen, ob die Rechnung jetzt voll bezahlt ist
// Prüfen, ob die Rechnung jetzt voll bezahlt ist
if ($this->istRechnungVollBezahlt($factureId)) {
$total += $this->onRechnungBezahlt($factureId, $user);
}
@ -137,7 +137,7 @@ class InterfaceMahnungTriggers extends DolibarrTriggers
}
/**
* Prueft ob noch offene Mahnvorgaenge existieren (Status weder erledigt noch storniert).
* Prüft ob noch offene Mahnvorgänge existieren (Status weder erledigt noch storniert).
*
* @return bool true wenn mindestens eine offene Mahnung existiert
*/

View file

@ -5,7 +5,7 @@
#
ModuleMahnungName = Mahnung
ModuleMahnungDesc = Mahnwesen mit Vorschlagsliste, Stufen, Verzugszinsen (BGB §288)
MahnungDescription = 3-stufiges Mahnwesen fuer ueberfaellige Kundenrechnungen mit Mahngebuehren, Verzugszinsen nach BGB §288 und PDF-Versand.
MahnungDescription = 3-stufiges Mahnwesen für überfällige Kundenrechnungen mit Mahngebühren, Verzugszinsen nach BGB §288 und PDF-Versand.
#
# Berechtigungen
@ -13,15 +13,15 @@ MahnungDescription = 3-stufiges Mahnwesen fuer ueberfaellige Kundenrechnungen mi
PermMahnungRead = Mahnungen lesen
PermMahnungWrite = Mahnungen erstellen / bearbeiten
PermMahnungSend = Mahnungen versenden (E-Mail / Druck)
PermMahnungDelete = Mahnungen loeschen
PermMahnungDelete = Mahnungen löschen
PermMahnungSetup = Mahnwesen konfigurieren
#
# Menues
# Menüs
#
MahnungMenu = Mahnwesen
MahnungVorschlagsliste = Vorschlagsliste
MahnungArchiv = Mahnvorgaenge
MahnungArchiv = Mahnvorgänge
#
# Stufen
@ -31,10 +31,10 @@ MahnungStufe1 = Zahlungserinnerung
MahnungStufe2 = 1. Mahnung
MahnungStufe3 = Letzte Mahnung
MahnungStufeLabel = Bezeichnung
MahnungStufeFristTage = Frist (Tage nach Faelligkeit)
MahnungStufeFristTage = Frist (Tage nach Fälligkeit)
MahnungStufeNeueFristTage = Neue Zahlungsfrist (Tage)
MahnungStufeGebuehrB2C = Mahngebuehr B2C
MahnungStufeGebuehrB2B = Mahngebuehr B2B
MahnungStufeGebuehrB2C = Mahngebühr B2C
MahnungStufeGebuehrB2B = Mahngebühr B2B
MahnungStufeZinssatzB2C = Zinssatz B2C (Override)
MahnungStufeZinssatzB2B = Zinssatz B2B (Override)
MahnungStufeVersandartDefault = Versandart-Default
@ -73,7 +73,7 @@ MahnungVersandwegHermes = Hermes
MahnungVersandwegUps = UPS
MahnungVersandwegFax = Fax
MahnungVersandwegEmail = E-Mail
MahnungVersandwegPersoenlich = Persoenliche Uebergabe
MahnungVersandwegPersoenlich = Persönliche Übergabe
MahnungVersandwegEigen = Eigener Versand
MahnungTrackingNr = Sendungsnummer
MahnungTrackingNrHint = z.B. 1234567890 (DHL), RR123456789DE (Einschreiben)
@ -81,37 +81,37 @@ MahnungTrackingProvider = Anbieter
MahnungTrackingProviderAuto = automatisch erkennen
MahnungSendungVerfolgen = Sendung verfolgen
MahnungVersandBearbeiten = Versand bearbeiten
MahnungVersandLeeren = Versand zuruecksetzen
MahnungVersandLeerenConfirm = Versanddaten wirklich zuruecksetzen? Status bleibt unveraendert.
MahnungVersandLeeren = Versand zurücksetzen
MahnungVersandLeerenConfirm = Versanddaten wirklich zurücksetzen? Status bleibt unverändert.
MahnungVersandGespeichert = Versanddaten gespeichert
MahnungVersandGeleert = Versanddaten zurueckgesetzt
MahnungVersandGeleert = Versanddaten zurückgesetzt
MahnungSendebelege = Sendebelege
MahnungSendebelegeHint = Hier Beleg von Post/DHL/Fax/Mail hochladen (PDF, Foto). Bleibt am Mahnvorgang fuer spaetere Nachweise.
MahnungSendebelegeHint = Hier Beleg von Post/DHL/Fax/Mail hochladen (PDF, Foto). Bleibt am Mahnvorgang für spätere Nachweise.
#
# Tracking-Patterns (Phase 3)
#
MahnungTrackingPatternsSetup = Tracking-Muster (Regex)
MahnungTrackingPatternsIntro = Hier konfigurierst du, welche Regex auf den Text eines hochgeladenen Sendebelegs angewendet werden, um die Sendungsnummer + den passenden Provider automatisch zu erkennen. Reihenfolge: hoechste Prioritaet zuerst.
MahnungTrackingPatternsIntro = Hier konfigurierst du, welche Regex auf den Text eines hochgeladenen Sendebelegs angewendet werden, um die Sendungsnummer + den passenden Provider automatisch zu erkennen. Reihenfolge: höchste Priorität zuerst.
MahnungTrackingPatternsEmpty = Keine Tracking-Muster konfiguriert. Beim ersten Aufruf werden Standard-Muster eingesetzt.
MahnungTrackingPatternLabel = Bezeichnung
MahnungTrackingPatternProvider = Provider-Schluessel
MahnungTrackingPatternProvider = Provider-Schlüssel
MahnungTrackingPatternRegex = Regex (mit Delimiter / # ~)
MahnungTrackingPatternUrlTemplate = URL-Template
MahnungTrackingPatternUrlHint = https-URL mit Platzhalter <code>{nr}</code> — wird mit der erkannten Sendungsnummer ersetzt.
MahnungTrackingPatternPriority = Prioritaet
MahnungTrackingPatternPriorityHint = Hoeher = wird zuerst gepruef (z.B. 90 fuer spezifisch, 20 fuer generisch).
MahnungTrackingPatternPriority = Priorität
MahnungTrackingPatternPriorityHint = Höher = wird zuerst geprüft (z.B. 90 für spezifisch, 20 für generisch).
MahnungTrackingPatternSample = Beispieltext (Live-Vorschau)
MahnungTrackingPatternSamplePlaceholder = Hier ein Beispiel-Beleg-Text einfuegen — Treffer + URL erscheinen live unten.
MahnungTrackingPatternSamplePlaceholder = Hier ein Beispiel-Beleg-Text einfügen — Treffer + URL erscheinen live unten.
MahnungTrackingPatternMatch = Treffer
MahnungTrackingPatternNoMatch = Kein Treffer im Beispieltext.
MahnungTrackingPatternRegexValid = Regex syntaktisch gueltig.
MahnungTrackingPatternRegexInvalid = Regex ungueltig.
MahnungTrackingPatternRegexValid = Regex syntaktisch gültig.
MahnungTrackingPatternRegexInvalid = Regex ungültig.
MahnungTrackingPatternNewTitle = Neues Muster anlegen
MahnungTrackingPatternEditTitle = Muster bearbeiten
MahnungTrackingPatternSaved = Muster gespeichert.
MahnungTrackingPatternDeleted = Muster geloescht.
MahnungTrackingPatternProviderRequired = Provider-Schluessel fehlt.
MahnungTrackingPatternDeleted = Muster gelöscht.
MahnungTrackingPatternProviderRequired = Provider-Schlüssel fehlt.
MahnungTrackingPatternLabelRequired = Bezeichnung fehlt.
MahnungTrackingPatternUrlMustHttps = URL-Template muss mit https:// beginnen.
MahnungTrackingPatternUrlMissingPlaceholder = URL-Template muss den Platzhalter {nr} enthalten.
@ -122,27 +122,27 @@ MahnungTrackingPatternUrlMissingPlaceholder = URL-Template muss den Platzhalter
MahnungBelegeScannen = Belege scannen
MahnungBelegeScannenHint = Hochgeladene PDFs nach Sendungsnummer durchsuchen (pdftotext + Regex)
MahnungTrackingErkannt = Sendungsnummern erkannt
MahnungTrackingUebernehmen = Uebernehmen
MahnungTrackingUebernommen = Sendungsnummer uebernommen
MahnungTrackingVerwerfen = Vorschlaege verwerfen
MahnungPdftotextMissing = pdftotext nicht im Container verfuegbar — PDFs koennen nicht durchsucht werden. Nur txt/html werden gescannt.
MahnungTrackingUebernehmen = Übernehmen
MahnungTrackingUebernommen = Sendungsnummer übernommen
MahnungTrackingVerwerfen = Vorschläge verwerfen
MahnungPdftotextMissing = pdftotext nicht im Container verfügbar — PDFs können nicht durchsucht werden. Nur txt/html werden gescannt.
#
# Bonitaet / Forderungsausfall (Phase 6)
# Bonität / Forderungsausfall (Phase 6)
#
MahnungBonitaetWarnung = Forderungsausfaelle vorhanden — Bonitaet pruefen
MahnungBonitaetWarnungKurz = Bonitaet
MahnungBonitaetWarnung = Forderungsausfälle vorhanden — Bonität prüfen
MahnungBonitaetWarnungKurz = Bonität
MahnungBonitaetRechnungSing = abgeschriebene Rechnung
MahnungBonitaetRechnungPlur = abgeschriebene Rechnungen
MahnungBonitaetGesamtAusfall = gesamter Ausfall
MahnungBonitaetLetzteAm = Letzte Abschreibung am
MahnungBonitaetAusfaelleAnzeigen = Abgeschriebene Rechnungen anzeigen
MahnungBonitaetKundeHat = Dieser Kunde hat %d uneinbringliche Rechnung(en) in Hoehe von %s. Vor neuem Geschaeft Bonitaet pruefen.
MahnungBonitaetKundeHat = Dieser Kunde hat %d uneinbringliche Rechnung(en) in Höhe von %s. Vor neuem Geschäft Bonität prüfen.
MahnungUneinbringlich = Als uneinbringlich klassifizieren
MahnungUneinbringlichHint = Rechnung wird als abandoned + close_code='badcustomer' markiert. Endgueltiger Schritt nach erfolglosem Mahnverfahren / Vollstreckung.
MahnungUneinbringlichHint = Rechnung wird als abandoned + close_code='badcustomer' markiert. Endgültiger Schritt nach erfolglosem Mahnverfahren / Vollstreckung.
MahnungUneinbringlichTitel = Forderung als uneinbringlich klassifizieren
MahnungUneinbringlichWarnung = Achtung: Dieser Schritt ist (fast) endgueltig. Die Rechnung wird auf STATUS_ABANDONED gesetzt und die Mahnung storniert. Bitte VORHER sicherstellen: Mahnbescheid + Vollstreckungsversuch erfolglos ODER Insolvenz nachgewiesen ODER Verjaehrung eingetreten. Weiter mit
MahnungUneinbringlichBegruendung = Begruendung (z.B. Vollstreckungsbescheid vom ..., Insolvenz-Aktenzeichen)
MahnungUneinbringlichWarnung = Achtung: Dieser Schritt ist (fast) endgültig. Die Rechnung wird auf STATUS_ABANDONED gesetzt und die Mahnung storniert. Bitte VORHER sicherstellen: Mahnbescheid + Vollstreckungsversuch erfolglos ODER Insolvenz nachgewiesen ODER Verjährung eingetreten. Weiter mit
MahnungUneinbringlichBegruendung = Begründung (z.B. Vollstreckungsbescheid vom ..., Insolvenz-Aktenzeichen)
MahnungUneinbringlichErfolg = Rechnung als uneinbringlich klassifiziert + Mahnung storniert
MahnungRechnungBereitsUneinbringlich = Rechnung bereits abandoned
@ -155,13 +155,13 @@ MahnungKunde = Kunde
MahnungKontakt = Kontakt
MahnungKundentyp = Typ
MahnungKundentypB2C = Privat (B2C)
MahnungKundentypB2B = Geschaeftlich (B2B)
MahnungKundentypB2B = Geschäftlich (B2B)
MahnungDatum = Mahndatum
MahnungFaelligkeitAlt = Original-Faelligkeit
MahnungFaelligkeitAlt = Original-Fälligkeit
MahnungFaelligkeitNeu = Neue Frist
MahnungTageVerzug = Tage Verzug
MahnungBetragOffen = Offener Betrag
MahnungGebuehr = Mahngebuehr
MahnungGebuehr = Mahngebühr
MahnungPauschaleB2B = Pauschale (40 € §288)
MahnungVerzugszinsen = Verzugszinsen
MahnungSumme = Gesamtsumme
@ -172,9 +172,9 @@ MahnungAktion = Aktion
MahnungErstellen = Mahnung erstellen
MahnungSammelbrief = Sammelbrief erzeugen
MahnungStornieren = Stornieren
MahnungKeineUeberfaelligen = Keine ueberfaelligen Rechnungen vorhanden.
MahnungUebersprungen = Aktuell uebersprungene Rechnungen
MahnungUebersprungenHint = Diese Rechnungen sind ueberfaellig, werden aber aktuell nicht vorgeschlagen (Wartefrist laeuft noch oder alle Mahnstufen ausgeschoepft).
MahnungKeineUeberfaelligen = Keine überfälligen Rechnungen vorhanden.
MahnungUebersprungen = Aktuell übersprungene Rechnungen
MahnungUebersprungenHint = Diese Rechnungen sind überfällig, werden aber aktuell nicht vorgeschlagen (Wartefrist läuft noch oder alle Mahnstufen ausgeschöpft).
MahnungSkipGrund = Grund
#
@ -184,12 +184,12 @@ MahnungSetup = Mahnwesen Einstellungen
MahnungSetupPage = Mahnwesen Konfiguration
MahnungSetupDescription = Mahnstufen, Basiszins, Versandwege und Ntfy-Topic konfigurieren.
MahnungBasiszins = BGB-Basiszins (%)
MahnungBasiszinsHelp = Aktueller Basiszins der Bundesbank, halbjaehrlich pflegen (1.1. / 1.7.).
MahnungBasiszinsHelp = Aktueller Basiszins der Bundesbank, halbjährlich pflegen (1.1. / 1.7.).
MahnungAufschlagB2C = Aufschlag B2C (%)
MahnungAufschlagB2B = Aufschlag B2B (%)
MahnungPauschaleB2BLabel = Pauschale B2B (EUR)
MahnungNtfyTopic = Ntfy-Topic
MahnungNtfyTopicHelp = Topic fuer Push-Benachrichtigungen (Default: vk-builds).
MahnungNtfyTopicHelp = Topic für Push-Benachrichtigungen (Default: vk-builds).
MahnungSettingsSaved = Einstellungen gespeichert.
#
@ -197,12 +197,12 @@ MahnungSettingsSaved = Einstellungen gespeichert.
#
MahnungCronBuildVorschlag = Mahnwesen — Vorschlagsliste aufbauen
MahnungCronVersandReminder = Mahnwesen — Versand-Reminder (unversendete Mahnungen)
MahnungCronBuildVorschlagDesc = Sucht taeglich ueberfaellige Rechnungen und sendet einen Ntfy-Push mit der Anzahl neuer Vorschlaege.
MahnungCronBuildVorschlagDesc = Sucht täglich überfällige Rechnungen und sendet einen Ntfy-Push mit der Anzahl neuer Vorschläge.
#
# Widget
#
MahnungBoxOffeneRechnungen = Ueberfaellige Rechnungen mit Mahnstufe (%s)
MahnungBoxOffeneRechnungen = Überfällige Rechnungen mit Mahnstufe (%s)
#
# Dokumentenmodelle
@ -211,4 +211,165 @@ MahnungDokumentModelle = Dokumentenmodelle
MahnungPdfStandard = Standard-PDF (DIN 5008)
MahnungGenerate = Dokument generieren
NoDocuments = Keine Dokumente vorhanden.
MahnungDokumentLoeschenConfirm = Dokument '%s' wirklich loeschen?
MahnungDokumentLoeschenConfirm = Dokument '%s' wirklich löschen?
#
# Hardcoded-Strings (i18n)
#
MahnungDokumentErstellt = Dokument erstellt
MahnungDokumentFehler = Dokument-Fehler
MahnungDateiNichtGefunden = Datei nicht gefunden oder nicht zugehörig
MahnungFehlerSpeichern = Fehler beim Speichern
MahnungVerfahrenErfolglos = Mahnverfahren erfolglos abgeschlossen am
MahnungFehlerKlassifizieren = Fehler beim Klassifizieren
MahnungRechnungNichtLadbar = Rechnung nicht ladbar
MahnungUneinbringlichKlassifiziert = Uneinbringlich klassifiziert
MahnungKeineVorgaenge = Keine Mahnvorgänge.
MahnungStufeAmDatum = Stufe %s am %s
MahnungCronKeineUeberfaellige = Keine überfälligen Rechnungen mit fälliger Mahnung.
MahnungCronOffeneVorschlaege = Mahnwesen: %s offene Vorschläge
MahnungCronStufe1Erinnerung = Stufe 1 (Erinnerung): %s
MahnungCronStufe2Mahnung = Stufe 2 (Mahnung): %s
MahnungCronStufe3LetzteMahnung = Stufe 3 (Letzte Mahnung): %s
MahnungCronOffenerBetrag = Offener Betrag: %s EUR
MahnungCronVorschlaege = Mahnwesen: %s Vorschläge
MahnungCronVorschlagslisteOeffnen = Vorschlagsliste öffnen
MahnungCronKeineUnversendet = Keine Mahnungen unversendet > %s Tage.
MahnungCronUnversendetTitel = Mahnwesen: %s Mahnung(en) unversendet
MahnungCronStufeAlter = %s (Stufe %s, %s Tage alt) — %s
MahnungCronWeitere = + %s weitere
MahnungCronArchivOeffnen = Archiv öffnen
MahnungCronEintraege = %s — %s Einträge
MahnungCsrfFehler = Token-Verifikation fehlgeschlagen (CSRF).
MahnungNichtBerechtigt = Nicht berechtigt.
MahnungKeineRechnungenAusgewaehlt = Keine Rechnungen ausgewählt.
MahnungStufeNichtKonfiguriert = Rechnung #%s: Stufe %s nicht konfiguriert
MahnungMahnungErstellt = %s Mahnung(en) erstellt
MahnungUebersprungen2 = , %s übersprungen (Wartefrist)
MahnungFehlerLabel = — Fehler: %s
MahnungCsrfTokenUngueltig = CSRF-Token ungültig.
MahnungNichtBerechtigtSend = Nicht berechtigt (mahnung.send).
MahnungIdFehlt = mahnung_id fehlt.
MahnungNichtGefunden = Mahnung %s nicht gefunden.
MahnungPdfFehlt = PDF zur Mahnung %s fehlt — bitte zuerst Mahnung erzeugen.
MahnungKundeNichtLadbar = Kunde nicht ladbar.
MahnungKundeKeineEmail = Kunde hat keine E-Mail-Adresse hinterlegt.
MahnungEmailGesendet = E-Mail an %s gesendet.
MahnungEmailFehlgeschlagen = E-Mail-Versand fehlgeschlagen: %s
MahnungSammelbriefNichtBerechtigt = Nicht berechtigt.
MahnungSammelbriefCsrfFehler = Token-Verifikation fehlgeschlagen.
MahnungSammelbriefKeinePdfs = Keine PDFs erzeugt — prüfe ob die Rechnungen mahnreif sind.
MahnungSammelbriefFehler = Sammelbrief-PDF konnte nicht erzeugt werden.
MahnungTemplateVarsTitle = Mahnung — Template-Variablen
MahnungTemplateVarsHeader = Verfügbare Variablen für ODT-Templates
MahnungTemplateVarsBackToSetup = Zurück zum Setup
MahnungTemplateVarsIntro = Diese Variablen können in ODT-Templates mit geschweiften Klammern verwendet werden, z.B. <code>{mahnung_ref}</code>.
MahnungTemplateVarsIntro2 = Stufen-spezifische Templates: <code>mahnung_stufe1.odt</code>, <code>mahnung_stufe2.odt</code>, <code>mahnung_stufe3.odt</code> — Fallback: beliebiges <code>.odt</code> im Template-Verzeichnis.
MahnungTemplateVarsGrpMahnung = Mahnung
MahnungTemplateVarsGrpRechnung = Verknüpfte Rechnung
MahnungTemplateVarsGrpFirma = Eigene Firma (Absender)
MahnungTemplateVarsGrpKunde = Kunde (Empfänger)
MahnungTemplateVarsGrpBank = Bankverbindung
MahnungTemplateVarsGrpStandard = Dolibarr-Standard (Auswahl)
MahnungTemplateVarsColVariable = Variable
MahnungTemplateVarsColBeschreibung = Beschreibung
MahnungTemplateVarsColBeispiel = Beispiel
MahnungTemplateVarMahnungRef = Mahnung-Referenznummer
MahnungTemplateVarMahnungStufe = Mahnstufe (Nummer)
MahnungTemplateVarMahnungStufeLabel = Bezeichnung der Mahnstufe
MahnungTemplateVarMahnungDate = Datum der Mahnung
MahnungTemplateVarMahnungDateLimAlt = Ursprüngliches Fälligkeitsdatum der Rechnung
MahnungTemplateVarMahnungDateLimNeu = Neue Zahlungsfrist
MahnungTemplateVarMahnungBetragOffen = Offener Rechnungsbetrag
MahnungTemplateVarMahnungMahngebuehr = Mahngebühr dieser Stufe
MahnungTemplateVarMahnungPauschale = B2B-Pauschale nach BGB §288 Abs. 5
MahnungTemplateVarMahnungVerzugszinsen = Berechnete Verzugszinsen
MahnungTemplateVarMahnungSumme = Gesamtforderung (offen + Gebühren + Zinsen)
MahnungTemplateVarMahnungBasiszins = BGB-Basiszinssatz (Snapshot bei Erstellung)
MahnungTemplateVarMahnungZinssatz = Effektiver Zinssatz (Basis + Aufschlag)
MahnungTemplateVarMahnungKundentyp = Kundentyp
MahnungTemplateVarMahnungKundentypBsp = B2C oder B2B
MahnungTemplateVarMahnungVersandart = Versandart
MahnungTemplateVarMahnungVersandartBsp = pdf, mail, druck, none
MahnungTemplateVarMahnungPdfIntro = Einleitungstext der Mahnstufe (aus Setup oder Default)
MahnungTemplateVarMahnungPdfIntroBsp = unsere unten aufgeführte Rechnung...
MahnungTemplateVarFactureRef = Rechnungsnummer
MahnungTemplateVarFactureDate = Rechnungsdatum
MahnungTemplateVarFactureDateLim = Original-Fälligkeitsdatum
MahnungTemplateVarFactureTotalHt = Nettobetrag der Rechnung
MahnungTemplateVarFactureTotalTtc = Bruttobetrag der Rechnung
MahnungTemplateVarFactureTotalTva = MwSt-Betrag
MahnungTemplateVarFactureAlreadyPaid = Bereits gezahlter Betrag
MahnungTemplateVarFirmaName = Firmenname
MahnungTemplateVarFirmaStrasse = Strasse
MahnungTemplateVarFirmaPlz = PLZ
MahnungTemplateVarFirmaOrt = Ort
MahnungTemplateVarFirmaLand = Land
MahnungTemplateVarFirmaTelefon = Telefonnummer
MahnungTemplateVarFirmaFax = Faxnummer
MahnungTemplateVarFirmaEmail = E-Mail-Adresse
MahnungTemplateVarFirmaWeb = Webseite
MahnungTemplateVarFirmaHr = Handelsregisternummer
MahnungTemplateVarFirmaSteuernr = SIRET/Steuernummer
MahnungTemplateVarFirmaKapital = Stammkapital
MahnungTemplateVarFirmaLogo = Firmenlogo (wird als Bild eingefügt)
MahnungTemplateVarFirmaLogoBsp = (Bilddatei)
MahnungTemplateVarKundeName = Kundenname
MahnungTemplateVarKundeAlias = Kurzname/Alias
MahnungTemplateVarKundeStrasse = Strasse
MahnungTemplateVarKundePlz = PLZ
MahnungTemplateVarKundeOrt = Ort
MahnungTemplateVarKundeLand = Land
MahnungTemplateVarKundeTelefon = Telefon
MahnungTemplateVarKundeEmail = E-Mail
MahnungTemplateVarKundeHr = Handelsregister
MahnungTemplateVarKundeSteuernr = Steuernummer
MahnungTemplateVarKundeUstIdNr = USt-IdNr.
MahnungTemplateVarKundeNotiz = Öffentliche Notiz des Kunden
MahnungTemplateVarBankName = Name der Bank
MahnungTemplateVarBankIban = IBAN
MahnungTemplateVarBankBic = BIC/SWIFT
MahnungTemplateVarAbsenderName = Absender-Name
MahnungTemplateVarAbsenderEmail = Absender-E-Mail
MahnungTemplateVarDatum = Aktuelles Datum
MahnungTemplateVarUserNachname = Nachname des eingeloggten Users
MahnungTemplateVarUserVorname = Vorname des eingeloggten Users
MahnungTemplateVarUserEmail = E-Mail des eingeloggten Users
MahnungSetupTemplateVars = Verfügbare Template-Variablen
MahnungTriggerBeschreibung = Mahnung-Trigger: erledigt offene Mahnvorgänge bei Zahlungseingang.
MahnungBoxStufe = Stufe %s
MahnungBoxStufeVom = Stufe %s vom %s
MahnungVorschlagStufeNichtKonfiguriert = Stufe 1 nicht konfiguriert
MahnungVorschlagFristNichtErreicht = Frist Stufe 1 (%s Tage) noch nicht erreicht (Verzug %s Tage)
MahnungVorschlagAlleStufenAusgeschoepft = Alle Mahnstufen ausgeschöpft (zuletzt Stufe %s)
MahnungVorschlagWartefristLaeuft = Wartefrist nach Stufe %s läuft noch (%s/%s Tage)
MahnungVorschlagBetragNull = Offener Betrag <= 0 (vermutl. komplett bezahlt, paye-Flag noch nicht gesetzt)
MahnungPatternNichtGefunden = Pattern nicht gefunden
MahnungSpeichernFehlgeschlagen = Speichern fehlgeschlagen
MahnungCronCommentBuild = Sucht überfällige Rechnungen, ermittelt vorgeschlagene Mahnstufen, sendet Ntfy-Push
MahnungCronCommentReminder = Erinnert per Ntfy an Mahnungen mit Status ERSTELLT, die seit > N Tagen nicht versendet wurden (MAHNUNG_VERSAND_REMINDER_DAYS, Default 2)
#
# PDF-Texte
#
MahnungPdfAnrede = Sehr geehrte Damen und Herren,
MahnungPdfGruss = Mit freundlichen Grüßen
MahnungPdfFristUmgehend = Wir bitten Sie um umgehende Begleichung.
MahnungPdfFristBis = Wir bitten Sie, den ausstehenden Betrag bis spätestens %s auf das unten genannte Konto zu überweisen.
MahnungPdfDefaultIntro1 = unsere unten aufgeführte Rechnung ist trotz Ablauf der Zahlungsfrist noch nicht beglichen. Vielleicht ist Ihnen dies entgangen — wir bitten Sie höflich, den ausstehenden Betrag zeitnah zu überweisen.
MahnungPdfDefaultIntro2 = leider mussten wir feststellen, dass die unten aufgeführte Rechnung trotz unserer Zahlungserinnerung weiterhin offen ist. Wir bitten Sie nun nachdrücklich um Begleichung des offenen Betrags zuzüglich Verzugszinsen und Mahnkosten.
MahnungPdfDefaultIntro3 = wir haben Sie bereits zweimal an die Begleichung der unten aufgeführten Rechnung erinnert. Sollte der offene Betrag inkl. Verzugszinsen und Mahnkosten nicht innerhalb der angegebenen Frist auf unserem Konto eingehen, sehen wir uns gezwungen, weitere rechtliche Schritte einzuleiten.
MahnungPdfRechnungNichtLadbar = Rechnung %s nicht ladbar.
MahnungPdfKundeNichtLadbar = Kunde %s nicht ladbar.
MahnungPdfStufeNichtKonfiguriert = Mahnstufe %s nicht konfiguriert.
MahnungPdfVerzeichnisFehler = Kann Verzeichnis nicht anlegen: %s
MahnungPdfFooterEmail = E-Mail: %s
MahnungPdfFooterTel = Tel: %s
#
# E-Mail-Defaults
#
MahnungEmailDefaultSubject = Mahnung {stufe} zu Rechnung {rechnung}
MahnungEmailDefaultBody1 = Sehr geehrter Kunde,\n\nanbei senden wir Ihnen eine freundliche Zahlungserinnerung zu Rechnung {rechnung}.\nOffener Betrag inkl. evtl. Zinsen: {summe}.\nWir bitten um Begleichung bis spätestens {frist}.\n\nMit freundlichen Grüßen
MahnungEmailDefaultBody2 = Sehr geehrter Kunde,\n\nanbei die 1. Mahnung zur Rechnung {rechnung}.\nBitte überweisen Sie {summe} bis zum {frist}.\n\nMit freundlichen Grüßen
MahnungEmailDefaultBody3 = Sehr geehrter Kunde,\n\nanbei die letzte Mahnung zur Rechnung {rechnung}.\nFalls der Betrag von {summe} nicht bis zum {frist} eingeht, leiten wir gerichtliche Schritte ein.\n\nMit freundlichen Grüßen

View file

@ -200,3 +200,164 @@ MahnungCronBuildVorschlagDesc = Daily scan for overdue invoices, sends a Ntfy pu
MahnungCronVersandReminder = Dunning — shipment reminder (unsent dunnings)
MahnungCronVersandReminderDesc = Daily check for dunnings in status ERSTELLT that have not been sent for more than N days (MAHNUNG_VERSAND_REMINDER_DAYS, default 2).
MahnungDokumentLoeschenConfirm = Really delete document '%s'?
#
# Hardcoded strings (i18n)
#
MahnungDokumentErstellt = Document created
MahnungDokumentFehler = Document error
MahnungDateiNichtGefunden = File not found or not associated
MahnungFehlerSpeichern = Error saving
MahnungVerfahrenErfolglos = Dunning procedure completed unsuccessfully on
MahnungFehlerKlassifizieren = Error classifying
MahnungRechnungNichtLadbar = Invoice could not be loaded
MahnungUneinbringlichKlassifiziert = Classified as unrecoverable
MahnungKeineVorgaenge = No dunning records.
MahnungStufeAmDatum = Stage %s on %s
MahnungCronKeineUeberfaellige = No overdue invoices with pending dunning.
MahnungCronOffeneVorschlaege = Dunning: %s open proposals
MahnungCronStufe1Erinnerung = Stage 1 (reminder): %s
MahnungCronStufe2Mahnung = Stage 2 (dunning): %s
MahnungCronStufe3LetzteMahnung = Stage 3 (final dunning): %s
MahnungCronOffenerBetrag = Open amount: %s EUR
MahnungCronVorschlaege = Dunning: %s proposals
MahnungCronVorschlagslisteOeffnen = Open proposal list
MahnungCronKeineUnversendet = No dunnings unsent > %s days.
MahnungCronUnversendetTitel = Dunning: %s dunning(s) unsent
MahnungCronStufeAlter = %s (stage %s, %s days old) — %s
MahnungCronWeitere = + %s more
MahnungCronArchivOeffnen = Open archive
MahnungCronEintraege = %s — %s entries
MahnungCsrfFehler = Token verification failed (CSRF).
MahnungNichtBerechtigt = Not authorised.
MahnungKeineRechnungenAusgewaehlt = No invoices selected.
MahnungStufeNichtKonfiguriert = Invoice #%s: stage %s not configured
MahnungMahnungErstellt = %s dunning(s) created
MahnungUebersprungen2 = , %s skipped (waiting period)
MahnungFehlerLabel = — Errors: %s
MahnungCsrfTokenUngueltig = CSRF token invalid.
MahnungNichtBerechtigtSend = Not authorised (mahnung.send).
MahnungIdFehlt = mahnung_id missing.
MahnungNichtGefunden = Dunning %s not found.
MahnungPdfFehlt = PDF for dunning %s missing — please generate dunning first.
MahnungKundeNichtLadbar = Customer could not be loaded.
MahnungKundeKeineEmail = Customer has no e-mail address configured.
MahnungEmailGesendet = E-mail sent to %s.
MahnungEmailFehlgeschlagen = E-mail dispatch failed: %s
MahnungSammelbriefNichtBerechtigt = Not authorised.
MahnungSammelbriefCsrfFehler = Token verification failed.
MahnungSammelbriefKeinePdfs = No PDFs generated — check whether invoices are eligible for dunning.
MahnungSammelbriefFehler = Bulk letter PDF could not be generated.
MahnungTemplateVarsTitle = Dunning — Template variables
MahnungTemplateVarsHeader = Available variables for ODT templates
MahnungTemplateVarsBackToSetup = Back to setup
MahnungTemplateVarsIntro = These variables can be used in ODT templates with curly braces, e.g. <code>{mahnung_ref}</code>.
MahnungTemplateVarsIntro2 = Stage-specific templates: <code>mahnung_stufe1.odt</code>, <code>mahnung_stufe2.odt</code>, <code>mahnung_stufe3.odt</code> — fallback: any <code>.odt</code> in the template directory.
MahnungTemplateVarsGrpMahnung = Dunning
MahnungTemplateVarsGrpRechnung = Linked invoice
MahnungTemplateVarsGrpFirma = Own company (sender)
MahnungTemplateVarsGrpKunde = Customer (recipient)
MahnungTemplateVarsGrpBank = Bank details
MahnungTemplateVarsGrpStandard = Dolibarr standard (selection)
MahnungTemplateVarsColVariable = Variable
MahnungTemplateVarsColBeschreibung = Description
MahnungTemplateVarsColBeispiel = Example
MahnungTemplateVarMahnungRef = Dunning reference number
MahnungTemplateVarMahnungStufe = Dunning stage (number)
MahnungTemplateVarMahnungStufeLabel = Stage label
MahnungTemplateVarMahnungDate = Dunning date
MahnungTemplateVarMahnungDateLimAlt = Original invoice due date
MahnungTemplateVarMahnungDateLimNeu = New payment deadline
MahnungTemplateVarMahnungBetragOffen = Open invoice amount
MahnungTemplateVarMahnungMahngebuehr = Dunning fee for this stage
MahnungTemplateVarMahnungPauschale = B2B flat fee per BGB §288 (5)
MahnungTemplateVarMahnungVerzugszinsen = Calculated late-payment interest
MahnungTemplateVarMahnungSumme = Total claim (open + fees + interest)
MahnungTemplateVarMahnungBasiszins = BGB base rate (snapshot at creation)
MahnungTemplateVarMahnungZinssatz = Effective interest rate (base + surcharge)
MahnungTemplateVarMahnungKundentyp = Customer type
MahnungTemplateVarMahnungKundentypBsp = B2C or B2B
MahnungTemplateVarMahnungVersandart = Dispatch method
MahnungTemplateVarMahnungVersandartBsp = pdf, mail, druck, none
MahnungTemplateVarMahnungPdfIntro = Introduction text of dunning stage (from setup or default)
MahnungTemplateVarMahnungPdfIntroBsp = our invoice listed below...
MahnungTemplateVarFactureRef = Invoice number
MahnungTemplateVarFactureDate = Invoice date
MahnungTemplateVarFactureDateLim = Original due date
MahnungTemplateVarFactureTotalHt = Net amount of invoice
MahnungTemplateVarFactureTotalTtc = Gross amount of invoice
MahnungTemplateVarFactureTotalTva = VAT amount
MahnungTemplateVarFactureAlreadyPaid = Already paid amount
MahnungTemplateVarFirmaName = Company name
MahnungTemplateVarFirmaStrasse = Street
MahnungTemplateVarFirmaPlz = Postal code
MahnungTemplateVarFirmaOrt = City
MahnungTemplateVarFirmaLand = Country
MahnungTemplateVarFirmaTelefon = Phone number
MahnungTemplateVarFirmaFax = Fax number
MahnungTemplateVarFirmaEmail = E-mail address
MahnungTemplateVarFirmaWeb = Website
MahnungTemplateVarFirmaHr = Commercial register number
MahnungTemplateVarFirmaSteuernr = SIRET/Tax number
MahnungTemplateVarFirmaKapital = Share capital
MahnungTemplateVarFirmaLogo = Company logo (inserted as image)
MahnungTemplateVarFirmaLogoBsp = (image file)
MahnungTemplateVarKundeName = Customer name
MahnungTemplateVarKundeAlias = Short name/alias
MahnungTemplateVarKundeStrasse = Street
MahnungTemplateVarKundePlz = Postal code
MahnungTemplateVarKundeOrt = City
MahnungTemplateVarKundeLand = Country
MahnungTemplateVarKundeTelefon = Phone
MahnungTemplateVarKundeEmail = E-mail
MahnungTemplateVarKundeHr = Commercial register
MahnungTemplateVarKundeSteuernr = Tax number
MahnungTemplateVarKundeUstIdNr = VAT ID
MahnungTemplateVarKundeNotiz = Public note of customer
MahnungTemplateVarBankName = Bank name
MahnungTemplateVarBankIban = IBAN
MahnungTemplateVarBankBic = BIC/SWIFT
MahnungTemplateVarAbsenderName = Sender name
MahnungTemplateVarAbsenderEmail = Sender e-mail
MahnungTemplateVarDatum = Current date
MahnungTemplateVarUserNachname = Last name of logged-in user
MahnungTemplateVarUserVorname = First name of logged-in user
MahnungTemplateVarUserEmail = E-mail of logged-in user
MahnungSetupTemplateVars = Available template variables
MahnungTriggerBeschreibung = Dunning trigger: marks open dunnings as closed on payment receipt.
MahnungBoxStufe = Stage %s
MahnungBoxStufeVom = Stage %s from %s
MahnungVorschlagStufeNichtKonfiguriert = Stage 1 not configured
MahnungVorschlagFristNichtErreicht = Stage 1 deadline (%s days) not yet reached (overdue %s days)
MahnungVorschlagAlleStufenAusgeschoepft = All dunning stages exhausted (last stage %s)
MahnungVorschlagWartefristLaeuft = Waiting period after stage %s still running (%s/%s days)
MahnungVorschlagBetragNull = Open amount <= 0 (probably fully paid, paye flag not yet set)
MahnungPatternNichtGefunden = Pattern not found
MahnungSpeichernFehlgeschlagen = Save failed
MahnungCronCommentBuild = Scans for overdue invoices, determines proposed dunning stages, sends Ntfy push
MahnungCronCommentReminder = Ntfy reminder for dunnings with status ERSTELLT that have not been dispatched for > N days (MAHNUNG_VERSAND_REMINDER_DAYS, default 2)
#
# PDF texts
#
MahnungPdfAnrede = Dear Sir or Madam,
MahnungPdfGruss = Kind regards
MahnungPdfFristUmgehend = We kindly ask for immediate settlement.
MahnungPdfFristBis = We kindly ask you to transfer the outstanding amount by %s at the latest to the account listed below.
MahnungPdfDefaultIntro1 = our invoice listed below has not been settled despite the payment deadline having passed. Perhaps this escaped your attention — we kindly ask you to transfer the outstanding amount promptly.
MahnungPdfDefaultIntro2 = unfortunately we have noted that the invoice listed below remains unpaid despite our payment reminder. We now urge you to settle the outstanding amount plus late-payment interest and dunning fees.
MahnungPdfDefaultIntro3 = we have already reminded you twice to settle the invoice listed below. Should the outstanding amount including late-payment interest and dunning fees not be received in our account within the stated deadline, we will be compelled to take further legal action.
MahnungPdfRechnungNichtLadbar = Invoice %s could not be loaded.
MahnungPdfKundeNichtLadbar = Customer %s could not be loaded.
MahnungPdfStufeNichtKonfiguriert = Dunning stage %s not configured.
MahnungPdfVerzeichnisFehler = Cannot create directory: %s
MahnungPdfFooterEmail = E-mail: %s
MahnungPdfFooterTel = Phone: %s
#
# E-mail defaults
#
MahnungEmailDefaultSubject = Dunning notice {stufe} for invoice {rechnung}
MahnungEmailDefaultBody1 = Dear Customer,\n\nplease find attached a friendly payment reminder for invoice {rechnung}.\nOutstanding amount incl. interest: {summe}.\nWe kindly ask for settlement by {frist} at the latest.\n\nKind regards
MahnungEmailDefaultBody2 = Dear Customer,\n\nplease find attached the 1st dunning notice for invoice {rechnung}.\nPlease transfer {summe} by {frist}.\n\nKind regards
MahnungEmailDefaultBody3 = Dear Customer,\n\nplease find attached the final dunning notice for invoice {rechnung}.\nIf the amount of {summe} is not received by {frist}, we will initiate legal proceedings.\n\nKind regards

View file

@ -10,7 +10,7 @@
/**
* \file mahnung/list.php
* \ingroup mahnung
* \brief Vorschlagsliste (mode=vorschlag) und Mahnvorgaenge-Archiv (mode=archiv).
* \brief Vorschlagsliste (mode=vorschlag) und Mahnvorgänge-Archiv (mode=archiv).
*/
$res = 0;
@ -67,7 +67,7 @@ if ($filter_minverzug !== '' && $filter_minverzug !== null) {
$filter['min_tage_verzug'] = (int) $filter_minverzug;
}
$filter_socid = GETPOST('search_socid', 'int');
// select_company liefert -1 fuer "nichts ausgewaehlt" — nur positive IDs als Filter werten
// select_company liefert -1 für "nichts ausgewählt" — nur positive IDs als Filter werten
if ((int) $filter_socid > 0) {
$filter['soc_id'] = (int) $filter_socid;
}
@ -119,9 +119,9 @@ print '<td><input type="number" name="filter_minverzug" value="'.dol_escape_html
// Mindestbetrag (in EUR, Komma erlaubt)
print '<td><input type="text" name="filter_minbetrag" value="'.dol_escape_htmltag((string) $filter_minbetrag).'" size="6" placeholder="0,00"> €</td>';
// Kundentyp — Auto-Submit beim Wechsel + Kunden-Auswahl zuruecksetzen, damit das
// Kundentyp — Auto-Submit beim Wechsel + Kunden-Auswahl zurücksetzen, damit das
// Kunden-Dropdown direkt mit dem neuen Typ-Filter neu geladen wird (alte Auswahl
// koennte im neuen Filter gar nicht mehr enthalten sein).
// könnte im neuen Filter gar nicht mehr enthalten sein).
print '<td><select name="filter_kundentyp" onchange="';
print 'var s=this.form.elements[\'search_socid\']; if(s){s.value=\'\';} this.form.submit();';
print '">';
@ -131,9 +131,9 @@ print '<option value="B2C"'.($filter_kundentyp === 'B2C' ? ' selected' : '').'>B
print '</select></td>';
// Kunden-Auswahl: Dolibarr-Standard select_company (Ajax wenn COMPANY_USE_SEARCH_TO_SELECT,
// sonst klassisches Dropdown). htmlname='search_socid' bleibt = Backward-Kompatibilitaet
// sonst klassisches Dropdown). htmlname='search_socid' bleibt = Backward-Kompatibilität
// zu Direkt-Links (?search_socid=74) von der Kundenkarte. Wenn Kundentyp-Filter
// gesetzt ist, schraenken wir die Dropdown-Liste passend ein.
// gesetzt ist, schränken wir die Dropdown-Liste passend ein.
//
// WICHTIG: select_thirdparty_list erwartet $filter im Universal-Search-Criteria-Format
// (siehe forgeSQLFromUniversalSearchCriteria), NICHT plain SQL.
@ -226,7 +226,7 @@ function renderVorschlagsliste($db, $filter)
print '<td>'.dol_print_date($r['facture_date_lim_reglement'], 'day').'</td>';
print '<td class="right">'.((int) $r['tage_verzug']).'</td>';
print '<td class="right">'.price($r['betrag_offen']).'</td>';
print '<td>'.($r['letzte_mahnung_stufe'] ? 'Stufe '.((int) $r['letzte_mahnung_stufe']).' am '.dol_print_date($r['letzte_mahnung_datum'], 'day') : '—').'</td>';
print '<td>'.($r['letzte_mahnung_stufe'] ? $langs->trans('MahnungStufeAmDatum', ((int) $r['letzte_mahnung_stufe']), dol_print_date($r['letzte_mahnung_datum'], 'day')) : '—').'</td>';
print '<td><strong>'.((int) $r['vorgeschlagene_stufe']).'</strong> — '.dol_escape_htmltag($r['vorgeschlagene_stufe_label']).'</td>';
print '</tr>';
$summeOffen += (float) $r['betrag_offen'];
@ -250,8 +250,8 @@ function renderVorschlagsliste($db, $filter)
}
/**
* Diagnose-Tabelle: ueberfaellige Rechnungen, die aktuell nicht vorgeschlagen werden,
* inklusive Grund (Wartefrist, Stufen ausgeschoepft, ...).
* Diagnose-Tabelle: überfällige Rechnungen, die aktuell nicht vorgeschlagen werden,
* inklusive Grund (Wartefrist, Stufen ausgeschöpft, ...).
*
* @param array $skipped
* @return void
@ -285,7 +285,7 @@ function renderUebersprungeneTabelle($skipped)
print '<td>'.dol_print_date($r['facture_date_lim_reglement'], 'day').'</td>';
print '<td class="right">'.((int) $r['tage_verzug']).'</td>';
print '<td class="right">'.price($r['betrag_offen']).'</td>';
print '<td>'.($r['letzte_mahnung_stufe'] ? 'Stufe '.((int) $r['letzte_mahnung_stufe']).' am '.dol_print_date($r['letzte_mahnung_datum'], 'day') : '—').'</td>';
print '<td>'.($r['letzte_mahnung_stufe'] ? $langs->trans('MahnungStufeAmDatum', ((int) $r['letzte_mahnung_stufe']), dol_print_date($r['letzte_mahnung_datum'], 'day')) : '—').'</td>';
print '<td><span class="opacitymedium">'.dol_escape_htmltag((string) $r['skip_reason']).'</span></td>';
print '</tr>';
}
@ -320,7 +320,7 @@ function renderKontaktIcons($phone, $email)
}
/**
* Rendert das Archiv aller bestehenden Mahnvorgaenge.
* Rendert das Archiv aller bestehenden Mahnvorgänge.
*
* @param DoliDB $db
* @param array $filter
@ -338,11 +338,11 @@ function renderArchiv($db, $filter)
$mahnungen = $mahnungObj->fetchAll('date_mahnung', 'DESC', 200, 0, $archivFilter);
if (empty($mahnungen)) {
print '<div class="info">Keine Mahnvorgaenge.</div>';
print '<div class="info">'.$langs->trans('MahnungKeineVorgaenge').'</div>';
return;
}
// Refs fuer alle in der Liste vorkommenden Rechnungen+Kunden in zwei Queries holen
// Refs für alle in der Liste vorkommenden Rechnungen+Kunden in zwei Queries holen
$socIds = array();
$factIds = array();
foreach ($mahnungen as $m) {
@ -375,7 +375,7 @@ function renderArchiv($db, $filter)
print '<th class="right">'.$langs->trans('MahnungGebuehr').'</th>';
print '<th class="right">'.$langs->trans('MahnungVerzugszinsen').'</th>';
print '<th class="right">'.$langs->trans('MahnungSumme').'</th>';
print '<th>Status</th>';
print '<th>'.$langs->trans('Status').'</th>';
print '</tr>';
foreach ($mahnungen as $m) {