feat(inventory): edit items in inventory grid
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

- Added 'Editar' button in inventory rows.

- Reused create modal as create/edit with pre-filled data.

- Added fields: unit, max_stock, tax_rate, description, is_active.

- Added /inventory/categories/all endpoint for flat category selector.

- Price/cost inputs are disabled for users without config.edit_prices.
This commit is contained in:
2026-06-30 19:43:03 +00:00
parent b6679c6d9c
commit 603046cb09
3 changed files with 131 additions and 59 deletions

View File

@@ -15,7 +15,7 @@
<meta name="theme-color" content="#F5A623" />
<link rel="shortcut icon" type="image/png" href="/pos/static/pwa/icon-192.png" />
<link rel="stylesheet" href="/pos/static/css/inventory.css?v=33"></head>
<link rel="stylesheet" href="/pos/static/css/inventory.css?v=34"></head>
<body>
@@ -710,42 +710,48 @@
<!-- ===== MODALS ===== -->
<!-- Create Item Modal -->
<!-- Create/Edit Item Modal -->
<div class="inv-modal-overlay" id="createModal">
<div class="inv-modal">
<div class="inv-modal__header">
<h3>Nuevo Producto</h3>
<h3 id="createModalTitle">Nuevo Producto</h3>
<button class="inv-modal__close" onclick="closeCreateModal()">&times;</button>
</div>
<div class="inv-modal__body">
<input type="hidden" id="editItemId" />
<div class="inv-form-grid">
<div class="inv-field"><label>No. Parte *</label><input type="text" id="newPartNumber" placeholder="Ej: GAT-50104" /></div>
<div class="inv-field"><label>Nombre *</label><input type="text" id="newName" placeholder="Nombre del producto" /></div>
<div class="inv-field"><label>Marca</label><input type="text" id="newBrand" placeholder="Marca del fabricante" /></div>
<div class="inv-field"><label>Categoría</label>
<select class="select-filter" id="newCategory" onchange="onCategoryChange(this.value)" style="width:100%;">
<option value="">Selecciona categoría</option>
</select>
</div>
<div class="inv-field"><label>Subcategoría</label>
<select class="select-filter" id="newSubcategory" style="width:100%;" disabled>
<option value="">Selecciona categoría primero</option>
<select class="select-filter" id="newCategory" style="width:100%;">
<option value="">Sin categoría</option>
</select>
</div>
<div class="inv-field"><label>Barcode</label><input type="text" id="newBarcode" placeholder="Auto-generado si vacío" /></div>
<div class="inv-field"><label>SKU Alternativo 1</label><input type="text" id="newSku2" placeholder="Ej: SKU-Bodega-A" /></div>
<div class="inv-field"><label>SKU Alternativo 2</label><input type="text" id="newSku3" placeholder="Ej: SKU-Bodega-B" /></div>
<div class="inv-field"><label>Costo</label><input type="number" id="newCost" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Precio Mostrador</label><input type="number" id="newPrice1" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Unidad</label><input type="text" id="newUnit" placeholder="pza, kit, lt..." /></div>
<div class="inv-field price-field"><label>Costo</label><input type="number" id="newCost" step="0.01" placeholder="0.00" /></div>
<div class="inv-field price-field"><label>Precio Mostrador</label><input type="number" id="newPrice1" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Stock Mínimo</label><input type="number" id="newMinStock" placeholder="0" /></div>
<div class="inv-field"><label>Stock Inicial</label><input type="number" id="newInitialStock" placeholder="0" /></div>
<div class="inv-field" id="initialStockField"><label>Stock Inicial</label><input type="number" id="newInitialStock" placeholder="0" /></div>
<div class="inv-field"><label>Stock Máximo</label><input type="number" id="newMaxStock" placeholder="0" /></div>
<div class="inv-field"><label>Impuesto (%)</label><input type="number" id="newTaxRate" step="0.01" placeholder="0.00" /></div>
<div class="inv-field"><label>Ubicación</label><input type="text" id="newLocation" placeholder="Ej: A-12-3" /></div>
<div class="inv-field"><label>Estado</label>
<select class="select-filter" id="newIsActive" style="width:100%;">
<option value="true">Activo</option>
<option value="false">Inactivo</option>
</select>
</div>
<div class="inv-field inv-field--full"><label>Descripción</label><textarea id="newDescription" rows="2" placeholder="Descripción del producto"></textarea></div>
</div>
<div id="createResult" style="margin-top:var(--space-3);min-height:1.5em;"></div>
</div>
<div class="inv-modal__footer">
<button class="btn btn--ghost" onclick="closeCreateModal()">Cancelar</button>
<button class="btn btn--primary" onclick="createItem()">Crear Producto</button>
<button class="btn btn--primary" id="createModalBtn" onclick="createItem()">Crear Producto</button>
</div>
</div>
</div>
@@ -1058,7 +1064,7 @@
<script src="/pos/static/js/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=36" defer></script>
<script src="/pos/static/js/virtual-scroll.js?v=33" defer></script>
<script src="/pos/static/js/inventory.js?v=33" defer></script>
<script src="/pos/static/js/inventory.js?v=34" defer></script>
<script src="/pos/static/js/offline-banner.js" defer></script>
<script src="/pos/static/js/sync-engine.js" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>