0632aa22e1
Co-authored-by: Copilot <copilot@github.com>
369 lines
11 KiB
Python
369 lines
11 KiB
Python
"""
|
|
SQLite Data Access Layer
|
|
Provides database operations using SQLAlchemy
|
|
"""
|
|
from models import db, User, Product, Location, ProductAttribute
|
|
from werkzeug.security import generate_password_hash
|
|
|
|
# ============================================================================
|
|
# USER OPERATIONS
|
|
# ============================================================================
|
|
|
|
def get_user_by_username(username):
|
|
"""Get a user by username"""
|
|
return User.query.filter_by(username=username).first()
|
|
|
|
def get_user_by_id(user_id):
|
|
"""Get a user by ID"""
|
|
return User.query.get(user_id)
|
|
|
|
def get_all_users():
|
|
"""Get all users"""
|
|
users = User.query.all()
|
|
return [user.to_dict() for user in users]
|
|
|
|
def create_user(user_data):
|
|
"""
|
|
Create a new user
|
|
|
|
Args:
|
|
user_data (dict): User data with keys: username, password, defaultLocation,
|
|
locationSettings, permissions, active
|
|
|
|
Returns:
|
|
dict: Created user as dictionary or None if username exists
|
|
"""
|
|
# Check if username already exists
|
|
if User.query.filter_by(username=user_data['username']).first():
|
|
return None
|
|
|
|
# Hash password if not already hashed
|
|
password = user_data['password']
|
|
if not password.startswith('pbkdf2:'):
|
|
password = generate_password_hash(password, method='pbkdf2:sha256')
|
|
|
|
# Get location settings
|
|
location_settings = user_data.get('locationSettings', {})
|
|
default_location = user_data['defaultLocation']
|
|
|
|
# Ensure default location is accessible
|
|
if default_location not in location_settings:
|
|
location_settings[default_location] = {}
|
|
location_settings[default_location]['accessible'] = True
|
|
|
|
# Create user
|
|
user = User(
|
|
username=user_data['username'],
|
|
password=password,
|
|
default_location=default_location,
|
|
active=user_data.get('active', True),
|
|
super_admin=user_data.get('superAdmin', False)
|
|
)
|
|
user.locationSettings = location_settings
|
|
user.permissions = user_data.get('permissions', {})
|
|
|
|
db.session.add(user)
|
|
db.session.commit()
|
|
|
|
return user.to_dict()
|
|
|
|
def update_user(user_id, user_data):
|
|
"""
|
|
Update an existing user
|
|
|
|
Args:
|
|
user_id (int): User ID
|
|
user_data (dict): Updated user data
|
|
|
|
Returns:
|
|
dict: Updated user as dictionary or None if not found
|
|
"""
|
|
user = User.query.get(user_id)
|
|
if not user:
|
|
return None
|
|
|
|
# Update fields
|
|
if 'defaultLocation' in user_data:
|
|
user.default_location = user_data['defaultLocation']
|
|
if 'active' in user_data:
|
|
user.active = user_data['active']
|
|
if 'superAdmin' in user_data:
|
|
user.super_admin = user_data['superAdmin']
|
|
if 'locationSettings' in user_data:
|
|
user.locationSettings = user_data['locationSettings']
|
|
if 'permissions' in user_data:
|
|
user.permissions = user_data['permissions']
|
|
if 'password' in user_data:
|
|
password = user_data['password']
|
|
if not password.startswith('pbkdf2:'):
|
|
password = generate_password_hash(password, method='pbkdf2:sha256')
|
|
user.password = password
|
|
|
|
db.session.commit()
|
|
return user.to_dict()
|
|
|
|
def delete_user(user_id):
|
|
"""
|
|
Delete a user
|
|
|
|
Args:
|
|
user_id (int): User ID
|
|
|
|
Returns:
|
|
bool: True if deleted, False if not found
|
|
"""
|
|
user = User.query.get(user_id)
|
|
if not user:
|
|
return False
|
|
|
|
db.session.delete(user)
|
|
db.session.commit()
|
|
return True
|
|
|
|
def toggle_user_active(user_id, active):
|
|
"""
|
|
Toggle user active status
|
|
|
|
Args:
|
|
user_id (int): User ID
|
|
active (bool): Active status
|
|
|
|
Returns:
|
|
dict: Updated user or None if not found
|
|
"""
|
|
user = User.query.get(user_id)
|
|
if not user:
|
|
return None
|
|
|
|
user.active = active
|
|
db.session.commit()
|
|
return user.to_dict()
|
|
|
|
def change_user_password(user_id, new_password):
|
|
"""
|
|
Change a user's password
|
|
|
|
Args:
|
|
user_id (int): User ID
|
|
new_password (str): New password (will be hashed)
|
|
|
|
Returns:
|
|
dict: Updated user or None if not found
|
|
"""
|
|
user = User.query.get(user_id)
|
|
if not user:
|
|
return None
|
|
|
|
hashed_password = generate_password_hash(new_password, method='pbkdf2:sha256')
|
|
user.password = hashed_password
|
|
db.session.commit()
|
|
return user.to_dict()
|
|
|
|
# ============================================================================
|
|
# PRODUCT OPERATIONS
|
|
# ============================================================================
|
|
|
|
def get_all_products(location=None):
|
|
"""
|
|
Get all products, optionally filtered by location
|
|
|
|
Args:
|
|
location (str, optional): Filter by location code
|
|
|
|
Returns:
|
|
list: List of product dictionaries
|
|
"""
|
|
query = Product.query
|
|
if location:
|
|
query = query.filter_by(location=location)
|
|
|
|
products = query.all()
|
|
return [product.to_dict() for product in products]
|
|
|
|
def get_product_by_code(product_code):
|
|
"""
|
|
Get a product by its product code
|
|
|
|
Args:
|
|
product_code (str): Product code
|
|
|
|
Returns:
|
|
dict: Product dictionary or None if not found
|
|
"""
|
|
product = Product.query.filter_by(product_code=product_code).first()
|
|
return product.to_dict() if product else None
|
|
|
|
def create_product(product_data):
|
|
"""
|
|
Create a new product
|
|
|
|
Args:
|
|
product_data (dict): Product data
|
|
|
|
Returns:
|
|
dict: Created product or None if code exists
|
|
"""
|
|
# Check if product already exists
|
|
if Product.query.filter_by(product_code=product_data['productCode']).first():
|
|
return None
|
|
|
|
# Create product
|
|
product = Product(
|
|
product_code=product_data['productCode'],
|
|
category=product_data.get('category'),
|
|
description=product_data.get('description'),
|
|
discontinued=product_data.get('discontinued', False),
|
|
location=product_data.get('location'),
|
|
base_type=product_data.get('baseType', ''),
|
|
is_accessory=product_data.get('isAccessory', False)
|
|
)
|
|
|
|
# Set JSON properties
|
|
product.subType = product_data.get('subType', {})
|
|
product.materials = product_data.get('materials', [])
|
|
product.colors = product_data.get('colors', [])
|
|
product.compatibleAccessories = product_data.get('compatibleAccessories', [])
|
|
product.imageConfig = product_data.get('imageConfig', {})
|
|
|
|
db.session.add(product)
|
|
db.session.commit()
|
|
|
|
return product.to_dict()
|
|
|
|
def update_product(product_code, product_data):
|
|
"""
|
|
Update an existing product
|
|
|
|
Args:
|
|
product_code (str): Product code
|
|
product_data (dict): Updated product data
|
|
|
|
Returns:
|
|
dict: Updated product or None if not found
|
|
"""
|
|
product = Product.query.filter_by(product_code=product_code).first()
|
|
if not product:
|
|
return None
|
|
|
|
# Update fields
|
|
if 'category' in product_data:
|
|
product.category = product_data['category']
|
|
if 'description' in product_data:
|
|
product.description = product_data['description']
|
|
if 'discontinued' in product_data:
|
|
product.discontinued = product_data['discontinued']
|
|
if 'location' in product_data:
|
|
product.location = product_data['location']
|
|
if 'baseType' in product_data:
|
|
product.base_type = product_data['baseType']
|
|
if 'isAccessory' in product_data:
|
|
product.is_accessory = product_data['isAccessory']
|
|
|
|
# Update JSON properties
|
|
if 'subType' in product_data:
|
|
product.subType = product_data['subType']
|
|
if 'materials' in product_data:
|
|
product.materials = product_data['materials']
|
|
if 'colors' in product_data:
|
|
product.colors = product_data['colors']
|
|
if 'compatibleAccessories' in product_data:
|
|
product.compatibleAccessories = product_data['compatibleAccessories']
|
|
if 'imageConfig' in product_data:
|
|
product.imageConfig = product_data['imageConfig']
|
|
|
|
db.session.commit()
|
|
return product.to_dict()
|
|
|
|
def delete_product(product_code):
|
|
"""
|
|
Delete a product
|
|
|
|
Args:
|
|
product_code (str): Product code
|
|
|
|
Returns:
|
|
bool: True if deleted, False if not found
|
|
"""
|
|
product = Product.query.filter_by(product_code=product_code).first()
|
|
if not product:
|
|
return False
|
|
|
|
db.session.delete(product)
|
|
db.session.commit()
|
|
return True
|
|
|
|
# ============================================================================
|
|
# LOCATION OPERATIONS
|
|
# ============================================================================
|
|
|
|
def get_all_locations():
|
|
"""Get all locations"""
|
|
locations = Location.query.filter_by(active=True).all()
|
|
return [loc.to_dict() for loc in locations]
|
|
|
|
def get_location_by_code(code):
|
|
"""Get a location by code"""
|
|
location = Location.query.filter_by(code=code).first()
|
|
return location.to_dict() if location else None
|
|
|
|
# ============================================================================
|
|
# PRODUCT ATTRIBUTES OPERATIONS
|
|
# ============================================================================
|
|
|
|
def get_product_attributes():
|
|
"""
|
|
Get product attributes configuration
|
|
|
|
Returns:
|
|
dict: Attributes with locations, statuses, productTypes, codeModifiers
|
|
"""
|
|
attributes = ProductAttribute.query.first()
|
|
|
|
if not attributes:
|
|
return {
|
|
'locations': get_all_locations(),
|
|
'statuses': [],
|
|
'productTypes': [],
|
|
'codeModifiers': []
|
|
}
|
|
|
|
return attributes.to_dict()
|
|
|
|
def update_product_attributes(attributes_data):
|
|
"""
|
|
Update product attributes configuration
|
|
|
|
Args:
|
|
attributes_data (dict): Updated attributes
|
|
|
|
Returns:
|
|
dict: Updated attributes
|
|
"""
|
|
attributes = ProductAttribute.query.first()
|
|
|
|
if not attributes:
|
|
attributes = ProductAttribute()
|
|
db.session.add(attributes)
|
|
|
|
if 'statuses' in attributes_data:
|
|
attributes.statuses = attributes_data['statuses']
|
|
if 'productTypes' in attributes_data:
|
|
attributes.productTypes = attributes_data['productTypes']
|
|
if 'codeModifiers' in attributes_data:
|
|
attributes.codeModifiers = attributes_data['codeModifiers']
|
|
|
|
db.session.commit()
|
|
return attributes.to_dict()
|
|
|
|
# ============================================================================
|
|
# UTILITY FUNCTIONS
|
|
# ============================================================================
|
|
|
|
def commit():
|
|
"""Commit current transaction"""
|
|
db.session.commit()
|
|
|
|
def rollback():
|
|
"""Rollback current transaction"""
|
|
db.session.rollback()
|