diff --git a/.gitignore b/.gitignore index 2714bdf..6456288 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ test.py .VScodeCounter celerybeat-schedule instance/application.cfg.py +docs diff --git a/application/access_module/__pycache__/access_processes.cpython-313.pyc b/application/access_module/__pycache__/access_processes.cpython-313.pyc new file mode 100644 index 0000000..8dfe248 Binary files /dev/null and b/application/access_module/__pycache__/access_processes.cpython-313.pyc differ diff --git a/application/database_postgres/BaseModel.py b/application/database_postgres/BaseModel.py index 7c446c3..4e345e4 100644 --- a/application/database_postgres/BaseModel.py +++ b/application/database_postgres/BaseModel.py @@ -234,6 +234,7 @@ class BaseModel(ABC): @classmethod def select_tuple(self, site: str, payload: dict, convert: bool = True, conn=None): + ''' payload = {'key': value_to_filter}''' record = () self_conn = False @@ -264,7 +265,41 @@ class BaseModel(ABC): except Exception as error: raise DatabaseError(error, payload, sql) + + @classmethod + def select_tuples_by_key(self, site: str, payload: dict, convert: bool = True, conn=None): + '''payload = {'key'}''' + records = () + self_conn = False + if self.site_agnostic: + sql = f"SELECT * FROM {self.table_name} WHERE {self.primary_key} = %(key)s::{self.primary_key_type};" + else: + sql = f"SELECT * FROM {site}_{self.table_name} WHERE {self.primary_key} = %(key)s::{self.primary_key_type};" + 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 = [tupleDictionaryFactory(cur.description, row) for row in rows] + elif rows and not convert: + records = rows + + if self_conn: + conn.commit() + conn.close() + + return records + + except Exception as error: + raise DatabaseError(error, {}, sql) + @classmethod def select_tuples(self, site: str, convert: bool = True, conn=None): records = () diff --git a/application/database_postgres/CostLayersModel.py b/application/database_postgres/CostLayersModel.py index 0fcfb46..ec70814 100644 --- a/application/database_postgres/CostLayersModel.py +++ b/application/database_postgres/CostLayersModel.py @@ -1,17 +1,93 @@ from dataclasses import dataclass import datetime -from application.database_postgres.BaseModel import BasePayload, BaseModel +import config +import psycopg2 +from application.database_postgres.BaseModel import BasePayload, BaseModel, tupleDictionaryFactory, DatabaseError, updateStringFactory class CostLayersModel(BaseModel): table_name = "cost_layers" + primary_key = "item_location_uuid" + primary_key_type = "uuid" @dataclass class Payload(BasePayload): - aquisition_date: datetime.datetime - quantity: float - cost: float - currency_type: str - vendor: int = 0 - expires: datetime.datetime = None - \ No newline at end of file + item_location_uuid: str + layer_aquisition_date: datetime.datetime + layer_quantity: float + layer_cost: float + layer_currency_type: str + layer_vendor: str = None + layer_expires: datetime.datetime = None + + @classmethod + def delete_by_layer_id(self, site: str, payload: tuple, convert: bool = True, conn=None): + """ Pass a tuple of layer_ids to remove from the database. + + Args: + site (str): name of the site to delete from + payload (tuple): a tuple of layer_ids + convert (bool, optional): whether to return the deleted rows as dictionaries. Defaults to True. + conn (_type_, optional): postgresql connector object. Defaults to None. + + Raises: + DatabaseError: raised for all errors with database handling, logs to database.log + + Returns: + dict, list: returns a list of all deleted rows. + """ + deleted = () + self_conn = False + sql = f"WITH deleted_rows AS (DELETE FROM {site}_{self.table_name} WHERE layer_id IN ({','.join(['%s'] * len(payload))}) RETURNING *) SELECT * FROM deleted_rows;" + 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: + deleted = [tupleDictionaryFactory(cur.description, r) for r in rows] + elif rows and not convert: + deleted = rows + + if self_conn: + conn.commit() + conn.close() + + return deleted + except Exception as error: + raise DatabaseError(error, payload, sql) + + @classmethod + def update_by_layer_id(self, site: str, payload:dict, convert=True, conn=None): + updated = () + self_conn = False + set_clause, values = updateStringFactory(payload['update']) + values.append(payload['key']) + sql = f"UPDATE {site}_{self.table_name} SET {set_clause} WHERE layer_id=%s RETURNING *;" + try: + if not conn: + database_config = config.config() + conn = psycopg2.connect(**database_config) + conn.autocommit = False + self_conn = True + + with conn.cursor() as cur: + cur.execute(sql, values) + rows = cur.fetchone() + if rows and convert: + updated = tupleDictionaryFactory(cur.description, rows) + elif rows and not convert: + updated = rows + + if self_conn: + conn.commit() + conn.close() + + return updated + except Exception as error: + raise DatabaseError(error, payload, sql) \ No newline at end of file diff --git a/application/database_postgres/ItemLocationsModel.py b/application/database_postgres/ItemLocationsModel.py index 3d023df..c883df9 100644 --- a/application/database_postgres/ItemLocationsModel.py +++ b/application/database_postgres/ItemLocationsModel.py @@ -1,5 +1,9 @@ from dataclasses import dataclass, field -from application.database_postgres.BaseModel import BasePayload, BaseModel, lst2pgarr +from application.database_postgres.BaseModel import BasePayload, BaseModel, lst2pgarr, tupleDictionaryFactory, DatabaseError + +import config + +import psycopg2 class ItemLocationsModel(BaseModel): table_name = "item_locations" @@ -11,4 +15,32 @@ class ItemLocationsModel(BaseModel): item_uuid: str location_uuid: str item_quantity_on_hand: float = 0.0 - \ No newline at end of file + + @classmethod + def select_by_location_and_item(self, site:str, payload:dict, convert: bool=True, conn = None): + recordset = () + self_conn = False + sql = f"SELECT * FROM {site}_item_locations WHERE item_uuid = %(item_uuid)s AND location_uuid = %(location_uuid)s;" + 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: + recordset = tupleDictionaryFactory(cur.description, rows) + if rows and not convert: + recordset = rows + + + if self_conn: + conn.close() + + return recordset + + except Exception as error: + raise DatabaseError(error, payload, sql) \ No newline at end of file diff --git a/application/database_postgres/ItemsModel.py b/application/database_postgres/ItemsModel.py index 337ecbe..c0b29b9 100644 --- a/application/database_postgres/ItemsModel.py +++ b/application/database_postgres/ItemsModel.py @@ -33,6 +33,35 @@ class ItemsModel(BaseModel): payload['item_links'] = json.dumps(self.item_links) return payload + @classmethod + def get_item_by_uuid(self, site:str, payload: dict, convert: bool=True, conn = None): + record = () + self_conn = False + with open('application/database_postgres/sql/ItemsModel/getItemAllByUUID.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: + record = tupleDictionaryFactory(cur.description, rows) + if rows and not convert: + record = rows + + if self_conn: + conn.close() + + return record + + except Exception as error: + raise DatabaseError(error, payload, sql) + @classmethod def paginate_items_with_qoh(self, site:str, payload: dict, convert: bool=True, conn = None): recordset = () diff --git a/application/database_postgres/TransactionsModel.py b/application/database_postgres/TransactionsModel.py index aa5bd9e..bd0c9bc 100644 --- a/application/database_postgres/TransactionsModel.py +++ b/application/database_postgres/TransactionsModel.py @@ -6,7 +6,7 @@ from application.database_postgres.BaseModel import BasePayload, BaseModel class TransactionsModel(BaseModel): table_name = "transactions" - primary_key = "item_uuid" + primary_key = "transaction_uuid" primary_key_type = "uuid" @dataclass diff --git a/application/database_postgres/__pycache__/BaseModel.cpython-313.pyc b/application/database_postgres/__pycache__/BaseModel.cpython-313.pyc index 611c1b8..cd77b68 100644 Binary files a/application/database_postgres/__pycache__/BaseModel.cpython-313.pyc and b/application/database_postgres/__pycache__/BaseModel.cpython-313.pyc differ diff --git a/application/database_postgres/__pycache__/CostLayersModel.cpython-313.pyc b/application/database_postgres/__pycache__/CostLayersModel.cpython-313.pyc index f2fd2c5..fdde6a4 100644 Binary files a/application/database_postgres/__pycache__/CostLayersModel.cpython-313.pyc and b/application/database_postgres/__pycache__/CostLayersModel.cpython-313.pyc differ diff --git a/application/database_postgres/__pycache__/ItemLocationsModel.cpython-313.pyc b/application/database_postgres/__pycache__/ItemLocationsModel.cpython-313.pyc index ef0d38f..c7e1a5f 100644 Binary files a/application/database_postgres/__pycache__/ItemLocationsModel.cpython-313.pyc and b/application/database_postgres/__pycache__/ItemLocationsModel.cpython-313.pyc differ diff --git a/application/database_postgres/__pycache__/ItemsModel.cpython-313.pyc b/application/database_postgres/__pycache__/ItemsModel.cpython-313.pyc index c3ed4ec..6c6d4a6 100644 Binary files a/application/database_postgres/__pycache__/ItemsModel.cpython-313.pyc and b/application/database_postgres/__pycache__/ItemsModel.cpython-313.pyc differ diff --git a/application/database_postgres/__pycache__/TransactionsModel.cpython-313.pyc b/application/database_postgres/__pycache__/TransactionsModel.cpython-313.pyc index 14fc344..51985c1 100644 Binary files a/application/database_postgres/__pycache__/TransactionsModel.cpython-313.pyc and b/application/database_postgres/__pycache__/TransactionsModel.cpython-313.pyc differ diff --git a/application/database_postgres/sql/CREATE/cost_layers.sql b/application/database_postgres/sql/CREATE/cost_layers.sql index 566c74a..52e9725 100644 --- a/application/database_postgres/sql/CREATE/cost_layers.sql +++ b/application/database_postgres/sql/CREATE/cost_layers.sql @@ -1,4 +1,5 @@ CREATE TABLE IF NOT EXISTS %%site_name%%_cost_layers ( + layer_id SERIAL UNIQUE, item_location_uuid UUID REFERENCES %%site_name%%_item_locations(item_location_uuid) ON DELETE SET NULL, layer_aquisition_date TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, layer_quantity FLOAT8 DEFAULT 0.00 NOT NULL, diff --git a/application/database_postgres/sql/CREATE/item_info.sql b/application/database_postgres/sql/CREATE/item_info.sql index 02f9fe2..e85c480 100644 --- a/application/database_postgres/sql/CREATE/item_info.sql +++ b/application/database_postgres/sql/CREATE/item_info.sql @@ -7,5 +7,5 @@ CREATE TABLE IF NOT EXISTS %%site_name%%_item_info ( item_safety_stock FLOAT8 DEFAULT 0.00 NOT NULL, item_lead_time_days FLOAT8 DEFAULT 0.00 NOT NULL, item_ai_pick BOOLEAN DEFAULT false NOT NULL, - item_prefixes INTEGER [] DEFAULT '{}' NOT NULL + item_prefixes UUID [] DEFAULT '{}' NOT NULL ); \ No newline at end of file diff --git a/application/database_postgres/sql/CREATE/transactions.sql b/application/database_postgres/sql/CREATE/transactions.sql index e24facd..dad4da9 100644 --- a/application/database_postgres/sql/CREATE/transactions.sql +++ b/application/database_postgres/sql/CREATE/transactions.sql @@ -1,6 +1,6 @@ CREATE TABLE IF NOT EXISTS %%site_name%%_transactions ( - item_uuid UUID PRIMARY KEY REFERENCES %%site_name%%_items(item_uuid) ON DELETE CASCADE, - transaction_uuid UUID DEFAULT uuid_generate_v4() NOT NULL; + transaction_uuid UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + item_uuid UUID REFERENCES %%site_name%%_items(item_uuid) ON DELETE CASCADE NOT NULL, transaction_created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, transaction_name VARCHAR(255) DEFAULT NULL, transaction_type VARCHAR(64) DEFAULT '' NOT NULL, diff --git a/application/database_postgres/sql/INSERT/cost_layers.sql b/application/database_postgres/sql/INSERT/cost_layers.sql index 5515a0e..2651ced 100644 --- a/application/database_postgres/sql/INSERT/cost_layers.sql +++ b/application/database_postgres/sql/INSERT/cost_layers.sql @@ -1,4 +1,4 @@ INSERT INTO %%site_name%%_cost_layers -(aquisition_date, quantity, cost, currency_type, expires, vendor) -VALUES (%(aquisition_date)s, %(quantity)s, %(cost)s, %(currency_type)s, %(expires)s, %(vendor)s) +(item_location_uuid, layer_aquisition_date, layer_quantity, layer_cost, layer_currency_type, layer_expires, layer_vendor) +VALUES (%(item_location_uuid)s::uuid, %(layer_aquisition_date)s, %(layer_quantity)s, %(layer_cost)s, %(layer_currency_type)s, %(layer_expires)s, %(layer_vendor)s) RETURNING *; \ No newline at end of file diff --git a/application/database_postgres/sql/ItemsModel/getItemAllByUUID.sql b/application/database_postgres/sql/ItemsModel/getItemAllByUUID.sql new file mode 100644 index 0000000..c63242e --- /dev/null +++ b/application/database_postgres/sql/ItemsModel/getItemAllByUUID.sql @@ -0,0 +1,44 @@ +WITH passed_uuid AS (SELECT %(item_uuid)s::uuid AS passed_uuid), + cte_conversions AS ( + SELECT * + FROM %%site_name%%_conversions conversion + WHERE conversion.item_uuid = (SELECT passed_uuid FROM passed_uuid) + ), + cte_item_info AS (SELECT item_info.*, + COALESCE((SELECT json_agg(convs) FROM cte_conversions convs), '[]'::json) AS conversions, + COALESCE((SELECT json_agg(p.*) FROM %%site_name%%_sku_prefix p WHERE p.sku_prefix_uuid = ANY(item_info.item_prefixes)), '[]'::json) as prefixes + FROM %%site_name%%_item_info item_info + WHERE item_info.item_uuid = (SELECT passed_uuid FROM passed_uuid) + ), + cte_food_info AS (SELECT * + FROM %%site_name%%_food_info food_info + WHERE food_info.item_uuid = (SELECT passed_uuid FROM passed_uuid) + ), + cte_logistics_info AS (SELECT * + FROM %%site_name%%_logistics_info log_info + WHERE log_info.item_uuid = (SELECT passed_uuid FROM passed_uuid) + ), + cte_item_locations AS ( + SELECT * FROM %%site_name%%_item_locations item_locations + LEFT JOIN %%site_name%%_locations locations ON locations.location_uuid = item_locations.location_uuid + WHERE item_locations.item_uuid = (SELECT passed_uuid FROM passed_uuid) + ), + cte_barcodes AS ( + SELECT + barcode.barcode As barcode, + barcode.in_exchange AS in_exchange, + barcode.out_exchange AS out_exchange, + barcode.descriptor AS descriptor + FROM %%site_name%%_barcodes AS barcode + LEFT JOIN %%site_name%%_items AS item ON item.item_uuid = (SELECT passed_uuid FROM passed_uuid) + WHERE barcode.item_uuid = item.item_uuid + ) + +SELECT item.*, +(SELECT COALESCE(row_to_json(ii), '{}') FROM cte_item_info ii) AS item_info, +(SELECT COALESCE(row_to_json(fi), '{}') FROM cte_food_info fi) AS food_info, +(SELECT COALESCE(row_to_json(li), '{}') FROM cte_logistics_info li) AS logistics_info, +(SELECT COALESCE(array_agg(row_to_json(ils)), '{}') FROM cte_item_locations ils) AS item_locations, +(SELECT COALESCE(array_agg(row_to_json(bar)), '{}') FROM cte_barcodes bar) AS item_barcodes +FROM %%site_name%%_items item +WHERE item.item_uuid=(SELECT passed_uuid FROM passed_uuid) diff --git a/application/items/__pycache__/items_API.cpython-313.pyc b/application/items/__pycache__/items_API.cpython-313.pyc index a6f45a0..da55cdb 100644 Binary files a/application/items/__pycache__/items_API.cpython-313.pyc and b/application/items/__pycache__/items_API.cpython-313.pyc differ diff --git a/application/items/__pycache__/services.cpython-313.pyc b/application/items/__pycache__/services.cpython-313.pyc index 6f550a3..1186726 100644 Binary files a/application/items/__pycache__/services.cpython-313.pyc and b/application/items/__pycache__/services.cpython-313.pyc differ diff --git a/application/items/items_API.py b/application/items/items_API.py index e1ebbe5..5981073 100644 --- a/application/items/items_API.py +++ b/application/items/items_API.py @@ -18,8 +18,9 @@ import application.database_payloads as dbPayloads from application.database_postgres.UsersModel import UsersModel from application.database_postgres.SitesModel import SitesModel from application.database_postgres.UnitsModel import UnitsModel -from application.items import models +from application.items import models, services from application.database_postgres.ItemsModel import ItemsModel +from application.database_postgres.TransactionsModel import TransactionsModel items_api = Blueprint('items_api', __name__, template_folder="templates", static_folder="static") @@ -44,7 +45,7 @@ def items(): def item(item_uuid): sites = [SitesModel.select_tuple('', {'key': site})['site_name'] for site in session['user'].get('user_sites', [])] units = UnitsModel.select_tuples('') - return render_template("item_new.html", id=id, units=units, current_site=session['selected_site'], sites=sites) + return render_template("item_new.html", item_uuid=item_uuid, units=units, current_site=session['selected_site'], sites=sites) @items_api.route("/transaction") @access_api.login_required @@ -82,9 +83,10 @@ def getTransactions(): def getTransaction(): transaction = () if request.method == "GET": - id = int(request.args.get('id', 1)) - site_name = session['selected_site'] - transaction = database_items.getTransaction(site_name, (id, )) + transaction_uuid = int(request.args.get('transaction_uuid', None)) + if transaction_uuid: + site_name = session['selected_site'] + transaction = TransactionsModel.select_tuple(site_name, {'key': transaction_uuid}) return jsonify({"transaction": transaction, "error": False, "message": ""}) return jsonify({"transaction": transaction, "error": True, "message": f"method {request.method} is not allowed."}) @@ -92,11 +94,13 @@ def getTransaction(): @access_api.login_required def get_item(): if request.method == "GET": - id = int(request.args.get('id', 1)) - site_name = session['selected_site'] + item_uuid = request.args.get('item_uuid', None) item = () - - item = database_items.getItemAllByID(site_name, (id, )) + print(item_uuid) + if item_uuid: + site_name = session['selected_site'] + item = ItemsModel.get_item_by_uuid(site_name, {'item_uuid': item_uuid}) + print(item) return jsonify({'item': item, 'error': False, 'message': ''}) return jsonify({'item': item, 'error': True, 'message': f'method {request.method} not allowed.'}) @@ -424,15 +428,13 @@ def getItemLocations(): return jsonify({"locations":recordset, "end":math.ceil(count/limit), "error":False, "message":"item fetched succesfully!"}) return jsonify({"locations":recordset, "end": math.ceil(count/limit), "error":True, "message":"There was an error with this GET statement"}) + @items_api.route('/postTransaction', methods=["POST"]) @access_api.login_required def post_transaction(): if request.method == "POST": - result = items_processes.postAdjustment( - site_name=session['selected_site'], - user_id=session['user_id'], - data=dict(request.json) - ) + print(session.keys()) + result = services.postAdjustment(site_name=session['selected_site'], user_uuid=session['user_uuid'], data=request.get_json()) return jsonify(result) return jsonify({"error":True, "message":"There was an error with this POST statement"}) diff --git a/application/items/services.py b/application/items/services.py index 6e4fb09..087a663 100644 --- a/application/items/services.py +++ b/application/items/services.py @@ -1,4 +1,5 @@ import psycopg2 +import datetime from application.database_postgres.ItemsModel import ItemsModel from application.database_postgres.ItemInfoModel import ItemInfoModel @@ -6,6 +7,7 @@ from application.database_postgres.LogisticsInfoModel import LogisticsInfoModel from application.database_postgres.FoodInfoModel import FoodInfoModel from application.database_postgres.TransactionsModel import TransactionsModel from application.database_postgres.ItemLocationsModel import ItemLocationsModel +from application.database_postgres.CostLayersModel import CostLayersModel import config def add_new_item(site: str, data: dict, user_uuid: str, conn=None): @@ -42,7 +44,7 @@ def add_new_item(site: str, data: dict, user_uuid: str, conn=None): ) items_location = ItemLocationsModel.insert_tuple(site, items_location.payload_dictionary(), conn=conn) - if item['item_category'] in ['FOOD', 'FOOD PLU']: + if item['item_category'] in ['FOOD', 'FOOD_PLU']: food_info['item_uuid'] = item['item_uuid'] food_info_payload = FoodInfoModel.Payload(**food_info) food_info = FoodInfoModel.insert_tuple(site, food_info_payload.payload_dictionary(), conn=conn) @@ -58,4 +60,93 @@ def add_new_item(site: str, data: dict, user_uuid: str, conn=None): if self_conn: conn.commit() - conn.close() \ No newline at end of file + conn.close() + +def postAdjustment(site_name, user_uuid, data: dict, conn=None): + """ This process handles manual transactions found at /items/transaction endpoint + + Args: + site_name (_type_): _description_ + user_uuid (_type_): _description_ + data (dict): dataKEYS = {'item_uuid', 'item_name', 'transaction_type', 'transaction_quantity', 'transaction_description', 'transaction_cost', 'transaction_vendor', 'trans_action_expires', 'location_uuid'} + conn (_type_, optional): _description_. Defaults to None. + """ + def quantityFactory(quantity_on_hand:float, quantity:float, transaction_type:str): + if transaction_type == "Adjust In": + quantity_on_hand += quantity + return quantity_on_hand + if transaction_type == "Adjust Out": + quantity_on_hand -= quantity + return quantity_on_hand + raise Exception("The transaction type is wrong!") + + self_conn = False + + if not conn: + database_config = config.config() + conn = psycopg2.connect(**database_config) + conn.autocommit = False + self_conn = True + + transaction_data = { + 'item_uuid': data['item_uuid'], + 'transaction_created_by': user_uuid, + 'transaction_name': data['item_name'], + 'transaction_type': data['transaction_type'], + 'transaction_quantity': data['transaction_quantity'], + 'transaction_cost': data['transaction_cost'], + 'transaction_description': data['transaction_description'] + } + + transaction = TransactionsModel.Payload(**transaction_data) + + location = ItemLocationsModel.select_by_location_and_item(site_name, {'item_uuid': data['item_uuid'], 'location_uuid': data['location_uuid']}) + + cost_layer_data = { + 'item_location_uuid': location['item_location_uuid'], + 'layer_aquisition_date': datetime.datetime.now(), + 'layer_quantity': data['transaction_quantity'], + 'layer_cost': data['transaction_cost'], + 'layer_currency_type': "USD" + } + + new_cost_layer = CostLayersModel.Payload(**cost_layer_data) + + cost_layers = list(CostLayersModel.select_tuples_by_key(site_name, {'key': location['item_location_uuid']}, conn=conn)) + print(cost_layers) + cost_layers.sort(key=lambda x: x['layer_aquisition_date']) + + if data['transaction_type'] == "Adjust In": + CostLayersModel.insert_tuple(site_name, new_cost_layer.payload_dictionary(), conn=conn) + + if data['transaction_type'] == "Adjust Out": + if float(location['item_quantity_on_hand']) < float(data['transaction_quantity']): + pass + else: + qty = float(data['transaction_quantity']) + for layer in cost_layers: + if qty >= float(layer['layer_quantity']): + qty -= float(layer['layer_quantity']) + layer['layer_quantity'] = 0.0 + else: + layer['layer_quantity'] -= qty + CostLayersModel.update_by_layer_id(site_name, {'key': layer['layer_id'], 'update': {'layer_quantity': layer['layer_quantity']}}, conn=conn) + qty = 0.0 + + if layer['layer_quantity'] == 0.0: + CostLayersModel.delete_by_layer_id(site_name, (layer['layer_id'],), conn=conn) + + quantity_on_hand = quantityFactory(float(location['item_quantity_on_hand']), data['transaction_quantity'], data['transaction_type']) + + ItemLocationsModel.update_tuple(site_name, {'key': location['item_location_uuid'], 'update': {'item_quantity_on_hand': quantity_on_hand}}, conn=conn) + + transaction.data = {'location': location['item_location_uuid']} + + TransactionsModel.insert_tuple(site_name, transaction.payload_dictionary(), conn=conn) + + if self_conn: + conn.commit() + conn.close() + return False + + return conn \ No newline at end of file diff --git a/application/items/static/itemEditHandler.js b/application/items/static/itemEditHandler.js index 457f224..270119e 100644 --- a/application/items/static/itemEditHandler.js +++ b/application/items/static/itemEditHandler.js @@ -1117,8 +1117,8 @@ async function fetchLocations(logis) { } async function fetchItem() { - const url = new URL('/items/getItem', window.location.origin); - url.searchParams.append('id', item_id); + const url = new URL('/items/api/getItem', window.location.origin); + url.searchParams.append('item_uuid', item_uuid); const response = await fetch(url); data = await response.json(); item = data.item; diff --git a/application/items/static/transactionHandler.js b/application/items/static/transactionHandler.js index 5100dc8..92386ce 100644 --- a/application/items/static/transactionHandler.js +++ b/application/items/static/transactionHandler.js @@ -87,7 +87,7 @@ async function selectItem(item_uuid) { } var transaction_zone_uuid = "" -var transaction_location_uuid = "" +var transaction_item_location_uuid = "" async function selectLocation(zone_uuid, location_uuid, zone_name, location_name) { document.getElementById('zone').value = zone_name document.getElementById('location').value = location_name @@ -131,6 +131,7 @@ async function replenishItemLocationsTable(locations) { let itemLocationTableBody = document.getElementById('itemLocationTableBody') itemLocationTableBody.innerHTML = "" for(let i = 0; i < locations.length; i++){ + console.log(locations[i]) let tableRow = document.createElement('tr') let loca = locations[i].location_shortname.split('@') @@ -198,7 +199,7 @@ async function getItem(item_uuid) { } async function validateTransaction() { - let database_id = document.getElementById("database_id") + let database_uuid = document.getElementById("database_uuid") let transaction_type = document.getElementById("trans_type") let transaction_zone = document.getElementById("zone") let transaction_location = document.getElementById("location") @@ -207,11 +208,11 @@ async function validateTransaction() { let error_count = 0 - if(database_id.value === ""){ + if(database_uuid.value === ""){ error_count = error_count + 1 - database_id.classList.add("uk-form-danger") + database_uuid.classList.add("uk-form-danger") } else { - database_id.classList.remove("uk-form-danger") + database_uuid.classList.remove("uk-form-danger") } if(transaction_type.value === "0"){ error_count = error_count + 1 @@ -270,12 +271,12 @@ async function submitTransaction() { item_uuid: item.item_uuid, item_name: item.item_name, transaction_type: document.getElementById('trans_type').value, - quantity: parseFloat(document.getElementById('transaction_quantity').value), - description: document.getElementById('transaction_description').value, - cost: cost, - vendor: 0, - expires: null, - location_id: transaction_location_uuid + transaction_quantity: parseFloat(document.getElementById('transaction_quantity').value), + transaction_description: document.getElementById('transaction_description').value, + transaction_cost: cost, + transaction_vendor: null, + trans_action_expires: null, + location_uuid: transaction_item_location_uuid }), }); data = await response.json(); @@ -291,7 +292,7 @@ async function submitTransaction() { timeout: 5000 }); - item = await getItem(item.id) + item = await getItem(item.item_uuid) await populateForm() document.getElementById('transaction_quantity').value = '0.00' diff --git a/application/items/static/transactionsHandler.js b/application/items/static/transactionsHandler.js index a2d76c8..b210375 100644 --- a/application/items/static/transactionsHandler.js +++ b/application/items/static/transactionsHandler.js @@ -104,9 +104,9 @@ async function getItem(id) { return item; } -async function getTransaction(id) { +async function getTransaction(transaction_uuid) { const url = new URL('/items/getTransaction', window.location.origin); - url.searchParams.append('id', id); + url.searchParams.append('transaction_uuid', transaction_uuid); const response = await fetch(url); data = await response.json(); let transaction = data.transaction; diff --git a/application/items/templates/transaction.html b/application/items/templates/transaction.html index 7a8345a..324f984 100644 --- a/application/items/templates/transaction.html +++ b/application/items/templates/transaction.html @@ -128,7 +128,7 @@