improved changes
This commit is contained in:
BIN
Machine-Backend/app/models/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
Machine-Backend/app/models/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
Machine-Backend/app/models/__pycache__/models.cpython-314.pyc
Normal file
BIN
Machine-Backend/app/models/__pycache__/models.cpython-314.pyc
Normal file
Binary file not shown.
@ -4,7 +4,35 @@ import time
|
||||
import json
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
|
||||
# Machine Model
|
||||
class RefillerMachine(db.Model):
|
||||
__tablename__ = 'refiller_machines'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
refiller_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
|
||||
machine_id = db.Column(db.String(10), db.ForeignKey('machines.machine_id', ondelete='CASCADE'), nullable=False)
|
||||
assigned_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
assigned_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
|
||||
# Relationships
|
||||
assigner = db.relationship('User', foreign_keys=[assigned_by], backref='machine_assignments_made')
|
||||
|
||||
# Unique constraint: one refiller can't be assigned to same machine twice
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint('refiller_id', 'machine_id', name='unique_refiller_machine'),
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'refiller_id': self.refiller_id,
|
||||
'machine_id': self.machine_id,
|
||||
'assigned_at': self.assigned_at.strftime("%Y-%m-%d %H:%M:%S") if self.assigned_at else None,
|
||||
'assigned_by': self.assigned_by,
|
||||
'assigned_by_username': self.assigner.username if self.assigner else None
|
||||
}
|
||||
|
||||
|
||||
# Machine Model - UPDATED
|
||||
class Machine(db.Model):
|
||||
__tablename__ = 'machines'
|
||||
|
||||
@ -20,10 +48,37 @@ class Machine(db.Model):
|
||||
connection_status = db.Column(db.String(50), nullable=False)
|
||||
created_on = db.Column(db.String(20), nullable=False)
|
||||
password = db.Column(db.String(128), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
|
||||
# Relationships
|
||||
slots = db.relationship('VendingSlot', backref='machine', lazy=True)
|
||||
client = db.relationship('User', backref='machines')
|
||||
client = db.relationship('User', foreign_keys=[client_id], backref='client_machines')
|
||||
creator = db.relationship('User', foreign_keys=[created_by], backref='created_machines')
|
||||
|
||||
# ⭐ NEW: Many-to-many relationship with Refillers through RefillerMachine
|
||||
assigned_refillers = db.relationship(
|
||||
'User',
|
||||
secondary='refiller_machines',
|
||||
primaryjoin='Machine.machine_id == RefillerMachine.machine_id',
|
||||
secondaryjoin='and_(User.id == RefillerMachine.refiller_id, User.roles == "Refiller")',
|
||||
backref='assigned_machines_rel',
|
||||
viewonly=True
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
# Get assigned refillers
|
||||
refiller_assignments = RefillerMachine.query.filter_by(machine_id=self.machine_id).all()
|
||||
assigned_refillers = []
|
||||
for assignment in refiller_assignments:
|
||||
refiller = User.query.get(assignment.refiller_id)
|
||||
if refiller:
|
||||
assigned_refillers.append({
|
||||
'id': refiller.id,
|
||||
'username': refiller.username,
|
||||
'email': refiller.email,
|
||||
'assigned_at': assignment.assigned_at.strftime("%Y-%m-%d %H:%M:%S") if assignment.assigned_at else None
|
||||
})
|
||||
|
||||
return {
|
||||
'id': self.id,
|
||||
'machine_id': self.machine_id,
|
||||
@ -36,7 +91,10 @@ class Machine(db.Model):
|
||||
'operation_status': self.operation_status,
|
||||
'connection_status': self.connection_status,
|
||||
'created_on': self.created_on,
|
||||
'password': self.password
|
||||
'password': self.password,
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'assigned_refillers': assigned_refillers # ⭐ NEW
|
||||
}
|
||||
|
||||
def set_password(self, password):
|
||||
@ -46,7 +104,7 @@ class Machine(db.Model):
|
||||
return check_password_hash(self.password, password)
|
||||
|
||||
|
||||
# User Model - UPDATED with proper password hashing
|
||||
# User Model - UPDATED WITH BOTH CLIENT AND MACHINE ASSIGNMENTS
|
||||
class User(db.Model):
|
||||
__tablename__ = 'users'
|
||||
|
||||
@ -57,7 +115,9 @@ class User(db.Model):
|
||||
contact = db.Column(db.String(20), nullable=False)
|
||||
roles = db.Column(db.String(50), nullable=False)
|
||||
user_status = db.Column(db.String(50), nullable=False)
|
||||
password = db.Column(db.String(255), nullable=False) # Increased length for hash
|
||||
password = db.Column(db.String(255), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
assigned_to = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True) # Assigned to Client
|
||||
|
||||
# File storage fields
|
||||
photo = db.Column(db.String(255), nullable=True)
|
||||
@ -67,9 +127,27 @@ class User(db.Model):
|
||||
# Timestamps
|
||||
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
creator = db.relationship('User', remote_side=[id], backref='created_users', foreign_keys=[created_by])
|
||||
assigned_client = db.relationship('User', remote_side=[id], backref='assigned_refillers', foreign_keys=[assigned_to])
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert user object to dictionary"""
|
||||
# Get assigned machines for Refillers
|
||||
assigned_machines = []
|
||||
if self.roles == 'Refiller':
|
||||
machine_assignments = RefillerMachine.query.filter_by(refiller_id=self.id).all()
|
||||
for assignment in machine_assignments:
|
||||
machine = Machine.query.filter_by(machine_id=assignment.machine_id).first()
|
||||
if machine:
|
||||
assigned_machines.append({
|
||||
'machine_id': machine.machine_id,
|
||||
'machine_model': machine.machine_model,
|
||||
'branch_name': machine.branch_name,
|
||||
'assigned_at': assignment.assigned_at.strftime("%Y-%m-%d %H:%M:%S") if assignment.assigned_at else None
|
||||
})
|
||||
|
||||
return {
|
||||
'id': self.id,
|
||||
'user_id': self.user_id,
|
||||
@ -83,7 +161,12 @@ class User(db.Model):
|
||||
'documents': json.loads(self.documents) if self.documents else [],
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None,
|
||||
'updated_at': self.updated_at.strftime("%Y-%m-%d %H:%M:%S") if self.updated_at else None,
|
||||
'machines': [m.to_dict() for m in self.machines] if hasattr(self, 'machines') else []
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'assigned_to': self.assigned_to,
|
||||
'assigned_to_username': self.assigned_client.username if self.assigned_client else None,
|
||||
'assigned_machines': assigned_machines, # ⭐ NEW
|
||||
'assigned_machines_count': len(assigned_machines) # ⭐ NEW
|
||||
}
|
||||
|
||||
def set_password(self, password):
|
||||
@ -125,6 +208,13 @@ class Product(db.Model):
|
||||
price = db.Column(db.Float, nullable=False)
|
||||
product_image = db.Column(db.String(255), nullable=False)
|
||||
created_date = db.Column(db.String(20), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
# NEW: Billing and expiration dates
|
||||
billing_date = db.Column(db.DateTime, nullable=True)
|
||||
expiration_date = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
# Relationship
|
||||
creator = db.relationship('User', backref='created_products')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@ -133,7 +223,11 @@ class Product(db.Model):
|
||||
'product_name': self.product_name,
|
||||
'price': str(self.price),
|
||||
'product_image': self.product_image,
|
||||
'created_date': self.created_date
|
||||
'created_date': self.created_date,
|
||||
'billing_date': self.billing_date.strftime("%Y-%m-%d") if self.billing_date else None,
|
||||
'expiration_date': self.expiration_date.strftime("%Y-%m-%d") if self.expiration_date else None,
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None
|
||||
}
|
||||
|
||||
|
||||
@ -191,7 +285,9 @@ class Transaction(db.Model):
|
||||
'return_amount': self.return_amount,
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None
|
||||
}
|
||||
# Add to your models.py
|
||||
|
||||
|
||||
# Role Model
|
||||
class Role(db.Model):
|
||||
__tablename__ = 'roles'
|
||||
|
||||
@ -199,15 +295,260 @@ class Role(db.Model):
|
||||
name = db.Column(db.String(50), unique=True, nullable=False)
|
||||
description = db.Column(db.String(255))
|
||||
permissions = db.Column(db.Text) # JSON string of permission IDs
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
# Relationship
|
||||
creator = db.relationship('User', backref='created_roles')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'description': self.description,
|
||||
'permissions': json.loads(self.permissions) if self.permissions else [],
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None,
|
||||
'updated_at': self.updated_at.strftime("%Y-%m-%d %H:%M:%S") if self.updated_at else None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Branch Model
|
||||
class Branch(db.Model):
|
||||
__tablename__ = 'branches'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
branch_id = db.Column(db.String(50), unique=True, nullable=False)
|
||||
code = db.Column(db.String(20), unique=True, nullable=False)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
location = db.Column(db.String(100), nullable=False)
|
||||
address = db.Column(db.Text, nullable=False)
|
||||
contact = db.Column(db.String(20), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
# Relationship
|
||||
creator = db.relationship('User', backref='created_branches')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'branch_id': self.branch_id,
|
||||
'code': self.code,
|
||||
'name': self.name,
|
||||
'location': self.location,
|
||||
'address': self.address,
|
||||
'contact': self.contact,
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None,
|
||||
'updated_at': self.updated_at.strftime("%Y-%m-%d %H:%M:%S") if self.updated_at else None
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def generate_branch_id():
|
||||
"""Generate unique branch ID with BR prefix"""
|
||||
import uuid
|
||||
while True:
|
||||
branch_id = f"BR{uuid.uuid4().hex[:8].upper()}"
|
||||
if not Branch.query.filter_by(branch_id=branch_id).first():
|
||||
return branch_id
|
||||
|
||||
# Brand Model
|
||||
class Brand(db.Model):
|
||||
__tablename__ = 'brands'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
brand_id = db.Column(db.String(50), unique=True, nullable=False)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
branch_id = db.Column(db.String(50), db.ForeignKey('branches.branch_id'), nullable=False)
|
||||
branch_name = db.Column(db.String(100), nullable=False)
|
||||
image = db.Column(db.String(255), nullable=True)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
branch = db.relationship('Branch', backref='brands', foreign_keys=[branch_id])
|
||||
creator = db.relationship('User', backref='created_brands')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'brand_id': self.brand_id,
|
||||
'name': self.name,
|
||||
'branch_id': self.branch_id,
|
||||
'branch_name': self.branch_name,
|
||||
'image': self.image,
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None,
|
||||
'updated_at': self.updated_at.strftime("%Y-%m-%d %H:%M:%S") if self.updated_at else None
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def generate_brand_id(name):
|
||||
"""
|
||||
Generate brand ID from first 3 letters of name + 4-digit sequence
|
||||
Example: CocaCola -> COC0001, COC0002, etc.
|
||||
"""
|
||||
import re
|
||||
|
||||
# Extract only letters from name and get first 3
|
||||
letters_only = ''.join(filter(str.isalpha, name)).upper()
|
||||
prefix = letters_only[:3].ljust(3, 'X') # Pad with X if less than 3 letters
|
||||
|
||||
# Find the highest existing sequence number for this prefix
|
||||
existing_brands = Brand.query.filter(
|
||||
Brand.brand_id.like(f"{prefix}%")
|
||||
).all()
|
||||
|
||||
if not existing_brands:
|
||||
sequence = 1
|
||||
else:
|
||||
# Extract sequence numbers and find max
|
||||
sequences = []
|
||||
for brand in existing_brands:
|
||||
try:
|
||||
seq_part = brand.brand_id[3:] # Get part after prefix
|
||||
if seq_part.isdigit():
|
||||
sequences.append(int(seq_part))
|
||||
except:
|
||||
continue
|
||||
|
||||
sequence = max(sequences) + 1 if sequences else 1
|
||||
|
||||
# Format: PREFIX + 4-digit sequence
|
||||
brand_id = f"{prefix}{sequence:04d}"
|
||||
|
||||
return brand_id
|
||||
|
||||
# Category Model
|
||||
class Category(db.Model):
|
||||
__tablename__ = 'categories'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
category_id = db.Column(db.String(50), unique=True, nullable=False)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
image = db.Column(db.String(255), nullable=True)
|
||||
brand_id = db.Column(db.String(50), db.ForeignKey('brands.brand_id'), nullable=False)
|
||||
brand_name = db.Column(db.String(100), nullable=False)
|
||||
branch_id = db.Column(db.String(50), db.ForeignKey('branches.branch_id'), nullable=False)
|
||||
branch_name = db.Column(db.String(100), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
brand = db.relationship('Brand', backref='categories', foreign_keys=[brand_id])
|
||||
branch = db.relationship('Branch', backref='categories', foreign_keys=[branch_id])
|
||||
creator = db.relationship('User', backref='created_categories')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'category_id': self.category_id,
|
||||
'name': self.name,
|
||||
'image': self.image,
|
||||
'brand_id': self.brand_id,
|
||||
'brand_name': self.brand_name,
|
||||
'branch_id': self.branch_id,
|
||||
'branch_name': self.branch_name,
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None,
|
||||
'updated_at': self.updated_at.strftime("%Y-%m-%d %H:%M:%S") if self.updated_at else None
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def generate_category_id(name):
|
||||
"""
|
||||
Generate category ID from first 3 letters of name + 4-digit sequence
|
||||
Example: Beverages -> BEV0001, BEV0002, etc.
|
||||
"""
|
||||
import re
|
||||
|
||||
# Extract only letters from name and get first 3
|
||||
letters_only = ''.join(filter(str.isalpha, name)).upper()
|
||||
prefix = letters_only[:3].ljust(3, 'X') # Pad with X if less than 3 letters
|
||||
|
||||
# Find the highest existing sequence number for this prefix
|
||||
existing_categories = Category.query.filter(
|
||||
Category.category_id.like(f"{prefix}%")
|
||||
).all()
|
||||
|
||||
if not existing_categories:
|
||||
sequence = 1
|
||||
else:
|
||||
# Extract sequence numbers and find max
|
||||
sequences = []
|
||||
for category in existing_categories:
|
||||
try:
|
||||
seq_part = category.category_id[3:] # Get part after prefix
|
||||
if seq_part.isdigit():
|
||||
sequences.append(int(seq_part))
|
||||
except:
|
||||
continue
|
||||
|
||||
sequence = max(sequences) + 1 if sequences else 1
|
||||
|
||||
# Format: PREFIX + 4-digit sequence
|
||||
category_id = f"{prefix}{sequence:04d}"
|
||||
|
||||
return category_id
|
||||
|
||||
class SubCategory(db.Model):
|
||||
__tablename__ = 'sub_categories'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
sub_category_id = db.Column(db.String(50), unique=True, nullable=False)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
image = db.Column(db.String(255), nullable=True)
|
||||
category_id = db.Column(db.String(50), db.ForeignKey('categories.category_id'), nullable=False)
|
||||
category_name = db.Column(db.String(100), nullable=False)
|
||||
brand_id = db.Column(db.String(50), db.ForeignKey('brands.brand_id'), nullable=False)
|
||||
brand_name = db.Column(db.String(100), nullable=False)
|
||||
branch_id = db.Column(db.String(50), db.ForeignKey('branches.branch_id'), nullable=False)
|
||||
branch_name = db.Column(db.String(100), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
category = db.relationship('Category', backref='sub_categories', foreign_keys=[category_id])
|
||||
brand = db.relationship('Brand', backref='sub_categories', foreign_keys=[brand_id])
|
||||
branch = db.relationship('Branch', backref='sub_categories', foreign_keys=[branch_id])
|
||||
creator = db.relationship('User', backref='created_subcategories')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'sub_category_id': self.sub_category_id,
|
||||
'name': self.name,
|
||||
'image': self.image,
|
||||
'category_id': self.category_id,
|
||||
'category_name': self.category_name,
|
||||
'brand_id': self.brand_id,
|
||||
'brand_name': self.brand_name,
|
||||
'branch_id': self.branch_id,
|
||||
'branch_name': self.branch_name,
|
||||
'created_by': self.created_by,
|
||||
'created_by_username': self.creator.username if self.creator else None,
|
||||
'created_at': self.created_at.strftime("%Y-%m-%d %H:%M:%S") if self.created_at else None,
|
||||
'updated_at': self.updated_at.strftime("%Y-%m-%d %H:%M:%S") if self.updated_at else None
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def generate_sub_category_id(name):
|
||||
letters_only = ''.join(filter(str.isalpha, name)).upper()
|
||||
prefix = letters_only[:3].ljust(3, 'X')
|
||||
existing = SubCategory.query.filter(SubCategory.sub_category_id.like(f"{prefix}%")).all()
|
||||
if not existing:
|
||||
sequence = 1
|
||||
else:
|
||||
sequences = [int(s.sub_category_id[3:]) for s in existing if s.sub_category_id[3:].isdigit()]
|
||||
sequence = max(sequences) + 1 if sequences else 1
|
||||
return f"{prefix}{sequence:04d}"
|
||||
Reference in New Issue
Block a user