This commit is contained in:
Jadowyne Ulve 2024-10-27 10:12:51 -05:00
parent 76c3f33b55
commit e21fab65ea
11 changed files with 1564 additions and 558 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

143
api.py
View File

@ -155,6 +155,73 @@ def pagninate_items():
return jsonify({'items': pantry_inventory, "end": math.ceil(count/limit)})
@database_api.route("/getTransactions")
def pagninate_transactions():
item_id = request.args.get('id', 1)
page = int(request.args.get('page', 1))
limit = int(request.args.get('limit', 10))
site_name = session['selected_site']
offset = (page - 1) * limit
count = 0
transactions = []
database_config = config()
with psycopg2.connect(**database_config) as conn:
try:
with conn.cursor() as cur:
cur.execute(f"SELECT logistics_info_id FROM {site_name}_items WHERE id={item_id};")
logistics_info_id = cur.fetchone()[0]
sql = f"SELECT * FROM {site_name}_transactions WHERE logistics_info_id={logistics_info_id} LIMIT {limit} OFFSET {offset};"
count = f"SELECT COUNT(*) FROM {site_name}_transactions WHERE logistics_info_id={logistics_info_id};"
cur.execute(sql)
transactions = cur.fetchall()
cur.execute(count)
count = cur.fetchone()[0]
except (Exception, psycopg2.DatabaseError) as error:
print(error)
return jsonify({'transactions': transactions, "end": math.ceil(count/limit)})
@database_api.route("/getLocations")
def get_locations():
zone_name = request.args.get('zone', 1)
database_config = config()
site_name = session['selected_site']
locations = []
with psycopg2.connect(**database_config) as conn:
try:
with conn.cursor() as cur:
sql = f"SELECT id FROM {site_name}_zones WHERE name=%s;"
cur.execute(sql, (zone_name,))
zone_id = cur.fetchone()[0]
sqltwo = f"SELECT name FROM {site_name}_locations WHERE zone_id=%s;"
cur.execute(sqltwo, (zone_id, ))
locations = [location[0] for location in cur.fetchall()]
except (Exception, psycopg2.DatabaseError) as error:
print(error)
print(locations)
return jsonify(locations=locations)
@database_api.route("/getZones")
def get_zones():
database_config = config()
site_name = session['selected_site']
zones = []
with psycopg2.connect(**database_config) as conn:
try:
with conn.cursor() as cur:
sql = f"SELECT name FROM {site_name}_zones;"
cur.execute(sql)
zones = [zone[0] for zone in cur.fetchall()]
except (Exception, psycopg2.DatabaseError) as error:
print(error)
print(zones)
return jsonify(zones=zones)
@database_api.route("/getItem")
def get_item():
id = int(request.args.get('id', 1))
@ -181,7 +248,7 @@ def get_item():
except (Exception, psycopg2.DatabaseError) as error:
print(error)
return render_template(f"items/item.html", item=item, current_site=site_name, sites=sites['sites'])
return jsonify(item=item)
@database_api.route("/addItem")
def addItem():
@ -201,6 +268,8 @@ def addItem():
payload["logistics_info"]["primary_location"] = uuid
payload["logistics_info"]["auto_issue_location"] = uuid
tags = main.lst2pgarr([])
links = json.dumps({})
database_config = config()
with psycopg2.connect(**database_config) as conn:
@ -214,7 +283,7 @@ def addItem():
if not food_info_id:
return jsonify({'state': str(food_info_id)})
sqltwo = f"INSERT INTO {site_name}_items(barcode, item_name, description, item_info_id, logistics_info_id, food_info_id, row_type, item_type, search_string) VALUES('{barcode}', '{name}', '{description}', {item_info_id}, {logistics_info_id}, {food_info_id}, '{item_type}', '{subtype}', '{barcode}%{name}') RETURNING *;"
sqltwo = f"INSERT INTO {site_name}_items(barcode, item_name, tags, links, item_info_id, logistics_info_id, food_info_id, row_type, item_type, search_string) VALUES('{barcode}', '{name}', '{tags}', '{links}', {item_info_id}, {logistics_info_id}, {food_info_id}, 'single', 'FOOD', '{barcode}%{name}') RETURNING *;"
row = None
try:
with conn.cursor() as cur:
@ -237,6 +306,76 @@ def addItem():
return jsonify({'state': "SUCCESS"})
@database_api.route("/updateItem", methods=['POST'])
def updateItem():
def transformValues(values):
v = []
for value in values:
if isinstance(value, dict):
v.append(json.dumps(value))
elif isinstance(value, list):
v.append(main.lst2pgarr(value))
else:
v.append(value)
return v
def manufactureSQL(keys, item_id, table):
if len(keys) > 1:
x = f"({', '.join(keys)})"
y = f"({', '.join(['%s' for _ in keys])})"
else:
x = f"{', '.join(keys)}"
y = f"{', '.join(['%s' for _ in keys])}"
sql = f"UPDATE {table} SET {x} = {y} WHERE id={item_id};"
return sql
if request.method == "POST":
site_name = session['selected_site']
item_id = request.get_json()['id']
logistics_info_id = request.get_json()['logistics_info_id']
food_info_id = request.get_json()['food_info_id']
item_info_id = request.get_json()['item_info_id']
updated = request.get_json()['updated']
item_info = request.get_json()['item_info']
food_info = request.get_json()['food_info']
logistics_info = request.get_json()['logistics_info']
database_config = config()
with psycopg2.connect(**database_config) as conn:
try:
with conn.cursor() as cur:
if updated != {}:
values = transformValues(updated.values())
sql = manufactureSQL(updated.keys(), item_id, f"{site_name}_items")
cur.execute(sql, values)
if item_info != {}:
values = transformValues(item_info.values())
sql = manufactureSQL(item_info.keys(), item_info_id, f"{site_name}_item_info")
cur.execute(sql, values)
if food_info != {}:
values = transformValues(food_info.values())
sql = manufactureSQL(food_info.keys(), food_info_id, f"{site_name}_food_info")
cur.execute(sql, values)
if logistics_info != {}:
values = transformValues(logistics_info.values())
sql = manufactureSQL(logistics_info.keys(), logistics_info_id, f"{site_name}_logistics_info")
cur.execute(sql, values)
cur.execute(f"SELECT barcode FROM {site_name}_items WHERE id={item_id};")
barcode = cur.fetchone()[0]
print(barcode)
main.add_transaction(site_name, barcode, 0, 1, "SYSTEM", "Item data was update!", data=request.get_json())
except (Exception, psycopg2.DatabaseError) as error:
print(error)
conn.rollback()
return jsonify({"state": "SUCCESS"})
return jsonify({"status": "FAILED"})
@database_api.route("/addGroup")
def addGroup():
name = str(request.args.get('name', ""))

