| """
|
| نماذج بيانات النظام
|
| """
|
|
|
| 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}>" |