Transferred posting new item to new api
This commit is contained in:
parent
5933cc7338
commit
aec8f85a4d
461
application/database_payloads.py
Normal file
461
application/database_payloads.py
Normal file
@ -0,0 +1,461 @@
|
||||
from dataclasses import dataclass, field
|
||||
import json, datetime
|
||||
from database import lst2pgarr
|
||||
|
||||
@dataclass
|
||||
class LogisticsInfoPayload:
|
||||
barcode: str
|
||||
primary_location: int
|
||||
primary_zone: int
|
||||
auto_issue_location: int
|
||||
auto_issue_zone: int
|
||||
|
||||
def payload(self):
|
||||
return (self.barcode,
|
||||
self.primary_location,
|
||||
self.primary_zone,
|
||||
self.auto_issue_location,
|
||||
self.auto_issue_zone)
|
||||
|
||||
@dataclass
|
||||
class ItemInfoPayload:
|
||||
barcode: str
|
||||
packaging: str = ""
|
||||
uom_quantity: float = 1.0
|
||||
uom: int = 1
|
||||
cost: float = 0.0
|
||||
safety_stock: float = 0.0
|
||||
lead_time_days: float = 0.0
|
||||
ai_pick: bool = False
|
||||
prefixes: list = field(default_factory=list)
|
||||
|
||||
def __post_init__(self):
|
||||
if not isinstance(self.barcode, str):
|
||||
raise TypeError(f"barcode must be of type str; not {type(self.barcode)}")
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.barcode,
|
||||
self.packaging,
|
||||
self.uom_quantity,
|
||||
self.uom,
|
||||
self.cost,
|
||||
self.safety_stock,
|
||||
self.lead_time_days,
|
||||
self.ai_pick,
|
||||
lst2pgarr(self.prefixes)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class FoodInfoPayload:
|
||||
food_groups: list = field(default_factory=list)
|
||||
ingrediants: list = field(default_factory=list)
|
||||
nutrients: dict = field(default_factory=dict)
|
||||
expires: bool = False
|
||||
default_expiration: float = 0.0
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
lst2pgarr(self.food_groups),
|
||||
lst2pgarr(self.ingrediants),
|
||||
json.dumps(self.nutrients),
|
||||
self.expires,
|
||||
self.default_expiration
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ItemsPayload:
|
||||
barcode: str
|
||||
item_name: str
|
||||
item_info_id: int
|
||||
logistics_info_id: int
|
||||
food_info_id: int
|
||||
brand: int = 0
|
||||
description: str = ""
|
||||
tags: list = field(default_factory=list)
|
||||
links: dict = field(default_factory=dict)
|
||||
row_type: str = ""
|
||||
item_type: str = ""
|
||||
search_string: str =""
|
||||
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.barcode,
|
||||
self.item_name,
|
||||
self.brand,
|
||||
self.description,
|
||||
lst2pgarr(self.tags),
|
||||
json.dumps(self.links),
|
||||
self.item_info_id,
|
||||
self.logistics_info_id,
|
||||
self.food_info_id,
|
||||
self.row_type,
|
||||
self.item_type,
|
||||
self.search_string
|
||||
)
|
||||
|
||||
# done
|
||||
@dataclass
|
||||
class TransactionPayload:
|
||||
timestamp: datetime.datetime
|
||||
logistics_info_id: int
|
||||
barcode: str
|
||||
name: str
|
||||
transaction_type: str
|
||||
quantity: float
|
||||
description: str
|
||||
user_id: int
|
||||
data: dict = field(default_factory=dict)
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.timestamp,
|
||||
self.logistics_info_id,
|
||||
self.barcode,
|
||||
self.name,
|
||||
self.transaction_type,
|
||||
self.quantity,
|
||||
self.description,
|
||||
self.user_id,
|
||||
json.dumps(self.data)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class CostLayerPayload:
|
||||
aquisition_date: datetime.datetime
|
||||
quantity: float
|
||||
cost: float
|
||||
currency_type: str
|
||||
vendor: int = 0
|
||||
expires: datetime.datetime = None
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.aquisition_date,
|
||||
self.quantity,
|
||||
self.cost,
|
||||
self.currency_type,
|
||||
self.expires,
|
||||
self.vendor
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ItemLinkPayload:
|
||||
barcode: str
|
||||
link: int
|
||||
data: dict = field(default_factory=dict)
|
||||
conv_factor: float = 1
|
||||
|
||||
def __post_init__(self):
|
||||
if not isinstance(self.barcode, str):
|
||||
raise TypeError(f"barcode must be of type str; not {type(self.barocde)}")
|
||||
if not isinstance(self.link, int):
|
||||
raise TypeError(f"link must be of type str; not {type(self.link)}")
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.barcode,
|
||||
self.link,
|
||||
json.dumps(self.data),
|
||||
self.conv_factor
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class GroupPayload:
|
||||
name: str
|
||||
description: str
|
||||
group_type: str = "plain"
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.name,
|
||||
self.description,
|
||||
self.group_type
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class GroupItemPayload:
|
||||
uuid: str
|
||||
gr_id: int
|
||||
item_type: str
|
||||
item_name:str
|
||||
uom: str
|
||||
qty: float = 0.0
|
||||
item_id: int = None
|
||||
links: dict = field(default_factory=dict)
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.uuid,
|
||||
self.gr_id,
|
||||
self.item_type,
|
||||
self.item_name,
|
||||
self.uom,
|
||||
self.qty,
|
||||
self.item_id,
|
||||
json.dumps(self.links)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class RecipeItemPayload:
|
||||
uuid: str
|
||||
rp_id: int
|
||||
item_type: str
|
||||
item_name:str
|
||||
uom: str
|
||||
qty: float = 0.0
|
||||
item_id: int = None
|
||||
links: dict = field(default_factory=dict)
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.uuid,
|
||||
self.rp_id,
|
||||
self.item_type,
|
||||
self.item_name,
|
||||
self.uom,
|
||||
self.qty,
|
||||
self.item_id,
|
||||
json.dumps(self.links)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class RecipePayload:
|
||||
name: str
|
||||
author: int
|
||||
description: str
|
||||
creation_date: datetime.datetime = field(init=False)
|
||||
instructions: list = field(default_factory=list)
|
||||
picture_path: str = ""
|
||||
|
||||
def __post_init__(self):
|
||||
self.creation_date = datetime.datetime.now()
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.name,
|
||||
self.author,
|
||||
self.description,
|
||||
self.creation_date,
|
||||
lst2pgarr(self.instructions),
|
||||
self.picture_path
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ReceiptItemPayload:
|
||||
type: str
|
||||
receipt_id: int
|
||||
barcode: str
|
||||
name: str
|
||||
qty: float = 1.0
|
||||
uom: str = "each"
|
||||
data: dict = field(default_factory=dict)
|
||||
status: str = "Unresolved"
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.type,
|
||||
self.receipt_id,
|
||||
self.barcode,
|
||||
self.name,
|
||||
self.qty,
|
||||
self.uom,
|
||||
json.dumps(self.data),
|
||||
self.status
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ReceiptPayload:
|
||||
receipt_id: str
|
||||
receipt_status: str = "Unresolved"
|
||||
date_submitted: datetime.datetime = field(init=False)
|
||||
submitted_by: int = 0
|
||||
vendor_id: int = 1
|
||||
files: dict = field(default_factory=dict)
|
||||
|
||||
def __post_init__(self):
|
||||
self.date_submitted = datetime.datetime.now()
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.receipt_id,
|
||||
self.receipt_status,
|
||||
self.date_submitted,
|
||||
self.submitted_by,
|
||||
self.vendor_id,
|
||||
json.dumps(self.files)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ShoppingListItemPayload:
|
||||
uuid: str
|
||||
sl_id: int
|
||||
item_type: str
|
||||
item_name: str
|
||||
uom: str
|
||||
qty: float
|
||||
item_id: int = None
|
||||
links: dict = field(default_factory=dict)
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.uuid,
|
||||
self.sl_id,
|
||||
self.item_type,
|
||||
self.item_name,
|
||||
self.uom,
|
||||
self.qty,
|
||||
self.item_id,
|
||||
json.dumps(self.links)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ShoppingListPayload:
|
||||
name: str
|
||||
description: str
|
||||
author: int
|
||||
type: str = "plain"
|
||||
creation_date: datetime.datetime = field(init=False)
|
||||
|
||||
def __post_init__(self):
|
||||
self.creation_date = datetime.datetime.now()
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.name,
|
||||
self.description,
|
||||
self.author,
|
||||
self.creation_date,
|
||||
self.type
|
||||
)
|
||||
|
||||
|
||||
# DONE
|
||||
@dataclass
|
||||
class SitePayload:
|
||||
site_name: str
|
||||
site_description: str
|
||||
site_owner_id: int
|
||||
default_zone: str = None
|
||||
default_auto_issue_location: str = None
|
||||
default_primary_location: str = None
|
||||
creation_date: datetime.datetime = field(init=False)
|
||||
flags: dict = field(default_factory=dict)
|
||||
|
||||
def __post_init__(self):
|
||||
self.creation_date = datetime.datetime.now()
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.site_name,
|
||||
self.site_description,
|
||||
self.creation_date,
|
||||
self.site_owner_id,
|
||||
json.dumps(self.flags),
|
||||
self.default_zone,
|
||||
self.default_auto_issue_location,
|
||||
self.default_primary_location
|
||||
)
|
||||
|
||||
#DONE
|
||||
@dataclass
|
||||
class RolePayload:
|
||||
role_name:str
|
||||
role_description:str
|
||||
site_id: int
|
||||
flags: dict = field(default_factory=dict)
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.role_name,
|
||||
self.role_description,
|
||||
self.site_id,
|
||||
json.dumps(self.flags)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ItemLocationPayload:
|
||||
part_id: int
|
||||
location_id: int
|
||||
quantity_on_hand: float = 0.0
|
||||
cost_layers: list = field(default_factory=list)
|
||||
|
||||
def __post_init__(self):
|
||||
if not isinstance(self.part_id, int):
|
||||
raise TypeError(f"part_id must be of type int; not {type(self.part_id)}")
|
||||
if not isinstance(self.location_id, int):
|
||||
raise TypeError(f"part_id must be of type int; not {type(self.part_id)}")
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.part_id,
|
||||
self.location_id,
|
||||
self.quantity_on_hand,
|
||||
lst2pgarr(self.cost_layers)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class SiteManager:
|
||||
site_name: str
|
||||
admin_user: tuple
|
||||
default_zone: int
|
||||
default_location: int
|
||||
description: str
|
||||
create_order: list = field(init=False)
|
||||
drop_order: list = field(init=False)
|
||||
|
||||
def __post_init__(self):
|
||||
self.create_order = [
|
||||
"logins",
|
||||
"sites",
|
||||
"roles",
|
||||
"units",
|
||||
"cost_layers",
|
||||
"linked_items",
|
||||
"brands",
|
||||
"food_info",
|
||||
"item_info",
|
||||
"zones",
|
||||
"locations",
|
||||
"logistics_info",
|
||||
"transactions",
|
||||
"item",
|
||||
"vendors",
|
||||
"groups",
|
||||
"group_items",
|
||||
"receipts",
|
||||
"receipt_items",
|
||||
"recipes",
|
||||
"recipe_items",
|
||||
"shopping_lists",
|
||||
"shopping_list_items",
|
||||
"item_locations",
|
||||
"conversions",
|
||||
"sku_prefix"
|
||||
]
|
||||
self.drop_order = [
|
||||
"item_info",
|
||||
"items",
|
||||
"cost_layers",
|
||||
"linked_items",
|
||||
"transactions",
|
||||
"brands",
|
||||
"food_info",
|
||||
"logistics_info",
|
||||
"zones",
|
||||
"locations",
|
||||
"vendors",
|
||||
"group_items",
|
||||
"groups",
|
||||
"receipt_items",
|
||||
"receipts",
|
||||
"recipe_items",
|
||||
"recipes",
|
||||
"shopping_list_items",
|
||||
"shopping_lists",
|
||||
"item_locations",
|
||||
"conversions",
|
||||
"sku_prefix"
|
||||
]
|
||||
@ -3,7 +3,6 @@ import config
|
||||
import psycopg2
|
||||
import datetime
|
||||
|
||||
|
||||
def getTransactions(site:str, payload: tuple, convert:bool=True):
|
||||
database_config = config.config()
|
||||
sql = f"SELECT * FROM {site}_transactions WHERE logistics_info_id=%s LIMIT %s OFFSET %s;"
|
||||
@ -182,6 +181,23 @@ def getLocation(site:str, payload:tuple, convert:bool=True):
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def getZone(site:str, payload:tuple, convert:bool=True):
|
||||
selected = ()
|
||||
database_config = config.config()
|
||||
sql = f"SELECT * FROM {site}_zones WHERE id=%s;"
|
||||
try:
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
selected = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
selected = rows
|
||||
return selected
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def paginateZonesBySku(site: str, payload: tuple, convert=True):
|
||||
database_config = config.config()
|
||||
zones, count = (), 0
|
||||
@ -513,6 +529,162 @@ def insertItemLocationsTuple(conn, site, payload, convert=True):
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
def insertLogisticsInfoTuple(conn, site, payload, convert=False):
|
||||
"""insert payload into logistics_info table for site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple): (barcode[str], primary_location[str], auto_issue_location[str], dynamic_locations[jsonb],
|
||||
location_data[jsonb], quantity_on_hand[float])
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
logistics_info = ()
|
||||
with open(f"application/items/sql/insertLogisticsInfoTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
logistics_info = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
logistics_info = rows
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
return logistics_info
|
||||
|
||||
def insertItemInfoTuple(conn, site, payload, convert=False):
|
||||
"""inserts payload into the item_info table of site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site_name (str):
|
||||
payload (tuple): (barcode[str], linked_items[lst2pgarr], shopping_lists[lst2pgarr], recipes[lst2pgarr], groups[lst2pgarr],
|
||||
packaging[str], uom[str], cost[float], safety_stock[float], lead_time_days[float], ai_pick[bool])
|
||||
convert (bool optional): Determines if to return tuple as dictionary. DEFAULTS to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
item_info = ()
|
||||
with open(f"application/items/sql/insertItemInfoTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
item_info = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
item_info = rows
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
return item_info
|
||||
|
||||
def insertFoodInfoTuple(conn, site, payload, convert=False):
|
||||
"""insert payload into food_info table for site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (_type_): (ingrediants[lst2pgarr], food_groups[lst2pgarr], nutrients[jsonstr], expires[bool])
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
food_info = ()
|
||||
with open(f"application/items/sql/insertFoodInfoTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
food_info = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
food_info = rows
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
return food_info
|
||||
|
||||
def insertItemTuple(conn, site, payload, convert=False):
|
||||
"""insert payload into items table for site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple): (barcode[str], item_name[str], brand[int], description[str],
|
||||
tags[lst2pgarr], links[jsonb], item_info_id[int], logistics_info_id[int],
|
||||
food_info_id[int], row_type[str], item_type[str], search_string[str])
|
||||
convert (bool, optional): Determines if to return tuple as a dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
item = ()
|
||||
with open(f"application/items/sql/insertItemTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
item = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
item = rows
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
return item
|
||||
|
||||
def insertItemLocationsTuple(conn, site, payload, convert=False):
|
||||
"""insert payload into item_locations table for site
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
site (str):
|
||||
payload (tuple): (part_id[int], location_id[int], quantity_on_hand[float], cost_layers[lst2pgarr])
|
||||
convert (bool, optional): Determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: inserted tuple
|
||||
"""
|
||||
location = ()
|
||||
with open(f"application/items/sql/insertItemLocationsTuple.sql", "r+") as file:
|
||||
sql = file.read().replace("%%site_name%%", site)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
location = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
location = rows
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
return location
|
||||
|
||||
def selectItemLocationsTuple(site_name, payload, convert=True):
|
||||
"""select a single tuple from ItemLocations table for site_name
|
||||
|
||||
@ -570,6 +742,36 @@ def selectCostLayersTuple(site_name, payload, convert=True):
|
||||
except Exception as error:
|
||||
return error
|
||||
|
||||
def selectSiteTuple(payload, convert=True):
|
||||
"""Select a single Site from sites using site_name
|
||||
|
||||
Args:
|
||||
conn (_T_connector@connect): Postgresql Connector
|
||||
payload (tuple): (site_name,)
|
||||
convert (bool, optional): determines if to return tuple as dictionary. Defaults to False.
|
||||
|
||||
Raises:
|
||||
DatabaseError:
|
||||
|
||||
Returns:
|
||||
tuple or dict: selected tuples
|
||||
"""
|
||||
site = ()
|
||||
database_config = config.config()
|
||||
select_site_sql = f"SELECT * FROM sites WHERE site_name = %s;"
|
||||
try:
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(select_site_sql, payload)
|
||||
rows = cur.fetchone()
|
||||
if rows and convert:
|
||||
site = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||
elif rows and not convert:
|
||||
site = rows
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, select_site_sql)
|
||||
return site
|
||||
|
||||
def postDeleteCostLayer(site_name, payload, convert=True, conn=None):
|
||||
"""
|
||||
payload (tuple): (table_to_delete_from, tuple_id)
|
||||
@ -660,7 +862,6 @@ def postAddTransaction(site, payload, convert=False, conn=None):
|
||||
except Exception as error:
|
||||
raise postsqldb.DatabaseError(error, payload, sql)
|
||||
|
||||
|
||||
def postInsertItemLink(site, payload, convert=True, conn=None):
|
||||
"""insert payload into itemlinks table of site
|
||||
|
||||
|
||||
@ -1,7 +1,22 @@
|
||||
from flask import Blueprint, request, render_template, redirect, session, url_for, send_file, jsonify, Response
|
||||
import psycopg2, math, json, datetime, main, copy, requests, process, database, pprint, MyDataclasses
|
||||
# 3rd Party imports
|
||||
from flask import (
|
||||
Blueprint, request, render_template, redirect, session, url_for, send_file, jsonify, Response
|
||||
)
|
||||
import psycopg2
|
||||
import math
|
||||
import json
|
||||
import datetime
|
||||
import copy
|
||||
import requests
|
||||
import pprint
|
||||
|
||||
# applications imports
|
||||
from config import config, sites_config
|
||||
from main import unfoldCostLayers
|
||||
import process
|
||||
import database
|
||||
import main
|
||||
import MyDataclasses
|
||||
from user_api import login_required
|
||||
import application.postsqldb as db
|
||||
from application.items import database_items
|
||||
@ -25,14 +40,14 @@ def items():
|
||||
current_site=session['selected_site'],
|
||||
sites=sites)
|
||||
|
||||
@items_api.route("/item/<id>")
|
||||
@items_api.route("/<id>")
|
||||
@login_required
|
||||
def item(id):
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
database_config = config()
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
units = db.UnitsTable.getAll(conn)
|
||||
return render_template("items/item_new.html", id=id, units=units, current_site=session['selected_site'], sites=sites)
|
||||
return render_template("item_new.html", id=id, units=units, current_site=session['selected_site'], sites=sites)
|
||||
|
||||
@items_api.route("/transaction")
|
||||
@login_required
|
||||
@ -43,14 +58,31 @@ def transaction():
|
||||
units = db.UnitsTable.getAll(conn)
|
||||
return render_template("transaction.html", units=units, current_site=session['selected_site'], sites=sites, proto={'referrer': request.referrer})
|
||||
|
||||
@items_api.route("/transactions/<id>")
|
||||
@login_required
|
||||
def transactions(id):
|
||||
"""This is the main endpoint to reach the webpage for an items transaction history
|
||||
---
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
required: true
|
||||
default: all
|
||||
responses:
|
||||
200:
|
||||
description: Returns the transactions.html webpage for the item with passed ID
|
||||
"""
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
return render_template("transactions.html", id=id, current_site=session['selected_site'], sites=sites)
|
||||
|
||||
@items_api.route("/item/<parent_id>/itemLink/<id>")
|
||||
@items_api.route("/<parent_id>/itemLink/<id>")
|
||||
@login_required
|
||||
def itemLink(parent_id, id):
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
return render_template("itemlink.html", current_site=session['selected_site'], sites=sites, proto={'referrer': request.referrer}, id=id)
|
||||
|
||||
@items_api.route("/item/getTransactions", methods=["GET"])
|
||||
@items_api.route("/getTransactions", methods=["GET"])
|
||||
@login_required
|
||||
def getTransactions():
|
||||
""" GET a subquery of transactions by passing a logistics_info_id, limit, and page
|
||||
@ -71,7 +103,7 @@ def getTransactions():
|
||||
return jsonify({"transactions": recordset, "end": math.ceil(count/limit), "error": False, "message": ""})
|
||||
return jsonify({"transactions": recordset, "end": math.ceil(count/limit), "error": True, "message": f"method {request.method} is not allowed."})
|
||||
|
||||
@items_api.route("/item/getTransaction", methods=["GET"])
|
||||
@items_api.route("/getTransaction", methods=["GET"])
|
||||
@login_required
|
||||
def getTransaction():
|
||||
""" GET a transaction from the system by passing an ID
|
||||
@ -97,7 +129,7 @@ def getTransaction():
|
||||
return jsonify({"transaction": transaction, "error": False, "message": ""})
|
||||
return jsonify({"transaction": transaction, "error": True, "message": f"method {request.method} is not allowed."})
|
||||
|
||||
@items_api.route("/item/getItem", methods=["GET"])
|
||||
@items_api.route("/getItem", methods=["GET"])
|
||||
@login_required
|
||||
def get_item():
|
||||
""" GET item from system by passing its ID
|
||||
@ -183,7 +215,7 @@ def pagninate_items():
|
||||
return jsonify({'items': items, "end": math.ceil(count/limit), 'error':False, 'message': 'Items Loaded Successfully!'})
|
||||
return jsonify({'items': items, "end": math.ceil(count/limit), 'error':True, 'message': 'There was a problem loading the items!'})
|
||||
|
||||
@items_api.route('/item/getModalItems', methods=["GET"])
|
||||
@items_api.route('/getModalItems', methods=["GET"])
|
||||
@login_required
|
||||
def getModalItems():
|
||||
""" GET items from the system by passing a page, limit, search_string. For select modals
|
||||
@ -223,7 +255,7 @@ def getModalItems():
|
||||
return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":False, "message":"items fetched succesfully!"})
|
||||
return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":True, "message": f"method {request.method} is not allowed."})
|
||||
|
||||
@items_api.route('/item/getPrefixes', methods=["GET"])
|
||||
@items_api.route('/getPrefixes', methods=["GET"])
|
||||
@login_required
|
||||
def getModalPrefixes():
|
||||
""" GET prefixes from the system by passing page and limit.
|
||||
@ -259,7 +291,7 @@ def getModalPrefixes():
|
||||
return jsonify({"prefixes":recordset, "end":math.ceil(count/limit), "error":False, "message":"items fetched succesfully!"})
|
||||
return jsonify({"prefixes":recordset, "end":math.ceil(count/limit), "error":True, "message":f"method {request.method} is not allowed!"})
|
||||
|
||||
@items_api.route('/item/getZonesBySku', methods=["GET"])
|
||||
@items_api.route('/getZonesBySku', methods=["GET"])
|
||||
@login_required
|
||||
def getZonesbySku():
|
||||
""" GET zones by sku by passing page, limit, item_id
|
||||
@ -301,7 +333,7 @@ def getZonesbySku():
|
||||
return jsonify({'zones': zones, 'endpage': math.ceil(count/limit), 'error':False, 'message': f''})
|
||||
return jsonify({'zones': zones, 'endpage': math.ceil(count/limit), 'error':False, 'message': f'method {request.method} not allowed.'})
|
||||
|
||||
@items_api.route('/item/getLocationsBySkuZone', methods=['GET'])
|
||||
@items_api.route('/getLocationsBySkuZone', methods=['GET'])
|
||||
@login_required
|
||||
def getLocationsBySkuZone():
|
||||
""" GET locations by sku by passing page, limit, item_id, zone_id
|
||||
@ -351,7 +383,7 @@ def getLocationsBySkuZone():
|
||||
return jsonify({'locations': locations, 'endpage': math.ceil(count/limit), 'error': False, 'message': f''})
|
||||
return jsonify({'locations': locations, 'endpage': math.ceil(count/limit), 'error': True, 'message': f'method {request.method} is not allowed.'})
|
||||
|
||||
@items_api.route('/item/getBrands', methods=['GET'])
|
||||
@items_api.route('/getBrands', methods=['GET'])
|
||||
@login_required
|
||||
def getBrands():
|
||||
""" GET brands from the system by passing page, limit
|
||||
@ -386,7 +418,7 @@ def getBrands():
|
||||
return jsonify({'brands': brands, 'endpage': math.ceil(count/limit), 'error': True, 'message': f'method {request.method} is not allowed.'})
|
||||
|
||||
|
||||
@items_api.route('/item/updateItem', methods=['POST'])
|
||||
@items_api.route('/updateItem', methods=['POST'])
|
||||
@login_required
|
||||
def updateItem():
|
||||
""" POST update to item in the system by passing item_id, data
|
||||
@ -414,7 +446,7 @@ def updateItem():
|
||||
return jsonify({'error': False, 'message': f'Item was updated successfully!'})
|
||||
return jsonify({'error': True, 'message': f'method {request.method} is not allowed!'})
|
||||
|
||||
@items_api.route('/item/updateItemLink', methods=['POST'])
|
||||
@items_api.route('/updateItemLink', methods=['POST'])
|
||||
@login_required
|
||||
def updateItemLink():
|
||||
""" UPDATE item link by passing id, conv_factor, barcode, old_conv
|
||||
@ -462,7 +494,7 @@ def updateItemLink():
|
||||
return jsonify({'error': True, 'message': f"method {request.method} not allowed."})
|
||||
|
||||
|
||||
@items_api.route('/item/getPossibleLocations', methods=["GET"])
|
||||
@items_api.route('/getPossibleLocations', methods=["GET"])
|
||||
@login_required
|
||||
def getPossibleLocations():
|
||||
""" GET locations with zones by passing a page and limit
|
||||
@ -496,7 +528,7 @@ def getPossibleLocations():
|
||||
return jsonify({'locations': locations, 'end':math.ceil(count/limit), 'error':False, 'message': f'Locations received successfully!'})
|
||||
return jsonify({'locations': locations, 'end':math.ceil(count/limit), 'error':True, 'message': f'method {request.method} not allowed.'})
|
||||
|
||||
@items_api.route('/item/getLinkedItem', methods=["GET"])
|
||||
@items_api.route('/getLinkedItem', methods=["GET"])
|
||||
@login_required
|
||||
def getLinkedItem():
|
||||
""" GET itemlink from system by passing an ID
|
||||
@ -521,7 +553,7 @@ def getLinkedItem():
|
||||
return jsonify({'linked_item': linked_item, 'error': False, 'message': 'Linked Item added!!'})
|
||||
return jsonify({'linked_item': linked_item, 'error': True, 'message': f'method {request.method} not allowed'})
|
||||
|
||||
@items_api.route('/item/addLinkedItem', methods=["POST"])
|
||||
@items_api.route('/addLinkedItem', methods=["POST"])
|
||||
@login_required
|
||||
def addLinkedItem():
|
||||
""" POST a link between items by passing a parent_id, a child_id, conv_factor
|
||||
@ -569,7 +601,7 @@ def addLinkedItem():
|
||||
return jsonify({'error': False, 'message': 'Linked Item added!!'})
|
||||
return jsonify({'error': True, 'message': 'These was an error with adding to the linked list!'})
|
||||
|
||||
@items_api.route('/items/addBlankItem', methods=["POST"])
|
||||
@items_api.route('/addBlankItem', methods=["POST"])
|
||||
def addBlankItem():
|
||||
if request.method == "POST":
|
||||
data = {
|
||||
@ -577,20 +609,16 @@ def addBlankItem():
|
||||
'name': request.get_json()['name'],
|
||||
'subtype': request.get_json()['subtype']
|
||||
}
|
||||
pprint.pprint(data)
|
||||
database_config = config()
|
||||
site_name = session['selected_site']
|
||||
user_id = session['user_id']
|
||||
try:
|
||||
with psycopg2.connect(**database_config) as conn:
|
||||
process.postNewBlankItem(conn, site_name, user_id, data)
|
||||
except Exception as error:
|
||||
conn.rollback()
|
||||
return jsonify({'error': True, 'message': error})
|
||||
|
||||
items_processes.postNewBlankItem(site_name, user_id, data)
|
||||
|
||||
return jsonify({'error': False, 'message': 'Item added!!'})
|
||||
return jsonify({'error': True, 'message': 'These was an error with adding Item!'})
|
||||
|
||||
@items_api.route('/items/addSKUPrefix', methods=["POST"])
|
||||
@items_api.route('/addSKUPrefix', methods=["POST"])
|
||||
def addSKUPrefix():
|
||||
if request.method == "POST":
|
||||
database_config = config()
|
||||
@ -609,7 +637,7 @@ def addSKUPrefix():
|
||||
return jsonify({'error': False, 'message': 'Prefix added!!'})
|
||||
return jsonify({'error': True, 'message': 'These was an error with adding this Prefix!'})
|
||||
|
||||
@items_api.route('/item/addConversion', methods=['POST'])
|
||||
@items_api.route('/addConversion', methods=['POST'])
|
||||
def addConversion():
|
||||
if request.method == "POST":
|
||||
item_id = request.get_json()['parent_id']
|
||||
@ -627,7 +655,7 @@ def addConversion():
|
||||
return jsonify(error=False, message="Conversion was added successfully")
|
||||
return jsonify(error=True, message="Unable to save this conversion, ERROR!")
|
||||
|
||||
@items_api.route('/item/deleteConversion', methods=['POST'])
|
||||
@items_api.route('/deleteConversion', methods=['POST'])
|
||||
def deleteConversion():
|
||||
if request.method == "POST":
|
||||
conversion_id = request.get_json()['conversion_id']
|
||||
@ -640,7 +668,7 @@ def deleteConversion():
|
||||
return jsonify(error=False, message="Conversion was deleted successfully")
|
||||
return jsonify(error=True, message="Unable to delete this conversion, ERROR!")
|
||||
|
||||
@items_api.route('/item/updateConversion', methods=['POST'])
|
||||
@items_api.route('/updateConversion', methods=['POST'])
|
||||
def updateConversion():
|
||||
if request.method == "POST":
|
||||
conversion_id = request.get_json()['conversion_id']
|
||||
@ -653,7 +681,7 @@ def updateConversion():
|
||||
return jsonify(error=False, message="Conversion was updated successfully")
|
||||
return jsonify(error=True, message="Unable to save this conversion, ERROR!")
|
||||
|
||||
@items_api.route('/item/addPrefix', methods=['POST'])
|
||||
@items_api.route('/addPrefix', methods=['POST'])
|
||||
def addPrefix():
|
||||
if request.method == "POST":
|
||||
item_info_id = request.get_json()['parent_id']
|
||||
@ -670,7 +698,7 @@ def addPrefix():
|
||||
return jsonify(error=False, message="Prefix was added successfully")
|
||||
return jsonify(error=True, message="Unable to save this prefix, ERROR!")
|
||||
|
||||
@items_api.route('/item/deletePrefix', methods=['POST'])
|
||||
@items_api.route('/deletePrefix', methods=['POST'])
|
||||
def deletePrefix():
|
||||
if request.method == "POST":
|
||||
item_info_id = request.get_json()['item_info_id']
|
||||
@ -685,7 +713,7 @@ def deletePrefix():
|
||||
return jsonify(error=False, message="Prefix was deleted successfully")
|
||||
return jsonify(error=True, message="Unable to delete this prefix, ERROR!")
|
||||
|
||||
@items_api.route('/item/refreshSearchString', methods=['POST'])
|
||||
@items_api.route('/refreshSearchString', methods=['POST'])
|
||||
def refreshSearchString():
|
||||
if request.method == "POST":
|
||||
item_id = request.get_json()['item_id']
|
||||
@ -706,7 +734,7 @@ def refreshSearchString():
|
||||
return jsonify(error=False, message="Search String was updated successfully")
|
||||
return jsonify(error=True, message="Unable to update this search string, ERROR!")
|
||||
|
||||
@items_api.route('/item/postNewItemLocation', methods=['POST'])
|
||||
@items_api.route('/postNewItemLocation', methods=['POST'])
|
||||
def postNewItemLocation():
|
||||
if request.method == "POST":
|
||||
item_id = request.get_json()['item_id']
|
||||
|
||||
@ -1,9 +1,102 @@
|
||||
from application.items import database_items
|
||||
import application.postsqldb as db
|
||||
import application.database_payloads as dbPayloads
|
||||
import config
|
||||
|
||||
import datetime
|
||||
import psycopg2
|
||||
import json
|
||||
|
||||
def postNewBlankItem(site_name: str, user_id: int, data: dict, conn=None):
|
||||
""" data = {'barcode', 'name', 'subtype'}"""
|
||||
self_conn = False
|
||||
if not conn:
|
||||
database_config = config.config()
|
||||
conn = psycopg2.connect(**database_config)
|
||||
conn.autocommit = False
|
||||
self_conn = True
|
||||
|
||||
site = database_items.selectSiteTuple((site_name,))
|
||||
default_zone = database_items.getZone(site_name,(site['default_zone'], ))
|
||||
default_location = database_items.getLocation(site_name, (site['default_primary_location'],))
|
||||
uuid = f"{default_zone['name']}@{default_location['name']}"
|
||||
|
||||
# create logistics info
|
||||
logistics_info = dbPayloads.LogisticsInfoPayload(
|
||||
barcode=data['barcode'],
|
||||
primary_location=site['default_primary_location'],
|
||||
primary_zone=site['default_zone'],
|
||||
auto_issue_location=site['default_auto_issue_location'],
|
||||
auto_issue_zone=site['default_zone']
|
||||
)
|
||||
|
||||
# create item info
|
||||
item_info = dbPayloads.ItemInfoPayload(data['barcode'])
|
||||
|
||||
# create Food Info
|
||||
food_info = dbPayloads.FoodInfoPayload()
|
||||
|
||||
logistics_info_id = 0
|
||||
item_info_id = 0
|
||||
food_info_id = 0
|
||||
brand_id = 1
|
||||
|
||||
|
||||
logistics_info = database_items.insertLogisticsInfoTuple(conn, site_name, logistics_info.payload(), convert=True)
|
||||
item_info = database_items.insertItemInfoTuple(conn, site_name, item_info.payload(), convert=True)
|
||||
food_info = database_items.insertFoodInfoTuple(conn, site_name, food_info.payload(), convert=True)
|
||||
|
||||
name = data['name']
|
||||
name = name.replace("'", "@&apostraphe&")
|
||||
description = ""
|
||||
tags = db.lst2pgarr([])
|
||||
links = json.dumps({})
|
||||
search_string = f"&&{data['barcode']}&&{name}&&"
|
||||
|
||||
|
||||
item = dbPayloads.ItemsPayload(
|
||||
data['barcode'],
|
||||
data['name'],
|
||||
item_info['id'],
|
||||
logistics_info['id'],
|
||||
food_info['id'],
|
||||
brand=brand_id,
|
||||
row_type="single",
|
||||
item_type=data['subtype'],
|
||||
search_string=search_string
|
||||
)
|
||||
|
||||
item = database_items.insertItemTuple(conn, site_name, item.payload(), convert=True)
|
||||
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(f"SELECT id FROM {site_name}_locations WHERE uuid=%s;", (uuid, ))
|
||||
location_id = cur.fetchone()[0]
|
||||
|
||||
dbPayloads.ItemLocationPayload
|
||||
item_location = dbPayloads.ItemLocationPayload(item['id'], location_id)
|
||||
database_items.insertItemLocationsTuple(conn, site_name, item_location.payload())
|
||||
|
||||
|
||||
creation_tuple = dbPayloads.TransactionPayload(
|
||||
datetime.datetime.now(),
|
||||
logistics_info['id'],
|
||||
item['barcode'],
|
||||
item['item_name'],
|
||||
"SYSTEM",
|
||||
0.0,
|
||||
"Item added to the System!",
|
||||
user_id,
|
||||
{'location': uuid}
|
||||
)
|
||||
|
||||
database_items.postAddTransaction(site_name, creation_tuple.payload(), conn=conn)
|
||||
|
||||
if self_conn:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return False
|
||||
|
||||
return conn
|
||||
|
||||
def postLinkedItem(site, payload):
|
||||
"""
|
||||
|
||||
4
application/items/sql/insertFoodInfoTuple.sql
Normal file
4
application/items/sql/insertFoodInfoTuple.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_food_info
|
||||
(ingrediants, food_groups, nutrients, expires, default_expiration)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/items/sql/insertItemInfoTuple.sql
Normal file
4
application/items/sql/insertItemInfoTuple.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_item_info
|
||||
(barcode, packaging, uom_quantity, uom, cost, safety_stock, lead_time_days, ai_pick, prefixes)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/items/sql/insertItemLocationsTuple copy.sql
Normal file
4
application/items/sql/insertItemLocationsTuple copy.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_item_locations
|
||||
(part_id, location_id, quantity_on_hand, cost_layers)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
5
application/items/sql/insertItemTuple.sql
Normal file
5
application/items/sql/insertItemTuple.sql
Normal file
@ -0,0 +1,5 @@
|
||||
INSERT INTO %%site_name%%_items
|
||||
(barcode, item_name, brand, description, tags, links, item_info_id, logistics_info_id,
|
||||
food_info_id, row_type, item_type, search_string)
|
||||
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
4
application/items/sql/insertLogisticsInfoTuple.sql
Normal file
4
application/items/sql/insertLogisticsInfoTuple.sql
Normal file
@ -0,0 +1,4 @@
|
||||
INSERT INTO %%site_name%%_logistics_info
|
||||
(barcode, primary_location, primary_zone, auto_issue_location, auto_issue_zone)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
RETURNING *;
|
||||
@ -214,12 +214,12 @@ async function updateTableElements(){
|
||||
let viewOp = document.createElement('a')
|
||||
viewOp.innerHTML = `edit <span uk-icon="icon: pencil"></span>`
|
||||
viewOp.setAttribute('class', 'uk-button uk-button-default uk-button-small')
|
||||
viewOp.href = `/item/${items[i].id}`
|
||||
viewOp.href = `/items/${items[i].id}`
|
||||
|
||||
let historyOp = document.createElement('a')
|
||||
historyOp.innerHTML = `history <span uk-icon="icon: history"></span>`
|
||||
historyOp.setAttribute('class', 'uk-button uk-button-default uk-button-small')
|
||||
historyOp.href = `/transactions/${items[i].id}`
|
||||
historyOp.href = `/items/transactions/${items[i].id}`
|
||||
|
||||
buttonGroup.append(viewOp, historyOp)
|
||||
opsCell.append(buttonGroup)
|
||||
@ -263,8 +263,8 @@ async function updateListElements(){
|
||||
|
||||
let footer = document.createElement('div')
|
||||
footer.classList.add('uk-card-footer')
|
||||
footer.innerHTML = `<a style="margin-right: 5px; border-radius: 10px;" class="uk-button uk-button-default uk-button-small" uk-icon="icon: pencil" href="/item/${items[i].id}">edit</a>
|
||||
<a style="border-radius: 10px;" class="uk-button uk-button-default uk-button-small" uk-icon="icon: history" href="/transactions/${items[i].id}">History</a>`
|
||||
footer.innerHTML = `<a style="margin-right: 5px; border-radius: 10px;" class="uk-button uk-button-default uk-button-small" uk-icon="icon: pencil" href="/items/${items[i].id}">edit</a>
|
||||
<a style="border-radius: 10px;" class="uk-button uk-button-default uk-button-small" uk-icon="icon: history" href="/items/transactions/${items[i].id}">History</a>`
|
||||
|
||||
listItem.append(header)
|
||||
if(!items[i].description == ""){
|
||||
|
||||
@ -581,7 +581,7 @@ async function updateLinkedItemsTable() {
|
||||
let editOp = document.createElement('a')
|
||||
editOp.setAttribute('class', 'uk-button uk-button-default')
|
||||
editOp.setAttribute('uk-icon', 'icon: pencil')
|
||||
editOp.setAttribute('href', `/item/${item['id']}/itemLink/${linked_items[i].id}`)
|
||||
editOp.setAttribute('href', `/items/${item['id']}/itemLink/${linked_items[i].id}`)
|
||||
|
||||
opCell.append(editOp)
|
||||
|
||||
@ -755,7 +755,7 @@ async function openEditConversionsModal(conversion) {
|
||||
|
||||
|
||||
async function postConversion() {
|
||||
const response = await fetch(`/item/addConversion`, {
|
||||
const response = await fetch(`/items/addConversion`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -786,7 +786,7 @@ async function postConversion() {
|
||||
}
|
||||
|
||||
async function postConversionUpdate(id, update) {
|
||||
const response = await fetch(`/item/updateConversion`, {
|
||||
const response = await fetch(`/items/updateConversion`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -816,7 +816,7 @@ async function postConversionUpdate(id, update) {
|
||||
}
|
||||
|
||||
async function deleteConversion(conversion_id) {
|
||||
const response = await fetch(`/item/deleteConversion`, {
|
||||
const response = await fetch(`/items/deleteConversion`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -858,7 +858,7 @@ async function openAddPrefixesModal() {
|
||||
}
|
||||
|
||||
async function postPrefix(id) {
|
||||
const response = await fetch(`/item/addPrefix`, {
|
||||
const response = await fetch(`/items/addPrefix`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -887,7 +887,7 @@ async function postPrefix(id) {
|
||||
}
|
||||
|
||||
async function deletePrefix(prefix_id) {
|
||||
const response = await fetch(`/item/deletePrefix`, {
|
||||
const response = await fetch(`/items/deletePrefix`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -920,7 +920,7 @@ async function deletePrefix(prefix_id) {
|
||||
|
||||
let prefix_limit = 2;
|
||||
async function fetchPrefixes() {
|
||||
const url = new URL('/item/getPrefixes', window.location.origin);
|
||||
const url = new URL('/items/getPrefixes', window.location.origin);
|
||||
url.searchParams.append('page', current_page);
|
||||
url.searchParams.append('limit', prefix_limit);
|
||||
const response = await fetch(url);
|
||||
@ -930,7 +930,7 @@ async function fetchPrefixes() {
|
||||
|
||||
let brands_limit = 25;
|
||||
async function fetchBrands() {
|
||||
const url = new URL('/item/getBrands', window.location.origin);
|
||||
const url = new URL('/items/getBrands', window.location.origin);
|
||||
url.searchParams.append('page', current_page);
|
||||
url.searchParams.append('limit', brands_limit);
|
||||
const response = await fetch(url);
|
||||
@ -940,7 +940,7 @@ async function fetchBrands() {
|
||||
|
||||
let items_limit = 25;
|
||||
async function fetchItems() {
|
||||
const url = new URL('/item/getModalItems', window.location.origin);
|
||||
const url = new URL('/items/getModalItems', window.location.origin);
|
||||
url.searchParams.append('page', current_page);
|
||||
url.searchParams.append('limit', items_limit);
|
||||
url.searchParams.append('search_string', search_string);
|
||||
@ -951,7 +951,7 @@ async function fetchItems() {
|
||||
|
||||
let zones_limit = 20;
|
||||
async function fetchZones(){
|
||||
const url = new URL('/item/getZonesBySku', window.location.origin);
|
||||
const url = new URL('/items/getZonesBySku', window.location.origin);
|
||||
url.searchParams.append('page', current_page);
|
||||
url.searchParams.append('limit', zones_limit);
|
||||
url.searchParams.append('item_id', item.id);
|
||||
@ -962,7 +962,7 @@ async function fetchZones(){
|
||||
|
||||
let locations_limit = 10;
|
||||
async function fetchLocations(logis) {
|
||||
const url = new URL('/item/getLocationsBySkuZone', window.location.origin);
|
||||
const url = new URL('/items/getLocationsBySkuZone', window.location.origin);
|
||||
url.searchParams.append('page', current_page);
|
||||
url.searchParams.append('limit', locations_limit);
|
||||
url.searchParams.append('part_id', item.id);
|
||||
@ -977,7 +977,7 @@ async function fetchLocations(logis) {
|
||||
}
|
||||
|
||||
async function fetchItem() {
|
||||
const url = new URL('/item/getItem', window.location.origin);
|
||||
const url = new URL('/items/getItem', window.location.origin);
|
||||
url.searchParams.append('id', item_id);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
@ -1106,7 +1106,7 @@ async function addLinkedItem(parent_id, child_id) {
|
||||
|
||||
if(Number.isInteger(conversion_factor)){
|
||||
document.getElementById('conversion_factor').classList.remove('uk-form-danger')
|
||||
const response = await fetch(`/item/addLinkedItem`, {
|
||||
const response = await fetch(`/items/addLinkedItem`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -1145,7 +1145,7 @@ async function addLinkedItem(parent_id, child_id) {
|
||||
}
|
||||
|
||||
async function saveUpdated() {
|
||||
const response = await fetch(`/item/updateItem`, {
|
||||
const response = await fetch(`/items/updateItem`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -1175,7 +1175,7 @@ async function saveUpdated() {
|
||||
};
|
||||
|
||||
async function refreshSearchString() {
|
||||
const response = await fetch(`/item/refreshSearchString`, {
|
||||
const response = await fetch(`/items/refreshSearchString`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -1370,7 +1370,7 @@ var new_locations_current_page = 1
|
||||
var new_locations_end_page = 1
|
||||
var new_locations_limit = 25
|
||||
async function fetch_new_locations() {
|
||||
const url = new URL('/item/getPossibleLocations', window.location.origin);
|
||||
const url = new URL('/items/getPossibleLocations', window.location.origin);
|
||||
url.searchParams.append('page', new_locations_current_page);
|
||||
url.searchParams.append('limit', new_locations_limit);
|
||||
const response = await fetch(url);
|
||||
@ -1380,7 +1380,7 @@ async function fetch_new_locations() {
|
||||
};
|
||||
|
||||
async function postNewItemLocation(location_id) {
|
||||
const response = await fetch(`/item/postNewItemLocation`, {
|
||||
const response = await fetch(`/items/postNewItemLocation`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@ -105,7 +105,7 @@ async function getItem(id) {
|
||||
}
|
||||
|
||||
async function getTransaction(id) {
|
||||
const url = new URL('/item/getTransaction', window.location.origin);
|
||||
const url = new URL('/items/getTransaction', window.location.origin);
|
||||
url.searchParams.append('id', id);
|
||||
const response = await fetch(url);
|
||||
data = await response.json();
|
||||
@ -114,7 +114,7 @@ async function getTransaction(id) {
|
||||
}
|
||||
|
||||
async function getTransactions(){
|
||||
const url = new URL('/item/getTransactions', window.location.origin);
|
||||
const url = new URL('/items/getTransactions', window.location.origin);
|
||||
url.searchParams.append('page', pagination_current);
|
||||
url.searchParams.append('limit', limit);
|
||||
url.searchParams.append('logistics_info_id', item.logistics_info_id)
|
||||
|
||||
@ -691,6 +691,6 @@
|
||||
|
||||
|
||||
</body>
|
||||
<script src="{{ url_for('static', filename='handlers/itemEditHandler.js') }}"></script>
|
||||
<script src="{{ url_for('items_api.static', filename='itemEditHandler.js') }}"></script>
|
||||
<script>const item_id = {{id|tojson}}</script>
|
||||
</html>
|
||||
@ -115,6 +115,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="{{ url_for('static', filename='handlers/transactionsHandler.js') }}"></script>
|
||||
<script src="{{ url_for('items_api.static', filename='transactionsHandler.js') }}"></script>
|
||||
<script>const item_id = {{id|tojson}}</script>
|
||||
</html>
|
||||
@ -2409,3 +2409,64 @@ class ItemLinkPayload:
|
||||
json.dumps(self.data),
|
||||
self.conv_factor
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class LogisticsInfoPayload:
|
||||
barcode: str
|
||||
primary_location: int
|
||||
primary_zone: int
|
||||
auto_issue_location: int
|
||||
auto_issue_zone: int
|
||||
|
||||
def payload(self):
|
||||
return (self.barcode,
|
||||
self.primary_location,
|
||||
self.primary_zone,
|
||||
self.auto_issue_location,
|
||||
self.auto_issue_zone)
|
||||
|
||||
@dataclass
|
||||
class ItemInfoPayload:
|
||||
barcode: str
|
||||
packaging: str = ""
|
||||
uom_quantity: float = 1.0
|
||||
uom: int = 1
|
||||
cost: float = 0.0
|
||||
safety_stock: float = 0.0
|
||||
lead_time_days: float = 0.0
|
||||
ai_pick: bool = False
|
||||
prefixes: list = field(default_factory=list)
|
||||
|
||||
def __post_init__(self):
|
||||
if not isinstance(self.barcode, str):
|
||||
raise TypeError(f"barcode must be of type str; not {type(self.barcode)}")
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
self.barcode,
|
||||
self.packaging,
|
||||
self.uom_quantity,
|
||||
self.uom,
|
||||
self.cost,
|
||||
self.safety_stock,
|
||||
self.lead_time_days,
|
||||
self.ai_pick,
|
||||
lst2pgarr(self.prefixes)
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class FoodInfoPayload:
|
||||
food_groups: list = field(default_factory=list)
|
||||
ingrediants: list = field(default_factory=list)
|
||||
nutrients: dict = field(default_factory=dict)
|
||||
expires: bool = False
|
||||
default_expiration: float = 0.0
|
||||
|
||||
def payload(self):
|
||||
return (
|
||||
lst2pgarr(self.food_groups),
|
||||
lst2pgarr(self.ingrediants),
|
||||
json.dumps(self.nutrients),
|
||||
self.expires,
|
||||
self.default_expiration
|
||||
)
|
||||
19
webserver.py
19
webserver.py
@ -67,25 +67,6 @@ def inject_user():
|
||||
return dict(username="")
|
||||
|
||||
|
||||
@app.route("/transactions/<id>")
|
||||
@login_required
|
||||
def transactions(id):
|
||||
"""This is the main endpoint to reach the webpage for an items transaction history
|
||||
---
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
required: true
|
||||
default: all
|
||||
responses:
|
||||
200:
|
||||
description: Returns the transactions.html webpage for the item with passed ID
|
||||
"""
|
||||
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
|
||||
return render_template("items/transactions.html", id=id, current_site=session['selected_site'], sites=sites)
|
||||
|
||||
|
||||
@app.route("/api/push-subscriptions", methods=["POST"])
|
||||
def create_push_subscription():
|
||||
json_data = request.get_json()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user