Feature: ODT-Template-System, Widget, Dokumentenliste, Templatevariablen-Referenz [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- ODT-Template-System: Pro Mahnstufe eigenes Template (mahnung_stufe1/2/3.odt), Fallback auf generisches Template; Basis-Klasse ModelePDFMahnung, pdf_standard_mahnung (TCPDF refactored), doc_generic_mahnung_odt (ODTPHP) - Widget box_mahnung_offen: Überfällige Rechnungen mit Mahnstufe-Badge (blau/orange/rot) - card.php: Dokumentenliste mit Lupe (PDF-Vorschau), Download, Modellauswahl - admin/templatevars.php: Referenzseite aller verfügbaren ODT-Variablen - admin/setup.php: Dokumentenmodell-Verwaltung, Upload-Bereich mit Benennungskonvention - mahnung.class.php: generateDocument() + socid-Alias für commonGenerateDocument() - modMahnung.class.php: models=1, MAHNUNG_ADDON_PDF/ODT_PATH-Konstanten, document_model-Registrierung in init(), Widget registriert - mahnungpdf.class.php entfernt, Logik in pdf_standard_mahnung.modules.php Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1af917d818
commit
993ac50c0c
11 changed files with 1432 additions and 120 deletions
117
admin/setup.php
117
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 '</table>';
|
|||
print '<br><div class="center"><input type="submit" class="button" value="'.$langs->trans('Save').'"></div>';
|
||||
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>', '');
|
||||
|
||||
// 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 '<table class="noborder centpercent">';
|
||||
print '<tr class="liste_titre">';
|
||||
print '<th>'.$langs->trans('Name').'</th>';
|
||||
print '<th>'.$langs->trans('Description').'</th>';
|
||||
print '<th class="center">'.$langs->trans('Status').'</th>';
|
||||
print '<th class="center">'.$langs->trans('Default').'</th>';
|
||||
print '<th></th>';
|
||||
print '</tr>';
|
||||
|
||||
foreach ($modellist as $mname => $mobj) {
|
||||
print '<tr class="oddeven">';
|
||||
print '<td>'.dol_escape_htmltag($mobj->name).'</td>';
|
||||
print '<td>'.dol_escape_htmltag($mobj->description ?? '').'</td>';
|
||||
|
||||
// Status (aktiviert/deaktiviert)
|
||||
print '<td class="center">';
|
||||
if (in_array($mname, $def)) {
|
||||
print '<a class="reposition" href="'.$_SERVER['PHP_SELF'].'?action=del&token='.newToken().'&value='.urlencode($mname).'">';
|
||||
print img_picto($langs->trans('Activated'), 'switch_on');
|
||||
print '</a>';
|
||||
} else {
|
||||
print '<a class="reposition" href="'.$_SERVER['PHP_SELF'].'?action=set&token='.newToken().'&value='.urlencode($mname).'">';
|
||||
print img_picto($langs->trans('Disabled'), 'switch_off');
|
||||
print '</a>';
|
||||
}
|
||||
print '</td>';
|
||||
|
||||
// Default
|
||||
print '<td class="center">';
|
||||
if (getDolGlobalString('MAHNUNG_ADDON_PDF') === $mname) {
|
||||
print img_picto($langs->trans('Default'), 'on');
|
||||
} elseif (in_array($mname, $def)) {
|
||||
print '<a class="reposition" href="'.$_SERVER['PHP_SELF'].'?action=setdoc&token='.newToken().'&value='.urlencode($mname).'">';
|
||||
print img_picto($langs->trans('SetAsDefault'), 'off');
|
||||
print '</a>';
|
||||
}
|
||||
print '</td>';
|
||||
|
||||
// Info (ODT: Upload-Formular)
|
||||
print '<td>';
|
||||
if (method_exists($mobj, 'info')) {
|
||||
print $mobj->info($langs);
|
||||
}
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
|
||||
print '</table>';
|
||||
|
||||
llxFooter();
|
||||
$db->close();
|
||||
|
|
|
|||
220
admin/templatevars.php
Normal file
220
admin/templatevars.php
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, 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', '<a href="setup.php">Zurueck zum Setup</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 '</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>';
|
||||
|
||||
$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 '<tr class="oddeven">';
|
||||
print '<td><code>'.dol_escape_htmltag($v[0]).'</code></td>';
|
||||
print '<td>'.dol_escape_htmltag($v[1]).'</td>';
|
||||
print '<td class="opacitymedium">'.dol_escape_htmltag($v[2]).'</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
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>';
|
||||
|
||||
$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 '<tr class="oddeven">';
|
||||
print '<td><code>'.dol_escape_htmltag($v[0]).'</code></td>';
|
||||
print '<td>'.dol_escape_htmltag($v[1]).'</td>';
|
||||
print '<td class="opacitymedium">'.dol_escape_htmltag($v[2]).'</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
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>';
|
||||
|
||||
$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 '<tr class="oddeven">';
|
||||
print '<td><code>'.dol_escape_htmltag($v[0]).'</code></td>';
|
||||
print '<td>'.dol_escape_htmltag($v[1]).'</td>';
|
||||
print '<td class="opacitymedium">'.dol_escape_htmltag($v[2]).'</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
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>';
|
||||
|
||||
$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 '<tr class="oddeven">';
|
||||
print '<td><code>'.dol_escape_htmltag($v[0]).'</code></td>';
|
||||
print '<td>'.dol_escape_htmltag($v[1]).'</td>';
|
||||
print '<td class="opacitymedium">'.dol_escape_htmltag($v[2]).'</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
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>';
|
||||
|
||||
$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 '<tr class="oddeven">';
|
||||
print '<td><code>'.dol_escape_htmltag($v[0]).'</code></td>';
|
||||
print '<td>'.dol_escape_htmltag($v[1]).'</td>';
|
||||
print '<td class="opacitymedium">'.dol_escape_htmltag($v[2]).'</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
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>';
|
||||
|
||||
$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 '<tr class="oddeven">';
|
||||
print '<td><code>'.dol_escape_htmltag($v[0]).'</code></td>';
|
||||
print '<td>'.dol_escape_htmltag($v[1]).'</td>';
|
||||
print '<td class="opacitymedium">'.dol_escape_htmltag($v[2]).'</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
print '</table>';
|
||||
|
||||
llxFooter();
|
||||
$db->close();
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
134
card.php
134
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 '<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>';
|
||||
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 '<tr><td>PDF</td><td><a href="'.$dl.'">PDF herunterladen</a></td></tr>';
|
||||
}
|
||||
print '</table>';
|
||||
|
||||
// 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 '<br>';
|
||||
print load_fiche_titre($langs->trans('Documents'), '', 'fa-file');
|
||||
|
||||
// Dokumente im Rechnungsordner suchen die zur Mahnung gehoeren
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
||||
$docDir = '';
|
||||
if ($facture->id > 0) {
|
||||
$docDir = !empty($conf->facture->multidir_output[$facture->entity])
|
||||
? $conf->facture->multidir_output[$facture->entity]
|
||||
: $conf->facture->dir_output;
|
||||
$docDir .= '/'.dol_sanitizeFileName($facture->ref);
|
||||
}
|
||||
|
||||
$mahnungRef = dol_sanitizeFileName($mahnung->ref);
|
||||
$fileList = array();
|
||||
if (!empty($docDir) && is_dir($docDir)) {
|
||||
$allFiles = dol_dir_list($docDir, 'files', 0, preg_quote($mahnungRef, '/'));
|
||||
foreach ($allFiles as $f) {
|
||||
$fileList[] = $f;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($fileList)) {
|
||||
print '<table class="noborder centpercent">';
|
||||
print '<tr class="liste_titre">';
|
||||
print '<th>'.$langs->trans('Document').'</th>';
|
||||
print '<th class="right">'.$langs->trans('Size').'</th>';
|
||||
print '<th class="center">'.$langs->trans('Date').'</th>';
|
||||
print '<th class="center"></th>';
|
||||
print '</tr>';
|
||||
foreach ($fileList as $f) {
|
||||
$fname = $f['name'];
|
||||
$relativePath = dol_sanitizeFileName($facture->ref).'/'.$fname;
|
||||
$dlUrl = DOL_URL_ROOT.'/document.php?modulepart=facture&file='.urlencode($relativePath);
|
||||
$viewUrl = $dlUrl.'&attachment=0'; // Inline-Ansicht (keine Download-Erzwingung)
|
||||
$ext = strtolower(pathinfo($fname, PATHINFO_EXTENSION));
|
||||
$icon = ($ext === 'pdf') ? 'pdf' : (($ext === 'odt') ? 'ooffice' : 'generic');
|
||||
$filesize = !empty($f['size']) ? $f['size'] : filesize($f['fullname']);
|
||||
$filedate = !empty($f['date']) ? $f['date'] : filemtime($f['fullname']);
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
// Dateiname mit Icon
|
||||
print '<td class="nowraponall">';
|
||||
print '<a href="'.$dlUrl.'">';
|
||||
print img_picto('', $icon, 'class="pictofixedwidth"');
|
||||
print dol_escape_htmltag($fname);
|
||||
print '</a>';
|
||||
print '</td>';
|
||||
// Groesse
|
||||
print '<td class="right nowraponall">'.dol_print_size($filesize, 0, 0).'</td>';
|
||||
// Datum
|
||||
print '<td class="center nowraponall">'.dol_print_date($filedate, 'dayhour').'</td>';
|
||||
// Aktionen: Vorschau + Download
|
||||
print '<td class="right nowraponall">';
|
||||
if ($ext === 'pdf') {
|
||||
print '<a href="'.$viewUrl.'" target="_blank" title="'.dol_escape_htmltag($langs->trans('Preview')).'">'.img_picto($langs->trans('Preview'), 'search', 'class="pictofixedwidth"').'</a> ';
|
||||
}
|
||||
print '<a href="'.$dlUrl.'">'.img_picto($langs->trans('Download'), 'download', 'class="pictofixedwidth"').'</a>';
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
print '</table>';
|
||||
} else {
|
||||
print '<div class="opacitymedium">'.$langs->trans('NoDocuments').'</div>';
|
||||
}
|
||||
|
||||
// Aktionen
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
|
||||
$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 '<br><div class="tabsAction">';
|
||||
print '<br><div class="tabsAction">';
|
||||
if ($user->hasRight('mahnung', 'write')) {
|
||||
// Modellauswahl
|
||||
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/core/modules/mahnung/modules_mahnung.php';
|
||||
$modellist = ModelePDFMahnung::liste_modeles($db);
|
||||
$defaultModel = getDolGlobalString('MAHNUNG_ADDON_PDF', 'standard_mahnung');
|
||||
|
||||
if (is_array($modellist) && count($modellist) > 1) {
|
||||
print '<select name="model" id="selectmodel" style="margin-right: 5px;">';
|
||||
foreach ($modellist as $k => $v) {
|
||||
print '<option value="'.dol_escape_htmltag($k).'"'.($k === $defaultModel ? ' selected' : '').'>'.dol_escape_htmltag($v).'</option>';
|
||||
}
|
||||
print '</select>';
|
||||
}
|
||||
|
||||
print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=regenerate_pdf&token='.newToken().'" onclick="if(document.getElementById(\'selectmodel\')){this.href+=\'&model=\'+document.getElementById(\'selectmodel\').value;}">';
|
||||
print $langs->trans('MahnungGenerate');
|
||||
print '</a> ';
|
||||
}
|
||||
if ($mahnung->status !== Mahnung::STATUS_STORNIERT && $user->hasRight('mahnung', 'delete')) {
|
||||
print '<a class="butActionDelete" href="'.$_SERVER['PHP_SELF'].'?id='.((int) $mahnung->id).'&action=confirm_storno">';
|
||||
print $langs->trans('MahnungStornieren');
|
||||
print '</a></div>';
|
||||
print '</a>';
|
||||
}
|
||||
print '</div>';
|
||||
|
||||
llxFooter();
|
||||
$db->close();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
254
core/boxes/box_mahnung_offen.php
Normal file
254
core/boxes/box_mahnung_offen.php
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, 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' => '<span class="opacitymedium">'.$langs->trans("ReadPermissionNotAllowed").'</span>'
|
||||
);
|
||||
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 = ' <span class="badge" style="background-color:'.$color.';color:#fff;font-size:0.75em;" title="'.dol_escape_htmltag($tooltip).'">'.$label.'</span>';
|
||||
}
|
||||
|
||||
// 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 : '<span class="opacitymedium">—</span>',
|
||||
'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);
|
||||
}
|
||||
}
|
||||
504
core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php
Normal file
504
core/modules/mahnung/doc/doc_generic_mahnung_odt.modules.php
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
<?php
|
||||
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, 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.".<br>\n";
|
||||
$texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
|
||||
$texte .= '<input type="hidden" name="token" value="'.newToken().'">';
|
||||
$texte .= '<input type="hidden" name="page_y" value="">';
|
||||
$texte .= '<input type="hidden" name="action" value="setModuleOptions">';
|
||||
$texte .= '<input type="hidden" name="param1" value="MAHNUNG_ADDON_PDF_ODT_PATH">';
|
||||
$texte .= '<table class="nobordernopadding" width="100%">';
|
||||
|
||||
// Verzeichnis-Liste
|
||||
$texte .= '<tr><td valign="middle">';
|
||||
$texttitle = $langs->trans("ListOfDirectories");
|
||||
$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('MAHNUNG_ADDON_PDF_ODT_PATH'))));
|
||||
$listoffiles = array();
|
||||
foreach ($listofdir as $key => $tmpdir) {
|
||||
$tmpdir = trim($tmpdir);
|
||||
$tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
|
||||
if (!$tmpdir) {
|
||||
unset($listofdir[$key]);
|
||||
continue;
|
||||
}
|
||||
if (!is_dir($tmpdir)) {
|
||||
$texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), '');
|
||||
} else {
|
||||
$tmpfiles = dol_dir_list($tmpdir, 'files', 0, '\.(ods|odt)');
|
||||
if (count($tmpfiles)) {
|
||||
$listoffiles = array_merge($listoffiles, $tmpfiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
$texthelp = $langs->trans("ListOfDirectoriesForModelGenODT");
|
||||
$texthelp .= '<br><br><span class="opacitymedium">'.$langs->trans("ExampleOfDirectoriesForModelGen").'</span>';
|
||||
$texthelp .= '<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>';
|
||||
$texthelp .= '<br><b>Mahnung-spezifisch:</b><br>';
|
||||
$texthelp .= '{mahnung_ref}, {mahnung_stufe}, {mahnung_stufe_label}, {mahnung_date},<br>';
|
||||
$texthelp .= '{mahnung_betrag_offen}, {mahnung_mahngebuehr}, {mahnung_verzugszinsen},<br>';
|
||||
$texthelp .= '{mahnung_summe}, {mahnung_basiszins}, {mahnung_zinssatz}, {mahnung_kundentyp},<br>';
|
||||
$texthelp .= '{mahnung_pdf_intro}, {mahnung_date_lim_alt}, {mahnung_date_lim_neu}<br>';
|
||||
$texthelp .= '<br><b>Rechnungsdaten:</b><br>';
|
||||
$texthelp .= '{facture_ref}, {facture_date}, {facture_total_ttc}, {facture_already_paid}<br>';
|
||||
$texthelp .= '<br><b>Bankdaten:</b><br>';
|
||||
$texthelp .= '{mahnung_bank_label}, {mahnung_bank_iban}, {mahnung_bank_bic}<br>';
|
||||
$texthelp .= '<br><b>Stufen-spezifische Templates:</b><br>';
|
||||
$texthelp .= 'mahnung_stufe1.odt, mahnung_stufe2.odt, mahnung_stufe3.odt<br>';
|
||||
|
||||
$texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1, 3, $this->name);
|
||||
$texte .= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">';
|
||||
$texte .= '<textarea class="flat textareafordir" spellcheck="false" cols="60" name="value1">';
|
||||
$texte .= getDolGlobalString('MAHNUNG_ADDON_PDF_ODT_PATH');
|
||||
$texte .= '</textarea>';
|
||||
$texte .= '</div><div style="display: inline-block; vertical-align: middle;">';
|
||||
$texte .= '<input type="submit" class="button button-edit reposition smallpaddingimp" name="modify" value="'.dol_escape_htmltag($langs->trans("Modify")).'">';
|
||||
$texte .= '<br></div></div>';
|
||||
|
||||
// Gefundene Templates auflisten
|
||||
$nbofiles = count($listoffiles);
|
||||
if (getDolGlobalString('MAHNUNG_ADDON_PDF_ODT_PATH')) {
|
||||
$texte .= $langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>';
|
||||
}
|
||||
if ($nbofiles) {
|
||||
$texte .= '<div id="div_'.get_class($this).'">';
|
||||
foreach ($listoffiles as $file) {
|
||||
$texte .= '- '.$file['name'].' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=mahnung/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
|
||||
$texte .= ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=MAHNUNG_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
|
||||
$texte .= '<br>';
|
||||
}
|
||||
$texte .= '</div>';
|
||||
}
|
||||
|
||||
// Hinweis zur Benennung
|
||||
$texte .= '<br><div class="opacitymedium" style="margin: 8px 0; padding: 6px 10px; border-left: 3px solid #4a90d9; background: rgba(74,144,217,0.05);">';
|
||||
$texte .= '<b>Dateinamen-Konvention:</b><br>';
|
||||
$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 .= '</div>';
|
||||
|
||||
// Upload-Feld
|
||||
$texte .= '<div>'.$langs->trans("UploadNewTemplate");
|
||||
$maxfilesizearray = getMaxFileSizeArray();
|
||||
$maxmin = $maxfilesizearray['maxmin'];
|
||||
if ($maxmin > 0) {
|
||||
$texte .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">';
|
||||
}
|
||||
$texte .= ' <input type="file" name="uploadfile">';
|
||||
$texte .= '<input type="hidden" value="MAHNUNG_ADDON_PDF_ODT_PATH" name="keyforuploaddir">';
|
||||
$texte .= '<input type="submit" class="button smallpaddingimp reposition" value="'.dol_escape_htmltag($langs->trans("Upload")).'" name="upload">';
|
||||
$texte .= '</div>';
|
||||
$texte .= '</td></tr>';
|
||||
|
||||
$texte .= '</table>';
|
||||
$texte .= '</form>';
|
||||
|
||||
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.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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])
|
||||
55
core/modules/mahnung/modules_mahnung.php
Normal file
55
core/modules/mahnung/modules_mahnung.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, 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
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue