Added site planners to list generation
This commit is contained in:
parent
faafa75422
commit
160c21427d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -314,6 +314,7 @@ def postGeneratedList():
|
||||
payload: dict = request.get_json()
|
||||
site_name: str = session['selected_site']
|
||||
user_id: int = session['user_id']
|
||||
print(payload)
|
||||
shoplist_processess.postNewGeneratedList(site_name, payload, user_id)
|
||||
return jsonify(status=201, message=f"List Generated successfully!")
|
||||
return jsonify(status=405, message=f"{request.method} is not an accepted method on this endpoint!")
|
||||
@ -324,6 +324,36 @@ def getItemByUUID(site, payload:dict, convert=True, conn=None):
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def getEventRecipes(site, payload, convert=True, conn=None):
|
||||
""" payload: dict = {'plan_uuid', 'start_date', 'end_date'}"""
|
||||
records = ()
|
||||
self_conn = False
|
||||
with open('application/shoppinglists/sql/getEventsRecipes.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.fetchall()
|
||||
if rows and convert:
|
||||
records = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows]
|
||||
elif rows and not convert:
|
||||
records = rows
|
||||
|
||||
if self_conn:
|
||||
conn.close()
|
||||
|
||||
return records
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def deleteShoppingListsTuple(site_name, payload, convert=True, conn=None):
|
||||
deleted = ()
|
||||
self_conn = False
|
||||
|
||||
@ -48,6 +48,7 @@ def postNewGeneratedList(site: str, data: dict, user_id: int, conn=None):
|
||||
recipes: list = data['recipes']
|
||||
full_system_calculated: list = data['full_system_calculated']
|
||||
shopping_lists: list = data['shopping_lists']
|
||||
site_plans: list = data['site_plans']
|
||||
|
||||
|
||||
self_conn=False
|
||||
@ -158,6 +159,26 @@ def postNewGeneratedList(site: str, data: dict, user_id: int, conn=None):
|
||||
items_to_add_to_system.append(temp_item)
|
||||
|
||||
|
||||
if site_plans:
|
||||
for site_plan in site_plans:
|
||||
if site_plan['plan_uuid'] == 'site': site_plan['plan_uuid'] = None
|
||||
plan_recipes = [event['recipe_uuid'] for event in shoplist_database.getEventRecipes(site, site_plan, conn=conn)]
|
||||
if plan_recipes:
|
||||
for recipe_uuid in plan_recipes:
|
||||
recipe_items = shoplist_database.getRecipeItemsByUUID(site, (recipe_uuid,), conn=conn)
|
||||
for item in recipe_items:
|
||||
temp_item = database_payloads.ShoppingListItemPayload(
|
||||
list_uuid=shopping_list['list_uuid'],
|
||||
item_type='recipe',
|
||||
item_name=item['item_name'],
|
||||
uom=item['uom'],
|
||||
qty=float(item['qty']),
|
||||
item_uuid=item['item_uuid'],
|
||||
links=item['links']
|
||||
)
|
||||
items_to_add_to_system.append(temp_item)
|
||||
|
||||
|
||||
if items_to_add_to_system:
|
||||
for item in items_to_add_to_system:
|
||||
shoplist_database.insertShoppingListItemsTuple(site, item.payload(), conn=conn)
|
||||
@ -180,8 +201,10 @@ def deleteShoppingList(site: str, data: dict, user_id: int, conn=None):
|
||||
shopping_list_items = [item['list_item_uuid'] for item in shopping_list_items]
|
||||
|
||||
shoplist_database.deleteShoppingListsTuple(site, (shopping_list_uuid,), conn=conn)
|
||||
if shopping_list_items:
|
||||
shoplist_database.deleteShoppingListItemsTuple(site, shopping_list_items, conn=conn)
|
||||
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
7
application/shoppinglists/sql/getEventsRecipes.sql
Normal file
7
application/shoppinglists/sql/getEventsRecipes.sql
Normal file
@ -0,0 +1,7 @@
|
||||
SELECT events.recipe_uuid
|
||||
FROM %%site_name%%_plan_events events
|
||||
WHERE events.plan_uuid IS NULL
|
||||
AND events.event_type = 'recipe'
|
||||
AND events.recipe_uuid IS NOT NULL
|
||||
AND events.event_date_start <= %(end_date)s
|
||||
AND events.event_date_end >= %(start_date)s;
|
||||
@ -1076,6 +1076,130 @@ async function generateListsTable() {
|
||||
|
||||
}
|
||||
|
||||
// Site Planner Functions
|
||||
var site_planners = {}
|
||||
var site_planner_card_active = false;
|
||||
async function addPlannerCard(){
|
||||
if(!site_planner_card_active){
|
||||
document.getElementById('plannerCard').hidden = false
|
||||
site_planner_card_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
async function removePlannerCard(){
|
||||
document.getElementById('plannerCard').hidden = true
|
||||
site_planner_card_active = false;
|
||||
site_planners = []
|
||||
}
|
||||
|
||||
var PlannerZoneState = true
|
||||
async function changePlannerZoneState() {
|
||||
PlannerZoneState = !PlannerZoneState
|
||||
document.getElementById('plannerZone').hidden = !PlannerZoneState
|
||||
}
|
||||
|
||||
async function openPlannerModal(){
|
||||
document.getElementById('planUUID').setAttribute('class', 'uk-input uk-disabled')
|
||||
document.getElementById('planUUID').value = 'site'
|
||||
document.getElementById('planStartDate').value = ''
|
||||
document.getElementById('planEndDate').value = ''
|
||||
document.getElementById('plannerModalButton').innerHTML = "Save"
|
||||
document.getElementById('plannerModalButton').onclick = async function () { await addPlanner()}
|
||||
UIkit.modal(document.getElementById('plannerModal')).show()
|
||||
}
|
||||
|
||||
async function addPlanner() {
|
||||
var planner_select = document.getElementById('planUUID')
|
||||
planner_uuid = planner_select.value
|
||||
plan_name = planner_select.options[planner_select.selectedIndex].text
|
||||
startDate = document.getElementById('planStartDate').value
|
||||
endDate = document.getElementById('planEndDate').value
|
||||
site_planners[planner_uuid] = {
|
||||
start_date: startDate,
|
||||
end_date: endDate,
|
||||
plan_uuid: planner_uuid,
|
||||
plan_name: plan_name
|
||||
}
|
||||
UIkit.modal(document.getElementById('plannerModal')).hide()
|
||||
console.log(site_planners)
|
||||
await generatePlannerTable()
|
||||
}
|
||||
|
||||
async function editPlanner(planUUID) {
|
||||
let data = site_planners[planUUID]
|
||||
document.getElementById('planUUID').setAttribute('class', 'uk-input uk-disabled')
|
||||
document.getElementById('planUUID').value = data['plan_uuid']
|
||||
document.getElementById('planStartDate').value = data['start_date']
|
||||
document.getElementById('planEndDate').value = data['end_date']
|
||||
document.getElementById('plannerModalButton').innerHTML = "Save"
|
||||
document.getElementById('plannerModalButton').onclick = async function () {
|
||||
var planner_select = document.getElementById('planUUID')
|
||||
planner_uuid = planner_select.value
|
||||
plan_name = planner_select.options[planner_select.selectedIndex].text
|
||||
startDate = document.getElementById('planStartDate').value
|
||||
endDate = document.getElementById('planEndDate').value
|
||||
site_planners[planner_uuid] = {
|
||||
start_date: startDate,
|
||||
end_date: endDate,
|
||||
plan_uuid: planner_uuid,
|
||||
plan_name: plan_name
|
||||
}
|
||||
|
||||
await generatePlannerTable()
|
||||
UIkit.modal(document.getElementById('plannerModal')).hide()
|
||||
}
|
||||
|
||||
UIkit.modal(document.getElementById('plannerModal')).show()
|
||||
}
|
||||
|
||||
|
||||
async function deletePlan(plannerUUID) {
|
||||
delete site_planners[plannerUUID]
|
||||
await generatePlannerTable()
|
||||
}
|
||||
|
||||
async function generatePlannerTable() {
|
||||
let plannerTableBody = document.getElementById('plannerTableBody')
|
||||
plannerTableBody.innerHTML = ""
|
||||
|
||||
for(const key in site_planners){
|
||||
if(site_planners.hasOwnProperty(key)){
|
||||
let tableRow = document.createElement('tr')
|
||||
|
||||
|
||||
let nameCell = document.createElement('td')
|
||||
nameCell.innerHTML = `${site_planners[key].plan_name}`
|
||||
|
||||
let startCell = document.createElement('td')
|
||||
startCell.innerHTML = `${site_planners[key].start_date}`
|
||||
|
||||
let endCell = document.createElement('td')
|
||||
endCell.innerHTML = `${site_planners[key].end_date}`
|
||||
|
||||
let opCell = document.createElement('td')
|
||||
|
||||
let editButton = document.createElement('button')
|
||||
editButton.setAttribute('class', 'uk-button uk-button-default uk-button-small')
|
||||
editButton.setAttribute('uk-tooltip', 'Edits this rows plan dates.')
|
||||
editButton.innerHTML = "Edit"
|
||||
editButton.onclick = async function() {await editPlanner(site_planners[key].plan_uuid)}
|
||||
|
||||
|
||||
let removeButton = document.createElement('button')
|
||||
removeButton.setAttribute('class', 'uk-button uk-button-default uk-button-small')
|
||||
removeButton.setAttribute('uk-tooltip', 'Removes Shopping List from the saved shopping lists')
|
||||
removeButton.innerHTML = "Remove"
|
||||
removeButton.onclick = async function() {await deletePlan(site_planners[key].plan_uuid)}
|
||||
|
||||
opCell.append(editButton, removeButton)
|
||||
|
||||
tableRow.append(nameCell, startCell, endCell, opCell)
|
||||
plannerTableBody.append(tableRow)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Generate Functions
|
||||
async function postGenerateList() {
|
||||
@ -1088,7 +1212,8 @@ async function postGenerateList() {
|
||||
calculated_items: Object.keys(calculated_items),
|
||||
recipes: Object.keys(recipes),
|
||||
full_system_calculated: full_sku_enabled,
|
||||
shopping_lists: Object.keys(shopping_lists)
|
||||
shopping_lists: Object.keys(shopping_lists),
|
||||
site_plans: Object.values(site_planners)
|
||||
}
|
||||
|
||||
const response = await fetch(`/shopping-lists/api/postGeneratedList`, {
|
||||
@ -1098,4 +1223,5 @@ async function postGenerateList() {
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
location.href = "/shopping-lists"
|
||||
}
|
||||
@ -23,30 +23,55 @@ async function replenishLineTable(sl_items){
|
||||
listItemsTableBody.innerHTML = ""
|
||||
console.log(sl_items)
|
||||
|
||||
for(let i = 0; i < sl_items.length; i++){
|
||||
let tableRow = document.createElement('tr')
|
||||
let grouped = sl_items.reduce((accumen, item) => {
|
||||
if (!accumen[item.item_type]) {
|
||||
accumen[item.item_type] = [];
|
||||
}
|
||||
accumen[item.item_type].push(item);
|
||||
return accumen;
|
||||
}, {});
|
||||
|
||||
console.log(grouped)
|
||||
for(let key in grouped){
|
||||
console.log(key)
|
||||
let items = grouped[key]
|
||||
let headerRow = document.createElement('tr')
|
||||
let headerCell = document.createElement('td')
|
||||
headerCell.colSpan = 3;
|
||||
headerCell.textContent = key.toUpperCase();
|
||||
headerCell.className = 'type-header';
|
||||
headerCell.style = `font-weight: bold;background: #eee; text-align: left;`
|
||||
headerRow.appendChild(headerCell);
|
||||
listItemsTableBody.appendChild(headerRow);
|
||||
|
||||
for(let i = 0; i < items.length; i++){
|
||||
console.log(items)
|
||||
let tableRow = document.createElement('tr')
|
||||
let item = items[i]
|
||||
let checkboxCell = document.createElement('td')
|
||||
checkboxCell.innerHTML = `<label><input class="uk-checkbox" type="checkbox" ${sl_items[i].list_item_state ? 'checked' : ''}></label>`
|
||||
checkboxCell.innerHTML = `<label><input class="uk-checkbox" type="checkbox" ${item.list_item_state ? 'checked' : ''}></label>`
|
||||
checkboxCell.onclick = async function (event) {
|
||||
await updateListItemState(sl_items[i].list_item_uuid, event.target.checked)
|
||||
console.log(item)
|
||||
await updateListItemState(item.list_item_uuid, event.target.checked)
|
||||
}
|
||||
|
||||
namefield = sl_items[i].item_name
|
||||
if(sl_items[i].links.hasOwnProperty('main')){
|
||||
namefield = `<a href=${sl_items[i].links.main} target='_blank'>${sl_items[i].item_name}</a>`
|
||||
namefield = items[i].item_name
|
||||
if(items[i].links.hasOwnProperty('main')){
|
||||
namefield = `<a href=${item.links.main} target='_blank'>${item.item_name}</a>`
|
||||
}
|
||||
|
||||
let nameCell = document.createElement('td')
|
||||
nameCell.innerHTML = namefield
|
||||
|
||||
let qtyuomCell = document.createElement('td')
|
||||
qtyuomCell.innerHTML = `${sl_items[i].qty} ${sl_items[i].uom.fullname}`
|
||||
qtyuomCell.innerHTML = `${item.qty} ${item.uom.fullname}`
|
||||
|
||||
checkboxCell.checked = sl_items[i].list_item_state
|
||||
checkboxCell.checked = item.list_item_state
|
||||
tableRow.append(checkboxCell, nameCell, qtyuomCell)
|
||||
listItemsTableBody.append(tableRow)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchShoppingList() {
|
||||
|
||||
@ -176,11 +176,11 @@
|
||||
<li class="uk-nav-header">Active Operators</li>
|
||||
<li class="uk-nav-divider"></li>
|
||||
<li><a onclick="addCustomItemsCard()" uk-tooltip="title: Create Custom items to add into the generated list.; pos: right">Custom Items</a></li>
|
||||
<li><a onclick="addUncalculatedItemsCard()" uk-tooltip="title: Add items from the system that take a static quantity into the generated list.; pos: right">Non-Calculated System Items</a></li>
|
||||
<li><a onclick="addUncalculatedItemsCard()" uk-tooltip="title: Add items from the system that take a static quantity into the generated list.; pos: right">Un-Calculated System Items</a></li>
|
||||
<li><a onclick="addCalculatedItemsCard()" uk-tooltip="title: Add items from the system that calculate quantity using quantity on hand and a set safety stocks into the generated list.; pos: right">Calculated System Items</a></li>
|
||||
<li><a onclick="addRecipesCard()" uk-tooltip="title: Add Recipes that will take all the ingrediants and add them into the generated list.; pos: right">System Recipes</a></li>
|
||||
<li><a onclick="addFullSKUCard()" uk-tooltip="title: Takes a full safety stock count from the system and adds any quantities below their safety stocks into the generated list.; pos: right">Full System Calculated</a></li>
|
||||
<li><a class="uk-disabled" uk-tooltip="title: Uses a date range and selected planners for each to add any planned recipes into the generated list.; pos: right">Site Planners</a></li>
|
||||
<li><a onclick="addPlannerCard()" uk-tooltip="title: Uses a date range and selected planners for each to add any planned recipes into the generated list.; pos: right">Site Planners</a></li>
|
||||
<li><a onclick="addListsCard()" uk-tooltip="title: Combine already made lists into this one; pos: right">Shopping Lists</a></li>
|
||||
|
||||
</ul>
|
||||
@ -353,6 +353,39 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Full Calculated SKU -->
|
||||
<div id="plannerCard" hidden>
|
||||
<div class="uk-card uk-card-default uk-card-small uk-card-body">
|
||||
<h3>Site Planner Operator
|
||||
<span class="">
|
||||
<button onclick="changePlannerZoneState()" class="uk-button uk-button-small" title="Show/Hide the card body." uk-tooltip>Show/Hide</button>
|
||||
</span>
|
||||
<span class="uk-align-right">
|
||||
<button onclick="removePlannerCard()" class="uk-button uk-button-small" title="Will remove the Recipes card and data from the list." uk-tooltip >Remove</button>
|
||||
</span>
|
||||
</h3>
|
||||
<p class="uk-text-meta">Site Planner Operators allow you to select specific plans and a date range on that planner to insert any planned recipes into the list. This is best
|
||||
utilized without the Recipe Operator, but it has been allowed to have both. Currently you can only have one date range for a plan. If you
|
||||
do attempt to add from the same plan twice it will overwrite the last date range.
|
||||
</p>
|
||||
<div id="plannerZone" uk-grid>
|
||||
<div class="uk-width-1-1">
|
||||
<table class="uk-table uk-table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Plan Name</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Operations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="plannerTableBody"></tbody>
|
||||
</table>
|
||||
<button onclick="openPlannerModal()" class="uk-button uk-button-secondary uk-width-1-1">Add Item</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -655,6 +688,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Site Planner Modal -->
|
||||
<div id="plannerModal" class="uk-modal">
|
||||
<div class="uk-modal-dialog uk-modal-body">
|
||||
<h2 class="uk-modal-title">Add Planner Date Range...</h2>
|
||||
<p class="uk-text-small">Site Planner Operators allow you to select specific plans and a date range on that planner to insert any planned recipes into the list. This is best
|
||||
utilized without the Recipe Operator, but it has been allowed to have both.
|
||||
</p>
|
||||
<table class="uk-table uk-table-responsive uk-table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Plan</td>
|
||||
<td>
|
||||
<select id="planUUID" class="uk-select" aria-label="Select">
|
||||
<option value="site">Site Planner</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start Date</td>
|
||||
<td><input id="planStartDate" class="uk-input" type="date"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>End Date</td>
|
||||
<td><input id="planEndDate" 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="plannerModalButton" onclick="addPlanner()" class="uk-button uk-button-primary" type="button">Add Planner</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@ -578,3 +578,27 @@
|
||||
2025-08-19 15:45:32.184317 --- ERROR --- DatabaseError(message='syntax error at or near "FROM"LINE 11: FROM main_items items ^',
|
||||
payload={'item_uuid': '392f05b5-4ccd-41da-875d-0e593f51b610'},
|
||||
sql='WITH sum_cte AS ( SELECT mi.id, SUM(mil.quantity_on_hand) AS total_sum FROM main_item_locations mil JOIN main_items mi ON mil.part_id = mi.id GROUP BY mi.id)SELECT items.*, COALESCE(row_to_json(item_info.*), '{}') AS item_info, COALESCE(sum_cte.total_sum, 0) AS total_sum,FROM main_items itemsLEFT JOIN main_item_info item_info ON items.item_info_id = item_info.idLEFT JOIN units ON units.id = item_info.uomLEFT JOIN sum_cte ON items.id = sum_cte.idWHERE items.item_uuid = %(item_uuid)s')
|
||||
2025-08-19 17:38:27.622014 --- ERROR --- DatabaseError(message='syntax error at or near ")"LINE 1: ...WHERE main_shopping_list_items.list_item_uuid IN () RETURNIN... ^',
|
||||
payload=[],
|
||||
sql='WITH deleted_rows AS (DELETE FROM main_shopping_list_items WHERE main_shopping_list_items.list_item_uuid IN () RETURNING *) SELECT * FROM deleted_rows;')
|
||||
2025-08-19 17:39:39.750553 --- ERROR --- DatabaseError(message='syntax error at or near ")"LINE 1: ...WHERE main_shopping_list_items.list_item_uuid IN () RETURNIN... ^',
|
||||
payload=[],
|
||||
sql='WITH deleted_rows AS (DELETE FROM main_shopping_list_items WHERE main_shopping_list_items.list_item_uuid IN () RETURNING *) SELECT * FROM deleted_rows;')
|
||||
2025-08-19 17:55:16.825854 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "main_shopping_lists_name_key"DETAIL: Key (name)=() already exists.',
|
||||
payload=('', '', 1, datetime.datetime(2025, 8, 19, 17, 55, 16, 816288), 'plain', 'temporary'),
|
||||
sql='INSERT INTO main_shopping_lists(name, description, author, creation_date, sub_type, list_type) VALUES (%s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||
2025-08-20 05:17:43.764499 --- ERROR --- DatabaseError(message='syntax error at or near ")"LINE 1: ...WHERE main_shopping_list_items.list_item_uuid IN () RETURNIN... ^',
|
||||
payload=[],
|
||||
sql='WITH deleted_rows AS (DELETE FROM main_shopping_list_items WHERE main_shopping_list_items.list_item_uuid IN () RETURNING *) SELECT * FROM deleted_rows;')
|
||||
2025-08-20 05:17:54.498269 --- ERROR --- DatabaseError(message='syntax error at or near ")"LINE 1: ...WHERE main_shopping_list_items.list_item_uuid IN () RETURNIN... ^',
|
||||
payload=[],
|
||||
sql='WITH deleted_rows AS (DELETE FROM main_shopping_list_items WHERE main_shopping_list_items.list_item_uuid IN () RETURNING *) SELECT * FROM deleted_rows;')
|
||||
2025-08-20 05:17:57.313016 --- ERROR --- DatabaseError(message='syntax error at or near ")"LINE 1: ...WHERE main_shopping_list_items.list_item_uuid IN () RETURNIN... ^',
|
||||
payload=[],
|
||||
sql='WITH deleted_rows AS (DELETE FROM main_shopping_list_items WHERE main_shopping_list_items.list_item_uuid IN () RETURNING *) SELECT * FROM deleted_rows;')
|
||||
2025-08-20 15:32:51.822870 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "main_shopping_lists_name_key"DETAIL: Key (name)=(test) already exists.',
|
||||
payload=('test', 'test', 1, datetime.datetime(2025, 8, 20, 15, 32, 51, 814595), 'plain', 'temporary'),
|
||||
sql='INSERT INTO main_shopping_lists(name, description, author, creation_date, sub_type, list_type) VALUES (%s, %s, %s, %s, %s, %s) RETURNING *;')
|
||||
2025-08-20 15:38:30.303845 --- ERROR --- DatabaseError(message='column "start_date" does not existLINE 1: ... FROM main_plan_events WHERE plan_uuid = NULL AND start_date... ^',
|
||||
payload={'start_date': '2025-08-18', 'end_date': '2025-08-24', 'plan_uuid': None, 'plan_name': 'Site Planner'},
|
||||
sql='SELECT * FROM main_plan_events WHERE plan_uuid = %(plan_uuid)s AND start_date <= %(end_date)s AND end_date >= %(start_date)s;')
|
||||
Loading…
x
Reference in New Issue
Block a user