diff --git a/index.php b/index.php index 409580f..2b0b06b 100644 --- a/index.php +++ b/index.php @@ -6402,6 +6402,98 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; this.items = this.items.filter(item => item.id !== id); this.render(); }, + setQty(id, qty) { + if (!this.items) return; + const item = this.items.find(i => i.id === id); + if (item) { + const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1'); + const currentStock = parseFloat(item.stock_quantity) || 0; + + if (!allowZeroStock && qty > currentStock) { + Swal.fire('Error', 'Insufficient stock!', 'error'); + return; + } + + item.qty = qty; + if (item.qty <= 0) this.remove(id); + else this.render(); + } + }, + async readScale(id) { + if (!('serial' in navigator)) { + Swal.fire('Error', 'Web Serial API is not supported in this browser. Please use Chrome or Edge.', 'error'); + return; + } + try { + if (!this.scalePort) { + this.scalePort = await navigator.serial.requestPort(); + await this.scalePort.open({ baudRate: 9600 }); + } else if (!this.scalePort.readable) { + await this.scalePort.open({ baudRate: 9600 }); + } + + const reader = this.scalePort.readable.getReader(); + let accumulatedData = ''; + + Swal.fire({ + title: 'Reading Scale...', + text: 'Waiting for stable weight...', + allowOutsideClick: false, + didOpen: () => { + Swal.showLoading(); + } + }); + + let weight = null; + const decoder = new TextDecoder('utf-8'); + let readCount = 0; + + while (readCount < 30) { + const { value, done } = await Promise.race([ + reader.read(), + new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 1000)) + ]).catch(e => ({ done: true, value: null })); + + if (done) break; + if (value) { + accumulatedData += decoder.decode(value); + const matches = accumulatedData.match(/[\d]+\.\d+/g); + if (matches && matches.length > 0) { + weight = parseFloat(matches[matches.length - 1]); + if (!isNaN(weight) && weight > 0) { + break; + } + } + } + readCount++; + } + + reader.releaseLock(); + + if (weight !== null && weight > 0) { + Swal.close(); + this.setQty(id, weight); + Swal.fire({ + toast: true, + position: 'top-end', + icon: 'success', + title: 'Weight Read: ' + weight.toFixed(3) + ' kg', + showConfirmButton: false, + timer: 1500 + }); + } else { + Swal.fire('Warning', 'Could not read a valid weight. Please try again.', 'warning'); + } + } catch (err) { + console.error('Scale Error:', err); + if (err.name === 'NotFoundError') { + // User cancelled the prompt + return; + } + Swal.fire('Error', 'Failed to read from scale: ' + err.message, 'error'); + this.scalePort = null; + } + }, updateQty(id, delta) { if (!this.items) return; const item = this.items.find(i => i.id === id); @@ -6641,6 +6733,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; ${qty} +
${itemTotal.toFixed(3)}