diff --git a/admin/setup.php b/admin/setup.php
index 5cb9691..b8a2516 100644
--- a/admin/setup.php
+++ b/admin/setup.php
@@ -42,8 +42,10 @@ if (!$res) {
}
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
+require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
global $langs, $user, $conf, $db;
$langs->loadLangs(array('admin', 'mahnung@mahnung'));
@@ -165,6 +167,35 @@ function loadStufeById($db, $id, $entity)
return $s;
}
+// ---------------------------------------------------------------
+// Dokumentenmodell-Aktionen (vor View, da header()-Redirect)
+// ---------------------------------------------------------------
+if ($action === 'setdoc' && $user->hasRight('mahnung', 'setup')) {
+ $newModel = GETPOST('value', 'alphanohtml');
+ if (!empty($newModel)) {
+ dolibarr_set_const($db, 'MAHNUNG_ADDON_PDF', $newModel, 'chaine', 0, '', $conf->entity);
+ }
+ header('Location: '.$_SERVER['PHP_SELF']);
+ exit;
+}
+if ($action === 'set' && $user->hasRight('mahnung', 'setup')) {
+ $newModel = GETPOST('value', 'alphanohtml');
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity, libelle) VALUES ('".$db->escape($newModel)."', 'mahnung', ".((int) $conf->entity).", '".$db->escape($newModel)."')";
+ $db->query($sql);
+ header('Location: '.$_SERVER['PHP_SELF']);
+ exit;
+}
+if ($action === 'del' && $user->hasRight('mahnung', 'setup')) {
+ $newModel = GETPOST('value', 'alphanohtml');
+ $sql = "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$db->escape($newModel)."' AND type = 'mahnung' AND entity = ".((int) $conf->entity);
+ $db->query($sql);
+ if (getDolGlobalString('MAHNUNG_ADDON_PDF') === $newModel) {
+ dolibarr_del_const($db, 'MAHNUNG_ADDON_PDF', $conf->entity);
+ }
+ header('Location: '.$_SERVER['PHP_SELF']);
+ exit;
+}
+
// ---------------------------------------------------------------
// View
// ---------------------------------------------------------------
@@ -278,5 +309,91 @@ print '';
print '
';
print '';
+// --- Block: Dokumentenmodelle -----------------------------------------------------------
+print ' ';
+print load_fiche_titre($langs->trans('MahnungDokumentModelle'), 'Verfuegbare Template-Variablen ', '');
+
+// Aktionen fuer Dokumentenmodelle (Upload, Loeschen, setModuleOptions)
+include_once DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
+// Dokumentenmodelle auflisten
+$def = array();
+$sql = "SELECT nom FROM ".MAIN_DB_PREFIX."document_model WHERE type = 'mahnung' AND entity = ".((int) $conf->entity);
+$resql = $db->query($sql);
+if ($resql) {
+ while ($obj = $db->fetch_object($resql)) {
+ $def[] = $obj->nom;
+ }
+ $db->free($resql);
+}
+
+// Verfuegbare Modelle scannen (aus den doc/-Klassen)
+$dirmodels = array(
+ DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/doc/',
+);
+$modellist = array();
+foreach ($dirmodels as $dmod) {
+ $files = dol_dir_list($dmod, 'files', 0, '\.modules\.php$');
+ foreach ($files as $file) {
+ $classname = preg_replace('/\.modules\.php$/', '', $file['name']);
+ // Modellname ohne doc_/pdf_-Prefix (commonGenerateDocument fuegt den Prefix selbst hinzu)
+ $modelname = preg_replace('/^(doc|pdf)_/', '', $classname);
+ include_once $file['fullname'];
+ if (class_exists($classname)) {
+ $obj = new $classname($db);
+ $modellist[$modelname] = $obj;
+ }
+ }
+}
+
+print '';
+
llxFooter();
$db->close();
diff --git a/admin/templatevars.php b/admin/templatevars.php
new file mode 100644
index 0000000..792f193
--- /dev/null
+++ b/admin/templatevars.php
@@ -0,0 +1,220 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 3.
+ */
+
+/**
+ * \file mahnung/admin/templatevars.php
+ * \ingroup mahnung
+ * \brief Uebersicht aller verfuegbaren Variablen fuer ODT-Templates.
+ */
+
+$res = 0;
+if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
+ $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
+}
+$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
+$tmp2 = realpath(__FILE__);
+$i = strlen($tmp) - 1;
+$j = strlen($tmp2) - 1;
+while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
+ $i--;
+ $j--;
+}
+if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
+ $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
+}
+if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
+ $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
+}
+if (!$res && file_exists("../../main.inc.php")) {
+ $res = @include "../../main.inc.php";
+}
+if (!$res) {
+ die("Include of main fails");
+}
+
+global $langs, $user;
+$langs->loadLangs(array('admin', 'mahnung@mahnung'));
+
+if (!$user->admin && !$user->hasRight('mahnung', 'setup')) {
+ accessforbidden();
+}
+
+llxHeader('', 'Mahnung — Template-Variablen');
+
+print load_fiche_titre('Verfuegbare Variablen fuer ODT-Templates', 'Zurueck zum Setup ', 'fa-envelope-open-text');
+
+print '';
+print 'Diese Variablen koennen in ODT-Templates mit geschweiften Klammern verwendet werden, z.B. {mahnung_ref}. ';
+print 'Stufen-spezifische Templates: mahnung_stufe1.odt, mahnung_stufe2.odt, mahnung_stufe3.odt — Fallback: beliebiges .odt im Template-Verzeichnis.';
+print '
';
+
+// Mahnung-Variablen
+print '';
+print 'Mahnung ';
+print 'Variable Beschreibung Beispiel ';
+
+$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...'),
+);
+
+foreach ($mahnungVars as $v) {
+ print '';
+ print ''.dol_escape_htmltag($v[0]).' ';
+ print ''.dol_escape_htmltag($v[1]).' ';
+ print ''.dol_escape_htmltag($v[2]).' ';
+ print ' ';
+}
+print '
';
+
+// Rechnungs-Variablen
+print ' ';
+print '';
+print 'Verknuepfte Rechnung ';
+print 'Variable Beschreibung Beispiel ';
+
+$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'),
+);
+
+foreach ($factureVars as $v) {
+ print '';
+ print ''.dol_escape_htmltag($v[0]).' ';
+ print ''.dol_escape_htmltag($v[1]).' ';
+ print ''.dol_escape_htmltag($v[2]).' ';
+ print ' ';
+}
+print '
';
+
+// Firmen-Variablen (Absender)
+print ' ';
+print '';
+print 'Eigene Firma (Absender) ';
+print 'Variable Beschreibung Beispiel ';
+
+$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)'),
+);
+
+foreach ($mysocVars as $v) {
+ print '';
+ print ''.dol_escape_htmltag($v[0]).' ';
+ print ''.dol_escape_htmltag($v[1]).' ';
+ print ''.dol_escape_htmltag($v[2]).' ';
+ print ' ';
+}
+print '
';
+
+// Kunden-Variablen
+print ' ';
+print '';
+print 'Kunde (Empfaenger) ';
+print 'Variable Beschreibung Beispiel ';
+
+$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', ''),
+);
+
+foreach ($companyVars as $v) {
+ print '';
+ print ''.dol_escape_htmltag($v[0]).' ';
+ print ''.dol_escape_htmltag($v[1]).' ';
+ print ''.dol_escape_htmltag($v[2]).' ';
+ print ' ';
+}
+print '
';
+
+// Bank-Variablen
+print ' ';
+print '';
+print 'Bankverbindung ';
+print 'Variable Beschreibung Beispiel ';
+
+$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'),
+);
+
+foreach ($bankVars as $v) {
+ print '';
+ print ''.dol_escape_htmltag($v[0]).' ';
+ print ''.dol_escape_htmltag($v[1]).' ';
+ print ''.dol_escape_htmltag($v[2]).' ';
+ print ' ';
+}
+print '
';
+
+// Dolibarr-Standard-Variablen
+print ' ';
+print '';
+print 'Dolibarr-Standard (Auswahl) ';
+print 'Variable Beschreibung Beispiel ';
+
+$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'),
+);
+
+foreach ($stdVars as $v) {
+ print '';
+ print ''.dol_escape_htmltag($v[0]).' ';
+ print ''.dol_escape_htmltag($v[1]).' ';
+ print ''.dol_escape_htmltag($v[2]).' ';
+ print ' ';
+}
+print '
';
+
+llxFooter();
+$db->close();
diff --git a/ajax/createmahnung.php b/ajax/createmahnung.php
index 902fff3..6e312aa 100644
--- a/ajax/createmahnung.php
+++ b/ajax/createmahnung.php
@@ -28,7 +28,6 @@ require_once $_SERVER['DOCUMENT_ROOT'].'/main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungvorschlag.class.php';
-require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungpdf.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
@@ -101,7 +100,6 @@ $forceStufe = ($forceStufe >= 1 && $forceStufe <= 3) ? $forceStufe : 0;
// 4) Verarbeitung — pro Rechnung Vorschlag holen, Mahnung erzeugen, PDF generieren
$service = new MahnungVorschlag($db);
-$pdfGen = new MahnungPdf($db);
$basiszins = (float) getDolGlobalString('MAHNUNG_BASISZINS', '1.27');
$created = 0;
@@ -172,9 +170,9 @@ foreach ($factureIds as $fid) {
continue;
}
- $pdfPath = $pdfGen->generate($mahnung, $user);
- if ($pdfPath === false) {
- $failed[] = 'Rechnung #'.$fid.' (Mahnung '.$mahnung->ref.'): PDF-Fehler '.$pdfGen->error;
+ $docResult = $mahnung->generateDocument('', $langs);
+ if ($docResult <= 0) {
+ $failed[] = 'Rechnung #'.$fid.' (Mahnung '.$mahnung->ref.'): Dokument-Fehler '.$mahnung->error;
continue;
}
diff --git a/card.php b/card.php
index 1505386..9e95bb2 100644
--- a/card.php
+++ b/card.php
@@ -57,17 +57,26 @@ if ($mahnung->fetch($id) <= 0) {
// Stornieren
if ($action === 'storno' && $user->hasRight('mahnung', 'delete')) {
- if (!verifCsrf($_POST['token'] ?? '', 'mahnung_storno')) {
- setEventMessages($langs->trans('ErrorBadValueForToken'), null, 'errors');
- } else {
- $mahnung->status = Mahnung::STATUS_STORNIERT;
- if ($mahnung->update($user) > 0) {
- setEventMessages($langs->trans('MahnungStornieren').' OK', null, 'mesgs');
- header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
- exit;
- }
- setEventMessages($mahnung->error, null, 'errors');
+ $mahnung->status = Mahnung::STATUS_STORNIERT;
+ if ($mahnung->update($user) > 0) {
+ setEventMessages($langs->trans('MahnungStornieren').' OK', null, 'mesgs');
+ header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
+ exit;
}
+ setEventMessages($mahnung->error, null, 'errors');
+}
+
+// Dokument neu generieren
+if ($action === 'regenerate_pdf' && $user->hasRight('mahnung', 'write')) {
+ $selectedModel = GETPOST('model', 'alphanohtml');
+ $result = $mahnung->generateDocument($selectedModel, $langs);
+ if ($result > 0) {
+ setEventMessages('Dokument erstellt', null, 'mesgs');
+ } else {
+ setEventMessages('Dokument-Fehler: '.$mahnung->error, null, 'errors');
+ }
+ header('Location: '.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id));
+ exit;
}
llxHeader('', $langs->trans('MahnungRef').' '.$mahnung->ref);
@@ -103,18 +112,80 @@ if ((float) $mahnung->pauschale_b2b > 0) {
print ''.$langs->trans('MahnungVerzugszinsen').' '.price($mahnung->verzugszinsen).' (Basiszins '.number_format((float) $mahnung->basiszins_snapshot, 2, ',', '.').' %) ';
print ''.$langs->trans('MahnungSumme').' '.price($mahnung->summe_mahnung).' ';
print 'Status '.dol_escape_htmltag($mahnung->getStatusLabel()).' ';
-if (!empty($mahnung->pdf_path)) {
- $relativePdf = str_replace(DOL_DATA_ROOT, '', $mahnung->pdf_path);
- $dl = DOL_URL_ROOT.'/document.php?modulepart=facture&file='.urlencode(ltrim(str_replace('/facture/', '', $relativePdf), '/'));
- print 'PDF PDF herunterladen ';
-}
print '';
-// Aktionen
-if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
- require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
- $form = new Form($db);
+// --- Generierte Dokumente (wie bei Rechnungen) ---
+print ' ';
+print load_fiche_titre($langs->trans('Documents'), '', 'fa-file');
+// Dokumente im Rechnungsordner suchen die zur Mahnung gehoeren
+require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+$docDir = '';
+if ($facture->id > 0) {
+ $docDir = !empty($conf->facture->multidir_output[$facture->entity])
+ ? $conf->facture->multidir_output[$facture->entity]
+ : $conf->facture->dir_output;
+ $docDir .= '/'.dol_sanitizeFileName($facture->ref);
+}
+
+$mahnungRef = dol_sanitizeFileName($mahnung->ref);
+$fileList = array();
+if (!empty($docDir) && is_dir($docDir)) {
+ $allFiles = dol_dir_list($docDir, 'files', 0, preg_quote($mahnungRef, '/'));
+ foreach ($allFiles as $f) {
+ $fileList[] = $f;
+ }
+}
+
+if (!empty($fileList)) {
+ print '';
+ print '';
+ print ''.$langs->trans('Document').' ';
+ print ''.$langs->trans('Size').' ';
+ print ''.$langs->trans('Date').' ';
+ print ' ';
+ print ' ';
+ foreach ($fileList as $f) {
+ $fname = $f['name'];
+ $relativePath = dol_sanitizeFileName($facture->ref).'/'.$fname;
+ $dlUrl = DOL_URL_ROOT.'/document.php?modulepart=facture&file='.urlencode($relativePath);
+ $viewUrl = $dlUrl.'&attachment=0'; // Inline-Ansicht (keine Download-Erzwingung)
+ $ext = strtolower(pathinfo($fname, PATHINFO_EXTENSION));
+ $icon = ($ext === 'pdf') ? 'pdf' : (($ext === 'odt') ? 'ooffice' : 'generic');
+ $filesize = !empty($f['size']) ? $f['size'] : filesize($f['fullname']);
+ $filedate = !empty($f['date']) ? $f['date'] : filemtime($f['fullname']);
+
+ print '';
+ // Dateiname mit Icon
+ print '';
+ print '';
+ print img_picto('', $icon, 'class="pictofixedwidth"');
+ print dol_escape_htmltag($fname);
+ print ' ';
+ print ' ';
+ // Groesse
+ print ''.dol_print_size($filesize, 0, 0).' ';
+ // Datum
+ print ''.dol_print_date($filedate, 'dayhour').' ';
+ // Aktionen: Vorschau + Download
+ print '';
+ if ($ext === 'pdf') {
+ print ''.img_picto($langs->trans('Preview'), 'search', 'class="pictofixedwidth"').' ';
+ }
+ print ''.img_picto($langs->trans('Download'), 'download', 'class="pictofixedwidth"').' ';
+ print ' ';
+ print ' ';
+ }
+ print '
';
+} else {
+ print ''.$langs->trans('NoDocuments').'
';
+}
+
+// Aktionen
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
+$form = new Form($db);
+
+if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
if ($action === 'confirm_storno') {
print $form->formconfirm(
$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id),
@@ -126,12 +197,33 @@ if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung',
1
);
}
+}
- print '';
+print '
';
+if ($user->hasRight('mahnung', 'write')) {
+ // Modellauswahl
+ require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
+ $modellist = ModelePDFMahnung::liste_modeles($db);
+ $defaultModel = getDolGlobalString('MAHNUNG_ADDON_PDF', 'standard_mahnung');
+
+ if (is_array($modellist) && count($modellist) > 1) {
+ print '
';
+ foreach ($modellist as $k => $v) {
+ print ''.dol_escape_htmltag($v).' ';
+ }
+ print ' ';
+ }
+
+ print '
';
+ print $langs->trans('MahnungGenerate');
+ print ' ';
+}
+if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
print '
';
print $langs->trans('MahnungStornieren');
- print ' ';
+ print '';
}
+print '
';
llxFooter();
$db->close();
diff --git a/class/mahnung.class.php b/class/mahnung.class.php
index a04033f..242bb9c 100644
--- a/class/mahnung.class.php
+++ b/class/mahnung.class.php
@@ -92,6 +92,9 @@ class Mahnung extends CommonObject
/** @var string */
public $note_private;
+ /** @var string Aktuelles Dokumentenmodell */
+ public $model_pdf;
+
/** @var int 0..9 */
public $status = self::STATUS_ENTWURF;
@@ -250,10 +253,44 @@ 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()
+ $this->socid = $this->fk_soc;
+
$this->db->free($resql);
return 1;
}
+ /**
+ * Dokument generieren ueber das Dolibarr-Dokumentenmodell-System.
+ *
+ * @param string $modele Modellname ('standard_mahnung', 'generic_mahnung_odt')
+ * @param Translate $outputlangs Ausgabesprache
+ * @param int $hidedetails Details ausblenden
+ * @param int $hidedesc Beschreibung ausblenden
+ * @param int $hideref Referenz ausblenden
+ * @param array $moreparams Weitere Parameter
+ * @return int >0 OK, <=0 Fehler
+ */
+ public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
+ {
+ global $conf, $langs;
+
+ $langs->load("mahnung@mahnung");
+
+ if (!dol_strlen($modele)) {
+ $modele = 'standard_mahnung';
+ if (!empty($this->model_pdf)) {
+ $modele = $this->model_pdf;
+ } elseif (getDolGlobalString('MAHNUNG_ADDON_PDF')) {
+ $modele = getDolGlobalString('MAHNUNG_ADDON_PDF');
+ }
+ }
+
+ $modelpath = "core/modules/mahnung/doc/";
+
+ return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
+ }
+
/**
* Mehrere Mahnungen laden.
*
diff --git a/core/boxes/box_mahnung_offen.php b/core/boxes/box_mahnung_offen.php
new file mode 100644
index 0000000..6b9e1a2
--- /dev/null
+++ b/core/boxes/box_mahnung_offen.php
@@ -0,0 +1,254 @@
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 3.
+ */
+
+/**
+ * \file htdocs/custom/mahnung/core/boxes/box_mahnung_offen.php
+ * \ingroup mahnung
+ * \brief Widget: Aelteste offene Kundenrechnungen mit Mahnstufe.
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php';
+require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
+
+/**
+ * Widget: Offene Kundenrechnungen mit aktueller Mahnstufe.
+ */
+class box_mahnung_offen extends ModeleBoxes
+{
+ public $boxcode = "mahnungoffenerechnungen";
+ public $boximg = "fa-envelope-open-text";
+ public $boxlabel = "MahnungBoxOffeneRechnungen";
+ public $depends = array("facture", "mahnung");
+
+ /**
+ * @param DoliDB $db
+ * @param string $param
+ */
+ public function __construct($db, $param)
+ {
+ global $user;
+ $this->db = $db;
+ $this->hidden = !($user->hasRight('facture', 'lire'));
+ }
+
+ /**
+ * @param int $max
+ */
+ public function loadBox($max = 5)
+ {
+ global $conf, $user, $langs;
+
+ $this->max = $max;
+
+ $langs->loadLangs(array('bills', 'mahnung@mahnung'));
+
+ $facturestatic = new Facture($this->db);
+ $societestatic = new Societe($this->db);
+
+ $this->info_box_head = array(
+ 'text' => $langs->trans("MahnungBoxOffeneRechnungen", $this->max),
+ );
+
+ if (!$user->hasRight('facture', 'lire')) {
+ $this->info_box_contents[0][0] = array(
+ 'td' => 'class="nohover left"',
+ 'text' => ''.$langs->trans("ReadPermissionNotAllowed").' '
+ );
+ return;
+ }
+
+ // Offene Rechnungen mit optionalem LEFT JOIN auf letzte aktive Mahnung
+ $sql = "SELECT s.rowid as socid, s.nom as name, s.logo, s.email, s.entity,";
+ $sql .= " s.code_client, s.client,";
+ $sql .= " f.rowid as facid, f.ref, f.type, f.datef as date,";
+ $sql .= " f.date_lim_reglement as datelimit,";
+ $sql .= " f.total_ht, f.total_tva, f.total_ttc,";
+ $sql .= " f.paye, f.fk_statut as status,";
+ $sql .= " COALESCE(SUM(pf.amount), 0) as am,";
+ // Letzte Mahnstufe per Subquery
+ $sql .= " (SELECT m2.stufe FROM ".MAIN_DB_PREFIX."mahnung_mahnung as m2";
+ $sql .= " WHERE m2.fk_facture = f.rowid AND m2.status NOT IN (".Mahnung::STATUS_STORNIERT.")";
+ $sql .= " ORDER BY m2.stufe DESC LIMIT 1) as mahnstufe,";
+ $sql .= " (SELECT m3.date_mahnung FROM ".MAIN_DB_PREFIX."mahnung_mahnung as m3";
+ $sql .= " WHERE m3.fk_facture = f.rowid AND m3.status NOT IN (".Mahnung::STATUS_STORNIERT.")";
+ $sql .= " ORDER BY m3.stufe DESC LIMIT 1) as mahndatum";
+ $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
+ $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc";
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture";
+ $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
+ $sql .= " AND f.paye = 0";
+ $sql .= " AND f.fk_statut = 1";
+ $sql .= " AND f.date_lim_reglement IS NOT NULL";
+ $sql .= " AND f.date_lim_reglement < '".$this->db->idate(dol_now())."'";
+ if (empty($user->socid) && !$user->hasRight('societe', 'client', 'voir')) {
+ $sql .= " AND s.rowid IN (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_user = ".((int) $user->id).")";
+ }
+ if ($user->socid) {
+ $sql .= " AND s.rowid = ".((int) $user->socid);
+ }
+ $sql .= " GROUP BY s.rowid, s.nom, s.logo, s.email, s.entity, s.code_client, s.client,";
+ $sql .= " f.rowid, f.ref, f.type, f.datef, f.date_lim_reglement,";
+ $sql .= " f.total_ht, f.total_tva, f.total_ttc, f.paye, f.fk_statut";
+ $sql .= " ORDER BY f.date_lim_reglement ASC, f.ref ASC";
+ $sql .= $this->db->plimit($this->max + 1, 0);
+
+ require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
+
+ $result = $this->db->query($sql);
+ if (!$result) {
+ $this->info_box_contents[0][0] = array(
+ 'td' => '', 'maxlength' => 500,
+ 'text' => $this->db->error().' sql='.$sql,
+ );
+ return;
+ }
+
+ $num = $this->db->num_rows($result);
+ $line = 0;
+ $l_due_date = $langs->trans('Late').' ('.strtolower($langs->trans('DateDue')).': %s)';
+ $totalHt = 0;
+
+ while ($line < min($num, $this->max)) {
+ $objp = $this->db->fetch_object($result);
+
+ $datelimit = $this->db->jdate($objp->datelimit);
+ $tageVerzug = (int) floor((dol_now() - $datelimit) / 86400);
+
+ $facturestatic->id = $objp->facid;
+ $facturestatic->ref = $objp->ref;
+ $facturestatic->type = $objp->type;
+ $facturestatic->total_ht = $objp->total_ht;
+ $facturestatic->total_tva = $objp->total_tva;
+ $facturestatic->total_ttc = $objp->total_ttc;
+ $facturestatic->date = $this->db->jdate($objp->date);
+ $facturestatic->date_lim_reglement = $datelimit;
+ $facturestatic->statut = $objp->status;
+ $facturestatic->status = $objp->status;
+ $facturestatic->paye = $objp->paye;
+ $facturestatic->paid = $objp->paye;
+ $facturestatic->alreadypaid = $objp->am;
+ $facturestatic->totalpaid = $objp->am;
+
+ $societestatic->id = $objp->socid;
+ $societestatic->name = $objp->name;
+ $societestatic->code_client = $objp->code_client;
+ $societestatic->client = $objp->client;
+ $societestatic->logo = $objp->logo;
+ $societestatic->email = $objp->email;
+ $societestatic->entity = $objp->entity;
+
+ $late = '';
+ if ($facturestatic->hasDelay()) {
+ $late = img_warning(sprintf($l_due_date, dol_print_date($datelimit, 'day', 'tzuserrel')));
+ }
+
+ // Mahnstufe-Badge
+ $mahnBadge = '';
+ 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;
+ $mahnDatum = $objp->mahndatum ? dol_print_date($this->db->jdate($objp->mahndatum), 'day') : '';
+ $tooltip = $label.($mahnDatum ? ' vom '.$mahnDatum : '');
+ $mahnBadge = ' '.$label.' ';
+ }
+
+ // Spalte 1: Rechnung + Warnung
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="nowraponall"',
+ 'text' => $facturestatic->getNomUrl(1),
+ 'text2' => $late,
+ 'asis' => 1,
+ );
+
+ // Spalte 2: Kunde
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
+ 'text' => $societestatic->getNomUrl(1, '', 44),
+ 'asis' => 1,
+ );
+
+ // Spalte 3: Betrag
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="nowraponall right amount"',
+ 'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
+ );
+
+ // Spalte 4: Faelligkeitsdatum
+ $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'),
+ );
+
+ // Spalte 5: Tage Verzug
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="center nowraponall"',
+ 'text' => $tageVerzug.' T.',
+ );
+
+ // Spalte 6: Mahnstufe
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="center nowraponall"',
+ 'text' => !empty($mahnBadge) ? $mahnBadge : '— ',
+ 'asis' => 1,
+ );
+
+ $totalHt += (float) $objp->total_ht;
+ $line++;
+ }
+
+ if ($this->max < $num) {
+ $this->info_box_contents[$line][] = array('td' => 'colspan="6"', 'text' => '...');
+ $line++;
+ }
+
+ if ($num > 0) {
+ // Summenzeile
+ $this->info_box_contents[$line][] = array(
+ 'tr' => 'class="liste_total"',
+ 'td' => 'class="liste_total"',
+ 'text' => $langs->trans("Total"),
+ );
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="liste_total"',
+ 'text' => ' ',
+ );
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="nowraponall right liste_total"',
+ 'text' => price($totalHt, 0, $langs, 0, -1, -1, $conf->currency),
+ );
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="liste_total"',
+ 'text' => ' ',
+ );
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="liste_total"',
+ 'text' => ' ',
+ );
+ $this->info_box_contents[$line][] = array(
+ 'td' => 'class="liste_total"',
+ 'text' => ' ',
+ );
+ }
+
+ $this->db->free($result);
+ }
+
+ /**
+ * @param array|null $head
+ * @param array|null $contents
+ * @param int $nooutput
+ * @return string
+ */
+ public function showBox($head = null, $contents = null, $nooutput = 0)
+ {
+ return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput);
+ }
+}
diff --git a/core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php b/core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php
new file mode 100644
index 0000000..9f3d6b0
--- /dev/null
+++ b/core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php
@@ -0,0 +1,504 @@
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 3.
+ */
+
+/**
+ * \file htdocs/custom/mahnung/core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php
+ * \ingroup mahnung
+ * \brief ODT-Template-Generator fuer Mahnschreiben.
+ *
+ * Stufen-spezifische Templates: mahnung_stufe1.odt, mahnung_stufe2.odt, mahnung_stufe3.odt
+ * Fallback: beliebiges hochgeladenes .odt Template.
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
+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.
+ */
+class doc_generic_mahnung_odt extends ModelePDFMahnung
+{
+ /**
+ * @var string
+ */
+ public $version = 'dolibarr';
+
+ /**
+ * @param DoliDB $db
+ */
+ public function __construct($db)
+ {
+ global $langs, $mysoc;
+
+ $langs->loadLangs(array('main', 'companies'));
+
+ $this->db = $db;
+ $this->name = 'ODT templates';
+ $this->description = $langs->trans('DocumentModelOdt');
+ $this->scandir = 'MAHNUNG_ADDON_PDF_ODT_PATH';
+
+ $this->type = 'odt';
+ $this->page_largeur = 0;
+ $this->page_hauteur = 0;
+ $this->format = array($this->page_largeur, $this->page_hauteur);
+ $this->marge_gauche = 0;
+ $this->marge_droite = 0;
+ $this->marge_haute = 0;
+ $this->marge_basse = 0;
+
+ $this->option_logo = 1;
+ $this->option_multilang = 1;
+ $this->option_freetext = 1;
+
+ if ($mysoc !== null) {
+ $this->emetteur = $mysoc;
+ if (!$this->emetteur->country_code) {
+ $this->emetteur->country_code = substr($langs->defaultlang, -2);
+ }
+ }
+ }
+
+ /**
+ * Beschreibung und Template-Upload-Formular fuer die Admin-Seite.
+ *
+ * @param Translate $langs
+ * @return string
+ */
+ public function info($langs)
+ {
+ global $conf;
+
+ $langs->loadLangs(array('errors', 'companies'));
+
+ $form = new Form($this->db);
+
+ $texte = $this->description.". \n";
+ $texte .= '';
+
+ return $texte;
+ }
+
+ /**
+ * Erzeugt das ODT-Dokument aus einem Template.
+ *
+ * @param object $object Mahnung-Objekt
+ * @param Translate $outputlangs Ausgabesprache
+ * @param string $srctemplatepath Pfad zum ODT-Template
+ * @param int $hidedetails Details ausblenden
+ * @param int $hidedesc Beschreibung ausblenden
+ * @param int $hideref Referenz ausblenden
+ * @return int 1=OK, <=0=Fehler
+ */
+ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
+ {
+ global $user, $langs, $conf, $mysoc, $hookmanager;
+
+ if (empty($srctemplatepath)) {
+ dol_syslog("doc_generic_mahnung_odt::write_file srctemplatepath leer", LOG_WARNING);
+ return -1;
+ }
+
+ if (!is_object($hookmanager)) {
+ include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
+ $hookmanager = new HookManager($this->db);
+ }
+ $hookmanager->initHooks(array('odtgeneration'));
+ global $action;
+
+ if (!is_object($outputlangs)) {
+ $outputlangs = $langs;
+ }
+ $sav_charset_output = $outputlangs->charset_output;
+ $outputlangs->charset_output = 'UTF-8';
+ $outputlangs->loadLangs(array('main', 'dict', 'companies', 'bills', 'mahnung@mahnung'));
+
+ $mahnung = $object;
+
+ // Rechnung + Kunde + Stufe laden
+ $facture = new Facture($this->db);
+ if ($facture->fetch((int) $mahnung->fk_facture) <= 0) {
+ $this->error = 'Rechnung '.((int) $mahnung->fk_facture).' nicht ladbar.';
+ return -1;
+ }
+
+ $societe = new Societe($this->db);
+ if ($societe->fetch((int) $mahnung->fk_soc) <= 0) {
+ $this->error = 'Kunde '.((int) $mahnung->fk_soc).' nicht ladbar.';
+ return -1;
+ }
+ // Fuer die Standard-Substitution-Arrays
+ $mahnung->thirdparty = $societe;
+
+ $stufeObj = new MahnungStufe($this->db);
+ $stufeObj->fetchByStufe((int) $mahnung->stufe);
+
+ // Stufen-spezifisches Template suchen
+ $srctemplatepath = $this->findStufeTemplate($srctemplatepath, (int) $mahnung->stufe);
+
+ // Ausgabe-Verzeichnis: im Facture-Ordner (damit es im Rechnung-Tab sichtbar ist)
+ $dirFact = !empty($conf->facture->multidir_output[$facture->entity])
+ ? $conf->facture->multidir_output[$facture->entity]
+ : $conf->facture->dir_output;
+ $dir = $dirFact.'/'.dol_sanitizeFileName($facture->ref);
+
+ if (!file_exists($dir)) {
+ if (dol_mkdir($dir) < 0) {
+ $this->error = $outputlangs->transnoentities("ErrorCanNotCreateDir", $dir);
+ return -1;
+ }
+ }
+
+ // Dateiname
+ $newfile = basename($srctemplatepath);
+ $newfiletmp = preg_replace('/\.od[ts]/i', '', $newfile);
+ $newfiletmp = preg_replace('/template_/i', '', $newfiletmp);
+ $newfiletmp = preg_replace('/modele_/i', '', $newfiletmp);
+ $objectref = dol_sanitizeFileName($mahnung->ref);
+ $newfiletmp = $objectref.'_'.$newfiletmp;
+
+ $newfileformat = substr($newfile, strrpos($newfile, '.') + 1);
+ if (getDolGlobalString('MAIN_DOC_USE_TIMING')) {
+ $format = getDolGlobalString('MAIN_DOC_USE_TIMING');
+ if ($format == '1') {
+ $format = '%Y%m%d%H%M%S';
+ }
+ $filename = $newfiletmp.'-'.dol_print_date(dol_now(), $format).'.'.$newfileformat;
+ } else {
+ $filename = $newfiletmp.'.'.$newfileformat;
+ }
+ $file = $dir.'/'.$filename;
+
+ // Temp-Verzeichnis
+ $tmpdir = $conf->mahnung->dir_temp ?? ($conf->facture->dir_temp ?? DOL_DATA_ROOT.'/mahnung/temp');
+ dol_mkdir($tmpdir);
+
+ // ODT oeffnen
+ require_once ODTPHP_PATH.'odf.php';
+ try {
+ $odfHandler = new Odf(
+ $srctemplatepath,
+ array(
+ 'PATH_TO_TMP' => $tmpdir,
+ 'ZIP_PROXY' => getDolGlobalString('MAIN_ODF_ZIP_PROXY', 'PclZipProxy'),
+ 'DELIMITER_LEFT' => '{',
+ 'DELIMITER_RIGHT' => '}'
+ )
+ );
+ } catch (Exception $e) {
+ $this->error = $e->getMessage();
+ dol_syslog($e->getMessage(), LOG_ERR);
+ return -1;
+ }
+
+ // Substitution-Arrays zusammenbauen
+ $substitutionarray = array(
+ '__FROM_NAME__' => $this->emetteur->name,
+ '__FROM_EMAIL__' => $this->emetteur->email,
+ );
+ complete_substitutions_array($substitutionarray, $outputlangs, $mahnung);
+
+ // Standard-Arrays
+ $array_common = getCommonSubstitutionArray($outputlangs, 0, null, $mahnung);
+ $array_object_from_properties = $this->get_substitutionarray_each_var_object($mahnung, $outputlangs);
+ $array_objet = $this->get_substitutionarray_object($mahnung, $outputlangs);
+ $array_user = $this->get_substitutionarray_user($user, $outputlangs);
+ $array_soc = $this->get_substitutionarray_mysoc($mysoc, $outputlangs);
+ $array_thirdparty = $this->get_substitutionarray_thirdparty($societe, $outputlangs);
+ $array_other = $this->get_substitutionarray_other($outputlangs);
+
+ // Mahnung-spezifische Tags
+ $array_mahnung = $this->getMahnungSubstitutionArray($mahnung, $facture, $stufeObj, $outputlangs);
+
+ // Alles zusammenfuehren
+ $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);
+
+ // Hook
+ $parameters = array('odfHandler' => &$odfHandler, 'file' => $file, 'object' => $mahnung, 'outputlangs' => $outputlangs, 'substitutionarray' => &$tmparray);
+ $hookmanager->executeHooks('ODTSubstitution', $parameters, $this, $action);
+
+ // Variablen ins ODT schreiben
+ foreach ($tmparray as $key => $value) {
+ try {
+ if (preg_match('/logo$/', $key)) {
+ if (file_exists($value)) {
+ $odfHandler->setImage($key, $value);
+ } else {
+ $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
+ }
+ } else {
+ $odfHandler->setVars($key, $value, true, 'UTF-8');
+ }
+ } catch (OdfException $e) {
+ dol_syslog($e->getMessage(), LOG_INFO);
+ }
+ }
+
+ // Uebersetzungs-Labels
+ $tmparray2 = $outputlangs->get_translations_for_substitutions();
+ foreach ($tmparray2 as $key => $value) {
+ try {
+ $odfHandler->setVars($key, $value, true, 'UTF-8');
+ } catch (OdfException $e) {
+ dol_syslog($e->getMessage(), LOG_INFO);
+ }
+ }
+
+ // Speichern (als PDF wenn MAIN_ODT_AS_PDF gesetzt)
+ if (getDolGlobalString('MAIN_ODT_AS_PDF')) {
+ try {
+ $odfHandler->exportAsAttachedPDF($file);
+ } catch (Exception $e) {
+ $this->error = $e->getMessage();
+ dol_syslog($e->getMessage(), LOG_ERR);
+ return -1;
+ }
+ } else {
+ try {
+ $odfHandler->saveToDisk($file);
+ } catch (Exception $e) {
+ $this->error = $e->getMessage();
+ dol_syslog($e->getMessage(), LOG_ERR);
+ return -1;
+ }
+ }
+
+ dolChmod($file);
+ $odfHandler = null;
+
+ // Pfad in DB persistieren
+ $mahnung->pdf_path = $file;
+ $mahnung->update($user);
+
+ $this->result = array('fullpath' => $file);
+ $outputlangs->charset_output = $sav_charset_output;
+
+ return 1;
+ }
+
+ /**
+ * Sucht ein stufen-spezifisches Template (mahnung_stufe{N}.odt).
+ * Fallback: das uebergebene generische Template.
+ *
+ * @param string $srctemplatepath Generisches Template (von commonGenerateDocument)
+ * @param int $stufe Mahnstufe 1-3
+ * @return string Pfad zum besten Template
+ */
+ private function findStufeTemplate($srctemplatepath, $stufe)
+ {
+ global $conf;
+
+ $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('MAHNUNG_ADDON_PDF_ODT_PATH'))));
+ foreach ($listofdir as $tmpdir) {
+ $tmpdir = trim(preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir));
+ if (empty($tmpdir)) {
+ continue;
+ }
+ $stufeFile = $tmpdir.'/mahnung_stufe'.$stufe.'.odt';
+ if (file_exists($stufeFile)) {
+ return $stufeFile;
+ }
+ }
+
+ return $srctemplatepath;
+ }
+
+ /**
+ * Mahnung-spezifische Substitution-Variablen.
+ *
+ * @param Mahnung $mahnung
+ * @param Facture $facture
+ * @param MahnungStufe $stufe
+ * @param Translate $outputlangs
+ * @return array
+ */
+ private function getMahnungSubstitutionArray($mahnung, $facture, $stufe, $outputlangs)
+ {
+ $gezahlt = (float) $facture->total_ttc - (float) $mahnung->betrag_offen;
+ $basiszins = $mahnung->basiszins_snapshot !== null ? (float) $mahnung->basiszins_snapshot : 0.0;
+ $aufschlag = $mahnung->customertype === Mahnung::KUNDENTYP_B2B
+ ? (float) getDolGlobalString('MAHNUNG_AUFSCHLAG_B2B', '9.0')
+ : (float) getDolGlobalString('MAHNUNG_AUFSCHLAG_B2C', '5.0');
+
+ $intro = (string) ($stufe->pdf_intro ?? '');
+ if (empty($intro)) {
+ $intro = $this->defaultIntro((int) $mahnung->stufe);
+ }
+
+ $bank = $this->getDefaultBankData();
+
+ return array(
+ 'mahnung_ref' => $mahnung->ref,
+ 'mahnung_stufe' => (int) $mahnung->stufe,
+ 'mahnung_stufe_label' => $stufe->label ?? '',
+ 'mahnung_date' => dol_print_date($mahnung->date_mahnung, 'day'),
+ 'mahnung_date_lim_alt' => dol_print_date($mahnung->date_lim_reglement_alt, 'day'),
+ 'mahnung_date_lim_neu' => dol_print_date($mahnung->date_lim_reglement_neu, 'day'),
+ 'mahnung_betrag_offen' => price((float) $mahnung->betrag_offen),
+ 'mahnung_mahngebuehr' => price((float) $mahnung->mahngebuehr),
+ 'mahnung_pauschale_b2b' => price((float) $mahnung->pauschale_b2b),
+ 'mahnung_verzugszinsen' => price((float) $mahnung->verzugszinsen),
+ 'mahnung_summe' => price((float) $mahnung->summe_mahnung),
+ 'mahnung_basiszins' => number_format($basiszins, 2, ',', '.'),
+ 'mahnung_zinssatz' => number_format($basiszins + $aufschlag, 2, ',', '.'),
+ 'mahnung_kundentyp' => $mahnung->customertype,
+ 'mahnung_versandart' => $mahnung->versandart ?? '',
+ 'mahnung_pdf_intro' => $intro,
+ // Rechnungsdaten
+ 'facture_ref' => $facture->ref,
+ 'facture_date' => dol_print_date($facture->date, 'day'),
+ 'facture_date_lim' => dol_print_date($facture->date_lim_reglement, 'day'),
+ 'facture_total_ht' => price((float) $facture->total_ht),
+ 'facture_total_ttc' => price((float) $facture->total_ttc),
+ 'facture_total_tva' => price((float) $facture->total_tva),
+ 'facture_already_paid' => price($gezahlt),
+ // Bank
+ 'mahnung_bank_label' => $bank['label'] ?? '',
+ 'mahnung_bank_iban' => $bank['iban'] ?? '',
+ 'mahnung_bank_bic' => $bank['bic'] ?? '',
+ );
+ }
+
+ /**
+ * Standard-Bankkonto-Daten.
+ *
+ * @return array
+ */
+ private function getDefaultBankData()
+ {
+ $sql = "SELECT label, iban_prefix as iban, bic FROM ".MAIN_DB_PREFIX."bank_account";
+ $sql .= " WHERE clos = 0 AND default_rib = 1 LIMIT 1";
+ $resql = $this->db->query($sql);
+ if (!$resql || !$this->db->num_rows($resql)) {
+ return array();
+ }
+ $obj = $this->db->fetch_object($resql);
+ $this->db->free($resql);
+ return array('label' => $obj->label, 'iban' => $obj->iban, 'bic' => $obj->bic);
+ }
+
+ /**
+ * Default-Intro je Stufe.
+ *
+ * @param int $stufe
+ * @return string
+ */
+ private function defaultIntro($stufe)
+ {
+ 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.';
+ 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.';
+ 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.';
+ }
+ }
+}
diff --git a/class/mahnungpdf.class.php b/core/modules/mahnung/doc/pdf_standard_mahnung.modules.php
similarity index 67%
rename from class/mahnungpdf.class.php
rename to core/modules/mahnung/doc/pdf_standard_mahnung.modules.php
index 90bf4a6..38424e1 100644
--- a/class/mahnungpdf.class.php
+++ b/core/modules/mahnung/doc/pdf_standard_mahnung.modules.php
@@ -6,96 +6,107 @@
*/
/**
- * \file htdocs/custom/mahnung/class/mahnungpdf.class.php
+ * \file htdocs/custom/mahnung/core/modules/mahnung/doc/pdf_standard_mahnung.modules.php
* \ingroup mahnung
- * \brief PDF-Generator fuer Mahnschreiben (DIN-5008 Form A).
- *
- * Nutzt Dolibarrs TCPDF-Wrapper (pdf_getInstance) und schreibt das fertige
- * PDF in den Dokumenten-Ordner der Original-Rechnung
- * documents/facture/{ref-rechnung}/mahnung-{stufe}-{ref-mahnung}.pdf
- * Damit erscheint die Mahnung automatisch im Dokumente-Tab der Rechnung.
+ * \brief Standard-PDF-Generator (TCPDF, DIN-5008) fuer Mahnschreiben.
*/
+require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
-class MahnungPdf
+/**
+ * Standard-PDF-Generator fuer Mahnungen (DIN-5008 Form A, TCPDF).
+ */
+class pdf_standard_mahnung extends ModelePDFMahnung
{
- /** @var DoliDB */
- public $db;
-
- /** @var string */
- public $error = '';
-
/**
* @param DoliDB $db
*/
public function __construct($db)
{
+ global $langs;
$this->db = $db;
+ $this->name = 'standard_mahnung';
+ $this->description = $langs->trans('MahnungPdfStandard');
+ $this->type = 'pdf';
+
+ $this->page_largeur = 210;
+ $this->page_hauteur = 297;
+ $this->format = array($this->page_largeur, $this->page_hauteur);
+ $this->marge_gauche = 25;
+ $this->marge_droite = 25;
+ $this->marge_haute = 25;
+ $this->marge_basse = 25;
}
/**
- * Erzeugt das PDF zum Mahnvorgang. Setzt $mahnung->pdf_path nach Erfolg
- * und schreibt sie via update($user) in die DB.
- *
- * @param Mahnung $mahnung
- * @param User $user
- * @return string|false Absoluter Pfad zur PDF-Datei oder false bei Fehler
+ * @param object $object Mahnung-Objekt
+ * @param Translate $outputlangs Ausgabesprache
+ * @param string $srctemplatepath (nicht verwendet bei TCPDF)
+ * @param int $hidedetails Details ausblenden
+ * @param int $hidedesc Beschreibung ausblenden
+ * @param int $hideref Referenz ausblenden
+ * @return int 1=OK, <=0=Fehler
*/
- public function generate(Mahnung $mahnung, $user)
+ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
{
- global $conf, $langs, $mysoc;
+ global $conf, $langs, $mysoc, $user;
- $langs->loadLangs(array('main', 'bills', 'companies', 'mahnung@mahnung'));
+ if (!is_object($outputlangs)) {
+ $outputlangs = $langs;
+ }
+ $outputlangs->loadLangs(array('main', 'bills', 'companies', 'mahnung@mahnung'));
- // Original-Rechnung + Kunde laden
+ $mahnung = $object;
+
+ // 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.';
- return false;
+ return -1;
}
$societe = new Societe($this->db);
if ($societe->fetch((int) $mahnung->fk_soc) <= 0) {
$this->error = 'Kunde '.((int) $mahnung->fk_soc).' nicht ladbar.';
- return false;
+ return -1;
}
$stufeObj = new MahnungStufe($this->db);
if ($stufeObj->fetchByStufe((int) $mahnung->stufe) <= 0) {
$this->error = 'Mahnstufe '.((int) $mahnung->stufe).' nicht konfiguriert.';
- return false;
+ return -1;
}
- // Ziel-Verzeichnis im Doc-Ordner der Rechnung
- $dirOutput = $this->getOutputDir($facture);
- if (!dol_mkdir($dirOutput)) {
+ // Ziel-Verzeichnis
+ $dirOutput = $this->getOutputDir($mahnung, $facture);
+ if (dol_mkdir($dirOutput) < 0) {
$this->error = 'Kann Verzeichnis nicht anlegen: '.$dirOutput;
- return false;
+ return -1;
}
$filename = 'mahnung-'.((int) $mahnung->stufe).'-'.dol_sanitizeFileName($mahnung->ref).'.pdf';
$absPath = $dirOutput.'/'.$filename;
// PDF-Instanz
$pdf = pdf_getInstance(array('210', '297'));
- $default_font_size = pdf_getPDFFontSize($langs);
+ $default_font_size = pdf_getPDFFontSize($outputlangs);
$pdf->SetAutoPageBreak(true, 25);
- $pdf->SetFont(pdf_getPDFFont($langs), '', $default_font_size);
+ $pdf->SetFont(pdf_getPDFFont($outputlangs), '', $default_font_size);
- $pdf->SetTitle($langs->trans('MahnungStufe').' '.((int) $mahnung->stufe).' — '.$facture->ref);
- $pdf->SetSubject($langs->trans('MahnungRef').' '.$mahnung->ref);
+ $pdf->SetTitle($outputlangs->trans('MahnungStufe').' '.((int) $mahnung->stufe).' — '.$facture->ref);
+ $pdf->SetSubject($outputlangs->trans('MahnungRef').' '.$mahnung->ref);
$pdf->SetAuthor((string) $mysoc->name);
$pdf->SetCreator('Dolibarr Mahnung-Modul');
$pdf->Open();
$pdf->AddPage();
- $this->renderHeader($pdf, $facture, $societe, $mahnung, $stufeObj);
- $this->renderBody($pdf, $facture, $societe, $mahnung, $stufeObj);
+ $this->renderHeader($pdf, $facture, $societe, $mahnung, $stufeObj, $outputlangs);
+ $this->renderBody($pdf, $facture, $societe, $mahnung, $stufeObj, $outputlangs);
$this->renderFooter($pdf);
$pdf->Output($absPath, 'F');
@@ -104,30 +115,22 @@ class MahnungPdf
$mahnung->pdf_path = $absPath;
$mahnung->update($user);
- return $absPath;
+ $this->result = array('fullpath' => $absPath);
+ return 1;
}
/**
- * Adressfenster, Datum, Betreff (DIN-5008 Form A: Adressfeld 45mm hoch ab 27mm).
- *
- * @param TCPDF $pdf
- * @param Facture $facture
- * @param Societe $societe
- * @param Mahnung $mahnung
- * @param MahnungStufe $stufe
- * @return void
+ * Adressfenster, Datum, Betreff (DIN-5008 Form A).
*/
- private function renderHeader($pdf, $facture, $societe, $mahnung, $stufe)
+ private function renderHeader($pdf, $facture, $societe, $mahnung, $stufe, $outputlangs)
{
- global $langs, $mysoc;
+ global $mysoc;
- // Absender klein im Adressfeld (Faltmarke darueber, oben in DIN 5008 Adresszeile)
$pdf->SetFont('helvetica', '', 7);
$pdf->SetXY(25, 50);
$senderLine = trim(($mysoc->name ?? '').' · '.($mysoc->address ?? '').' · '.($mysoc->zip ?? '').' '.($mysoc->town ?? ''));
$pdf->Cell(85, 4, $senderLine, 0, 1, 'L');
- // Empfaenger-Block (Adressfenster: links 25mm, ab y=55)
$pdf->SetFont('helvetica', '', 11);
$pdf->SetXY(25, 55);
$lines = array();
@@ -149,47 +152,34 @@ class MahnungPdf
$pdf->SetX(25);
}
- // Bezugszeichen-Zeile rechts (DIN-5008): Datum + Mahn-Nr.
$pdf->SetFont('helvetica', '', 9);
$pdf->SetXY(125, 50);
- $pdf->Cell(60, 4, $langs->trans('Date').': '.dol_print_date($mahnung->date_mahnung, 'day'), 0, 1, 'L');
+ $pdf->Cell(60, 4, $outputlangs->trans('Date').': '.dol_print_date($mahnung->date_mahnung, 'day'), 0, 1, 'L');
$pdf->SetX(125);
- $pdf->Cell(60, 4, $langs->trans('MahnungRef').': '.$mahnung->ref, 0, 1, 'L');
+ $pdf->Cell(60, 4, $outputlangs->trans('MahnungRef').': '.$mahnung->ref, 0, 1, 'L');
$pdf->SetX(125);
- $pdf->Cell(60, 4, $langs->trans('MahnungRechnung').': '.$facture->ref, 0, 1, 'L');
+ $pdf->Cell(60, 4, $outputlangs->trans('MahnungRechnung').': '.$facture->ref, 0, 1, 'L');
- // Betreff
$pdf->SetXY(25, 100);
$pdf->SetFont('helvetica', 'B', 12);
- $betreff = $stufe->label.' — '.$langs->trans('MahnungRechnung').' '.$facture->ref;
+ $betreff = $stufe->label.' — '.$outputlangs->trans('MahnungRechnung').' '.$facture->ref;
$pdf->Cell(0, 6, $betreff, 0, 1, 'L');
}
/**
- * Anrede, Intro, Tabelle (Rechnung/Datum/Betrag/gezahlt/offen),
- * Gebuehrenblock, Gesamtsumme, neue Frist, Bankverbindung.
- *
- * @param TCPDF $pdf
- * @param Facture $facture
- * @param Societe $societe
- * @param Mahnung $mahnung
- * @param MahnungStufe $stufe
- * @return void
+ * Anrede, Intro, Tabelle, Gebuehrenblock, Gesamtsumme, neue Frist.
*/
- private function renderBody($pdf, $facture, $societe, $mahnung, $stufe)
+ private function renderBody($pdf, $facture, $societe, $mahnung, $stufe, $outputlangs)
{
- global $langs, $mysoc;
+ global $mysoc;
$pdf->SetFont('helvetica', '', 11);
$pdf->SetXY(25, 110);
- // Anrede
- $anrede = 'Sehr geehrte Damen und Herren,';
- $pdf->Cell(0, 5, $anrede, 0, 1, 'L');
+ $pdf->Cell(0, 5, 'Sehr geehrte Damen und Herren,', 0, 1, 'L');
$pdf->SetX(25);
$pdf->Ln(2);
- // Intro aus Stufen-Konfig (Fallback Default-Text je Stufe)
$intro = (string) $stufe->pdf_intro;
if (empty($intro)) {
$intro = $this->defaultIntro((int) $mahnung->stufe);
@@ -201,11 +191,11 @@ class MahnungPdf
// Rechnungs-Tabelle
$pdf->SetFont('helvetica', 'B', 10);
$pdf->SetX(25);
- $pdf->Cell(40, 6, $langs->trans('MahnungRechnung'), 'B', 0, 'L');
- $pdf->Cell(30, 6, $langs->trans('Date'), 'B', 0, 'L');
- $pdf->Cell(30, 6, $langs->trans('TotalTTC'), 'B', 0, 'R');
- $pdf->Cell(30, 6, $langs->trans('AlreadyPaid'), 'B', 0, 'R');
- $pdf->Cell(30, 6, $langs->trans('MahnungBetragOffen'), 'B', 1, 'R');
+ $pdf->Cell(40, 6, $outputlangs->trans('MahnungRechnung'), 'B', 0, 'L');
+ $pdf->Cell(30, 6, $outputlangs->trans('Date'), 'B', 0, 'L');
+ $pdf->Cell(30, 6, $outputlangs->trans('TotalTTC'), 'B', 0, 'R');
+ $pdf->Cell(30, 6, $outputlangs->trans('AlreadyPaid'), 'B', 0, 'R');
+ $pdf->Cell(30, 6, $outputlangs->trans('MahnungBetragOffen'), 'B', 1, 'R');
$pdf->SetFont('helvetica', '', 10);
$pdf->SetX(25);
@@ -220,16 +210,16 @@ class MahnungPdf
// Gebuehrenblock
$pdf->SetX(25);
$pdf->SetFont('helvetica', '', 10);
- $pdf->Cell(130, 6, $langs->trans('MahnungBetragOffen'), 0, 0, 'L');
+ $pdf->Cell(130, 6, $outputlangs->trans('MahnungBetragOffen'), 0, 0, 'L');
$pdf->Cell(30, 6, price((float) $mahnung->betrag_offen).' EUR', 0, 1, 'R');
if ((float) $mahnung->mahngebuehr > 0) {
$pdf->SetX(25);
- $pdf->Cell(130, 6, $langs->trans('MahnungGebuehr'), 0, 0, 'L');
+ $pdf->Cell(130, 6, $outputlangs->trans('MahnungGebuehr'), 0, 0, 'L');
$pdf->Cell(30, 6, price((float) $mahnung->mahngebuehr).' EUR', 0, 1, 'R');
}
if ((float) $mahnung->pauschale_b2b > 0) {
$pdf->SetX(25);
- $pdf->Cell(130, 6, $langs->trans('MahnungPauschaleB2B').' (BGB §288 Abs. 5)', 0, 0, 'L');
+ $pdf->Cell(130, 6, $outputlangs->trans('MahnungPauschaleB2B').' (BGB §288 Abs. 5)', 0, 0, 'L');
$pdf->Cell(30, 6, price((float) $mahnung->pauschale_b2b).' EUR', 0, 1, 'R');
}
if ((float) $mahnung->verzugszinsen > 0) {
@@ -239,7 +229,7 @@ class MahnungPdf
? (float) getDolGlobalString('MAHNUNG_AUFSCHLAG_B2B', '9.0')
: (float) getDolGlobalString('MAHNUNG_AUFSCHLAG_B2C', '5.0');
$satz = $basis + $auf;
- $pdf->Cell(130, 6, $langs->trans('MahnungVerzugszinsen').' ('.number_format($satz, 2, ',', '.').' %)', 0, 0, 'L');
+ $pdf->Cell(130, 6, $outputlangs->trans('MahnungVerzugszinsen').' ('.number_format($satz, 2, ',', '.').' %)', 0, 0, 'L');
$pdf->Cell(30, 6, price((float) $mahnung->verzugszinsen).' EUR', 0, 1, 'R');
}
@@ -247,7 +237,7 @@ class MahnungPdf
$pdf->Ln(1);
$pdf->SetX(25);
$pdf->SetFont('helvetica', 'B', 11);
- $pdf->Cell(130, 7, $langs->trans('MahnungSumme'), 'T', 0, 'L');
+ $pdf->Cell(130, 7, $outputlangs->trans('MahnungSumme'), 'T', 0, 'L');
$pdf->Cell(30, 7, price((float) $mahnung->summe_mahnung).' EUR', 'T', 1, 'R');
$pdf->Ln(5);
@@ -270,9 +260,6 @@ class MahnungPdf
/**
* Fusszeile mit Bankverbindung + Firmen-Footer.
- *
- * @param TCPDF $pdf
- * @return void
*/
private function renderFooter($pdf)
{
@@ -288,10 +275,9 @@ class MahnungPdf
if (!empty($mysoc->phone)) {
$lines[] = 'Tel: '.$mysoc->phone;
}
- // Bankverbindung aus Standard-Bankaccount
- $bankAccount = $this->getDefaultBankLine();
- if (!empty($bankAccount)) {
- $lines[] = $bankAccount;
+ $bankLine = $this->getDefaultBankLine();
+ if (!empty($bankLine)) {
+ $lines[] = $bankLine;
}
foreach ($lines as $l) {
$pdf->Cell(0, 4, $l, 0, 1, 'C');
@@ -299,7 +285,7 @@ class MahnungPdf
}
/**
- * Standard-Bankkonto in einer Zeile (Bank · IBAN · BIC).
+ * Standard-Bankkonto in einer Zeile.
*
* @return string
*/
@@ -319,7 +305,7 @@ class MahnungPdf
}
/**
- * Default-Intro je Stufe (wenn Setup leer ist).
+ * Default-Intro je Stufe.
*
* @param int $stufe
* @return string
@@ -344,12 +330,13 @@ class MahnungPdf
}
/**
- * Ziel-Verzeichnis: documents/facture/{ref}/
+ * Ziel-Verzeichnis: documents/facture/{ref}/ (damit die Mahnung im Rechnung-Tab erscheint).
*
+ * @param Mahnung $mahnung
* @param Facture $facture
* @return string
*/
- private function getOutputDir($facture)
+ private function getOutputDir($mahnung, $facture)
{
global $conf;
$documentDir = !empty($conf->facture->multidir_output[$facture->entity])
diff --git a/core/modules/mahnung/modules_mahnung.php b/core/modules/mahnung/modules_mahnung.php
new file mode 100644
index 0000000..30722e7
--- /dev/null
+++ b/core/modules/mahnung/modules_mahnung.php
@@ -0,0 +1,55 @@
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 3.
+ */
+
+/**
+ * \file htdocs/custom/mahnung/core/modules/mahnung/modules_mahnung.php
+ * \ingroup mahnung
+ * \brief Abstrakte Basis-Klasse fuer Mahnung-Dokumentengeneratoren.
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php';
+
+/**
+ * Elternklasse der Mahnung-Dokumentengeneratoren (PDF, ODT).
+ */
+abstract class ModelePDFMahnung extends CommonDocGenerator
+{
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Gibt die Liste der aktiven Dokumentenmodelle zurueck.
+ *
+ * @param DoliDB $db Datenbank-Handler
+ * @param int $maxfilenamelength Max Laenge
+ * @return array|int
+ */
+ public static function liste_modeles($db, $maxfilenamelength = 0)
+ {
+ // phpcs:enable
+ $type = 'mahnung';
+ $list = array();
+
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+ $list = getListOfModels($db, $type, $maxfilenamelength);
+
+ return $list;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Erzeugt das Dokument auf der Festplatte.
+ *
+ * @param object $object Mahnung-Objekt
+ * @param Translate $outputlangs Ausgabesprache
+ * @param string $srctemplatepath Pfad zum Template (ODT)
+ * @param int $hidedetails Details ausblenden
+ * @param int $hidedesc Beschreibung ausblenden
+ * @param int $hideref Referenz ausblenden
+ * @return int 1=OK, <=0=Fehler
+ */
+ abstract public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0);
+ // phpcs:enable
+}
diff --git a/core/modules/modMahnung.class.php b/core/modules/modMahnung.class.php
index 3557b8d..6da907f 100644
--- a/core/modules/modMahnung.class.php
+++ b/core/modules/modMahnung.class.php
@@ -69,7 +69,7 @@ class modMahnung extends DolibarrModules
'menus' => 0,
'tpl' => 0,
'barcode' => 0,
- 'models' => 0,
+ 'models' => 1,
'printing' => 0,
'theme' => 0,
'css' => array(),
@@ -154,6 +154,24 @@ class modMahnung extends DolibarrModules
'allentities',
1,
),
+ 5 => array(
+ 'MAHNUNG_ADDON_PDF',
+ 'chaine',
+ 'standard_mahnung',
+ 'Standard-Dokumentenmodell fuer Mahnungen',
+ 0,
+ 'current',
+ 1,
+ ),
+ 6 => array(
+ 'MAHNUNG_ADDON_PDF_ODT_PATH',
+ 'chaine',
+ 'DOL_DATA_ROOT/doctemplates/mahnung',
+ 'Verzeichnis fuer ODT-Templates',
+ 0,
+ 'current',
+ 1,
+ ),
);
if (!isModEnabled('mahnung')) {
@@ -166,7 +184,12 @@ class modMahnung extends DolibarrModules
$this->dictionaries = array();
- $this->boxes = array();
+ $this->boxes = array(
+ 0 => array(
+ 'file' => 'box_mahnung_offen@mahnung',
+ 'enabledbydefaulton' => 'Home',
+ ),
+ );
// Cron-Job: Vorschlagsliste taeglich 06:00
$this->cronjobs = array(
@@ -281,13 +304,25 @@ class modMahnung extends DolibarrModules
*/
public function init($options = '')
{
+ global $conf;
+
// Tabellen anlegen aus sql/-Verzeichnis
$result = $this->_load_tables('/mahnung/sql/');
if ($result < 0) {
return -1;
}
+ // Dokumentenmodelle registrieren
$sql = array();
+ $sql[] = "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = 'standard_mahnung' AND type = 'mahnung' AND entity = ".((int) $conf->entity);
+ $sql[] = "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity, libelle, description) VALUES ('standard_mahnung', 'mahnung', ".((int) $conf->entity).", 'Standard PDF (DIN 5008)', NULL)";
+ $sql[] = "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = 'generic_mahnung_odt' AND type = 'mahnung' AND entity = ".((int) $conf->entity);
+ $sql[] = "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity, libelle, description) VALUES ('generic_mahnung_odt', 'mahnung', ".((int) $conf->entity).", 'ODT templates', 'MAHNUNG_ADDON_PDF_ODT_PATH')";
+
+ // ODT-Template-Verzeichnis anlegen
+ $doctemplatedir = DOL_DATA_ROOT.'/doctemplates/mahnung';
+ dol_mkdir($doctemplatedir);
+
return $this->_init($sql, $options);
}
diff --git a/langs/de_DE/mahnung.lang b/langs/de_DE/mahnung.lang
index be23383..bdfc45a 100644
--- a/langs/de_DE/mahnung.lang
+++ b/langs/de_DE/mahnung.lang
@@ -109,3 +109,16 @@ MahnungSettingsSaved = Einstellungen gespeichert.
#
MahnungCronBuildVorschlag = Mahnwesen — Vorschlagsliste aufbauen
MahnungCronBuildVorschlagDesc = Sucht taeglich ueberfaellige Rechnungen und sendet einen Ntfy-Push mit der Anzahl neuer Vorschlaege.
+
+#
+# Widget
+#
+MahnungBoxOffeneRechnungen = Ueberfaellige Rechnungen mit Mahnstufe (%s)
+
+#
+# Dokumentenmodelle
+#
+MahnungDokumentModelle = Dokumentenmodelle
+MahnungPdfStandard = Standard-PDF (DIN 5008)
+MahnungGenerate = Dokument generieren
+NoDocuments = Keine Dokumente vorhanden.