esp attempt, stock + unit type
This commit is contained in:
5
SekiScaleESP/.gitignore
vendored
Normal file
5
SekiScaleESP/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
10
SekiScaleESP/.vscode/extensions.json
vendored
Normal file
10
SekiScaleESP/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
||||||
37
SekiScaleESP/include/README
Normal file
37
SekiScaleESP/include/README
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the convention is to give header files names that end with `.h'.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
46
SekiScaleESP/lib/README
Normal file
46
SekiScaleESP/lib/README
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into the executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a separate directory
|
||||||
|
("lib/your_library_name/[Code]").
|
||||||
|
|
||||||
|
For example, see the structure of the following example libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
Example contents of `src/main.c` using Foo and Bar:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries by scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
16
SekiScaleESP/platformio.ini
Normal file
16
SekiScaleESP/platformio.ini
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:d1]
|
||||||
|
platform = espressif8266
|
||||||
|
board = d1
|
||||||
|
framework = arduino
|
||||||
|
monitor_speed = 115200
|
||||||
|
upload_port = /dev/ttyUSB1
|
||||||
39
SekiScaleESP/src/main.cpp
Normal file
39
SekiScaleESP/src/main.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
const int triggerPin = D2;
|
||||||
|
bool lastState = HIGH;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
randomSeed(analogRead(0));
|
||||||
|
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
pinMode(triggerPin, INPUT_PULLUP);
|
||||||
|
|
||||||
|
// Flash LED to signal boot
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(500);
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
bool currentState = digitalRead(triggerPin);
|
||||||
|
|
||||||
|
// Detect when D4 touches GND (Falling Edge)
|
||||||
|
if (currentState == LOW && lastState == HIGH) {
|
||||||
|
int randomWeight = random(100, 5000);
|
||||||
|
|
||||||
|
// Output formatted for easy parsing
|
||||||
|
Serial.print("WEIGHT:");
|
||||||
|
Serial.println(randomWeight);
|
||||||
|
|
||||||
|
// Visual feedback
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
|
||||||
|
delay(250); // Debounce
|
||||||
|
}
|
||||||
|
|
||||||
|
lastState = currentState;
|
||||||
|
}
|
||||||
11
SekiScaleESP/test/README
Normal file
11
SekiScaleESP/test/README
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||||
59
app.py
59
app.py
@@ -38,10 +38,16 @@ def init_db():
|
|||||||
with sqlite3.connect(DB_FILE) as conn:
|
with sqlite3.connect(DB_FILE) as conn:
|
||||||
conn.execute('''CREATE TABLE IF NOT EXISTS users
|
conn.execute('''CREATE TABLE IF NOT EXISTS users
|
||||||
(id INTEGER PRIMARY KEY, username TEXT UNIQUE, password TEXT)''')
|
(id INTEGER PRIMARY KEY, username TEXT UNIQUE, password TEXT)''')
|
||||||
|
# Updated table definition
|
||||||
conn.execute('''CREATE TABLE IF NOT EXISTS products
|
conn.execute('''CREATE TABLE IF NOT EXISTS products
|
||||||
(barcode TEXT PRIMARY KEY, name TEXT, price REAL, image_url TEXT)''')
|
(barcode TEXT PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
price REAL,
|
||||||
|
image_url TEXT,
|
||||||
|
stock REAL DEFAULT 0,
|
||||||
|
unit_type TEXT DEFAULT 'unit')''')
|
||||||
|
|
||||||
# Default user: admin / Pass: choripan1234
|
# Default user logic remains same...
|
||||||
user = conn.execute('SELECT * FROM users WHERE username = ?', ('admin',)).fetchone()
|
user = conn.execute('SELECT * FROM users WHERE username = ?', ('admin',)).fetchone()
|
||||||
if not user:
|
if not user:
|
||||||
hashed_pw = generate_password_hash('choripan1234')
|
hashed_pw = generate_password_hash('choripan1234')
|
||||||
@@ -143,16 +149,25 @@ def upsert():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
price = float(d['price'])
|
price = float(d['price'])
|
||||||
|
stock = float(d.get('stock', 0)) # New field
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
price = 0.0
|
price = 0.0
|
||||||
|
stock = 0.0
|
||||||
|
|
||||||
|
unit_type = d.get('unit_type', 'unit') # New field (unit or kg)
|
||||||
final_image_path = download_image(d['image_url'], barcode)
|
final_image_path = download_image(d['image_url'], barcode)
|
||||||
|
|
||||||
with sqlite3.connect(DB_FILE) as conn:
|
with sqlite3.connect(DB_FILE) as conn:
|
||||||
conn.execute('''INSERT INTO products (barcode, name, price, image_url) VALUES (?,?,?,?)
|
# Updated UPSERT query
|
||||||
ON CONFLICT(barcode) DO UPDATE SET name=excluded.name,
|
conn.execute('''INSERT INTO products (barcode, name, price, image_url, stock, unit_type)
|
||||||
price=excluded.price, image_url=excluded.image_url''',
|
VALUES (?,?,?,?,?,?)
|
||||||
(barcode, d['name'], price, final_image_path))
|
ON CONFLICT(barcode) DO UPDATE SET
|
||||||
|
name=excluded.name,
|
||||||
|
price=excluded.price,
|
||||||
|
image_url=excluded.image_url,
|
||||||
|
stock=excluded.stock,
|
||||||
|
unit_type=excluded.unit_type''',
|
||||||
|
(barcode, d['name'], price, final_image_path, stock, unit_type))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
@@ -175,14 +190,13 @@ def scan():
|
|||||||
return jsonify({"status": "error", "message": "empty barcode"}), 400
|
return jsonify({"status": "error", "message": "empty barcode"}), 400
|
||||||
|
|
||||||
with sqlite3.connect(DB_FILE) as conn:
|
with sqlite3.connect(DB_FILE) as conn:
|
||||||
# Specifically select the 4 columns the code expects
|
# Fixed: Selecting all 6 necessary columns
|
||||||
p = conn.execute('SELECT barcode, name, price, image_url FROM products WHERE barcode = ?', (barcode,)).fetchone()
|
p = conn.execute('SELECT barcode, name, price, image_url, stock, unit_type FROM products WHERE barcode = ?', (barcode,)).fetchone()
|
||||||
|
|
||||||
if p:
|
if p:
|
||||||
# Now this will always have exactly 4 values, regardless of DB changes
|
# Now matches the 6 columns in the SELECT statement
|
||||||
barcode_val, name, price, image_path = p
|
barcode_val, name, price, image_path, stock, unit_type = p
|
||||||
|
|
||||||
# Image recovery logic for missing local files
|
|
||||||
if image_path and image_path.startswith('/static/'):
|
if image_path and image_path.startswith('/static/'):
|
||||||
clean_path = image_path.split('?')[0].lstrip('/')
|
clean_path = image_path.split('?')[0].lstrip('/')
|
||||||
if not os.path.exists(clean_path):
|
if not os.path.exists(clean_path):
|
||||||
@@ -197,7 +211,9 @@ def scan():
|
|||||||
"barcode": barcode_val,
|
"barcode": barcode_val,
|
||||||
"name": name,
|
"name": name,
|
||||||
"price": int(price),
|
"price": int(price),
|
||||||
"image": image_path
|
"image": image_path,
|
||||||
|
"stock": stock,
|
||||||
|
"unit_type": unit_type
|
||||||
}
|
}
|
||||||
|
|
||||||
socketio.emit('new_scan', product_data)
|
socketio.emit('new_scan', product_data)
|
||||||
@@ -288,6 +304,25 @@ def upload_image():
|
|||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
return jsonify({"status": "success", "image_url": f"/static/cache/{filename}?t={timestamp}"}), 200
|
return jsonify({"status": "success", "image_url": f"/static/cache/{filename}?t={timestamp}"}), 200
|
||||||
|
|
||||||
|
@app.route('/api/scale/weight', methods=['POST'])
|
||||||
|
def update_scale_weight():
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
# Assuming the scale sends {"weight": 1250} (in grams)
|
||||||
|
weight_grams = data.get('weight', 0)
|
||||||
|
|
||||||
|
# Optional: Convert to kg if you prefer
|
||||||
|
weight_kg = round(weight_grams / 1000, 3)
|
||||||
|
|
||||||
|
# Broadcast to all connected clients via SocketIO
|
||||||
|
socketio.emit('scale_update', {
|
||||||
|
"grams": weight_grams,
|
||||||
|
"kilograms": weight_kg,
|
||||||
|
"timestamp": time.time()
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify({"status": "received"}), 200
|
||||||
|
|
||||||
# @app.route('/process_payment', methods=['POST'])
|
# @app.route('/process_payment', methods=['POST'])
|
||||||
# @login_required
|
# @login_required
|
||||||
# def process_payment():
|
# def process_payment():
|
||||||
|
|||||||
@@ -252,6 +252,23 @@
|
|||||||
[data-theme="dark"] .btn-close {
|
[data-theme="dark"] .btn-close {
|
||||||
filter: invert(1) grayscale(100%) brightness(200%);
|
filter: invert(1) grayscale(100%) brightness(200%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix for the missing dropdown arrow */
|
||||||
|
.form-select {
|
||||||
|
background-color: var(--input-bg) !important;
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
border: none !important;
|
||||||
|
/* This ensures the arrow icon is still rendered over the custom background */
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23adb5bd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e") !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
|
background-position: right 0.75rem center !important;
|
||||||
|
background-size: 16px 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .form-select {
|
||||||
|
/* Lighter arrow for dark mode */
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dcddde' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e") !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -335,8 +352,22 @@
|
|||||||
placeholder="Barcode" required>
|
placeholder="Barcode" required>
|
||||||
<input class="form-control mb-2" type="text" name="name" id="form-name" placeholder="Nombre"
|
<input class="form-control mb-2" type="text" name="name" id="form-name" placeholder="Nombre"
|
||||||
required>
|
required>
|
||||||
<input class="form-control mb-2" type="number" name="price" id="form-price"
|
|
||||||
placeholder="Precio (CLP)" required>
|
<div class="row g-2 mb-2">
|
||||||
|
<div class="col-8">
|
||||||
|
<input class="form-control" type="number" name="price" id="form-price"
|
||||||
|
placeholder="Precio (CLP)" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<select class="form-select" name="unit_type" id="form-unit-type">
|
||||||
|
<option value="unit">Unidad</option>
|
||||||
|
<option value="kg">Kg</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input class="form-control mb-2" type="number" step="1" name="stock" id="form-stock"
|
||||||
|
placeholder="Stock Inicial">
|
||||||
|
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<input class="form-control" type="text" name="image_url" id="form-image"
|
<input class="form-control" type="text" name="image_url" id="form-image"
|
||||||
@@ -398,36 +429,27 @@
|
|||||||
<table class="table table-borderless mb-0" id="inventoryTable">
|
<table class="table table-borderless mb-0" id="inventoryTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:36px;">
|
<th style="width:36px;"><input class="form-check-input" type="checkbox"
|
||||||
<input class="form-check-input" type="checkbox" id="select-all"
|
id="select-all" onclick="toggleAll(this)"></th>
|
||||||
onclick="toggleAll(this)">
|
<th class="col-barcode" onclick="sortTable(1)">Código</th>
|
||||||
</th>
|
<th onclick="sortTable(2)">Nombre</th>
|
||||||
<th class="col-barcode" onclick="sortTable(1)" style="cursor:pointer;">
|
<th onclick="sortTable(3)">Stock</th>
|
||||||
Código <i class="bi bi-arrow-down-up ms-1" style="font-size: 0.6rem;"></i>
|
<th onclick="sortTable(4)">Precio</th>
|
||||||
</th>
|
|
||||||
<th onclick="sortTable(2)" style="cursor:pointer;">
|
|
||||||
Nombre <i class="bi bi-arrow-down-up ms-1" style="font-size: 0.6rem;"></i>
|
|
||||||
</th>
|
|
||||||
<th onclick="sortTable(3)" style="cursor:pointer;">
|
|
||||||
Precio <i class="bi bi-arrow-down-up ms-1" style="font-size: 0.6rem;"></i>
|
|
||||||
</th>
|
|
||||||
<th>Acciones</th>
|
<th>Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for p in products %}
|
{% for p in products %}
|
||||||
<tr data-barcode="{{ p[0] }}">
|
<tr data-barcode="{{ p[0] }}">
|
||||||
<td>
|
<td><input class="form-check-input product-checkbox" type="checkbox"
|
||||||
<input class="form-check-input product-checkbox" type="checkbox"
|
onclick="updateBulkBar()"></td>
|
||||||
onclick="updateBulkBar()">
|
<td class="col-barcode">{{ p[0] }}</td>
|
||||||
</td>
|
|
||||||
<td class="col-barcode" style="font-family:monospace; font-size:.8rem;">{{ p[0] }}
|
|
||||||
</td>
|
|
||||||
<td class="name-cell">{{ p[1] }}</td>
|
<td class="name-cell">{{ p[1] }}</td>
|
||||||
|
<td>{{ p[4] }} <small class="text-muted">{{ p[5] }}</small></td>
|
||||||
<td class="price-cell" data-value="{{ p[2] }}"></td>
|
<td class="price-cell" data-value="{{ p[2] }}"></td>
|
||||||
<td style="white-space:nowrap;">
|
<td>
|
||||||
<button class="btn btn-accent btn-sm btn-edit-sm me-1"
|
<button class="btn btn-accent btn-sm"
|
||||||
onclick="editProduct('{{ p[0] }}', '{{ p[1] }}', '{{ p[2] }}', '{{ p[3] }}')"
|
onclick="editProduct('{{ p[0] }}', '{{ p[1] }}', '{{ p[2] }}', '{{ p[3] }}', '{{ p[4] }}', '{{ p[5] }}')"
|
||||||
data-bs-toggle="modal" data-bs-target="#editModal">
|
data-bs-toggle="modal" data-bs-target="#editModal">
|
||||||
<i class="bi bi-pencil"></i>
|
<i class="bi bi-pencil"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -442,7 +464,6 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- /row -->
|
</div><!-- /row -->
|
||||||
@@ -619,12 +640,25 @@
|
|||||||
updateForm(d.barcode, d.name || '', '', d.image || '', 'Crear: ' + d.barcode);
|
updateForm(d.barcode, d.name || '', '', d.image || '', 'Crear: ' + d.barcode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('scale_update', function (data) {
|
||||||
|
console.log("Current Weight:", data.grams + "g");
|
||||||
|
// If the unit type is 'kg', update the stock field automatically
|
||||||
|
const unitType = document.getElementById('form-unit-type').value;
|
||||||
|
if (unitType === 'kg') {
|
||||||
|
document.getElementById('form-stock').value = data.kilograms;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Replace your existing updateForm function with this one
|
// Replace your existing updateForm function with this one
|
||||||
function updateForm(b, n, p, i, t) {
|
function updateForm(b, n, p, i, t, stock, unit) {
|
||||||
dismissPrompt();
|
dismissPrompt();
|
||||||
document.getElementById('form-barcode').value = b;
|
document.getElementById('form-barcode').value = b;
|
||||||
document.getElementById('form-name').value = n;
|
document.getElementById('form-name').value = n;
|
||||||
document.getElementById('form-price').value = (p !== undefined && p !== null) ? p : '';
|
document.getElementById('form-price').value = p || '';
|
||||||
|
document.getElementById('form-stock').value = stock || 0;
|
||||||
|
document.getElementById('form-unit-type').value = unit || 'unit';
|
||||||
|
document.getElementById('form-image').value = i || '';
|
||||||
|
document.getElementById('form-title').innerText = t;
|
||||||
|
|
||||||
// Add a timestamp to the URL if it's a local cache image
|
// Add a timestamp to the URL if it's a local cache image
|
||||||
let displayImg = i || './static/placeholder.png';
|
let displayImg = i || './static/placeholder.png';
|
||||||
@@ -644,25 +678,22 @@
|
|||||||
document.getElementById('new-product-prompt').classList.add('d-none');
|
document.getElementById('new-product-prompt').classList.add('d-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
function editProduct(b, n, p, i) {
|
function editProduct(b, n, p, i, stock, unit) {
|
||||||
document.getElementById('editProductName').innerText = n;
|
document.getElementById('editProductName').innerText = n;
|
||||||
document.getElementById('editModal').dataset.barcode = b;
|
const modal = document.getElementById('editModal');
|
||||||
document.getElementById('editModal').dataset.name = n;
|
modal.dataset.barcode = b;
|
||||||
document.getElementById('editModal').dataset.price = p;
|
modal.dataset.name = n;
|
||||||
document.getElementById('editModal').dataset.image = i; // This captures the image
|
modal.dataset.price = p;
|
||||||
|
modal.dataset.image = i;
|
||||||
|
modal.dataset.stock = stock;
|
||||||
|
modal.dataset.unit = unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmEdit() {
|
function confirmEdit() {
|
||||||
const modal = document.getElementById('editModal');
|
const m = document.getElementById('editModal');
|
||||||
updateForm(
|
updateForm(m.dataset.barcode, m.dataset.name, m.dataset.price, m.dataset.image, 'Editando: ' + m.dataset.name, m.dataset.stock, m.dataset.unit);
|
||||||
modal.dataset.barcode,
|
|
||||||
modal.dataset.name,
|
|
||||||
modal.dataset.price,
|
|
||||||
modal.dataset.image,
|
|
||||||
'Editando: ' + modal.dataset.name
|
|
||||||
);
|
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
bootstrap.Modal.getInstance(modal).hide();
|
bootstrap.Modal.getInstance(m).hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmDelete() {
|
function confirmDelete() {
|
||||||
|
|||||||
Reference in New Issue
Block a user