feat: Phase 2.3 + 2.4 — REST-API mit JWT-Auth
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
- api/_jwt.php: HS256 JWT encode/decode/from_request, Secret aus
dolibarr_main_instance_unique_id, 7 Tage TTL
- api/_inc.php: gemeinsamer API-Init mit CORS, JSON-Helpers,
api_authenticate() lädt User aus JWT und prüft bericht/read
- api/auth.php: POST { login, password } → JWT mit user + perms
- api/orders.php:
- GET /api/orders.php — Liste der Aufträge des Users (Multi-User
Filter über fk_user_*, Admin sieht alle)
- GET /api/orders.php?id=X — Auftrags-Detail mit Kunde + Berichten
- GET /api/orders.php?id=X&action=photos — Anhänge
- POST /api/orders.php?id=X&action=upload_photo — Foto hochladen,
Bericht wird automatisch angelegt falls nicht vorhanden
- api/reports.php:
- GET /api/reports.php?id=X — Bericht-Detail + Seiten
- POST /api/reports.php?id=X&action=finalize — Status auf final
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
This commit is contained in:
parent
3d84f7e0be
commit
bed611cd8b
5 changed files with 467 additions and 0 deletions
102
api/_inc.php
Normal file
102
api/_inc.php
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/* Gemeinsamer API-Init für alle Bericht-API-Endpoints.
|
||||
*
|
||||
* - Lädt Dolibarr ohne Login (NOLOGIN), wir machen User-Auth selbst per JWT
|
||||
* - CORS für die PWA
|
||||
* - JSON Request/Response Helpers
|
||||
* - Authentifiziert per JWT (außer auth.php)
|
||||
*/
|
||||
|
||||
if (!defined('NOLOGIN')) define('NOLOGIN', '1');
|
||||
if (!defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1');
|
||||
if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1');
|
||||
if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1');
|
||||
if (!defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1');
|
||||
if (!defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1');
|
||||
|
||||
$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 && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
||||
if (!$res) die("Include of main fails");
|
||||
|
||||
require_once __DIR__.'/_jwt.php';
|
||||
require_once __DIR__.'/../class/bericht.class.php';
|
||||
require_once __DIR__.'/../lib/bericht.lib.php';
|
||||
|
||||
// CORS — die PWA läuft auf der gleichen Domain (subpfad), aber wir sind defensiv
|
||||
$allowed_origin = '*'; // bei Bedarf in Konstante BERICHT_API_CORS_ORIGIN packen
|
||||
if (getDolGlobalString('BERICHT_API_CORS_ORIGIN')) {
|
||||
$allowed_origin = getDolGlobalString('BERICHT_API_CORS_ORIGIN');
|
||||
}
|
||||
header('Access-Control-Allow-Origin: '.$allowed_origin);
|
||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
||||
header('Access-Control-Max-Age: 86400');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(204);
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
function api_send($data, $code = 200)
|
||||
{
|
||||
http_response_code($code);
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function api_fail($msg, $code = 400)
|
||||
{
|
||||
api_send(array('error' => $msg), $code);
|
||||
}
|
||||
|
||||
function api_ok($data = array())
|
||||
{
|
||||
api_send(array_merge(array('ok' => true), $data));
|
||||
}
|
||||
|
||||
function api_input()
|
||||
{
|
||||
$body = file_get_contents('php://input');
|
||||
if (!$body) return $_POST;
|
||||
$json = json_decode($body, true);
|
||||
return is_array($json) ? $json : $_POST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt den User aus dem JWT und liefert das User-Objekt zurück.
|
||||
* Beendet bei ungültigem/fehlendem Token.
|
||||
*/
|
||||
function api_authenticate($db_param = null)
|
||||
{
|
||||
global $db, $user, $conf;
|
||||
if ($db_param) $db = $db_param;
|
||||
|
||||
$payload = bericht_jwt_from_request();
|
||||
if (!$payload || empty($payload['sub'])) {
|
||||
api_fail('Token ungültig oder fehlt', 401);
|
||||
}
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
||||
$u = new User($db);
|
||||
if ($u->fetch((int) $payload['sub']) <= 0) {
|
||||
api_fail('User nicht gefunden', 401);
|
||||
}
|
||||
if (empty($u->statut)) {
|
||||
api_fail('User deaktiviert', 401);
|
||||
}
|
||||
$u->loadRights();
|
||||
$user = $u;
|
||||
|
||||
if (!$user->hasRight('bericht', 'read')) {
|
||||
api_fail('Keine Bericht-Rechte', 403);
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
66
api/_jwt.php
Normal file
66
api/_jwt.php
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/* Mini JWT Helper für die Bericht-API.
|
||||
* HS256 only — kein externes Lib nötig.
|
||||
*
|
||||
* Secret kommt aus $dolibarr_main_instance_unique_id (siehe conf.php),
|
||||
* salt'ed mit "bericht-api-v1".
|
||||
*/
|
||||
|
||||
if (!defined('BERICHT_JWT_TTL')) define('BERICHT_JWT_TTL', 7 * 86400); // 7 Tage
|
||||
|
||||
function bericht_jwt_secret()
|
||||
{
|
||||
global $dolibarr_main_instance_unique_id;
|
||||
$base = $dolibarr_main_instance_unique_id ?? 'fallback-secret-do-not-use';
|
||||
return hash('sha256', $base.'|bericht-api-v1');
|
||||
}
|
||||
|
||||
function bericht_b64url_encode($data)
|
||||
{
|
||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
function bericht_b64url_decode($data)
|
||||
{
|
||||
return base64_decode(strtr($data, '-_', '+/').str_repeat('=', (4 - strlen($data) % 4) % 4));
|
||||
}
|
||||
|
||||
function bericht_jwt_encode(array $payload)
|
||||
{
|
||||
$header = array('alg' => 'HS256', 'typ' => 'JWT');
|
||||
$h = bericht_b64url_encode(json_encode($header));
|
||||
$p = bericht_b64url_encode(json_encode($payload));
|
||||
$sig = hash_hmac('sha256', $h.'.'.$p, bericht_jwt_secret(), true);
|
||||
return $h.'.'.$p.'.'.bericht_b64url_encode($sig);
|
||||
}
|
||||
|
||||
function bericht_jwt_decode($token)
|
||||
{
|
||||
$parts = explode('.', $token);
|
||||
if (count($parts) !== 3) return null;
|
||||
list($h, $p, $s) = $parts;
|
||||
$expected = bericht_b64url_encode(hash_hmac('sha256', $h.'.'.$p, bericht_jwt_secret(), true));
|
||||
if (!hash_equals($expected, $s)) return null;
|
||||
$payload = json_decode(bericht_b64url_decode($p), true);
|
||||
if (!is_array($payload)) return null;
|
||||
if (isset($payload['exp']) && $payload['exp'] < time()) return null;
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liest und validiert das Authorization: Bearer <jwt> Header.
|
||||
* @return array|null decoded payload
|
||||
*/
|
||||
function bericht_jwt_from_request()
|
||||
{
|
||||
$hdr = '';
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$hdr = $_SERVER['HTTP_AUTHORIZATION'];
|
||||
} elseif (function_exists('apache_request_headers')) {
|
||||
$h = apache_request_headers();
|
||||
if (isset($h['Authorization'])) $hdr = $h['Authorization'];
|
||||
}
|
||||
if (!$hdr || stripos($hdr, 'bearer ') !== 0) return null;
|
||||
$token = trim(substr($hdr, 7));
|
||||
return bericht_jwt_decode($token);
|
||||
}
|
||||
61
api/auth.php
Normal file
61
api/auth.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/* POST /api/auth.php
|
||||
* Body: { "login": "...", "password": "..." }
|
||||
* Response: { "token": "...", "user": { id, login, fullname }, "expires": <unix> }
|
||||
*/
|
||||
require_once __DIR__.'/_inc.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') api_fail('POST erforderlich', 405);
|
||||
|
||||
$in = api_input();
|
||||
$login = trim($in['login'] ?? '');
|
||||
$pass = (string) ($in['password'] ?? '');
|
||||
if (empty($login) || empty($pass)) api_fail('login + password erforderlich');
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
||||
|
||||
$u = new User($db);
|
||||
if ($u->fetch('', $login) <= 0) api_fail('Login fehlgeschlagen', 401);
|
||||
|
||||
// Passwort prüfen — Dolibarr's checkPassword braucht den schon geladenen User
|
||||
if (!dol_verifyHash($pass, $u->pass_indatabase_crypted ?: $u->pass_indatabase)) {
|
||||
// Fallback: alter Hash-Vergleich
|
||||
if (md5($pass) !== $u->pass_indatabase) {
|
||||
api_fail('Login fehlgeschlagen', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($u->statut)) api_fail('User deaktiviert', 403);
|
||||
|
||||
$u->loadRights();
|
||||
if (!$u->hasRight('bericht', 'read')) api_fail('Keine Bericht-Rechte', 403);
|
||||
|
||||
// JWT erstellen
|
||||
$exp = time() + BERICHT_JWT_TTL;
|
||||
$payload = array(
|
||||
'sub' => (int) $u->id,
|
||||
'login' => $u->login,
|
||||
'name' => method_exists($u, 'getFullName') ? $u->getFullName($langs ?? null) : $u->login,
|
||||
'iat' => time(),
|
||||
'exp' => $exp,
|
||||
'iss' => 'bericht-api',
|
||||
'perms' => array(
|
||||
'read' => (bool) $u->hasRight('bericht', 'read'),
|
||||
'write' => (bool) $u->hasRight('bericht', 'write'),
|
||||
'delete' => (bool) $u->hasRight('bericht', 'delete'),
|
||||
'admin' => (bool) $u->hasRight('bericht', 'admin'),
|
||||
),
|
||||
);
|
||||
$token = bericht_jwt_encode($payload);
|
||||
|
||||
api_ok(array(
|
||||
'token' => $token,
|
||||
'expires' => $exp,
|
||||
'user' => array(
|
||||
'id' => (int) $u->id,
|
||||
'login' => $u->login,
|
||||
'name' => $payload['name'],
|
||||
'admin' => (bool) ($u->admin ?? false),
|
||||
),
|
||||
'perms' => $payload['perms'],
|
||||
));
|
||||
180
api/orders.php
Normal file
180
api/orders.php
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
/* GET /api/orders.php
|
||||
* Liefert Aufträge des aktuellen Users.
|
||||
* GET /api/orders.php?id=<id>
|
||||
* Liefert Detail eines einzelnen Auftrags.
|
||||
* GET /api/orders.php?id=<id>&action=photos
|
||||
* Liefert die Anhang-Bilder/PDFs eines Auftrags.
|
||||
* POST /api/orders.php?id=<id>&action=upload_photo
|
||||
* multipart: file=<binary> — fügt ein Foto zum Bericht des Auftrags hinzu
|
||||
* (legt automatisch einen Bericht an wenn keiner existiert)
|
||||
*/
|
||||
require_once __DIR__.'/_inc.php';
|
||||
|
||||
api_authenticate();
|
||||
global $db, $user, $conf;
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
||||
|
||||
$id = (int) ($_GET['id'] ?? 0);
|
||||
$action = $_GET['action'] ?? '';
|
||||
|
||||
/* ----- LISTE ----- */
|
||||
if (!$id) {
|
||||
// Filter: nur Aufträge des aktuellen Users (oder Admin sieht alle)
|
||||
$where = "c.entity IN (".getEntity('commande').")";
|
||||
if (empty($user->admin)) {
|
||||
$where .= " AND (c.fk_user_author = ".((int) $user->id)
|
||||
." OR c.fk_user_valid = ".((int) $user->id)
|
||||
." OR c.fk_user_modif = ".((int) $user->id).")";
|
||||
}
|
||||
|
||||
// Optional: nur offene
|
||||
if (!empty($_GET['open'])) {
|
||||
$where .= " AND c.fk_statut IN (1, 2)"; // validiert + in Bearbeitung
|
||||
}
|
||||
// Suchterm
|
||||
if (!empty($_GET['q'])) {
|
||||
$q = $db->escape($_GET['q']);
|
||||
$where .= " AND (c.ref LIKE '%$q%' OR s.nom LIKE '%$q%')";
|
||||
}
|
||||
|
||||
$sql = "SELECT c.rowid, c.ref, c.date_commande, c.fk_statut, c.total_ttc,"
|
||||
." s.rowid AS soc_id, s.nom AS soc_name, s.zip, s.town, s.address,"
|
||||
." (SELECT COUNT(*) FROM ".$db->prefix()."bericht b WHERE b.element_type='order' AND b.fk_element=c.rowid) AS bericht_count"
|
||||
." FROM ".$db->prefix()."commande c"
|
||||
." LEFT JOIN ".$db->prefix()."societe s ON s.rowid = c.fk_soc"
|
||||
." WHERE ".$where
|
||||
." ORDER BY c.date_commande DESC, c.rowid DESC"
|
||||
." LIMIT 200";
|
||||
|
||||
$r = $db->query($sql);
|
||||
if (!$r) api_fail('DB-Fehler: '.$db->lasterror(), 500);
|
||||
$orders = array();
|
||||
while ($o = $db->fetch_object($r)) {
|
||||
$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,
|
||||
'customer' => array(
|
||||
'id' => (int) $o->soc_id,
|
||||
'name' => $o->soc_name,
|
||||
'zip' => $o->zip,
|
||||
'town' => $o->town,
|
||||
'address' => $o->address,
|
||||
),
|
||||
'bericht_count' => (int) $o->bericht_count,
|
||||
);
|
||||
}
|
||||
api_ok(array('orders' => $orders, 'count' => count($orders)));
|
||||
}
|
||||
|
||||
/* ----- DETAIL eines Auftrags ----- */
|
||||
$cmd = new Commande($db);
|
||||
if ($cmd->fetch($id) <= 0) api_fail('Auftrag nicht gefunden', 404);
|
||||
$cmd->fetch_thirdparty();
|
||||
if (method_exists($cmd, 'fetch_optionals')) $cmd->fetch_optionals();
|
||||
|
||||
if ($action === 'photos') {
|
||||
// Anhänge des Auftrags
|
||||
$upload_dir = $conf->commande->multidir_output[$cmd->entity].'/'.dol_sanitizeFileName($cmd->ref);
|
||||
$files = is_dir($upload_dir)
|
||||
? dol_dir_list($upload_dir, 'files', 1, '', '(\.meta|_preview.*\.png|thumbs)$')
|
||||
: array();
|
||||
$out = array();
|
||||
foreach ($files as $f) {
|
||||
$out[] = array(
|
||||
'filename' => $f['name'],
|
||||
'size' => (int) $f['size'],
|
||||
'mime' => dol_mimetype($f['name']),
|
||||
'date' => (int) $f['date'],
|
||||
'relpath' => str_replace(DOL_DATA_ROOT.'/', '', $f['fullname']),
|
||||
);
|
||||
}
|
||||
api_ok(array('photos' => $out, 'count' => count($out)));
|
||||
}
|
||||
|
||||
if ($action === 'upload_photo' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!$user->hasRight('bericht', 'write')) api_fail('Schreibrechte fehlen', 403);
|
||||
if (empty($_FILES['file']['tmp_name'])) api_fail('file fehlt');
|
||||
|
||||
// Bericht zum Auftrag suchen oder neu anlegen
|
||||
$list = Bericht::fetchAllForElement($db, 'order', $cmd->id);
|
||||
$bericht = !empty($list) ? $list[0] : null;
|
||||
if (!$bericht) {
|
||||
$bericht = new Bericht($db);
|
||||
$bericht->element_type = 'order';
|
||||
$bericht->fk_element = $cmd->id;
|
||||
$bericht->titel = 'Bericht '.$cmd->ref;
|
||||
$bericht->auftragsnummer = $cmd->ref;
|
||||
$bericht->template_odt = getDolGlobalString('BERICHT_DEFAULT_TEMPLATE', '');
|
||||
if ($bericht->create($user) <= 0) api_fail('Bericht-Anlage fehlgeschlagen', 500);
|
||||
}
|
||||
|
||||
// Datei speichern
|
||||
$orig = dol_sanitizeFileName($_FILES['file']['name']);
|
||||
$ext = strtolower(pathinfo($orig, PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, array('jpg', 'jpeg', 'png'))) api_fail('Dateityp nicht unterstützt');
|
||||
|
||||
$workdir = DOL_DATA_ROOT.'/bericht/work/'.$bericht->id;
|
||||
if (!is_dir($workdir)) dol_mkdir($workdir);
|
||||
$target = $workdir.'/api_'.dol_print_date(dol_now(), '%Y%m%d_%H%M%S').'_'.uniqid().'.'.$ext;
|
||||
if (!move_uploaded_file($_FILES['file']['tmp_name'], $target)) api_fail('Upload fehlgeschlagen', 500);
|
||||
|
||||
$relpath = str_replace(DOL_DATA_ROOT.'/', '', $target);
|
||||
|
||||
// Als Page anlegen
|
||||
$resm = $db->query("SELECT COALESCE(MAX(page_order),0) AS m FROM ".$db->prefix()."bericht_page WHERE fk_bericht = ".((int) $bericht->id));
|
||||
$next = ($resm && ($o = $db->fetch_object($resm))) ? ((int) $o->m) + 1 : 1;
|
||||
$page = new BerichtPage($db);
|
||||
$page->fk_bericht = $bericht->id;
|
||||
$page->page_order = $next;
|
||||
$page->source_type = 'upload';
|
||||
$page->source_path = $relpath;
|
||||
if ($page->create() <= 0) api_fail('Page-Insert fehlgeschlagen', 500);
|
||||
|
||||
api_ok(array(
|
||||
'bericht_id' => (int) $bericht->id,
|
||||
'page_id' => (int) $page->id,
|
||||
'filename' => basename($target),
|
||||
));
|
||||
}
|
||||
|
||||
// Default: Auftrags-Detail
|
||||
$berichte = Bericht::fetchAllForElement($db, 'order', $cmd->id);
|
||||
$berichte_out = array();
|
||||
foreach ($berichte as $b) {
|
||||
$berichte_out[] = array(
|
||||
'id' => (int) $b->id,
|
||||
'ref' => $b->ref,
|
||||
'titel' => $b->titel,
|
||||
'status' => (int) $b->status,
|
||||
'datec' => (int) $b->datec,
|
||||
);
|
||||
}
|
||||
|
||||
api_ok(array(
|
||||
'order' => array(
|
||||
'id' => (int) $cmd->id,
|
||||
'ref' => $cmd->ref,
|
||||
'date' => $cmd->date_commande,
|
||||
'status'=> (int) $cmd->statut,
|
||||
'total' => (float) $cmd->total_ttc,
|
||||
'note_private' => $cmd->note_private,
|
||||
'auftragsbeschreibung' => $cmd->array_options['options_auftragsbeschreibung'] ?? '',
|
||||
),
|
||||
'customer' => array(
|
||||
'id' => (int) ($cmd->thirdparty->id ?? 0),
|
||||
'name' => $cmd->thirdparty->name ?? '',
|
||||
'address' => $cmd->thirdparty->address ?? '',
|
||||
'zip' => $cmd->thirdparty->zip ?? '',
|
||||
'town' => $cmd->thirdparty->town ?? '',
|
||||
'phone' => $cmd->thirdparty->phone ?? '',
|
||||
'email' => $cmd->thirdparty->email ?? '',
|
||||
),
|
||||
'berichte' => $berichte_out,
|
||||
));
|
||||
58
api/reports.php
Normal file
58
api/reports.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/* GET /api/reports.php?id=<id> — Detail eines Berichts
|
||||
* POST /api/reports.php?id=<id>&action=finalize — Finalisierung anstoßen
|
||||
*
|
||||
* Listing aller Berichte läuft über orders.php (pro Auftrag).
|
||||
*/
|
||||
require_once __DIR__.'/_inc.php';
|
||||
|
||||
api_authenticate();
|
||||
global $db, $user;
|
||||
|
||||
$id = (int) ($_GET['id'] ?? 0);
|
||||
$action = $_GET['action'] ?? '';
|
||||
|
||||
if (!$id) api_fail('id erforderlich');
|
||||
|
||||
$bericht = new Bericht($db);
|
||||
if ($bericht->fetch($id) <= 0) api_fail('Bericht nicht gefunden', 404);
|
||||
|
||||
if ($action === 'finalize') {
|
||||
if (!$user->hasRight('bericht', 'write')) api_fail('Schreibrechte fehlen', 403);
|
||||
// Wir rufen generate_pdf.php intern auf, indem wir die Logik laden — einfacher: redirect
|
||||
// Hier simpler Ansatz: setze Status auf Final (echte PDF-Generierung sollte separat triggern)
|
||||
$bericht->status = Bericht::STATUS_FINAL;
|
||||
$bericht->update($user);
|
||||
api_ok(array('status' => 'final'));
|
||||
}
|
||||
|
||||
// Detail
|
||||
$pages = BerichtPage::fetchAllForBericht($db, $bericht->id);
|
||||
$pages_out = array();
|
||||
foreach ($pages as $p) {
|
||||
$pages_out[] = array(
|
||||
'id' => (int) $p->id,
|
||||
'page_order' => (int) $p->page_order,
|
||||
'source_type'=> $p->source_type,
|
||||
'source_path'=> $p->source_path,
|
||||
'rotation' => (int) $p->rotation,
|
||||
'note' => $p->note,
|
||||
'layout' => $p->layout,
|
||||
);
|
||||
}
|
||||
|
||||
api_ok(array(
|
||||
'report' => array(
|
||||
'id' => (int) $bericht->id,
|
||||
'ref' => $bericht->ref,
|
||||
'titel' => $bericht->titel,
|
||||
'auftragsnummer' => $bericht->auftragsnummer,
|
||||
'element_type' => $bericht->element_type,
|
||||
'fk_element' => (int) $bericht->fk_element,
|
||||
'page_format' => $bericht->page_format,
|
||||
'page_orientation'=> $bericht->page_orientation,
|
||||
'status' => (int) $bericht->status,
|
||||
'datec' => (int) $bericht->datec,
|
||||
),
|
||||
'pages' => $pages_out,
|
||||
));
|
||||
Loading…
Reference in a new issue