Mass Update
This commit is contained in:
parent
05a6fbddb6
commit
f1cc51f378
Binary file not shown.
Binary file not shown.
BIN
__pycache__/external_devices.cpython-312.pyc
Normal file
BIN
__pycache__/external_devices.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
456
api.py
456
api.py
@ -1,6 +1,7 @@
|
|||||||
from flask import Blueprint, request, render_template, redirect, session, url_for, send_file, jsonify, Response
|
from flask import Blueprint, request, render_template, redirect, session, url_for, send_file, jsonify, Response
|
||||||
import psycopg2, math, json, datetime, main, copy
|
import psycopg2, math, json, datetime, main, copy, requests
|
||||||
from config import config, sites_config
|
from config import config, sites_config
|
||||||
|
from main import unfoldCostLayers
|
||||||
|
|
||||||
database_api= Blueprint('database_api', __name__)
|
database_api= Blueprint('database_api', __name__)
|
||||||
|
|
||||||
@ -126,6 +127,32 @@ def paginate_groups():
|
|||||||
|
|
||||||
return jsonify({'groups': new_groups, "end": math.ceil(count/limit)})
|
return jsonify({'groups': new_groups, "end": math.ceil(count/limit)})
|
||||||
|
|
||||||
|
@database_api.route("/getReceipts")
|
||||||
|
def pagninate_receipts():
|
||||||
|
page = int(request.args.get('page', 1))
|
||||||
|
limit = int(request.args.get('limit', 10))
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
offset = (page - 1) * limit
|
||||||
|
|
||||||
|
receipts = []
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
database_config = config()
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_receipts LIMIT {limit} OFFSET {offset};"
|
||||||
|
count = f"SELECT COUNT(*) FROM {site_name}_receipts;"
|
||||||
|
cur.execute(sql)
|
||||||
|
receipts = cur.fetchall()
|
||||||
|
cur.execute(count)
|
||||||
|
count = cur.fetchone()[0]
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
return jsonify({'receipts': receipts, "end": math.ceil(count/limit)})
|
||||||
|
|
||||||
@database_api.route("/getItems")
|
@database_api.route("/getItems")
|
||||||
def pagninate_items():
|
def pagninate_items():
|
||||||
page = int(request.args.get('page', 1))
|
page = int(request.args.get('page', 1))
|
||||||
@ -184,6 +211,22 @@ def pagninate_transactions():
|
|||||||
|
|
||||||
return jsonify({'transactions': transactions, "end": math.ceil(count/limit)})
|
return jsonify({'transactions': transactions, "end": math.ceil(count/limit)})
|
||||||
|
|
||||||
|
@database_api.route("/getVendors")
|
||||||
|
def get_vendors():
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
vendors = []
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_vendors;"
|
||||||
|
cur.execute(sql)
|
||||||
|
vendors = cur.fetchall()
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
return jsonify(vendors=vendors)
|
||||||
|
|
||||||
@database_api.route("/getTransaction")
|
@database_api.route("/getTransaction")
|
||||||
def get_transaction():
|
def get_transaction():
|
||||||
id = int(request.args.get('id', 1))
|
id = int(request.args.get('id', 1))
|
||||||
@ -200,7 +243,6 @@ def get_transaction():
|
|||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
|
|
||||||
print(transaction)
|
|
||||||
return jsonify(transaction=transaction)
|
return jsonify(transaction=transaction)
|
||||||
|
|
||||||
@database_api.route("/getLocations")
|
@database_api.route("/getLocations")
|
||||||
@ -222,7 +264,6 @@ def get_locations():
|
|||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
|
|
||||||
print(locations)
|
|
||||||
return jsonify(locations=locations)
|
return jsonify(locations=locations)
|
||||||
|
|
||||||
@database_api.route("/getZones")
|
@database_api.route("/getZones")
|
||||||
@ -241,13 +282,243 @@ def get_zones():
|
|||||||
print(zones)
|
print(zones)
|
||||||
return jsonify(zones=zones)
|
return jsonify(zones=zones)
|
||||||
|
|
||||||
|
def checkReceiptState(index, site):
|
||||||
|
database_config = config()
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT id, status FROM {site}_receipt_items WHERE receipt_id=%s;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
items = cur.fetchall()
|
||||||
|
number_unresolved = 0
|
||||||
|
for item in items:
|
||||||
|
if item[1] == "Unresolved":
|
||||||
|
number_unresolved += 1
|
||||||
|
|
||||||
|
if number_unresolved == 0:
|
||||||
|
sql = f"UPDATE {site}_receipts SET receipt_status = 'Resolved' WHERE id=%s;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
@database_api.route("/deleteReceiptItem", methods=["POST"])
|
||||||
|
def deleteReceiptItem():
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
index = request.json['index']
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"DELETE FROM {site_name}_receipt_items WHERE id=%s;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
@database_api.route("/saveReceipt", methods=["POST"])
|
||||||
|
def saveReceipt():
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
receipt_index = request.json['receipt_index']
|
||||||
|
vendor_index = request.json['vendor_index']
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"UPDATE {site_name}_receipts SET vendor_id=%s WHERE id=%s;"
|
||||||
|
cur.execute(sql, (vendor_index, receipt_index))
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
@database_api.route("/saveReceiptItem", methods=["POST"])
|
||||||
|
def saveReceiptItem():
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
index = request.json['index']
|
||||||
|
cost= request.json['cost']
|
||||||
|
qty = request.json['qty']
|
||||||
|
barcode = request.json['barcode']
|
||||||
|
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_receipt_items WHERE id=%s;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
receipt_item = list(cur.fetchone())
|
||||||
|
_new_type = receipt_item[1]
|
||||||
|
_new_name = receipt_item[4]
|
||||||
|
_new_item = receipt_item[6]
|
||||||
|
_new_cost = cost
|
||||||
|
if barcode != receipt_item[3]:
|
||||||
|
# grab the new barcode data...
|
||||||
|
sql = f"SELECT {site_name}_items.barcode FROM {site_name}_itemlinks LEFT JOIN {site_name}_items ON {site_name}_itemlinks.link = {site_name}_items.id WHERE {site_name}_itemlinks.barcode = %s;"
|
||||||
|
cur.execute(sql, (barcode, ))
|
||||||
|
x = cur.fetchone()
|
||||||
|
if x != None:
|
||||||
|
barcode = x[0]
|
||||||
|
# 078742013718
|
||||||
|
with open(f"sites/{site_name}/sql/unique/select_item_all_barcode.sql", "r+") as file:
|
||||||
|
sql = file.read()
|
||||||
|
cur.execute(sql, (barcode, ))
|
||||||
|
item = list(cur.fetchone())
|
||||||
|
if not item:
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
#TODO: implement the api code, this will be a big function in external that will do all the parsing and stuff in the system.
|
||||||
|
print(item)
|
||||||
|
_new_type = 'Pantry'
|
||||||
|
_new_name = item[2]
|
||||||
|
_new_cost = item[28]
|
||||||
|
_new_item = item
|
||||||
|
|
||||||
|
|
||||||
|
_new_item[28] = _new_cost
|
||||||
|
sql = f"UPDATE {site_name}_receipt_items SET type = %s, barcode = %s, name = %s, qty = %s, data = %s WHERE id=%s;"
|
||||||
|
cur.execute(sql, (_new_type, barcode, _new_name, qty, json.dumps(_new_item), index))
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
@database_api.route("/voidReceiptItem", methods=["POST"])
|
||||||
|
def voidReceiptItem():
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
index = request.json['index']
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"UPDATE {site_name}_receipt_items SET status = 'Voided' WHERE id=%s RETURNING receipt_id;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
receipt_id = cur.fetchone()[0]
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
checkReceiptState(receipt_id, site_name)
|
||||||
|
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
@database_api.route("/resolveReceiptItem", methods=["POST"])
|
||||||
|
def resolveReceiptItem():
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
index = request.json['index']
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_receipt_items WHERE id=%s;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
receipt_item = cur.fetchone()
|
||||||
|
sql = f"SELECT receipt_id FROM {site_name}_receipts WHERE id=%s;"
|
||||||
|
cur.execute(sql, (receipt_item[2], ))
|
||||||
|
receipt_id = cur.fetchone()[0]
|
||||||
|
payload = [
|
||||||
|
datetime.datetime.now(),
|
||||||
|
receipt_item[6][8],
|
||||||
|
receipt_item[3],
|
||||||
|
receipt_item[4],
|
||||||
|
"Receipt",
|
||||||
|
receipt_item[5],
|
||||||
|
f"{receipt_id}",
|
||||||
|
1,
|
||||||
|
json.dumps({'location': receipt_item[6][15], 'cost': receipt_item[6][28]})
|
||||||
|
]
|
||||||
|
|
||||||
|
print(payload)
|
||||||
|
main.addTransaction(
|
||||||
|
conn=conn,
|
||||||
|
site_name=site_name,
|
||||||
|
payload=payload,
|
||||||
|
location=receipt_item[6][15],
|
||||||
|
logistics_info_id=receipt_item[6][8],
|
||||||
|
item_id=receipt_item[6][0],
|
||||||
|
qty=receipt_item[5],
|
||||||
|
cost=receipt_item[6][28]
|
||||||
|
)
|
||||||
|
|
||||||
|
sql = f"UPDATE {site_name}_receipt_items SET status = 'Resolved' WHERE id=%s RETURNING receipt_id;"
|
||||||
|
cur.execute(sql, (index, ))
|
||||||
|
receipt_id = cur.fetchone()[0]
|
||||||
|
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
checkReceiptState(receipt_id, site_name)
|
||||||
|
|
||||||
|
return jsonify({})
|
||||||
|
|
||||||
|
@database_api.route("/getReceiptItem")
|
||||||
|
def get_receipt_item():
|
||||||
|
id = int(request.args.get('index', 1))
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
receipt_item = []
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_receipt_items WHERE id=%s;"
|
||||||
|
cur.execute(sql, (id, ))
|
||||||
|
receipt_item = list(cur.fetchone())
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
return jsonify({"receipt_item": receipt_item})
|
||||||
|
|
||||||
|
@database_api.route("/getReceipt")
|
||||||
|
def get_receipt():
|
||||||
|
id = int(request.args.get('id', 1))
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
receipt = []
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_receipts LEFT JOIN {site_name}_vendors ON {site_name}_receipts.vendor_id = {site_name}_vendors.id WHERE {site_name}_receipts.id=%s;"
|
||||||
|
cur.execute(sql, (id, ))
|
||||||
|
receipt = list(cur.fetchone())
|
||||||
|
sql = f"SELECT * FROM {site_name}_receipt_items WHERE receipt_id=%s;"
|
||||||
|
cur.execute(sql, (id, ))
|
||||||
|
receipt_items = cur.fetchall()
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
return jsonify({"receipt": receipt, "receipt_items": receipt_items})
|
||||||
|
|
||||||
|
|
||||||
|
@database_api.route("/getLinkedItem")
|
||||||
|
def get_linked_item():
|
||||||
|
id = int(request.args.get('id', 1))
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
sql = f"SELECT * FROM {site_name}_itemlinks WHERE id=%s;"
|
||||||
|
cur.execute(sql, (id, ))
|
||||||
|
linked_item = cur.fetchone()
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
return jsonify(linked_item=linked_item)
|
||||||
|
|
||||||
@database_api.route("/getItem")
|
@database_api.route("/getItem")
|
||||||
def get_item():
|
def get_item():
|
||||||
id = int(request.args.get('id', 1))
|
id = int(request.args.get('id', 1))
|
||||||
database_config = config()
|
database_config = config()
|
||||||
site_name = session['selected_site']
|
site_name = session['selected_site']
|
||||||
sites = sites_config()
|
|
||||||
|
|
||||||
|
|
||||||
item = []
|
item = []
|
||||||
with psycopg2.connect(**database_config) as conn:
|
with psycopg2.connect(**database_config) as conn:
|
||||||
@ -263,11 +534,25 @@ def get_item():
|
|||||||
SQL_shopping_lists = f"SELECT * FROM {site_name}_shopping_lists WHERE pantry_items @> ARRAY[%s];"
|
SQL_shopping_lists = f"SELECT * FROM {site_name}_shopping_lists WHERE pantry_items @> ARRAY[%s];"
|
||||||
cur.execute(SQL_shopping_lists, (item[0], ))
|
cur.execute(SQL_shopping_lists, (item[0], ))
|
||||||
item[23] = list(cur.fetchall())
|
item[23] = list(cur.fetchall())
|
||||||
print(item)
|
sql_location_data = f"SELECT {site_name}_locations.uuid, {site_name}_item_locations.quantity_on_hand, {site_name}_item_locations.cost_layers FROM {site_name}_item_locations LEFT JOIN {site_name}_locations ON {site_name}_item_locations.location_id = {site_name}_locations.id WHERE part_id=%s;"
|
||||||
|
cur.execute(sql_location_data, (item[0],))
|
||||||
|
# losing cost layers here by uniforming to the javascript, change to take a list?
|
||||||
|
columns = [desc[0] for desc in cur.description]
|
||||||
|
x = cur.fetchall()
|
||||||
|
qty_on_hand = sum([location[1] for location in x])
|
||||||
|
y = {location[0]: location[1] for location in x}
|
||||||
|
item[18] = y
|
||||||
|
item[19] = qty_on_hand
|
||||||
|
sql = f"SELECT * FROM {site_name}_itemlinks WHERE link=%s;"
|
||||||
|
cur.execute(sql, (item[0], ))
|
||||||
|
linked_items = cur.fetchall()
|
||||||
|
print(linked_items)
|
||||||
|
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
|
|
||||||
return jsonify(item=item)
|
return jsonify(item=item, linked_items=linked_items)
|
||||||
|
|
||||||
@database_api.route("/addItem")
|
@database_api.route("/addItem")
|
||||||
def addItem():
|
def addItem():
|
||||||
@ -303,6 +588,8 @@ def addItem():
|
|||||||
return jsonify({'state': str(food_info_id)})
|
return jsonify({'state': str(food_info_id)})
|
||||||
|
|
||||||
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 *;"
|
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 *;"
|
||||||
|
sqlthree = f"INSERT INTO {site_name}_item_locations(part_id, location_id, quantity_on_hand, cost_layers) VALUES (%s, %s, %s, %s);"
|
||||||
|
|
||||||
row = None
|
row = None
|
||||||
try:
|
try:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
@ -310,6 +597,9 @@ def addItem():
|
|||||||
rows = cur.fetchone()
|
rows = cur.fetchone()
|
||||||
if rows:
|
if rows:
|
||||||
row = rows[:]
|
row = rows[:]
|
||||||
|
cur.execute(f"SELECT id FROM {site_name}_locations WHERE uuid=%s;", (uuid, ))
|
||||||
|
location_id = cur.fetchone()
|
||||||
|
cur.execute(sqlthree, (row[0], location_id, 0.0, main.lst2pgarr([])))
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
@ -341,20 +631,82 @@ def addItem():
|
|||||||
payload=payload,
|
payload=payload,
|
||||||
location=location,
|
location=location,
|
||||||
logistics_info_id=logistics_info_id,
|
logistics_info_id=logistics_info_id,
|
||||||
barcode=barcode,
|
item_id=row[0],
|
||||||
qty=0.0)
|
qty=0.0,
|
||||||
|
cost=0.0)
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
return jsonify({'state': str(error)})
|
return jsonify({'state': str(error)})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return jsonify({'state': "SUCCESS"})
|
return jsonify({'state': "SUCCESS"})
|
||||||
|
|
||||||
|
@database_api.route("/transact", methods=['POST'])
|
||||||
|
def addTransaction():
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
if "site_name" in request.get_json().keys():
|
||||||
|
site_name = request.get_json()["site_name"]
|
||||||
|
print("passed")
|
||||||
|
elif "selected_site" in session.keys():
|
||||||
|
site_name = session['selected_site']
|
||||||
|
print(session)
|
||||||
|
else:
|
||||||
|
return jsonify({"message": "Failed", "error": "No site selected or sent along with request!"})
|
||||||
|
|
||||||
|
logistics_info_id = request.get_json()['logistics_info_id']
|
||||||
|
barcode = request.get_json()['barcode']
|
||||||
|
name = request.get_json()['name']
|
||||||
|
location = request.get_json()['location']
|
||||||
|
qty = request.get_json()['qty']
|
||||||
|
trans_type = request.get_json()['trans_type']
|
||||||
|
trans_cost = request.get_json()['trans_cost']
|
||||||
|
|
||||||
|
database_config = config()
|
||||||
|
|
||||||
|
actual_qty = qty
|
||||||
|
if trans_type == "Adjust Out":
|
||||||
|
actual_qty = -qty
|
||||||
|
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"SELECT id FROM {site_name}_items WHERE barcode=%s;", (barcode,))
|
||||||
|
item_id = cur.fetchone()
|
||||||
|
payload = [
|
||||||
|
datetime.datetime.now(),
|
||||||
|
logistics_info_id,
|
||||||
|
barcode,
|
||||||
|
name,
|
||||||
|
trans_type,
|
||||||
|
qty,
|
||||||
|
"",
|
||||||
|
1,
|
||||||
|
json.dumps({'location': location, 'cost': trans_cost})
|
||||||
|
]
|
||||||
|
|
||||||
|
print(payload)
|
||||||
|
main.addTransaction(
|
||||||
|
conn=conn,
|
||||||
|
site_name=site_name,
|
||||||
|
payload=payload,
|
||||||
|
location=location,
|
||||||
|
logistics_info_id=logistics_info_id,
|
||||||
|
item_id=item_id,
|
||||||
|
qty=actual_qty,
|
||||||
|
cost=trans_cost
|
||||||
|
)
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({'state': str(error)})
|
||||||
|
print("SUCCESS")
|
||||||
|
return jsonify({'state': str("SUCCESS")})
|
||||||
|
print("SUCCESS")
|
||||||
|
return jsonify({'state': str("FAILED")})
|
||||||
|
|
||||||
@database_api.route("/updateItem", methods=['POST'])
|
@database_api.route("/updateItem", methods=['POST'])
|
||||||
def updateItem():
|
def updateItem():
|
||||||
def transformValues(values):
|
def transformValues(values):
|
||||||
@ -443,8 +795,8 @@ def updateItem():
|
|||||||
save_data[f"{k}_old"] = v;
|
save_data[f"{k}_old"] = v;
|
||||||
cur.execute(sql, values)
|
cur.execute(sql, values)
|
||||||
|
|
||||||
cur.execute(f"SELECT {site_name}_items.barcode, {site_name}_items.item_name, {site_name}_logistics_info.primary_location FROM {site_name}_items LEFT JOIN {site_name}_logistics_info ON {site_name}_items.logistics_info_id = {site_name}_logistics_info.id WHERE {site_name}_items.id={item_id};")
|
cur.execute(f"SELECT {site_name}_items.id, {site_name}_items.barcode, {site_name}_items.item_name, {site_name}_logistics_info.primary_location FROM {site_name}_items LEFT JOIN {site_name}_logistics_info ON {site_name}_items.logistics_info_id = {site_name}_logistics_info.id WHERE {site_name}_items.id={item_id};")
|
||||||
barcode, name, primary_location = cur.fetchone()
|
item_id, barcode, name, primary_location = cur.fetchone()
|
||||||
payload = [
|
payload = [
|
||||||
datetime.datetime.now(),
|
datetime.datetime.now(),
|
||||||
logistics_info_id,
|
logistics_info_id,
|
||||||
@ -463,8 +815,9 @@ def updateItem():
|
|||||||
payload=payload,
|
payload=payload,
|
||||||
location=primary_location,
|
location=primary_location,
|
||||||
logistics_info_id=logistics_info_id,
|
logistics_info_id=logistics_info_id,
|
||||||
barcode=barcode,
|
item_id=item_id,
|
||||||
qty=0.0
|
qty=0.0,
|
||||||
|
cost=0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
@ -475,6 +828,73 @@ def updateItem():
|
|||||||
|
|
||||||
return jsonify({"status": "FAILED"})
|
return jsonify({"status": "FAILED"})
|
||||||
|
|
||||||
|
@database_api.route("/linkItem", methods=["POST"])
|
||||||
|
def linkItemToItem():
|
||||||
|
if request.method == "POST":
|
||||||
|
database_config = config()
|
||||||
|
site_name = session['selected_site']
|
||||||
|
master_index = request.json['master_index']
|
||||||
|
sub_index = request.json['sub_index']
|
||||||
|
print(master_index, sub_index)
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
with open(f"sites/{site_name}/sql/unique/select_item_all.sql", "r+") as file:
|
||||||
|
sql = file.read()
|
||||||
|
cur.execute(sql, (sub_index, ))
|
||||||
|
sub_item = cur.fetchone()
|
||||||
|
|
||||||
|
# grab all the location data and then get the qty on hand
|
||||||
|
sql_location_data = f"SELECT {site_name}_locations.uuid, {site_name}_item_locations.quantity_on_hand, {site_name}_item_locations.cost_layers FROM {site_name}_item_locations LEFT JOIN {site_name}_locations ON {site_name}_item_locations.location_id = {site_name}_locations.id WHERE part_id=%s;"
|
||||||
|
cur.execute(sql_location_data, (sub_item[0],))
|
||||||
|
x = cur.fetchall()
|
||||||
|
qty_on_hand = sum([location[1] for location in x])
|
||||||
|
|
||||||
|
# Delete sub_item from database and cascade through tables
|
||||||
|
sql = f"DELETE FROM {site_name}_items WHERE id=%s;"
|
||||||
|
cur.execute(sql, (sub_index,))
|
||||||
|
|
||||||
|
# insert sub_item into the links table
|
||||||
|
sql = f"INSERT INTO {site_name}_itemlinks (barcode, link, data, conv_factor) VALUES (%s, %s, %s, %s);"
|
||||||
|
cur.execute(sql, (sub_item[1], master_index, json.dumps(sub_item), 1.0))
|
||||||
|
|
||||||
|
# need to adjust the qty on hand into the master items
|
||||||
|
|
||||||
|
with open(f"sites/{site_name}/sql/unique/select_item_all.sql", "r+") as file:
|
||||||
|
sql = file.read()
|
||||||
|
|
||||||
|
cur.execute(sql, (master_index,))
|
||||||
|
master_item = cur.fetchone()
|
||||||
|
payload = [
|
||||||
|
datetime.datetime.now(),
|
||||||
|
master_item[8],
|
||||||
|
master_item[1],
|
||||||
|
master_item[2],
|
||||||
|
"Adjust In",
|
||||||
|
qty_on_hand,
|
||||||
|
f"COVERSION FROM {sub_item[1]}",
|
||||||
|
1,
|
||||||
|
json.dumps({'location': master_item[15], 'cost': sub_item[28]*qty_on_hand})
|
||||||
|
]
|
||||||
|
|
||||||
|
print(payload)
|
||||||
|
main.addTransaction(
|
||||||
|
conn=conn,
|
||||||
|
site_name=site_name,
|
||||||
|
payload=payload,
|
||||||
|
location=master_item[15],
|
||||||
|
logistics_info_id=master_item[8],
|
||||||
|
item_id=master_item[0],
|
||||||
|
qty=qty_on_hand,
|
||||||
|
cost=sub_item[28]*qty_on_hand
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
|
||||||
|
return jsonify({})
|
||||||
@database_api.route("/addGroup")
|
@database_api.route("/addGroup")
|
||||||
def addGroup():
|
def addGroup():
|
||||||
name = str(request.args.get('name', ""))
|
name = str(request.args.get('name', ""))
|
||||||
@ -641,7 +1061,7 @@ def paginate_lists():
|
|||||||
list_length = len(custom_items)
|
list_length = len(custom_items)
|
||||||
|
|
||||||
if shopping_list[10] == 'calculated':
|
if shopping_list[10] == 'calculated':
|
||||||
item_sql = f"SELECT COUNT(*) FROM {site_name}_items LEFT JOIN {site_name}_logistics_info ON {site_name}_items.logistics_info_id = {site_name}_logistics_info.id LEFT JOIN {site_name}n_item_info ON {site_name}_items.item_info_id = {site_name}_item_info.id LEFT JOIN {site_name}_food_info ON {site_name}_items.food_info_id = {site_name}_food_info.id WHERE {site_name}_logistics_info.quantity_on_hand < {site_name}_item_info.safety_stock AND shopping_lists @> ARRAY[%s];"
|
item_sql = f"SELECT COUNT(*) FROM {site_name}_items LEFT JOIN {site_name}_logistics_info ON {site_name}_items.logistics_info_id = {site_name}_logistics_info.id LEFT JOIN {site_name}_item_info ON {site_name}_items.item_info_id = {site_name}_item_info.id LEFT JOIN {site_name}_food_info ON {site_name}_items.food_info_id = {site_name}_food_info.id WHERE {site_name}_logistics_info.quantity_on_hand < {site_name}_item_info.safety_stock AND shopping_lists @> ARRAY[%s];"
|
||||||
cur.execute(item_sql, (shopping_list[0], ))
|
cur.execute(item_sql, (shopping_list[0], ))
|
||||||
list_length += cur.fetchone()[0]
|
list_length += cur.fetchone()[0]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -6,5 +6,5 @@ password = test
|
|||||||
port = 5432
|
port = 5432
|
||||||
|
|
||||||
[manage]
|
[manage]
|
||||||
sites = test,test2,main
|
sites = ,test,main,Backpack
|
||||||
|
|
||||||
|
|||||||
232
external_devices.py
Normal file
232
external_devices.py
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
from flask import Blueprint, request, render_template, redirect, session, url_for, send_file, jsonify, Response
|
||||||
|
import psycopg2, math, json, datetime, main, copy, openfoodfacts
|
||||||
|
from config import config, sites_config
|
||||||
|
from main import unfoldCostLayers
|
||||||
|
|
||||||
|
external_api= Blueprint('external_api', __name__)
|
||||||
|
|
||||||
|
open_food_api = openfoodfacts.API(user_agent="MyAwesomeApp/1.0")
|
||||||
|
|
||||||
|
open_food_enabled = False
|
||||||
|
|
||||||
|
|
||||||
|
def parseOpenFoodsData(data: dict):
|
||||||
|
print(data)
|
||||||
|
x = [
|
||||||
|
("brands_tags", list, []), # process into items.tags
|
||||||
|
("categories_tags", list, []), # process into items.tags
|
||||||
|
("countries_tags", list, []), # process into items.tags
|
||||||
|
("labels_hierarchy", list, []), # process into items.tags
|
||||||
|
("ingredients_text_en", str, ""), # process into a list of food_info.ingrediants
|
||||||
|
("nutriments", dict, {}), # process into food_info.nutrients
|
||||||
|
("product_name", str, ""), # #process into items.item_name
|
||||||
|
("serving_size", str, ""), # add to nutriments
|
||||||
|
("code", str, "") # process into items.barcode
|
||||||
|
]
|
||||||
|
|
||||||
|
dummy = {}
|
||||||
|
keys = data.keys()
|
||||||
|
for key in x:
|
||||||
|
if key[0] in keys and isinstance(data[key[0]], key[1]):
|
||||||
|
dummy[key[0]] = data[key[0]]
|
||||||
|
else:
|
||||||
|
dummy[key[0]] = key[2]
|
||||||
|
|
||||||
|
tags = dummy["brands_tags"] + dummy["categories_tags"] + dummy["countries_tags"] + dummy["labels_hierarchy"]
|
||||||
|
ingredients = str(dummy["ingredients_text_en"]).split(", ")
|
||||||
|
nutriments = dummy["nutriments"]
|
||||||
|
nutriments["serving_size"] = dummy["serving_size"]
|
||||||
|
|
||||||
|
payload = copy.deepcopy(main.payload_food_item)
|
||||||
|
payload["tags"] = tags
|
||||||
|
payload["product_name"] = dummy["product_name"]
|
||||||
|
payload["food_info"]["ingrediants"] = ingredients
|
||||||
|
payload["food_info"]["nutrients"] = nutriments
|
||||||
|
|
||||||
|
print(payload)
|
||||||
|
|
||||||
|
|
||||||
|
@external_api.route("/api/getLink/<site>/<barcode>")
|
||||||
|
def get_linked_item(site, barcode):
|
||||||
|
database_config = config()
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"SELECT * FROM {site}_itemlinks WHERE barcode=%s;", (barcode, ))
|
||||||
|
item = cur.fetchone()
|
||||||
|
if item:
|
||||||
|
return jsonify({"item": item}), 200
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({'state': str(error)}), 500
|
||||||
|
return jsonify({"item": []}), 500
|
||||||
|
|
||||||
|
@external_api.route("/api/getItem/<site>/<barcode>")
|
||||||
|
def get_item(site, barcode):
|
||||||
|
database_config = config()
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
with open(f"sites/{site}/sql/unique/select_item_all_barcode.sql", "r+") as file:
|
||||||
|
sql = file.read()
|
||||||
|
cur.execute(sql, (barcode, ))
|
||||||
|
item = cur.fetchone()
|
||||||
|
if item:
|
||||||
|
return jsonify({"item": item}), 200
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({'state': str(error)}), 500
|
||||||
|
return jsonify({"item": []}), 500
|
||||||
|
|
||||||
|
@external_api.route("/api/getOpenFacts/<site>/<barcode>")
|
||||||
|
def get_open_facts(site, barcode):
|
||||||
|
if open_food_enabled:
|
||||||
|
data = open_food_api.product.get(barcode)
|
||||||
|
if data != None:
|
||||||
|
return jsonify({"item": data}), 500
|
||||||
|
return jsonify({"item": []}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@external_api.route("/api/addTransaction", methods=['POST'])
|
||||||
|
def add_transaction():
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
print(request.get_json())
|
||||||
|
site_name = request.get_json()["site_name"]
|
||||||
|
logistics_info_id = request.get_json()['logistics_info_id']
|
||||||
|
barcode = request.get_json()['barcode']
|
||||||
|
name = request.get_json()['name']
|
||||||
|
location = request.get_json()['location']
|
||||||
|
qty = float(request.get_json()['qty'])
|
||||||
|
trans_type = request.get_json()['trans_type']
|
||||||
|
trans_cost = request.get_json()['trans_cost']
|
||||||
|
|
||||||
|
database_config = config()
|
||||||
|
|
||||||
|
actual_qty = qty
|
||||||
|
if trans_type == "Adjust Out":
|
||||||
|
actual_qty = -qty
|
||||||
|
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"SELECT id FROM {site_name}_items WHERE barcode=%s;", (barcode,))
|
||||||
|
item_id = cur.fetchone()
|
||||||
|
payload = [
|
||||||
|
datetime.datetime.now(),
|
||||||
|
logistics_info_id,
|
||||||
|
barcode,
|
||||||
|
name,
|
||||||
|
trans_type,
|
||||||
|
qty,
|
||||||
|
"",
|
||||||
|
1,
|
||||||
|
json.dumps({'location': location, 'cost': trans_cost})
|
||||||
|
]
|
||||||
|
|
||||||
|
print(payload)
|
||||||
|
main.addTransaction(
|
||||||
|
conn=conn,
|
||||||
|
site_name=site_name,
|
||||||
|
payload=payload,
|
||||||
|
location=location,
|
||||||
|
logistics_info_id=logistics_info_id,
|
||||||
|
item_id=item_id,
|
||||||
|
qty=actual_qty,
|
||||||
|
cost=trans_cost
|
||||||
|
)
|
||||||
|
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({'state': str(error)})
|
||||||
|
print("SUCCESS")
|
||||||
|
return jsonify({'state': str("SUCCESS")})
|
||||||
|
print("SUCCESS")
|
||||||
|
return jsonify({'state': str("FAILED")})
|
||||||
|
|
||||||
|
|
||||||
|
@external_api.route("/api/requestReceiptId/<site>")
|
||||||
|
def request_receipt_id(site):
|
||||||
|
"""gets the next id for receipts_id, currently returns a 8 digit number
|
||||||
|
|
||||||
|
Args:
|
||||||
|
site (str): site to get the next id for
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json: receipt_id, message, error keys
|
||||||
|
"""
|
||||||
|
database_config = config()
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"SELECT receipt_id FROM {site}_receipts ORDER BY id DESC LIMIT 1;")
|
||||||
|
next_receipt_id = cur.fetchone()
|
||||||
|
print(next_receipt_id)
|
||||||
|
if next_receipt_id == None:
|
||||||
|
next_receipt_id = "00000001"
|
||||||
|
else:
|
||||||
|
next_receipt_id = next_receipt_id[0]
|
||||||
|
next_receipt_id = int(next_receipt_id.split("-")[1]) + 1
|
||||||
|
y = str(next_receipt_id)
|
||||||
|
len_str = len(y)
|
||||||
|
x = "".join(["0" for _ in range(8 - len_str)])
|
||||||
|
next_receipt_id = x + y
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({"message": "Failed", "error": str(error)})
|
||||||
|
return jsonify({"receipt_id": next_receipt_id, "message": "Success", "error": "None"}), 200
|
||||||
|
|
||||||
|
@external_api.route("/api/addReceipt", methods=["POST"])
|
||||||
|
def add_receipt():
|
||||||
|
"""Receives a payload and adds the receipt to the system for <site>
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
receipt_id: str
|
||||||
|
receipt_status: str
|
||||||
|
date_submitted: timestamp
|
||||||
|
submitted_by: INT
|
||||||
|
vendor_id: INT
|
||||||
|
files: dict
|
||||||
|
items: list = (tuples)
|
||||||
|
(type, 0, barcode, name, qty, data, status),
|
||||||
|
site_name: str
|
||||||
|
}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Success: dict with "error", "message" keys
|
||||||
|
"""
|
||||||
|
if request.method == "POST":
|
||||||
|
site_name = request.get_json()["site_name"]
|
||||||
|
receipt_id = request.get_json()["receipt_id"]
|
||||||
|
receipt_status = request.get_json()["receipt_status"]
|
||||||
|
date_submitted = request.get_json()['date_submitted']
|
||||||
|
submitted_by = request.get_json()["submitted_by"]
|
||||||
|
vendor_id = request.get_json()["vendor_id"]
|
||||||
|
files = request.get_json()["files"]
|
||||||
|
items = request.get_json()["items"]
|
||||||
|
payload = (receipt_id, receipt_status, date_submitted, submitted_by, vendor_id, json.dumps(files))
|
||||||
|
database_config = config()
|
||||||
|
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
insert_receipt = f"INSERT INTO {site_name}_receipts (receipt_id, receipt_status, date_submitted, submitted_by, vendor_id, files) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id;"
|
||||||
|
cur.execute(insert_receipt, payload)
|
||||||
|
row_id = cur.fetchone()[0]
|
||||||
|
print(row_id)
|
||||||
|
insert_item = f"INSERT INTO {site_name}_receipt_items (type, receipt_id, barcode, name, qty, data, status) VALUES (%s, %s, %s, %s, %s, %s, %s);"
|
||||||
|
for item in items:
|
||||||
|
item = list(item)
|
||||||
|
item[1] = row_id
|
||||||
|
item[5] = json.dumps(item[5])
|
||||||
|
cur.execute(insert_item, item)
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return jsonify({"message": "Failed", "error": str(error)})
|
||||||
|
return jsonify({"message": "Success", "error": "None"})
|
||||||
|
return jsonify({"message": "Failed", "error": "Must be a post method!"})
|
||||||
118
main.py
118
main.py
@ -1,11 +1,15 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import psycopg2
|
import psycopg2
|
||||||
from config import config
|
from config import config
|
||||||
import json, datetime, copy, csv
|
import json, datetime, copy, csv, ast
|
||||||
|
|
||||||
def lst2pgarr(alist):
|
def lst2pgarr(alist):
|
||||||
return '{' + ','.join(alist) + '}'
|
return '{' + ','.join(alist) + '}'
|
||||||
|
|
||||||
|
def unfoldCostLayers(cost_layers: str):
|
||||||
|
cost_layers:list = [ast.literal_eval(item) for item in ast.literal_eval(cost_layers.replace('{', '[').replace('}', ']'))]
|
||||||
|
return cost_layers
|
||||||
|
|
||||||
def update_item_primary(site_name, barcode, new_primary: str):
|
def update_item_primary(site_name, barcode, new_primary: str):
|
||||||
zone, location = new_primary.split("@")
|
zone, location = new_primary.split("@")
|
||||||
|
|
||||||
@ -182,11 +186,54 @@ def setLogisticsDataTransaction(conn, site_name, location, logistics_info_id, qt
|
|||||||
quantity_on_hand = float(quantity_on_hand + qty)
|
quantity_on_hand = float(quantity_on_hand + qty)
|
||||||
cur.execute(sql, (quantity_on_hand, json.dumps(location_data), logistics_info_id))
|
cur.execute(sql, (quantity_on_hand, json.dumps(location_data), logistics_info_id))
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
conn.rollback()
|
|
||||||
return error
|
return error
|
||||||
return "success"
|
return "success"
|
||||||
|
|
||||||
def setLocationData(conn, site_name, location, barcode, qty):
|
|
||||||
|
def handleNegativeQuantityOnHand(qty, cost_layers):
|
||||||
|
cost_layers = [ast.literal_eval(item) for item in ast.literal_eval(cost_layers.replace('{', '[').replace('}', ']'))]
|
||||||
|
dummy_quantity = qty
|
||||||
|
while dummy_quantity > 0 and len(cost_layers) > 0:
|
||||||
|
layer: list = list(cost_layers[0])
|
||||||
|
if layer[0] < 0:
|
||||||
|
layer[0] = layer[0] + 1
|
||||||
|
dummy_quantity = dummy_quantity - 1
|
||||||
|
cost_layers[0] = tuple(layer)
|
||||||
|
if layer[0] == 0.0:
|
||||||
|
cost_layers.pop(0)
|
||||||
|
if dummy_quantity > 0 and len(cost_layers) > 0:
|
||||||
|
layer = list(cost_layers[0])
|
||||||
|
|
||||||
|
if dummy_quantity > 0 and len(cost_layers) == 0:
|
||||||
|
cost_layers.append((dummy_quantity, 0.0))
|
||||||
|
|
||||||
|
string_t = "ARRAY["
|
||||||
|
string_y = ', '.join([f"'{layer_tuple}'::cost_layer" for layer_tuple in cost_layers])
|
||||||
|
string_t += string_y + "]::cost_layer[]"
|
||||||
|
return string_t
|
||||||
|
|
||||||
|
def handleNegativeQuantity(qty, cost_layers):
|
||||||
|
cost_layers = [ast.literal_eval(item) for item in ast.literal_eval(cost_layers.replace('{', '[').replace('}', ']'))]
|
||||||
|
dummy_quantity = qty
|
||||||
|
while dummy_quantity < 0 and len(cost_layers) > 0:
|
||||||
|
layer: list = list(cost_layers[0])
|
||||||
|
layer[0] = layer[0] - 1
|
||||||
|
dummy_quantity = dummy_quantity + 1
|
||||||
|
cost_layers[0] = tuple(layer)
|
||||||
|
if layer[0] == 0.0:
|
||||||
|
cost_layers.pop(0)
|
||||||
|
if dummy_quantity < 0 and len(cost_layers) > 0:
|
||||||
|
layer = list(cost_layers[0])
|
||||||
|
|
||||||
|
if dummy_quantity < 0 and len(cost_layers) == 0:
|
||||||
|
cost_layers.append((dummy_quantity, 0.0))
|
||||||
|
|
||||||
|
string_t = "ARRAY["
|
||||||
|
string_y = ', '.join([f"'{layer_tuple}'::cost_layer" for layer_tuple in cost_layers])
|
||||||
|
string_t += string_y + "]::cost_layer[]"
|
||||||
|
return string_t
|
||||||
|
|
||||||
|
def setLocationData(conn, site_name, location, item_id, qty, cost):
|
||||||
"""Sets location data to include barcode: qty as k:v pair
|
"""Sets location data to include barcode: qty as k:v pair
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -198,16 +245,31 @@ def setLocationData(conn, site_name, location, barcode, qty):
|
|||||||
Returns:
|
Returns:
|
||||||
str: error/success
|
str: error/success
|
||||||
"""
|
"""
|
||||||
with open(f"sites/{site_name}/sql/unique/set_location_data.sql", "r+") as file:
|
#with open(f"sites/{site_name}/sql/unique/set_location_data.sql", "r+") as file:
|
||||||
sql = file.read()
|
# sql = file.read()
|
||||||
|
sql = f"UPDATE %sitename%_locations SET quantity_on_hand = %s WHERE id = %s;"
|
||||||
try:
|
try:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(f"SELECT id, items FROM {site_name}_locations WHERE uuid=%s;", (location, ))
|
cur.execute(f"SELECT id FROM {site_name}_locations WHERE uuid=%s;", (location, ))
|
||||||
loc_id, items = cur.fetchone()
|
loc_id = cur.fetchone()
|
||||||
items[barcode] = items.get(barcode, 0) + qty
|
cur.execute(f"SELECT id, quantity_on_hand, cost_layers FROM {site_name}_item_locations WHERE part_id = %s AND location_id = %s;", (item_id, loc_id))
|
||||||
cur.execute(sql, (json.dumps(items), loc_id))
|
x = cur.fetchone()
|
||||||
|
# maybe a while loop that will pull the cost_layers out and then go
|
||||||
|
# through each 1 by 1 until qty is at 0...
|
||||||
|
qty_on_hand = float(x[1]) + float(qty)
|
||||||
|
if x[1] < 0 and qty > 0:
|
||||||
|
# do thing
|
||||||
|
cost_layers_string = handleNegativeQuantityOnHand(qty, x[2])
|
||||||
|
cur.execute(f"UPDATE {site_name}_item_locations SET quantity_on_hand = %s, cost_layers = {cost_layers_string} WHERE id = %s;", (qty_on_hand, x[0]))
|
||||||
|
elif qty < 0:
|
||||||
|
print("ding")
|
||||||
|
cost_layers_string = handleNegativeQuantity(qty, x[2])
|
||||||
|
print(cost_layers_string)
|
||||||
|
cur.execute(f"UPDATE {site_name}_item_locations SET quantity_on_hand = %s, cost_layers = {cost_layers_string} WHERE id = %s;", (qty_on_hand, x[0]))
|
||||||
|
else:
|
||||||
|
cur.execute(f"UPDATE {site_name}_item_locations SET quantity_on_hand = %s, cost_layers = cost_layers || ({qty}, {cost})::cost_layer WHERE id = %s;", (qty_on_hand, x[0]))
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
conn.rollback()
|
print(error)
|
||||||
return error
|
return error
|
||||||
return "success"
|
return "success"
|
||||||
|
|
||||||
@ -230,12 +292,11 @@ def insertTransaction(conn, site_name, payload):
|
|||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(sql, payload)
|
cur.execute(sql, payload)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
conn.rollback()
|
|
||||||
return error
|
return error
|
||||||
|
|
||||||
return "success"
|
return "success"
|
||||||
|
|
||||||
def addTransaction(*, conn, site_name, payload, location, logistics_info_id, barcode, qty):
|
def addTransaction(*, conn, site_name, payload, location, logistics_info_id, item_id, qty, cost):
|
||||||
"""a complete function for adding a transaction to the system
|
"""a complete function for adding a transaction to the system
|
||||||
|
|
||||||
payload = [timestamp, logistics_info_id, barcode, name, transaction_type,
|
payload = [timestamp, logistics_info_id, barcode, name, transaction_type,
|
||||||
@ -255,8 +316,9 @@ def addTransaction(*, conn, site_name, payload, location, logistics_info_id, bar
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
insertTransaction(conn, site_name, payload)
|
insertTransaction(conn, site_name, payload)
|
||||||
setLocationData(conn, site_name, location, barcode, qty)
|
if qty != 0.0:
|
||||||
setLogisticsDataTransaction(conn, site_name, location, logistics_info_id, qty)
|
setLocationData(conn, site_name, location, item_id, qty, cost)
|
||||||
|
#setLogisticsDataTransaction(conn, site_name, location, logistics_info_id, qty)
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
@ -286,8 +348,18 @@ def add_food_item(site_name: str, barcode: str, name: str, payload: dict):
|
|||||||
food_info_id = create_food_info(conn, site_name, payload["food_info"])
|
food_info_id = create_food_info(conn, site_name, payload["food_info"])
|
||||||
if not food_info_id:
|
if not food_info_id:
|
||||||
return False
|
return False
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"SELECT id FROM {site_name}_locations WHERE uuid=%s;", (uuid, ))
|
||||||
|
location_id = cur.fetchone()[0]
|
||||||
|
print(location_id)
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return False
|
||||||
|
|
||||||
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 *;"
|
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 *;"
|
||||||
|
sqlthree = f"INSERT INTO {site_name}_item_locations(part_id, location_id, quantity_on_hand, cost_layers) VALUES (%s, %s, %s, %s);"
|
||||||
row = None
|
row = None
|
||||||
try:
|
try:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
@ -295,6 +367,8 @@ def add_food_item(site_name: str, barcode: str, name: str, payload: dict):
|
|||||||
rows = cur.fetchone()
|
rows = cur.fetchone()
|
||||||
if rows:
|
if rows:
|
||||||
row = rows[:]
|
row = rows[:]
|
||||||
|
print(row)
|
||||||
|
cur.execute(sqlthree, (row[0], location_id, 0.0, lst2pgarr([])))
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
print(error)
|
print(error)
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
@ -303,7 +377,7 @@ def add_food_item(site_name: str, barcode: str, name: str, payload: dict):
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
payload = [datetime.datetime.now(), logistics_info_id, barcode, name, "SYSTEM", 0.0, "Item added to system!", 1, json.dumps({})]
|
payload = [datetime.datetime.now(), logistics_info_id, barcode, name, "SYSTEM", 0.0, "Item added to system!", 1, json.dumps({})]
|
||||||
addTransaction(conn=conn, site_name=site_name,payload=payload, location=uuid, logistics_info_id=logistics_info_id,barcode=barcode, qty=0.0)
|
addTransaction(conn=conn, site_name=site_name,payload=payload, location=uuid, logistics_info_id=logistics_info_id,item_id=row[0], qty=0.0, cost=0.0)
|
||||||
|
|
||||||
def drop_table(sql_file: str):
|
def drop_table(sql_file: str):
|
||||||
database_config = config()
|
database_config = config()
|
||||||
@ -339,6 +413,7 @@ def delete_site(site_name):
|
|||||||
drop_table(f'sites/{site_name}/sql/drop/receipts.sql')
|
drop_table(f'sites/{site_name}/sql/drop/receipts.sql')
|
||||||
drop_table(f'sites/{site_name}/sql/drop/recipes.sql')
|
drop_table(f'sites/{site_name}/sql/drop/recipes.sql')
|
||||||
drop_table(f'sites/{site_name}/sql/drop/shopping_lists.sql')
|
drop_table(f'sites/{site_name}/sql/drop/shopping_lists.sql')
|
||||||
|
drop_table(f'sites/{site_name}/sql/drop/item_locations.sql')
|
||||||
|
|
||||||
def create_site(site_name):
|
def create_site(site_name):
|
||||||
|
|
||||||
@ -356,15 +431,16 @@ def create_site(site_name):
|
|||||||
create_table(f'sites/{site_name}/sql/create/zones.sql')
|
create_table(f'sites/{site_name}/sql/create/zones.sql')
|
||||||
create_table(f'sites/{site_name}/sql/create/locations.sql')
|
create_table(f'sites/{site_name}/sql/create/locations.sql')
|
||||||
create_table(f'sites/{site_name}/sql/create/vendors.sql')
|
create_table(f'sites/{site_name}/sql/create/vendors.sql')
|
||||||
create_table(f'sites/{site_name}/sql/create/receipt_items.sql')
|
|
||||||
create_table(f'sites/{site_name}/sql/create/receipts.sql')
|
create_table(f'sites/{site_name}/sql/create/receipts.sql')
|
||||||
|
create_table(f'sites/{site_name}/sql/create/receipt_items.sql')
|
||||||
create_table(f'sites/{site_name}/sql/create/recipes.sql')
|
create_table(f'sites/{site_name}/sql/create/recipes.sql')
|
||||||
create_table(f'sites/{site_name}/sql/create/shopping_lists.sql')
|
create_table(f'sites/{site_name}/sql/create/shopping_lists.sql')
|
||||||
|
create_table(f'sites/{site_name}/sql/create/item_locations.sql')
|
||||||
|
|
||||||
|
|
||||||
sql = f"INSERT INTO {site_name}_zones(name) VALUES (%s) RETURNING id;"
|
sql = f"INSERT INTO {site_name}_zones(name) VALUES (%s) RETURNING id;"
|
||||||
sqltwo = f"INSERT INTO {site_name}_locations(uuid, name, zone_id, items) VALUES (%s, %s, %s, %s);"
|
sqltwo = f"INSERT INTO {site_name}_locations(uuid, name, zone_id, items) VALUES (%s, %s, %s, %s);"
|
||||||
|
sqlthree = f"INSERT INTO {site_name}_vendors(vendor_name, creation_date, created_by) VALUES (%s, %s, %s);"
|
||||||
database_config = config()
|
database_config = config()
|
||||||
with psycopg2.connect(**database_config) as conn:
|
with psycopg2.connect(**database_config) as conn:
|
||||||
zone_id = None
|
zone_id = None
|
||||||
@ -388,6 +464,14 @@ def create_site(site_name):
|
|||||||
print(error)
|
print(error)
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(sqlthree, ("None", str(datetime.datetime.now()), 1))
|
||||||
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
|
print(error)
|
||||||
|
conn.rollback()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|||||||
@ -108,6 +108,7 @@ if __name__ == "__main__":
|
|||||||
main.create_site(sys.argv[3])
|
main.create_site(sys.argv[3])
|
||||||
|
|
||||||
if func_name == "delete" and argument == "site":
|
if func_name == "delete" and argument == "site":
|
||||||
|
print(func_name, argument)
|
||||||
main.delete_site(sys.argv[3])
|
main.delete_site(sys.argv[3])
|
||||||
shutil.rmtree(f"sites/{sys.argv[3]}")
|
shutil.rmtree(f"sites/{sys.argv[3]}")
|
||||||
cfg.delete_site(sys.argv[3])
|
cfg.delete_site(sys.argv[3])
|
||||||
|
|||||||
38
scratch.py
Normal file
38
scratch.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
sql = "SELECT items FROM main_locations WHERE id=1;"
|
||||||
|
|
||||||
|
from config import config
|
||||||
|
import psycopg2, requests
|
||||||
|
import main, datetime
|
||||||
|
|
||||||
|
|
||||||
|
"""database_config = config()
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
result = main.setLocationData(conn, "main", "default@all", 1, 4.0, 0.0)
|
||||||
|
print(result)"""
|
||||||
|
|
||||||
|
url = "http://192.168.1.45:5810/resolveReceiptItem"
|
||||||
|
"""payload_receipt = {
|
||||||
|
"receipt_id": 123456,
|
||||||
|
"receipt_status": "Unresolved",
|
||||||
|
"date_submitted": str(datetime.datetime.now()),
|
||||||
|
"submitted_by": 1,
|
||||||
|
"vendor_id": 0,
|
||||||
|
"files": {},
|
||||||
|
"items": [
|
||||||
|
("FOOD", 0, "%1234%", "test_item", 1.0, {"cost": 1.99, "EXPIRES": False}, "Unresolved"),
|
||||||
|
("FOOD", 0, "%1235%", "test_item", 1.0, {"cost": 1.99, "EXPIRES": False}, "Unresolved"),
|
||||||
|
("FOOD", 0, "%1236%", "test_item", 1.0, {"cost": 1.99, "EXPIRES": False}, "Unresolved"),
|
||||||
|
],
|
||||||
|
"site_name": "main"
|
||||||
|
}"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
response = requests.post(url)
|
||||||
|
|
||||||
|
receipt_id = response.json()["receipt_id"]
|
||||||
|
|
||||||
|
|
||||||
|
print(receipt_id)
|
||||||
@ -1,7 +1,7 @@
|
|||||||
[site]
|
[site]
|
||||||
site_name=test2
|
site_name=Backpack
|
||||||
site_owner=joe
|
site_owner=Jadowyne
|
||||||
email=jdoe@gmail.com
|
email=
|
||||||
|
|
||||||
[defaults]
|
[defaults]
|
||||||
default_zone=default
|
default_zone=default
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_brands (
|
CREATE TABLE IF NOT EXISTS Backpack_brands (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255)
|
name VARCHAR(255)
|
||||||
);
|
);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_food_info (
|
CREATE TABLE IF NOT EXISTS Backpack_food_info (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
food_groups TEXT [],
|
food_groups TEXT [],
|
||||||
ingrediants TEXT [],
|
ingrediants TEXT [],
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_groups(
|
CREATE TABLE IF NOT EXISTS Backpack_groups(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_items(
|
CREATE TABLE IF NOT EXISTS Backpack_items(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
barcode VARCHAR(255) NOT NULL,
|
barcode VARCHAR(255) NOT NULL,
|
||||||
item_name VARCHAR(255) NOT NULL,
|
item_name VARCHAR(255) NOT NULL,
|
||||||
@ -15,14 +15,18 @@ CREATE TABLE IF NOT EXISTS test2_items(
|
|||||||
UNIQUE(barcode, item_info_id),
|
UNIQUE(barcode, item_info_id),
|
||||||
CONSTRAINT fk_item_info
|
CONSTRAINT fk_item_info
|
||||||
FOREIGN KEY(item_info_id)
|
FOREIGN KEY(item_info_id)
|
||||||
REFERENCES test2_item_info(id),
|
REFERENCES Backpack_item_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_food_info
|
CONSTRAINT fk_food_info
|
||||||
FOREIGN KEY(food_info_id)
|
FOREIGN KEY(food_info_id)
|
||||||
REFERENCES test2_food_info(id),
|
REFERENCES Backpack_food_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_brand
|
CONSTRAINT fk_brand
|
||||||
FOREIGN KEY(brand)
|
FOREIGN KEY(brand)
|
||||||
REFERENCES test2_brands(id),
|
REFERENCES Backpack_brands(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_logistics_info
|
CONSTRAINT fk_logistics_info
|
||||||
FOREIGN KEY(logistics_info_id)
|
FOREIGN KEY(logistics_info_id)
|
||||||
REFERENCES test2_logistics_info(id)
|
REFERENCES Backpack_logistics_info(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOt EXISTS test2_item_info (
|
CREATE TABLE IF NOt EXISTS Backpack_item_info (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
barcode VARCHAR(255) NOT NULL,
|
barcode VARCHAR(255) NOT NULL,
|
||||||
linked_items INTEGER [],
|
linked_items INTEGER [],
|
||||||
23
sites/Backpack/sql/create/item_locations.sql
Normal file
23
sites/Backpack/sql/create/item_locations.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'cost_layer') THEN
|
||||||
|
CREATE TYPE cost_layer AS (qty FLOAT8, cost FLOAT8);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS Backpack_item_locations(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
part_id INTEGER NOT NULL,
|
||||||
|
location_id INTEGER NOT NULL,
|
||||||
|
quantity_on_hand FLOAT8 NOT NULL,
|
||||||
|
cost_layers cost_layer[],
|
||||||
|
UNIQUE(part_id, location_id),
|
||||||
|
CONSTRAINT fk_part_id
|
||||||
|
FOREIGN KEY(part_id)
|
||||||
|
REFERENCES Backpack_items(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT fk_location_id
|
||||||
|
FOREIGN KEY(location_id)
|
||||||
|
REFERENCES Backpack_locations(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_itemlinks (
|
CREATE TABLE IF NOT EXISTS Backpack_itemlinks (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
barcode VARCHAR(255) NOt NULL,
|
barcode VARCHAR(255) NOt NULL,
|
||||||
link INTEGER NOT NULL,
|
link INTEGER NOT NULL,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_locations(
|
CREATE TABLE IF NOT EXISTS Backpack_locations(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
uuid VARCHAR(255) NOT NULL,
|
uuid VARCHAR(255) NOT NULL,
|
||||||
name VARCHAR(32) NOT NULL,
|
name VARCHAR(32) NOT NULL,
|
||||||
@ -7,5 +7,5 @@ CREATE TABLE IF NOT EXISTS test2_locations(
|
|||||||
UNIQUE(uuid),
|
UNIQUE(uuid),
|
||||||
CONSTRAINT fk_zone
|
CONSTRAINT fk_zone
|
||||||
FOREIGN KEY(zone_id)
|
FOREIGN KEY(zone_id)
|
||||||
REFERENCES test2_zones(id)
|
REFERENCES Backpack_zones(id)
|
||||||
);
|
);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_logistics_info(
|
CREATE TABLE IF NOT EXISTS Backpack_logistics_info(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
barcode VARCHAR(255) NOT NULL,
|
barcode VARCHAR(255) NOT NULL,
|
||||||
primary_location VARCHAR(64),
|
primary_location VARCHAR(64),
|
||||||
13
sites/Backpack/sql/create/receipt_items.sql
Normal file
13
sites/Backpack/sql/create/receipt_items.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS Backpack_receipt_items (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
type VARCHAR(255) NOT NULL,
|
||||||
|
receipt_id INTEGER NOT NULL,
|
||||||
|
barcode VARCHAR(255) NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
qty FLOAT8 NOT NULL,
|
||||||
|
data JSONB,
|
||||||
|
status VARCHAR (64),
|
||||||
|
CONSTRAINT fk_receipt
|
||||||
|
FOREIGN KEY(receipt_id)
|
||||||
|
REFERENCES Backpack_receipts(id)
|
||||||
|
);
|
||||||
13
sites/Backpack/sql/create/receipts.sql
Normal file
13
sites/Backpack/sql/create/receipts.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS Backpack_receipts (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
receipt_id VARCHAR (32) NOT NULL,
|
||||||
|
receipt_status VARCHAR (64) NOT NULL,
|
||||||
|
date_submitted TIMESTAMP NOT NULL,
|
||||||
|
submitted_by INTEGER NOT NULL,
|
||||||
|
vendor_id INTEGER,
|
||||||
|
files JSONB,
|
||||||
|
UNIQUE(receipt_id),
|
||||||
|
CONSTRAINT fk_vendor
|
||||||
|
FOREIGN KEY(vendor_id)
|
||||||
|
REFERENCES Backpack_vendors(id)
|
||||||
|
);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_recipes (
|
CREATE TABLE IF NOT EXISTS Backpack_recipes (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR,
|
name VARCHAR,
|
||||||
author INTEGER,
|
author INTEGER,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_shopping_lists (
|
CREATE TABLE IF NOT EXISTS Backpack_shopping_lists (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_Transactions (
|
CREATE TABLE IF NOT EXISTS Backpack_Transactions (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
timestamp TIMESTAMP,
|
timestamp TIMESTAMP,
|
||||||
logistics_info_id INTEGER NOT NULL,
|
logistics_info_id INTEGER NOT NULL,
|
||||||
@ -11,5 +11,5 @@ CREATE TABLE IF NOT EXISTS test2_Transactions (
|
|||||||
data JSONB,
|
data JSONB,
|
||||||
CONSTRAINT fk_logistics_info
|
CONSTRAINT fk_logistics_info
|
||||||
FOREIGN KEY(logistics_info_id)
|
FOREIGN KEY(logistics_info_id)
|
||||||
REFERENCES test2_logistics_info(id)
|
REFERENCES Backpack_logistics_info(id)
|
||||||
);
|
);
|
||||||
8
sites/Backpack/sql/create/vendors.sql
Normal file
8
sites/Backpack/sql/create/vendors.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS Backpack_vendors (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
vendor_name VARCHAR(255) NOT NULL,
|
||||||
|
vendor_address VARCHAR(255),
|
||||||
|
creation_date TIMESTAMP NOT NULL,
|
||||||
|
created_by INTEGER NOT NULL,
|
||||||
|
phone_number VARCHAR(32)
|
||||||
|
);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_zones(
|
CREATE TABLE IF NOT EXISTS Backpack_zones(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(32) NOT NULL,
|
name VARCHAR(32) NOT NULL,
|
||||||
UNIQUE(name)
|
UNIQUE(name)
|
||||||
1
sites/Backpack/sql/drop/brands.sql
Normal file
1
sites/Backpack/sql/drop/brands.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_brands CASCADE;
|
||||||
1
sites/Backpack/sql/drop/food_info.sql
Normal file
1
sites/Backpack/sql/drop/food_info.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_food_info CASCADE;
|
||||||
1
sites/Backpack/sql/drop/groups.sql
Normal file
1
sites/Backpack/sql/drop/groups.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_groups CASCADE;
|
||||||
1
sites/Backpack/sql/drop/item_info.sql
Normal file
1
sites/Backpack/sql/drop/item_info.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_item_info CASCADE;
|
||||||
1
sites/Backpack/sql/drop/item_locations.sql
Normal file
1
sites/Backpack/sql/drop/item_locations.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_item_locations CASCADE;
|
||||||
1
sites/Backpack/sql/drop/items.sql
Normal file
1
sites/Backpack/sql/drop/items.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_items CASCADE;
|
||||||
1
sites/Backpack/sql/drop/linked_items.sql
Normal file
1
sites/Backpack/sql/drop/linked_items.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_itemlinks CASCADE;
|
||||||
1
sites/Backpack/sql/drop/locations.sql
Normal file
1
sites/Backpack/sql/drop/locations.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_locations CASCADE;
|
||||||
1
sites/Backpack/sql/drop/logistics_info.sql
Normal file
1
sites/Backpack/sql/drop/logistics_info.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_logistics_info CASCADE;
|
||||||
1
sites/Backpack/sql/drop/receipt_items.sql
Normal file
1
sites/Backpack/sql/drop/receipt_items.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_receipt_items CASCADE;
|
||||||
1
sites/Backpack/sql/drop/receipts.sql
Normal file
1
sites/Backpack/sql/drop/receipts.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_receipts CASCADE;
|
||||||
1
sites/Backpack/sql/drop/recipes.sql
Normal file
1
sites/Backpack/sql/drop/recipes.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_recipes CASCADE;
|
||||||
1
sites/Backpack/sql/drop/shopping_lists.sql
Normal file
1
sites/Backpack/sql/drop/shopping_lists.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_shopping_lists CASCADE;
|
||||||
1
sites/Backpack/sql/drop/transactions.sql
Normal file
1
sites/Backpack/sql/drop/transactions.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_transactions CASCADE;
|
||||||
1
sites/Backpack/sql/drop/vendors.sql
Normal file
1
sites/Backpack/sql/drop/vendors.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_vendors CASCADE;
|
||||||
1
sites/Backpack/sql/drop/zones.sql
Normal file
1
sites/Backpack/sql/drop/zones.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE Backpack_zones CASCADE;
|
||||||
3
sites/Backpack/sql/unique/Insert_transaction.sql
Normal file
3
sites/Backpack/sql/unique/Insert_transaction.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
INSERT INTO Backpack_transactions
|
||||||
|
(timestamp, logistics_info_id, barcode, name, transaction_type, quantity, description, user_id, data)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s);
|
||||||
3
sites/Backpack/sql/unique/logistics_transactions.sql
Normal file
3
sites/Backpack/sql/unique/logistics_transactions.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
UPDATE Backpack_logistics_info
|
||||||
|
SET quantity_on_hand = %s, location_data = %s
|
||||||
|
WHERE id = %s;
|
||||||
45
sites/Backpack/sql/unique/select_item_all.sql
Normal file
45
sites/Backpack/sql/unique/select_item_all.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
SELECT * FROM Backpack_items
|
||||||
|
LEFT JOIN Backpack_logistics_info ON Backpack_items.logistics_info_id = Backpack_logistics_info.id
|
||||||
|
LEFT JOIN Backpack_item_info ON Backpack_items.item_info_id = Backpack_item_info.id
|
||||||
|
LEFT JOIN Backpack_food_info ON Backpack_items.food_info_id = Backpack_food_info.id
|
||||||
|
WHERE Backpack_items.id=%s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
00 - item_id
|
||||||
|
01 - barcode
|
||||||
|
02 - item_name
|
||||||
|
03 - brand (id)
|
||||||
|
04 - description
|
||||||
|
05 - tags
|
||||||
|
06 - links
|
||||||
|
07 - item_info_id
|
||||||
|
08 - logistics_info_id
|
||||||
|
09 - food_info_id
|
||||||
|
10 - row_type
|
||||||
|
11 - item_type
|
||||||
|
12 - search_string
|
||||||
|
13 - logistics_info_id
|
||||||
|
14 - barcode
|
||||||
|
15 - primary_location
|
||||||
|
16 - auto_issue_location
|
||||||
|
17 - dynamic_locations
|
||||||
|
18 - location_data
|
||||||
|
19 - quantity_on_hand
|
||||||
|
20 - item_info_id
|
||||||
|
21 - barcode
|
||||||
|
22 - linked_items
|
||||||
|
23 - shopping_lists
|
||||||
|
24 - recipes
|
||||||
|
25 - groups
|
||||||
|
26 - packaging
|
||||||
|
27 - uom
|
||||||
|
28 - cost
|
||||||
|
29 - safety_stock
|
||||||
|
30 - lead_time_days
|
||||||
|
31 - ai_pick
|
||||||
|
32 - food_info_id
|
||||||
|
33 - food_groups
|
||||||
|
34 - ingrediants
|
||||||
|
35 - nutrients
|
||||||
|
36 - expires
|
||||||
|
*/
|
||||||
45
sites/Backpack/sql/unique/select_item_all_barcode.sql
Normal file
45
sites/Backpack/sql/unique/select_item_all_barcode.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
SELECT * FROM Backpack_items
|
||||||
|
LEFT JOIN Backpack_logistics_info ON Backpack_items.logistics_info_id = Backpack_logistics_info.id
|
||||||
|
LEFT JOIN Backpack_item_info ON Backpack_items.item_info_id = Backpack_item_info.id
|
||||||
|
LEFT JOIN Backpack_food_info ON Backpack_items.food_info_id = Backpack_food_info.id
|
||||||
|
WHERE Backpack_items.barcode=%s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
00 - item_id
|
||||||
|
01 - barcode
|
||||||
|
02 - item_name
|
||||||
|
03 - brand (id)
|
||||||
|
04 - description
|
||||||
|
05 - tags
|
||||||
|
06 - links
|
||||||
|
07 - item_info_id
|
||||||
|
08 - logistics_info_id
|
||||||
|
09 - food_info_id
|
||||||
|
10 - row_type
|
||||||
|
11 - item_type
|
||||||
|
12 - search_string
|
||||||
|
13 - logistics_info_id
|
||||||
|
14 - barcode
|
||||||
|
15 - primary_location
|
||||||
|
16 - auto_issue_location
|
||||||
|
17 - dynamic_locations
|
||||||
|
18 - location_data
|
||||||
|
19 - quantity_on_hand
|
||||||
|
20 - item_info_id
|
||||||
|
21 - barcode
|
||||||
|
22 - linked_items
|
||||||
|
23 - shopping_lists
|
||||||
|
24 - recipes
|
||||||
|
25 - groups
|
||||||
|
26 - packaging
|
||||||
|
27 - uom
|
||||||
|
28 - cost
|
||||||
|
29 - safety_stock
|
||||||
|
30 - lead_time_days
|
||||||
|
31 - ai_pick
|
||||||
|
32 - food_info_id
|
||||||
|
33 - food_groups
|
||||||
|
34 - ingrediants
|
||||||
|
35 - nutrients
|
||||||
|
36 - expires
|
||||||
|
*/
|
||||||
3
sites/Backpack/sql/unique/set_location_data.sql
Normal file
3
sites/Backpack/sql/unique/set_location_data.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
UPDATE Backpack_locations
|
||||||
|
SET items = %s
|
||||||
|
WHERE id = %s;
|
||||||
@ -15,14 +15,18 @@ CREATE TABLE IF NOT EXISTS %sitename%_items(
|
|||||||
UNIQUE(barcode, item_info_id),
|
UNIQUE(barcode, item_info_id),
|
||||||
CONSTRAINT fk_item_info
|
CONSTRAINT fk_item_info
|
||||||
FOREIGN KEY(item_info_id)
|
FOREIGN KEY(item_info_id)
|
||||||
REFERENCES %sitename%_item_info(id),
|
REFERENCES %sitename%_item_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_food_info
|
CONSTRAINT fk_food_info
|
||||||
FOREIGN KEY(food_info_id)
|
FOREIGN KEY(food_info_id)
|
||||||
REFERENCES %sitename%_food_info(id),
|
REFERENCES %sitename%_food_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_brand
|
CONSTRAINT fk_brand
|
||||||
FOREIGN KEY(brand)
|
FOREIGN KEY(brand)
|
||||||
REFERENCES %sitename%_brands(id),
|
REFERENCES %sitename%_brands(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_logistics_info
|
CONSTRAINT fk_logistics_info
|
||||||
FOREIGN KEY(logistics_info_id)
|
FOREIGN KEY(logistics_info_id)
|
||||||
REFERENCES %sitename%_logistics_info(id)
|
REFERENCES %sitename%_logistics_info(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|||||||
23
sites/default/sql/create/item_locations.sql
Normal file
23
sites/default/sql/create/item_locations.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'cost_layer') THEN
|
||||||
|
CREATE TYPE cost_layer AS (qty FLOAT8, cost FLOAT8);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS %sitename%_item_locations(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
part_id INTEGER NOT NULL,
|
||||||
|
location_id INTEGER NOT NULL,
|
||||||
|
quantity_on_hand FLOAT8 NOT NULL,
|
||||||
|
cost_layers cost_layer[],
|
||||||
|
UNIQUE(part_id, location_id),
|
||||||
|
CONSTRAINT fk_part_id
|
||||||
|
FOREIGN KEY(part_id)
|
||||||
|
REFERENCES %sitename%_items(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT fk_location_id
|
||||||
|
FOREIGN KEY(location_id)
|
||||||
|
REFERENCES %sitename%_locations(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
@ -1,9 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS %sitename%_receipt_items (
|
CREATE TABLE IF NOT EXISTS %sitename%_receipt_items (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
type VARCHAR(255) NOT NULL,
|
type VARCHAR(255) NOT NULL,
|
||||||
|
receipt_id INTEGER NOT NULL,
|
||||||
barcode VARCHAR(255) NOT NULL,
|
barcode VARCHAR(255) NOT NULL,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
qty FLOAT8 NOT NULL,
|
qty FLOAT8 NOT NULL,
|
||||||
data JSONB,
|
data JSONB,
|
||||||
status VARCHAR (64)
|
status VARCHAR (64),
|
||||||
|
CONSTRAINT fk_receipt
|
||||||
|
FOREIGN KEY(receipt_id)
|
||||||
|
REFERENCES %sitename%_receipts(id)
|
||||||
);
|
);
|
||||||
@ -1,10 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS %sitename%_receipts (
|
CREATE TABLE IF NOT EXISTS %sitename%_receipts (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
receipt_id INTEGER NOT NULL,
|
receipt_id VARCHAR (32) NOT NULL,
|
||||||
receipt_status VARCHAR (64) NOT NULL,
|
receipt_status VARCHAR (64) NOT NULL,
|
||||||
date_submitted TIMESTAMP NOT NULL,
|
date_submitted TIMESTAMP NOT NULL,
|
||||||
submitted_by INTEGER NOT NULL,
|
submitted_by INTEGER NOT NULL,
|
||||||
vendor_id INTEGER,
|
vendor_id INTEGER,
|
||||||
files JSONB,
|
files JSONB,
|
||||||
UNIQUE(receipt_id)
|
UNIQUE(receipt_id),
|
||||||
|
CONSTRAINT fk_vendor
|
||||||
|
FOREIGN KEY(vendor_id)
|
||||||
|
REFERENCES %sitename%_vendors(id)
|
||||||
);
|
);
|
||||||
@ -1,8 +1,8 @@
|
|||||||
CREATE TABLE IF NOT EXISTS %sitename%_vendors (
|
CREATE TABLE IF NOT EXISTS %sitename%_vendors (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
vendor_name VARCHAR(255) NOT NULL,
|
||||||
address VARCHAR(255),
|
vendor_address VARCHAR(255),
|
||||||
creation_date TIMESTAMP NOT NULL,
|
creation_date TIMESTAMP NOT NULL,
|
||||||
created_by TIMESTAMP NOT NULL,
|
created_by INTEGER NOT NULL,
|
||||||
phone_number VARCHAR(32)
|
phone_number VARCHAR(32)
|
||||||
);
|
);
|
||||||
1
sites/default/sql/drop/item_locations.sql
Normal file
1
sites/default/sql/drop/item_locations.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE %sitename%_item_locations CASCADE;
|
||||||
45
sites/default/sql/unique/select_item_all_barcode.sql
Normal file
45
sites/default/sql/unique/select_item_all_barcode.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
SELECT * FROM %sitename%_items
|
||||||
|
LEFT JOIN %sitename%_logistics_info ON %sitename%_items.logistics_info_id = %sitename%_logistics_info.id
|
||||||
|
LEFT JOIN %sitename%_item_info ON %sitename%_items.item_info_id = %sitename%_item_info.id
|
||||||
|
LEFT JOIN %sitename%_food_info ON %sitename%_items.food_info_id = %sitename%_food_info.id
|
||||||
|
WHERE %sitename%_items.barcode=%s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
00 - item_id
|
||||||
|
01 - barcode
|
||||||
|
02 - item_name
|
||||||
|
03 - brand (id)
|
||||||
|
04 - description
|
||||||
|
05 - tags
|
||||||
|
06 - links
|
||||||
|
07 - item_info_id
|
||||||
|
08 - logistics_info_id
|
||||||
|
09 - food_info_id
|
||||||
|
10 - row_type
|
||||||
|
11 - item_type
|
||||||
|
12 - search_string
|
||||||
|
13 - logistics_info_id
|
||||||
|
14 - barcode
|
||||||
|
15 - primary_location
|
||||||
|
16 - auto_issue_location
|
||||||
|
17 - dynamic_locations
|
||||||
|
18 - location_data
|
||||||
|
19 - quantity_on_hand
|
||||||
|
20 - item_info_id
|
||||||
|
21 - barcode
|
||||||
|
22 - linked_items
|
||||||
|
23 - shopping_lists
|
||||||
|
24 - recipes
|
||||||
|
25 - groups
|
||||||
|
26 - packaging
|
||||||
|
27 - uom
|
||||||
|
28 - cost
|
||||||
|
29 - safety_stock
|
||||||
|
30 - lead_time_days
|
||||||
|
31 - ai_pick
|
||||||
|
32 - food_info_id
|
||||||
|
33 - food_groups
|
||||||
|
34 - ingrediants
|
||||||
|
35 - nutrients
|
||||||
|
36 - expires
|
||||||
|
*/
|
||||||
@ -15,14 +15,18 @@ CREATE TABLE IF NOT EXISTS main_items(
|
|||||||
UNIQUE(barcode, item_info_id),
|
UNIQUE(barcode, item_info_id),
|
||||||
CONSTRAINT fk_item_info
|
CONSTRAINT fk_item_info
|
||||||
FOREIGN KEY(item_info_id)
|
FOREIGN KEY(item_info_id)
|
||||||
REFERENCES main_item_info(id),
|
REFERENCES main_item_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_food_info
|
CONSTRAINT fk_food_info
|
||||||
FOREIGN KEY(food_info_id)
|
FOREIGN KEY(food_info_id)
|
||||||
REFERENCES main_food_info(id),
|
REFERENCES main_food_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_brand
|
CONSTRAINT fk_brand
|
||||||
FOREIGN KEY(brand)
|
FOREIGN KEY(brand)
|
||||||
REFERENCES main_brands(id),
|
REFERENCES main_brands(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_logistics_info
|
CONSTRAINT fk_logistics_info
|
||||||
FOREIGN KEY(logistics_info_id)
|
FOREIGN KEY(logistics_info_id)
|
||||||
REFERENCES main_logistics_info(id)
|
REFERENCES main_logistics_info(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|||||||
23
sites/main/sql/create/item_locations.sql
Normal file
23
sites/main/sql/create/item_locations.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'cost_layer') THEN
|
||||||
|
CREATE TYPE cost_layer AS (qty FLOAT8, cost FLOAT8);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS main_item_locations(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
part_id INTEGER NOT NULL,
|
||||||
|
location_id INTEGER NOT NULL,
|
||||||
|
quantity_on_hand FLOAT8 NOT NULL,
|
||||||
|
cost_layers cost_layer[],
|
||||||
|
UNIQUE(part_id, location_id),
|
||||||
|
CONSTRAINT fk_part_id
|
||||||
|
FOREIGN KEY(part_id)
|
||||||
|
REFERENCES main_items(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT fk_location_id
|
||||||
|
FOREIGN KEY(location_id)
|
||||||
|
REFERENCES main_locations(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
@ -1,9 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS main_receipt_items (
|
CREATE TABLE IF NOT EXISTS main_receipt_items (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
type VARCHAR(255) NOT NULL,
|
type VARCHAR(255) NOT NULL,
|
||||||
|
receipt_id INTEGER NOT NULL,
|
||||||
barcode VARCHAR(255) NOT NULL,
|
barcode VARCHAR(255) NOT NULL,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
qty FLOAT8 NOT NULL,
|
qty FLOAT8 NOT NULL,
|
||||||
data JSONB,
|
data JSONB,
|
||||||
status VARCHAR (64)
|
status VARCHAR (64),
|
||||||
|
CONSTRAINT fk_receipt
|
||||||
|
FOREIGN KEY(receipt_id)
|
||||||
|
REFERENCES main_receipts(id)
|
||||||
);
|
);
|
||||||
@ -1,10 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS main_receipts (
|
CREATE TABLE IF NOT EXISTS main_receipts (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
receipt_id INTEGER NOT NULL,
|
receipt_id VARCHAR (32) NOT NULL,
|
||||||
receipt_status VARCHAR (64) NOT NULL,
|
receipt_status VARCHAR (64) NOT NULL,
|
||||||
date_submitted TIMESTAMP NOT NULL,
|
date_submitted TIMESTAMP NOT NULL,
|
||||||
submitted_by INTEGER NOT NULL,
|
submitted_by INTEGER NOT NULL,
|
||||||
vendor_id INTEGER,
|
vendor_id INTEGER,
|
||||||
files JSONB,
|
files JSONB,
|
||||||
UNIQUE(receipt_id)
|
UNIQUE(receipt_id),
|
||||||
|
CONSTRAINT fk_vendor
|
||||||
|
FOREIGN KEY(vendor_id)
|
||||||
|
REFERENCES main_vendors(id)
|
||||||
);
|
);
|
||||||
@ -1,8 +1,8 @@
|
|||||||
CREATE TABLE IF NOT EXISTS main_vendors (
|
CREATE TABLE IF NOT EXISTS main_vendors (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
vendor_name VARCHAR(255) NOT NULL,
|
||||||
address VARCHAR(255),
|
vendor_address VARCHAR(255),
|
||||||
creation_date TIMESTAMP NOT NULL,
|
creation_date TIMESTAMP NOT NULL,
|
||||||
created_by TIMESTAMP NOT NULL,
|
created_by INTEGER NOT NULL,
|
||||||
phone_number VARCHAR(32)
|
phone_number VARCHAR(32)
|
||||||
);
|
);
|
||||||
1
sites/main/sql/drop/item_locations.sql
Normal file
1
sites/main/sql/drop/item_locations.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE main_item_locations CASCADE;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
SELECT * FROM test2_items
|
SELECT * FROM main_items
|
||||||
LEFT JOIN test2_logistics_info ON test2_items.logistics_info_id = test2_logistics_info.id
|
LEFT JOIN main_logistics_info ON main_items.logistics_info_id = main_logistics_info.id
|
||||||
LEFT JOIN test2_item_info ON test2_items.item_info_id = test2_item_info.id
|
LEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.id
|
||||||
LEFT JOIN test2_food_info ON test2_items.food_info_id = test2_food_info.id
|
LEFT JOIN main_food_info ON main_items.food_info_id = main_food_info.id
|
||||||
WHERE test2_items.id=%s;
|
WHERE main_items.barcode=%s;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
00 - item_id
|
00 - item_id
|
||||||
@ -15,14 +15,18 @@ CREATE TABLE IF NOT EXISTS test_items(
|
|||||||
UNIQUE(barcode, item_info_id),
|
UNIQUE(barcode, item_info_id),
|
||||||
CONSTRAINT fk_item_info
|
CONSTRAINT fk_item_info
|
||||||
FOREIGN KEY(item_info_id)
|
FOREIGN KEY(item_info_id)
|
||||||
REFERENCES test_item_info(id),
|
REFERENCES test_item_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_food_info
|
CONSTRAINT fk_food_info
|
||||||
FOREIGN KEY(food_info_id)
|
FOREIGN KEY(food_info_id)
|
||||||
REFERENCES test_food_info(id),
|
REFERENCES test_food_info(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_brand
|
CONSTRAINT fk_brand
|
||||||
FOREIGN KEY(brand)
|
FOREIGN KEY(brand)
|
||||||
REFERENCES test_brands(id),
|
REFERENCES test_brands(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
CONSTRAINT fk_logistics_info
|
CONSTRAINT fk_logistics_info
|
||||||
FOREIGN KEY(logistics_info_id)
|
FOREIGN KEY(logistics_info_id)
|
||||||
REFERENCES test_logistics_info(id)
|
REFERENCES test_logistics_info(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|||||||
23
sites/test/sql/create/item_locations.sql
Normal file
23
sites/test/sql/create/item_locations.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'cost_layer') THEN
|
||||||
|
CREATE TYPE cost_layer AS (qty FLOAT8, cost FLOAT8);
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS test_item_locations(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
part_id INTEGER NOT NULL,
|
||||||
|
location_id INTEGER NOT NULL,
|
||||||
|
quantity_on_hand FLOAT8 NOT NULL,
|
||||||
|
cost_layers cost_layer[],
|
||||||
|
UNIQUE(part_id, location_id),
|
||||||
|
CONSTRAINT fk_part_id
|
||||||
|
FOREIGN KEY(part_id)
|
||||||
|
REFERENCES test_items(id)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT fk_location_id
|
||||||
|
FOREIGN KEY(location_id)
|
||||||
|
REFERENCES test_locations(id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
@ -1,9 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test_receipt_items (
|
CREATE TABLE IF NOT EXISTS test_receipt_items (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
type VARCHAR(255) NOT NULL,
|
type VARCHAR(255) NOT NULL,
|
||||||
|
receipt_id INTEGER NOT NULL,
|
||||||
barcode VARCHAR(255) NOT NULL,
|
barcode VARCHAR(255) NOT NULL,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
qty FLOAT8 NOT NULL,
|
qty FLOAT8 NOT NULL,
|
||||||
data JSONB,
|
data JSONB,
|
||||||
status VARCHAR (64)
|
status VARCHAR (64),
|
||||||
|
CONSTRAINT fk_receipt
|
||||||
|
FOREIGN KEY(receipt_id)
|
||||||
|
REFERENCES test_receipts(id)
|
||||||
);
|
);
|
||||||
@ -1,10 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test_receipts (
|
CREATE TABLE IF NOT EXISTS test_receipts (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
receipt_id INTEGER NOT NULL,
|
receipt_id VARCHAR (32) NOT NULL,
|
||||||
receipt_status VARCHAR (64) NOT NULL,
|
receipt_status VARCHAR (64) NOT NULL,
|
||||||
date_submitted TIMESTAMP NOT NULL,
|
date_submitted TIMESTAMP NOT NULL,
|
||||||
submitted_by INTEGER NOT NULL,
|
submitted_by INTEGER NOT NULL,
|
||||||
vendor_id INTEGER,
|
vendor_id INTEGER,
|
||||||
files JSONB,
|
files JSONB,
|
||||||
UNIQUE(receipt_id)
|
UNIQUE(receipt_id),
|
||||||
|
CONSTRAINT fk_vendor
|
||||||
|
FOREIGN KEY(vendor_id)
|
||||||
|
REFERENCES test_vendors(id)
|
||||||
);
|
);
|
||||||
@ -1,8 +1,8 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test_vendors (
|
CREATE TABLE IF NOT EXISTS test_vendors (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
vendor_name VARCHAR(255) NOT NULL,
|
||||||
address VARCHAR(255),
|
vendor_address VARCHAR(255),
|
||||||
creation_date TIMESTAMP NOT NULL,
|
creation_date TIMESTAMP NOT NULL,
|
||||||
created_by TIMESTAMP NOT NULL,
|
created_by INTEGER NOT NULL,
|
||||||
phone_number VARCHAR(32)
|
phone_number VARCHAR(32)
|
||||||
);
|
);
|
||||||
1
sites/test/sql/drop/item_locations.sql
Normal file
1
sites/test/sql/drop/item_locations.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE test_item_locations CASCADE;
|
||||||
3
sites/test/sql/unique/Insert_transaction.sql
Normal file
3
sites/test/sql/unique/Insert_transaction.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
INSERT INTO test_transactions
|
||||||
|
(timestamp, logistics_info_id, barcode, name, transaction_type, quantity, description, user_id, data)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s);
|
||||||
3
sites/test/sql/unique/logistics_transactions.sql
Normal file
3
sites/test/sql/unique/logistics_transactions.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
UPDATE test_logistics_info
|
||||||
|
SET quantity_on_hand = %s, location_data = %s
|
||||||
|
WHERE id = %s;
|
||||||
45
sites/test/sql/unique/select_item_all_barcode.sql
Normal file
45
sites/test/sql/unique/select_item_all_barcode.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
SELECT * FROM test_items
|
||||||
|
LEFT JOIN test_logistics_info ON test_items.logistics_info_id = test_logistics_info.id
|
||||||
|
LEFT JOIN test_item_info ON test_items.item_info_id = test_item_info.id
|
||||||
|
LEFT JOIN test_food_info ON test_items.food_info_id = test_food_info.id
|
||||||
|
WHERE test_items.barcode=%s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
00 - item_id
|
||||||
|
01 - barcode
|
||||||
|
02 - item_name
|
||||||
|
03 - brand (id)
|
||||||
|
04 - description
|
||||||
|
05 - tags
|
||||||
|
06 - links
|
||||||
|
07 - item_info_id
|
||||||
|
08 - logistics_info_id
|
||||||
|
09 - food_info_id
|
||||||
|
10 - row_type
|
||||||
|
11 - item_type
|
||||||
|
12 - search_string
|
||||||
|
13 - logistics_info_id
|
||||||
|
14 - barcode
|
||||||
|
15 - primary_location
|
||||||
|
16 - auto_issue_location
|
||||||
|
17 - dynamic_locations
|
||||||
|
18 - location_data
|
||||||
|
19 - quantity_on_hand
|
||||||
|
20 - item_info_id
|
||||||
|
21 - barcode
|
||||||
|
22 - linked_items
|
||||||
|
23 - shopping_lists
|
||||||
|
24 - recipes
|
||||||
|
25 - groups
|
||||||
|
26 - packaging
|
||||||
|
27 - uom
|
||||||
|
28 - cost
|
||||||
|
29 - safety_stock
|
||||||
|
30 - lead_time_days
|
||||||
|
31 - ai_pick
|
||||||
|
32 - food_info_id
|
||||||
|
33 - food_groups
|
||||||
|
34 - ingrediants
|
||||||
|
35 - nutrients
|
||||||
|
36 - expires
|
||||||
|
*/
|
||||||
3
sites/test/sql/unique/set_location_data.sql
Normal file
3
sites/test/sql/unique/set_location_data.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
UPDATE test_locations
|
||||||
|
SET items = %s
|
||||||
|
WHERE id = %s;
|
||||||
@ -1,9 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_receipt_items (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
type VARCHAR(255) NOT NULL,
|
|
||||||
barcode VARCHAR(255) NOT NULL,
|
|
||||||
name VARCHAR(255) NOT NULL,
|
|
||||||
qty FLOAT8 NOT NULL,
|
|
||||||
data JSONB,
|
|
||||||
status VARCHAR (64)
|
|
||||||
);
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_receipts (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
receipt_id INTEGER NOT NULL,
|
|
||||||
receipt_status VARCHAR (64) NOT NULL,
|
|
||||||
date_submitted TIMESTAMP NOT NULL,
|
|
||||||
submitted_by INTEGER NOT NULL,
|
|
||||||
vendor_id INTEGER,
|
|
||||||
files JSONB,
|
|
||||||
UNIQUE(receipt_id)
|
|
||||||
);
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS test2_vendors (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
name VARCHAR(255) NOT NULL,
|
|
||||||
address VARCHAR(255),
|
|
||||||
creation_date TIMESTAMP NOT NULL,
|
|
||||||
created_by TIMESTAMP NOT NULL,
|
|
||||||
phone_number VARCHAR(32)
|
|
||||||
);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_brands CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_food_info CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_groups CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_item_info CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_items CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_itemlinks CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_locations CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_logistics_info CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_receipt_items CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_receipts CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_recipes CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_shopping_lists CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_transactions CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_vendors CASCADE;
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE test2_zones CASCADE;
|
|
||||||
@ -4,6 +4,7 @@ async function fetchItem() {
|
|||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
data = await response.json();
|
data = await response.json();
|
||||||
item = data.item;
|
item = data.item;
|
||||||
|
linked_items = data.linked_items;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function fetchZones() {
|
async function fetchZones() {
|
||||||
@ -91,7 +92,6 @@ function updatePrimaryLocation(){
|
|||||||
document.getElementById('primary_location').style = ""
|
document.getElementById('primary_location').style = ""
|
||||||
logistics_info['primary_location'] = `${primary_zone}@${primary_location}`
|
logistics_info['primary_location'] = `${primary_zone}@${primary_location}`
|
||||||
};
|
};
|
||||||
console.log(logistics_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateIssueLocation(){
|
function updateIssueLocation(){
|
||||||
@ -108,54 +108,45 @@ function updateIssueLocation(){
|
|||||||
|
|
||||||
function updateEntryType(){
|
function updateEntryType(){
|
||||||
updated['row_type'] = document.getElementById('entry_type').value;
|
updated['row_type'] = document.getElementById('entry_type').value;
|
||||||
console.log(updated)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateItemType(){
|
function updateItemType(){
|
||||||
updated['item_type'] = document.getElementById('item_type').value;
|
updated['item_type'] = document.getElementById('item_type').value;
|
||||||
console.log(updated)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updatePackaging(){
|
function updatePackaging(){
|
||||||
let packaging = document.getElementById('packaging').value;
|
let packaging = document.getElementById('packaging').value;
|
||||||
item_info['packaging'] = packaging;
|
item_info['packaging'] = packaging;
|
||||||
console.log(item_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateUOM(){
|
function updateUOM(){
|
||||||
let uom = document.getElementById('uom').value;
|
let uom = document.getElementById('uom').value;
|
||||||
item_info['uom'] = uom;
|
item_info['uom'] = uom;
|
||||||
console.log(item_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateCost(){
|
function updateCost(){
|
||||||
let cost = document.getElementById('cost').value;
|
let cost = document.getElementById('cost').value;
|
||||||
item_info['cost'] = parseFloat(cost);
|
item_info['cost'] = parseFloat(cost);
|
||||||
console.log(item_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateSafetyStock(){
|
function updateSafetyStock(){
|
||||||
let safety_stock = document.getElementById('safety_stock').value;
|
let safety_stock = document.getElementById('safety_stock').value;
|
||||||
item_info['safety_stock'] = parseFloat(safety_stock);
|
item_info['safety_stock'] = parseFloat(safety_stock);
|
||||||
console.log(item_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateLeadTimeDays(){
|
function updateLeadTimeDays(){
|
||||||
let lead_time_days = document.getElementById('lead_time_days').value;
|
let lead_time_days = document.getElementById('lead_time_days').value;
|
||||||
item_info['lead_time_days'] = parseFloat(lead_time_days);
|
item_info['lead_time_days'] = parseFloat(lead_time_days);
|
||||||
console.log(item_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateAiPickable(){
|
function updateAiPickable(){
|
||||||
let ai_pick = document.getElementById('ai_pickable');
|
let ai_pick = document.getElementById('ai_pickable');
|
||||||
item_info['ai_pick'] = ai_pick.checked;
|
item_info['ai_pick'] = ai_pick.checked;
|
||||||
console.log(item_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateExpires(){
|
function updateExpires(){
|
||||||
let expires = document.getElementById('expires');
|
let expires = document.getElementById('expires');
|
||||||
food_info['expires'] = expires.checked;
|
food_info['expires'] = expires.checked;
|
||||||
console.log(food_info)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateNutrients(){
|
function updateNutrients(){
|
||||||
@ -177,10 +168,7 @@ function updateNutrients(){
|
|||||||
fibers: document.getElementById('fibers').value,
|
fibers: document.getElementById('fibers').value,
|
||||||
fibers_unit: document.getElementById('fibers_unit').value
|
fibers_unit: document.getElementById('fibers_unit').value
|
||||||
};
|
};
|
||||||
console.log(nutrients)
|
|
||||||
nutrients_changed = true;
|
nutrients_changed = true;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveItem() {
|
async function saveItem() {
|
||||||
@ -202,8 +190,6 @@ async function saveItem() {
|
|||||||
updated['links'] = links;
|
updated['links'] = links;
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`going into fetch ${logistics_info}`)
|
|
||||||
|
|
||||||
await fetch(`/updateItem`, {
|
await fetch(`/updateItem`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
276
static/receiptHandler.js
Normal file
276
static/receiptHandler.js
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
let receipt;
|
||||||
|
let receipt_items;
|
||||||
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
|
await updateReceipt();
|
||||||
|
|
||||||
|
var elems = document.querySelectorAll('.modal');
|
||||||
|
var instances = M.Modal.init(elems, {
|
||||||
|
// specify options here
|
||||||
|
});
|
||||||
|
var elems = document.getElementById('vendor_address');
|
||||||
|
var instances = M.CharacterCounter.init(elems);
|
||||||
|
var elems = document.querySelectorAll('.tooltipped');
|
||||||
|
var instances = M.Tooltip.init(elems, {
|
||||||
|
// specify options here
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function updateReceipt(){
|
||||||
|
await fetchReceipt();
|
||||||
|
await propagateInfo();
|
||||||
|
await propagateItems();
|
||||||
|
};
|
||||||
|
|
||||||
|
async function fetchReceiptItem(index){
|
||||||
|
const url = new URL('/getReceiptItem', window.location.origin);
|
||||||
|
url.searchParams.append('index', index);
|
||||||
|
const response = await fetch(url);
|
||||||
|
data = await response.json();
|
||||||
|
console.log(data)
|
||||||
|
receipt_item = data.receipt_item;
|
||||||
|
return receipt_item
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchReceipt(){
|
||||||
|
const url = new URL('/getReceipt', window.location.origin);
|
||||||
|
url.searchParams.append('id', receipt_id);
|
||||||
|
const response = await fetch(url);
|
||||||
|
data = await response.json();
|
||||||
|
receipt = data.receipt;
|
||||||
|
receipt_items = data.receipt_items
|
||||||
|
};
|
||||||
|
|
||||||
|
async function propagateInfo(){
|
||||||
|
document.getElementById('receipt_id').innerHTML = receipt[1]
|
||||||
|
document.getElementById('database_id').innerHTML = `Database ID: ${receipt[0]}`
|
||||||
|
document.getElementById('status').innerHTML = receipt[2]
|
||||||
|
document.getElementById('created').innerHTML = receipt[3]
|
||||||
|
document.getElementById('vendor_name').value = receipt[8]
|
||||||
|
document.getElementById('vendor_number').value = receipt[12]
|
||||||
|
document.getElementById('vendor_address').value = receipt[9]
|
||||||
|
M.Forms.textareaAutoResize(document.getElementById('vendor_address'));
|
||||||
|
};
|
||||||
|
|
||||||
|
async function propagateItems(){
|
||||||
|
const table = document.getElementById('item_table')
|
||||||
|
while (table.rows.length > 1) {
|
||||||
|
table.deleteRow(1);
|
||||||
|
};
|
||||||
|
let reference_state = 1
|
||||||
|
receipt_items.sort((a, b) => a[0] - b[0])
|
||||||
|
for (let i = 0; i < receipt_items.length; i++){
|
||||||
|
var row = table.insertRow();
|
||||||
|
if (receipt_items[i][7] == "Resolved" || receipt_items[i][7] == "Voided"){
|
||||||
|
row.classList.add("disabled-row")
|
||||||
|
}
|
||||||
|
|
||||||
|
var row_type = row.insertCell();
|
||||||
|
var row_barcode = row.insertCell();
|
||||||
|
var row_name = row.insertCell();
|
||||||
|
var row_qty = row.insertCell();
|
||||||
|
var row_cost = row.insertCell();
|
||||||
|
var row_status = row.insertCell();
|
||||||
|
|
||||||
|
row_type.innerHTML = receipt_items[i][1]
|
||||||
|
row_barcode.innerHTML = receipt_items[i][3]
|
||||||
|
row_name.innerHTML = receipt_items[i][4]
|
||||||
|
row_qty.innerHTML = receipt_items[i][5]
|
||||||
|
row_cost.innerHTML = receipt_items[i][6][28]
|
||||||
|
row_status.innerHTML = receipt_items[i][7]
|
||||||
|
|
||||||
|
if ((reference_state % 2) == 0){
|
||||||
|
row.classList.add('green')
|
||||||
|
row.classList.add('lighten-5')
|
||||||
|
}
|
||||||
|
row.classList.add("custom_row")
|
||||||
|
row.addEventListener('click', function(){
|
||||||
|
modify_item(receipt_items[i][0])
|
||||||
|
})
|
||||||
|
reference_state++
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function modify_item(index){
|
||||||
|
console.log(index)
|
||||||
|
item = await fetchReceiptItem(index)
|
||||||
|
console.log(item)
|
||||||
|
const modal = document.getElementById("modify_item")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
document.getElementById('item_barcode').value = item[3]
|
||||||
|
document.getElementById('item_database_id').value = item[0]
|
||||||
|
document.getElementById('item_type').value = item[1]
|
||||||
|
document.getElementById('item_name').value = item[4]
|
||||||
|
document.getElementById('item_qty').value = item[5]
|
||||||
|
document.getElementById('item_cost').value = item[6][28]
|
||||||
|
instance.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveItem(){
|
||||||
|
let index = document.getElementById('item_database_id').value
|
||||||
|
console.log(index)
|
||||||
|
const url = new URL('/saveReceiptItem', window.location.origin);
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
index: index,
|
||||||
|
cost: parseFloat(document.getElementById('item_cost').value),
|
||||||
|
qty: parseFloat(document.getElementById('item_qty').value),
|
||||||
|
barcode: document.getElementById('item_barcode').value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await updateReceipt();
|
||||||
|
const modal = document.getElementById("modify_item")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
instance.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function deleteItem(){
|
||||||
|
let index = document.getElementById('item_database_id').value
|
||||||
|
const url = new URL('/deleteReceiptItem', window.location.origin);
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
index: index
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await updateReceipt();
|
||||||
|
const modal = document.getElementById("modify_item")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
instance.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function voidItem(){
|
||||||
|
let index = document.getElementById('item_database_id').value
|
||||||
|
const url = new URL('/voidReceiptItem', window.location.origin);
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
index: index
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await updateReceipt();
|
||||||
|
const modal = document.getElementById("modify_item")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
instance.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function resolveItem(){
|
||||||
|
let index = document.getElementById('item_database_id').value
|
||||||
|
console.log(index)
|
||||||
|
await saveItem()
|
||||||
|
const url = new URL('/resolveReceiptItem', window.location.origin);
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
index: index
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await updateReceipt();
|
||||||
|
const modal = document.getElementById("modify_item")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
instance.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchVendors(){
|
||||||
|
const url = new URL('/getVendors', window.location.origin);
|
||||||
|
const response = await fetch(url);
|
||||||
|
data = await response.json();
|
||||||
|
var vendors = data.vendors;
|
||||||
|
return vendors
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectVendor(index){
|
||||||
|
const url = new URL('/saveReceipt', window.location.origin);
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
vendor_index: index,
|
||||||
|
receipt_index: receipt[0]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await updateReceipt();
|
||||||
|
const modal = document.getElementById("vendors")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
instance.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function populateVendors() {
|
||||||
|
const modal = document.getElementById("vendors")
|
||||||
|
var instance = M.Modal.getInstance(modal);
|
||||||
|
vendors = await fetchVendors()
|
||||||
|
console.log(vendors)
|
||||||
|
instance.open()
|
||||||
|
|
||||||
|
var table = document.getElementById("vendors_table")
|
||||||
|
while (table.rows.length > 0) {
|
||||||
|
table.deleteRow(0);
|
||||||
|
}
|
||||||
|
const header = table.createTHead();
|
||||||
|
const row = header.insertRow(0);
|
||||||
|
|
||||||
|
var header_database_id = row.insertCell();
|
||||||
|
header_database_id.classList.add('center')
|
||||||
|
var header_name = row.insertCell();
|
||||||
|
header_name.classList.add('center')
|
||||||
|
var header_address = row.insertCell();
|
||||||
|
header_address.classList.add('center')
|
||||||
|
var header_number = row.insertCell();
|
||||||
|
header_number.classList.add('center')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
header_database_id.innerHTML = `ID`;
|
||||||
|
header_name.innerHTML = `Name`;
|
||||||
|
header_address.innerHTML = `Address`;
|
||||||
|
header_number.innerHTML = `Phone Number`;
|
||||||
|
|
||||||
|
let colorstate = 1;
|
||||||
|
for (let i = 0; i < vendors.length; i++){
|
||||||
|
|
||||||
|
var vendor_row = table.insertRow();
|
||||||
|
|
||||||
|
var row_id = vendor_row.insertCell();
|
||||||
|
row_id.classList.add('center');
|
||||||
|
var row_name = vendor_row.insertCell();
|
||||||
|
row_name.classList.add('center');
|
||||||
|
var row_address = vendor_row.insertCell();
|
||||||
|
row_address.classList.add('center');
|
||||||
|
var row_number = vendor_row.insertCell();
|
||||||
|
row_number.classList.add('center');
|
||||||
|
|
||||||
|
row_id.innerHTML = vendors[i][0];
|
||||||
|
row_name.innerHTML = vendors[i][1];
|
||||||
|
row_address.innerHTML = vendors[i][2];
|
||||||
|
row_number.innerHTML = vendors[i][5];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ((colorstate % 2) == 0){
|
||||||
|
vendor_row.classList.add('green')
|
||||||
|
vendor_row.classList.add('lighten-5')
|
||||||
|
}
|
||||||
|
vendor_row.classList.add("custom_row")
|
||||||
|
vendor_row.addEventListener('click', function(){
|
||||||
|
selectVendor(vendors[i][0])
|
||||||
|
})
|
||||||
|
colorstate++
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,9 @@ let end_page;
|
|||||||
let limit = 50
|
let limit = 50
|
||||||
let search_text = ""
|
let search_text = ""
|
||||||
let zones;
|
let zones;
|
||||||
|
let barcode = ""
|
||||||
|
let item_name = ""
|
||||||
|
let logistics_info_id = 0
|
||||||
|
|
||||||
async function setupZones() {
|
async function setupZones() {
|
||||||
let primary_zone = document.getElementById('zone')
|
let primary_zone = document.getElementById('zone')
|
||||||
@ -22,7 +25,6 @@ async function fetchZones() {
|
|||||||
zones = data.zones;
|
zones = data.zones;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
async function fetchLocations(zone) {
|
async function fetchLocations(zone) {
|
||||||
const url = new URL('/getLocations', window.location.origin);
|
const url = new URL('/getLocations', window.location.origin);
|
||||||
url.searchParams.append('zone', zone);
|
url.searchParams.append('zone', zone);
|
||||||
@ -79,6 +81,8 @@ async function fetchItems(){
|
|||||||
document.getElementById('forward').classList.remove("disabled")
|
document.getElementById('forward').classList.remove("disabled")
|
||||||
document.getElementById('forward').classList.add("waves-effect")
|
document.getElementById('forward').classList.add("waves-effect")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is to populate the item table!
|
||||||
var table = document.getElementById("item_table")
|
var table = document.getElementById("item_table")
|
||||||
while (table.rows.length > 0) {
|
while (table.rows.length > 0) {
|
||||||
table.deleteRow(0);
|
table.deleteRow(0);
|
||||||
@ -130,17 +134,87 @@ async function fetchItems(){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function populateLocations(locations) {
|
||||||
|
console.log(locations)
|
||||||
|
var table = document.getElementById("location_table")
|
||||||
|
while (table.rows.length > 0) {
|
||||||
|
table.deleteRow(0);
|
||||||
|
}
|
||||||
|
const header = table.createTHead();
|
||||||
|
const row = header.insertRow(0);
|
||||||
|
|
||||||
|
var header_database_id = row.insertCell();
|
||||||
|
header_database_id.classList.add('center')
|
||||||
|
var header_barcode = row.insertCell();
|
||||||
|
header_barcode.classList.add('center')
|
||||||
|
var header_name = row.insertCell();
|
||||||
|
header_name.classList.add('center')
|
||||||
|
|
||||||
|
header_database_id.innerHTML = `Zone`;
|
||||||
|
header_barcode.innerHTML = `Location`;
|
||||||
|
header_name.innerHTML = `QOH`;
|
||||||
|
|
||||||
|
let colorstate = 1;
|
||||||
|
for (let key in locations){
|
||||||
|
console.log(key);
|
||||||
|
|
||||||
|
var location_row = table.insertRow();
|
||||||
|
|
||||||
|
var row_zone = location_row.insertCell();
|
||||||
|
row_zone.classList.add('center');
|
||||||
|
var row_location = location_row.insertCell();
|
||||||
|
row_location.classList.add('center');
|
||||||
|
var row_qoh = location_row.insertCell();
|
||||||
|
row_qoh.classList.add('center');
|
||||||
|
|
||||||
|
let r_location = key.split("@");
|
||||||
|
|
||||||
|
row_zone.innerHTML = r_location[0];
|
||||||
|
row_location.innerHTML = r_location[1];
|
||||||
|
row_qoh.innerHTML = locations[key];
|
||||||
|
|
||||||
|
|
||||||
|
if ((colorstate % 2) == 0){
|
||||||
|
location_row.classList.add('grey')
|
||||||
|
location_row.classList.add('lighten-5')
|
||||||
|
}
|
||||||
|
location_row.classList.add("custom_row")
|
||||||
|
location_row.addEventListener('click', function(){
|
||||||
|
clickRowLocation(r_location)
|
||||||
|
})
|
||||||
|
colorstate++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function clickRow(database_id){
|
async function clickRow(database_id){
|
||||||
let item = await fetchItem(database_id);
|
let item = await fetchItem(database_id);
|
||||||
await populateFields(item)
|
await populateFields(item)
|
||||||
|
await populateLocations(item[18])
|
||||||
|
let modal = document.getElementById("item_modal")
|
||||||
|
var instance = M.Modal.getInstance(modal)
|
||||||
|
instance.close()
|
||||||
|
};
|
||||||
|
|
||||||
|
async function clickRowLocation(location){
|
||||||
|
console.log(location)
|
||||||
|
let modal = document.getElementById("locations")
|
||||||
|
var instance = M.Modal.getInstance(modal)
|
||||||
|
await setLocation(location[0], location[1])
|
||||||
|
instance.close()
|
||||||
};
|
};
|
||||||
|
|
||||||
async function populateFields(item){
|
async function populateFields(item){
|
||||||
|
barcode = item[1]
|
||||||
|
item_name = item[2]
|
||||||
|
logistics_info_id = item[8]
|
||||||
document.getElementById("database_id").value = item[0];
|
document.getElementById("database_id").value = item[0];
|
||||||
|
document.getElementById("database_id").style = "";
|
||||||
document.getElementById("barcode").value = item[1];
|
document.getElementById("barcode").value = item[1];
|
||||||
|
document.getElementById("barcode").style = "";
|
||||||
document.getElementById("name").value = item[2];
|
document.getElementById("name").value = item[2];
|
||||||
document.getElementById("QOH").value = item[19];
|
document.getElementById("QOH").value = item[19];
|
||||||
|
document.getElementById("UOM").value = item[27];
|
||||||
|
document.getElementById("transaction_cost").value = item[28];
|
||||||
|
|
||||||
let location = item[16].split('@')
|
let location = item[16].split('@')
|
||||||
await setLocation(location[0], location[1])
|
await setLocation(location[0], location[1])
|
||||||
@ -148,8 +222,10 @@ async function populateFields(item){
|
|||||||
|
|
||||||
async function setLocation(zone, location){
|
async function setLocation(zone, location){
|
||||||
document.getElementById('zone').value = zone
|
document.getElementById('zone').value = zone
|
||||||
|
document.getElementById('zone').style = ""
|
||||||
await loadLocations()
|
await loadLocations()
|
||||||
document.getElementById('location').value = location
|
document.getElementById('location').value = location
|
||||||
|
document.getElementById('location').style = ""
|
||||||
};
|
};
|
||||||
|
|
||||||
async function fetchItem(database_id){
|
async function fetchItem(database_id){
|
||||||
@ -160,6 +236,87 @@ async function fetchItem(database_id){
|
|||||||
return data.item;
|
return data.item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateSubmit(){
|
||||||
|
var checked = true;
|
||||||
|
let database_id = document.getElementById('database_id')
|
||||||
|
let barcode = document.getElementById("barcode")
|
||||||
|
let zone = document.getElementById('zone')
|
||||||
|
let loc = document.getElementById('location')
|
||||||
|
let trans_type = document.getElementById("trans_type")
|
||||||
|
let qty = document.getElementById('transaction_quantity')
|
||||||
|
|
||||||
|
if (database_id.value == ""){
|
||||||
|
database_id.style = "border-color: red;"
|
||||||
|
checked = false;
|
||||||
|
} else {
|
||||||
|
database_id.style = ""
|
||||||
|
}
|
||||||
|
if (barcode.value == ""){
|
||||||
|
barcode.style = "border-color: red;"
|
||||||
|
checked = false;
|
||||||
|
} else {
|
||||||
|
barcode.style = ""
|
||||||
|
}
|
||||||
|
if (trans_type.value == ""){
|
||||||
|
trans_type.style = "border-color: red;"
|
||||||
|
checked = false;
|
||||||
|
} else {
|
||||||
|
trans_type.style = ""
|
||||||
|
}
|
||||||
|
if (parseFloat(qty.value) == 0.0 || Number.isNaN(parseFloat(qty.value))){
|
||||||
|
qty.style = "border-color: red;"
|
||||||
|
checked = false;
|
||||||
|
}
|
||||||
|
if (zone.value == ""){
|
||||||
|
zone.style = "border-color: red;"
|
||||||
|
checked = false;
|
||||||
|
}
|
||||||
|
if (loc.value == ""){
|
||||||
|
loc.style = "border-color: red;"
|
||||||
|
checked = false;
|
||||||
|
} else {
|
||||||
|
loc.style = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTransaction() {
|
||||||
|
let zone = document.getElementById('zone').value
|
||||||
|
let loc = document.getElementById('location').value
|
||||||
|
let location = `${zone}@${loc}`
|
||||||
|
let barcode = document.getElementById("barcode").value
|
||||||
|
let trans_type = document.getElementById("trans_type").value
|
||||||
|
let trans_cost = parseFloat(document.getElementById("transaction_cost").value)
|
||||||
|
let qty = parseFloat(document.getElementById('transaction_quantity').value)
|
||||||
|
|
||||||
|
var result = validateSubmit();
|
||||||
|
|
||||||
|
console.log(result)
|
||||||
|
if (result === true){
|
||||||
|
fetch(`/transact`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
logistics_info_id: logistics_info_id,
|
||||||
|
barcode: barcode,
|
||||||
|
name: item_name,
|
||||||
|
location: location,
|
||||||
|
qty: qty,
|
||||||
|
trans_type: trans_type,
|
||||||
|
trans_cost: trans_cost
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
M.toast({text: 'Transaction Complete!'})
|
||||||
|
document.getElementById('transaction_quantity').value = "";
|
||||||
|
} else {
|
||||||
|
M.toast({text: 'Please ensure your receipt is filled out.'})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('forward').addEventListener('click', async function(){
|
document.getElementById('forward').addEventListener('click', async function(){
|
||||||
current_page++
|
current_page++
|
||||||
await fetchItems()
|
await fetchItems()
|
||||||
|
|||||||
@ -35,7 +35,6 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.5; /* or your desired degree of transparency */
|
opacity: 0.5; /* or your desired degree of transparency */
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<ul id='dropdown1' class='dropdown-content'>
|
<ul id='dropdown1' class='dropdown-content'>
|
||||||
{% for site in sites %}
|
{% for site in sites %}
|
||||||
@ -58,6 +57,7 @@
|
|||||||
<li class="active"><a href="/items">Site Items</a></li>
|
<li class="active"><a href="/items">Site Items</a></li>
|
||||||
<li><a href="/groups">Site Groups</a></li>
|
<li><a href="/groups">Site Groups</a></li>
|
||||||
<li><a href="/shopping-lists">Site Shopping Lists</a></li>
|
<li><a href="/shopping-lists">Site Shopping Lists</a></li>
|
||||||
|
<li><a href="/receipts">Site Receipts</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<body>
|
<body>
|
||||||
<div class="container section" style="padding-bottom: 72px;">
|
<div class="container section" style="padding-bottom: 72px;">
|
||||||
@ -92,6 +92,12 @@
|
|||||||
<span>Non Zero Items</span>
|
<span>Non Zero Items</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col s6 m4 l2">
|
||||||
|
<label>
|
||||||
|
<input name="group3" type="radio" onclick="changeView(2)"/>
|
||||||
|
<span>Hidden Items</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div class="col s12 divider"></div>
|
<div class="col s12 divider"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- This is for sorting values -->
|
<!-- This is for sorting values -->
|
||||||
@ -176,7 +182,6 @@
|
|||||||
<li id="current_page" style="padding-top: 7px; padding-left: 5px; padding-right: 5px; font-size: 18px;">page_number</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="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>
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -322,8 +327,6 @@
|
|||||||
url.searchParams.append('sort_order', sort_order);
|
url.searchParams.append('sort_order', sort_order);
|
||||||
url.searchParams.append('view', view);
|
url.searchParams.append('view', view);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await fetch(url)
|
await fetch(url)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
|||||||
@ -30,6 +30,10 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.5; /* or your desired degree of transparency */
|
opacity: 0.5; /* or your desired degree of transparency */
|
||||||
}
|
}
|
||||||
|
.custom_row:hover{
|
||||||
|
background-color: rgb(230, 230, 230) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<ul id='dropdown1' class='dropdown-content'>
|
<ul id='dropdown1' class='dropdown-content'>
|
||||||
{% for site in sites %}
|
{% for site in sites %}
|
||||||
@ -148,7 +152,7 @@
|
|||||||
<li class="tab col s3"><a class="active" href="#item_info">Item Info</a></li>
|
<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="#food_info">Food Info</a></li>
|
||||||
<li class="tab col s3"><a href="#logistics_info">Logistics 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>
|
<li id="linked_items_tab" class="tab col s3 disabled"><a href="#linked_items">Linked Items</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="item_info" class="col s12 grey lighten-5 p-3">
|
<div id="item_info" class="col s12 grey lighten-5 p-3">
|
||||||
@ -441,7 +445,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="linked_items" class="col s12 disabled">Linked Items</div>
|
<div id="linked_items" class="col s12">
|
||||||
|
<div class="row" style="gap: 10px; padding-top: 10px;">
|
||||||
|
<div class="col s12 green lighten-4" style="border-radius: 10px;">
|
||||||
|
<h5 class="center">Linked Items</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="card-panel green z-depth-0 lighten-5">
|
||||||
|
<span class="black-text">If an item is a linked item then it possesses other barcodes under its umbrella. The system will
|
||||||
|
use this to ensure that as things are coming in an dout of the system at the right barcode. A good example is if you want
|
||||||
|
to track cans of pop and not cases. You would link the case to the can barcode so when the case is received it will been
|
||||||
|
adjusted in at the can barcode.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<button class="btn btn-flat green lighten-4" onclick="openLinkedItems()">Add Item</button>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<table class="" id="linked_items_table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Linked Item</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -476,7 +510,41 @@
|
|||||||
<button onclick="addLink()" class="waves-effect green lighten-4 btn-flat">Add</button>
|
<button onclick="addLink()" class="waves-effect green lighten-4 btn-flat">Add</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Item Selection Modal -->
|
||||||
|
<div id="item_modal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="row" style="gap: 5px;">
|
||||||
|
<div class="col s12">
|
||||||
|
<h4>Add Items...</h4>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="card-panel grey lighten-4 z-depth-0">
|
||||||
|
<span class="black-text"> Here is where you can search, add, and remove items from this group by checking or unchecking the items below. You can select
|
||||||
|
multiple at a time or simply one. Utilize the search bar to filter down quickly to items you need or simply scroll to your hearts content.
|
||||||
|
<br><br>
|
||||||
|
<b>WARNING:</b> clicking the checkbox will not save the changes right off the bat! You <b>MUST</b> click the Update Items button!
|
||||||
|
<br><br>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col s9 m6 offset-m3 input-field outlined align-center">
|
||||||
|
<i class="material-icons prefix">search</i>
|
||||||
|
<input style="border-radius: 20px; border: 1px solid #ccc;" id="search" name="search" type="search" placeholder="Search Items" value="">
|
||||||
|
</div>
|
||||||
|
<div class="col s12 center">
|
||||||
|
<a id="item_back" class="btn icon-left purple lighten-4 black-text z-depth-0"><i class="material-icons">chevron_left</i></a>
|
||||||
|
<a id="current_page_item" class="" style="color: black;">0/0</a>
|
||||||
|
<a id="item_forward" class="btn icon-right purple lighten-4 black-text z-depth-0"><i class="material-icons">chevron_right</i></a>
|
||||||
|
</div>
|
||||||
|
<div class="divider col s12"></div>
|
||||||
|
<div id="table-container" class="col s12">
|
||||||
|
<table id="item_table">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="fixed-action-btn show-on-med-and-up hide-on-small-only">
|
<div class="fixed-action-btn show-on-med-and-up hide-on-small-only">
|
||||||
<button class="btn-floating btn-large" onclick="saveItem()">
|
<button class="btn-floating btn-large" onclick="saveItem()">
|
||||||
<i class="large material-icons">save</i>
|
<i class="large material-icons">save</i>
|
||||||
@ -488,6 +556,7 @@
|
|||||||
|
|
||||||
const item_id = {{id|tojson}}
|
const item_id = {{id|tojson}}
|
||||||
let item;
|
let item;
|
||||||
|
let linked_items;
|
||||||
var reference_state = 1
|
var reference_state = 1
|
||||||
let zones;
|
let zones;
|
||||||
let primary_locations;
|
let primary_locations;
|
||||||
@ -557,8 +626,7 @@
|
|||||||
await propagateInfo()
|
await propagateInfo()
|
||||||
await propagateLinks()
|
await propagateLinks()
|
||||||
await populateLocations()
|
await populateLocations()
|
||||||
console.log(updated)
|
await propagateLinkedItems()
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function propagateInfo(){
|
async function propagateInfo(){
|
||||||
@ -595,6 +663,9 @@
|
|||||||
nutrients_changed = false;
|
nutrients_changed = false;
|
||||||
links_changed = false;
|
links_changed = false;
|
||||||
|
|
||||||
|
if (item[10] == "linked"){
|
||||||
|
document.getElementById('linked_items_tab').classList.remove('disabled')
|
||||||
|
}
|
||||||
M.toast({html: "Item has been loaded successfully!", classes: "rounded green lighten-4 black-text flow-text"});
|
M.toast({html: "Item has been loaded successfully!", classes: "rounded green lighten-4 black-text flow-text"});
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -716,6 +787,26 @@
|
|||||||
document.getElementById('fibers_unit').value = nutrients['fibers_unit']
|
document.getElementById('fibers_unit').value = nutrients['fibers_unit']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function propagateLinkedItems(){
|
||||||
|
var table = document.getElementById("linked_items_table")
|
||||||
|
let colorstate = 1
|
||||||
|
for (let i = 0; i < linked_items.length; i++){
|
||||||
|
var row = table.insertRow();
|
||||||
|
|
||||||
|
var row_item = row.insertCell();
|
||||||
|
var row_buttons = row.insertCell();
|
||||||
|
|
||||||
|
row_item.innerHTML = `${linked_items[i][1]} - ${linked_items[i][2]}`
|
||||||
|
row_buttons.innerHTML = `<a class="btn btn-flat green lighten-4 right" href="/itemlink/${linked_items[i][0]}" style="margin-left: 5px;">Edit</a><button class="btn btn-flat red lighten-4 right" onclick="deleteLink(${linked_items[i][0]})">Delete</button>`
|
||||||
|
|
||||||
|
if ((colorstate % 2) == 0){
|
||||||
|
row.classList.add('green')
|
||||||
|
row.classList.add('lighten-5')
|
||||||
|
}
|
||||||
|
colorstate++
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function populateReferences(references, reference_type){
|
function populateReferences(references, reference_type){
|
||||||
var table = document.getElementById("reference_table")
|
var table = document.getElementById("reference_table")
|
||||||
for (let i = 0; i < references.length; i++){
|
for (let i = 0; i < references.length; i++){
|
||||||
@ -734,6 +825,124 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var current_page_item = 1
|
||||||
|
var endpage_item = 10
|
||||||
|
var limit_item = 50
|
||||||
|
var search_text_item = ""
|
||||||
|
|
||||||
|
async function fetchItems(){
|
||||||
|
|
||||||
|
if (current_page_item === 1){
|
||||||
|
document.getElementById('item_back').classList.add("disabled")
|
||||||
|
document.getElementById('item_back').classList.remove("waves-effect")
|
||||||
|
} else {
|
||||||
|
document.getElementById('item_back').classList.remove("disabled")
|
||||||
|
document.getElementById('item_back').classList.add("waves-effect")
|
||||||
|
};
|
||||||
|
|
||||||
|
const url = new URL('/getItems', window.location.origin);
|
||||||
|
url.searchParams.append('page', current_page_item);
|
||||||
|
url.searchParams.append('limit', limit_item);
|
||||||
|
await fetch(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log(data)
|
||||||
|
endpage_item = parseInt(data.end)
|
||||||
|
if (current_page_item === endpage_item){
|
||||||
|
document.getElementById('item_forward').classList.add("disabled")
|
||||||
|
document.getElementById('item_forward').classList.remove("waves-effect")
|
||||||
|
} else {
|
||||||
|
document.getElementById('item_forward').classList.remove("disabled")
|
||||||
|
document.getElementById('item_forward').classList.add("waves-effect")
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is to populate the item table!
|
||||||
|
var table = document.getElementById("item_table")
|
||||||
|
while (table.rows.length > 0) {
|
||||||
|
table.deleteRow(0);
|
||||||
|
}
|
||||||
|
const header = table.createTHead();
|
||||||
|
const row = header.insertRow(0);
|
||||||
|
|
||||||
|
var header_database_id = row.insertCell();
|
||||||
|
header_database_id.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')
|
||||||
|
|
||||||
|
header_database_id.innerHTML = `<b>Database ID</b>`;
|
||||||
|
header_barcode.innerHTML = `<b>Barcode</b>`;
|
||||||
|
header_name.innerHTML = `<b>Product Name</b>`;
|
||||||
|
|
||||||
|
let colorstate = 1;
|
||||||
|
data.items.forEach(item => {
|
||||||
|
var row = table.insertRow();
|
||||||
|
|
||||||
|
var row_id = row.insertCell();
|
||||||
|
row_id.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')
|
||||||
|
|
||||||
|
|
||||||
|
row_id.innerHTML = item[0];
|
||||||
|
row_barcode.innerHTML = item[1];
|
||||||
|
row_name.innerHTML = item[2];
|
||||||
|
|
||||||
|
|
||||||
|
if ((colorstate % 2) == 0){
|
||||||
|
row.classList.add('grey')
|
||||||
|
row.classList.add('lighten-5')
|
||||||
|
}
|
||||||
|
row.classList.add("custom_row")
|
||||||
|
row.addEventListener('click', function(){
|
||||||
|
clickRowItem(item[0])
|
||||||
|
})
|
||||||
|
colorstate++
|
||||||
|
});
|
||||||
|
})
|
||||||
|
document.getElementById("current_page_item").innerHTML = `${String(current_page_item)} / ${String(endpage_item)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openLinkedItems(){
|
||||||
|
var elem = document.getElementById('item_modal')
|
||||||
|
var instance = M.Modal.init(elem)
|
||||||
|
await fetchItems()
|
||||||
|
instance.open()
|
||||||
|
};
|
||||||
|
|
||||||
|
async function clickRowItem(database_id){
|
||||||
|
let linkitem = await fetchLinkedItem(database_id);
|
||||||
|
console.log(item)
|
||||||
|
const url = new URL('/linkItem', window.location.origin);
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
master_index: item[0],
|
||||||
|
sub_index: linkitem[0]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
var elem = document.getElementById('item_modal')
|
||||||
|
var instance = M.Modal.init(elem)
|
||||||
|
instance.close()
|
||||||
|
};
|
||||||
|
|
||||||
|
async function fetchLinkedItem(database_id){
|
||||||
|
const url = new URL('/getItem', window.location.origin);
|
||||||
|
url.searchParams.append('id', database_id);
|
||||||
|
const response = await fetch(url);
|
||||||
|
data = await response.json();
|
||||||
|
return data.item;
|
||||||
|
}
|
||||||
|
|
||||||
async function populateLocations(){
|
async function populateLocations(){
|
||||||
var table = document.getElementById("locations_table")
|
var table = document.getElementById("locations_table")
|
||||||
console.log(item[18])
|
console.log(item[18])
|
||||||
@ -767,6 +976,20 @@
|
|||||||
colorstate++
|
colorstate++
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.getElementById('item_forward').addEventListener('click', async function(){
|
||||||
|
current_page++
|
||||||
|
await fetchItems()
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('item_back').addEventListener('click', async function(){
|
||||||
|
current_page--
|
||||||
|
await fetchItems()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function deleteLink(index){
|
||||||
|
console.log(index)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
70
templates/items/itemlink.html
Normal file
70
templates/items/itemlink.html
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
|
||||||
|
<title>My Pantry</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/css/materialize.min.css" />
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@materializecss/materialize@2.0.3-alpha/dist/js/materialize.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="grey lighten-5">
|
||||||
|
<div class="container col s12">
|
||||||
|
<div class="section">
|
||||||
|
<div id="editLinkedItem" class="row" style="gap: 1em;">
|
||||||
|
<div class="col s12">
|
||||||
|
<a href='{{ proto['referrer'] }}' class="left btn green lighten-4 black-text btn-flat"><i class="material-icons">arrow_back</i></a>
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field">
|
||||||
|
<input id="barcode" type="text" name="barcode" value="" placeholder=" " maxlength="20" disabled />
|
||||||
|
<label for="barcode">Barcode</label>
|
||||||
|
<span class="supporting-text">Item Barcode</span>
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field">
|
||||||
|
<input id="LinkID" type="text" name="LinkID" placeholder=" " value="" maxlength="20" disabled />
|
||||||
|
<label for="LinkID">LinkID</label>
|
||||||
|
<span class="supporting-text">Pantry Item this is linked to.</span>
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field">
|
||||||
|
<input id="conversion" name="conversion" type="text" placeholder=" " value="" maxlength="20" />
|
||||||
|
<label for="conversion">Conversion Factor</label>
|
||||||
|
<span class="supporting-text">Conversion Factor for scanning adjustments.</span>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s12">
|
||||||
|
<textarea id="itemdata" class="materialize-textarea" name="itemdata" placeholder=" "></textarea>
|
||||||
|
<label for="itemdata">Saved Data</label>
|
||||||
|
</div>
|
||||||
|
<div class="divider s12"></div>
|
||||||
|
<div class="col s12">
|
||||||
|
<button class="btn icon-right waves-effect waves-light right" type="submit" name="action">Update</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
const id = {{id|tojson}}
|
||||||
|
let linked_item;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
|
await fetchLinkedItem()
|
||||||
|
await populateForm()
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetchLinkedItem(){
|
||||||
|
const url = new URL('/getLinkedItem', window.location.origin);
|
||||||
|
url.searchParams.append('id', id);
|
||||||
|
const response = await fetch(url);
|
||||||
|
data = await response.json();
|
||||||
|
linked_item = data.linked_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function populateForm(){
|
||||||
|
document.getElementById('barcode').value = linked_item[1];
|
||||||
|
document.getElementById('LinkID').value = linked_item[2];
|
||||||
|
document.getElementById('conversion').value = linked_item[4];
|
||||||
|
document.getElementById('itemdata').value = JSON.stringify(linked_item[3]);
|
||||||
|
M.Forms.textareaAutoResize(document.querySelector('#itemdata'));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
184
templates/receipts/index.html
Normal file
184
templates/receipts/index.html
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
|
||||||
|
<title>My Pantry - Receipts</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>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
.hand-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
[type="radio"]:checked + span:after {
|
||||||
|
border: 2px solid rgb(0 128 0 / 30%); /* Outline color */
|
||||||
|
background-color: rgb(0 128 0 / 30%); /* Fill color */
|
||||||
|
}
|
||||||
|
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" 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 class="active"><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>
|
||||||
|
<li><a href="/receipts">Site Receipts</a></li>
|
||||||
|
</ul>
|
||||||
|
<body>
|
||||||
|
<div class="container section">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12 collection" id="collection">
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
let current_page = 1
|
||||||
|
let end_page = 10
|
||||||
|
let limit = 50
|
||||||
|
let site = {{ current_site|tojson }}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
|
await updateList()
|
||||||
|
|
||||||
|
var elems = document.querySelectorAll('.dropdown-trigger');
|
||||||
|
var instances = M.Dropdown.init(elems, {
|
||||||
|
alignment: 'right',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function changeSite(new_site){
|
||||||
|
console.log(`current_site: ${site}`)
|
||||||
|
console.log(`new site: ${new_site}`)
|
||||||
|
site = new_site
|
||||||
|
console.log(`current_site: ${site}`)
|
||||||
|
const url = new URL('/changeSite', window.location.origin);
|
||||||
|
url.searchParams.append('site', site)
|
||||||
|
await fetch(url)
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function updateList(){
|
||||||
|
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('/getReceipts', window.location.origin);
|
||||||
|
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")
|
||||||
|
};
|
||||||
|
const collection = document.getElementById("collection")
|
||||||
|
const dummy = document.createElement('div')
|
||||||
|
data.receipts.forEach(receipt => {
|
||||||
|
var item = document.createElement("a")
|
||||||
|
if (receipt[2] == "Unresolved"){
|
||||||
|
item.innerHTML = `<span class="badge red white-text" style="border-radius: 10px;">${receipt[2]}</span>${receipt[1]}`
|
||||||
|
} else if (receipt[2] == "Resolved"){
|
||||||
|
item.innerHTML = `<span class="badge green white-text" style="border-radius: 10px;">${receipt[2]}</span>${receipt[1]}`
|
||||||
|
}
|
||||||
|
item.classList.add("collection-item")
|
||||||
|
item.href = `/receipt/${receipt[0]}`
|
||||||
|
dummy.appendChild(item)
|
||||||
|
});
|
||||||
|
collection.innerHTML = dummy.innerHTML
|
||||||
|
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 update_list();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('back').addEventListener('click', async () =>{
|
||||||
|
if (!(document.getElementById("back").classList.contains("disabled"))){
|
||||||
|
current_page--
|
||||||
|
await update_list();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('last').addEventListener('click', async () =>{
|
||||||
|
if(!(document.getElementById("last").classList.contains("disabled"))){
|
||||||
|
current_page = end_page
|
||||||
|
await update_list();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('first').addEventListener('click', async () =>{
|
||||||
|
if (!(document.getElementById("first").classList.contains("disabled"))){
|
||||||
|
current_page = 1
|
||||||
|
await update_list();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
217
templates/receipts/receipt.html
Normal file
217
templates/receipts/receipt.html
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8" />
|
||||||
|
<title>My Pantry - Items</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>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
.hand-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
[type="radio"]:checked + span:after {
|
||||||
|
border: 2px solid rgb(0 128 0 / 30%); /* Outline color */
|
||||||
|
background-color: rgb(0 128 0 / 30%); /* Fill color */
|
||||||
|
}
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled-row {
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.custom_row:hover{
|
||||||
|
background-color: rgb(230, 230, 230) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</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" 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 class="active"><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>
|
||||||
|
<li><a href="/receipts">Site Receipts</a></li>
|
||||||
|
</ul>
|
||||||
|
<body>
|
||||||
|
<div class="container section">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12">
|
||||||
|
<h3 id="receipt_id"></h3>
|
||||||
|
</div>
|
||||||
|
<div class="col s6">
|
||||||
|
<h5 id="database_id"></h5>
|
||||||
|
</div>
|
||||||
|
<div class="col s6 right">
|
||||||
|
<h5 class="right" id="status"></h5>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<p id="created"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Vendor info starts here -->
|
||||||
|
<div class="col s12 green lighten-4" style="border-radius: 10px;">
|
||||||
|
<h5 class="center">Vendor</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 divider"></div>
|
||||||
|
<div class="row col s12" style="gap: 15px; margin-top: 10px;">
|
||||||
|
<div class="col s12 m8 input-field outlined">
|
||||||
|
<input id="vendor_name" type="text" placeholder=" " disabled>
|
||||||
|
<label for="vendor_name">Name</label>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 m4 l3">
|
||||||
|
<button class="btn btn-flat green lighten-4" onclick="populateVendors()" style="display: flex; align-items: center;"><i class="material-symbols-outlined" style="padding-right: 10px;">event_list</i>Vendors</button>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 input-field outlined">
|
||||||
|
<input id="vendor_number" type="text" placeholder=" " disabled>
|
||||||
|
<label for="vendor_number">Phone Number</label>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 input-field">
|
||||||
|
<input id="vendor_address" class="materialize-textarea" placeholder=" " disabled>
|
||||||
|
<label for="vendor_address">Address</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Receipt Items start here -->
|
||||||
|
<div class="col s12 green lighten-4" style="border-radius: 10px; margin-top: 10px;">
|
||||||
|
<h5 class="center">Receipt Items</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="card-panel green z-depth-0 lighten-5">
|
||||||
|
<span class="black-text">Below are the line items on this receipt. By clicking on the row you can modify, save, delete, void, resolve the lines.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 divider"></div>
|
||||||
|
<div class="col s12">
|
||||||
|
<table class="" id="item_table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>type</th>
|
||||||
|
<th>barcode</th>
|
||||||
|
<th>name</th>
|
||||||
|
<th>qty</th>
|
||||||
|
<th>cost</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Modal code for modifying an item -->
|
||||||
|
<div id="modify_item" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="row" style="gap: 15px;">
|
||||||
|
<div class="col s12 green lighten-4">
|
||||||
|
<h5 class="center" style="border-radius: 10px;">Modify Item</h5>
|
||||||
|
</div>
|
||||||
|
<div class="row col s12" style="gap: 15px;">
|
||||||
|
<div class="s12 m6 input-field outlined">
|
||||||
|
<input id="item_barcode" type="text" placeholder=" ">
|
||||||
|
<label for="item_barcode">Line Barcode</label>
|
||||||
|
<span class="supporting-text">Barcode must be in the system surrounded by %%s</span>
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field outlined">
|
||||||
|
<input id="item_database_id" type="text" placeholder=" " disabled>
|
||||||
|
<label for="item_database_id">Database ID</label>
|
||||||
|
<!--<span class="supporting-text">Supporting Text</span>-->
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field outlined">
|
||||||
|
<input id="item_type" type="text" placeholder=" " disabled>
|
||||||
|
<label for="item_type">Line Type</label>
|
||||||
|
<!--<span class="supporting-text">Supporting Text</span>-->
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field outlined">
|
||||||
|
<input id="item_name" type="text" placeholder=" " disabled>
|
||||||
|
<label for="item_name">Line Name</label>
|
||||||
|
<!--<span class="supporting-text">Supporting Text</span>-->
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field outlined">
|
||||||
|
<input id="item_qty" type="text" placeholder=" ">
|
||||||
|
<label for="item_qty">Line Quantity</label>
|
||||||
|
<!--<span class="supporting-text">Supporting Text</span>-->
|
||||||
|
</div>
|
||||||
|
<div class="s12 m6 input-field outlined">
|
||||||
|
<input id="item_cost" type="text" placeholder=" ">
|
||||||
|
<label for="item_cost">Line Cost</label>
|
||||||
|
<!--<span class="supporting-text">Supporting Text</span>-->
|
||||||
|
</div>
|
||||||
|
<div class="col s12 divider"></div>
|
||||||
|
<div class="row col s12" style="gap: 5px;">
|
||||||
|
<button onclick="saveItem()" class="waves-effect btn-flat right blue white-text tooltipped" data-position="bottom" data-tooltip="Save Changes to Line Item">
|
||||||
|
<i class="material-icons">save</i></button>
|
||||||
|
<button onclick="voidItem()" class="waves-effect btn-flat right black white-text tooltipped" data-position="bottom" data-tooltip="Void Line Item">
|
||||||
|
<i class="material-icons">cancel</i></button>
|
||||||
|
<button onclick="deleteItem()" class="waves-effect btn-flat right red white-text tooltipped" data-position="bottom" data-tooltip="Delete Line Item">
|
||||||
|
<i class="material-icons">delete</i></button>
|
||||||
|
<button onclick="resolveItem()" class="waves-effect btn-flat right green white-text tooltipped" data-position="bottom" data-tooltip="Resolve Line Item">
|
||||||
|
<i class="material-icons">check</i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Modal code for selecting a vendor -->
|
||||||
|
<div id="vendors" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="row" style="gap: 5px;">
|
||||||
|
<div class="col s12">
|
||||||
|
<h4>Vendors</h4>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="card-panel grey lighten-4 z-depth-0">
|
||||||
|
<span class="black-text">Listed below is all the Vendors avaiable to select for this receipt. </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="divider col s12"></div>
|
||||||
|
<div id="vendors-table-container" class="col s12">
|
||||||
|
<table id="vendors_table">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script src="{{ url_for('static', filename='receiptHandler.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
const receipt_id = {{id|tojson}}
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@ -13,8 +13,8 @@
|
|||||||
<!-- Material Symbols - Sharp Set -->
|
<!-- Material Symbols - Sharp Set -->
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp" rel="stylesheet" />
|
<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://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>
|
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
|
||||||
|
-->
|
||||||
</head>
|
</head>
|
||||||
<style>
|
<style>
|
||||||
.custom_row:hover{
|
.custom_row:hover{
|
||||||
@ -49,36 +49,54 @@
|
|||||||
<input id="name" type="text" placeholder="" disabled>
|
<input id="name" type="text" placeholder="" disabled>
|
||||||
<label for="name">Item Name</label>
|
<label for="name">Item Name</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s7 m4 input-field outlined m-2">
|
<div class="col s7 m4 l2 input-field outlined m-2">
|
||||||
<input id="QOH" type="text" placeholder="" disabled>
|
<input id="QOH" type="text" placeholder="" disabled>
|
||||||
<label for="QOH">Quantity on Hand</label>
|
<label for="QOH">Quantity on Hand</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s2" style="margin-top: 15px;">
|
<div class="col s5 m2 l2 input-field outlined m-2">
|
||||||
<a class="btn btn-flat green lighten-4 modal-trigger" href="#locations" style="display: flex; align-items: center; width: 180px;"><i class="material-symbols-outlined" style="padding-right: 10px;">event_list</i>Item Locations</a>
|
<input id="UOM" type="text" placeholder="" disabled>
|
||||||
|
<label for="UOM">UOM</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s12 divider"></div>
|
<div class="col s12 m6 l4 right">
|
||||||
<div class="col s12 m6 m-2">
|
|
||||||
<label for="trans_type">Transaction Type</label>
|
<label for="trans_type">Transaction Type</label>
|
||||||
<select id="trans_type" class="browser-default">
|
<select id="trans_type" class="browser-default">
|
||||||
<option value="" disabled selected>Choose your option</option>
|
<option value="" disabled selected>Choose your option</option>
|
||||||
<option value="In">Adjust In</option>
|
<option value="Adjust In">Adjust In</option>
|
||||||
<option value="Out">Adjust Out</option>
|
<option value="Adjust Out">Adjust Out</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s6 m3 m-2">
|
<div class="col s12 divider hide-on-small-only"></div>
|
||||||
<label onchange="loadLocations()" for="zone">Zone</label>
|
<div class="col s12 m3 m-2">
|
||||||
<select id="zone" class="browser-default">
|
<label for="zone">Zone</label>
|
||||||
|
<select onchange="loadLocations()" id="zone" class="browser-default">
|
||||||
<option value="" disabled selected>Choose your option</option>
|
<option value="" disabled selected>Choose your option</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s6 m3 m-2">
|
<div class="col s12 m3 m-2">
|
||||||
<label for="location">Location</label>
|
<label for="location">Location</label>
|
||||||
<select id="location" class="browser-default">
|
<select id="location" class="browser-default">
|
||||||
<option value="" disabled selected>Choose your option</option>
|
<option value="" disabled selected>Choose your option</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col s12 m4 l3" style="padding-top: 25px;">
|
||||||
|
<a class="btn btn-flat green lighten-4 modal-trigger" href="#locations" style="display: flex; align-items: center;"><i class="material-symbols-outlined" style="padding-right: 10px;">event_list</i>Item Locations</a>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 divider hide-on-small-only"></div>
|
||||||
|
<div class="col s12 m4 l2 input-field outlined m-2">
|
||||||
|
<input id="transaction_quantity" type="text" placeholder=" " maxlength="20">
|
||||||
|
<label for="transaction_quantity">Quantity</label>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 m4 l2 input-field outlined m-2">
|
||||||
|
<input id="transaction_cost" type="text" placeholder=" " maxlength="20">
|
||||||
|
<label for="transaction_cost">SKU cost</label>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 divider"></div>
|
||||||
|
<div class="col s12" style="padding-top: 10px;">
|
||||||
|
<button class="btn btn-flat right green lighten-4 black-text" onclick="addTransaction()">Submit</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Item Selection Modal -->
|
||||||
<div id="item_modal" class="modal">
|
<div id="item_modal" class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="row" style="gap: 5px;">
|
<div class="row" style="gap: 5px;">
|
||||||
@ -113,16 +131,53 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Transaction Modal -->
|
||||||
|
<div id="locations" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="row" style="gap: 5px;">
|
||||||
|
<div class="col s12">
|
||||||
|
<h4>Item Locations</h4>
|
||||||
|
</div>
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="card-panel grey lighten-4 z-depth-0">
|
||||||
|
<span class="black-text">Listed below is all the locations this item has ever existed in and the current QOH for each location. </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="divider col s12"></div>
|
||||||
|
<div id="location-table-container" class="col s12">
|
||||||
|
<table id="location_table">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="{{ url_for('static', filename='transactionHandler.js') }}"></script>
|
<script src="{{ url_for('static', filename='transactionHandler.js') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', async function() {
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
await fetchZones()
|
await fetchZones()
|
||||||
await setupZones()
|
await setupZones()
|
||||||
|
await fetchItems()
|
||||||
|
|
||||||
var elems = document.querySelectorAll('.modal');
|
var elems = document.querySelectorAll('.modal');
|
||||||
var instances = M.Modal.init(elems, {
|
var instances = M.Modal.init(elems, {
|
||||||
// specify options here
|
// specify options here
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById("database_id").addEventListener('keydown', async function(event){
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
await clickRow(Number(event.target.value))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById("trans_type").addEventListener('change', async function(){
|
||||||
|
this.style = "";
|
||||||
|
});
|
||||||
|
document.getElementById("transaction_quantity").addEventListener('change', async function(){
|
||||||
|
this.style = "";
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user