28
main.py
View File

@ -248,6 +248,8 @@ def add_food_item(site_name: str, barcode: str, name: str, payload: dict):
payload["logistics_info"]["primary_location"] = uuid
payload["logistics_info"]["auto_issue_location"] = uuid
tags = lst2pgarr([])
links = json.dumps({})
database_config = config()
with psycopg2.connect(**database_config) as conn:
@ -261,7 +263,7 @@ def add_food_item(site_name: str, barcode: str, name: str, payload: dict):
if not food_info_id:
return False
sqltwo = f"INSERT INTO {site_name}_items(barcode, item_name, item_info_id, logistics_info_id, food_info_id, row_type, item_type, search_string) VALUES('{barcode}', '{name}', {item_info_id}, {logistics_info_id}, {food_info_id}, 'item', 'FOOD', '{barcode}%{name}') RETURNING *;"
sqltwo = f"INSERT INTO {site_name}_items(barcode, item_name, tags, links, item_info_id, logistics_info_id, food_info_id, row_type, item_type, search_string) VALUES('{barcode}', '{name}', '{tags}', '{links}', {item_info_id}, {logistics_info_id}, {food_info_id}, 'single', 'FOOD', '{barcode}%{name}') RETURNING *;"
row = None
try:
with conn.cursor() as cur:
@ -398,7 +400,24 @@ payload_food_item = {
"food_info": {
"food_groups": [],
"ingrediants": [],
"nutrients": {},
"nutrients": {
'serving': '',
'serving_unit': '',
'calories': '',
'calories_unit': 'serving',
'proteins': '',
'proteins_unit': '',
'fats': '',
'fats_unit': '',
'carbohydrates': '',
'carbohydrates_unit': '',
'sugars': '',
'sugars_unit': '',
'sodium': '',
'sodium_unit': '',
'fibers': '',
'fibers_unit': ''
},
"expires": False
},
"logistics_info":{
@ -426,7 +445,7 @@ def parse_csv(path_to_csv):
if line[17] != "None":
payload["item_info"]["safety_stock"] = line[17]
qty = float(line[30])
add_food_item(site_name="main", barcode=line[1], name=line[2], qty=qty, payload=payload)
add_food_item(site_name="main", barcode=line[1], name=line[2], payload=payload)
@ -443,4 +462,5 @@ if __name__ == "__main__":
for k, v in items.items():
print(f"{k}: {v}")
"""
parse_csv(r"C:\\Users\\jadow\\Documents\\code\\postgresql python\\postgresql-python\\2024-10-02-Pantry.csv")
parse_csv(r"C:\\Users\\jadow\\Documents\\code\\postgresql python\\postgresql-python\\2024-10-02-Pantry.csv")

View File

@ -30,7 +30,7 @@ WHERE test_items.id=%s;
22 - linked_items
23 - shopping_lists
24 - recipes
25 - groups <--
25 - groups
26 - packaging
27 - uom
28 - cost

View File

@ -1,12 +1,120 @@
async function fetchItem() {
const url = new URL('/getItem', window.location.origin);
url.searchParams.append('id', item_id);
const response = await fetch(url);
data = await response.json();
item = data.item;
};
async function fetchZones() {
const url = new URL('/getZones', window.location.origin);
const response = await fetch(url);
data = await response.json();
zones = data.zones;
};
async function fetchLocations(zone) {
const url = new URL('/getLocations', window.location.origin);
url.searchParams.append('zone', zone);
const response = await fetch(url);
data = await response.json();
return data.locations;
};
async function setupLocations(locations, el) {
let loc_el = document.getElementById(el)
console.log(locations)
loc_el.innerHTML = ""
let option = document.createElement('option')
option.value = "undefined"
option.innerHTML = "Select Location..."
loc_el.appendChild(option)
for (let i = 0; i < locations.length; i++){
let option = document.createElement('option')
option.value = locations[i]
option.innerHTML = locations[i]
loc_el.appendChild(option)
};
};
async function setupZones() {
let primary_zone = document.getElementById('primary_zone')
for (let i = 0; i < zones.length; i++){
let option = document.createElement('option')
option.value = zones[i]
option.innerHTML = zones[i]
primary_zone.appendChild(option)
};
let issue_zone = document.getElementById('issue_zone')
for (let i = 0; i < zones.length; i++){
let option = document.createElement('option')
option.value = zones[i]
option.innerHTML = zones[i]
issue_zone.appendChild(option)
};
};
async function loadPrimaryLocations() {
let primary_zone = document.getElementById('primary_zone').value
primary_locations = await fetchLocations(primary_zone)
await setupLocations(primary_locations, 'primary_location')
};
async function loadIssueLocations() {
let issue_zone = document.getElementById('issue_zone').value
issue_locations = await fetchLocations(issue_zone)
await setupLocations(issue_locations, 'issue_location')
};
async function addLink(){
event.preventDefault()
let key = document.getElementById('link_name').value;
let link = document.getElementById('link').value;
links[key] = link;
console.log(links)
links_changed = true;
await propagateLinks()
};
function updatePrimaryLocation(){
let primary_zone = document.getElementById('primary_zone').value
let primary_location = document.getElementById('primary_location').value
if (primary_location == "undefined"){
document.getElementById('primary_location').style = "border-color: red;"
} else {
document.getElementById('primary_location').style = ""
logistics_info['primary_location'] = `${primary_zone}@${primary_location}`
};
};
function updateIssueLocation(){
let issue_zone = document.getElementById('issue_zone').value
let issue_location = document.getElementById('issue_location').value
if (issue_location == "undefined"){
document.getElementById('issue_location').style = "border-color: red;"
} else {
document.getElementById('issue_location').style = ""
logistics_info['auto_issue_location'] = `${issue_zone}@${issue_location}`
};
};
function updateEntryType(){
updated['row_type'] = document.getElementById('entry_type').value;
console.log(updated)
};
function updateItemType(){
updated['item_type'] = document.getElementById('item_type').value;
console.log(updated)
};
function updatePackaging(){
let packaging = document.getElementById('packaging').value;
item_info['packaging'] = packaging;
@ -43,3 +151,71 @@ function updateAiPickable(){
console.log(item_info)
};
function updateExpires(){
let expires = document.getElementById('expires');
food_info['expires'] = expires.checked;
console.log(food_info)
};
function updateNutrients(){
nutrients = {
serving: document.getElementById('serving').value,
serving_unit: document.getElementById('serving_unit').value,
calories: document.getElementById('calories').value,
calories_unit: document.getElementById('calories_unit').value,
proteins: document.getElementById('proteins').value,
proteins_unit: document.getElementById('proteins_unit').value,
fats: document.getElementById('fats').value,
fats_unit: document.getElementById('fats_unit').value,
carbohydrates: document.getElementById('carbohydrates').value,
carbohydrates_unit: document.getElementById('carbohydrates_unit').value,
sugars: document.getElementById('sugars').value,
sugars_unit: document.getElementById('sugars_unit').value,
sodium: document.getElementById('sodium').value,
sodium_unit: document.getElementById('sodium_unit').value,
fibers: document.getElementById('fibers').value,
fibers_unit: document.getElementById('fibers_unit').value
};
console.log(nutrients)
nutrients_changed = true;
}
async function saveItem() {
// Only add the key, values if something has changed
if (food_groups_changed){
food_info['food_groups'] = food_groups;
};
if (tags_changed){
updated['tags'] = tags;
};
if (ingrediants_changed){
food_info['ingrediants'] = ingrediants;
};
if (nutrients_changed){
food_info['nutrients'] = nutrients;
};
if (links_changed){
updated['links'] = links;
};
await fetch(`/updateItem`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: item_id,
logistics_info_id: item[8],
food_info_id: item[9],
item_info_id: item[7],
updated: updated,
item_info: item_info,
food_info: food_info,
logistics_info: logistics_info,
}),
});
M.toast({html: "Item has been saved successfully!", classes: "rounded green lighten-4 black-text"});
};

View File

@ -385,7 +385,7 @@
button_group.style = "margin-bottom: 0px; padding-bottom: 0px;"
button_group.innerHTML = `
<div class="col s12" style="align-items: center;">
<a href="/getItem?id=${item[0]}"class="btn right green lighten-3 black-text text-darken-2 z-depth-0 tooltipped" data-position="bottom" data-tooltip="Edit Item" style="display: inline-flex; border-radius: 20px 10px 20px 10px;">
<a href="/item/${item[0]}"class="btn right green lighten-3 black-text text-darken-2 z-depth-0 tooltipped" data-position="bottom" data-tooltip="Edit Item" style="display: inline-flex; border-radius: 20px 10px 20px 10px;">
<i class='material-icons'>edit</i>
</a>
<a class="btn right green lighten-3 black-text text-darken-2 z-depth-0 tooltipped" data-position="left" data-tooltip="Transactions" style="display: inline-flex; margin-right: 5px; margin-top:0px; border-radius: 20px 10px 20px 10px;">

View File

@ -53,121 +53,398 @@
<li><a href="/groups">Site Groups</a></li>
<li><a href="/shopping-lists">Site Shopping Lists</a></li>
</ul>
<body>
<body style="margin-bottom: 80px;">
<div class="container section">
<div class="row g-4">
<div class="col s12">
<h3>{{item[2]}}</h3>
<h5>Database ID: {{item[0]}}</h5>
<h5>Barcode: {{item[1]}}</h5>
</div>
<div class="s12 m6" style="margin-right: 5px;">
<label for="entry_type">Entry Type</label>
<select id="entry_type" class="browser-default" >
<option value="" disabled selected>Choose your option</option>
<option value="single">item</option>
<option value="linked">linked list</option>
</select>
</div>
<div class="s12 m6">
<label for="item_type">Item Type</label>
<select id="item_type" class="browser-default">
<option value="" disabled selected>Choose your option</option>
<option value="FOOD">Food</option>
<option value="FOOD (PLU)">Food(PLU)</option>
<option value="OTHER">Other</option>
</select>
</div>
<!-- Weblinks Input perhaps a modal to add a link or a text input..?-->
<div class="divider col s12" style="margin-top: 5px;"></div>
<div class="col s12">
<div class="row">
<div class="col s6" style="padding-top: 10px;">
<span style="font-size: 16px;">Links</span>
<div class="col s6">
<a href="#" data-target="slide-out" class="sidenav-trigger hide-on-large-only left btn green lighten-4 black-text btn-flat"><i class="material-icons">menu</i></a>
</div>
<div class="col s6">
<button class="btn btn-flat grey right white-text hide-on-med-and-up show-on-small-only" onclick="saveItem()"><i class="large material-icons">save</i></button>
</div>
<div class="col s12">
<h3 id="item_name"></h3>
</div>
<div class="col s6">
<h5 id="database_id"></h5>
</div>
<div class="col s6 right">
<h5 class="right" id="barcode"></h5>
</div>
<div class="col s12 green lighten-4" style="margin-top: 10px; margin-bottom: 10px; border-radius: 10px;">
<h5 class="center">Item Types</h5>
</div>
<div class="col s12">
<div class="card-panel grey z-depth-0 lighten-4">
<span class="black-text">
Here is how you classify the type of item this barcode/id is. There are two types:<br><br>
<b>Entry Type:</b> is how the item is classified across the system.<br>
<b>Item Type:</b> is more of a subtype for your own filtering and defining.
</span>
</div>
<div class="col s6">
<button class="btn btn-small btn-flat right modal-trigger green lighten-4 black-text" data-target="web-modal" style="margin-top: 5px; padding-bottom: 10px;">Add Link</button>
</div>
<div class="s12 m6" style="margin-right: 5px;">
<label for="entry_type">Entry Type</label>
<select onchange="updateEntryType()" id="entry_type" class="browser-default" >
<option value="" disabled selected>Choose your option</option>
<option value="single">Single</option>
<option value="linked">Linked</option>
</select>
</div>
<div class="s12 m6">
<label for="item_type">Item Type</label>
<select onchange="updateItemType()" id="item_type" class="browser-default">
<option value="" disabled selected>Choose your option</option>
<option value="FOOD">Food</option>
<option value="FOOD (PLU)">Food(PLU)</option>
<option value="OTHER">Other</option>
</select>
</div>
<div class="col s12 green lighten-4" style="margin-top: 10px; margin-bottom: 10px; border-radius: 10px;">
<h5 class="center">General Tags</h5>
</div>
<div class="col s12">
<div class="card-panel grey z-depth-0 lighten-4">
<span class="black-text">Here is where you can assign this barcode/id general tags to your
liking. These can be things that set them apart, group items together, or even little notes
to remind yourself what this item is.
</span>
</div>
<div id="tags_container" class="col s12 chips">
<!-- This holds open for tags pills -->
</div>
<div class="col s12 p-3">
<div id="weblinks">
</div>
<div id="tags_container" class="col s12 chips">
<!-- This holds open for tags pills -->
</div>
<!-- Weblinks Input perhaps a modal to add a link or a text input..?-->
<div class="divider col s12" style="margin-top: 5px;"></div>
<div class="col s12">
<div class="row">
<div class="col s12 green lighten-4" style="margin-bottom: 10px; border-radius: 10px;">
<h5 class="center">Links</h5>
</div>
<div class="col s12">
<div class="card-panel grey z-depth-0 lighten-4">
<span class="black-text">Here is where you can set links for this barcode/id that
might provide you and others paths to understand better what this item is used for.
The only rule here is that if you would like for other systems to use a link then you
must assign a <b>main</b> link.
</span>
</div>
</div>
<div class="col s10">
<div id="weblinks">
</div>
</div>
<div class="col s2">
<button class="btn btn-small btn-flat right modal-trigger green lighten-4 black-text" data-target="web-modal" style="margin-top: 5px; padding-bottom: 10px;">Add Link</button>
</div>
</div>
</div>
</div>
<div class="divider col s12" style="margin-top: 5px;"></div>
<div class="divider col s12" style="margin-top: 5px;"></div>
<div class="col s12">
<div class="row">
<div class="col s12">
<ul class="tabs tabs-fixed-width" id="info_tabs" style="background-color: white;">
<li class="tab col s3"><a class="active" href="#item_info">Item Info</a></li>
<li class="tab col s3"><a href="#food_info">Food Info</a></li>
<li class="tab col s3"><a href="#logistics_info">Logistics Info</a></li>
<li class="tab col s3 disabled"><a href="#linked_items">Linked Items</a></li>
</ul>
</div>
<div id="item_info" class="col s12">
<div class="row" style="gap: 10px; padding-top: 10px;">
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updatePackaging()" id="packaging" type="text" placeholder=" " maxlength="32">
<label for="packaging">Packaging</label>
<div class="col s12" style="margin-top: 50px;">
<div class="row">
<div class="col s12">
<ul class="tabs tabs-fixed-width green lighten-4 black-text" id="info_tabs" style="border-radius: 10px 10px 0px 0px">
<li class="tab col s3"><a class="active" href="#item_info">Item Info</a></li>
<li class="tab col s3"><a href="#food_info">Food Info</a></li>
<li class="tab col s3"><a href="#logistics_info">Logistics Info</a></li>
<li class="tab col s3 disabled"><a href="#linked_items">Linked Items</a></li>
</ul>
</div>
<div id="item_info" class="col s12 grey lighten-5 p-3">
<div class="row" style="gap: 10px; padding-top: 10px;">
<div class="col s12 green lighten-4" style="border-radius: 10px;">
<h5 class="center">Purchasing/Packaging</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">The following information is used for financial
reports and to give quick information to the user how this item is represented
logically in the system. <b>Safety Stock</b> and <b>Leadtime</b> is used when using systems that
calculate quantites on the fly. <b>AI Pickable</b> sets this item to be used with any
Artifical Intelligent systems (TBD).
</span>
</div>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updatePackaging()" id="packaging" type="text" placeholder=" " maxlength="32">
<label for="packaging">Packaging</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateUOM()" id="uom" type="text" placeholder=" " maxlength="32">
<label for="uom">Unit of Measure</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateCost()" id="cost" type="number" placeholder=" " maxlength="32">
<label for="cost">Cost</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateSafetyStock()" id="safety_stock" type="number" placeholder=" " maxlength="32">
<label for="safety_stock">Safety Stock</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateLeadTimeDays()" id="lead_time_days" type="number" placeholder=" " maxlength="32">
<label for="lead_time_days">Leadtime (Days)</label>
</div>
<div class="col s6 m4 center">
<p>
<label>
<input onclick="updateAiPickable()" id="ai_pickable" type="checkbox" />
<span>AI Pickable</span>
</label>
</p>
</div>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateUOM()" id="uom" type="text" placeholder=" " maxlength="32">
<label for="uom">Unit of Measure</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateCost()" id="cost" type="number" placeholder=" " maxlength="32">
<label for="cost">Cost</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateSafetyStock()" id="safety_stock" type="number" placeholder=" " maxlength="32">
<label for="safety_stock">Safety Stock</label>
</div>
<div class="col s6 m4 input-field outlined item_info_target">
<input onchange="updateLeadTimeDays()" id="lead_time_days" type="number" placeholder=" " maxlength="32">
<label for="lead_time_days">Leadtime (Days)</label>
</div>
<div class="col s6 m4 center">
<p>
<label>
<input onclick="updateAiPickable()" id="ai_pickable" type="checkbox" />
<span>AI Pickable</span>
</label>
</p>
<div class="divider col s12" style="margin-top: 10px;"></div>
<div class="row" style="gap: 10px; padding-top: 10px;">
<div class="col s12 green lighten-4" style="border-radius: 10px;">
<h5 class="center">References</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">References are where this barcode/id is used in other systems
such as Recipes, Shopping Lists, Groups, etc. This will further be expanded on as more
systems are distributed.
</span>
</div>
</div>
<div class="col s12">
<table class="" id="reference_table">
<thead>
<tr>
<th>Reference Type</th>
<th>Reference Name</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<table class="" id="reference_table">
<thead>
<tr>
<th>Reference Type</th>
<th>Reference Name</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div id="food_info" class="col s12">
<div class="row" style="gap: 10px; padding-top: 10px;">
<div id="food_groups_container" class="col s12 chips chips-initial">
<!-- This holds open for food groups pills -->
<div id="food_info" class="col s12">
<div class="row grey lighten-5 p-3" style="gap: 10px; padding-top: 10px;">
<!-- expiration -->
<div class="col s12 green lighten-4" style="border-radius: 10px;">
<h5 class="center">Expiration</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">You may want to set up expiration dates for this barcode/id and this is where you
set this information so the system can use that information to send you notifications when
an item has something that will expire.
</span>
</div>
</div>
<div class="col s1 m2"></div>
<div class="col s5 m4 input-field outlined item_info_target">
<input id="default_expiry_days" type="number" placeholder=" " maxlength="32" disabled>
<label for="default_expiry_days">Default Expires (Days)</label>
</div>
<div class="col s5 m4 center">
<p>
<label>
<input onclick="updateExpires()" id="expires" type="checkbox" />
<span>Expires</span>
</label>
</p>
</div>
<div class="col s1 m2"></div>
<!-- Food tags -->
<div class="col s12 green lighten-4" style="border-radius: 10px;">
<h5 class="center">Food Tags</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">Just like general tags these are tags specific to food items though
you can use them entirely to your own wills. These have been seperated by <b>food groups</b> and
<b>ingrediants</b>.
</span>
</div>
</div>
<div id="food_groups_container" class="col s12 chips chips-initial">
<!-- This holds open for food groups pills -->
</div>
<div id="ingrediants_container" class="col s12 chips">
<!-- This holds all the ingrediants pills -->
</div>
<div class="divider col s12"></div>
<div id="nutrients_container" class="col s12">
<div class="row" style="gap: 10px; padding-top: 10px;">
<!-- nutrients -->
<div class="col s12 green lighten-4" style="border-radius: 10px;">
<h5 class="center">Nutriments</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">Self explanitory, this is nutriments for this barcode/id for
quick reference for foods. Not really used outside of food items, but if this info is
set then other systems will use the info to calculate overall nutriments.
</span>
</div>
</div>
<!-- serving size -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="serving" type="text" placeholder="" name="serving" value="">
<label for="serving">Serving</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="serving_unit" type="text" placeholder="" name="serving_unit" value="">
<label for="serving_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- calories -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="calories" type="text" placeholder="" name="calories" value="">
<label for="calories">Calories</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="calories_unit" type="text" placeholder="" name="calories_unit" value="serving" disabled="">
<label for="calories_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- Proteins -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="proteins" type="text" placeholder="" name="proteins" value="10.94">
<label for="proteins">Proteins</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="proteins_unit" type="text" placeholder="" name="proteins_unit" value="g">
<label for="proteins_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- Fats -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="fats" type="text" placeholder="" name="fats" value="">
<label for="fats">Fats</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="fats_unit" type="text" placeholder="" name="fats_unit" value="">
<label for="fats_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- Carbohydrates -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="carbohydrates" type="text" placeholder="" name="carbohydrates" value="60.94">
<label for="carbohydrates">Carbs</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="carbohydrates_unit" type="text" placeholder="" name="carbohydrates_unit" value="g">
<label for="carbohydrates_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- Sugars -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="sugars" type="text" placeholder="" name="sugars" value="3.12">
<label for="sugars">Sugars</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="sugars_unit" type="text" placeholder="" name="sugars_unit" value="g">
<label for="sugars_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- Sodium -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="sodium" type="text" placeholder="" name="sodium" value="1.859">
<label for="sodium">Sodium</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="sodium_unit" type="text" placeholder="" name="sodium_unit" value="mg">
<label for="sodium_unit">Unit</label>
</div>
<div class="col s1 m1"></div>
<!-- Fibers -->
<div class="col s1 m1"></div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" class="right-align" id="fibers" type="text" placeholder="" name="fibers" value="">
<label for="fibers">Fibers</label>
</div>
<div class="col s5 m2 input-field outlined">
<input onchange="updateNutrients()" id="fibers_unit" type="text" placeholder="" name="fibers_unit" value="">
<label for="fibers_unit">Unit</label>
</div>
</div>
</div>
</div>
<div id="ingrediants_container" class="col s12 chips">
<!-- This holds all the ingrediants pills -->
</div>
<div id="nutrients_container" class="col s12">
<!-- This holds all the nutrients tables -->
</div>
</div>
<div id="logistics_info" class="col s12">
<div class="row grey lighten-5 p-3" style="gap: 10px; padding-top: 10px;">
<div class="col s12 green lighten-4" style="border-radius: 10px;">
<h5 class="center">Primary/Auto-Issue</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">Here is where you will assign this barcode/id's primary zone, primary
location, auto-issue zone, and auto-issue location. Essentially the <b>Primary</b> is where
the item will be adjusted into by default and the <b>Auto-Issue</b> will be where it is
adjusted out of by default. This data is madatory for all items and the admin will have
set up defaults for these.
</span>
</div>
</div>
<div class="s12 m6" style="margin-right: 5px;">
<label for="primary_zone">Primary Zone</label>
<select onchange="loadPrimaryLocations()" id="primary_zone" class="browser-default" >
<option value="" disabled selected>Choose your option</option>
</select>
</div>
<div class="s12 m6" style="margin-right: 5px;">
<label for="primary_location">Primary Location</label>
<select onchange="updatePrimaryLocation()" id="primary_location" class="browser-default" >
<option value="" disabled selected>Choose your option</option>
</select>
</div>
<div class="s12 m6" style="margin-right: 5px;">
<label for="issue_zone">Auto-Issue Zone</label>
<select onchange="loadIssueLocations()" id="issue_zone" class="browser-default" >
<option value="" disabled selected>Choose your option</option>
</select>
</div>
<div class="s12 m6" style="margin-right: 5px;">
<label for="issue_location">Auto-Issue Location</label>
<select onchange="updateIssueLocation()" id="issue_location" class="browser-default" >
<option value="" disabled selected>Choose your option</option>
<option value="single">Single</option>
<option value="linked">Linked</option>
</select>
</div>
<div class="col s12 green lighten-4" style=" margin-top: 10px; border-radius: 10px;">
<h5 class="center">Locations</h5>
</div>
<div class="col s12">
<div class="card-panel green z-depth-0 lighten-5">
<span class="black-text">Here is a general table of where this barcode/id has
quantities on hand in the system.
</span>
</div>
</div>
<div class="col s12">
<table class="" id="locations_table">
<thead>
<tr>
<th class="center">Zone</th>
<th class="center">Location</th>
<th class="center">QOH</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
<div id="linked_items" class="col s12 disabled">Linked Items</div>
</div>
<div id="logistics_info" class="col s12">Logistics Info</div>
<div id="linked_items" class="col s12 disabled">Linked Items</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="web-modal" class="modal">
@ -199,22 +476,48 @@
<button onclick="addLink()" class="waves-effect green lighten-4 btn-flat">Add</button>
</div>
</div>
<div class="fixed-action-btn show-on-med-and-up hide-on-small-only">
<button class="btn-floating btn-large" onclick="saveItem()">
<i class="large material-icons">save</i>
</button>
</div>
</body>
<script src="{{ url_for('static', filename='itemHandler.js') }}"></script>
<script>
var item = {{ item|tojson }};
const item_id = {{id|tojson}}
let item;
var reference_state = 1
let links = {};
let updated = {};
let item_info = {};
let food_info = {};
let logistics_info = {};
let zones;
let primary_locations;
let issue_locations;
let updated = {}; // updated columns in the item table
let item_info = {}; // updated columns in the item_info table
let food_info = {}; // updated columns in the food_info table
let logistics_info = {}; // updated columns in the logistics_info table
let food_groups = [];
let food_groups_changed = false;
let ingrediants = [];
let ingrediants_changed = false;
let tags = [];
let tags_changed = false;
let links = {};
let links_changed = false;
let nutrients = {};
let nutrients_changed = false;
document.addEventListener('DOMContentLoaded', async function() {
await fetchItem()
await fetchZones()
await setupZones()
document.getElementById("title").innerHTML = String(item[2])
var elemsSelects = document.querySelectorAll('select');
@ -226,53 +529,89 @@
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems, {});
await propagateInfo()
M.AutoInit();
var elem = document.getElementById('food_groups_container');
M.Chips.init(elem, {
placeholder: 'Add Group...',
secondaryPlaceholder: 'Add Group...',
onChipDelete: deleteFoodGroup,
onChipAdd: addFoodGroup,
onChipDelete: deleteChip,
onChipAdd: addChip,
});
var elem = document.getElementById('ingrediants_container');
M.Chips.init(elem, {
placeholder: 'Add Ingrediant...',
secondaryPlaceholder: 'Add Ingrediant...',
onChipDelete: deleteIngrediant,
onChipAdd: addIngrediant,
onChipDelete: deleteChip,
onChipAdd: addChip,
});
var elem = document.getElementById('tags_container');
M.Chips.init(elem, {
placeholder: 'Add Tag...',
secondaryPlaceholder: 'Add Tag...',
onChipDelete: deleteTag,
onChipAdd: addTag,
onChipDelete: deleteChip,
onChipAdd: addChip,
});
await propagateInfo()
//refreshFoodGroups()
refreshChips('food_groups_container', food_groups, item[33])
refreshChips('ingrediants_container', ingrediants, item[34])
populateReferences(item[23], 'shopping_list')
populateReferences(item[24], 'recipe')
populateReferences(item[25], 'group')
await propagateLinks()
await populateLocations()
console.log(updated)
});
async function propagateInfo(){
document.getElementById('item_name').innerHTML = item[2];
document.getElementById('database_id').innerHTML = `Database ID: ${item[0]}`;
document.getElementById('barcode').innerHTML = `Barcode: ${item[1]}`;
const entryType = document.getElementById('entry_type');
entryType.value = item[10];
const itemType = document.getElementById('item_type');
itemType.value = item[11];
await propagateLinks()
//food_groups = item[33];
//ingrediants = item[34];
tags = item[5];
if (item[6]){
links = item[6];
} else {
links = {};
};
refreshChips('food_groups_container', food_groups, item[33])
refreshChips('ingrediants_container', ingrediants, item[34])
refreshChips('tags_container', tags, item[5])
await propagateItemInfo()
await propagateNutrients()
let primary = item[15].split('@')
let issue = item[16].split('@')
console.log(primary)
await setPrimaryLocation(primary[0], primary[1])
await setIssueLocation(issue[0], issue[1])
food_groups_changed = false;
ingrediants_changed = false;
tags_changed = false;
nutrients_changed = false;
links_changed = false;
M.toast({html: "Item has been loaded successfully!", classes: "rounded green lighten-4 black-text flow-text"});
};
async function setPrimaryLocation(zone, location){
console.log(zone)
document.getElementById('primary_zone').value = zone
await loadPrimaryLocations()
console.log(location)
document.getElementById('primary_location').value = location
};
async function setIssueLocation(zone, location){
console.log(zone)
document.getElementById('issue_zone').value = zone
await loadIssueLocations()
document.getElementById('issue_location').value = location
};
function refreshChips(elem_id, chips_array, initial_chips){
@ -283,42 +622,43 @@
}
};
function addFoodGroup(e, chip){
function addChip(e, chip){
chipText = chip.textContent.replace('close', '').trim()
console.log(chipText)
food_groups.push(chipText)
console.log(food_groups)
}
function addIngrediant(e, chip){
chipText = chip.textContent.replace('close', '').trim()
console.log(chipText)
ingrediants.push(chipText)
console.log(ingrediants)
}
function addTag(e, chip){
chipText = chip.textContent.replace('close', '').trim()
console.log(chipText)
tags.push(chipText)
console.log(tags)
}
function deleteFoodGroup(e, chip){
chipText = chip.textContent.replace('close', '').trim()
food_groups = food_groups.filter(chip => chip !== chipText);
if (e[0].id == "food_groups_container"){
food_groups.push(chipText)
food_groups_changed = true;
console.log(food_groups)
};
if (e[0].id == "ingrediants_container"){
ingrediants.push(chipText)
ingrediants_changed = true;
console.log(ingrediants)
};
if (e[0].id == "tags_container"){
tags.push(chipText)
tags_changed = true;
console.log(tags)
};
};
function deleteIngrediant(e, chip){
function deleteChip(e, chip){
chipText = chip.textContent.replace('close', '').trim()
ingrediants = ingrediants.filter(chip => chip !== chipText);
}
function deleteTag(e, chip){
chipText = chip.textContent.replace('close', '').trim()
tags = tags.filter(chip => chip !== chipText);
}
if (e[0].id == "food_groups_container"){
food_groups = food_groups.filter(chip => chip !== chipText);
food_groups_changed = true;
console.log(food_groups)
};
if (e[0].id == "ingrediants_container"){
ingrediants = ingrediants.filter(chip => chip !== chipText);
ingrediants_changed = true;
console.log(ingrediants)
};
if (e[0].id == "tags_container"){
tags = tags.filter(chip => chip !== chipText);
tags_changed = true;
console.log(tags)
};
};
async function propagateLinks(){
var element = document.getElementById("weblinks");
@ -335,16 +675,46 @@
link.href = links[key];
element.appendChild(link);
}
}
};
async function addLink(){
event.preventDefault()
let key = document.getElementById('link_name').value;
let link = document.getElementById('link').value;
links[key] = link;
console.log(links)
await propagateLinks()
}
async function propagateItemInfo(){
document.getElementById('packaging').value = item[26]
document.getElementById('uom').value = item[27]
document.getElementById('cost').value = item[28]
document.getElementById('safety_stock').value = item[29]
document.getElementById('lead_time_days').value = item[30]
// ai_pickable
document.getElementById('ai_pickable').checked = item[31];
document.getElementById('expires').checked = item[36];
populateReferences(item[23], 'shopping_list')
populateReferences(item[24], 'recipe')
populateReferences(item[25], 'group')
};
async function propagateNutrients(){
if (item[35]){
nutrients = item[35];
} else {
nutrients = {};
};
document.getElementById('serving').value = nutrients['serving']
document.getElementById('serving_unit').value = nutrients['serving_unit']
document.getElementById('calories').value = nutrients['calories']
document.getElementById('calories_unit').value = nutrients['calories_unit']
document.getElementById('proteins').value = nutrients['proteins']
document.getElementById('proteins_unit').value = nutrients['proteins_unit']
document.getElementById('fats').value = nutrients['fats']
document.getElementById('fats_unit').value = nutrients['fats_unit']
document.getElementById('carbohydrates').value = nutrients['carbohydrates']
document.getElementById('carbohydrates_unit').value = nutrients['carbohydrates_unit']
document.getElementById('sugars').value = nutrients['sugars']
document.getElementById('sugars_unit').value = nutrients['sugars_unit']
document.getElementById('sodium').value = nutrients['sodium']
document.getElementById('sodium_unit').value = nutrients['sodium_unit']
document.getElementById('fibers').value = nutrients['fibers']
document.getElementById('fibers_unit').value = nutrients['fibers_unit']
};
function populateReferences(references, reference_type){
var table = document.getElementById("reference_table")
@ -361,8 +731,42 @@
row.style = "background-color: gainsboro;"
}
reference_state++
}
}
};
};
async function populateLocations(){
var table = document.getElementById("locations_table")
console.log(item[18])
let colorstate = 1;
for (let key in item[18]){
console.log(item[18][key])
this_location = key.split("@")
qty = item[18][key]
var row = table.insertRow();
var row_type = row.insertCell();
var row_name = row.insertCell();
var row_qty = row.insertCell();
row_type.classList.add("center")
row_name.classList.add("center")
row_qty.classList.add("center")
row_type.innerHTML = this_location[0]
row_name.innerHTML = this_location[1]
row_qty.innerHTML = qty
if ((colorstate % 2) == 0){
row.style = "background-color: gainsboro;"
}
colorstate++
};
};
</script>
</html>

View File

@ -0,0 +1,255 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
<title id="title"></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/css/materialize.min.css" />
<!-- Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<!-- Material Symbols - Outlined Set -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
<!-- Material Symbols - Rounded Set -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded" rel="stylesheet" />
<!-- Material Symbols - Sharp Set -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</head>
<style>
header, main, footer, body {
padding-left: 300px;
}
@media only screen and (max-width : 992px) {
header, main, footer, body {
padding-left: 0;
}
}
.dropdown-disabled {
pointer-events: none;
opacity: 0.5; /* or your desired degree of transparency */
}
</style>
<ul id='dropdown1' class='dropdown-content'>
{% for site in sites %}
<li><button class="btn transparent black-text z-depth-0" onclick="changeSite('{{ site }}')">{{site}}</button></li>
{% endfor %}
</ul>
<ul id="slide-out" class="sidenav sidenav-fixed green lighten-4" style="width: 250px;">
<li>
<div class="user-view">
<!-- <div class="background">
<img src="images/office.jpg">
</div> -->
<!-- <a href="#user"><img class="circle" src="images/yuna.jpg"></a> -->
<a href="#name"><span class="black-text name">John Doe</span></a>
<a href="#email"><span class="black-text email">jdoe@example.com</span></a>
</div>
</li>
<li><a class="dropdown-trigger dropdown-disabled" data-target="dropdown1">Current Site > {{current_site}}<i class="material-icons right">arrow_drop_down</i></a></li>
<li><div class="divider grey darken-1" style="margin-left: 5px; margin-right: 10px;"></div></li>
<li><a href="/items">Site Items</a></li>
<li><a href="/groups">Site Groups</a></li>
<li><a href="/shopping-lists">Site Shopping Lists</a></li>
</ul>
<body style="margin-bottom: 80px;">
<div class="container section">
<div class="row g-4">
<div class="col s6">
<a href="#" data-target="slide-out" class="sidenav-trigger hide-on-large-only left btn green lighten-4 black-text btn-flat"><i class="material-icons">menu</i></a>
</div>
<div class="col s6">
<button class="btn btn-flat grey right white-text hide-on-med-and-up show-on-small-only" onclick="saveItem()"><i class="large material-icons">save</i></button>
</div>
<div class="col s12">
<table id="transaction_table">
<thead>
</thead>
<tbody id="table_body">
</tbody>
</table>
</div>
<div class="col s12 center" id="pagination_list">
<ul class="pagination">
<li id="first" class="waves-effect hand-pointer"><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">first_page</i></a></li>
<li id="back" class="waves-effect hand-pointer" ><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">chevron_left</i></a></li>
<li id="current_page" style="padding-top: 7px; padding-left: 5px; padding-right: 5px; font-size: 18px;">page_number</li>
<li id="forward" class="waves-effect hand-pointer"><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">chevron_right</i></a></li>
<li id="last" class="waves-effect hand-pointer"><a class="green lighten-3" style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 10px;"><i class="material-icons">last_page</i></a></li>
</ul>
</div>
<div class="fixed-action-btn">
<a class="btn-floating btn-large">
<i class="large material-icons">more_vert</i>
</a>
<ul>
<li><a class="btn-floating blue darken-1 modal-trigger" href="#modal1"><i class="material-icons">playlist_add</i></a></li>
<li><a class="btn-floating green darken-1"><i class="material-icons">download</i></a></li>
</ul>
</div>
</div>
</body>
<script>
const item_id = {{id|tojson}}
let current_page = 1
let end_page;
let limit = 50
document.addEventListener('DOMContentLoaded', async function() {
await fetchTransactions();
});
async function fetchTransactions(){
console.log(current_page)
if (current_page === 1){
document.getElementById('back').classList.add("disabled")
document.getElementById('back').classList.remove("waves-effect")
document.getElementById('first').classList.add("disabled")
document.getElementById('first').classList.remove("waves-effect")
} else {
document.getElementById('back').classList.remove("disabled")
document.getElementById('back').classList.add("waves-effect")
document.getElementById('first').classList.remove("disabled")
document.getElementById('first').classList.add("waves-effect")
};
const url = new URL('/getTransactions', window.location.origin);
url.searchParams.append('id', item_id);
url.searchParams.append('page', current_page);
url.searchParams.append('limit', limit);
await fetch(url)
.then(response => response.json())
.then(data => {
end_page = parseInt(data.end)
if (current_page === end_page){
document.getElementById('forward').classList.add("disabled")
document.getElementById('forward').classList.remove("waves-effect")
document.getElementById('last').classList.add("disabled")
document.getElementById('last').classList.remove("waves-effect")
} else {
document.getElementById('forward').classList.remove("disabled")
document.getElementById('forward').classList.add("waves-effect")
document.getElementById('last').classList.remove("disabled")
document.getElementById('last').classList.add("waves-effect")
};
console.log(data)
var table = document.getElementById("transaction_table")
while (table.rows.length > 0) {
table.deleteRow(0);
}
const header = table.createTHead();
const row = header.insertRow(0);
var header_id = row.insertCell();
header_id.classList.add('center')
header_id.classList.add('hide-on-med-and-down')
var header_stamp = row.insertCell();
header_stamp.classList.add('center')
var header_barcode = row.insertCell();
header_barcode.classList.add('center')
var header_name = row.insertCell();
header_name.classList.add('center')
header_name.classList.add('hide-on-med-and-down')
var header_type = row.insertCell();
header_type.classList.add('center')
header_type.classList.add('hide-on-small-only')
var header_qty = row.insertCell();
header_qty.classList.add('center')
var header_desc = row.insertCell();
header_desc.classList.add('center')
header_desc.classList.add('hide-on-med-and-down')
var header_user = row.insertCell();
header_user.classList.add('center')
header_user.classList.add('hide-on-med-and-down')
header_id.innerHTML = `<b>Database ID</b>`;
header_stamp.innerHTML = `<b>Timestamp</b>`;
header_barcode.innerHTML = `<b>Barcode</b>`;
header_name.innerHTML = `<b>Name</b>`;
header_type.innerHTML = `<b>Type</b>`;
header_qty.innerHTML = `<b>Qty</b>`;
header_desc.innerHTML = `<b>Description</b>`;
header_user.innerHTML = `<b>UserID</b>`;
let colorstate = 1;
data.transactions.forEach(transaction => {
console.log(transaction)
table.c
var row = table.insertRow();
var row_id = row.insertCell();
row_id.classList.add('center')
row_id.classList.add('hide-on-med-and-down')
var row_stamp = row.insertCell();
row_stamp.classList.add('center')
var row_barcode = row.insertCell();
row_barcode.classList.add('center')
var row_name = row.insertCell();
row_name.classList.add('hide-on-med-and-down')
row_name.classList.add('center')
var row_type = row.insertCell();
row_type.classList.add('center')
row_type.classList.add('hide-on-small-only')
var row_qty = row.insertCell();
row_qty.classList.add('center')
var row_desc = row.insertCell();
row_desc.classList.add('center')
row_desc.classList.add('hide-on-med-and-down')
var row_user = row.insertCell();
row_user.classList.add('center')
row_user.classList.add('hide-on-med-and-down')
row_id.innerHTML = transaction[0];
row_stamp.innerHTML = transaction[1];
row_barcode.innerHTML = transaction[3];
row_name.innerHTML = transaction[4];
row_type.innerHTML = transaction[5];
row_qty.innerHTML = transaction[6];
row_desc.innerHTML = transaction[7];
row_user.innerHTML = transaction[8];
if ((colorstate % 2) == 0){
row.classList.add('green')
row.classList.add('lighten-5')
}
colorstate++
});
document.getElementById("current_page").innerHTML = `${String(current_page)} / ${String(end_page)}`
});
};
document.getElementById('forward').addEventListener('click', async () =>{
if (!(document.getElementById("forward").classList.contains("disabled"))){
current_page++
await fetchTransactions();
};
});
document.getElementById('back').addEventListener('click', async () =>{
if (!(document.getElementById("back").classList.contains("disabled"))){
current_page--
await fetchTransactions();
}
});
document.getElementById('last').addEventListener('click', async () =>{
if(!(document.getElementById("last").classList.contains("disabled"))){
current_page = end_page
await fetchTransactions();
};
});
document.getElementById('first').addEventListener('click', async () =>{
if (!(document.getElementById("first").classList.contains("disabled"))){
current_page = 1
await fetchTransactions();
};
});
</script>
</html>

View File

@ -9,6 +9,18 @@ def group(id):
sites = config.sites_config()
return render_template("groups/group.html", id=id, current_site=session['selected_site'], sites=sites['sites'])
@app.route("/transactions/<id>")
def transactions(id):
sites = config.sites_config()
return render_template("items/transactions.html", id=id, current_site=session['selected_site'], sites=sites['sites'])
@app.route("/item/<id>")
def item(id):
sites = config.sites_config()
return render_template("items/item.html", id=id, current_site=session['selected_site'], sites=sites['sites'])
@app.route("/workshop")
def workshop():
sites = config.sites_config()