Reiter am Kunden nur bei vorhandenen Berichten (1.7.1) [deploy]
All checks were successful
Deploy bericht / deploy (push) Successful in 13s

Der Reiter stand auf jeder Kundenkarte; auf Prod gibt es 9 Berichte
(ueber Auftraege/Rechnungen/Angebote) bei einem Teil der Kunden. Er
erscheint jetzt nur bei Bestand, mit Anzahl — reiner Lesereiter, kein
Anlegen-Weg geht verloren.

completeTabsHead in der vorhandenen Hook-Klasse ergaenzt (dieselbe
UNION-Abfrage wie bericht_thirdparty.php). Uebernimmt einen bereits
vorhandenen Eintrag desselben Schluessels statt einen zweiten
anzuhaengen — sonst waere der Reiter bis zur Reaktivierung doppelt (live
beobachtet und nachgezogen).

Lokal verifiziert: Kunde mit Berichten zeigt 'Berichte 1' einmalig.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-09-07 21:28:28 +02:00
parent 7f51c89d3f
commit f72e68b43e
3 changed files with 126 additions and 3 deletions

View file

@ -1,5 +1,17 @@
# Changelog # Changelog
## 1.7.1 — 2026-09-07
### Reiter am Kunden nur noch bei vorhandenen Berichten
Der Reiter „Berichte" stand auf **jeder** Kundenkarte. Die Reiterleiste dort trägt über 20
Einträge; auf Prod gibt es 9 Berichte (über Aufträge, Rechnungen, Angebote) bei einem Teil der
Kunden. Er erscheint jetzt nur bei Bestand, mit der Anzahl daneben — reiner Lesereiter, kein
Anlegen-Weg geht dadurch verloren.
Technisch als Hook (`class/actions_bericht.class.php`, `completeTabsHead`, gleiche UNION-
Abfrage wie `bericht_thirdparty.php`) statt festem Tab. Muster wie bei Mahnung,
ElektroPlanung, NetDiag, ElektroCheck. **Nach dem Deploy Modul einmal reaktivieren.**
## 1.7.0 — 2026-08-28 ## 1.7.0 — 2026-08-28
### Fotoqualität ist einstellbar — Vorgabe ist jetzt 1:1 ### Fotoqualität ist einstellbar — Vorgabe ist jetzt 1:1

View file

