All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Vollstaendiges 3-stufiges Mahnwesen nach BGB §288: - SQL-Schema (llx_mahnung_mahnung, llx_mahnung_stufe) - CRUD-Klassen (Mahnung, MahnungStufe, MahnungVorschlag) - TCPDF DIN-5008 PDF-Generierung - Verzugszinsberechnung B2C/B2B + §288 Abs.5 Pauschale - Trigger: offene Mahnungen bei Zahlungseingang schliessen - Hook: Tab + Button auf Rechnungs-/Kundenkarte - Cron: taegl. Vorschlagsliste + Ntfy-Push - Deploy-Pipeline (.forgejo/workflows/deploy.yml) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
232 lines
8.9 KiB
PHP
232 lines
8.9 KiB
PHP
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/**
|
|
* \file mahnung/list.php
|
|
* \ingroup mahnung
|
|
* \brief Vorschlagsliste (mode=vorschlag) und Mahnvorgaenge-Archiv (mode=archiv).
|
|
*/
|
|
|
|
$res = 0;
|
|
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
|
|
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
|
|
}
|
|
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
|
|
$tmp2 = realpath(__FILE__);
|
|
$i = strlen($tmp) - 1;
|
|
$j = strlen($tmp2) - 1;
|
|
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
|
|
$i--;
|
|
$j--;
|
|
}
|
|
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
|
|
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
|
|
}
|
|
if (!$res && file_exists("../main.inc.php")) {
|
|
$res = @include "../main.inc.php";
|
|
}
|
|
if (!$res && file_exists("../../main.inc.php")) {
|
|
$res = @include "../../main.inc.php";
|
|
}
|
|
if (!$res) {
|
|
die("Include of main fails");
|
|
}
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnung.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungstufe.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungvorschlag.class.php';
|
|
|
|
global $langs, $user, $db;
|
|
$langs->loadLangs(array('mahnung@mahnung', 'companies', 'bills'));
|
|
|
|
if (!$user->hasRight('mahnung', 'read')) {
|
|
accessforbidden();
|
|
}
|
|
|
|
$mode = GETPOST('mode', 'aZ09');
|
|
if ($mode !== 'archiv') {
|
|
$mode = 'vorschlag';
|
|
}
|
|
|
|
$filter = array();
|
|
$filter_stufe = GETPOST('filter_stufe', 'int');
|
|
if ($filter_stufe !== '' && $filter_stufe !== null) {
|
|
$filter['stufe'] = (int) $filter_stufe;
|
|
}
|
|
$filter_minverzug = GETPOST('filter_minverzug', 'int');
|
|
if ($filter_minverzug !== '' && $filter_minverzug !== null) {
|
|
$filter['min_tage_verzug'] = (int) $filter_minverzug;
|
|
}
|
|
$filter_socid = GETPOST('search_socid', 'int');
|
|
if (!empty($filter_socid)) {
|
|
$filter['soc_id'] = (int) $filter_socid;
|
|
}
|
|
|
|
llxHeader('', $langs->trans($mode === 'archiv' ? 'MahnungArchiv' : 'MahnungVorschlagsliste'));
|
|
|
|
print load_fiche_titre(
|
|
$langs->trans($mode === 'archiv' ? 'MahnungArchiv' : 'MahnungVorschlagsliste'),
|
|
'',
|
|
'fa-envelope-open-text'
|
|
);
|
|
|
|
// --- Filter-Form ---
|
|
print '<form method="GET" action="'.$_SERVER['PHP_SELF'].'">';
|
|
print '<input type="hidden" name="mode" value="'.dol_escape_htmltag($mode).'">';
|
|
print '<table class="noborder centpercent"><tr class="liste_titre">';
|
|
print '<th>'.$langs->trans('MahnungStufe').'</th>';
|
|
print '<th>'.$langs->trans('MahnungTageVerzug').' (min)</th>';
|
|
print '<th>'.$langs->trans('MahnungKunde').'</th>';
|
|
print '<th></th></tr>';
|
|
print '<tr><td><select name="filter_stufe">';
|
|
print '<option value="">— '.$langs->trans('All').' —</option>';
|
|
foreach (array(1, 2, 3) as $st) {
|
|
print '<option value="'.$st.'"'.((string) $filter_stufe === (string) $st ? ' selected' : '').'>'.$st.'</option>';
|
|
}
|
|
print '</select></td>';
|
|
print '<td><input type="number" name="filter_minverzug" value="'.dol_escape_htmltag((string) $filter_minverzug).'" size="4"></td>';
|
|
print '<td><input type="number" name="search_socid" value="'.dol_escape_htmltag((string) $filter_socid).'" size="6" placeholder="rowid">';
|
|
print '</td>';
|
|
print '<td><input type="submit" class="button" value="'.$langs->trans('Search').'"></td>';
|
|
print '</tr></table>';
|
|
print '</form><br>';
|
|
|
|
if ($mode === 'vorschlag') {
|
|
renderVorschlagsliste($db, $filter);
|
|
} else {
|
|
renderArchiv($db, $filter);
|
|
}
|
|
|
|
llxFooter();
|
|
$db->close();
|
|
|
|
/**
|
|
* Rendert die Vorschlagsliste auf Basis von MahnungVorschlag.
|
|
*
|
|
* @param DoliDB $db
|
|
* @param array $filter
|
|
* @return void
|
|
*/
|
|
function renderVorschlagsliste($db, $filter)
|
|
{
|
|
global $langs, $user;
|
|
|
|
$service = new MahnungVorschlag($db);
|
|
$rows = $service->getVorschlaege($filter);
|
|
|
|
if (empty($rows)) {
|
|
print '<div class="info">'.$langs->trans('MahnungKeineUeberfaelligen').'</div>';
|
|
return;
|
|
}
|
|
|
|
$canWrite = $user->hasRight('mahnung', 'write');
|
|
|
|
print '<form method="POST" action="'.DOL_URL_ROOT.'/custom/mahnung/ajax/createmahnung.php" id="formMahnung">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
if ($canWrite) {
|
|
print '<th><input type="checkbox" id="chkAll"></th>';
|
|
}
|
|
print '<th>'.$langs->trans('MahnungRechnung').'</th>';
|
|
print '<th>'.$langs->trans('MahnungKunde').'</th>';
|
|
print '<th>'.$langs->trans('MahnungKundentyp').'</th>';
|
|
print '<th>'.$langs->trans('MahnungFaelligkeitAlt').'</th>';
|
|
print '<th class="right">'.$langs->trans('MahnungTageVerzug').'</th>';
|
|
print '<th class="right">'.$langs->trans('MahnungBetragOffen').'</th>';
|
|
print '<th>'.$langs->trans('MahnungLetzteMahnung').'</th>';
|
|
print '<th>'.$langs->trans('MahnungVorgeschlageneStufe').'</th>';
|
|
print '</tr>';
|
|
|
|
$summeOffen = 0.0;
|
|
foreach ($rows as $r) {
|
|
print '<tr class="oddeven">';
|
|
if ($canWrite) {
|
|
print '<td><input type="checkbox" name="facture_ids[]" value="'.((int) $r['facture_id']).'" data-stufe="'.((int) $r['vorgeschlagene_stufe']).'"></td>';
|
|
}
|
|
print '<td><a href="'.DOL_URL_ROOT.'/compta/facture/card.php?id='.((int) $r['facture_id']).'">'.dol_escape_htmltag($r['facture_ref']).'</a></td>';
|
|
print '<td><a href="'.DOL_URL_ROOT.'/societe/card.php?socid='.((int) $r['soc_id']).'">'.dol_escape_htmltag($r['soc_nom']).'</a></td>';
|
|
print '<td>'.dol_escape_htmltag($r['kundentyp']).'</td>';
|
|
print '<td>'.dol_print_date($r['facture_date_lim_reglement'], 'day').'</td>';
|
|
print '<td class="right">'.((int) $r['tage_verzug']).'</td>';
|
|
print '<td class="right">'.price($r['betrag_offen']).'</td>';
|
|
print '<td>'.($r['letzte_mahnung_stufe'] ? 'Stufe '.((int) $r['letzte_mahnung_stufe']).' am '.dol_print_date($r['letzte_mahnung_datum'], 'day') : '—').'</td>';
|
|
print '<td><strong>'.((int) $r['vorgeschlagene_stufe']).'</strong> — '.dol_escape_htmltag($r['vorgeschlagene_stufe_label']).'</td>';
|
|
print '</tr>';
|
|
$summeOffen += (float) $r['betrag_offen'];
|
|
}
|
|
print '<tr class="liste_total"><td colspan="'.($canWrite ? 6 : 5).'" class="right">'.$langs->trans('Total').'</td>';
|
|
print '<td class="right">'.price($summeOffen).'</td><td colspan="2"></td></tr>';
|
|
print '</table>';
|
|
|
|
if ($canWrite) {
|
|
print '<br><div class="center">';
|
|
print '<button type="submit" class="button" name="action" value="bulk_create">'.$langs->trans('MahnungErstellen').'</button> ';
|
|
print '<button type="submit" class="button" name="action" value="bulk_sammelbrief" formaction="'.DOL_URL_ROOT.'/custom/mahnung/ajax/sammelbrief.php">'.$langs->trans('MahnungSammelbrief').'</button>';
|
|
print '</div>';
|
|
print '<script>document.getElementById("chkAll")?.addEventListener("change", function(e){';
|
|
print 'document.querySelectorAll("input[name=\'facture_ids[]\']").forEach(c => c.checked = e.target.checked);';
|
|
print '});</script>';
|
|
}
|
|
print '</form>';
|
|
}
|
|
|
|
/**
|
|
* Rendert das Archiv aller bestehenden Mahnvorgaenge.
|
|
*
|
|
* @param DoliDB $db
|
|
* @param array $filter
|
|
* @return void
|
|
*/
|
|
function renderArchiv($db, $filter)
|
|
{
|
|
global $langs;
|
|
|
|
$mahnungObj = new Mahnung($db);
|
|
$archivFilter = array();
|
|
if (isset($filter['stufe'])) {
|
|
$archivFilter['stufe'] = $filter['stufe'];
|
|
}
|
|
$mahnungen = $mahnungObj->fetchAll('date_mahnung', 'DESC', 200, 0, $archivFilter);
|
|
|
|
if (empty($mahnungen)) {
|
|
print '<div class="info">Keine Mahnvorgaenge.</div>';
|
|
return;
|
|
}
|
|
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<th>'.$langs->trans('MahnungRef').'</th>';
|
|
print '<th>'.$langs->trans('MahnungRechnung').'</th>';
|
|
print '<th>'.$langs->trans('MahnungKunde').'</th>';
|
|
print '<th>'.$langs->trans('MahnungStufe').'</th>';
|
|
print '<th>'.$langs->trans('MahnungDatum').'</th>';
|
|
print '<th class="right">'.$langs->trans('MahnungBetragOffen').'</th>';
|
|
print '<th class="right">'.$langs->trans('MahnungGebuehr').'</th>';
|
|
print '<th class="right">'.$langs->trans('MahnungVerzugszinsen').'</th>';
|
|
print '<th class="right">'.$langs->trans('MahnungSumme').'</th>';
|
|
print '<th>Status</th>';
|
|
print '</tr>';
|
|
|
|
foreach ($mahnungen as $m) {
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.dol_escape_htmltag($m->ref).'</td>';
|
|
print '<td><a href="'.DOL_URL_ROOT.'/compta/facture/card.php?id='.((int) $m->fk_facture).'">#'.((int) $m->fk_facture).'</a></td>';
|
|
print '<td><a href="'.DOL_URL_ROOT.'/societe/card.php?socid='.((int) $m->fk_soc).'">#'.((int) $m->fk_soc).'</a></td>';
|
|
print '<td>'.((int) $m->stufe).'</td>';
|
|
print '<td>'.dol_print_date($m->date_mahnung, 'day').'</td>';
|
|
print '<td class="right">'.price($m->betrag_offen).'</td>';
|
|
print '<td class="right">'.price((float) $m->mahngebuehr + (float) $m->pauschale_b2b).'</td>';
|
|
print '<td class="right">'.price($m->verzugszinsen).'</td>';
|
|
print '<td class="right"><strong>'.price($m->summe_mahnung).'</strong></td>';
|
|
print '<td>'.dol_escape_htmltag($m->getStatusLabel()).'</td>';
|
|
print '</tr>';
|
|
}
|
|
print '</table>';
|
|
}
|