test
This commit is contained in:
parent
76c3f33b55
commit
e21fab65ea
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
143
api.py
143
api.py
@ -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', ""))
|
||||
|
||||
26
main.py
26
main.py
@ -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)
|
||||
|
||||
|
||||
|
||||
@ -444,3 +463,4 @@ if __name__ == "__main__":
|
||||
print(f"{k}: {v}")
|
||||
"""
|
||||
parse_csv(r"C:\\Users\\jadow\\Documents\\code\\postgresql python\\postgresql-python\\2024-10-02-Pantry.csv")
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"});
|
||||
};
|
||||
|
||||
@ -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;">
|
||||
|
||||
@ -53,64 +53,119 @@
|
||||
<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 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>{{item[2]}}</h3>
|
||||
<h5>Database ID: {{item[0]}}</h5>
|
||||
<h5>Barcode: {{item[1]}}</h5>
|
||||
<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>
|
||||
<div class="s12 m6" style="margin-right: 5px;">
|
||||
<label for="entry_type">Entry Type</label>
|
||||
<select id="entry_type" class="browser-default" >
|
||||
<select onchange="updateEntryType()" 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>
|
||||
<option value="single">Single</option>
|
||||
<option value="linked">Linked</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="s12 m6">
|
||||
<label for="item_type">Item Type</label>
|
||||
<select id="item_type" class="browser-default">
|
||||
<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>
|
||||
<!-- 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 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 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 id="tags_container" class="col s12 chips">
|
||||
<!-- This holds open for tags pills -->
|
||||
</div>
|
||||
<div class="col s12 p-3">
|
||||
<!-- 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 class="divider col s12" style="margin-top: 5px;"></div>
|
||||
|
||||
<div class="col s12">
|
||||
<div class="col s12" style="margin-top: 50px;">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<ul class="tabs tabs-fixed-width" id="info_tabs" style="background-color: white;">
|
||||
<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">
|
||||
<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>
|
||||
@ -140,6 +195,20 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
@ -151,25 +220,233 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="food_info" class="col s12">
|
||||
<div class="row" style="gap: 10px; padding-top: 10px;">
|
||||
<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">
|
||||
<!-- This holds all the nutrients tables -->
|
||||
<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>
|
||||
<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="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 id="web-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="row">
|
||||
@ -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)
|
||||
if (e[0].id == "food_groups_container"){
|
||||
food_groups.push(chipText)
|
||||
food_groups_changed = true;
|
||||
console.log(food_groups)
|
||||
}
|
||||
|
||||
function addIngrediant(e, chip){
|
||||
chipText = chip.textContent.replace('close', '').trim()
|
||||
console.log(chipText)
|
||||
};
|
||||
if (e[0].id == "ingrediants_container"){
|
||||
ingrediants.push(chipText)
|
||||
ingrediants_changed = true;
|
||||
console.log(ingrediants)
|
||||
}
|
||||
|
||||
function addTag(e, chip){
|
||||
chipText = chip.textContent.replace('close', '').trim()
|
||||
console.log(chipText)
|
||||
};
|
||||
if (e[0].id == "tags_container"){
|
||||
tags.push(chipText)
|
||||
tags_changed = true;
|
||||
console.log(tags)
|
||||
}
|
||||
|
||||
function deleteFoodGroup(e, chip){
|
||||
chipText = chip.textContent.replace('close', '').trim()
|
||||
food_groups = food_groups.filter(chip => chip !== chipText);
|
||||
};
|
||||
};
|
||||
|
||||
function deleteIngrediant(e, chip){
|
||||
function deleteChip(e, chip){
|
||||
chipText = chip.textContent.replace('close', '').trim()
|
||||
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);
|
||||
}
|
||||
|
||||
function deleteTag(e, chip){
|
||||
chipText = chip.textContent.replace('close', '').trim()
|
||||
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>
|
||||
255
templates/items/transactions.html
Normal file
255
templates/items/transactions.html
Normal 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>
|
||||
12
webserver.py
12
webserver.py
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user