| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815 |
- import json
- import sqlite3
- from typing import List, Dict, Optional
- from abc import ABC, abstractmethod
- from config.settings import BG_DATA_PATH, DB_PATH
- from logging import getLogger
- from datetime import datetime
- import uuid
- logger = getLogger(__name__)
- """
- ESQUEMA DE BASE DE DATOS SQLITE (data.db)
- 1. Tabla: users
- -----------------------------------
- - id INTEGER PRIMARY KEY AUTOINCREMENT
- - correo TEXT UNIQUE NOT NULL
- - nombre TEXT NOT NULL
- - rut TEXT UNIQUE NOT NULL
- - pin_hash TEXT NOT NULL
- (Guarda la información del usuario con su pin hasheado)
- 2. Tabla: productos
- -----------------------------------
- - id INTEGER PRIMARY KEY AUTOINCREMENT
- - name TEXT NOT NULL
- - type TEXT
- - description TEXT
- - price REAL NOT NULL
- - image TEXT (URL de la imagen)
- (Guarda los productos disponibles para venta)
- 3. Tabla: ventas
- -----------------------------------
- - id INTEGER PRIMARY KEY AUTOINCREMENT
- - user_id INTEGER NOT NULL (relación a users.id)
- - total REAL NOT NULL (precio total de la venta)
- - venta_uuid TEXT UNIQUE NOT NULL (ID string único por venta)
- - fecha TEXT NOT NULL (fecha y hora en formato ISO 8601)
- (Guarda cada venta, asociada a un usuario)
- 4. Tabla: venta_productos
- -----------------------------------
- - venta_id INTEGER NOT NULL (relación a ventas.id)
- - producto_id INTEGER NOT NULL (relación a productos.id)
- (Relación muchos a muchos entre ventas y productos)
- 5. Tabla: blacklist
- -----------------------------------
- - id INTEGER PRIMARY KEY AUTOINCREMENT
- - user_id INTEGER NOT NULL (relación a users.id)
- (Usuarios bloqueados o no autorizados para ciertas acciones)
- RELACIONES:
- -----------------------------------
- - users puede tener muchas ventas
- - ventas puede tener muchos productos (y viceversa), por eso se usa una tabla intermedia (venta_productos)
- - productos pueden repetirse en múltiples ventas
- """
- # 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:
- """Get database connection"""
- return sqlite3.connect(self.db_path)
-
- @abstractmethod
- def get_all(self) -> List[Dict]:
- """Get all records"""
- pass
-
- @abstractmethod
- def get_by_id(self, id: int) -> Optional[Dict]:
- """Get record by ID"""
- pass
-
- @abstractmethod
- def create(self, **kwargs) -> int:
- """Create new record"""
- pass
-
- @abstractmethod
- def update(self, id: int, **kwargs) -> bool:
- """Update record"""
- pass
-
- @abstractmethod
- def delete(self, id: int) -> bool:
- """Delete record"""
- pass
- # User Data Service
- class UserDataService(BaseDataService):
- """Service for managing user data"""
- #region Create
- def create(self, correo: str, nombre: str, rut: str, pin_hash: str) -> int:
- """Add a new user to the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- try:
- cursor.execute(
- "INSERT INTO users (correo, nombre, rut, pin_hash) VALUES (?, ?, ?, ?)",
- (correo, nombre, rut, pin_hash)
- )
- conn.commit()
- user_id = cursor.lastrowid
- if user_id:
- logger.info(f"User added with ID: {user_id}")
- return user_id
- else:
- logger.error("Failed to add user.")
- return -1
- except sqlite3.IntegrityError as e:
- logger.error(f"Failed to add user: {e}")
- return -1
- finally:
- conn.close()
- #endregion
- #region Read
- def get_all(self) -> List[Dict[str, str]]:
- """Get all users from the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users")
- users = cursor.fetchall()
- conn.close()
- return [
- {
- "id": user[0],
- "correo": user[1],
- "nombre": user[2],
- "rut": user[3],
- "pin_hash": user[4]
- } for user in users
- ]
-
- def get_by_id(self, user_id: int) -> Optional[Dict[str, str]]:
- """Get user data from the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
- user = cursor.fetchone()
- conn.close()
- if user:
- return {
- "id": user[0],
- "correo": user[1],
- "nombre": user[2],
- "rut": user[3],
- "pin_hash": user[4]
- }
- return None
-
- def get_by_email(self, correo: str) -> Optional[Dict[str, str]]:
- """Get user by email"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE correo = ?", (correo,))
- user = cursor.fetchone()
- conn.close()
- if user:
- return {
- "id": user[0],
- "correo": user[1],
- "nombre": user[2],
- "rut": user[3],
- "pin_hash": user[4]
- }
- return None
-
- def get_by_rut(self, rut: str) -> Optional[Dict[str, str]]:
- """Get user by RUT"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE rut = ?", (rut,))
- user = cursor.fetchone()
- conn.close()
- if user:
- return {
- "id": user[0],
- "correo": user[1],
- "nombre": user[2],
- "rut": user[3],
- "pin_hash": user[4]
- }
- return None
- #endregion
- #region Update
- def update(self, user_id: int, correo=None, nombre=None, rut=None, pin_hash=None) -> bool:
- """Update user information in the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- updates = []
- params = []
- if correo:
- updates.append("correo = ?")
- params.append(correo)
- if nombre:
- updates.append("nombre = ?")
- params.append(nombre)
- if rut:
- updates.append("rut = ?")
- params.append(rut)
- if pin_hash:
- updates.append("pin_hash = ?")
- params.append(pin_hash)
- if not updates:
- conn.close()
- return False
- try:
- cursor.execute(f"UPDATE users SET {', '.join(updates)} WHERE id = ?", (*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:
- logger.error(f"Failed to update user: {e}")
- return False
- finally:
- conn.close()
- #endregion
- #region Delete
- def delete(self, user_id: int) -> bool:
- """Delete a user from the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
- conn.commit()
- conn.close()
- if cursor.rowcount > 0:
- logger.info(f"User with ID {user_id} deleted.")
- return True
- else:
- logger.error(f"Failed to delete user with ID {user_id}.")
- return False
- #endregion
- # Blacklist Data Service
- class BlacklistDataService(BaseDataService):
- """Service for managing blacklisted users"""
- #region Create
- def create(self, user_id: int) -> int:
- """Add a user to the blacklist"""
- conn = self._get_connection()
- cursor = conn.cursor()
- try:
- cursor.execute("INSERT INTO blacklist (user_id) VALUES (?)", (user_id,))
- conn.commit()
- blacklist_id = cursor.lastrowid
- if blacklist_id:
- logger.info(f"User with ID {user_id} added to blacklist.")
- return blacklist_id
- else:
- logger.error(f"Failed to add user with ID {user_id} to blacklist.")
- return -1
- except sqlite3.IntegrityError as e:
- logger.error(f"Failed to add user to blacklist: {e}")
- return -1
- finally:
- conn.close()
- #endregion
- #region Read
- def get_all(self) -> List[Dict]:
- """Get all blacklisted users"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT b.id, b.user_id, u.correo, u.nombre, u.rut
- FROM blacklist b
- LEFT JOIN users u ON b.user_id = u.id
- """)
- blacklisted = cursor.fetchall()
- conn.close()
- return [
- {
- "id": row[0],
- "user_id": row[1],
- "correo": row[2],
- "nombre": row[3],
- "rut": row[4]
- } for row in blacklisted
- ]
-
- def get_by_id(self, id: int) -> Optional[Dict]:
- """Get blacklist entry by ID"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT b.id, b.user_id, u.correo, u.nombre, u.rut
- FROM blacklist b
- LEFT JOIN users u ON b.user_id = u.id
- WHERE b.id = ?
- """, (id,))
- row = cursor.fetchone()
- conn.close()
- if row:
- return {
- "id": row[0],
- "user_id": row[1],
- "correo": row[2],
- "nombre": row[3],
- "rut": row[4]
- }
- return None
-
- def get_blacklisted_user_ids(self) -> List[int]:
- """Get a list of blacklisted user IDs"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT user_id FROM blacklist")
- blacklisted_users = [row[0] for row in cursor.fetchall()]
- conn.close()
- return blacklisted_users
-
- def is_user_blacklisted(self, user_id: int) -> bool:
- """Check if a user is blacklisted"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM blacklist WHERE user_id = ?", (user_id,))
- blacklisted = cursor.fetchone() is not None
- conn.close()
- return blacklisted
- #endregion
- #region Update
- def update(self, id: int, **kwargs) -> bool:
- """Update blacklist entry (not commonly used)"""
- # Blacklist entries typically don't need updates
- return False
- #endregion
- #region Delete
- def delete(self, id: int) -> bool:
- """Remove a blacklist entry by ID"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM blacklist WHERE id = ?", (id,))
- conn.commit()
- success = cursor.rowcount > 0
- conn.close()
- if success:
- logger.info(f"Blacklist entry with ID {id} removed.")
- else:
- logger.error(f"Failed to remove blacklist entry with ID {id}.")
- return success
-
- def remove_user_from_blacklist(self, user_id: int) -> bool:
- """Remove a user from the blacklist"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM blacklist WHERE user_id = ?", (user_id,))
- conn.commit()
- success = cursor.rowcount > 0
- conn.close()
- if success:
- logger.info(f"User with ID {user_id} removed from blacklist.")
- else:
- logger.error(f"Failed to remove user with ID {user_id} from blacklist.")
- return success
- #endregion
- # Product Data Service
- class ProductDataService(BaseDataService):
- """Service for managing products"""
- #region Create
- def create(self, name: str, price: float, type: Optional[str] = None, description: Optional[str] = None, image: Optional[str] = None) -> int:
- """Add a new product to the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- try:
- cursor.execute(
- "INSERT INTO productos (name, type, description, price, image) VALUES (?, ?, ?, ?, ?)",
- (name, type, description, price, image)
- )
- conn.commit()
- product_id = cursor.lastrowid
- if product_id:
- logger.info(f"Product added with ID: {product_id}")
- return product_id
- else:
- logger.error("Failed to add product.")
- return -1
- except sqlite3.Error as e:
- logger.error(f"Failed to add product: {e}")
- return -1
- finally:
- conn.close()
- #endregion
- #region Read
- def get_all(self) -> List[Dict[str, str]]:
- """Get all products from the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM productos")
- products = cursor.fetchall()
- conn.close()
- return [
- {
- "id": product[0],
- "name": product[1],
- "type": product[2],
- "description": product[3],
- "price": product[4],
- "image": product[5]
- } for product in products
- ]
-
- def get_by_id(self, product_id: int) -> Optional[Dict]:
- """Get product by ID"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM productos WHERE id = ?", (product_id,))
- product = cursor.fetchone()
- conn.close()
- if product:
- return {
- "id": product[0],
- "name": product[1],
- "type": product[2],
- "description": product[3],
- "price": product[4],
- "image": product[5]
- }
- return None
-
- def get_by_type(self, product_type: str) -> List[Dict]:
- """Get products by type"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM productos WHERE type = ?", (product_type,))
- products = cursor.fetchall()
- conn.close()
- return [
- {
- "id": product[0],
- "name": product[1],
- "type": product[2],
- "description": product[3],
- "price": product[4],
- "image": product[5]
- } for product in products
- ]
-
- def search_by_name(self, name: str) -> List[Dict]:
- """Search products by name"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM productos WHERE name LIKE ?", (f"%{name}%",))
- products = cursor.fetchall()
- conn.close()
- return [
- {
- "id": product[0],
- "name": product[1],
- "type": product[2],
- "description": product[3],
- "price": product[4],
- "image": product[5]
- } for product in products
- ]
- #endregion
- #region Update
- def update(self, product_id: int, name=None, type=None, description=None, price=None, image=None) -> bool:
- """Update product information"""
- conn = self._get_connection()
- cursor = conn.cursor()
- updates = []
- params = []
- if name is not None:
- updates.append("name = ?")
- params.append(name)
- if type is not None:
- updates.append("type = ?")
- params.append(type)
- if description is not None:
- updates.append("description = ?")
- params.append(description)
- if price is not None:
- updates.append("price = ?")
- params.append(price)
- if image is not None:
- updates.append("image = ?")
- params.append(image)
- if not updates:
- conn.close()
- return False
- try:
- cursor.execute(f"UPDATE productos SET {', '.join(updates)} WHERE id = ?", (*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:
- logger.error(f"Failed to update product: {e}")
- return False
- finally:
- conn.close()
- #endregion
- #region Delete
- def delete(self, product_id: int) -> bool:
- """Delete a product from the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM productos WHERE id = ?", (product_id,))
- conn.commit()
- success = cursor.rowcount > 0
- conn.close()
- if success:
- logger.info(f"Product with ID {product_id} deleted.")
- else:
- logger.error(f"Failed to delete product with ID {product_id}.")
- return success
- #endregion
- # Sales Data Service
- class SalesDataService(BaseDataService):
- """Service for managing sales"""
- #region C
- def create(self, user_id: int, total: float, product_ids: List[int]) -> int:
- """Create a new sale with products"""
- conn = self._get_connection()
- cursor = conn.cursor()
- try:
- # Generate unique UUID for the sale
- venta_uuid = str(uuid.uuid4())
- fecha = datetime.now().isoformat()
-
- # Insert sale
- cursor.execute(
- "INSERT INTO ventas (user_id, total, venta_uuid, fecha) VALUES (?, ?, ?, ?)",
- (user_id, total, venta_uuid, fecha)
- )
- sale_id = cursor.lastrowid
-
- if sale_id and product_ids:
- # Insert sale-product relationships
- for product_id in product_ids:
- cursor.execute(
- "INSERT INTO venta_productos (venta_id, producto_id) VALUES (?, ?)",
- (sale_id, product_id)
- )
-
- conn.commit()
- if sale_id:
- logger.info(f"Sale created with ID: {sale_id}, UUID: {venta_uuid}")
- return sale_id
- else:
- logger.error("Failed to create sale.")
- return -1
- except sqlite3.Error as e:
- logger.error(f"Failed to create sale: {e}")
- conn.rollback()
- return -1
- finally:
- conn.close()
-
- def add_product_to_sale(self, sale_id: int, product_id: int) -> bool:
- """Add a product to an existing sale"""
- conn = self._get_connection()
- cursor = conn.cursor()
- try:
- cursor.execute(
- "INSERT INTO venta_productos (venta_id, producto_id) VALUES (?, ?)",
- (sale_id, product_id)
- )
- conn.commit()
- success = cursor.rowcount > 0
- if success:
- logger.info(f"Product {product_id} added to sale {sale_id}.")
- return success
- except sqlite3.IntegrityError as e:
- logger.error(f"Failed to add product to sale: {e}")
- return False
- finally:
- conn.close()
-
- #endregion
- #region R
- def get_all(self) -> List[Dict]:
- """Get all sales from the database"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT v.id, v.user_id, v.total, v.venta_uuid, v.fecha, u.nombre, u.correo
- FROM ventas v
- LEFT JOIN users u ON v.user_id = u.id
- ORDER BY v.fecha DESC
- """)
- sales = cursor.fetchall()
- conn.close()
- return [
- {
- "id": sale[0],
- "user_id": sale[1],
- "total": sale[2],
- "venta_uuid": sale[3],
- "fecha": sale[4],
- "user_name": sale[5],
- "user_email": sale[6]
- } for sale in sales
- ]
-
- def get_by_id(self, sale_id: int) -> Optional[Dict]:
- """Get sale by ID"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT v.id, v.user_id, v.total, v.venta_uuid, v.fecha, u.nombre, u.correo
- FROM ventas v
- LEFT JOIN users u ON v.user_id = u.id
- WHERE v.id = ?
- """, (sale_id,))
- sale = cursor.fetchone()
- conn.close()
- if sale:
- return {
- "id": sale[0],
- "user_id": sale[1],
- "total": sale[2],
- "venta_uuid": sale[3],
- "fecha": sale[4],
- "user_name": sale[5],
- "user_email": sale[6]
- }
- return None
-
- def get_by_uuid(self, venta_uuid: str) -> Optional[Dict]:
- """Get sale by UUID"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT v.id, v.user_id, v.total, v.venta_uuid, v.fecha, u.nombre, u.correo
- FROM ventas v
- LEFT JOIN users u ON v.user_id = u.id
- WHERE v.venta_uuid = ?
- """, (venta_uuid,))
- sale = cursor.fetchone()
- conn.close()
- if sale:
- return {
- "id": sale[0],
- "user_id": sale[1],
- "total": sale[2],
- "venta_uuid": sale[3],
- "fecha": sale[4],
- "user_name": sale[5],
- "user_email": sale[6]
- }
- return None
-
- def get_by_user(self, user_id: int) -> List[Dict]:
- """Get sales by user ID"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT v.id, v.user_id, v.total, v.venta_uuid, v.fecha, u.nombre, u.correo
- FROM ventas v
- LEFT JOIN users u ON v.user_id = u.id
- WHERE v.user_id = ?
- ORDER BY v.fecha DESC
- """, (user_id,))
- sales = cursor.fetchall()
- conn.close()
- return [
- {
- "id": sale[0],
- "user_id": sale[1],
- "total": sale[2],
- "venta_uuid": sale[3],
- "fecha": sale[4],
- "user_name": sale[5],
- "user_email": sale[6]
- } for sale in sales
- ]
-
- def get_sale_products(self, sale_id: int) -> List[Dict]:
- """Get products for a specific sale"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- SELECT p.id, p.name, p.type, p.description, p.price, p.image
- FROM venta_productos vp
- JOIN productos p ON vp.producto_id = p.id
- WHERE vp.venta_id = ?
- """, (sale_id,))
- products = cursor.fetchall()
- conn.close()
- return [
- {
- "id": product[0],
- "name": product[1],
- "type": product[2],
- "description": product[3],
- "price": product[4],
- "image": product[5]
- } for product in products
- ]
- #endregion
- #region U
- def update(self, sale_id: int, user_id=None, total=None) -> bool:
- """Update sale information (products cannot be updated directly)"""
- conn = self._get_connection()
- cursor = conn.cursor()
- updates = []
- params = []
- if user_id is not None:
- updates.append("user_id = ?")
- params.append(user_id)
- if total is not None:
- updates.append("total = ?")
- params.append(total)
- if not updates:
- conn.close()
- return False
- try:
- cursor.execute(f"UPDATE ventas SET {', '.join(updates)} WHERE id = ?", (*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:
- logger.error(f"Failed to update sale: {e}")
- return False
- finally:
- conn.close()
- #endregion
- #region D
- def delete(self, sale_id: int) -> bool:
- """Delete a sale and its product relationships"""
- conn = self._get_connection()
- cursor = conn.cursor()
- try:
- # Delete sale-product relationships first
- cursor.execute("DELETE FROM venta_productos WHERE venta_id = ?", (sale_id,))
- # Delete the sale
- cursor.execute("DELETE FROM ventas WHERE id = ?", (sale_id,))
- conn.commit()
- success = cursor.rowcount > 0
- if success:
- logger.info(f"Sale with ID {sale_id} deleted.")
- else:
- logger.error(f"Failed to delete sale with ID {sale_id}.")
- return success
- except sqlite3.Error as e:
- logger.error(f"Failed to delete sale: {e}")
- return False
- finally:
- conn.close()
-
- def remove_product_from_sale(self, sale_id: int, product_id: int) -> bool:
- """Remove a product from a sale"""
- conn = self._get_connection()
- cursor = conn.cursor()
- cursor.execute(
- "DELETE FROM venta_productos WHERE venta_id = ? AND producto_id = ?",
- (sale_id, product_id)
- )
- conn.commit()
- success = cursor.rowcount > 0
- conn.close()
- if success:
- logger.info(f"Product {product_id} removed from sale {sale_id}.")
- else:
- logger.error(f"Failed to remove product {product_id} from sale {sale_id}.")
- return success
- #endregion
- # Factory class to get service instances
- class DataServiceFactory:
- """Factory class to create data service instances"""
-
- @staticmethod
- def get_user_service() -> UserDataService:
- """Get user data service instance"""
- return UserDataService()
-
- @staticmethod
- def get_blacklist_service() -> BlacklistDataService:
- """Get blacklist data service instance"""
- return BlacklistDataService()
-
- @staticmethod
- def get_product_service() -> ProductDataService:
- """Get product data service instance"""
- return ProductDataService()
-
- @staticmethod
- def get_sales_service() -> SalesDataService:
- """Get sales data service instance"""
- return SalesDataService()
- # Helper functions for background data
- def load_bg_data() -> List[Dict[str, str]]:
- """Load background data for AI assistant"""
- try:
- with open(BG_DATA_PATH, 'r', encoding='utf-8') as f:
- return json.load(f)
- except FileNotFoundError:
- logger.error(f"Data file not found at {BG_DATA_PATH}. Serving with empty data.")
- return []
- except json.JSONDecodeError:
- logger.error(f"Could not decode JSON from {BG_DATA_PATH}. Serving with empty data.")
- return []
|