Files
TK-BOM-Project/backend/app/models.py
Hyungi Ahn 1dc735f362
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
리비전 페이지 제거 및 트랜잭션 오류 임시 수정
- frontend/src/pages/revision/ 폴더 완전 삭제
- EnhancedRevisionPage.css 제거
- support_details 저장 시 트랜잭션 오류로 인해 임시로 상세 정보 저장 비활성화
- 리비전 기능 재설계 예정
2025-10-21 12:11:57 +09:00

886 lines
34 KiB
Python

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)
job_no = Column(String(50)) # 작업 번호
revision = Column(String(20), default='Rev.0')
bom_name = Column(String(200)) # BOM 이름
description = Column(Text) # 파일 설명
upload_date = Column(DateTime, default=datetime.utcnow)
uploaded_by = Column(String(100))
file_type = Column(String(10))
file_size = Column(Integer)
parsed_count = 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)
row_number = Column(Integer) # 업로드 시 행 번호
original_description = Column(Text, nullable=False)
classified_category = Column(String(50))
classified_subcategory = Column(String(100))
material_grade = Column(String(50))
full_material_grade = Column(Text) # 전체 재질명 (ASTM A312 TP304 등)
schedule = Column(String(20))
size_spec = Column(String(50))
main_nom = Column(String(50)) # 주 사이즈 (4", 150A 등)
red_nom = Column(String(50)) # 축소 사이즈 (Reducing 피팅/플랜지용)
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))
classification_details = Column(JSON) # 분류 상세 정보 (JSON)
is_verified = Column(Boolean, default=False)
verified_by = Column(String(50))
verified_at = Column(DateTime)
# 구매 관련 필드
purchase_confirmed = Column(Boolean, default=False)
confirmed_quantity = Column(Numeric(10, 3))
purchase_status = Column(String(20))
purchase_confirmed_by = Column(String(100))
purchase_confirmed_at = Column(DateTime)
# 리비전 관리 필드
revision_status = Column(String(20)) # 'new', 'changed', 'inventory', 'deleted_not_purchased'
material_hash = Column(String(64)) # 자재 비교용 해시
normalized_description = Column(Text) # 정규화된 설명
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)
# 관계 설정은 문자열 기반이므로 제거
class UserRequirement(Base):
"""사용자 추가 요구사항"""
__tablename__ = "user_requirements"
id = Column(Integer, primary_key=True, index=True)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=True) # 자재 ID (개별 자재별 요구사항 연결)
# 요구사항 타입
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")
# ========== Tubing 시스템 모델들 ==========
class TubingCategory(Base):
"""Tubing 카테고리 (일반, VCR, 위생용 등)"""
__tablename__ = "tubing_categories"
id = Column(Integer, primary_key=True, index=True)
category_code = Column(String(20), unique=True, nullable=False)
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)
# 관계 설정
specifications = relationship("TubingSpecification", back_populates="category")
class TubingSpecification(Base):
"""Tubing 규격 마스터"""
__tablename__ = "tubing_specifications"
id = Column(Integer, primary_key=True, index=True)
category_id = Column(Integer, ForeignKey("tubing_categories.id"))
spec_code = Column(String(50), unique=True, nullable=False)
spec_name = Column(String(200), nullable=False)
# 물리적 규격
outer_diameter_mm = Column(Numeric(8, 3))
wall_thickness_mm = Column(Numeric(6, 3))
inner_diameter_mm = Column(Numeric(8, 3))
# 재질 정보
material_grade = Column(String(100))
material_standard = Column(String(100))
# 압력/온도 등급
max_pressure_bar = Column(Numeric(8, 2))
max_temperature_c = Column(Numeric(6, 2))
min_temperature_c = Column(Numeric(6, 2))
# 표준 규격
standard_length_m = Column(Numeric(8, 3))
bend_radius_min_mm = Column(Numeric(8, 2))
# 기타 정보
surface_finish = Column(String(100))
hardness = Column(String(50))
notes = Column(Text)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
category = relationship("TubingCategory", back_populates="specifications")
products = relationship("TubingProduct", back_populates="specification")
class TubingManufacturer(Base):
"""Tubing 제조사"""
__tablename__ = "tubing_manufacturers"
id = Column(Integer, primary_key=True, index=True)
manufacturer_code = Column(String(20), unique=True, nullable=False)
manufacturer_name = Column(String(200), nullable=False)
country = Column(String(100))
website = Column(String(500))
contact_info = Column(JSON) # JSONB 타입
quality_certs = Column(JSON) # JSONB 타입
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
products = relationship("TubingProduct", back_populates="manufacturer")
class TubingProduct(Base):
"""제조사별 Tubing 제품 (품목번호 매핑)"""
__tablename__ = "tubing_products"
id = Column(Integer, primary_key=True, index=True)
specification_id = Column(Integer, ForeignKey("tubing_specifications.id"))
manufacturer_id = Column(Integer, ForeignKey("tubing_manufacturers.id"))
# 제조사 품목번호 정보
manufacturer_part_number = Column(String(200), nullable=False)
manufacturer_product_name = Column(String(300))
# 가격/공급 정보
list_price = Column(Numeric(12, 2))
currency = Column(String(10), default='KRW')
lead_time_days = Column(Integer)
minimum_order_qty = Column(Numeric(10, 3))
standard_packaging_qty = Column(Numeric(10, 3))
# 가용성 정보
availability_status = Column(String(50))
last_price_update = Column(DateTime)
# 추가 정보
datasheet_url = Column(String(500))
catalog_page = Column(String(100))
notes = Column(Text)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
specification = relationship("TubingSpecification", back_populates="products")
manufacturer = relationship("TubingManufacturer", back_populates="products")
material_mappings = relationship("MaterialTubingMapping", back_populates="tubing_product")
class MaterialTubingMapping(Base):
"""BOM 자재와 Tubing 제품 매핑"""
__tablename__ = "material_tubing_mapping"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id", ondelete="CASCADE"))
tubing_product_id = Column(Integer, ForeignKey("tubing_products.id"))
# 매핑 정보
confidence_score = Column(Numeric(3, 2))
mapping_method = Column(String(50))
mapped_by = Column(String(100))
mapped_at = Column(DateTime, default=datetime.utcnow)
# 수량 정보
required_length_m = Column(Numeric(10, 3))
calculated_quantity = Column(Numeric(10, 3))
# 검증 정보
is_verified = Column(Boolean, default=False)
verified_by = Column(String(100))
verified_at = Column(DateTime)
notes = Column(Text)
created_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
material = relationship("Material", backref="tubing_mappings")
tubing_product = relationship("TubingProduct", back_populates="material_mappings")
class SupportDetails(Base):
__tablename__ = "support_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 서포트 정보
support_type = Column(String(50))
support_subtype = Column(String(100))
load_rating = Column(String(50))
load_capacity = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
pipe_size = Column(String(50))
# 치수 정보
length_mm = Column(Numeric(10, 2))
width_mm = Column(Numeric(10, 2))
height_mm = Column(Numeric(10, 2))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class PurchaseRequestItems(Base):
__tablename__ = "purchase_request_items"
id = Column(Integer, primary_key=True, index=True)
request_id = Column(String(50), nullable=False) # 구매신청 ID
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
# 수량 정보
quantity = Column(Integer, nullable=False)
unit = Column(String(10), nullable=False)
user_requirement = Column(Text)
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
class FittingDetails(Base):
__tablename__ = "fitting_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 피팅 정보
fitting_type = Column(String(50))
fitting_subtype = Column(String(100))
connection_type = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
nominal_size = Column(String(50))
wall_thickness = Column(String(50))
# 치수 정보
length_mm = Column(Numeric(10, 2))
width_mm = Column(Numeric(10, 2))
height_mm = Column(Numeric(10, 2))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class FlangeDetails(Base):
__tablename__ = "flange_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 플랜지 정보
flange_type = Column(String(50))
flange_subtype = Column(String(100))
pressure_rating = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
nominal_size = Column(String(50))
# 치수 정보
outer_diameter = Column(Numeric(10, 2))
thickness = Column(Numeric(10, 2))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class ValveDetails(Base):
__tablename__ = "valve_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 밸브 정보
valve_type = Column(String(50))
valve_subtype = Column(String(100))
connection_type = Column(String(50))
actuation_type = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
nominal_size = Column(String(50))
pressure_rating = Column(String(50))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class GasketDetails(Base):
__tablename__ = "gasket_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 가스켓 정보
gasket_type = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
nominal_size = Column(String(50))
pressure_rating = Column(String(50))
filler_material = Column(String(50))
thickness = Column(Numeric(10, 2))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class BoltDetails(Base):
__tablename__ = "bolt_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 볼트 정보
bolt_type = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
thread_size = Column(String(50))
length = Column(Numeric(10, 2))
pressure_rating = Column(String(50))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class InstrumentDetails(Base):
__tablename__ = "instrument_details"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
# 계기 정보
instrument_type = Column(String(50))
instrument_subtype = Column(String(100))
connection_type = Column(String(50))
material_standard = Column(String(50))
material_grade = Column(String(50))
nominal_size = Column(String(50))
# 분류 신뢰도
classification_confidence = Column(Numeric(3, 2))
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class PurchaseRequests(Base):
__tablename__ = "purchase_requests"
request_id = Column(String(50), primary_key=True, index=True)
request_no = Column(String(100), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
job_no = Column(String(50), nullable=False)
category = Column(String(50))
material_count = Column(Integer)
excel_file_path = Column(String(500))
requested_by = Column(Integer) # ForeignKey 제거
requested_by_username = Column(String(100)) # 사용자명 직접 저장
# 시간 정보
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# 관계 설정
file = relationship("File")
# requested_by_user relationship 제거
class Jobs(Base):
__tablename__ = "jobs"
id = Column(Integer, primary_key=True, index=True)
job_no = Column(String(50), unique=True, nullable=False)
job_name = Column(String(200))
status = Column(String(20), default='active')
created_at = Column(DateTime, default=datetime.utcnow)
class PipeEndPreparations(Base):
__tablename__ = "pipe_end_preparations"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
end_prep_type = Column(String(50))
end_prep_standard = Column(String(50))
classification_confidence = Column(Numeric(3, 2))
created_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class MaterialPurchaseTracking(Base):
__tablename__ = "material_purchase_tracking"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"), nullable=False)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
purchase_status = Column(String(20))
requested_quantity = Column(Integer)
confirmed_quantity = Column(Integer)
purchase_date = Column(DateTime)
created_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
material = relationship("Material")
file = relationship("File")
class ExcelExports(Base):
__tablename__ = "excel_exports"
id = Column(Integer, primary_key=True, index=True)
file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
export_type = Column(String(50))
file_path = Column(String(500))
exported_by = Column(Integer, ForeignKey("users.user_id"))
created_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
file = relationship("File")
# exported_by_user relationship 제거
class UserActivityLogs(Base):
__tablename__ = "user_activity_logs"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.user_id"))
activity_type = Column(String(50))
activity_description = Column(Text)
created_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
# user relationship 제거
class ExcelExportHistory(Base):
__tablename__ = "excel_export_history"
export_id = Column(String(50), primary_key=True, index=True)
file_id = Column(Integer, ForeignKey("files.id"))
job_no = Column(String(50))
exported_by = Column(Integer) # ForeignKey 제거
exported_by_username = Column(String(100)) # 사용자명 직접 저장
export_date = Column(DateTime, default=datetime.utcnow)
# 관계 설정
file = relationship("File")
# exported_by_user relationship 제거
class ExportedMaterials(Base):
__tablename__ = "exported_materials"
id = Column(Integer, primary_key=True, index=True)
export_id = Column(String(50), ForeignKey("excel_export_history.export_id"))
material_id = Column(Integer, ForeignKey("materials.id"))
quantity = Column(Integer)
status = Column(String(20))
# 관계 설정
export_history = relationship("ExcelExportHistory")
material = relationship("Material")
class PurchaseStatusHistory(Base):
__tablename__ = "purchase_status_history"
id = Column(Integer, primary_key=True, index=True)
material_id = Column(Integer, ForeignKey("materials.id"))
old_status = Column(String(20))
new_status = Column(String(20))
changed_by = Column(Integer, ForeignKey("users.user_id"))
changed_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정
material = relationship("Material")
# changed_by_user relationship 제거
# ========== 간단한 리비전 관리 시스템 ==========
class SimpleRevisionComparison(Base):
"""간단한 리비전 비교 결과 저장"""
__tablename__ = "simple_revision_comparisons"
id = Column(Integer, primary_key=True, index=True)
job_no = Column(String(50), nullable=False, index=True)
current_file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
previous_file_id = Column(Integer, ForeignKey("files.id"), nullable=False)
category = Column(String(50), nullable=False) # 비교 대상 카테고리
# 비교 결과 통계
added_count = Column(Integer, default=0)
removed_count = Column(Integer, default=0)
changed_count = Column(Integer, default=0)
unchanged_count = Column(Integer, default=0)
# 구매 상태별 통계
purchased_affected = Column(Integer, default=0)
unpurchased_affected = Column(Integer, default=0)
inventory_count = Column(Integer, default=0)
# 메타데이터
comparison_data = Column(JSON) # 상세 비교 결과
created_at = Column(DateTime, default=datetime.utcnow)
created_by_username = Column(String(100))
# 관계 설정 (간단하게)
current_file = relationship("File", foreign_keys=[current_file_id])
previous_file = relationship("File", foreign_keys=[previous_file_id])
class SimpleRevisionMaterial(Base):
"""간단한 리비전 자재 변경 로그"""
__tablename__ = "simple_revision_materials"
id = Column(Integer, primary_key=True, index=True)
comparison_id = Column(Integer, ForeignKey("simple_revision_comparisons.id"), nullable=False)
material_id = Column(Integer, ForeignKey("materials.id"))
change_type = Column(String(20), nullable=False) # 'added', 'removed', 'changed', 'quantity_changed'
revision_action = Column(String(30)) # 'maintain', 'additional_purchase', 'inventory', 'delete', 'quantity_update'
# 수량 변경 정보
quantity_before = Column(Numeric(10, 3))
quantity_after = Column(Numeric(10, 3))
quantity_difference = Column(Numeric(10, 3))
purchase_status = Column(String(20)) # 'purchased', 'not_purchased'
created_at = Column(DateTime, default=datetime.utcnow)
# 관계 설정 (간단하게)
comparison = relationship("SimpleRevisionComparison")
material = relationship("Material")
# ========== 간단한 리비전 시스템 완료 ==========
# 나머지 복잡한 테이블들은 제거하고 필요시 추가
# 기존 복잡한 모델들 제거됨 (PipeLengthCalculation, MaterialPurchaseHistory 등)
# 필요시 간단한 구조로 다시 추가 예정