@ -8,6 +8,17 @@
class ActionsBericht class ActionsBericht
{ {
/** @var DoliDB */
private $db;
/**
* @param DoliDB $db Datenbank
*/
public function __construct($db)
{
$this->db = $db;
}
/** @var string */ /** @var string */
public $error = ''; public $error = '';
/** @var string[] */ /** @var string[] */
@ -74,4 +85,103 @@ class ActionsBericht
} }
return 0; return 0;
} }
/**
* Hook completeTabsHead: Reiter "Berichte" an der Kundenkarte nur bei
* vorhandenen Berichten. Ein fester Tab kann das nicht pruefen (verifCond()
* laesst keine Abfrage zu). Die Leiste dort traegt ueber 20 Eintraege
* (Stand 2026-09-07); auf Prod gibt es 9 Berichte bei einem Teil der Kunden.
* Reiner Lesereiter kein Anlegen-Weg, der verloren gehen koennte.
*
* @param array<string,mixed> $parameters Hook-Parameter (context, head, mode, filterorigmodule)
* @param object $object Societe
* @param string $action Aktuelle Aktion
* @param object $hookmanager Hook-Verwaltung
* @return int 0 = weiter
*/
public function completeTabsHead($parameters, &$object, &$action, $hookmanager)
{
global $langs, $user;
$contexts = explode(':', $parameters['context'] ?? '');
if (!in_array('thirdpartycard', $contexts, true)) {
return 0;
}
if (empty($object->id) || !isset($parameters['head']) || !is_array($parameters['head'])) {
return 0;
}
if (($parameters['mode'] ?? '') !== 'add' || ($parameters['filterorigmodule'] ?? '') !== 'external') {
return 0;
}
if (!$user->hasRight('bericht', 'read')) {
return 0;
}
$anzahl = $this->zaehleBerichte((int) $object->id);
$head = &$parameters['head'];
// Der frühere feste Tab steht bis zur Modul-Reaktivierung als
// MAIN_MODULE_BERICHT_TABS_3 in der Datenbank — vorhandenen Eintrag
// uebernehmen statt einen zweiten anzuhaengen, sonst waere der Reiter doppelt.
$vorhanden = -1;
foreach ($head as $i => $eintrag) {
if (isset($eintrag[2]) && $eintrag[2] === 'bericht') {
$vorhanden = $i;
break;
}
}
if ($anzahl < 1) {
if ($vorhanden >= 0) {
unset($head[$vorhanden]);
$head = array_values($head);
}
return 0;
}
$langs->load('bericht@bericht');
$pos = ($vorhanden >= 0) ? $vorhanden : count($head);
$head[$pos][0] = DOL_URL_ROOT.'/custom/bericht/bericht_thirdparty.php?socid='.((int) $object->id);
$head[$pos][1] = $langs->trans('Berichte').' <span class="badge">'.$anzahl.'</span>';
$head[$pos][2] = 'bericht';
return 0;
}
/**
* Wie viele Berichte (an Auftrag, Rechnung oder Angebot) haengen an diesem Kunden?
* Gleiche UNION-Abfrage wie in bericht_thirdparty.php.
*
* @param int $socId Kunde
* @return int Anzahl
*/
private function zaehleBerichte($socId)
{
if ($socId <= 0) {
return 0;
}
$sql = "SELECT COUNT(*) AS anzahl FROM (";
$sql .= "SELECT b.rowid FROM ".MAIN_DB_PREFIX."bericht b";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."commande c ON c.rowid = b.fk_element";
$sql .= " WHERE b.element_type = 'order' AND c.fk_soc = ".((int) $socId);
$sql .= " UNION ";
$sql .= "SELECT b.rowid FROM ".MAIN_DB_PREFIX."bericht b";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."facture f ON f.rowid = b.fk_element";
$sql .= " WHERE b.element_type = 'invoice' AND f.fk_soc = ".((int) $socId);
$sql .= " UNION ";
$sql .= "SELECT b.rowid FROM ".MAIN_DB_PREFIX."bericht b";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."propal p ON p.rowid = b.fk_element";
$sql .= " WHERE b.element_type = 'propal' AND p.fk_soc = ".((int) $socId);
$sql .= ") AS alle";
$resql = $this->db->query($sql);
if (!$resql) {
return 0;
}
$obj = $this->db->fetch_object($resql);
return $obj ? (int) $obj->anzahl : 0;
}
} }

View file

@ -27,7 +27,7 @@ class modBericht extends DolibarrModules
$this->editor_name = 'Alles Watt läuft'; $this->editor_name = 'Alles Watt läuft';
$this->editor_url = ''; $this->editor_url = '';
$this->version = '1.6.0'; $this->version = '1.7.1';
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
$this->picto = 'fa-file-pdf'; $this->picto = 'fa-file-pdf';
@ -43,7 +43,7 @@ class modBericht extends DolibarrModules
'theme' => 0, 'theme' => 0,
'css' => array('/bericht/css/bericht.css'), 'css' => array('/bericht/css/bericht.css'),
'js' => array(), 'js' => array(),
'hooks' => array('data' => array('odtgeneration')), 'hooks' => array('data' => array('odtgeneration', 'thirdpartycard')),
'moduleforexternal' => 0, 'moduleforexternal' => 0,
); );
@ -90,7 +90,8 @@ class modBericht extends DolibarrModules
'invoice:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=invoice', 'invoice:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=invoice',
'order:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=order', 'order:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=order',
'propal:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=propal', 'propal:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=propal',
'thirdparty:+bericht:Berichte:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_thirdparty.php?socid=__ID__', // Am KUNDEN setzt den Reiter die Hook-Klasse (nur bei vorhandenen
// Berichten) — ein fester Tab kann das nicht pruefen.
'shipping:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=shipment', 'shipping:+bericht:Bericht:bericht@bericht:$user->hasRight("bericht","read"):/custom/bericht/bericht_card.php?id=__ID__&element=shipment',
); );