bericht/api/customers.php
Eduard Wisch 5db126210c
All checks were successful
Deploy bericht / deploy (push) Successful in 2s
feat: Unterschriften-Härtung + Kundenkarten-API
Unterschrift (api/pages.php?action=signature):
- Metadaten einbrennen: Überschrift, Bericht-Ref, Parent-Ref, Kunde,
  Datum/Zeit (Server), Unterzeichner-Name, Bestätigungstext, GPS
- SHA256 Hash-Verkettung über alle vorherigen Seiten + Bericht-Ref
  → nachträgliches Austauschen von Seiten fällt auf
- Composite-Canvas: Header mit Metadaten, Unterschrift mittig,
  Footer mit Hash + Server + Zeitstempel
- Metadaten-JSON neben der PNG (für spätere Verifikation)
- signer_name ist Pflicht, gps_lat/gps_lon optional
- Page-Note zeigt Unterzeichner + Zeit statt nur 'Unterschrift Kunde'

Kundenkarten-API (api/customers.php):
- GET ohne id = Liste mit Suche (q-Param), zeigt Stammdaten + Bericht-Count
- GET mit id = Detail: Stammdaten, letzten 50 Aufträge, 50 Rechnungen,
  100 Berichte über UNION aus commande/facture JOIN
- Nur echte Kunden (client IN (1,2,3)), keine reinen Lieferanten

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
2026-04-09 08:06:21 +02:00

147 lines
5.4 KiB
PHP

