|
"""
|
|
نماذج بيانات النظام
|
|
"""
|
|
|
|
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, Boolean, Text, Table, Enum
|
|
from sqlalchemy.orm import relationship
|
|
from datetime import datetime
|
|
import enum
|
|
|
|
from database.db_connector import Base
|
|
|
|
|
|
|
|
project_files = Table(
|
|
'project_files',
|
|
Base.metadata,
|
|
Column('project_id', Integer, ForeignKey('projects.id'), primary_key=True),
|
|
Column('file_id', Integer, ForeignKey('files.id'), primary_key=True)
|
|
)
|
|
|
|
|
|
class ProjectStatus(enum.Enum):
|
|
"""حالة المشروع"""
|
|
NEW = "جديد"
|
|
PRICING = "قيد التسعير"
|
|
SUBMITTED = "تم التقديم"
|
|
AWARDED = "تمت الترسية"
|
|
EXECUTION = "قيد التنفيذ"
|
|
COMPLETED = "منتهي"
|
|
CANCELLED = "ملغي"
|
|
|
|
class TenderType(enum.Enum):
|
|
"""نوع المناقصة"""
|
|
PUBLIC = "عامة"
|
|
PRIVATE = "خاصة"
|
|
DIRECT = "أمر مباشر"
|
|
|
|
class PricingMethod(enum.Enum):
|
|
"""طريقة التسعير"""
|
|
STANDARD = "قياسي"
|
|
UNBALANCED = "غير متزن"
|
|
COMPETITIVE = "تنافسي"
|
|
PROFITABILITY = "موجه بالربحية"
|
|
|
|
|
|
class User(Base):
|
|
"""نموذج بيانات المستخدم"""
|
|
__tablename__ = 'users'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
username = Column(String(50), unique=True, nullable=False)
|
|
password_hash = Column(String(128), nullable=False)
|
|
full_name = Column(String(100), nullable=False)
|
|
email = Column(String(100), unique=True, nullable=False)
|
|
phone = Column(String(20))
|
|
role = Column(String(20), nullable=False)
|
|
department = Column(String(50))
|
|
is_active = Column(Boolean, default=True)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
last_login = Column(DateTime)
|
|
|
|
|
|
projects = relationship("Project", back_populates="created_by")
|
|
pricing_items = relationship("PricingItem", back_populates="created_by")
|
|
|
|
def __repr__(self):
|
|
return f"<User {self.username}>"
|
|
|
|
|
|
class Project(Base):
|
|
"""نموذج بيانات المشروع"""
|
|
__tablename__ = 'projects'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
name = Column(String(100), nullable=False)
|
|
tender_number = Column(String(50))
|
|
client = Column(String(100), nullable=False)
|
|
location = Column(String(100))
|
|
description = Column(Text)
|
|
status = Column(Enum(ProjectStatus), default=ProjectStatus.NEW)
|
|
tender_type = Column(Enum(TenderType), default=TenderType.PUBLIC)
|
|
pricing_method = Column(Enum(PricingMethod), default=PricingMethod.STANDARD)
|
|
submission_date = Column(DateTime)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
created_by_id = Column(Integer, ForeignKey('users.id'))
|
|
|
|
|
|
created_by = relationship("User", back_populates="projects")
|
|
pricing_sections = relationship("PricingSection", back_populates="project", cascade="all, delete-orphan")
|
|
pricing_items = relationship("PricingItem", back_populates="project", cascade="all, delete-orphan")
|
|
local_content_items = relationship("LocalContentItem", back_populates="project", cascade="all, delete-orphan")
|
|
risk_items = relationship("RiskItem", back_populates="project", cascade="all, delete-orphan")
|
|
files = relationship("File", secondary=project_files, back_populates="projects")
|
|
|
|
def __repr__(self):
|
|
return f"<Project {self.name}>"
|
|
|
|
|
|
class PricingSection(Base):
|
|
"""نموذج بيانات قسم التسعير"""
|
|
__tablename__ = 'pricing_sections'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
project_id = Column(Integer, ForeignKey('projects.id'), nullable=False)
|
|
name = Column(String(100), nullable=False)
|
|
description = Column(Text)
|
|
section_order = Column(Integer, default=0)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
project = relationship("Project", back_populates="pricing_sections")
|
|
pricing_items = relationship("PricingItem", back_populates="section", cascade="all, delete-orphan")
|
|
|
|
def __repr__(self):
|
|
return f"<PricingSection {self.name}>"
|
|
|
|
|
|
class PricingItem(Base):
|
|
"""نموذج بيانات بند التسعير"""
|
|
__tablename__ = 'pricing_items'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
project_id = Column(Integer, ForeignKey('projects.id'), nullable=False)
|
|
section_id = Column(Integer, ForeignKey('pricing_sections.id'))
|
|
item_code = Column(String(20))
|
|
description = Column(Text, nullable=False)
|
|
unit = Column(String(20), nullable=False)
|
|
quantity = Column(Float, nullable=False)
|
|
unit_price = Column(Float, default=0)
|
|
unbalanced_price = Column(Float)
|
|
final_price = Column(Float)
|
|
pricing_strategy = Column(String(20), default="متوازن")
|
|
notes = Column(Text)
|
|
created_by_id = Column(Integer, ForeignKey('users.id'))
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
project = relationship("Project", back_populates="pricing_items")
|
|
section = relationship("PricingSection", back_populates="pricing_items")
|
|
created_by = relationship("User", back_populates="pricing_items")
|
|
resource_usages = relationship("ResourceUsage", back_populates="pricing_item")
|
|
|
|
def __repr__(self):
|
|
return f"<PricingItem {self.item_code}: {self.description[:30]}>"
|
|
|
|
|
|
class LocalContentItem(Base):
|
|
"""نموذج بيانات بند المحتوى المحلي"""
|
|
__tablename__ = 'local_content_items'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
project_id = Column(Integer, ForeignKey('projects.id'), nullable=False)
|
|
category = Column(String(50), nullable=False)
|
|
item_name = Column(String(100), nullable=False)
|
|
supplier_id = Column(Integer, ForeignKey('suppliers.id'))
|
|
total_cost = Column(Float, default=0)
|
|
local_percentage = Column(Float, default=0)
|
|
notes = Column(Text)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
project = relationship("Project", back_populates="local_content_items")
|
|
supplier = relationship("Supplier", back_populates="local_content_items")
|
|
|
|
def __repr__(self):
|
|
return f"<LocalContentItem {self.item_name}>"
|
|
|
|
|
|
class Supplier(Base):
|
|
"""نموذج بيانات المورد"""
|
|
__tablename__ = 'suppliers'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
name = Column(String(100), nullable=False)
|
|
contact_person = Column(String(100))
|
|
phone = Column(String(20))
|
|
email = Column(String(100))
|
|
address = Column(String(200))
|
|
category = Column(String(50))
|
|
is_local = Column(Boolean, default=False)
|
|
local_content_percentage = Column(Float, default=0)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
local_content_items = relationship("LocalContentItem", back_populates="supplier")
|
|
resources = relationship("Resource", back_populates="supplier")
|
|
|
|
def __repr__(self):
|
|
return f"<Supplier {self.name}>"
|
|
|
|
|
|
class RiskItem(Base):
|
|
"""نموذج بيانات المخاطرة"""
|
|
__tablename__ = 'risk_items'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
project_id = Column(Integer, ForeignKey('projects.id'), nullable=False)
|
|
risk_code = Column(String(20))
|
|
description = Column(Text, nullable=False)
|
|
category = Column(String(50), nullable=False)
|
|
impact = Column(String(20), nullable=False)
|
|
probability = Column(String(20), nullable=False)
|
|
mitigation_strategy = Column(Text)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
project = relationship("Project", back_populates="risk_items")
|
|
|
|
def __repr__(self):
|
|
return f"<RiskItem {self.risk_code}: {self.description[:30]}>"
|
|
|
|
|
|
class Resource(Base):
|
|
"""نموذج بيانات المورد"""
|
|
__tablename__ = 'resources'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
code = Column(String(20), unique=True)
|
|
name = Column(String(100), nullable=False)
|
|
description = Column(Text)
|
|
category = Column(String(50), nullable=False)
|
|
unit = Column(String(20), nullable=False)
|
|
unit_price = Column(Float, default=0)
|
|
supplier_id = Column(Integer, ForeignKey('suppliers.id'))
|
|
is_local = Column(Boolean, default=False)
|
|
local_content_percentage = Column(Float, default=0)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
supplier = relationship("Supplier", back_populates="resources")
|
|
resource_usages = relationship("ResourceUsage", back_populates="resource")
|
|
|
|
def __repr__(self):
|
|
return f"<Resource {self.code}: {self.name}>"
|
|
|
|
|
|
class ResourceUsage(Base):
|
|
"""نموذج بيانات استخدام المورد"""
|
|
__tablename__ = 'resource_usages'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
pricing_item_id = Column(Integer, ForeignKey('pricing_items.id'), nullable=False)
|
|
resource_id = Column(Integer, ForeignKey('resources.id'), nullable=False)
|
|
quantity = Column(Float, nullable=False)
|
|
created_at = Column(DateTime, default=datetime.now)
|
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
|
|
|
|
|
pricing_item = relationship("PricingItem", back_populates="resource_usages")
|
|
resource = relationship("Resource", back_populates="resource_usages")
|
|
|
|
def __repr__(self):
|
|
return f"<ResourceUsage {self.pricing_item_id} - {self.resource_id}>"
|
|
|
|
|
|
class File(Base):
|
|
"""نموذج بيانات الملف"""
|
|
__tablename__ = 'files'
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
filename = Column(String(100), nullable=False)
|
|
original_filename = Column(String(100), nullable=False)
|
|
file_type = Column(String(20), nullable=False)
|
|
file_size = Column(Integer, nullable=False)
|
|
file_path = Column(String(255), nullable=False)
|
|
upload_date = Column(DateTime, default=datetime.now)
|
|
|
|
|
|
projects = relationship("Project", secondary=project_files, back_populates="files")
|
|
|
|
def __repr__(self):
|
|
return f"<File {self.original_filename}>" |