Added Take Out Events and REceipts
This commit is contained in:
parent
0fc1b6dc1d
commit
1156ab5aca
Binary file not shown.
@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS %%site_name%%_plan_events(
|
||||
event_uuid UUID DEFAULT gen_random_uuid(),
|
||||
plan_uuid UUID,
|
||||
recipe_uuid UUID,
|
||||
receipt_uuid UUID DEFAULT NULL,
|
||||
event_shortname VARCHAR(32) NOT NULL,
|
||||
event_description TEXT,
|
||||
event_date_start TIMESTAMP NOT NULL,
|
||||
|
||||
@ -576,6 +576,7 @@ class PlanEventPayload:
|
||||
event_date_end: datetime.datetime
|
||||
created_by: int
|
||||
recipe_uuid: str
|
||||
receipt_uuid: str
|
||||
event_type: str
|
||||
|
||||
def payload(self):
|
||||
@ -587,6 +588,7 @@ class PlanEventPayload:
|
||||
self.event_date_end,
|
||||
self.created_by,
|
||||
self.recipe_uuid,
|
||||
self.receipt_uuid,
|
||||
self.event_type
|
||||
)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -10,7 +10,7 @@ import datetime
|
||||
from config import config
|
||||
from application.access_module import access_api
|
||||
from application import postsqldb, database_payloads
|
||||
from application.meal_planner import meal_planner_database
|
||||
from application.meal_planner import meal_planner_database, meal_planner_processes
|
||||
|
||||
meal_planner_api = Blueprint('meal_planner_api', __name__, template_folder="templates", static_folder="static")
|
||||
|
||||
@ -62,6 +62,24 @@ def getRecipes():
|
||||
return jsonify(status=201, message="Recipes fetched Successfully!", recipes=recipes, end=math.ceil(count/limit))
|
||||
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!", recipes=recipes, end=math.ceil(count/limit))
|
||||
|
||||
|
||||
@meal_planner_api.route('/api/getVendors', methods=["GET"])
|
||||
@access_api.login_required
|
||||
def getVendors():
|
||||
if request.method == "GET":
|
||||
site_name = session['selected_site']
|
||||
page = int(request.args.get('page', 1))
|
||||
limit = int(request.args.get('limit', 50))
|
||||
search_string = request.args.get('search_string', "")
|
||||
|
||||
offset = (page - 1) * limit
|
||||
vendors, count = [], 0
|
||||
vendors, count = meal_planner_database.paginateVendorsTuples(site_name, (limit, offset))
|
||||
|
||||
return jsonify(status=201, message="Recipes fetched Successfully!", vendors=vendors, end=math.ceil(count/limit))
|
||||
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!", vendors=vendors, end=math.ceil(count/limit))
|
||||
|
||||
|
||||
@meal_planner_api.route('/api/addEvent', methods=["POST"])
|
||||
@access_api.login_required
|
||||
def addEvent():
|
||||
@ -78,6 +96,7 @@ def addEvent():
|
||||
event_date_end=event_date_end,
|
||||
created_by=session['user_id'],
|
||||
recipe_uuid=request.get_json()['recipe_uuid'],
|
||||
receipt_uuid=None,
|
||||
event_type=request.get_json()['event_type']
|
||||
)
|
||||
|
||||
@ -86,6 +105,20 @@ def addEvent():
|
||||
return jsonify(status=201, message="Event added Successfully!")
|
||||
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!")
|
||||
|
||||
@meal_planner_api.route('/api/addTOEvent', methods=["POST"])
|
||||
@access_api.login_required
|
||||
def addTOEvent():
|
||||
if request.method == "POST":
|
||||
site_name = session['selected_site']
|
||||
data= request.get_json()
|
||||
user_id = session['user_id']
|
||||
|
||||
meal_planner_processes.addTakeOutEvent(site_name, data, user_id)
|
||||
|
||||
return jsonify(status=201, message="Event added Successfully!")
|
||||
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!")
|
||||
|
||||
|
||||
@meal_planner_api.route('/api/saveEvent', methods=["POST"])
|
||||
@access_api.login_required
|
||||
def saveEvent():
|
||||
|
||||
@ -3,6 +3,46 @@ import psycopg2
|
||||
from application import postsqldb
|
||||
import config
|
||||
|
||||
def requestNextReceiptID(site_name, conn=None):
|
||||
"""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
|
||||
self_conn = False
|
||||
sql = f"SELECT receipt_id FROM {site_name}_receipts ORDER BY id DESC LIMIT 1;"
|
||||
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)
|
||||
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
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return next_receipt_id
|
||||
except (Exception, psycopg2.DatabaseError) as error:
|
||||
raise postsqldb.DatabaseError(error, payload=(), sql=sql)
|
||||
|
||||
def paginateRecipesTuples(site: str, payload: tuple, convert=True, conn=None):
|
||||
self_conn = False
|
||||
recipes = ()
|
||||
@ -34,6 +74,37 @@ def paginateRecipesTuples(site: str, payload: tuple, convert=True, conn=None):
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def paginateVendorsTuples(site: str, payload: tuple, convert=True, conn=None):
|
||||
self_conn = False
|
||||
recipes = ()
|
||||
count = 0
|
||||
sql = f"SELECT * FROM {site}_vendors ORDER BY vendor_name ASC LIMIT %s OFFSET %s;"
|
||||
sql_count = f"SELECT COUNT(*) FROM {site}_vendors;"
|
||||
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.fetchall()
|
||||
if rows and convert:
|
||||
recipes = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows]
|
||||
if rows and not convert:
|
||||
recipes = rows
|
||||
|
||||
cur.execute(sql_count)
|
||||
count = cur.fetchone()[0]
|
||||
|
||||
if self_conn:
|
||||
conn.close()
|
||||
|
||||
return recipes, count
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def selectPlanEventsByMonth(site: str, payload: tuple, convert=True, conn=None):
|
||||
"""payload=(year, month)"""
|
||||
self_conn = False
|
||||
@ -127,6 +198,62 @@ def insertPlanEventTuple(site: str, payload: tuple, convert=True, conn=None):
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def insertReceiptItemsTuple(site, payload, convert=True, conn=None):
|
||||
receipt_item = ()
|
||||
self_conn = False
|
||||
with open(f"application/meal_planner/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 insertReceiptsTuple(site, payload, convert=True, conn=None):
|
||||
receipt = ()
|
||||
self_conn = False
|
||||
with open(f"application/meal_planner/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 updatePlanEventTuple(site:str, payload: dict, convert=True, conn=None):
|
||||
""" payload (dict): {'barcode': row_id, 'update': {... column_to_update: value_to_update_to...}} """
|
||||
updated = ()
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
import datetime
|
||||
import psycopg2
|
||||
|
||||
from application.meal_planner import meal_planner_database
|
||||
from application import postsqldb, database_payloads
|
||||
import config
|
||||
|
||||
def addTakeOutEvent(site, data, user_id, conn=None):
|
||||
event_date_start = datetime.datetime.strptime(data['event_date_start'], "%Y-%m-%d")
|
||||
event_date_end = datetime.datetime.strptime(data['event_date_end'], "%Y-%m-%d")
|
||||
|
||||
vendor_id = data['vendor_id']
|
||||
|
||||
self_conn = False
|
||||
if not conn:
|
||||
database_config = config.config()
|
||||
conn = psycopg2.connect(**database_config)
|
||||
conn.autocommit = False
|
||||
self_conn = True
|
||||
|
||||
receipt_id = meal_planner_database.requestNextReceiptID(site, conn=conn)
|
||||
|
||||
receipt_payload = database_payloads.ReceiptPayload(
|
||||
receipt_id=f"TOR-{receipt_id}",
|
||||
receipt_status="Unresolved",
|
||||
submitted_by=user_id,
|
||||
vendor_id=vendor_id
|
||||
)
|
||||
|
||||
receipt = meal_planner_database.insertReceiptsTuple(site, receipt_payload.payload(), conn=conn)
|
||||
|
||||
print(receipt)
|
||||
|
||||
receipt_item = database_payloads.ReceiptItemPayload(
|
||||
type = 'custom',
|
||||
receipt_id=receipt['id'],
|
||||
barcode="",
|
||||
item_uuid=None,
|
||||
name=data['event_shortname'],
|
||||
qty=data['attendees'],
|
||||
uom=1,
|
||||
data={'cost': data['cost'], 'expires': False}
|
||||
)
|
||||
|
||||
receipt_item = meal_planner_database.insertReceiptItemsTuple(site, receipt_item.payload(), conn=conn)
|
||||
print(receipt_item)
|
||||
event_payload = database_payloads.PlanEventPayload(
|
||||
plan_uuid=None,
|
||||
event_shortname=data['event_shortname'],
|
||||
event_description=data['event_description'],
|
||||
event_date_start=event_date_start,
|
||||
event_date_end=event_date_end,
|
||||
created_by=user_id,
|
||||
recipe_uuid=data['recipe_uuid'],
|
||||
receipt_uuid=receipt['receipt_uuid'],
|
||||
event_type=data['event_type']
|
||||
)
|
||||
|
||||
event = meal_planner_database.insertPlanEventTuple(site, event_payload.payload(), conn=conn)
|
||||
print(event)
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return False
|
||||
|
||||
return True
|
||||
@ -1,4 +1,4 @@
|
||||
INSERT INTO %%site_name%%_plan_events
|
||||
(plan_uuid, event_shortname, event_description, event_date_start, event_date_end, created_by, recipe_uuid, event_type)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
(plan_uuid, event_shortname, event_description, event_date_start, event_date_end, created_by, recipe_uuid, receipt_uuid, event_type)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/meal_planner/sql/insertReceiptItemsTuple.sql
Normal file
4
application/meal_planner/sql/insertReceiptItemsTuple.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_receipt_items
|
||||
(type, receipt_id, barcode, item_uuid, name, qty, uom, data, status)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/meal_planner/sql/insertReceiptsTuple.sql
Normal file
4
application/meal_planner/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 *;
|
||||
@ -133,6 +133,24 @@
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.take-out-label {
|
||||
background:rgb(250, 162, 238);
|
||||
margin-bottom: 3px;
|
||||
padding: 2px 5px;
|
||||
border-radius: 1px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.take-out-label:hover{
|
||||
background-color: rgb(225, 255, 255);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.take-out-label:hover, .custom-label-selected {
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.my-list-item:hover {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
@ -105,6 +105,7 @@ async function setupCalendarAndEvents(){
|
||||
let recipeLabel = e.target.closest('.recipe-label');
|
||||
let calendarCell = e.target.closest('.calendar-cell');
|
||||
let customLabel = e.target.closest('.custom-label');
|
||||
let takeOutLabel = e.target.closest('.take-out-label')
|
||||
if (recipeLabel) {
|
||||
recipeLabel.classList.add('recipe-label-selected')
|
||||
let rect = recipeLabel.getBoundingClientRect();
|
||||
@ -121,6 +122,14 @@ async function setupCalendarAndEvents(){
|
||||
let menuX = rect.left + scrollLeft;
|
||||
let menuY = rect.bottom + scrollTop;
|
||||
showContextMenuForEvent(customLabel, menuX, menuY);
|
||||
} else if (takeOutLabel) {
|
||||
takeOutLabel.classList.add('take-out-label-selected')
|
||||
let rect = takeOutLabel.getBoundingClientRect();
|
||||
let scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
||||
let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
let menuX = rect.left + scrollLeft;
|
||||
let menuY = rect.bottom + scrollTop;
|
||||
showContextMenuForTOEvent(takeOutLabel, menuX, menuY);
|
||||
} else if (calendarCell) {
|
||||
calendarCell.classList.add('calendar-cell-selected')
|
||||
let rect = calendarCell.getBoundingClientRect();
|
||||
@ -167,6 +176,8 @@ async function createCalender() {
|
||||
eventsHTML += `<div class="recipe-label recipe-error" data-event_uuid="${event.event_uuid}" data-day="${day}">${event.event_shortname}</div>`;
|
||||
} else if (event.event_type==="recipe" && !event.has_missing_ingredients){
|
||||
eventsHTML += `<div class="recipe-label recipe-success" data-event_uuid="${event.event_uuid}" data-day="${day}">${event.event_shortname}</div>`;
|
||||
} else if (event.event_type==="take out"){
|
||||
eventsHTML += `<div class="take-out-label" data-event_uuid="${event.event_uuid}" data-day="${day}">${event.event_shortname}</div>`;
|
||||
} else {
|
||||
eventsHTML += `<div class="custom-label" data-event_uuid="${event.event_uuid}" data-day="${day}">${event.event_shortname}</div>`;
|
||||
}
|
||||
@ -218,6 +229,21 @@ function showContextMenuForEvent(eventLabel, x, y) {
|
||||
menu.style.top = y + 'px';
|
||||
}
|
||||
|
||||
function showContextMenuForTOEvent(eventLabel, x, y) {
|
||||
const menu = document.getElementById('calendarContextMenu');
|
||||
// Set only "Edit" and "Remove" (and optionally "Add Another")
|
||||
menu.className = "uk-dropdown uk-open";
|
||||
menu.innerHTML = `
|
||||
<ul class="uk-nav uk-dropdown-nav">
|
||||
<li><a href="#" onclick="postRemoveEvent('${eventLabel.dataset.event_uuid}')">Remove Event</a></li>
|
||||
</ul>
|
||||
`;
|
||||
menu.style.display = 'block';
|
||||
menu.style.left = x + 'px';
|
||||
menu.style.top = y + 'px';
|
||||
}
|
||||
|
||||
|
||||
function showContextMenuForCell(calendarCell, x, y) {
|
||||
const menu = document.getElementById('calendarContextMenu');
|
||||
// Only "Add Event"
|
||||
@ -225,6 +251,7 @@ function showContextMenuForCell(calendarCell, x, y) {
|
||||
menu.innerHTML = `
|
||||
<ul class="uk-nav uk-dropdown-nav">
|
||||
<li><a href="#" onclick="addEvent('${calendarCell.dataset.day}')">Add Event</a></li>
|
||||
<li><a href="#" onclick="addTakeOut('${calendarCell.dataset.day}')">Add Take Out</a></li>
|
||||
</ul>
|
||||
`;
|
||||
menu.style.display = 'block';
|
||||
@ -237,6 +264,7 @@ window.addEventListener('click', function() {
|
||||
document.querySelectorAll('.calendar-cell-selected').forEach(el => el.classList.remove('calendar-cell-selected'));
|
||||
document.querySelectorAll('.custom-label-selected').forEach(el => el.classList.remove('custom-label-selected'));
|
||||
document.querySelectorAll('.recipe-label-selected').forEach(el => el.classList.remove('recipe-label-selected'));
|
||||
document.querySelectorAll('.take-out-label-selected').forEach(el => el.classList.remove('recipe-label-selected'));
|
||||
});
|
||||
|
||||
async function addEvent(day) {
|
||||
@ -594,3 +622,206 @@ async function updateEventsPaginationElement() {
|
||||
}
|
||||
paginationElement.append(nextElement)
|
||||
}
|
||||
|
||||
// Take Out Event Functions
|
||||
var TO_current_page = 1;
|
||||
var TO_end_page = 1;
|
||||
var TO_Limit = 10;
|
||||
var TO_search_string = "";
|
||||
|
||||
async function addTakeOut(day) {
|
||||
TO_current_page = 1;
|
||||
TO_end_page = 1;
|
||||
TO_Limit = 10;
|
||||
TO_search_string = "";
|
||||
let menu = document.getElementById('calendarContextMenu');
|
||||
//let day = menu.getAttribute('data-day')
|
||||
console.log(year, month, day)
|
||||
let customDate = new Date(year, month-1, day);
|
||||
document.getElementById('TO_date_start').value = customDate.toISOString().split('T')[0];
|
||||
document.getElementById('TO_date_end').value = customDate.toISOString().split('T')[0];
|
||||
UIkit.modal(document.getElementById('takeOutOrderModal')).show();
|
||||
}
|
||||
|
||||
async function selectTOEvent() {
|
||||
document.getElementById('TOModalBody').hidden = true
|
||||
document.getElementById('paginationTOModalBody').hidden = false
|
||||
document.getElementById('TOModalFooter').hidden = true
|
||||
let vendors = await fetchVendors()
|
||||
await updateTOPaginationElement()
|
||||
await updateTOTableWithVendors(vendors)
|
||||
}
|
||||
|
||||
async function fetchVendors() {
|
||||
const url = new URL('/planner/api/getVendors', window.location.origin);
|
||||
url.searchParams.append('page', TO_current_page);
|
||||
url.searchParams.append('limit', TO_Limit);
|
||||
url.searchParams.append('search_string', TO_search_string);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
TO_end_page = data.end
|
||||
return data.vendors;
|
||||
}
|
||||
|
||||
async function updateTOTableWithVendors(vendors) {
|
||||
let vendorsTableBody = document.getElementById('vendorsTableBody')
|
||||
vendorsTableBody.innerHTML = ""
|
||||
|
||||
|
||||
for (let i = 0; i < vendors.length; i++){
|
||||
let tableRow = document.createElement('tr')
|
||||
|
||||
let nameCell = document.createElement('td')
|
||||
nameCell.innerHTML = `${vendors[i].vendor_name}`
|
||||
|
||||
|
||||
let opCell = document.createElement('td')
|
||||
|
||||
let selectButton = document.createElement('button')
|
||||
selectButton.setAttribute('class', 'uk-button uk-button-primary uk-button-small')
|
||||
selectButton.innerHTML = "Select"
|
||||
selectButton.onclick = async function() {
|
||||
document.getElementById('vendor_id').value = vendors[i].id
|
||||
document.getElementById('selected_vendor_name').value = vendors[i].vendor_name
|
||||
document.getElementById('TOModalBody').hidden = false
|
||||
document.getElementById('paginationTOModalBody').hidden = true
|
||||
document.getElementById('TOModalFooter').hidden = false
|
||||
}
|
||||
|
||||
opCell.append(selectButton)
|
||||
|
||||
tableRow.append(nameCell, opCell)
|
||||
vendorsTableBody.append(tableRow)
|
||||
}
|
||||
}
|
||||
|
||||
async function setTOModalPage(pageNumber){
|
||||
TO_current_page = pageNumber;
|
||||
let vendors = await fetchVendors()
|
||||
await updateTOTableWithVendors(vendors)
|
||||
await updateTOPaginationElement()
|
||||
}
|
||||
|
||||
async function updateTOPaginationElement() {
|
||||
let paginationElement = document.getElementById('takeOutOrderPage');
|
||||
paginationElement.innerHTML = "";
|
||||
// previous
|
||||
let previousElement = document.createElement('li')
|
||||
if(TO_current_page<=1){
|
||||
previousElement.innerHTML = `<a><span uk-pagination-previous></span></a>`;
|
||||
previousElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
previousElement.innerHTML = `<a onclick="setTOModalPage(${TO_current_page-1})"><span uk-pagination-previous></span></a>`;
|
||||
}
|
||||
paginationElement.append(previousElement)
|
||||
|
||||
//first
|
||||
let firstElement = document.createElement('li')
|
||||
if(TO_current_page<=1){
|
||||
firstElement.innerHTML = `<a><strong>1</strong></a>`;
|
||||
firstElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
firstElement.innerHTML = `<a onclick="setTOModalPage(1)">1</a>`;
|
||||
}
|
||||
paginationElement.append(firstElement)
|
||||
|
||||
// ...
|
||||
if(TO_current_page-2>1){
|
||||
let firstDotElement = document.createElement('li')
|
||||
firstDotElement.classList.add('uk-disabled')
|
||||
firstDotElement.innerHTML = `<span>…</span>`;
|
||||
paginationElement.append(firstDotElement)
|
||||
}
|
||||
// last
|
||||
if(TO_current_page-2>0){
|
||||
let lastElement = document.createElement('li')
|
||||
lastElement.innerHTML = `<a onclick="setTOModalPage(${TO_current_page-1})">${TO_current_page-1}</a>`
|
||||
paginationElement.append(lastElement)
|
||||
}
|
||||
// current
|
||||
if(TO_current_page!=1 && TO_current_page != TO_end_page){
|
||||
let currentElement = document.createElement('li')
|
||||
currentElement.innerHTML = `<li class="uk-active"><span aria-current="page"><strong>${TO_current_page}</strong></span></li>`
|
||||
paginationElement.append(currentElement)
|
||||
}
|
||||
// next
|
||||
if(TO_current_page+2<TO_end_page+1){
|
||||
let nextElement = document.createElement('li')
|
||||
nextElement.innerHTML = `<a onclick="setTOModalPage(${TO_current_page+1})">${TO_current_page+1}</a>`
|
||||
paginationElement.append(nextElement)
|
||||
}
|
||||
// ...
|
||||
if(TO_current_page+2<=TO_end_page){
|
||||
let secondDotElement = document.createElement('li')
|
||||
secondDotElement.classList.add('uk-disabled')
|
||||
secondDotElement.innerHTML = `<span>…</span>`;
|
||||
paginationElement.append(secondDotElement)
|
||||
}
|
||||
//end
|
||||
let endElement = document.createElement('li')
|
||||
if(TO_current_page>=TO_end_page){
|
||||
endElement.innerHTML = `<a><strong>${TO_end_page}</strong></a>`;
|
||||
endElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
endElement.innerHTML = `<a onclick="setTOModalPage(${TO_end_page})">${TO_end_page}</a>`;
|
||||
}
|
||||
paginationElement.append(endElement)
|
||||
//next button
|
||||
let nextElement = document.createElement('li')
|
||||
if(TO_current_page>=TO_end_page){
|
||||
nextElement.innerHTML = `<a><span uk-pagination-next></span></a>`;
|
||||
nextElement.classList.add('uk-disabled');
|
||||
}else {
|
||||
nextElement.innerHTML = `<a onclick="setTOModalPage(${TO_current_page+1})"><span uk-pagination-next></span></a>`;
|
||||
console.log(nextElement.innerHTML)
|
||||
}
|
||||
paginationElement.append(nextElement)
|
||||
}
|
||||
|
||||
async function postTOEvent(){
|
||||
let event_shortname = `Take Out: ${document.getElementById('selected_vendor_name').value}`
|
||||
let event_description = `Take out dining at ${event_shortname}`
|
||||
let event_date_start = document.getElementById('TO_date_start').value
|
||||
let event_date_end = document.getElementById('TO_date_end').value
|
||||
let event_type = 'take out'
|
||||
let recipe_uuid = null
|
||||
|
||||
let vendor_id = parseInt(document.getElementById('vendor_id').value)
|
||||
let attendees = parseInt(document.getElementById('TO_attendees').value)
|
||||
let cost = parseFloat(document.getElementById('TO_cost').value)
|
||||
|
||||
const response = await fetch('/planner/api/addTOEvent', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
event_shortname: event_shortname,
|
||||
event_description: event_description,
|
||||
event_date_start: event_date_start,
|
||||
event_date_end: event_date_end,
|
||||
recipe_uuid: recipe_uuid,
|
||||
event_type: event_type,
|
||||
vendor_id: vendor_id,
|
||||
attendees: attendees,
|
||||
cost: cost
|
||||
})
|
||||
});
|
||||
|
||||
data = await response.json();
|
||||
response_status = 'primary'
|
||||
if (!data.status === 201){
|
||||
response_status = 'danger'
|
||||
}
|
||||
|
||||
UIkit.notification({
|
||||
message: data.message,
|
||||
status: response_status,
|
||||
pos: 'top-right',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
await setupCalendarAndEvents()
|
||||
UIkit.modal(document.getElementById('takeOutOrderModal')).hide();
|
||||
|
||||
}
|
||||
@ -203,6 +203,103 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Take Out Order -->
|
||||
<div id="takeOutOrderModal" class="uk-flex-top" uk-modal>
|
||||
<div class="uk-modal-dialog">
|
||||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<div class="uk-modal-header">
|
||||
<h2 class="uk-modal-title">Take Out Form</h2>
|
||||
</div>
|
||||
<div id="paginationTOModalBody" class="uk-modal-body" hidden>
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<div class="uk-width-1-1">
|
||||
<div id="searchItemsForm" onkeydown="" class="uk-search uk-search-default uk-align-center">
|
||||
<input id="searchVendorsInput" class="uk-border-pill uk-search-input" type="search" placeholder="" aria-label="">
|
||||
<span class="uk-search-icon-flip" uk-search-icon></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<nav aria-label="Pagination">
|
||||
<ul id="takeOutOrderPage" class="uk-pagination uk-flex-center" uk-margin>
|
||||
<li><a href="#"><span uk-pagination-previous></span></a></li>
|
||||
<li><a href="#">1</a></li>
|
||||
<li class="uk-disabled"><span>…</span></li>
|
||||
<li><a href="#">5</a></li>
|
||||
<li><a href="#">6</a></li>
|
||||
<li class="uk-active"><span aria-current="page">7</span></li>
|
||||
<li><a href="#">8</a></li>
|
||||
<li><a href="#"><span uk-pagination-next></span></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<caption>Select a Vendor from the system...</caption>
|
||||
<table class="uk-table uk-table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Operations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="vendorsTableBody">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="TOModalBody" class="uk-modal-body">
|
||||
<div class="uk-grid-small" uk-grid>
|
||||
<div class="uk-width-1-1">
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="TO_date_start">Date</label>
|
||||
<div class="uk-form-controls">
|
||||
<input id="TO_date_start" class="uk-input uk-disabled" type="date">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-1" hidden>
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="TO_date_end"></label>
|
||||
<div class="uk-form-controls">
|
||||
<input id="TO_date_end" class="uk-input uk-disabled" type="date">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-1" id="vendor_button_modal">
|
||||
<div class="uk-margin">
|
||||
<button class="uk-button uk-button-default" type="button" onclick="selectTOEvent()">Choose Vendor...</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-1" id="vendor_name">
|
||||
<div class="uk-margin">
|
||||
<input id="selected_vendor_name" class="uk-input uk-disabled" type="text" placeholder="No Vendor selected">
|
||||
</div>
|
||||
<input id="vendor_id" hidden>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="TO_attendees">Attendees</label>
|
||||
<div class="uk-form-controls">
|
||||
<input id="TO_attendees" class="uk-input" type="number" step="1" min="1" placeholder="1" value="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<div class="uk-margin">
|
||||
<label class="uk-form-label" for="TO_cost">Cost</label>
|
||||
<div class="uk-form-controls">
|
||||
<input id="TO_cost" class="uk-input" type="number" step="0.01" min="0" placeholder="0.00">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-modal-footer uk-text-right" id="TOModalFooter">
|
||||
<button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button>
|
||||
<button onclick="postTOEvent()" class="uk-button uk-button-primary" type="button">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Event Modal-->
|
||||
<div id="eventModal" class="uk-flex-top" uk-modal>
|
||||
<div class="uk-modal-dialog">
|
||||
|
||||
@ -653,3 +653,6 @@
|
||||
2025-08-21 17:32:19.598403 --- ERROR --- DatabaseError(message='syntax error at or near "%"LINE 1: ...CT COUNT(items.*) FROM main_items items LEFT JOIN %site_name... ^',
|
||||
payload=('', 25, 0),
|
||||
sql='SELECT items.item_uuid as item_uuid, items.item_name as item_name, units.fullname AS fullname, units.id AS unit_id, items.links AS linksFROM main_items itemsLEFT JOIN main_item_info item_info ON item_info.id = items.item_info_idLEFT JOIN units ON item_info.uom = units.idWHERE items.search_string LIKE '%%' || %s || '%%' AND items.inactive IS false AND item_info.safety_stock > 0ORDER BY items.item_name LIMIT %s OFFSET %s;')
|
||||
2025-08-21 18:44:41.870684 --- ERROR --- DatabaseError(message='column "name" does not existLINE 1: SELECT * FROM test_vendors ORDER BY name ASC LIMIT 10 OFFSET... ^',
|
||||
payload=(10, 0),
|
||||
sql='SELECT * FROM test_vendors ORDER BY name ASC LIMIT %s OFFSET %s;')
|
||||
Loading…
x
Reference in New Issue
Block a user