Fix: Widget zeigt alle offenen Rechnungen wie Original + Mahnstufe [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s

Widget basiert jetzt 1:1 auf box_factures_imp.php:
- Alle offenen Rechnungen (nicht nur ueberfaellige)
- Status-Icon wie Original (LibStatut)
- Summenzeile ueber alle offenen (separate Query)
- Link zur Rechnungsliste im Header
Plus: Extra-Spalte Mahnstufe mit farbigem Badge (wenn vorhanden)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-05-10 18:44:45 +02:00
parent 7387d3ac1e
commit ec0c843492

View file

@ -9,6 +9,7 @@
* \file htdocs/custom/mahnung/core/boxes/box_mahnung_offen.php * \file htdocs/custom/mahnung/core/boxes/box_mahnung_offen.php
* \ingroup mahnung * \ingroup mahnung
* \brief Widget: Aelteste offene Kundenrechnungen mit Mahnstufe. * \brief Widget: Aelteste offene Kundenrechnungen mit Mahnstufe.
* Basiert auf box_factures_imp.php, erweitert um Mahnstufe-Spalte.
*/ */
require_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php'; require_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php';
@ -17,12 +18,12 @@ 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/mahnung.class.php';
/** /**
* Widget: Offene Kundenrechnungen mit aktueller Mahnstufe. * Widget: Aelteste offene Kundenrechnungen mit Mahnstufe-Badge.
*/ */
class box_mahnung_offen extends ModeleBoxes class box_mahnung_offen extends ModeleBoxes
{ {
public $boxcode = "mahnungoffenerechnungen"; public $boxcode = "mahnungoffenerechnungen";
public $boximg = "fa-envelope-open-text"; public $boximg = "object_bill";
public $boxlabel = "MahnungBoxOffeneRechnungen"; public $boxlabel = "MahnungBoxOffeneRechnungen";
public $depends = array("facture", "mahnung"); public $depends = array("facture", "mahnung");
@ -51,8 +52,10 @@ class box_mahnung_offen extends ModeleBoxes
$facturestatic = new Facture($this->db); $facturestatic = new Facture($this->db);
$societestatic = new Societe($this->db); $societestatic = new Societe($this->db);
$textHead = $langs->trans("MahnungBoxOffeneRechnungen", $this->max);
$this->info_box_head = array( $this->info_box_head = array(
'text' => $langs->trans("MahnungBoxOffeneRechnungen", $this->max), 'text' => $textHead.'<a class="paddingleft valignmiddle" href="'.DOL_URL_ROOT.'/compta/facture/list.php?search_status=1&sortfield=f.date_lim_reglement,f.ref&sortorder=ASC,ASC"><span class="badge">...</span></a>',
'limit' => dol_strlen($textHead),
); );
if (!$user->hasRight('facture', 'lire')) { if (!$user->hasRight('facture', 'lire')) {
@ -63,20 +66,20 @@ class box_mahnung_offen extends ModeleBoxes
return; return;
} }
// Offene Rechnungen mit optionalem LEFT JOIN auf letzte aktive Mahnung // Query wie box_factures_imp, plus Mahnstufe per Subquery
$sql = "SELECT s.rowid as socid, s.nom as name, s.logo, s.email, s.entity,"; $sql = "SELECT s.rowid as socid, s.nom as name, s.code_client, s.client,";
$sql .= " s.code_client, s.client,"; $sql .= " s.logo, s.email, s.entity,";
$sql .= " f.rowid as facid, f.ref, f.type, f.datef as date,"; $sql .= " f.rowid as facid, f.ref, f.type, f.datef as date,";
$sql .= " f.date_lim_reglement as datelimit,"; $sql .= " f.date_lim_reglement as datelimit,";
$sql .= " f.total_ht, f.total_tva, f.total_ttc,"; $sql .= " f.total_ht, f.total_tva, f.total_ttc,";
$sql .= " f.paye, f.fk_statut as status,"; $sql .= " f.paye, f.fk_statut as status,";
$sql .= " COALESCE(SUM(pf.amount), 0) as am,"; $sql .= " SUM(pf.amount) as am,";
// Letzte Mahnstufe per Subquery // Letzte aktive Mahnstufe
$sql .= " (SELECT m2.stufe FROM ".MAIN_DB_PREFIX."mahnung_mahnung as m2"; $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 .= " WHERE m2.fk_facture = f.rowid AND m2.status != ".((int) Mahnung::STATUS_STORNIERT);
$sql .= " ORDER BY m2.stufe DESC LIMIT 1) as mahnstufe,"; $sql .= " ORDER BY m2.stufe DESC LIMIT 1) as mahnstufe,";
$sql .= " (SELECT m3.date_mahnung FROM ".MAIN_DB_PREFIX."mahnung_mahnung as m3"; $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 .= " WHERE m3.fk_facture = f.rowid AND m3.status != ".((int) Mahnung::STATUS_STORNIERT);
$sql .= " ORDER BY m3.stufe DESC LIMIT 1) as mahndatum"; $sql .= " ORDER BY m3.stufe DESC LIMIT 1) as mahndatum";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f"; $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc";
@ -84,15 +87,13 @@ class box_mahnung_offen extends ModeleBoxes
$sql .= " WHERE f.entity IN (".getEntity('invoice').")"; $sql .= " WHERE f.entity IN (".getEntity('invoice').")";
$sql .= " AND f.paye = 0"; $sql .= " AND f.paye = 0";
$sql .= " AND f.fk_statut = 1"; $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')) { 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).")"; $sql .= " AND s.rowid = (SELECT sc.fk_soc FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc WHERE sc.fk_soc = s.rowid AND sc.fk_user = ".((int) $user->id)." LIMIT 1)";
} }
if ($user->socid) { if ($user->socid) {
$sql .= " AND s.rowid = ".((int) $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 .= " GROUP BY s.rowid, s.nom, s.code_client, s.client, s.logo, s.email, s.entity,";
$sql .= " f.rowid, f.ref, f.type, f.datef, f.date_lim_reglement,"; $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 .= " 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 .= " ORDER BY f.date_lim_reglement ASC, f.ref ASC";
@ -110,13 +111,11 @@ class box_mahnung_offen extends ModeleBoxes
$num = $this->db->num_rows($result); $num = $this->db->num_rows($result);
$line = 0; $line = 0;
$l_due_date = $langs->trans('Late').' ('.strtolower($langs->trans('DateDue')).': %s)'; $l_due_date = $langs->trans('Late').' ('.strtolower($langs->trans('DateDue')).': %s)';
$totalHt = 0;
while ($line < min($num, $this->max)) { while ($line < min($num, $this->max)) {
$objp = $this->db->fetch_object($result); $objp = $this->db->fetch_object($result);
$datelimit = $this->db->jdate($objp->datelimit); $datelimit = $this->db->jdate($objp->datelimit);
$tageVerzug = (int) floor((dol_now() - $datelimit) / 86400);
$facturestatic->id = $objp->facid; $facturestatic->id = $objp->facid;
$facturestatic->ref = $objp->ref; $facturestatic->ref = $objp->ref;
@ -156,7 +155,7 @@ class box_mahnung_offen extends ModeleBoxes
$label = $labels[$stufe] ?? 'Stufe '.$stufe; $label = $labels[$stufe] ?? 'Stufe '.$stufe;
$mahnDatum = $objp->mahndatum ? dol_print_date($this->db->jdate($objp->mahndatum), 'day') : ''; $mahnDatum = $objp->mahndatum ? dol_print_date($this->db->jdate($objp->mahndatum), 'day') : '';
$tooltip = $label.($mahnDatum ? ' vom '.$mahnDatum : ''); $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>'; $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 // Spalte 1: Rechnung + Warnung
@ -186,20 +185,19 @@ class box_mahnung_offen extends ModeleBoxes
'text' => dol_print_date($datelimit, 'day', 'tzuserrel'), 'text' => dol_print_date($datelimit, 'day', 'tzuserrel'),
); );
// Spalte 5: Tage Verzug // Spalte 5: Status (wie Original)
$this->info_box_contents[$line][] = array( $this->info_box_contents[$line][] = array(
'td' => 'class="center nowraponall"', 'td' => 'class="right" width="18"',
'text' => $tageVerzug.' T.', 'text' => $facturestatic->LibStatut($objp->paye, $objp->status, 3, $objp->am, $objp->type),
); );
// Spalte 6: Mahnstufe // Spalte 6: Mahnstufe
$this->info_box_contents[$line][] = array( $this->info_box_contents[$line][] = array(
'td' => 'class="center nowraponall"', 'td' => 'class="center nowraponall"',
'text' => !empty($mahnBadge) ? $mahnBadge : '<span class="opacitymedium">—</span>', 'text' => !empty($mahnBadge) ? $mahnBadge : '',
'asis' => 1, 'asis' => 1,
); );
$totalHt += (float) $objp->total_ht;
$line++; $line++;
} }
@ -209,7 +207,23 @@ class box_mahnung_offen extends ModeleBoxes
} }
if ($num > 0) { if ($num > 0) {
// Summenzeile // Summe (wie Original: separate Query ohne LIMIT)
$sql2 = "SELECT SUM(f.total_ht) as total_ht";
$sql2 .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql2 .= " INNER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc";
$sql2 .= " WHERE f.entity IN (".getEntity('invoice').")";
$sql2 .= " AND f.paye = 0 AND f.fk_statut = 1";
if ($user->socid) {
$sql2 .= " AND s.rowid = ".((int) $user->socid);
}
$resTotal = $this->db->query($sql2);
$totalHt = 0;
if ($resTotal) {
$objTotal = $this->db->fetch_object($resTotal);
$totalHt = (float) $objTotal->total_ht;
$this->db->free($resTotal);
}
$this->info_box_contents[$line][] = array( $this->info_box_contents[$line][] = array(
'tr' => 'class="liste_total"', 'tr' => 'class="liste_total"',
'td' => 'class="liste_total"', 'td' => 'class="liste_total"',