from sqlalchemy import Column, Integer, String, Boolean, DateTime, Text, Numeric, ForeignKey, JSON from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from datetime import datetime Base = declarative_base() class Project(Base): __tablename__ = "projects" id = Column(Integer, primary_key=True, index=True) official_project_code = Column(String(50), unique=True, index=True) project_name = Column(String(200), nullable=False) client_name = Column(String(100)) design_project_code = Column(String(50)) design_project_name = Column(String(200)) is_code_matched = Column(Boolean, default=False) matched_by = Column(String(100)) matched_at = Column(DateTime) status = Column(String(20), default='active') created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) description = Column(Text) notes = Column(Text) # 관계 설정 files = relationship("File", back_populates="project") class File(Base): __tablename__ = "files" id = Column(Integer, primary_key=True, index=True) project_id = Column(Integer, ForeignKey("projects.id")) filename = Column(String(255), nullable=False) original_filename = Column(String(255), nullable=False) file_path = Column(String(500), nullable=False) revision = Column(String(20), default='Rev.0') upload_date = Column(DateTime, default=datetime.utcnow) uploaded_by = Column(String(100)) file_type = Column(String(10)) file_size = Column(Integer) is_active = Column(Boolean, default=True) # 관계 설정 project = relationship("Project", back_populates="files") materials = relationship("Material", back_populates="file") class Material(Base): __tablename__ = "materials" id = Column(Integer, primary_key=True, index=True) file_id = Column(Integer, ForeignKey("files.id")) line_number = Column(Integer) original_description = Column(Text, nullable=False) classified_category = Column(String(50)) classified_subcategory = Column(String(100)) material_grade = Column(String(50)) schedule = Column(String(20)) size_spec = Column(String(50)) quantity = Column(Numeric(10, 3), nullable=False) unit = Column(String(10), nullable=False) # length = Column(Numeric(10, 3)) # 임시로 주석 처리 drawing_name = Column(String(100)) area_code = Column(String(20)) line_no = Column(String(50)) classification_confidence = Column(Numeric(3, 2)) is_verified = Column(Boolean, default=False) verified_by = Column(String(50)) verified_at = Column(DateTime) drawing_reference = Column(String(100)) notes = Column(Text) created_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 file = relationship("File", back_populates="materials") # ========== 자재 규격/재질 기준표 테이블들 ========== class MaterialStandard(Base): """자재 규격 표준 (ASTM, KS, JIS 등)""" __tablename__ = "material_standards" id = Column(Integer, primary_key=True, index=True) standard_code = Column(String(20), unique=True, nullable=False, index=True) # ASTM_ASME, KS, JIS standard_name = Column(String(100), nullable=False) # 미국재질학회, 한국산업표준, 일본공업규격 description = Column(Text) country = Column(String(50)) # USA, KOREA, JAPAN is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 categories = relationship("MaterialCategory", back_populates="standard") class MaterialCategory(Base): """제조방식별 카테고리 (FORGED, WELDED, CAST 등)""" __tablename__ = "material_categories" id = Column(Integer, primary_key=True, index=True) standard_id = Column(Integer, ForeignKey("material_standards.id")) category_code = Column(String(50), nullable=False) # FORGED_GRADES, WELDED_GRADES, CAST_GRADES category_name = Column(String(100), nullable=False) # 단조품, 용접품, 주조품 description = Column(Text) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 standard = relationship("MaterialStandard", back_populates="categories") specifications = relationship("MaterialSpecification", back_populates="category") class MaterialSpecification(Base): """구체적인 규격 (A182, A105, D3507 등)""" __tablename__ = "material_specifications" id = Column(Integer, primary_key=True, index=True) category_id = Column(Integer, ForeignKey("material_categories.id")) spec_code = Column(String(20), nullable=False) # A182, A105, D3507 spec_name = Column(String(100), nullable=False) # 탄소강 단조품, 배관용 탄소강관 description = Column(Text) material_type = Column(String(50)) # carbon_alloy, stainless, carbon manufacturing = Column(String(50)) # FORGED, WELDED_FABRICATED, CAST, SEAMLESS pressure_rating = Column(String(100)) # 150LB ~ 9000LB is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 category = relationship("MaterialCategory", back_populates="specifications") grades = relationship("MaterialGrade", back_populates="specification") patterns = relationship("MaterialPattern", back_populates="specification") class MaterialGrade(Base): """등급별 상세 정보 (F1, F5, WPA, WPB 등)""" __tablename__ = "material_grades" id = Column(Integer, primary_key=True, index=True) specification_id = Column(Integer, ForeignKey("material_specifications.id")) grade_code = Column(String(20), nullable=False) # F1, F5, WPA, WPB grade_name = Column(String(100)) composition = Column(String(200)) # 0.5Mo, 5Cr-0.5Mo, 18Cr-8Ni applications = Column(String(200)) # 중온용, 고온용, 저압용 temp_max = Column(String(50)) # 482°C, 649°C temp_range = Column(String(100)) # -29°C ~ 400°C yield_strength = Column(String(50)) # 30 ksi, 35 ksi tensile_strength = Column(String(50)) corrosion_resistance = Column(String(50)) # 보통, 우수 stabilizer = Column(String(50)) # Titanium, Niobium base_grade = Column(String(20)) # 304, 316 is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 specification = relationship("MaterialSpecification", back_populates="grades") class MaterialPattern(Base): """정규식 패턴들""" __tablename__ = "material_patterns" id = Column(Integer, primary_key=True, index=True) specification_id = Column(Integer, ForeignKey("material_specifications.id")) pattern = Column(Text, nullable=False) # 정규식 패턴 description = Column(String(200)) priority = Column(Integer, default=1) # 패턴 우선순위 is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 specification = relationship("MaterialSpecification", back_populates="patterns") class SpecialMaterial(Base): """특수 재질 (INCONEL, HASTELLOY, TITANIUM 등)""" __tablename__ = "special_materials" id = Column(Integer, primary_key=True, index=True) material_type = Column(String(50), nullable=False) # SUPER_ALLOYS, TITANIUM, COPPER_ALLOYS material_name = Column(String(100), nullable=False) # INCONEL, HASTELLOY, TITANIUM description = Column(Text) composition = Column(String(200)) applications = Column(Text) temp_max = Column(String(50)) manufacturing = Column(String(50)) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 grades = relationship("SpecialMaterialGrade", back_populates="material") patterns = relationship("SpecialMaterialPattern", back_populates="material") class SpecialMaterialGrade(Base): """특수 재질 등급""" __tablename__ = "special_material_grades" id = Column(Integer, primary_key=True, index=True) material_id = Column(Integer, ForeignKey("special_materials.id")) grade_code = Column(String(20), nullable=False) # 600, 625, C276 composition = Column(String(200)) applications = Column(String(200)) temp_max = Column(String(50)) strength = Column(String(50)) purity = Column(String(100)) corrosion = Column(String(50)) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 material = relationship("SpecialMaterial", back_populates="grades") class SpecialMaterialPattern(Base): """특수 재질 정규식 패턴""" __tablename__ = "special_material_patterns" id = Column(Integer, primary_key=True, index=True) material_id = Column(Integer, ForeignKey("special_materials.id")) pattern = Column(Text, nullable=False) description = Column(String(200)) priority = Column(Integer, default=1) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 material = relationship("SpecialMaterial", back_populates="patterns") # ========== 파이프 상세 정보 및 사용자 요구사항 테이블 ========== class PipeDetail(Base): """파이프 상세 정보""" __tablename__ = "pipe_details" id = Column(Integer, primary_key=True, index=True) file_id = Column(Integer, ForeignKey("files.id"), nullable=False) # 재질 정보 material_standard = Column(String(50)) # ASTM, KS, JIS 등 material_grade = Column(String(50)) # A106, A53, STPG370 등 material_type = Column(String(50)) # CARBON, STAINLESS 등 # 파이프 특화 정보 manufacturing_method = Column(String(50)) # SEAMLESS, WELDED, CAST end_preparation = Column(String(50)) # BOTH_ENDS_BEVELED, ONE_END_BEVELED, NO_BEVEL schedule = Column(String(50)) # SCH 10, 20, 40, 80 등 wall_thickness = Column(String(50)) # 벽두께 정보 # 치수 정보 nominal_size = Column(String(50)) # MAIN_NOM (인치, 직경) length_mm = Column(Numeric(10, 3)) # LENGTH (길이) # 신뢰도 material_confidence = Column(Numeric(3, 2)) manufacturing_confidence = Column(Numeric(3, 2)) end_prep_confidence = Column(Numeric(3, 2)) schedule_confidence = Column(Numeric(3, 2)) # 메타데이터 created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 file = relationship("File", backref="pipe_details") class RequirementType(Base): """요구사항 타입 마스터""" __tablename__ = "requirement_types" id = Column(Integer, primary_key=True, index=True) type_code = Column(String(50), unique=True, nullable=False) # 'IMPACT_TEST', 'HEAT_TREATMENT' 등 type_name = Column(String(100), nullable=False) # '임팩테스트', '열처리' 등 category = Column(String(50), nullable=False) # 'TEST', 'TREATMENT', 'CERTIFICATION', 'CUSTOM' 등 description = Column(Text) # 타입 설명 is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 requirements = relationship("UserRequirement", back_populates="requirement_type") class UserRequirement(Base): """사용자 추가 요구사항""" __tablename__ = "user_requirements" id = Column(Integer, primary_key=True, index=True) file_id = Column(Integer, ForeignKey("files.id"), nullable=False) # 요구사항 타입 requirement_type = Column(String(50), nullable=False) # 'IMPACT_TEST', 'HEAT_TREATMENT', 'CUSTOM_SPEC', 'CERTIFICATION' 등 # 요구사항 내용 requirement_title = Column(String(200), nullable=False) # '임팩테스트', '열처리', '인증서' 등 requirement_description = Column(Text) # 상세 설명 requirement_spec = Column(Text) # 구체적 스펙 (예: "Charpy V-notch -20°C") # 상태 관리 status = Column(String(20), default='PENDING') # 'PENDING', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED' priority = Column(String(20), default='NORMAL') # 'LOW', 'NORMAL', 'HIGH', 'URGENT' # 담당자 정보 assigned_to = Column(String(100)) # 담당자명 due_date = Column(DateTime) # 완료 예정일 # 메타데이터 created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) # 관계 설정 file = relationship("File", backref="user_requirements") requirement_type_rel = relationship("RequirementType", back_populates="requirements")