dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
-myLKW_dispo.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\myLKW;
3
4
6
7 private string $dd_lkw = 'lkw';
8 private string $dd_dispo = 'lkw_dispo_dia';
9 private $oDB;
10
11 public function __construct(){
12 $this->oDB = dbx()->get_system_obj('dbxDB');
13 }
14
15 /* ========================================================= */
16
18 public function run() {
19
20 $work = dbx()->get_modul_var('dbx_run2','create_tab','parameter');
21 dbx_debug("myLKW_order run work=($work)");
22 switch($work){
23
24 case 'create_tab': // default
25 // Liefert HTML Modul Template zurück (Page Template ersetzt [dbx:content])
26 return $this->create_tab();
27
28 case 'read_dispo':
29 // Liefert JSON direkt an Browser und beendet Skript
30 $this->read_dispo();
31 break;
32
33 case 'save_dispo':
34 // Speichert Datensatz, JSON Response + exit
35 $this->save_dispo();
36 break;
37
38 case 'delete_dispo':
39 // Löscht Datensatz, JSON Response + exit
40 $this->delete_dispo();
41 break;
42
43 default:
44 return "Unbekannte Aktion ($work)";
45 }
46 }
47
48 /* ========================================================= */
49
51 private function create_tab() {
52
53 $oTPL = dbx()->get_system_obj('dbxTPL');
54
55 $cols = <<<JS
56 [
57 {
58 title: "LKW",
59 columns: [
60 { title: "Tractor", field: "TRACTOR", width: 120 },
61 { title: "Remolque", field: "REMOLQUE", width: 120 },
62 { title: "Conductor", field: "CONDUCTOR", width: 160 },
63 { title: "Tipo", field: "TIPO", width: 80 }
64 ]
65 },
66 {
67 title: "Hoy",
68 columns: [
69 { title: "Origen Reg", field: "d0_origen_region", width: 90 },
70 { title: "Origen", field: "d0_origen_lugar", width: 140 },
71 { title: "Carga Reg", field: "d0_carga_region", width: 90 },
72 { title: "Carga", field: "d0_carga_lugar", width: 140 },
73 { title: "Hora Prev", field: "d0_hora_prev", width: 90 },
74 { title: "Hora Real", field: "d0_hora_real", width: 90 },
75 { title: "Estado", field: "d0_estado", width: 90 },
76 { title: "Taller", field: "d0_taller", width: 70 }
77 ]
78 },
79 {
80 title: "Mañana",
81 columns: [
82 { title: "Origen Reg", field: "d1_origen_region", width: 90 },
83 { title: "Origen", field: "d1_origen_lugar", width: 140 },
84 { title: "Carga Reg", field: "d1_carga_region", width: 90 },
85 { title: "Carga", field: "d1_carga_lugar", width: 140 },
86 { title: "Hora Prev", field: "d1_hora_prev", width: 90 },
87 { title: "Hora Real", field: "d1_hora_real", width: 90 },
88 { title: "Estado", field: "d1_estado", width: 90 },
89 { title: "Taller", field: "d1_taller", width: 70 }
90 ]
91 },
92 {
93 title: "Sig Día",
94 columns: [
95 { title: "Origen Reg", field: "d2_origen_region", width: 90 },
96 { title: "Origen", field: "d2_origen_lugar", width: 140 },
97 { title: "Carga Reg", field: "d2_carga_region", width: 90 },
98 { title: "Carga", field: "d2_carga_lugar", width: 140 },
99 { title: "Hora Prev", field: "d2_hora_prev", width: 90 },
100 { title: "Hora Real", field: "d2_hora_real", width: 90 },
101 { title: "Estado", field: "d2_estado", width: 90 },
102 { title: "Taller", field: "d2_taller", width: 70 }
103 ]
104 },
105
106 { field: "id", visible: false },
107 { field: "d0_dispo_id", visible: false },
108 { field: "d0_update_date", visible: false },
109 { field: "d1_dispo_id", visible: false },
110 { field: "d1_update_date", visible: false },
111 { field: "d2_dispo_id", visible: false },
112 { field: "d2_update_date", visible: false }
113 ]
114 JS;
115
116 $data['cols'] = $cols;
117
118 return $oTPL->get_tpl('modul','report-dispo',$data);
119 }
120
121
122
123 /* ========================================================= */
125 private function read_dispo(){
126
127 /* --------------------------------------------------------- */
128 /* 0. GLOBALEN TAGESWECHSEL SICHERSTELLEN */
129 /* --------------------------------------------------------- */
130 $this->ensure_dispo_rollover();
131
132 /* --------------------------------------------------------- */
133 /* 1. Dispo-Tage bestimmen (nur Werktage) */
134 /* --------------------------------------------------------- */
135 $today = date('Y-m-d');
136 $days = $this->getNextWorkdays($today, 3);
137
138 $d0 = $days[0];
139 $d1 = $days[1];
140 $d2 = $days[2];
141
142 /* --------------------------------------------------------- */
143 /* 2. LKW-Stammdaten laden */
144 /* --------------------------------------------------------- */
145 $lkwCols = $this->oDB->get_dd_cols($this->dd_lkw);
146
147 $lkwRows = $this->oDB->select(
148 $this->dd_lkw,
149 '',
150 $lkwCols,
151 'TIPO DESC, TRACTOR ASC',
152 '',
153 '',
154 1000,
155 0
156 );
157
158 if (!is_array($lkwRows)) {
159 $lkwRows = [];
160 }
161
162 /* --------------------------------------------------------- */
163 /* 3. Dispo-Daten für d0/d1/d2 laden */
164 /* --------------------------------------------------------- */
165 $dispoCols = $this->oDB->get_dd_cols($this->dd_dispo);
166
167 $where = "fecha_trabajo IN ('$d0','$d1','$d2')";
168
169 $dispoRows = $this->oDB->select(
170 $this->dd_dispo,
171 $where,
172 $dispoCols,
173 '',
174 '',
175 '',
176 5000,
177 0
178 );
179
180 if (!is_array($dispoRows)) {
181 $dispoRows = [];
182 }
183
184 /* --------------------------------------------------------- */
185 /* 4. Dispo-Daten indexieren: [lkw_id][fecha_trabajo] */
186 /* --------------------------------------------------------- */
187 $dispoMap = [];
188
189 foreach ($dispoRows as $row) {
190 $lid = (int)$row['lkw_id'];
191 $day = $row['fecha_trabajo'];
192 $dispoMap[$lid][$day] = $row;
193 }
194
195 /* --------------------------------------------------------- */
196 /* 5. Ergebniszeilen bauen (EXAKT Template-Felder!) */
197 /* --------------------------------------------------------- */
198 $result = [];
199
200 foreach ($lkwRows as $lkw) {
201
202 $lid = (int)$lkw['id'];
203 $row = $lkw;
204
205 /* ================= d0 ================= */
206 $d = $dispoMap[$lid][$d0] ?? null;
207 $row['d0_origen_region'] = $d['origen_region'] ?? null;
208 $row['d0_origen_lugar'] = $d['origen_lugar'] ?? null;
209 $row['d0_carga_region'] = $d['carga_region'] ?? null;
210 $row['d0_carga_lugar'] = $d['carga_lugar'] ?? null;
211 $row['d0_hora_prev'] = $d['hora_descarga_prevista'] ?? null;
212 $row['d0_hora_real'] = $d['hora_descarga_real'] ?? null;
213 $row['d0_estado'] = $d['estado_carga'] ?? null;
214 $row['d0_dispo_id'] = $d['id'] ?? null;
215 $row['d0_update_date'] = $d['update_date'] ?? null;
216
217 /* ================= d1 ================= */
218 $d = $dispoMap[$lid][$d1] ?? null;
219 $row['d1_origen_region'] = $d['origen_region'] ?? null;
220 $row['d1_origen_lugar'] = $d['origen_lugar'] ?? null;
221 $row['d1_carga_region'] = $d['carga_region'] ?? null;
222 $row['d1_carga_lugar'] = $d['carga_lugar'] ?? null;
223 $row['d1_hora_prev'] = $d['hora_descarga_prevista'] ?? null;
224 $row['d1_hora_real'] = $d['hora_descarga_real'] ?? null;
225 $row['d1_estado'] = $d['estado_carga'] ?? null;
226 $row['d1_dispo_id'] = $d['id'] ?? null;
227 $row['d1_update_date'] = $d['update_date'] ?? null;
228
229 /* ================= d2 ================= */
230 $d = $dispoMap[$lid][$d2] ?? null;
231 $row['d2_origen_region'] = $d['origen_region'] ?? null;
232 $row['d2_origen_lugar'] = $d['origen_lugar'] ?? null;
233 $row['d2_carga_region'] = $d['carga_region'] ?? null;
234 $row['d2_carga_lugar'] = $d['carga_lugar'] ?? null;
235 $row['d2_hora_prev'] = $d['hora_descarga_prevista'] ?? null;
236 $row['d2_hora_real'] = $d['hora_descarga_real'] ?? null;
237 $row['d2_estado'] = $d['estado_carga'] ?? null;
238 $row['d2_dispo_id'] = $d['id'] ?? null;
239 $row['d2_update_date'] = $d['update_date'] ?? null;
240
241 $result[] = $row;
242 }
243
244 header('Content-Type: application/json; charset=utf-8');
245 echo json_encode($result, JSON_UNESCAPED_UNICODE);
246 exit;
247 }
248
249
250
251
252 /* ========================================================= */
253
254 protected function save_dispo(){
255 $post = $_POST;
256
257 /* --------------------------------------------------------- */
258 /* 1. Pflicht: id */
259 /* --------------------------------------------------------- */
260 if (empty($post['id'])) {
261 $this->json(false, 'missing_id');
262 }
263
264 $id = (int)$post['id'];
265 unset($post['id']);
266
267 /* --------------------------------------------------------- */
268 /* 2. Pflicht: update_date (Optimistic Lock) */
269 /* --------------------------------------------------------- */
270 if (empty($post['update_date'])) {
271 $this->json(false, 'missing_update_date');
272 }
273
274 $clientUpdateDate = $post['update_date'];
275 unset($post['update_date']);
276
277 /* --------------------------------------------------------- */
278 /* 3. Nichts zu speichern */
279 /* --------------------------------------------------------- */
280 if (empty($post)) {
281 $this->json(true, 'noop');
282 }
283
284 /* --------------------------------------------------------- */
285 /* 4. Aktuellen Stand aus DB lesen */
286 /* --------------------------------------------------------- */
287 $row = $this->oDB->select1($this->dd_dispo, $id, 'update_date', 0);
288
289 if (!is_array($row) || empty($row['update_date'])) {
290 $this->json(false, 'not_found');
291 }
292
293 $dbUpdateDate = $row['update_date'];
294
295 /* --------------------------------------------------------- */
296 /* 5. Optimistic Concurrency Check */
297 /* --------------------------------------------------------- */
298 if ($dbUpdateDate !== $clientUpdateDate) {
299 $this->json(false, 'conflict');
300 }
301
302 /* --------------------------------------------------------- */
303 /* 6. Schreiben über dbxDB (DD-Automatismen!) */
304 /* --------------------------------------------------------- */
305 // Strings trimmen (wie in anderen Modulen)
306 foreach ($post as $k => $v) {
307 if (is_string($v)) {
308 $post[$k] = trim($v);
309 }
310 }
311
312 // update($dd, $field_values, $id, $verify_access, $verify_fields, $verify_values, $trace)
313 $ok = $this->oDB->update(
314 $this->dd_dispo,
315 $post,
316 $id,
317 0, // access (wie in myLKW)
318 1, // verify fields
319 0, // verify values
320 0 // trace
321 );
322
323 if (!$ok) {
324 $this->json(false, 'update_failed');
325 }
326
327 /* --------------------------------------------------------- */
328 /* 7. Erfolg */
329 /* --------------------------------------------------------- */
330 $this->json(true, 'ok');
331 }
332
333
334
335 /* ========================================================= */
336
338 private function delete_dispo(){
339
340 $id = intval($_POST['id'] ?? 0);
341
342 if(!$id){
343 $this->json(false,"Keine ID übergeben");
344 }
345
346 $ok = $this->oDB->delete($this->dd_dispo,$id);
347
348 $this->json($ok);
349 }
350
351 /* ========================================================= */
352
353
355 private function ensure_dispo_rollover(){
356
357 // nächster Arbeitstag (d0)
358 $today = date('Y-m-d');
359 $days = $this->getNextWorkdays($today, 1);
360 $workday = $days[0];
361
362 $last = dbx()->get_config('myLKW', 'last_dispo_rollover');
363 if ($last === $workday) {
364 return;
365 }
366
367 /* --------------------------------------------------------- */
368 /* LOCK (verhindert parallelen Tageswechsel) */
369 /* --------------------------------------------------------- */
370 $lockFile = dbx_get_file_dir() . 'sys/lock/myLKW_dispo_rollover.lock';
371 $lockFile = dbx_os_path_file($lockFile);
372
373 $fh = fopen($lockFile, 'c');
374 if (!$fh) {
375 // im Zweifel: nichts kaputt machen
376 return;
377 }
378
379 // exklusiver Lock
380 if (!flock($fh, LOCK_EX)) {
381 fclose($fh);
382 return;
383 }
384
385 try {
386
387 // NACH Lock erneut prüfen (wichtig!)
388 $last = dbx()->get_config('myLKW', 'last_dispo_rollover');
389 if ($last === $workday) {
390 return;
391 }
392
393 // Tageswechsel durchführen
394 $this->rollover_dispo();
395
396 // global merken
397 //dbx()->set_config('myLKW', 'last_dispo_rollover', $workday);
398
399 } finally {
400 flock($fh, LOCK_UN);
401 fclose($fh);
402 }
403 }
404
405
406
412 private function rollover_dispo(){
413
414 /* --------------------------------------------------------- */
415 /* 1. Relevante Tage bestimmen */
416 /* --------------------------------------------------------- */
417 $today = date('Y-m-d');
418 $days = $this->getNextWorkdays($today, 3);
419
420 $d0 = $days[0];
421 $d1 = $days[1];
422 $d2 = $days[2];
423
424 /* --------------------------------------------------------- */
425 /* 2. ALLE bestehenden d2-Datensätze löschen */
426 /* --------------------------------------------------------- */
427 $this->oDB->delete($this->dd_dispo, array('fecha_trabajo' => $d2), 0, 0);
428
429 /* --------------------------------------------------------- */
430 /* 3. Bestehende Dispo-Daten für d0 und d1 laden */
431 /* --------------------------------------------------------- */
432 $rows = $this->oDB->select($this->dd_dispo, "fecha_trabajo IN ('$d0', '$d1')", '*', '', 'ASC', '', 0, 0, 0);
433
434 if (!is_array($rows) || empty($rows)) {
435 return;
436 }
437
438 /* --------------------------------------------------------- */
439 /* 4. Nach LKW + Tag indexieren */
440 /* --------------------------------------------------------- */
441 $map = [];
442
443 foreach ($rows as $r) {
444 $map[(int)$r['lkw_id']][$r['fecha_trabajo']] = $r;
445 }
446
447 /* --------------------------------------------------------- */
448 /* 5. Für jeden LKW Tageswechsel durchführen */
449 /* --------------------------------------------------------- */
450 foreach ($map as $lkw_id => $dayset) {
451
452 /* -------- d1 -> d2 -------- */
453 if (!empty($dayset[$d1])) {
454
455 $src = $dayset[$d1];
456
457 $this->oDB->insert($this->dd_dispo, [
458 'lkw_id' => $lkw_id,
459 'fecha_trabajo' => $d2,
460 'origen_region' => $src['origen_region'],
461 'origen_lugar' => $src['origen_lugar'],
462 'carga_region' => $src['carga_region'],
463 'carga_lugar' => $src['carga_lugar'],
464 'hora_descarga_prevista' => $src['hora_descarga_prevista'],
465 'hora_descarga_real' => null,
466 'estado_carga' => null,
467 ]);
468 }
469
470 /* -------- d0 -> d1 -------- */
471 if (!empty($dayset[$d0])) {
472
473 $src = $dayset[$d0];
474
475 $this->oDB->insert($this->dd_dispo, [
476 'lkw_id' => $lkw_id,
477 'fecha_trabajo' => $d1,
478 'origen_region' => $src['origen_region'],
479 'origen_lugar' => $src['origen_lugar'],
480 'carga_region' => $src['carga_region'],
481 'carga_lugar' => $src['carga_lugar'],
482 'hora_descarga_prevista' => $src['hora_descarga_prevista'],
483 'hora_descarga_real' => null,
484 'estado_carga' => null,
485
486 ]);
487 }
488 }
489 }
490
491
492 private function getNextWorkdays(string $startDate, int $count = 3): array {
493 $days = [];
494 $ts = strtotime($startDate);
495
496 while (count($days) < $count) {
497 $w = date('N', $ts); // 1=Mo … 7=So
498 if ($w <= 5) {
499 $days[] = date('Y-m-d', $ts);
500 }
501 $ts = strtotime('+1 day', $ts);
502 }
503
504 return $days; // [d0, d1, d2]
505 }
506
507
508
509
511 private function json(bool $success, string $msg=""){
512 header('Content-Type: application/json; charset=utf-8');
513 echo json_encode([
514 'success'=>$success,
515 'msg'=>$msg
516 ],JSON_UNESCAPED_UNICODE);
517 exit;
518 }
519}
dbx_os_path_file($path_file)
Definition index.php:164
exit
Definition index.php:532
dbx_get_file_dir()
Definition index.php:265
DBX schema administration.
if(! $db->connect_db_server($server)) $result