- 자재 리비전간 비교 기능 추가 (MaterialComparisonPage) - 버그 해결 필요 - 리비전간 추가 구매 필요 자재 분석 페이지 추가 (RevisionPurchasePage) - 자재 비교 결과 컴포넌트 구현 (MaterialComparisonResult) - 자재 비교 API 라우터 추가 (material_comparison.py) - 로직 개선 필요 - 자재 비교 시스템 데이터베이스 스키마 추가 - FileManager, FileUpload 컴포넌트 개선 - BOMManagerPage 제거 및 새로운 구조로 리팩토링 - 자재 분류기 및 스키마 개선 TODO: 자재 비교 알고리즘 정확도 향상 및 예외 처리 강화 필요
243 lines
8.0 KiB
PL/PgSQL
243 lines
8.0 KiB
PL/PgSQL
-- 자재 비교 및 발주 추적 시스템
|
|
-- 실행일: 2025.01.22
|
|
|
|
-- ================================
|
|
-- 1. materials 테이블에 해시 컬럼 추가
|
|
-- ================================
|
|
|
|
-- 자재 비교를 위한 해시 컬럼 추가
|
|
ALTER TABLE materials ADD COLUMN IF NOT EXISTS material_hash VARCHAR(32);
|
|
ALTER TABLE materials ADD COLUMN IF NOT EXISTS normalized_description TEXT;
|
|
|
|
-- 해시 인덱스 추가 (성능 최적화)
|
|
CREATE INDEX IF NOT EXISTS idx_materials_hash ON materials(material_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_materials_file_hash ON materials(file_id, material_hash);
|
|
|
|
-- ================================
|
|
-- 2. 자재 비교 결과 저장 테이블
|
|
-- ================================
|
|
|
|
CREATE TABLE IF NOT EXISTS material_revisions_comparison (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
-- 비교 기본 정보
|
|
job_no VARCHAR(50) NOT NULL,
|
|
current_revision VARCHAR(20) NOT NULL,
|
|
previous_revision VARCHAR(20) NOT NULL,
|
|
current_file_id INTEGER NOT NULL,
|
|
previous_file_id INTEGER NOT NULL,
|
|
|
|
-- 비교 결과 요약
|
|
total_current_items INTEGER DEFAULT 0,
|
|
total_previous_items INTEGER DEFAULT 0,
|
|
new_items_count INTEGER DEFAULT 0,
|
|
modified_items_count INTEGER DEFAULT 0,
|
|
removed_items_count INTEGER DEFAULT 0,
|
|
unchanged_items_count INTEGER DEFAULT 0,
|
|
|
|
-- 상세 결과 (JSON)
|
|
comparison_details JSONB,
|
|
|
|
-- 관리 정보
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
created_by VARCHAR(100),
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (current_file_id) REFERENCES files(id),
|
|
FOREIGN KEY (previous_file_id) REFERENCES files(id),
|
|
|
|
-- 유니크 제약 (같은 비교는 한 번만)
|
|
UNIQUE(job_no, current_revision, previous_revision)
|
|
);
|
|
|
|
-- ================================
|
|
-- 3. 개별 자재 비교 상세 테이블
|
|
-- ================================
|
|
|
|
CREATE TABLE IF NOT EXISTS material_comparison_details (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
comparison_id INTEGER NOT NULL,
|
|
material_hash VARCHAR(32) NOT NULL,
|
|
|
|
-- 비교 타입
|
|
change_type VARCHAR(20) NOT NULL, -- 'NEW', 'MODIFIED', 'REMOVED', 'UNCHANGED'
|
|
|
|
-- 자재 정보
|
|
description TEXT NOT NULL,
|
|
size_spec VARCHAR(100),
|
|
material_grade VARCHAR(100),
|
|
|
|
-- 수량 비교
|
|
previous_quantity DECIMAL(10,3) DEFAULT 0,
|
|
current_quantity DECIMAL(10,3) DEFAULT 0,
|
|
quantity_diff DECIMAL(10,3) DEFAULT 0,
|
|
|
|
-- 추가 구매 필요량 (핵심!)
|
|
additional_purchase_needed DECIMAL(10,3) DEFAULT 0,
|
|
|
|
-- 분류 정보
|
|
classified_category VARCHAR(50),
|
|
classification_confidence DECIMAL(3,2),
|
|
|
|
-- 관리 정보
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (comparison_id) REFERENCES material_revisions_comparison(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- ================================
|
|
-- 4. 발주 추적 테이블 (실제 발주 관리)
|
|
-- ================================
|
|
|
|
CREATE TABLE IF NOT EXISTS material_purchase_tracking (
|
|
id SERIAL PRIMARY KEY,
|
|
|
|
-- 연결 정보
|
|
job_no VARCHAR(50) NOT NULL,
|
|
material_hash VARCHAR(32) NOT NULL,
|
|
revision VARCHAR(20) NOT NULL,
|
|
|
|
-- 자재 정보
|
|
description TEXT NOT NULL,
|
|
size_spec VARCHAR(100),
|
|
unit VARCHAR(10) DEFAULT 'EA',
|
|
|
|
-- 수량 정보
|
|
bom_quantity DECIMAL(10,3) NOT NULL, -- BOM상 필요 수량
|
|
safety_margin DECIMAL(3,2) DEFAULT 1.10, -- 여유율 (10%)
|
|
calculated_quantity DECIMAL(10,3) NOT NULL, -- 계산된 구매 수량
|
|
|
|
-- 발주 상태
|
|
purchase_status VARCHAR(20) DEFAULT 'PENDING', -- 'PENDING', 'CONFIRMED', 'ORDERED', 'RECEIVED'
|
|
confirmed_quantity DECIMAL(10,3) DEFAULT 0, -- 확정된 발주 수량
|
|
ordered_quantity DECIMAL(10,3) DEFAULT 0, -- 실제 주문 수량
|
|
received_quantity DECIMAL(10,3) DEFAULT 0, -- 입고 수량
|
|
|
|
-- 발주 정보
|
|
purchase_order_no VARCHAR(100),
|
|
supplier_name VARCHAR(200),
|
|
unit_price DECIMAL(10,2),
|
|
total_price DECIMAL(12,2),
|
|
order_date DATE,
|
|
delivery_date DATE,
|
|
|
|
-- 관리 정보
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
confirmed_by VARCHAR(100),
|
|
confirmed_at TIMESTAMP,
|
|
|
|
-- 외래키
|
|
FOREIGN KEY (job_no) REFERENCES jobs(job_no),
|
|
|
|
-- 유니크 제약
|
|
UNIQUE(job_no, material_hash, revision)
|
|
);
|
|
|
|
-- ================================
|
|
-- 5. 누적 재고 현황 뷰
|
|
-- ================================
|
|
|
|
CREATE OR REPLACE VIEW material_inventory_status AS
|
|
SELECT
|
|
mpt.job_no,
|
|
mpt.material_hash,
|
|
mpt.description,
|
|
mpt.size_spec,
|
|
mpt.unit,
|
|
|
|
-- 누적 수량
|
|
SUM(mpt.confirmed_quantity) as total_confirmed,
|
|
SUM(mpt.ordered_quantity) as total_ordered,
|
|
SUM(mpt.received_quantity) as total_received,
|
|
|
|
-- 현재 가용 재고
|
|
SUM(mpt.received_quantity) as available_stock,
|
|
|
|
-- 최신 리비전 정보
|
|
MAX(mpt.revision) as latest_revision,
|
|
MAX(mpt.updated_at) as last_updated
|
|
|
|
FROM material_purchase_tracking mpt
|
|
WHERE mpt.purchase_status != 'CANCELLED'
|
|
GROUP BY mpt.job_no, mpt.material_hash, mpt.description, mpt.size_spec, mpt.unit;
|
|
|
|
-- ================================
|
|
-- 6. 인덱스 생성
|
|
-- ================================
|
|
|
|
-- material_revisions_comparison 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_material_revisions_job ON material_revisions_comparison(job_no);
|
|
CREATE INDEX IF NOT EXISTS idx_material_revisions_current ON material_revisions_comparison(current_revision);
|
|
|
|
-- material_comparison_details 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_material_comparison_hash ON material_comparison_details(material_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_material_comparison_type ON material_comparison_details(change_type);
|
|
|
|
-- material_purchase_tracking 인덱스
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_tracking_job_hash ON material_purchase_tracking(job_no, material_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_tracking_status ON material_purchase_tracking(purchase_status);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_tracking_revision ON material_purchase_tracking(revision);
|
|
|
|
-- ================================
|
|
-- 7. 해시 생성 함수 (PostgreSQL)
|
|
-- ================================
|
|
|
|
CREATE OR REPLACE FUNCTION generate_material_hash(
|
|
description TEXT,
|
|
size_spec TEXT DEFAULT '',
|
|
material_grade TEXT DEFAULT ''
|
|
) RETURNS VARCHAR(32) AS $$
|
|
BEGIN
|
|
-- 정규화: 대소문자 통일, 공백 정리
|
|
description := UPPER(TRIM(REGEXP_REPLACE(description, '\s+', ' ', 'g')));
|
|
size_spec := UPPER(TRIM(COALESCE(size_spec, '')));
|
|
material_grade := UPPER(TRIM(COALESCE(material_grade, '')));
|
|
|
|
-- MD5 해시 생성 (32자리)
|
|
RETURN MD5(description || '|' || size_spec || '|' || material_grade);
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- ================================
|
|
-- 8. 기존 데이터에 해시 생성 (배치 처리)
|
|
-- ================================
|
|
|
|
-- 기존 materials 데이터에 해시 추가
|
|
UPDATE materials
|
|
SET
|
|
material_hash = generate_material_hash(original_description, size_spec, material_grade),
|
|
normalized_description = UPPER(TRIM(REGEXP_REPLACE(original_description, '\s+', ' ', 'g')))
|
|
WHERE material_hash IS NULL;
|
|
|
|
-- ================================
|
|
-- 9. 트리거 생성 (자동 해시 생성)
|
|
-- ================================
|
|
|
|
CREATE OR REPLACE FUNCTION auto_generate_material_hash()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
-- 새로 삽입되거나 업데이트될 때 자동으로 해시 생성
|
|
NEW.material_hash := generate_material_hash(
|
|
NEW.original_description,
|
|
NEW.size_spec,
|
|
NEW.material_grade
|
|
);
|
|
NEW.normalized_description := UPPER(TRIM(REGEXP_REPLACE(NEW.original_description, '\s+', ' ', 'g')));
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER trigger_auto_material_hash
|
|
BEFORE INSERT OR UPDATE ON materials
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION auto_generate_material_hash();
|
|
|
|
-- ================================
|
|
-- 10. 완료 메시지
|
|
-- ================================
|
|
|
|
SELECT 'Material comparison and purchase tracking system created successfully!' as status; |