189 lines
7.2 KiB
PHP
Executable file
189 lines
7.2 KiB
PHP
Executable file
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/**
|
|
* \file handybarcodescanner/handybarcodescannerindex.php
|
|
* \ingroup handybarcodescanner
|
|
* \brief Mobile Barcode Scanner - Hauptseite (Dolibarr integriert)
|
|
*/
|
|
|
|
// Load Dolibarr environment
|
|
$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 && file_exists("../../../main.inc.php")) {
|
|
$res = @include "../../../main.inc.php";
|
|
}
|
|
if (!$res) {
|
|
die("Include of main fails");
|
|
}
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
|
|
|
|
// Load translation files
|
|
$langs->loadLangs(array("handybarcodescanner@handybarcodescanner", "products", "orders", "stocks"));
|
|
|
|
// Get parameters
|
|
$action = GETPOST('action', 'aZ09');
|
|
$mode = GETPOST('mode', 'alpha') ?: 'order';
|
|
|
|
// Security check
|
|
if (!$user->hasRight('handybarcodescanner', 'use')) {
|
|
// Fallback für ältere Rechte-Prüfung
|
|
if (!$user->hasRight('fournisseur', 'commande', 'creer') && !$user->hasRight('supplier_order', 'creer')) {
|
|
accessforbidden('You need permission to use the barcode scanner');
|
|
}
|
|
}
|
|
|
|
// Check mode-specific permissions
|
|
$enableOrder = getDolGlobalInt('HANDYBARCODESCANNER_ENABLE_ORDER', 1);
|
|
$enableShop = getDolGlobalInt('HANDYBARCODESCANNER_ENABLE_SHOP', 1);
|
|
$enableInventory = getDolGlobalInt('HANDYBARCODESCANNER_ENABLE_INVENTORY', 1);
|
|
|
|
/*
|
|
* View
|
|
*/
|
|
|
|
$form = new Form($db);
|
|
|
|
// CSS einbinden (JS wird manuell am Ende geladen)
|
|
$arrayofcss = array('/handybarcodescanner/css/scanner.css');
|
|
|
|
llxHeader('', $langs->trans("HandyBarcodeScanner"), '', '', 0, 0, array(), $arrayofcss, '', 'mod-handybarcodescanner page-scanner classforhorizontalscrolloftabs');
|
|
|
|
print '<div class="scanner-wrapper fichecenter">';
|
|
|
|
// Mode Tabs - Dolibarr Style
|
|
$head = array();
|
|
$h = 0;
|
|
if ($enableOrder) {
|
|
$head[$h][0] = dol_buildpath('/handybarcodescanner/handybarcodescannerindex.php', 1).'?mode=order';
|
|
$head[$h][1] = img_picto('', 'order', 'class="pictofixedwidth"').$langs->trans("Order");
|
|
$head[$h][2] = 'order';
|
|
$h++;
|
|
}
|
|
if ($enableShop) {
|
|
$head[$h][0] = dol_buildpath('/handybarcodescanner/handybarcodescannerindex.php', 1).'?mode=shop';
|
|
$head[$h][1] = img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans("Shop");
|
|
$head[$h][2] = 'shop';
|
|
$h++;
|
|
}
|
|
if ($enableInventory) {
|
|
$head[$h][0] = dol_buildpath('/handybarcodescanner/handybarcodescannerindex.php', 1).'?mode=inventory';
|
|
$head[$h][1] = img_picto('', 'stock', 'class="pictofixedwidth"').$langs->trans("Inventory");
|
|
$head[$h][2] = 'inventory';
|
|
$h++;
|
|
}
|
|
|
|
print dol_get_fiche_head($head, $mode, '', -1, '');
|
|
|
|
// Scanner Container
|
|
print '<div class="div-table-responsive-no-min">';
|
|
print '<div class="scanner-box">';
|
|
|
|
// Video Container
|
|
print '<div id="scanner-video-container" class="scanner-video-box">';
|
|
print '<video id="scanner-video" playsinline></video>';
|
|
print '<div class="scan-region-highlight"></div>';
|
|
print '</div>';
|
|
|
|
// Scanner Controls
|
|
print '<div class="scanner-controls center">';
|
|
print '<button type="button" id="start-scan-btn" class="button butAction">'.$langs->trans("StartScan").'</button>';
|
|
print '<button type="button" id="stop-scan-btn" class="button butActionDelete hidden">'.$langs->trans("StopScan").'</button>';
|
|
print '</div>';
|
|
|
|
print '</div>'; // scanner-box
|
|
print '</div>'; // div-table-responsive
|
|
|
|
// Manual Barcode Input (for testing without camera/HTTPS)
|
|
print '<div class="manual-input-section marginbottomonly margintoponly">';
|
|
print '<div style="display: flex; gap: 10px; align-items: center;">';
|
|
print '<input type="text" id="manual-barcode-input" class="flat" placeholder="'.$langs->trans("BarcodeManualInput").'" style="flex: 1; padding: 12px; font-size: 16px; border: 1px solid #ccc; border-radius: 4px;">';
|
|
print '<button type="button" id="manual-search-btn" class="button" style="background: #0077b3; color: #fff; padding: 12px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;">'.$langs->trans("Search").'</button>';
|
|
print '</div>';
|
|
print '</div>';
|
|
|
|
// Last Scan Info
|
|
print '<div class="scanner-last-scan marginbottomonly margintoponly">';
|
|
print '<span class="opacitymedium">'.$langs->trans("LastScan").':</span> ';
|
|
print '<span id="last-scan-code" class="badge badge-status4 badge-status">-</span>';
|
|
print '</div>';
|
|
|
|
// Result Area
|
|
print '<div id="result-area" class="scanner-result hidden">';
|
|
print '<!-- Dynamic content loaded via JavaScript -->';
|
|
print '</div>';
|
|
|
|
print dol_get_fiche_end();
|
|
|
|
print '</div>'; // scanner-wrapper
|
|
|
|
// Hidden config for JavaScript
|
|
?>
|
|
<script>
|
|
var SCANNER_CONFIG = {
|
|
ajaxUrl: '<?php echo dol_buildpath('/handybarcodescanner/ajax/', 1); ?>',
|
|
token: '<?php echo newToken(); ?>',
|
|
mode: '<?php echo $mode; ?>',
|
|
enableVibration: <?php echo getDolGlobalInt('HANDYBARCODESCANNER_ENABLE_VIBRATION', 1); ?>,
|
|
enableSound: <?php echo getDolGlobalInt('HANDYBARCODESCANNER_ENABLE_SOUND', 0); ?>,
|
|
lang: {
|
|
productNotFound: '<?php echo $langs->trans("ProductNotFound"); ?>',
|
|
added: '<?php echo $langs->trans("Added"); ?>',
|
|
saved: '<?php echo $langs->trans("Saved"); ?>',
|
|
error: '<?php echo $langs->trans("Error"); ?>',
|
|
selectSupplier: '<?php echo $langs->trans("SelectSupplier"); ?>',
|
|
noSupplier: '<?php echo $langs->trans("NoSupplierForProduct"); ?>',
|
|
quantity: '<?php echo $langs->trans("Qty"); ?>',
|
|
add: '<?php echo $langs->trans("Add"); ?>',
|
|
price: '<?php echo $langs->trans("Price"); ?>',
|
|
stock: '<?php echo $langs->trans("Stock"); ?>',
|
|
currentStock: '<?php echo $langs->trans("CurrentStock"); ?>',
|
|
newStock: '<?php echo $langs->trans("NewStock"); ?>',
|
|
save: '<?php echo $langs->trans("Save"); ?>',
|
|
confirmStockChange: '<?php echo $langs->trans("ConfirmStockChange"); ?>',
|
|
cancel: '<?php echo $langs->trans("Cancel"); ?>',
|
|
confirm: '<?php echo $langs->trans("Confirm"); ?>',
|
|
openShop: '<?php echo $langs->trans("OpenShop"); ?>',
|
|
cheapest: '<?php echo $langs->trans("Cheapest"); ?>',
|
|
cameraError: '<?php echo $langs->trans("CameraAccessError"); ?>',
|
|
ref: '<?php echo $langs->trans("Ref"); ?>',
|
|
product: '<?php echo $langs->trans("Product"); ?>'
|
|
}
|
|
};
|
|
</script>
|
|
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
|
<script src="<?php echo dol_buildpath('/handybarcodescanner/js/scanner.js', 1); ?>"></script>
|
|
<?php
|
|
|
|
// End of page
|
|
llxFooter();
|
|
$db->close();
|