diff --git a/upgrade/data/db_schema.json b/upgrade/data/db_schema.json index e6a0f50d..b1ea4924 100644 --- a/upgrade/data/db_schema.json +++ b/upgrade/data/db_schema.json @@ -91519,6 +91519,15 @@ "id" ], "Non_unique": "" + }, + { + "Key_name": "seriennummer_artikel", + "Index_type": "BTREE", + "columns": [ + "seriennummer", + "artikel" + ], + "Non_unique": "UNIQUE" } ] }, diff --git a/www/pages/ajax.php b/www/pages/ajax.php index 3a08c07e..f3826b9b 100644 --- a/www/pages/ajax.php +++ b/www/pages/ajax.php @@ -2608,6 +2608,16 @@ select a.kundennummer, (SELECT name FROM adresse a2 WHERE a2.kundennummer = a.ku $newarr[] = $arr[$i]['name']; } break; + case "seriennummerverfuegbar": + $artikel = (int)$this->app->Secure->GetGET('artikel'); + $arr = $this->app->DB->SelectArr("SELECT seriennummer FROM seriennummern WHERE lieferschein = 0 AND seriennummer LIKE '%$term%' AND artikel = '$artikel' LIMIT 20"); + $carr = !empty($arr)?count($arr):0; + for($i = 0; $i < $carr; $i++) { + $newarr[] = $arr[$i]['seriennummer']; + } + break; + + break; case "artikelmengeinbeleg": $beleg = $this->app->Secure->GetGet('beleg'); $belegid = $this->app->Secure->GetGet('id'); diff --git a/www/pages/content/seriennummern_edit.tpl b/www/pages/content/seriennummern_edit.tpl new file mode 100644 index 00000000..0fa2f0eb --- /dev/null +++ b/www/pages/content/seriennummern_edit.tpl @@ -0,0 +1,215 @@ +
+ + +
+ [MESSAGE] +
+ [FORMHANDLEREVENT] +
+
+
+
+
+ {|seriennummern|}Info like this. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {|Seriennummer|}: + + +
+ {|Adresse|}: + + +
+ {|Artikel|}: + + +
+ {|Beschreibung|}: + + +
+ {|Lieferung|}: + + +
+ {|Lieferschein|}: + + +
+ {|Lieferscheinpos|}: + + +
+ {|Bearbeiter|}: + + +
+ {|Logdatei|}: + + +
+
+
+
+
+
+ + +
+
+ +
+ diff --git a/www/pages/content/seriennummern_enter.tpl b/www/pages/content/seriennummern_enter.tpl new file mode 100644 index 00000000..bee44aea --- /dev/null +++ b/www/pages/content/seriennummern_enter.tpl @@ -0,0 +1,167 @@ +
+ + +
+ [MESSAGE] +
+ [FORMHANDLEREVENT] +
+
+
+
+
+ {|Seriennummern erfassen Artikel [ARTIKELNUMMER] [ARTIKEL]|} + + + + + + + + + + + + + + + + + +
+ {|Lagermenge|}: + + +
+ {|Seriennummern verfügbar|}: + + +
+ {|Seriennummern fehlen|}: + + +
+ {|Seriennummer scannen|}: + + +
+
+
+
+
+
+
+ {|Seriennummernassistent|} + + + + + + + + + + + + + + + + + + + + + +
+ {|Letzte Seriennummer|}: + + +
+ {|Präfix|}: + + +
+ {|Start|}: + + +
+ {|Postfix|}: + + +
+ {|Anzahl|}: + + +
+
+
+
+
+
+
+ {|Aktionen|} + + + + + + + +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+ {|Gewählte Seriennummern|} + + + + + +
+ {|Seriennummern|}: + + + Liste der Seriennummern, 1 pro Zeile +
+
+
+
+
+
+
+ {|Aktionen|} + + + + +
+ +
+
+
+
+
+
+
+
+
+ diff --git a/www/pages/content/seriennummern_list.tpl b/www/pages/content/seriennummern_list.tpl new file mode 100644 index 00000000..b5bec045 --- /dev/null +++ b/www/pages/content/seriennummern_list.tpl @@ -0,0 +1,16 @@ +
+ +
+ [MESSAGE] + [TAB1] + [TAB1NEXT] +
+
+ [MESSAGE] + [TAB2] + [TAB2NEXT] +
+
diff --git a/www/pages/seriennummern.php b/www/pages/seriennummern.php new file mode 100644 index 00000000..70427ec7 --- /dev/null +++ b/www/pages/seriennummern.php @@ -0,0 +1,447 @@ +app = $app; + if ($intern) + return; + + $this->app->ActionHandlerInit($this); + $this->app->ActionHandler("list", "seriennummern_list"); + $this->app->ActionHandler("enter", "seriennummern_enter"); + $this->app->ActionHandler("delete", "seriennummern_delete"); + $this->app->DefaultActionHandler("list"); + $this->app->ActionHandlerListen($app); + } + + public function Install() { + /* Fill out manually later */ + } + + static function TableSearch(&$app, $name, $erlaubtevars) { + switch ($name) { + case "seriennummern_list": + $allowed['seriennummern_list'] = array('list'); + $heading = array('','','Artikel', 'Seriennummer','Adresse','Lieferschein','Lieferdatum', 'Menü'); + $width = array('1%','1%','10%'); // Fill out manually later + + // columns that are aligned right (numbers etc) + // $alignright = array(4,5,6,7,8); + + $findcols = array('s.id','s.id','a.nummer', 's.seriennummer','ad.name','l.belegnr','l.datum','s.id'); + + $defaultorder = 1; + $defaultorderdesc = 0; + $aligncenter = array(); + $alignright = array(); + $numbercols = array(); + $sumcol = array(); + + $dropnbox = "'' AS `open`, CONCAT('') AS `auswahl`"; + +// $moreinfo = true; // Allow drop down details +// $moreinfoaction = "lieferschein"; // specify suffix for minidetail-URL to allow different minidetails +// $menucol = 11; // Set id col for moredata/menu + + $menu = "
" . "" . "Conf->WFconf['defaulttheme']}/images/delete.svg\" border=\"0\">" . "
"; + + $sql = " + SELECT SQL_CALC_FOUND_ROWS + s.id, + $dropnbox, + a.nummer, + s.seriennummer, + ad.name, + l.belegnr, + ".$app->erp->FormatDate("l.datum").", + s.id + FROM + seriennummern s + INNER JOIN + artikel a ON s.artikel = a.id + LEFT JOIN + lieferschein_position lp ON lp.id = s.lieferscheinpos + LEFT JOIN + lieferschein l ON l.id = lp.lieferschein + LEFT JOIN + adresse ad ON ad.id = l.adresse + "; + + $where = "1"; + $count = "SELECT count(DISTINCT id) FROM seriennummern WHERE $where"; +// $groupby = ""; + + break; + case "seriennummern_artikel_list": + $allowed['seriennummern_artikel_list'] = array('list'); + $heading = array('','', 'Nummer', 'Artikel', 'Lagermenge', 'Nummern verfügbar', 'Nummern ausgeliefert', 'Nummern gesamt', 'Menü',''); + $width = array('1%','1%','10%'); // Fill out manually later + + // columns that are aligned right (numbers etc) + // $alignright = array(4,5,6,7,8); + + $findcols = array('a.id','a.id', 'a.nummer', 'a.name_de' ); + $searchsql = array('a.name_de', 'a.nummer'); + + $menucol = 1; + $defaultorder = 1; + $defaultorderdesc = 0; + $aligncenter = array(); + $alignright = array(); + $numbercols = array(); + $sumcol = array(); + + $dropnbox = "'' AS `open`, CONCAT('') AS `auswahl`"; + +// $moreinfo = true; // Allow drop down details +// $moreinfoaction = "lieferschein"; // specify suffix for minidetail-URL to allow different minidetails +// $menucol = 11; // Set id col for moredata/menu + + $menu_link = array( + '', + 'Erfassen', + '' + ); + + $sql = "SELECT SQL_CALC_FOUND_ROWS + a.id, + $dropnbox, + CONCAT('',a.nummer,'') as nummer, + a.name_de, + auf_lager.anzahl, + SUM(if(s.id IS NULL,0,1))-SUM(if(s.lieferscheinpos <> 0,1,0)), + SUM(if(s.lieferscheinpos <> 0,1,0)), + SUM(if(s.id IS NULL,0,1)), + ".$app->erp->ConcatSQL($menu_link).", + a.id + FROM + artikel a + LEFT JOIN + ( + SELECT + a.id, + a.nummer, + a.name_de name, + SUM(lpi.menge) anzahl + FROM + artikel a + INNER JOIN lager_platz_inhalt lpi ON + a.id = lpi.artikel + WHERE + a.seriennummern <> 'keine' AND a.seriennummern <> '' + GROUP BY + a.id + ) auf_lager ON auf_lager.id = a.id + LEFT JOIN + seriennummern s ON s.artikel = a.id + "; + + $where = "a.seriennummern <> 'keine' AND a.seriennummern <> ''"; + $count = "SELECT count(DISTINCT a.id) FROM artikel a WHERE $where"; + $groupby = "GROUP BY a.id"; + + break; + case "seriennummern_lieferscheine_list": + $allowed['seriennummern_artikel_list'] = array('list'); + $heading = array('','', 'Nummer', 'Artikel', 'Lagermenge', 'Nummern verfügbar', 'Nummern ausgeliefert', 'Nummern gesamt', 'Menü'); + $width = array('1%','1%','10%'); // Fill out manually later + + // columns that are aligned right (numbers etc) + // $alignright = array(4,5,6,7,8); + + $findcols = array('a.id','a.id', 'a.nummer', 'a.name_de' ); + $searchsql = array('a.name_de', 'a.nummer'); + + $defaultorder = 1; + $defaultorderdesc = 0; + $aligncenter = array(); + $alignright = array(); + $numbercols = array(); + $sumcol = array(); + + $dropnbox = "'' AS `open`, CONCAT('') AS `auswahl`"; + +// $moreinfo = true; // Allow drop down details +// $moreinfoaction = "lieferschein"; // specify suffix for minidetail-URL to allow different minidetails +// $menucol = 11; // Set id col for moredata/menu + + $menu = "
" . "Conf->WFconf['defaulttheme']}/images/edit.svg\" border=\"0\"> " . "Conf->WFconf['defaulttheme']}/images/delete.svg\" border=\"0\">" . "
"; + + $sql = "SELECT SQL_CALC_FOUND_ROWS + a.id, + $dropnbox, + CONCAT('',a.nummer,'') as nummer, + a.name_de, + auf_lager.anzahl, + SUM(if(s.id IS NULL,0,1))-SUM(if(s.lieferscheinpos <> 0,1,0)), + SUM(if(s.lieferscheinpos <> 0,1,0)), + SUM(if(s.id IS NULL,0,1)) + FROM + artikel a + LEFT JOIN + ( + SELECT + a.id, + a.nummer, + a.name_de name, + SUM(lpi.menge) anzahl + FROM + artikel a + INNER JOIN lager_platz_inhalt lpi ON + a.id = lpi.artikel + WHERE + a.seriennummern <> 'keine' AND a.seriennummern <> '' + GROUP BY + a.id + ) auf_lager ON auf_lager.id = a.id + LEFT JOIN + seriennummern s ON s.artikel = a.id + "; + + $where = "a.seriennummern <> 'keine' AND a.seriennummern <> ''"; + $count = "SELECT count(DISTINCT a.id) FROM artikel a WHERE $where"; + $groupby = "GROUP BY a.id"; + + break; + } + + $erg = false; + + foreach ($erlaubtevars as $k => $v) { + if (isset($$v)) { + $erg[$v] = $$v; + } + } + return $erg; + } + + function seriennummern_list() { + $this->app->erp->MenuEintrag("index.php?module=seriennummern&action=list", "Übersicht"); + + $this->app->erp->MenuEintrag("index.php", "Zurück"); + + $this->app->YUI->TableSearch('TAB1', 'seriennummern_artikel_list', "show", "", "", basename(__FILE__), __CLASS__); + $this->app->YUI->TableSearch('TAB2', 'seriennummern_list', "show", "", "", basename(__FILE__), __CLASS__); + + $check_seriennummern = $this->seriennummern_check_serials(); + + if (!empty($check_seriennummern)) { + $artikel_id_links = array(); + foreach ($check_seriennummern as $artikel_id) { + if ($artikel_id['menge_nummern'] < $artikel_id['menge_auf_lager']) { + $artikel_id_links[] = ''.$artikel_id['nummer'].''; + } + } + if (!empty($artikel_id_links)) { + $this->app->YUI->Message('warning','Seriennummern fehlen für Artikel: '.implode(', ',$artikel_id_links)); + } + } + + $this->app->Tpl->Parse('PAGE', "seriennummern_list.tpl"); + } + + public function seriennummern_delete() { + $id = (int) $this->app->Secure->GetGET('id'); + + if ($this->app->DB->Select("SELECT id FROM `seriennummern` WHERE `id` = '{$id}' AND `lieferscheinpos` = 0")) { + $this->app->DB->Delete("DELETE FROM `seriennummern` WHERE `id` = '{$id}' AND `lieferscheinpos` = 0"); + $this->app->Tpl->addMessage('error', 'Der Eintrag wurde gelöscht'); + } else { + $this->app->Tpl->addMessage('error', 'Der Eintrag kann nicht gelöscht werden!'); + } + $this->seriennummern_list(); + } + + function seriennummern_enter() { + + $this->app->erp->MenuEintrag("index.php?module=seriennummern&action=list", "Zurück zur Übersicht"); + $artikel_id = (int) $this->app->Secure->GetGET('artikel'); + + $artikel = $this->app->DB->SelectRow("SELECT name_de, nummer FROM artikel WHERE id ='".$artikel_id."'"); + + $this->app->Tpl->SetText('KURZUEBERSCHRIFT1','Erfassen'); + $this->app->Tpl->SetText('KURZUEBERSCHRIFT2',$artikel['name_de']." (Artikel ".$artikel['nummer'].")"); + + $submit = $this->app->Secure->GetPOST('submit'); + $seriennummern = array(); + + $seriennummern_text = $this->app->Secure->GetPOST('seriennummern'); + $seriennummern = explode('\n',str_replace(['\r'],'',$seriennummern_text)); + + switch ($submit) { + case 'hinzufuegen': + $eingabe = $this->app->Secure->GetPOST('eingabeneu'); + if (!empty($eingabe)) { + $seriennummern[] = $eingabe; + } + break; + case 'speichern': + $seriennummern_not_written = array(); + foreach ($seriennummern as $seriennummer) { + + $seriennummer = trim($seriennummer); + + if (empty($seriennummer)) { + continue; + } + + $sql = "INSERT INTO seriennummern (seriennummer, artikel) VALUES ('".$this->app->DB->real_escape_string($seriennummer)."', '".$artikel_id."')"; + try { + $this->app->DB->Insert($sql); + } catch (mysqli_sql_exception $e) { + $error = true; + $seriennummern_not_written[] = $seriennummer; + } + } + if ($error) { + $this->app->Tpl->addMessage('error', 'Einige Seriennummern konnten nicht gespeichert werden.'); + } + $seriennummern = $seriennummern_not_written; + break; + case 'assistent': + $praefix = $this->app->Secure->GetPOST('praefix'); + $start = $this->app->Secure->GetPOST('start'); + $postfix = $this->app->Secure->GetPOST('postfix'); + $anzahl = (int) $this->app->Secure->GetPOST('anzahl'); + + while ($anzahl) { + $seriennummern[] = $praefix.$start.$postfix; + $anzahl--; + $start++; + } + + break; + } + + $seriennummern = array_unique($seriennummern); + + $check_seriennummern = $this->seriennummern_check_serials($artikel_id); + if (empty($check_seriennummern)) { + $this->app->Tpl->addMessage('success', 'Seriennummern vollständig.'); + } + + $check_seriennummern = $check_seriennummern[0]; + + $anzahl_fehlt = $check_seriennummern['menge_auf_lager']-$check_seriennummern['menge_nummern']; + + if ($anzahl_fehlt < 0) { + $anzahl_fehlt = 0; + } + + $letzte_seriennummer = (string) $this->app->DB->Select("SELECT seriennummer FROM seriennummern WHERE artikel = '".$artikel_id."' ORDER BY id DESC LIMIT 1"); + $regex_result = array(preg_match('/(.*?)(\d+)(?!.*\d)(.*)/', $letzte_seriennummer, $matches)); + + $this->app->Tpl->Set('LETZTE', $letzte_seriennummer); + + $this->app->Tpl->Set('PRAEFIX', $matches[1]); + $this->app->Tpl->Set('START', $matches[2]+1); + $this->app->Tpl->Set('POSTFIX', $matches[3]); + + $this->app->Tpl->Set('ANZAHL', $anzahl_fehlt); + + $this->app->Tpl->Set('ARTIKELNUMMER', ''.$check_seriennummern['nummer'].''); + $this->app->Tpl->Set('ARTIKEL', $check_seriennummern['name']); + $this->app->Tpl->Set('ANZLAGER', $check_seriennummern['menge_auf_lager']); + $this->app->Tpl->Set('ANZVORHANDEN', $check_seriennummern['menge_nummern']); + $this->app->Tpl->Set('ANZFEHLT', $anzahl_fehlt); + $this->app->Tpl->Set('SERIENNUMMERN', implode("\n",$seriennummern)); + + $this->app->YUI->AutoComplete("eingabe", "seriennummerverfuegbar",0,"&artikel=$artikel_id"); + $this->app->Tpl->Parse('PAGE', "seriennummern_enter.tpl"); + + } + + /* + * Check if all serial numbers are given + * Return array of article ids + */ + public function seriennummern_check_serials($artikel_id = null) : array { + $sql = " + SELECT + auf_lager.id, + nummer, + name, + auf_lager.anzahl menge_auf_lager, + COALESCE(nummern_verfuegbar.anzahl,0) menge_nummern + FROM + ( + SELECT + a.id, + a.nummer, + a.name_de name, + SUM(lpi.menge) anzahl + FROM + artikel a + INNER JOIN lager_platz_inhalt lpi ON + a.id = lpi.artikel + WHERE + a.seriennummern <> 'keine' AND a.seriennummern <> '' AND (a.id = '".$artikel_id."' OR '".$artikel_id."' = '') + GROUP BY + a.id + ) auf_lager + LEFT JOIN( + SELECT + artikel, + COUNT(id) anzahl + FROM + seriennummern + WHERE + lieferscheinpos = 0 + GROUP BY + artikel + ) nummern_verfuegbar + ON + auf_lager.id = nummern_verfuegbar.artikel + GROUP BY + auf_lager.id + HAVING + menge_nummern <> menge_auf_lager + "; + + $result = $this->app->DB->SelectArr($sql); + return(empty($result)?array():$result); + } + + /** + * @param int $printerId + * @param string $filename + * + * @return void + */ + protected function seriennummern_create_notification($article) + { + // Notification erstellen + $message = new NotificationMessageData('default', 'Seriennummern check problem alter'); + $message->setMessage('Nicht genug Seriendinges'); + $message->addTags(['seriennummern']); + $message->setOption('id', $article); + $message->setPriority(true); + + $messageButtons = [ + [ + 'text' => 'Seriennummern pflegen', + 'link' => sprintf('index.php?module=seriennummern&action=edit&article=%s', $article), + ], + [ + 'text' => 'Zum Spooler', + 'link' => '#' + ] + ]; + $message->setOption('buttons', $messageButtons); + + /** @var NotificationService $notification */ + $notification = $this->app->Container->get('NotificationService'); + $notification->createFromData($this->app->User->GetID(), $message); + } + }