<?php
/* GET /api/customers.php — Liste der Kunden mit letzten Berichten
* GET /api/customers.php?id=<soc_id> — Kunden-Detail: Stammdaten + Aufträge + Berichte
* GET /api/customers.php?q=<search> — Filter per Name
*/
require_once __DIR__.'/_inc.php';
api_authenticate();
global $db, $user, $conf, $langs;
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
$id = (int) ($_GET['id'] ?? 0);
$q = (string) ($_GET['q'] ?? '');
/* ----- LISTE ----- */
if (!$id) {
$where = "s.entity IN (".getEntity('societe').")";
if ($q !== '') {
$q_esc = $db->escape($q);
$where .= " AND (s.nom LIKE '%$q_esc%' OR s.code_client LIKE '%$q_esc%' OR s.town LIKE '%$q_esc%')";
}
// Standardmäßig nur Kunden (client=1 oder 3) — keine reinen Lieferanten
$where .= " AND (s.client = 1 OR s.client = 2 OR s.client = 3)";
$sql = "SELECT s.rowid, s.nom, s.code_client, s.zip, s.town, s.phone, s.email,"
." (SELECT COUNT(*) FROM ".$db->prefix()."bericht b"
." INNER JOIN ".$db->prefix()."commande c ON c.rowid = b.fk_element AND b.element_type='order' AND c.fk_soc = s.rowid) AS b_order,"
." (SELECT COUNT(*) FROM ".$db->prefix()."bericht b"
." INNER JOIN ".$db->prefix()."facture f ON f.rowid = b.fk_element AND b.element_type='invoice' AND f.fk_soc = s.rowid) AS b_invoice,"
." (SELECT MAX(c2.date_commande) FROM ".$db->prefix()."commande c2 WHERE c2.fk_soc = s.rowid) AS last_order_date"
." FROM ".$db->prefix()."societe s"
." WHERE ".$where
." ORDER BY last_order_date DESC, s.nom ASC"
." LIMIT 200";
$r = $db->query($sql);
if (!$r) api_fail('DB-Fehler: '.$db->lasterror(), 500);
$out = array();
while ($o = $db->fetch_object($r)) {
$bericht_count = (int) $o->b_order + (int) $o->b_invoice;
$out[] = array(
'id' => (int) $o->rowid,
'name' => $o->nom,
'code' => $o->code_client,
'zip' => $o->zip,
'town' => $o->town,
'phone' => $o->phone,
'email' => $o->email,
'bericht_count' => $bericht_count,
'last_order_date' => $o->last_order_date ? $db->jdate($o->last_order_date) : null,
);
}
api_ok(array('customers' => $out, 'count' => count($out)));
}
/* ----- DETAIL eines Kunden ----- */
$soc = new Societe($db);
if ($soc->fetch($id) <= 0) api_fail('Kunde nicht gefunden', 404);
// Aufträge des Kunden
$orders = array();
$ro = $db->query("SELECT c.rowid, c.ref, c.date_commande, c.fk_statut, c.total_ttc"
." FROM ".$db->prefix()."commande c"
." WHERE c.fk_soc = ".((int) $id)
." AND c.entity IN (".getEntity('commande').")"
." ORDER BY c.date_commande DESC, c.rowid DESC LIMIT 50");
if ($ro) {
while ($o = $db->fetch_object($ro)) {
// Bericht-Count pro Auftrag
$rb = $db->query("SELECT COUNT(*) AS n FROM ".$db->prefix()."bericht WHERE element_type='order' AND fk_element = ".((int) $o->rowid));
$bc = ($rb && ($rbo = $db->fetch_object($rb))) ? (int) $rbo->n : 0;
$orders[] = array(
'id' => (int) $o->rowid,
'ref' => $o->ref,
'date' => $db->jdate($o->date_commande),
'status' => (int) $o->fk_statut,
'total' => (float) $o->total_ttc,
'bericht_count' => $bc,
);
}
}
// Rechnungen des Kunden
$invoices = array();
$ri = $db->query("SELECT f.rowid, f.ref, f.datef, f.fk_statut, f.total_ttc"
." FROM ".$db->prefix()."facture f"
." WHERE f.fk_soc = ".((int) $id)
." AND f.entity IN (".getEntity('facture').")"
." ORDER BY f.datef DESC, f.rowid DESC LIMIT 50");
if ($ri) {
while ($f = $db->fetch_object($ri)) {
$invoices[] = array(
'id' => (int) $f->rowid,
'ref' => $f->ref,
'date' => $db->jdate($f->datef),
'status' => (int) $f->fk_statut,
'total' => (float) $f->total_ttc,
);
}
}
// Alle Berichte des Kunden (über Joins)
$reports = array();
$rr = $db->query(
"SELECT b.rowid, b.ref, b.titel, b.status, b.datec, b.element_type, c.ref AS parent_ref"
." FROM ".$db->prefix()."bericht b"
." INNER JOIN ".$db->prefix()."commande c ON c.rowid = b.fk_element"
." WHERE b.element_type = 'order' AND c.fk_soc = ".((int) $id)
." UNION "
."SELECT b.rowid, b.ref, b.titel, b.status, b.datec, b.element_type, f.ref AS parent_ref"
." FROM ".$db->prefix()."bericht b"
." INNER JOIN ".$db->prefix()."facture f ON f.rowid = b.fk_element"
." WHERE b.element_type = 'invoice' AND f.fk_soc = ".((int) $id)
." ORDER BY datec DESC LIMIT 100"
);
if ($rr) {
while ($b = $db->fetch_object($rr)) {
$reports[] = array(
'id' => (int) $b->rowid,
'ref' => $b->ref,
'titel' => $b->titel,
'status' => (int) $b->status,
'datec' => $db->jdate($b->datec),
'element_type' => $b->element_type,
'parent_ref' => $b->parent_ref,
);
}
}
api_ok(array(
'customer' => array(
'id' => (int) $soc->id,
'name' => $soc->name,
'code' => $soc->code_client,
'address' => $soc->address,
'zip' => $soc->zip,
'town' => $soc->town,
'country' => $soc->country,
'phone' => $soc->phone,
'email' => $soc->email,
'siret' => $soc->idprof1 ?? '',
'vat' => $soc->tva_intra ?? '',
),
'orders' => $orders,
'invoices' => $invoices,
'reports' => $reports,
));