Migrated scanning to receipt process to poe
This commit is contained in:
parent
61661db807
commit
109c7fbd31
@ -254,56 +254,6 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Line Edit Modal USED FOR RECEIPTS-->
|
||||
<div id="lineEditModal" uk-modal>
|
||||
<div class="uk-modal-dialog uk-modal-body">
|
||||
<h2 class="uk-modal-title">Edit Line...</h2>
|
||||
<p class="uk-text-meta">Edit any fields here for the selected Line and then save them.</p>
|
||||
<table class="uk-table uk-table-responsive uk-table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>QTY</td>
|
||||
<td><input id="lineName" class="uk-input" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>QTY</td>
|
||||
<td><input id="lineQty" class="uk-input" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UOM</td>
|
||||
<td>
|
||||
<select id="lineUOM" class="uk-select" type="text">
|
||||
{% for unit in units %}
|
||||
<option value="{{unit['id']}}">{{unit['fullname']}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COST</td>
|
||||
<td><input id="lineCost" class="uk-input" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EXPIRES</td>
|
||||
<td><input id="lineExpires" class="uk-input" type="date"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="uk-text-right">
|
||||
<button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button>
|
||||
<button id="saveLineButton" class="uk-button uk-button-primary" type="button">Save</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% assets "js_all" %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
|
||||
0
application/poe/__init__.py
Normal file
0
application/poe/__init__.py
Normal file
@ -8,6 +8,7 @@ import time, process
|
||||
from user_api import login_required
|
||||
import webpush
|
||||
from application.poe import poe_processes
|
||||
from application import postsqldb
|
||||
|
||||
point_of_ease = Blueprint('poe', __name__, template_folder="templates", static_folder="static")
|
||||
|
||||
@ -21,9 +22,14 @@ def scannerEndpoint():
|
||||
@point_of_ease.route('/receipts', methods=["GET"])
|
||||
def receiptsEndpoint():
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
database_config = config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
units = postsqldb.UnitsTable.getAll(conn)
|
||||
#units = db.UnitsTable.getAll(conn)
|
||||
return render_template('receipts.html', current_site=session['selected_site'],
|
||||
sites=sites)
|
||||
sites=sites, units=units)
|
||||
|
||||
# DONT NEED
|
||||
@point_of_ease.route('/getItemLocations', methods=["GET"])
|
||||
def getItemLocations():
|
||||
recordset = []
|
||||
@ -41,7 +47,7 @@ def getItemLocations():
|
||||
return jsonify({"locations":recordset, "end": math.ceil(count/limit), "error":True, "message":"There was an error with this GET statement"})
|
||||
|
||||
|
||||
# in item api
|
||||
# in item api, DONT NEED
|
||||
@point_of_ease.route('/getItem', methods=["GET"])
|
||||
def getItem():
|
||||
record = {}
|
||||
@ -69,7 +75,7 @@ def getItemBarcode():
|
||||
return jsonify({"item":record, "error":False, "message":"item fetched succesfully!"})
|
||||
return jsonify({"item":record, "error":True, "message":"There was an error with this GET statement"})
|
||||
|
||||
# in items api
|
||||
# in items api DONT NEED
|
||||
@point_of_ease.route('/getModalItems', methods=["GET"])
|
||||
@login_required
|
||||
def getModalItems():
|
||||
@ -97,12 +103,6 @@ def post_transaction():
|
||||
user_id=session['user_id'],
|
||||
data=dict(request.json)
|
||||
)
|
||||
#result = process.postTransaction(
|
||||
# conn=conn,
|
||||
# site_name=session['selected_site'],
|
||||
# user_id=session['user_id'],
|
||||
# data=dict(request.json)
|
||||
#)
|
||||
return jsonify(result)
|
||||
return jsonify({"error":True, "message":"There was an error with this POST statement"})
|
||||
|
||||
@ -112,30 +112,7 @@ def post_receipt():
|
||||
if request.method == "POST":
|
||||
site_name = session['selected_site']
|
||||
user_id = session['user_id']
|
||||
database_config = config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
items = request.json['items']
|
||||
receipt_id = database.request_receipt_id(conn, site_name)
|
||||
receipt_id = f"SIR-{receipt_id}"
|
||||
receipt = MyDataclasses.ReceiptPayload(
|
||||
receipt_id=receipt_id,
|
||||
submitted_by=user_id
|
||||
)
|
||||
receipt = database.insertReceiptsTuple(conn, site_name, receipt.payload(), convert=True)
|
||||
|
||||
for item in items:
|
||||
|
||||
receipt_item = MyDataclasses.ReceiptItemPayload(
|
||||
type=item['type'],
|
||||
receipt_id=receipt['id'],
|
||||
barcode=item['item']['barcode'],
|
||||
name=item['item']['item_name'],
|
||||
qty=item['item']['qty'],
|
||||
uom=item['item']['uom'],
|
||||
data=item['item']['data']
|
||||
)
|
||||
database.insertReceiptItemsTuple(conn, site_name, receipt_item.payload())
|
||||
#webpush.push_notifications('New Receipt', f"Receipt {receipt['receipt_id']} was added to Site -> {site_name}!")
|
||||
webpush.push_ntfy('New Receipt', f"Receipt {receipt['receipt_id']} was added to Site -> {site_name}!")
|
||||
return jsonify({"error":False, "message":"Transaction Complete!"})
|
||||
data= {'items': request.json['items']}
|
||||
status = poe_processes.post_receipt(site_name, user_id, data)
|
||||
return jsonify(status)
|
||||
return jsonify({"error":True, "message":"There was an error with this POST statement"})
|
||||
@ -2,6 +2,36 @@ import psycopg2
|
||||
import config
|
||||
from application import postsqldb
|
||||
|
||||
def request_receipt_id(conn, site_name):
|
||||
"""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
|
||||
"""
|
||||
next_receipt_id = None
|
||||
sql = f"SELECT receipt_id FROM {site_name}_receipts ORDER BY id DESC LIMIT 1;"
|
||||
try:
|
||||
database_config = config.config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql)
|
||||
next_receipt_id = cur.fetchone()
|
||||
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:
|
||||
raise postsqldb.DatabaseError(error, payload=(), sql=sql)
|
||||
|
||||
return next_receipt_id
|
||||
|
||||
def selectItemLocationsTuple(site_name, payload, convert=True):
|
||||
"""select a single tuple from ItemLocations table for site_name
|
||||
@ -198,6 +228,93 @@ def insertTransactionsTuple(site, payload, convert=True, conn=None):
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
return transaction
|
||||
|
||||
def insertReceiptsTuple(site, payload, convert=True, conn=None):
|
||||
"""insert payload into receipt table of site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple):
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
receipt = ()
|
||||
self_conn = False
|
||||
with open(f"application/poe/sql/insertReceiptsTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
if not conn:
|
||||
database_config = config.config()
|
||||
conn = psycopg2.connect(**database_config)
|
||||
conn.autocommit = True
|
||||
self_conn = True
|
||||
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
receipt = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
receipt = rows
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return receipt
|
||||
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def insertReceiptItemsTuple(site, payload, convert=True, conn=None):
|
||||
"""insert payload into receipt_items table of site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple): (type[str], receipt_id[int], barcode[str], name[str],
|
||||
qty[float], data[jsonb], status[str])
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
receipt_item = ()
|
||||
self_conn = False
|
||||
|
||||
with open(f"application/poe/sql/insertReceiptItemsTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
if not conn:
|
||||
database_config = config.config()
|
||||
conn = psycopg2.connect(**database_config)
|
||||
conn.autocommit = True
|
||||
self_conn = True
|
||||
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
receipt_item = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
receipt_item = rows
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return receipt_item
|
||||
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def updateCostLayersTuple(site, payload, convert=True, conn=None):
|
||||
"""_summary_
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from application import postsqldb
|
||||
from application import postsqldb, database_payloads
|
||||
from application.poe import poe_database
|
||||
|
||||
import datetime
|
||||
@ -97,7 +97,47 @@ def postTransaction(site_name, user_id, data: dict, conn=None):
|
||||
#database.insertTransactionsTuple(conn, site_name, transaction.payload())
|
||||
|
||||
if self_conn:
|
||||
conn.rollback()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return {"error": False, "message":f"Transaction Successful!"}
|
||||
|
||||
def post_receipt(site_name, user_id, data: dict, conn=None):
|
||||
# data = {'items': items}
|
||||
self_conn = False
|
||||
items = data['items']
|
||||
if not conn:
|
||||
database_config = config.config()
|
||||
conn = psycopg2.connect(**database_config)
|
||||
conn.autocommit = False
|
||||
self_conn = True
|
||||
|
||||
receipt_id = poe_database.request_receipt_id(conn, site_name)
|
||||
receipt_id = f"SIR-{receipt_id}"
|
||||
receipt = database_payloads.ReceiptPayload(
|
||||
receipt_id=receipt_id,
|
||||
submitted_by=user_id
|
||||
)
|
||||
#receipt = database.insertReceiptsTuple(conn, site_name, receipt.payload(), convert=True)
|
||||
receipt = poe_database.insertReceiptsTuple(site_name, receipt.payload(), conn=conn)
|
||||
for item in items:
|
||||
|
||||
receipt_item = database_payloads.ReceiptItemPayload(
|
||||
type=item['type'],
|
||||
receipt_id=receipt['id'],
|
||||
barcode=item['item']['barcode'],
|
||||
name=item['item']['item_name'],
|
||||
qty=item['item']['qty'],
|
||||
uom=item['item']['uom'],
|
||||
data=item['item']['data']
|
||||
)
|
||||
#database.insertReceiptItemsTuple(conn, site_name, receipt_item.payload())
|
||||
poe_database.insertReceiptItemsTuple(site_name, receipt_item.payload(), conn=conn)
|
||||
#webpush.push_notifications('New Receipt', f"Receipt {receipt['receipt_id']} was added to Site -> {site_name}!")
|
||||
#webpush.push_ntfy('New Receipt', f"Receipt {receipt['receipt_id']} was added to Site -> {site_name}!")
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return {"error":False, "message":"Transaction Complete!"}
|
||||
|
||||
4
application/poe/sql/insertReceiptItemsTuple.sql
Normal file
4
application/poe/sql/insertReceiptItemsTuple.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_receipt_items
|
||||
(type, receipt_id, barcode, name, qty, uom, data, status)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/poe/sql/insertReceiptsTuple.sql
Normal file
4
application/poe/sql/insertReceiptsTuple.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_receipts
|
||||
(receipt_id, receipt_status, date_submitted, submitted_by, vendor_id, files)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
@ -30,511 +30,20 @@ async function changeSite(site){
|
||||
location.reload(true)
|
||||
}
|
||||
|
||||
async function replenishItemsTable(items) {
|
||||
let itemsTableBody = document.getElementById("itemsTableBody")
|
||||
itemsTableBody.innerHTML = ""
|
||||
|
||||
for(let i = 0; i < items.length; i++){
|
||||
let tableRow = document.createElement('tr')
|
||||
|
||||
|
||||
let idCell = document.createElement('td')
|
||||
idCell.innerHTML = items[i].id
|
||||
let barcodeCell = document.createElement('td')
|
||||
barcodeCell.innerHTML = items[i].barcode
|
||||
let nameCell = document.createElement('td')
|
||||
nameCell.innerHTML = items[i].item_name
|
||||
|
||||
tableRow.append(idCell)
|
||||
tableRow.append(barcodeCell)
|
||||
tableRow.append(nameCell)
|
||||
|
||||
tableRow.onclick = function(){
|
||||
selectItem(items[i].id)
|
||||
}
|
||||
|
||||
itemsTableBody.append(tableRow)
|
||||
}
|
||||
}
|
||||
|
||||
async function populateForm() {
|
||||
if (item){
|
||||
console.log(item)
|
||||
document.getElementById('database_id').value = item.id
|
||||
document.getElementById('barcode').value = item.barcode
|
||||
document.getElementById('name').value = item.item_name
|
||||
document.getElementById('transaction_cost').value = parseFloat(item.item_info.cost)
|
||||
|
||||
await selectLocation(
|
||||
item.logistics_info.primary_zone.id,
|
||||
item.logistics_info.primary_location.id,
|
||||
item.logistics_info.primary_zone.name,
|
||||
item.logistics_info.primary_location.name
|
||||
)
|
||||
|
||||
|
||||
let quantity_on_hand = 0
|
||||
let locations = await getItemLocations()
|
||||
for(let i = 0; i < locations.length; i++){
|
||||
quantity_on_hand = quantity_on_hand + locations[i].quantity_on_hand
|
||||
}
|
||||
document.getElementById('QOH').value = quantity_on_hand
|
||||
document.getElementById('UOM').value = item.item_info.uom.fullname
|
||||
|
||||
await replenishItemLocationsTable(locations)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async function selectItem(id) {
|
||||
UIkit.modal(document.getElementById("itemsModal")).hide();
|
||||
item = await getItem(id)
|
||||
await populateForm()
|
||||
}
|
||||
|
||||
var transaction_zone_id = 0
|
||||
var transaction_item_location_id = 0
|
||||
async function selectLocation(zone_id, location_id, zone_name, location_name) {
|
||||
document.getElementById('zone').value = zone_name
|
||||
document.getElementById('location').value = location_name
|
||||
transaction_zone_id = zone_id
|
||||
transaction_item_location_id = location_id
|
||||
}
|
||||
|
||||
async function openItemsModal(elementID){
|
||||
UIkit.modal(document.getElementById("itemsModal")).show();
|
||||
pagination_current = 1
|
||||
search_string = ''
|
||||
let items = await getItems()
|
||||
await replenishItemsTable(items)
|
||||
await updatePaginationElement(elementID)
|
||||
setFormButtonsEnabled(true)
|
||||
}
|
||||
|
||||
async function setFormButtonsEnabled(state) {
|
||||
let item_location_button = document.getElementById("itemLocations")
|
||||
|
||||
if(state){
|
||||
item_location_button.classList.remove("uk-disabled")
|
||||
} else {
|
||||
item_location_button.classList.add("uk-disabled")
|
||||
}
|
||||
}
|
||||
|
||||
async function setTransactionTypeAdjustments() {
|
||||
let trans_type = document.getElementById('trans_type').value
|
||||
|
||||
if(trans_type=="Adjust Out"){
|
||||
document.getElementById('transaction_cost').classList.add('uk-disabled')
|
||||
}
|
||||
if(trans_type=="Adjust In"){
|
||||
document.getElementById('transaction_cost').classList.remove('uk-disabled')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function replenishItemLocationsTable(locations) {
|
||||
let itemLocationTableBody = document.getElementById('itemLocationTableBody')
|
||||
itemLocationTableBody.innerHTML = ""
|
||||
for(let i = 0; i < locations.length; i++){
|
||||
let tableRow = document.createElement('tr')
|
||||
|
||||
let loca = locations[i].uuid.split('@')
|
||||
|
||||
let zoneCell = document.createElement('td')
|
||||
zoneCell.innerHTML = loca[0]
|
||||
|
||||
let locationCell = document.createElement('td')
|
||||
locationCell.innerHTML = loca[1]
|
||||
|
||||
let qohCell = document.createElement('td')
|
||||
qohCell.innerHTML = parseFloat(locations[i].quantity_on_hand)
|
||||
|
||||
tableRow.append(zoneCell, locationCell, qohCell)
|
||||
tableRow.onclick = async function(){
|
||||
await selectLocation(
|
||||
locations[i].zone_id,
|
||||
locations[i].id,
|
||||
loca[0],
|
||||
loca[1]
|
||||
)
|
||||
}
|
||||
itemLocationTableBody.append(tableRow)
|
||||
}
|
||||
}
|
||||
|
||||
let locations_limit = 10;
|
||||
async function getItemLocations() {
|
||||
console.log("getting Locations")
|
||||
const url = new URL('/external/getItemLocations', window.location.origin);
|
||||
url.searchParams.append('page', pagination_current);
|
||||
url.searchParams.append('limit', locations_limit);
|
||||
url.searchParams.append('id', item.id);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
pagination_end = data.end
|
||||
let locations = data.locations;
|
||||
console.log(locations)
|
||||
return locations;
|
||||
}
|
||||
|
||||
|
||||
let items_limit = 50;
|
||||
async function getItems() {
|
||||
console.log("getting items")
|
||||
const url = new URL('/external/getModalItems', window.location.origin);
|
||||
url.searchParams.append('page', pagination_current);
|
||||
url.searchParams.append('limit', items_limit);
|
||||
url.searchParams.append('search_string', search_string)
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
pagination_end = data.end
|
||||
let items = data.items;
|
||||
return items;
|
||||
}
|
||||
|
||||
async function getItem(id) {
|
||||
console.log(`selected item: ${id}`)
|
||||
const url = new URL('/external/getItem', window.location.origin);
|
||||
url.searchParams.append('id', id);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
item = data.item;
|
||||
return item;
|
||||
}
|
||||
|
||||
async function validateTransaction() {
|
||||
let database_id = document.getElementById("database_id")
|
||||
let transaction_type = document.getElementById("trans_type")
|
||||
let transaction_zone = document.getElementById("zone")
|
||||
let transaction_location = document.getElementById("location")
|
||||
let transaction_quantity = document.getElementById("transaction_quantity")
|
||||
let transaction_cost = document.getElementById("transaction_cost")
|
||||
|
||||
|
||||
let error_count = 0
|
||||
if(database_id.value === ""){
|
||||
error_count = error_count + 1
|
||||
database_id.classList.add("uk-form-danger")
|
||||
} else {
|
||||
database_id.classList.remove("uk-form-danger")
|
||||
}
|
||||
if(transaction_type.value === "0"){
|
||||
error_count = error_count + 1
|
||||
transaction_type.classList.add("uk-form-danger")
|
||||
} else {
|
||||
transaction_type.classList.remove("uk-form-danger")
|
||||
}
|
||||
|
||||
if (transaction_zone.value === ""){
|
||||
error_count = error_count + 1
|
||||
transaction_zone.classList.add("uk-form-danger")
|
||||
} else {
|
||||
transaction_zone.classList.remove("uk-form-danger")
|
||||
}
|
||||
|
||||
if (transaction_location.value === ""){
|
||||
error_count = error_count + 1
|
||||
transaction_location.classList.add("uk-form-danger")
|
||||
} else {
|
||||
transaction_location.classList.remove("uk-form-danger")
|
||||
}
|
||||
|
||||
let transaction_quantity_int = parseFloat(transaction_quantity.value)
|
||||
if (transaction_quantity_int === 0.00 || transaction_quantity_int < 0.00){
|
||||
error_count = error_count + 1
|
||||
transaction_quantity.classList.add("uk-form-danger")
|
||||
} else {
|
||||
transaction_quantity.classList.remove("uk-form-danger")
|
||||
}
|
||||
|
||||
let transaction_cost_int = parseFloat(transaction_cost.value)
|
||||
if (transaction_cost_int == 0.00 && transaction_type.value == "Adjust In"){
|
||||
error_count = error_count + 1
|
||||
transaction_cost.classList.add("uk-form-danger")
|
||||
} else {
|
||||
transaction_cost.classList.remove("uk-form-danger")
|
||||
}
|
||||
|
||||
if(error_count > 0){
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
async function submitTransaction() {
|
||||
let validated = await validateTransaction()
|
||||
if (validated){
|
||||
let cost = parseFloat(document.getElementById('transaction_cost').value.replace(/[^0-9.-]+/g, ""));
|
||||
const response = await fetch(`/external/postTransaction`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
item_id: item.id,
|
||||
logistics_info_id: item.logistics_info_id,
|
||||
barcode: item.barcode,
|
||||
item_name: item.item_name,
|
||||
transaction_type: document.getElementById('trans_type').value,
|
||||
quantity: parseFloat(document.getElementById('transaction_quantity').value),
|
||||
description: document.getElementById('transaction_description').value,
|
||||
cost: cost,
|
||||
vendor: 0,
|
||||
expires: null,
|
||||
location_id: transaction_item_location_id
|
||||
}),
|
||||
});
|
||||
data = await response.json();
|
||||
transaction_status = "success"
|
||||
if (data.error){
|
||||
transaction_status = "danger"
|
||||
}
|
||||
|
||||
UIkit.notification({
|
||||
message: data.message,
|
||||
status: transaction_status,
|
||||
pos: 'top-right',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
item = await getItem(item.id)
|
||||
await populateForm()
|
||||
document.getElementById('transaction_quantity').value = '0.00'
|
||||
|
||||
} else {
|
||||
UIkit.notification({
|
||||
message: 'Please verify your transaction receipt.',
|
||||
status: 'warning',
|
||||
pos: 'top-right',
|
||||
timeout: 5000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function searchTable(event, logis, elementID) {
|
||||
if(event.key==='Enter' && logis==='items'){
|
||||
search_string = event.srcElement.value
|
||||
let items = await getItems()
|
||||
await replenishItemsTable(items)
|
||||
}
|
||||
await updatePaginationElement(elementID)
|
||||
}
|
||||
|
||||
async function setPage(pageNumber, elementID){
|
||||
pagination_current = pageNumber;
|
||||
|
||||
if(elementID=="itemsPage"){
|
||||
let items = await getItems()
|
||||
await replenishItemsTable(items)
|
||||
}
|
||||
await updatePaginationElement(elementID)
|
||||
}
|
||||
|
||||
async function updatePaginationElement(elementID) {
|
||||
let paginationElement = document.getElementById(elementID);
|
||||
paginationElement.innerHTML = "";
|
||||
// previous
|
||||
let previousElement = document.createElement('li')
|
||||
if(pagination_current<=1){
|
||||
previousElement.innerHTML = `<a><span uk-pagination-previous></span></a>`;
|
||||
previousElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
previousElement.innerHTML = `<a onclick="setPage(${pagination_current-1}, '${elementID}')"><span uk-pagination-previous></span></a>`;
|
||||
}
|
||||
paginationElement.append(previousElement)
|
||||
|
||||
//first
|
||||
let firstElement = document.createElement('li')
|
||||
if(pagination_current<=1){
|
||||
firstElement.innerHTML = `<a><strong>1</strong></a>`;
|
||||
firstElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
firstElement.innerHTML = `<a onclick="setPage(1, '${elementID}')">1</a>`;
|
||||
}
|
||||
paginationElement.append(firstElement)
|
||||
|
||||
// ...
|
||||
if(pagination_current-2>1){
|
||||
let firstDotElement = document.createElement('li')
|
||||
firstDotElement.classList.add('uk-disabled')
|
||||
firstDotElement.innerHTML = `<span>…</span>`;
|
||||
paginationElement.append(firstDotElement)
|
||||
}
|
||||
// last
|
||||
if(pagination_current-2>0){
|
||||
let lastElement = document.createElement('li')
|
||||
lastElement.innerHTML = `<a onclick="setPage(${pagination_current-1}, '${elementID}')">${pagination_current-1}</a>`
|
||||
paginationElement.append(lastElement)
|
||||
}
|
||||
// current
|
||||
if(pagination_current!=1 && pagination_current != pagination_end){
|
||||
let currentElement = document.createElement('li')
|
||||
currentElement.innerHTML = `<li class="uk-active"><span aria-current="page"><strong>${pagination_current}</strong></span></li>`
|
||||
paginationElement.append(currentElement)
|
||||
}
|
||||
// next
|
||||
if(pagination_current+2<pagination_end+1){
|
||||
let nextElement = document.createElement('li')
|
||||
nextElement.innerHTML = `<a onclick="setPage(${pagination_current+1}, '${elementID}')">${pagination_current+1}</a>`
|
||||
paginationElement.append(nextElement)
|
||||
}
|
||||
// ...
|
||||
if(pagination_current+2<=pagination_end){
|
||||
let secondDotElement = document.createElement('li')
|
||||
secondDotElement.classList.add('uk-disabled')
|
||||
secondDotElement.innerHTML = `<span>…</span>`;
|
||||
paginationElement.append(secondDotElement)
|
||||
}
|
||||
//end
|
||||
let endElement = document.createElement('li')
|
||||
if(pagination_current>=pagination_end){
|
||||
endElement.innerHTML = `<a><strong>${pagination_end}</strong></a>`;
|
||||
endElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
endElement.innerHTML = `<a onclick="setPage(${pagination_end}, '${elementID}')">${pagination_end}</a>`;
|
||||
}
|
||||
paginationElement.append(endElement)
|
||||
//next button
|
||||
let nextElement = document.createElement('li')
|
||||
if(pagination_current>=pagination_end){
|
||||
nextElement.innerHTML = `<a><span uk-pagination-next></span></a>`;
|
||||
nextElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
nextElement.innerHTML = `<a onclick="setPage(${pagination_current+1}, '${elementID}')"><span uk-pagination-next></span></a>`;
|
||||
console.log(nextElement.innerHTML)
|
||||
}
|
||||
paginationElement.append(nextElement)
|
||||
}
|
||||
|
||||
var scannedItems = Array();
|
||||
const queueLimit = 5; // 49 should be default
|
||||
|
||||
async function addToQueue(event) {
|
||||
if (event.key == "Enter"){
|
||||
let data = await getItemBarcode(document.getElementById('barcode-scan').value)
|
||||
let scannedItem = data.item
|
||||
if(data.error){
|
||||
UIkit.notification({
|
||||
message: data.message,
|
||||
status: "danger",
|
||||
pos: 'top-right',
|
||||
timeout: 5000
|
||||
});
|
||||
}
|
||||
if(scannedItems.length > queueLimit){
|
||||
scannedItems.shift()
|
||||
}
|
||||
if(!Array.isArray(scannedItem) && !data.error){
|
||||
let status = await submitScanTransaction(scannedItem)
|
||||
scannedItems.push({'item': scannedItem, 'type': `${document.getElementById('scan_trans_type').value}`, 'error': status})
|
||||
document.getElementById('barcode-scan').value = ""
|
||||
}
|
||||
}
|
||||
await replenishScanTable()
|
||||
}
|
||||
|
||||
async function getItemBarcode(barcode) {
|
||||
console.log(`selected item: ${barcode}`)
|
||||
const url = new URL('/external/getItem/barcode', window.location.origin);
|
||||
const url = new URL('/poe/getItem/barcode', window.location.origin);
|
||||
url.searchParams.append('barcode', barcode);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
async function submitScanTransaction(scannedItem) {
|
||||
/// I need to find the location that matches the items auto issue location id
|
||||
|
||||
let trans_type = document.getElementById('scan_trans_type').value
|
||||
let scan_transaction_item_location_id = 0
|
||||
let comparator = 0
|
||||
|
||||
if (trans_type === "Adjust In"){
|
||||
comparator = scannedItem.logistics_info.primary_location.id
|
||||
} else if (trans_type === "Adjust Out"){
|
||||
comparator = scannedItem.logistics_info.auto_issue_location.id
|
||||
}
|
||||
|
||||
for (let i = 0; i < scannedItem.item_locations.length; i++){
|
||||
if (scannedItem.item_locations[i].location_id === comparator){
|
||||
scan_transaction_item_location_id = scannedItem.item_locations[i].id
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(`/external/postTransaction`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
item_id: scannedItem.id,
|
||||
logistics_info_id: scannedItem.logistics_info_id,
|
||||
barcode: scannedItem.barcode,
|
||||
item_name: scannedItem.item_name,
|
||||
transaction_type: document.getElementById('scan_trans_type').value,
|
||||
quantity: scannedItem.item_info.uom_quantity,
|
||||
description: "",
|
||||
cost: parseFloat(scannedItem.item_info.cost),
|
||||
vendor: 0,
|
||||
expires: null,
|
||||
location_id: scan_transaction_item_location_id
|
||||
}),
|
||||
});
|
||||
data = await response.json();
|
||||
transaction_status = "success"
|
||||
if (data.error){
|
||||
transaction_status = "danger"
|
||||
}
|
||||
|
||||
UIkit.notification({
|
||||
message: data.message,
|
||||
status: transaction_status,
|
||||
pos: 'top-right',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
return data.error
|
||||
|
||||
}
|
||||
|
||||
async function replenishScanTable() {
|
||||
let scanTableBody = document.getElementById("scanTableBody")
|
||||
scanTableBody.innerHTML = ""
|
||||
|
||||
let reversedScannedItems = scannedItems.slice().reverse()
|
||||
|
||||
for(let i = 0; i < reversedScannedItems.length; i++){
|
||||
let tableRow = document.createElement('tr')
|
||||
|
||||
let icon = `<span uk-icon="check"></span>`
|
||||
if(reversedScannedItems[i].error){
|
||||
icon = `<span uk-icon="warning"></span>`
|
||||
}
|
||||
|
||||
let statusCell = document.createElement('td')
|
||||
statusCell.innerHTML = icon
|
||||
let barcodeCell = document.createElement('td')
|
||||
barcodeCell.innerHTML = reversedScannedItems[i].item.barcode
|
||||
let nameCell = document.createElement('td')
|
||||
nameCell.innerHTML = reversedScannedItems[i].item.item_name
|
||||
let typeCell = document.createElement('td')
|
||||
typeCell.innerHTML = reversedScannedItems[i].type
|
||||
let locationCell = document.createElement('td')
|
||||
if (reversedScannedItems[i].type === "Adjust In"){
|
||||
locationCell.innerHTML = reversedScannedItems[i].item.logistics_info.primary_location.uuid
|
||||
} else {
|
||||
locationCell.innerHTML = reversedScannedItems[i].item.logistics_info.auto_issue_location.uuid
|
||||
}
|
||||
|
||||
tableRow.append(statusCell, barcodeCell, nameCell, typeCell, locationCell)
|
||||
scanTableBody.append(tableRow)
|
||||
}
|
||||
}
|
||||
|
||||
async function submitScanReceipt(items) {
|
||||
const response = await fetch(`/external/postReceipt`, {
|
||||
const response = await fetch(`/poe/postReceipt`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -585,7 +94,6 @@ async function completeReceipt() {
|
||||
scanReceiptTableBody.innerHTML = ""
|
||||
|
||||
scannedReceiptItems = Array()
|
||||
|
||||
}
|
||||
|
||||
async function closeReceipt(){
|
||||
@ -611,7 +119,6 @@ async function addToReceipt(event) {
|
||||
let scannedItem = data.item
|
||||
if(scannedItem){
|
||||
let expires = scannedItem.food_info.expires
|
||||
console.log(expires)
|
||||
if(scannedItem.food_info.expires){
|
||||
let today = new Date();
|
||||
today.setDate(today.getDate() + Number(scannedItem.food_info.default_expiration))
|
||||
|
||||
@ -146,6 +146,53 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Line Edit Modal USED FOR RECEIPTS-->
|
||||
<div id="lineEditModal" uk-modal>
|
||||
<div class="uk-modal-dialog uk-modal-body">
|
||||
<h2 class="uk-modal-title">Edit Line...</h2>
|
||||
<p class="uk-text-meta">Edit any fields here for the selected Line and then save them.</p>
|
||||
<table class="uk-table uk-table-responsive uk-table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>QTY</td>
|
||||
<td><input id="lineName" class="uk-input" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>QTY</td>
|
||||
<td><input id="lineQty" class="uk-input" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UOM</td>
|
||||
<td>
|
||||
<select id="lineUOM" class="uk-select" type="text">
|
||||
{% for unit in units %}
|
||||
<option value="{{unit['id']}}">{{unit['fullname']}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COST</td>
|
||||
<td><input id="lineCost" class="uk-input" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EXPIRES</td>
|
||||
<td><input id="lineExpires" class="uk-input" type="date"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="uk-text-right">
|
||||
<button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button>
|
||||
<button id="saveLineButton" class="uk-button uk-button-primary" type="button">Save</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
{% assets "js_all" %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
|
||||
@ -1938,3 +1938,9 @@
|
||||
2025-07-02 18:04:47.600077 --- ERROR --- DatabaseError(message='not all arguments converted during string formatting',
|
||||
payload=(1, 2),
|
||||
sql='SELECT * FROM main_locations WHERE id=%s;')
|
||||
2025-07-02 18:32:23.140191 --- ERROR --- DatabaseError(message='invalid input syntax for type integer: ""LINE 3: ...041789001314%', 'Chicken Ramen Noodle Soup', '2', '', '{"cos... ^',
|
||||
payload=('sku', 19, '%041789001314%', 'Chicken Ramen Noodle Soup', '2', '', '{"cost": "1.99", "expires": false}', 'Unresolved'),
|
||||
sql='INSERT INTO test_receipt_items(type, receipt_id, barcode, name, qty, uom, data, status) VALUES (%s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||
2025-07-04 08:19:34.889657 --- ERROR --- DatabaseError(message='invalid input syntax for type integer: "{"cost": 1.99, "expires": false}"LINE 3: ...41789001314%', 'Chicken Ramen Noodle Soup', 1, 5, '{"cost": ... ^',
|
||||
payload=('sku', 23, '%041789001314%', 'Chicken Ramen Noodle Soup', 1, 5, '{"cost": 1.99, "expires": false}', 'Unresolved'),
|
||||
sql='INSERT INTO test_recipe_items(uuid, rp_id, item_type, item_name, uom, qty, item_id, links) VALUES (%s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||
Loading…
x
Reference in New Issue
Block a user