- Menü aus Header entfernt, neuer Eintrag unter Produkte > Scanner - Barcode-Erkennung: patchSize medium, grösserer Scan-Bereich, höhere Frequenz - Timeout-Hinweis nach 8s wenn kein Barcode erkannt wird - Tab-Wechsel (Order/Shop/Inventur) ohne Seitenreload, Kamera bleibt aktiv - PWA: gleiche Tab-Logik, Buttons statt Links - Changelog und README aktualisiert Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
3.4 KiB
PHP
Executable file
124 lines
3.4 KiB
PHP
Executable file
<?php
|
|
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
|
|
*
|
|
* AJAX: Update product stock (Inventory mode)
|
|
*/
|
|
|
|
if (!defined('NOTOKENRENEWAL')) {
|
|
define('NOTOKENRENEWAL', '1');
|
|
}
|
|
if (!defined('NOREQUIREMENU')) {
|
|
define('NOREQUIREMENU', '1');
|
|
}
|
|
if (!defined('NOREQUIREHTML')) {
|
|
define('NOREQUIREHTML', '1');
|
|
}
|
|
if (!defined('NOREQUIREAJAX')) {
|
|
define('NOREQUIREAJAX', '1');
|
|
}
|
|
|
|
// Load Dolibarr environment
|
|
$res = 0;
|
|
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(json_encode(['success' => false, 'error' => 'Failed to load Dolibarr']));
|
|
}
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
// Security check
|
|
if (!$user->hasRight('stock', 'mouvement', 'creer')) {
|
|
echo json_encode(['success' => false, 'error' => 'Access denied - no stock movement rights']);
|
|
exit;
|
|
}
|
|
|
|
// Get parameters
|
|
$productId = GETPOSTINT('product_id');
|
|
$newStock = GETPOSTFLOAT('stock');
|
|
|
|
if (empty($productId)) {
|
|
echo json_encode(['success' => false, 'error' => 'Missing product_id']);
|
|
exit;
|
|
}
|
|
|
|
if ($newStock === null || $newStock === '') {
|
|
echo json_encode(['success' => false, 'error' => 'Missing stock value']);
|
|
exit;
|
|
}
|
|
|
|
// Load product
|
|
$product = new Product($db);
|
|
if ($product->fetch($productId) <= 0) {
|
|
echo json_encode(['success' => false, 'error' => 'Product not found']);
|
|
exit;
|
|
}
|
|
|
|
$currentStock = (float) $product->stock_reel;
|
|
$newStock = (float) $newStock;
|
|
$diff = $newStock - $currentStock;
|
|
|
|
if ($diff == 0) {
|
|
echo json_encode(['success' => true, 'message' => 'No change needed']);
|
|
exit;
|
|
}
|
|
|
|
// Get default warehouse from config or use first available
|
|
$warehouseId = getDolGlobalInt('HANDYBARCODESCANNER_DEFAULT_WAREHOUSE', 0);
|
|
|
|
if ($warehouseId <= 0) {
|
|
// Get first warehouse
|
|
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."entrepot WHERE statut = 1 AND entity IN (".getEntity('stock').") ORDER BY rowid ASC LIMIT 1";
|
|
$resql = $db->query($sql);
|
|
if ($resql && $db->num_rows($resql) > 0) {
|
|
$obj = $db->fetch_object($resql);
|
|
$warehouseId = $obj->rowid;
|
|
}
|
|
}
|
|
|
|
if ($warehouseId <= 0) {
|
|
echo json_encode(['success' => false, 'error' => 'No warehouse configured']);
|
|
exit;
|
|
}
|
|
|
|
// Create stock movement
|
|
$movementStock = new MouvementStock($db);
|
|
$movementStock->origin_type = 'handybarcodescanner';
|
|
$movementStock->origin_id = 0;
|
|
|
|
$inventoryCode = 'INV-SCAN-'.date('Ymd-His');
|
|
$label = 'Inventur per HandyBarcodeScanner';
|
|
|
|
if ($diff > 0) {
|
|
// Increase stock
|
|
$result = $movementStock->reception($user, $productId, $warehouseId, $diff, 0, $label, '', '', '', '', 0, $inventoryCode);
|
|
} else {
|
|
// Decrease stock
|
|
$result = $movementStock->livraison($user, $productId, $warehouseId, abs($diff), 0, $label, '', '', '', '', 0, $inventoryCode);
|
|
}
|
|
|
|
if ($result < 0) {
|
|
echo json_encode(['success' => false, 'error' => 'Stock movement failed: ' . $movementStock->error]);
|
|
exit;
|
|
}
|
|
|
|
// Reload product to get updated stock
|
|
$product->fetch($productId);
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'old_stock' => $currentStock,
|
|
'new_stock' => (float) $product->stock_reel,
|
|
'difference' => $diff,
|
|
'warehouse_id' => $warehouseId
|
|
]);
|