|
|
@@ -2,7 +2,8 @@ import json
|
|
|
from math import log
|
|
|
import os
|
|
|
import re
|
|
|
-import sqlite3
|
|
|
+import psycopg2
|
|
|
+from config.settings import POSTGRESQL_DB_CONFIG
|
|
|
from typing import List, Dict, Optional, Any
|
|
|
from abc import ABC, abstractmethod
|
|
|
from config.settings import BG_DATA_PATH, DB_PATH, IMAGE_PATH, PRODUCT_DATA_PATH, CURRENT_URL
|
|
|
@@ -26,10 +27,10 @@ ESQUEMA DE BASE DE DATOS SQLITE (data.db)
|
|
|
|
|
|
1. Tabla: users
|
|
|
-----------------------------------
|
|
|
-- id INTEGER PRIMARY KEY AUTOINCREMENT
|
|
|
-- email TEXT UNIQUE NOT NULL
|
|
|
-- name TEXT NOT NULL
|
|
|
-- rut TEXT UNIQUE NOT NULL
|
|
|
+- id SERIAL PRIMARY KEY
|
|
|
+- email VARCHAR(255) UNIQUE NOT NULL
|
|
|
+- name VARCHAR(255) NOT NULL
|
|
|
+- rut VARCHAR(20) UNIQUE NOT NULL
|
|
|
- pin_hash TEXT NOT NULL (encriptado)
|
|
|
- kleincoins TEXT NOT NULL (encriptado, valor por defecto "0")
|
|
|
- created_at TEXT NOT NULL (fecha de creación en formato ISO 8601)
|
|
|
@@ -38,19 +39,19 @@ ESQUEMA DE BASE DE DATOS SQLITE (data.db)
|
|
|
2. Tabla: products
|
|
|
-----------------------------------
|
|
|
- id INTEGER PRIMARY KEY
|
|
|
-- name TEXT NOT NULL
|
|
|
-- type TEXT
|
|
|
-- description TEXT
|
|
|
-- price REAL NOT NULL
|
|
|
+- name VARCHAR(255) NOT NULL
|
|
|
+- type VARCHAR(100) NOT NULL
|
|
|
+- description TEXT NOT NULL
|
|
|
+- price INTEGER NOT NULL
|
|
|
- image TEXT (URL de la imagen)
|
|
|
- status INTEGER DEFAULT 1 NOT NULL CHECK (status IN (0, 1)) -- 0: Inactivo, 1: Activo
|
|
|
(Guarda los productos disponibles para venta con su estado activo/inactivo)
|
|
|
|
|
|
3. Tabla: sales
|
|
|
-----------------------------------
|
|
|
-- id INTEGER PRIMARY KEY AUTOINCREMENT
|
|
|
-- user_id INTEGER NOT NULL (relación a users.id)
|
|
|
-- total REAL NOT NULL (precio total de la venta)
|
|
|
+- id SERIAL PRIMARY KEY
|
|
|
+- user_id INTEGER NOT NULL REFERENCES users.id
|
|
|
+- total INTEGER NOT NULL (precio total de la venta)
|
|
|
- fudo_id TEXT UNIQUE NOT NULL (ID string único por venta)
|
|
|
- date TEXT NOT NULL (fecha y hora en formato ISO 8601)
|
|
|
- table INTEGER NOT NULL (número de mesa)
|
|
|
@@ -65,7 +66,7 @@ ESQUEMA DE BASE DE DATOS SQLITE (data.db)
|
|
|
|
|
|
5. Tabla: blacklist
|
|
|
-----------------------------------
|
|
|
-- id INTEGER PRIMARY KEY AUTOINCREMENT
|
|
|
+- id SERIAL PRIMARY KEY
|
|
|
- user_id INTEGER NOT NULL (relación a users.id)
|
|
|
(Usuarios bloqueados o no autorizados para ciertas acciones)
|
|
|
|
|
|
@@ -79,14 +80,20 @@ RELACIONES:
|
|
|
# Base abstract class for data access
|
|
|
class BaseDataService(ABC):
|
|
|
"""Abstract base class for data services"""
|
|
|
-
|
|
|
- def __init__(self, db_path: str = DB_PATH):
|
|
|
- self.db_path = db_path
|
|
|
-
|
|
|
- def _get_connection(self) -> sqlite3.Connection:
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ self.db_config = POSTGRESQL_DB_CONFIG
|
|
|
+
|
|
|
+ def _get_connection(self):
|
|
|
"""Get database connection"""
|
|
|
- return sqlite3.connect(self.db_path)
|
|
|
-
|
|
|
+ return psycopg2.connect(
|
|
|
+ dbname=self.db_config['dbname'],
|
|
|
+ user=self.db_config['user'],
|
|
|
+ password=self.db_config['password'],
|
|
|
+ host=self.db_config['host'],
|
|
|
+ port=self.db_config['port']
|
|
|
+ )
|
|
|
+
|
|
|
@abstractmethod
|
|
|
def get_all(self) -> List[Any]:
|
|
|
"""Get all records"""
|
|
|
@@ -123,7 +130,7 @@ class UserDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
try:
|
|
|
cursor.execute(
|
|
|
- "INSERT INTO users (name, email, rut, pin_hash, kleincoins, created_at) VALUES (?, ?, ?, ?, ?, ?)",
|
|
|
+ "INSERT INTO users (name, email, rut, pin_hash, kleincoins, created_at) VALUES (%s, %s, %s, %s, %s, %s)",
|
|
|
(name, email, rut, fernet.encrypt(pin_hash.encode()).decode(), fernet.encrypt(b"0").decode(), datetime.now().isoformat())
|
|
|
)
|
|
|
conn.commit()
|
|
|
@@ -134,7 +141,7 @@ class UserDataService(BaseDataService):
|
|
|
else:
|
|
|
logger.error("Failed to add user.")
|
|
|
return -1
|
|
|
- except sqlite3.IntegrityError as e:
|
|
|
+ except psycopg2.IntegrityError as e:
|
|
|
logger.error(f"Failed to add user: {e}")
|
|
|
return -1
|
|
|
finally:
|
|
|
@@ -164,7 +171,7 @@ class UserDataService(BaseDataService):
|
|
|
"""Get user data from the database"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
|
|
|
+ cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
|
|
|
user = cursor.fetchone()
|
|
|
conn.close()
|
|
|
if user:
|
|
|
@@ -183,7 +190,7 @@ class UserDataService(BaseDataService):
|
|
|
"""Get user by email"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT * FROM users WHERE email = ?", (email,))
|
|
|
+ cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
|
|
|
user = cursor.fetchone()
|
|
|
conn.close()
|
|
|
logger.debug(f"get_by_email: {email}, user: {user}")
|
|
|
@@ -213,8 +220,12 @@ class UserDataService(BaseDataService):
|
|
|
"""Get user permissions"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT permissions FROM users WHERE id = ?", (user_id,))
|
|
|
+ cursor.execute("SELECT permissions FROM users WHERE id = %s", (user_id,))
|
|
|
result = cursor.fetchone()
|
|
|
+ if not result:
|
|
|
+ logger.error(f"User with ID {user_id} not found.")
|
|
|
+ return 0
|
|
|
+ result = result[0]
|
|
|
conn.close()
|
|
|
if result:
|
|
|
return result[0]
|
|
|
@@ -224,8 +235,13 @@ class UserDataService(BaseDataService):
|
|
|
"""Get user by RUT"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT * FROM users WHERE rut = ?", (rut,))
|
|
|
+ cursor.execute("SELECT * FROM users WHERE rut = %s", (rut,))
|
|
|
user = cursor.fetchone()
|
|
|
+ if not user:
|
|
|
+ logger.error(f"User with RUT {rut} not found.")
|
|
|
+ conn.close()
|
|
|
+ return None
|
|
|
+ user = user[0]
|
|
|
conn.close()
|
|
|
if user:
|
|
|
return User(
|
|
|
@@ -247,31 +263,31 @@ class UserDataService(BaseDataService):
|
|
|
updates = []
|
|
|
params = []
|
|
|
if email:
|
|
|
- updates.append("email = ?")
|
|
|
+ updates.append("email = %s")
|
|
|
params.append(email)
|
|
|
if name:
|
|
|
- updates.append("name = ?")
|
|
|
+ updates.append("name = %s")
|
|
|
params.append(name)
|
|
|
if rut:
|
|
|
- updates.append("rut = ?")
|
|
|
+ updates.append("rut = %s")
|
|
|
params.append(rut)
|
|
|
if pin_hash:
|
|
|
- updates.append("pin_hash = ?")
|
|
|
+ updates.append("pin_hash = %s")
|
|
|
params.append(fernet.encrypt(pin_hash.encode()).decode())
|
|
|
if kleincoins is not None:
|
|
|
- updates.append("kleincoins = ?")
|
|
|
+ updates.append("kleincoins = %s")
|
|
|
params.append(fernet.encrypt(str(kleincoins).encode()).decode())
|
|
|
if not updates:
|
|
|
conn.close()
|
|
|
return False
|
|
|
try:
|
|
|
- cursor.execute(f"UPDATE users SET {', '.join(updates)} WHERE id = ?", (*params, user_id))
|
|
|
+ cursor.execute(f"UPDATE users SET {', '.join(updates)} WHERE id = %s", (*params, user_id))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
if success:
|
|
|
logger.info(f"User with ID {user_id} updated.")
|
|
|
return success
|
|
|
- except sqlite3.IntegrityError as e:
|
|
|
+ except psycopg2.IntegrityError as e:
|
|
|
logger.error(f"Failed to update user: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -282,7 +298,7 @@ class UserDataService(BaseDataService):
|
|
|
"""Delete a user from the database"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
|
|
|
+ cursor.execute("DELETE FROM users WHERE id = %s", (user_id,))
|
|
|
conn.commit()
|
|
|
conn.close()
|
|
|
if cursor.rowcount > 0:
|
|
|
@@ -298,7 +314,7 @@ class UserDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
try:
|
|
|
cursor.execute(
|
|
|
- "UPDATE users SET kleincoins = ? WHERE id = ?",
|
|
|
+ "UPDATE users SET kleincoins = %s WHERE id = %s",
|
|
|
(fernet.encrypt(str(kleincoins).encode()).decode(), user_id)
|
|
|
)
|
|
|
conn.commit()
|
|
|
@@ -306,7 +322,7 @@ class UserDataService(BaseDataService):
|
|
|
if success:
|
|
|
logger.info(f"Kleincoins updated for user {user_id}: {kleincoins}")
|
|
|
return success
|
|
|
- except sqlite3.IntegrityError as e:
|
|
|
+ except psycopg2.IntegrityError as e:
|
|
|
logger.error(f"Failed to update kleincoins: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -316,7 +332,7 @@ class UserDataService(BaseDataService):
|
|
|
"""Get user's kleincoins"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT kleincoins FROM users WHERE id = ?", (user_id,))
|
|
|
+ cursor.execute("SELECT kleincoins FROM users WHERE id = %s", (user_id,))
|
|
|
result = cursor.fetchone()
|
|
|
conn.close()
|
|
|
if result:
|
|
|
@@ -337,7 +353,7 @@ class BlacklistDataService(BaseDataService):
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
try:
|
|
|
- cursor.execute("INSERT INTO blacklist (user_id) VALUES (?)", (user_id,))
|
|
|
+ cursor.execute("INSERT INTO blacklist (user_id) VALUES (%s)", (user_id,))
|
|
|
conn.commit()
|
|
|
blacklist_id = cursor.lastrowid
|
|
|
if blacklist_id:
|
|
|
@@ -346,7 +362,7 @@ class BlacklistDataService(BaseDataService):
|
|
|
else:
|
|
|
logger.error(f"Failed to add user with ID {user_id} to blacklist.")
|
|
|
return -1
|
|
|
- except sqlite3.IntegrityError as e:
|
|
|
+ except psycopg2.IntegrityError as e:
|
|
|
logger.error(f"Failed to add user to blacklist: {e}")
|
|
|
return -1
|
|
|
finally:
|
|
|
@@ -382,7 +398,7 @@ class BlacklistDataService(BaseDataService):
|
|
|
SELECT b.id, b.user_id, u.email, u.name, u.rut
|
|
|
FROM blacklist b
|
|
|
LEFT JOIN users u ON b.user_id = u.id
|
|
|
- WHERE b.id = ?
|
|
|
+ WHERE b.id = %s
|
|
|
""", (id,))
|
|
|
row = cursor.fetchone()
|
|
|
conn.close()
|
|
|
@@ -425,7 +441,7 @@ class BlacklistDataService(BaseDataService):
|
|
|
"""Remove a blacklist entry by ID"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("DELETE FROM blacklist WHERE id = ?", (id,))
|
|
|
+ cursor.execute("DELETE FROM blacklist WHERE id = %s", (id,))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
conn.close()
|
|
|
@@ -439,7 +455,7 @@ class BlacklistDataService(BaseDataService):
|
|
|
"""Remove a user from the blacklist"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("DELETE FROM blacklist WHERE user_id = ?", (user_id,))
|
|
|
+ cursor.execute("DELETE FROM blacklist WHERE user_id = %s", (user_id,))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
conn.close()
|
|
|
@@ -459,14 +475,14 @@ class ProductDataService(BaseDataService):
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
if image and "base64" in image:
|
|
|
- extension = re.search(r'data:image/(.*?);base64,', image)
|
|
|
+ extension = re.search(r'data:image/(.*%s);base64,', image)
|
|
|
image_name = f"{id}_img"
|
|
|
if extension:
|
|
|
image_name += f".{extension.group(1)}"
|
|
|
image = self._image_process(image_name, image)
|
|
|
try:
|
|
|
cursor.execute(
|
|
|
- "INSERT INTO products (id, name, type, description, price, image, status) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
|
+ "INSERT INTO products (id, name, type, description, price, image, status) VALUES (%s, %s, %s, %s, %s, %s, %s)",
|
|
|
(id, name, type, description, price, image, status)
|
|
|
)
|
|
|
conn.commit()
|
|
|
@@ -477,7 +493,7 @@ class ProductDataService(BaseDataService):
|
|
|
else:
|
|
|
logger.error("Failed to add product.")
|
|
|
return -1
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to add product: {e}")
|
|
|
return -1
|
|
|
finally:
|
|
|
@@ -525,7 +541,7 @@ class ProductDataService(BaseDataService):
|
|
|
"""Get product by ID"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT * FROM products WHERE id = ?", (product_id,))
|
|
|
+ cursor.execute("SELECT * FROM products WHERE id = %s", (product_id,))
|
|
|
product = cursor.fetchone()
|
|
|
conn.close()
|
|
|
if product:
|
|
|
@@ -544,7 +560,7 @@ class ProductDataService(BaseDataService):
|
|
|
"""Get products by type"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT * FROM products WHERE type = ?", (product_type,))
|
|
|
+ cursor.execute("SELECT * FROM products WHERE type = %s", (product_type,))
|
|
|
products = cursor.fetchall()
|
|
|
conn.close()
|
|
|
return [
|
|
|
@@ -563,7 +579,7 @@ class ProductDataService(BaseDataService):
|
|
|
"""Search products by name"""
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
- cursor.execute("SELECT * FROM products WHERE name LIKE ?", (f"%{name}%",))
|
|
|
+ cursor.execute("SELECT * FROM products WHERE name LIKE %s", (f"%{name}%",))
|
|
|
products = cursor.fetchall()
|
|
|
conn.close()
|
|
|
return [
|
|
|
@@ -582,7 +598,7 @@ class ProductDataService(BaseDataService):
|
|
|
"""Get multiple products by their IDs"""
|
|
|
if not product_ids:
|
|
|
return []
|
|
|
- placeholders = ', '.join('?' for _ in product_ids)
|
|
|
+ placeholders = ', '.join('%s' for _ in product_ids)
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute(f"SELECT * FROM products WHERE id IN ({placeholders})", product_ids)
|
|
|
@@ -623,23 +639,23 @@ class ProductDataService(BaseDataService):
|
|
|
updates = []
|
|
|
params = []
|
|
|
if name is not None:
|
|
|
- updates.append("name = ?")
|
|
|
+ updates.append("name = %s")
|
|
|
params.append(name)
|
|
|
if type is not None:
|
|
|
- updates.append("type = ?")
|
|
|
+ updates.append("type = %s")
|
|
|
params.append(type)
|
|
|
if description is not None:
|
|
|
- updates.append("description = ?")
|
|
|
+ updates.append("description = %s")
|
|
|
params.append(description)
|
|
|
if price is not None:
|
|
|
- updates.append("price = ?")
|
|
|
+ updates.append("price = %s")
|
|
|
params.append(price)
|
|
|
if image is not None:
|
|
|
if product.image and product.image != image:
|
|
|
if os.path.exists(os.path.join(IMAGE_PATH, product.image)):
|
|
|
os.remove(os.path.join(IMAGE_PATH, product.image))
|
|
|
try:
|
|
|
- extension = re.search(r'data:image/(.*?);base64,', image)
|
|
|
+ extension = re.search(r'data:image/(.*%s);base64,', image)
|
|
|
if not extension:
|
|
|
raise ValueError("Invalid image format")
|
|
|
extension = extension.group(1)
|
|
|
@@ -647,22 +663,22 @@ class ProductDataService(BaseDataService):
|
|
|
except ValueError as e:
|
|
|
logger.error(f"Failed to process image: {e}")
|
|
|
return False
|
|
|
- updates.append("image = ?")
|
|
|
+ updates.append("image = %s")
|
|
|
params.append(image)
|
|
|
if status is not None:
|
|
|
- updates.append("status = ?")
|
|
|
+ updates.append("status = %s")
|
|
|
params.append(status)
|
|
|
if not updates:
|
|
|
conn.close()
|
|
|
return False
|
|
|
try:
|
|
|
- cursor.execute(f"UPDATE products SET {', '.join(updates)} WHERE id = ?", (*params, product_id))
|
|
|
+ cursor.execute(f"UPDATE products SET {', '.join(updates)} WHERE id = %s", (*params, product_id))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
if success:
|
|
|
logger.info(f"Product with ID {product_id} updated.")
|
|
|
return success
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to update product: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -729,7 +745,7 @@ class ProductDataService(BaseDataService):
|
|
|
product = self.get_by_id(product_id)
|
|
|
if product and product.image:
|
|
|
os.remove(os.path.join(IMAGE_PATH, product.image.removeprefix(CURRENT_URL + "/images/")))
|
|
|
- cursor.execute("DELETE FROM products WHERE id = ?", (product_id,))
|
|
|
+ cursor.execute("DELETE FROM products WHERE id = %s", (product_id,))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
conn.close()
|
|
|
@@ -753,10 +769,11 @@ class SalesDataService(BaseDataService):
|
|
|
|
|
|
# Insert sale
|
|
|
cursor.execute(
|
|
|
- "INSERT INTO sales (user_id, total, fudo_id, date, 'table') VALUES (?, ?, ?, ?, ?)",
|
|
|
+ "INSERT INTO sales (user_id, total, fudo_id, date, table_number) VALUES (%s, %s, %s, %s, %s) RETURNING id",
|
|
|
(user_id, total, fudo_id, fecha, table)
|
|
|
)
|
|
|
- sale_id = cursor.lastrowid
|
|
|
+ last_sale = cursor.fetchone()
|
|
|
+ sale_id = last_sale[0] if last_sale else None
|
|
|
|
|
|
if sale_id and product_ids:
|
|
|
# Insert sale-product relationships with quantities
|
|
|
@@ -766,7 +783,7 @@ class SalesDataService(BaseDataService):
|
|
|
for i, product_id in enumerate(product_ids):
|
|
|
quantity = quantities[i] if i < len(quantities) else 1
|
|
|
cursor.execute(
|
|
|
- "INSERT INTO sale_products (sale_id, product_id, quantity) VALUES (?, ?, ?)",
|
|
|
+ "INSERT INTO sale_products (sale_id, product_id, quantity) VALUES (%s, %s, %s)",
|
|
|
(sale_id, product_id, quantity)
|
|
|
)
|
|
|
|
|
|
@@ -777,7 +794,7 @@ class SalesDataService(BaseDataService):
|
|
|
else:
|
|
|
logger.error("Failed to create sale.")
|
|
|
return -1
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to create sale: {e}")
|
|
|
conn.rollback()
|
|
|
return -1
|
|
|
@@ -791,7 +808,7 @@ class SalesDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
try:
|
|
|
cursor.execute(
|
|
|
- "INSERT INTO sale_products (sale_id, product_id, quantity) VALUES (?, ?, ?)",
|
|
|
+ "INSERT INTO sale_products (sale_id, product_id, quantity) VALUES (%s, %s, %s)",
|
|
|
(sale_id, product_id, quantity)
|
|
|
)
|
|
|
conn.commit()
|
|
|
@@ -799,7 +816,7 @@ class SalesDataService(BaseDataService):
|
|
|
if success:
|
|
|
logger.info(f"Product {product_id} (qty: {quantity}) added to sale {sale_id}.")
|
|
|
return success
|
|
|
- except sqlite3.IntegrityError as e:
|
|
|
+ except psycopg2.IntegrityError as e:
|
|
|
logger.error(f"Failed to add product to sale: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -816,7 +833,7 @@ class SalesDataService(BaseDataService):
|
|
|
for i, product_id in enumerate(product_ids):
|
|
|
quantity = quantities[i] if i < len(quantities) else 1
|
|
|
cursor.execute(
|
|
|
- "INSERT INTO sale_products (sale_id, product_id, quantity) VALUES (?, ?, ?)",
|
|
|
+ "INSERT INTO sale_products (sale_id, product_id, quantity) VALUES (%s, %s, %s)",
|
|
|
(sale_id, product_id, quantity)
|
|
|
)
|
|
|
|
|
|
@@ -825,7 +842,7 @@ class SalesDataService(BaseDataService):
|
|
|
if success:
|
|
|
logger.info(f"Products added to sale {sale_id}.")
|
|
|
return success
|
|
|
- except sqlite3.IntegrityError as e:
|
|
|
+ except psycopg2.IntegrityError as e:
|
|
|
logger.error(f"Failed to add products to sale: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -866,7 +883,7 @@ class SalesDataService(BaseDataService):
|
|
|
SELECT s.id, s.user_id, s.total, s.fudo_id, s.date, s.table, u.name, u.email
|
|
|
FROM sales s
|
|
|
LEFT JOIN users u ON s.user_id = u.id
|
|
|
- WHERE s.id = ?
|
|
|
+ WHERE s.id = %s
|
|
|
""", (sale_id,))
|
|
|
sale = cursor.fetchone()
|
|
|
conn.close()
|
|
|
@@ -891,7 +908,7 @@ class SalesDataService(BaseDataService):
|
|
|
SELECT s.id, s.user_id, s.total, s.fudo_id, s.date, s.table, u.name, u.email
|
|
|
FROM sales s
|
|
|
LEFT JOIN users u ON s.user_id = u.id
|
|
|
- WHERE s.fudo_id = ?
|
|
|
+ WHERE s.fudo_id = %s
|
|
|
""", (fudo_id,))
|
|
|
sale = cursor.fetchone()
|
|
|
conn.close()
|
|
|
@@ -914,10 +931,10 @@ class SalesDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute(
|
|
|
"""
|
|
|
- SELECT s.id, s.user_id, s.total, s.fudo_id, s.date, s."table", u.name, u.email
|
|
|
+ SELECT s.id, s.user_id, s.total, s.fudo_id, s.date, s.table_number, u.name, u.email
|
|
|
FROM sales s
|
|
|
LEFT JOIN users u ON s.user_id = u.id
|
|
|
- WHERE s.user_id = ?
|
|
|
+ WHERE s.user_id = %s
|
|
|
ORDER BY s.date DESC
|
|
|
""",
|
|
|
(user_id,)
|
|
|
@@ -945,7 +962,7 @@ class SalesDataService(BaseDataService):
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute("""
|
|
|
- SELECT product_id FROM sale_products WHERE sale_id = ?
|
|
|
+ SELECT product_id FROM sale_products WHERE sale_id = %s
|
|
|
""", (sale_id,))
|
|
|
products = cursor.fetchall()
|
|
|
conn.close()
|
|
|
@@ -959,7 +976,7 @@ class SalesDataService(BaseDataService):
|
|
|
SELECT p.id, p.name, p.type, p.description, p.price, p.image, p.status, sp.quantity
|
|
|
FROM sale_products sp
|
|
|
JOIN products p ON sp.product_id = p.id
|
|
|
- WHERE sp.sale_id = ?
|
|
|
+ WHERE sp.sale_id = %s
|
|
|
""", (sale_id,))
|
|
|
products = cursor.fetchall()
|
|
|
conn.close()
|
|
|
@@ -982,10 +999,10 @@ class SalesDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute(
|
|
|
"""
|
|
|
- SELECT s.id, s.user_id, s.total, s.fudo_id, s.date, s."table", u.name, u.email
|
|
|
+ SELECT s.id, s.user_id, s.total, s.fudo_id, s.date, s.table_number, u.name, u.email
|
|
|
FROM sales s
|
|
|
LEFT JOIN users u ON s.user_id = u.id
|
|
|
- WHERE s."table" = ?
|
|
|
+ WHERE s.table_number = %s
|
|
|
ORDER BY s.date DESC
|
|
|
""",
|
|
|
(table,)
|
|
|
@@ -1011,7 +1028,7 @@ class SalesDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
try:
|
|
|
cursor.execute(
|
|
|
- "UPDATE sale_products SET quantity = ? WHERE sale_id = ? AND product_id = ?",
|
|
|
+ "UPDATE sale_products SET quantity = %s WHERE sale_id = %s AND product_id = %s",
|
|
|
(new_quantity, sale_id, product_id)
|
|
|
)
|
|
|
conn.commit()
|
|
|
@@ -1019,7 +1036,7 @@ class SalesDataService(BaseDataService):
|
|
|
if success:
|
|
|
logger.info(f"Updated quantity to {new_quantity} for product {product_id} in sale {sale_id}.")
|
|
|
return success
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to update product quantity: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -1030,7 +1047,7 @@ class SalesDataService(BaseDataService):
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute(
|
|
|
- "SELECT quantity FROM sale_products WHERE sale_id = ? AND product_id = ?",
|
|
|
+ "SELECT quantity FROM sale_products WHERE sale_id = %s AND product_id = %s",
|
|
|
(sale_id, product_id)
|
|
|
)
|
|
|
result = cursor.fetchone()
|
|
|
@@ -1045,25 +1062,25 @@ class SalesDataService(BaseDataService):
|
|
|
updates = []
|
|
|
params = []
|
|
|
if user_id is not None:
|
|
|
- updates.append("user_id = ?")
|
|
|
+ updates.append("user_id = %s")
|
|
|
params.append(user_id)
|
|
|
if total is not None:
|
|
|
- updates.append("total = ?")
|
|
|
+ updates.append("total = %s")
|
|
|
params.append(total)
|
|
|
if table is not None:
|
|
|
- updates.append("table = ?")
|
|
|
+ updates.append("table = %s")
|
|
|
params.append(table)
|
|
|
if not updates:
|
|
|
conn.close()
|
|
|
return False
|
|
|
try:
|
|
|
- cursor.execute(f"UPDATE sales SET {', '.join(updates)} WHERE id = ?", (*params, sale_id))
|
|
|
+ cursor.execute(f"UPDATE sales SET {', '.join(updates)} WHERE id = %s", (*params, sale_id))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
if success:
|
|
|
logger.info(f"Sale with ID {sale_id} updated.")
|
|
|
return success
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to update sale: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -1076,9 +1093,9 @@ class SalesDataService(BaseDataService):
|
|
|
cursor = conn.cursor()
|
|
|
try:
|
|
|
# Delete sale-product relationships first
|
|
|
- cursor.execute("DELETE FROM sale_products WHERE sale_id = ?", (sale_id,))
|
|
|
+ cursor.execute("DELETE FROM sale_products WHERE sale_id = %s", (sale_id,))
|
|
|
# Delete the sale
|
|
|
- cursor.execute("DELETE FROM sales WHERE id = ?", (sale_id,))
|
|
|
+ cursor.execute("DELETE FROM sales WHERE id = %s", (sale_id,))
|
|
|
conn.commit()
|
|
|
success = cursor.rowcount > 0
|
|
|
if success:
|
|
|
@@ -1086,7 +1103,7 @@ class SalesDataService(BaseDataService):
|
|
|
else:
|
|
|
logger.error(f"Failed to delete sale with ID {sale_id}.")
|
|
|
return success
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to delete sale: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -1097,7 +1114,7 @@ class SalesDataService(BaseDataService):
|
|
|
conn = self._get_connection()
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute(
|
|
|
- "DELETE FROM sale_products WHERE sale_id = ? AND product_id = ?",
|
|
|
+ "DELETE FROM sale_products WHERE sale_id = %s AND product_id = %s",
|
|
|
(sale_id, product_id)
|
|
|
)
|
|
|
conn.commit()
|
|
|
@@ -1116,7 +1133,7 @@ class SalesDataService(BaseDataService):
|
|
|
try:
|
|
|
# Get current quantity
|
|
|
cursor.execute(
|
|
|
- "SELECT quantity FROM sale_products WHERE sale_id = ? AND product_id = ?",
|
|
|
+ "SELECT quantity FROM sale_products WHERE sale_id = %s AND product_id = %s",
|
|
|
(sale_id, product_id)
|
|
|
)
|
|
|
result = cursor.fetchone()
|
|
|
@@ -1129,21 +1146,21 @@ class SalesDataService(BaseDataService):
|
|
|
if new_quantity <= 0:
|
|
|
# Remove the product completely
|
|
|
cursor.execute(
|
|
|
- "DELETE FROM sale_products WHERE sale_id = ? AND product_id = ?",
|
|
|
+ "DELETE FROM sale_products WHERE sale_id = %s AND product_id = %s",
|
|
|
(sale_id, product_id)
|
|
|
)
|
|
|
logger.info(f"Product {product_id} removed from sale {sale_id} (quantity reached 0).")
|
|
|
else:
|
|
|
# Update with new quantity
|
|
|
cursor.execute(
|
|
|
- "UPDATE sale_products SET quantity = ? WHERE sale_id = ? AND product_id = ?",
|
|
|
+ "UPDATE sale_products SET quantity = %s WHERE sale_id = %s AND product_id = %s",
|
|
|
(new_quantity, sale_id, product_id)
|
|
|
)
|
|
|
logger.info(f"Product {product_id} quantity decreased to {new_quantity} in sale {sale_id}.")
|
|
|
|
|
|
conn.commit()
|
|
|
return True
|
|
|
- except sqlite3.Error as e:
|
|
|
+ except psycopg2.Error as e:
|
|
|
logger.error(f"Failed to decrease product quantity: {e}")
|
|
|
return False
|
|
|
finally:
|
|
|
@@ -1188,28 +1205,57 @@ def load_bg_data() -> List[Dict[str, str]]:
|
|
|
except json.JSONDecodeError:
|
|
|
logger.error(f"Could not decode JSON from {BG_DATA_PATH}. Serving with empty data.")
|
|
|
return []
|
|
|
-
|
|
|
+
|
|
|
def initialize_db():
|
|
|
|
|
|
- if os.path.exists(DB_PATH):
|
|
|
- logger.info("Base de datos ya existe, no se necesita inicializar.")
|
|
|
- return
|
|
|
+ # En PostgreSQL, no se crea el archivo de base de datos, así que verificamos si las tablas existen.
|
|
|
+ try:
|
|
|
+ conn = psycopg2.connect(
|
|
|
+ dbname=POSTGRESQL_DB_CONFIG['dbname'],
|
|
|
+ user=POSTGRESQL_DB_CONFIG['user'],
|
|
|
+ password=POSTGRESQL_DB_CONFIG['password'],
|
|
|
+ host=POSTGRESQL_DB_CONFIG['host'],
|
|
|
+ port=POSTGRESQL_DB_CONFIG['port']
|
|
|
+ )
|
|
|
+ cursor = conn.cursor()
|
|
|
+ # Verificar si la tabla 'users' ya existe
|
|
|
+ cursor.execute("""
|
|
|
+ SELECT EXISTS (
|
|
|
+ SELECT FROM information_schema.tables
|
|
|
+ WHERE table_name = 'users'
|
|
|
+ );
|
|
|
+ """)
|
|
|
+ exists = cursor.fetchone()
|
|
|
+ if exists:
|
|
|
+ logger.info("La base de datos ya está inicializada, no se necesita inicializar.")
|
|
|
+ conn.close()
|
|
|
+ return
|
|
|
+ conn.close()
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Error comprobando la existencia de tablas: {e}")
|
|
|
+ # Si hay error, continuamos con la inicialización
|
|
|
|
|
|
- conn = sqlite3.connect(DB_PATH)
|
|
|
+ conn = psycopg2.connect(
|
|
|
+ dbname=POSTGRESQL_DB_CONFIG['dbname'],
|
|
|
+ user=POSTGRESQL_DB_CONFIG['user'],
|
|
|
+ password=POSTGRESQL_DB_CONFIG['password'],
|
|
|
+ host=POSTGRESQL_DB_CONFIG['host'],
|
|
|
+ port=POSTGRESQL_DB_CONFIG['port']
|
|
|
+ )
|
|
|
cursor = conn.cursor()
|
|
|
# Crear tabla de usuarios
|
|
|
logger.info("Inicializando base de datos...")
|
|
|
logger.info("Creando tabla de usuarios...")
|
|
|
cursor.execute("""
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
|
- id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
- email TEXT UNIQUE NOT NULL,
|
|
|
- name TEXT NOT NULL,
|
|
|
- rut TEXT UNIQUE NOT NULL,
|
|
|
+ id SERIAL PRIMARY KEY,
|
|
|
+ email VARCHAR(255) UNIQUE NOT NULL,
|
|
|
+ name VARCHAR(255) NOT NULL,
|
|
|
+ rut VARCHAR(20) UNIQUE NOT NULL,
|
|
|
pin_hash TEXT NOT NULL,
|
|
|
kleincoins TEXT NOT NULL,
|
|
|
created_at TEXT NOT NULL,
|
|
|
- permissions INTEGER DEFAULT 0 NOT NULL CHECK (permissions IN (0, 1, 2)), -- 0: Usuario normal, 1: Administrador, 2: Superusuario
|
|
|
+ permissions INTEGER DEFAULT 0 NOT NULL CHECK (permissions IN (0, 1, 2)) -- 0: Usuario normal, 1: Administrador, 2: Superusuario
|
|
|
);
|
|
|
""")
|
|
|
|
|
|
@@ -1218,10 +1264,10 @@ def initialize_db():
|
|
|
cursor.execute("""
|
|
|
CREATE TABLE IF NOT EXISTS products (
|
|
|
id INTEGER PRIMARY KEY,
|
|
|
- name TEXT NOT NULL,
|
|
|
- type TEXT,
|
|
|
- description TEXT,
|
|
|
- price REAL NOT NULL,
|
|
|
+ name VARCHAR(255) NOT NULL,
|
|
|
+ type VARCHAR(100) NOT NULL,
|
|
|
+ description TEXT NOT NULL,
|
|
|
+ price INTEGER NOT NULL,
|
|
|
image TEXT,
|
|
|
status INTEGER DEFAULT 1 NOT NULL CHECK (status IN (0, 1)) -- 0: Inactivo, 1: Activo
|
|
|
);
|
|
|
@@ -1231,12 +1277,12 @@ def initialize_db():
|
|
|
logger.info("Creando tabla de sales...")
|
|
|
cursor.execute("""
|
|
|
CREATE TABLE IF NOT EXISTS sales (
|
|
|
- id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
+ id SERIAL PRIMARY KEY,
|
|
|
user_id INTEGER NOT NULL,
|
|
|
- total REAL NOT NULL,
|
|
|
- fudo_id TEXT NOT NULL,
|
|
|
+ total INTEGER NOT NULL,
|
|
|
+ fudo_id TEXT UNIQUE NOT NULL,
|
|
|
date TEXT NOT NULL,
|
|
|
- "table" INTEGER NOT NULL,
|
|
|
+ table_number INTEGER NOT NULL,
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
|
);
|
|
|
""")
|
|
|
@@ -1257,7 +1303,7 @@ def initialize_db():
|
|
|
logger.info("Creando tabla de blacklist...")
|
|
|
cursor.execute("""
|
|
|
CREATE TABLE IF NOT EXISTS blacklist (
|
|
|
- id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
+ id SERIAL PRIMARY KEY,
|
|
|
user_id INTEGER NOT NULL,
|
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
|
);
|