docs: 5130 레거시 분석 문서 및 기존 문서 초기 커밋
- 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON) - MES 프로젝트 문서 - API/프론트엔드 스펙 문서 - 가이드 및 레퍼런스 문서
This commit is contained in:
110
projects/legacy-5130/00_OVERVIEW.md
Normal file
110
projects/legacy-5130/00_OVERVIEW.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# 5130 프로젝트 분석 개요
|
||||
|
||||
## 문서 정보
|
||||
- **분석일**: 2025-12-04
|
||||
- **분석자**: Claude Code
|
||||
- **목적**: SAM 시스템으로 마이그레이션을 위한 5130 레거시 시스템 분석
|
||||
|
||||
## 프로젝트 개요
|
||||
|
||||
### 시스템 정보
|
||||
- **프로젝트명**: 5130 (주일/경동 통합정보시스템)
|
||||
- **기술 스택**: PHP (레거시), MySQL, Bootstrap 3.x
|
||||
- **URL**: https://5130.co.kr
|
||||
- **DB명**: `chandj` (기본값, 세션으로 동적 변경 가능)
|
||||
|
||||
### 멀티테넌시 구조
|
||||
```php
|
||||
// session.php
|
||||
$DB = isset($_SESSION["DB"]) ? $_SESSION["DB"] : 'chandj';
|
||||
$mycompany = $_SESSION["mycompany"] ?? ''; // 회사: 주일, 경동
|
||||
$mypart = $_SESSION["mypart"] ?? ''; // 부서
|
||||
$authority = $_SESSION["authority"] ?? ''; // 권한: ACCOUNT 등
|
||||
```
|
||||
|
||||
## 도메인 구조
|
||||
|
||||
### 1. 자재/재고 (Material/Instock)
|
||||
- **디렉토리**: `/instock/`
|
||||
- **주요 테이블**: `i_*` (자재 유형별 테이블)
|
||||
- **기능**: LOT 관리, 입고 검사, 자재 추적
|
||||
|
||||
### 2. 품목/모델 (Product/Model)
|
||||
- **디렉토리**: `/models/`
|
||||
- **주요 테이블**: `models`, `parts`, `parts_sub`
|
||||
- **기능**: 제품 모델 정의, BOM 관리, 단가 관리
|
||||
|
||||
### 3. 견적 (Estimate)
|
||||
- **디렉토리**: `/estimate/`
|
||||
- **주요 테이블**: `estimate` (동적 테이블명)
|
||||
- **기능**: 견적서 작성, 단가 계산, 견적 이력
|
||||
|
||||
### 4. 생산/공사 (Production/Work)
|
||||
- **디렉토리**: `/make/`, `/work/`
|
||||
- **주요 테이블**: `work`, `make_*`
|
||||
- **기능**: 공사 관리, 생산 지시, 작업 진행 추적
|
||||
|
||||
### 5. 출하 (Shipping/Output)
|
||||
- **디렉토리**: `/output/`
|
||||
- **주요 테이블**: `output`, `output_extra`
|
||||
- **기능**: 출하 관리, 배송 추적, 인정검사(ACI)
|
||||
|
||||
### 6. 품질/AS (Quality/After Service)
|
||||
- **디렉토리**: `/as/`
|
||||
- **주요 테이블**: `work` (AS 관련 컬럼)
|
||||
- **기능**: AS 접수, 처리 현황, 보증 관리
|
||||
|
||||
### 7. 회계 (Accounting)
|
||||
- **디렉토리**: `/account/`, `/account_plan/`
|
||||
- **주요 테이블**: `account`
|
||||
- **기능**: 입출금 관리, 미수금, 전자세금계산서
|
||||
|
||||
## 공통 패턴
|
||||
|
||||
### 파일 구조
|
||||
```
|
||||
/도메인/
|
||||
├── _request.php # 요청 파라미터 정의
|
||||
├── _row.php # 행 데이터 렌더링
|
||||
├── insert.php # 데이터 INSERT/UPDATE/DELETE
|
||||
├── list.php # 목록 조회
|
||||
├── write_form.php # 등록/수정 폼
|
||||
├── view.php # 상세 조회
|
||||
└── common/ # 도메인별 공통 모듈
|
||||
```
|
||||
|
||||
### DB 공통 컬럼
|
||||
- `num`: PK (AUTO_INCREMENT)
|
||||
- `is_deleted`: 소프트 삭제 플래그 (0/1)
|
||||
- `update_log`: 수정 이력 (날짜 + 사용자명)
|
||||
- `searchtag`: 검색용 통합 텍스트
|
||||
|
||||
### JSON 데이터 저장 패턴
|
||||
- 복잡한 리스트 데이터는 JSON 문자열로 저장
|
||||
- 예: `estimateList`, `screenlist`, `slatlist`, `accountList`
|
||||
|
||||
## SAM 마이그레이션 고려사항
|
||||
|
||||
### 멀티테넌시
|
||||
- 5130: DB명 분리 방식 (`chandj.테이블`)
|
||||
- SAM: `tenant_id` 컬럼 기반 분리
|
||||
|
||||
### 데이터 구조 개선
|
||||
1. JSON 필드 → 정규화된 관계 테이블
|
||||
2. 동적 테이블명 → 고정 테이블 + 타입 컬럼
|
||||
3. 검색태그 → Full-Text Search 또는 Elasticsearch
|
||||
|
||||
### 코드 현대화
|
||||
1. 레거시 PHP → Laravel 12
|
||||
2. 직접 SQL → Eloquent ORM
|
||||
3. jQuery → React/Next.js
|
||||
|
||||
## 관련 문서
|
||||
- [01_MATERIAL.md](./01_MATERIAL.md) - 자재/재고 분석
|
||||
- [02_PRODUCT.md](./02_PRODUCT.md) - 품목/모델 분석
|
||||
- [03_ESTIMATE.md](./03_ESTIMATE.md) - 견적 분석
|
||||
- [04_PRODUCTION.md](./04_PRODUCTION.md) - 생산 분석
|
||||
- [05_SHIPPING.md](./05_SHIPPING.md) - 출하 분석
|
||||
- [06_QUALITY.md](./06_QUALITY.md) - 품질/AS 분석
|
||||
- [07_ACCOUNTING.md](./07_ACCOUNTING.md) - 회계 분석
|
||||
- [08_SAM_COMPARISON.md](./08_SAM_COMPARISON.md) - SAM 비교 검증
|
||||
202
projects/legacy-5130/01_MATERIAL.md
Normal file
202
projects/legacy-5130/01_MATERIAL.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# 자재/재고 (Material/Instock) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/instock/`
|
||||
- **DB 테이블**: 자재 유형별 개별 테이블 (i_* 패턴)
|
||||
- **주요 기능**: LOT 관리, 입고 검사, 자재 추적, 재고 관리
|
||||
|
||||
## 디렉토리 구조
|
||||
```
|
||||
/instock/
|
||||
├── _request.php # 요청 파라미터 정의
|
||||
├── _row.php # 행 렌더링
|
||||
├── insert.php # 데이터 저장
|
||||
├── list.php # 자재 목록
|
||||
├── list_sheet.php # 시트 형태 목록
|
||||
├── statistics.php # 통계
|
||||
├── i_*.php # 자재 유형별 입력 폼 (23개)
|
||||
│ ├── i_EGI155.php # EGI155 자재
|
||||
│ ├── i_GIplate.php # GI 판재
|
||||
│ ├── i_SUSplate.php # SUS 판재
|
||||
│ ├── i_SUScoil.php # SUS 코일
|
||||
│ ├── i_angle.php # 앵글
|
||||
│ ├── i_anglebottom.php # 앵글 바텀
|
||||
│ ├── i_antifireglass.php # 방화 유리
|
||||
│ ├── i_bendingcoil.php # 벤딩 코일
|
||||
│ ├── i_bracket.php # 브라켓
|
||||
│ ├── i_cerakwool.php # 세락울
|
||||
│ ├── i_controller.php # 컨트롤러
|
||||
│ ├── i_fiber.php # 파이버
|
||||
│ ├── i_fireproofWire.php # 방화 와이어
|
||||
│ ├── i_motor.php # 모터
|
||||
│ ├── i_platesteel.php # 판강
|
||||
│ ├── i_pole.php # 폴
|
||||
│ ├── i_recpipe.php # 각관
|
||||
│ ├── i_shaft.php # 샤프트
|
||||
│ ├── i_sillica.php # 실리카
|
||||
│ ├── i_slatcoil.php # 슬랫 코일
|
||||
│ ├── i_wire.php # 와이어
|
||||
│ ├── i_wireDaehan.php # 대한 와이어
|
||||
│ └── i_Fireproof_sealings.php # 방화 씰링
|
||||
├── fetch_*.php # AJAX 데이터 조회
|
||||
└── common/ # 공통 모듈
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### 자재 공통 테이블 구조
|
||||
```sql
|
||||
CREATE TABLE i_[자재유형] (
|
||||
num INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- LOT 정보
|
||||
lot_no VARCHAR(50), -- LOT 번호
|
||||
inspection_date DATE, -- 검사일
|
||||
lotDone DATE, -- LOT 완료일
|
||||
|
||||
-- 공급업체 정보
|
||||
supplier VARCHAR(100), -- 공급업체
|
||||
manufacturer VARCHAR(100), -- 제조사
|
||||
|
||||
-- 자재 정보
|
||||
item_name VARCHAR(200), -- 품명
|
||||
specification VARCHAR(200), -- 규격
|
||||
unit VARCHAR(20), -- 단위
|
||||
prodcode VARCHAR(50), -- 제품코드
|
||||
|
||||
-- 수량/가격 정보
|
||||
received_qty DECIMAL(15,2), -- 입고수량
|
||||
weight_kg DECIMAL(15,2), -- 중량(kg)
|
||||
purchase_price_excl_vat DECIMAL(15,0), -- 구매단가(부가세 제외)
|
||||
|
||||
-- 참조/이력
|
||||
material_no VARCHAR(50), -- 자재번호
|
||||
remarks TEXT, -- 비고
|
||||
|
||||
-- 시스템 필드
|
||||
searchtag TEXT, -- 검색태그 (자동생성)
|
||||
update_log TEXT, -- 수정이력
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
INDEX idx_lot_no (lot_no),
|
||||
INDEX idx_supplier (supplier),
|
||||
INDEX idx_item_name (item_name)
|
||||
);
|
||||
```
|
||||
|
||||
### 검색태그 생성 로직
|
||||
```php
|
||||
// insert.php에서 searchtag 자동 생성
|
||||
$searchtag = $lot_no . ' ' .
|
||||
$inspection_date . ' ' .
|
||||
$supplier . ' ' .
|
||||
$item_name . ' ' .
|
||||
$specification . ' ' .
|
||||
$unit . ' ' .
|
||||
$received_qty . ' ' .
|
||||
$material_no . ' ' .
|
||||
$manufacturer . ' ' .
|
||||
$purchase_price_excl_vat . ' ' .
|
||||
$weight_kg . ' ' .
|
||||
$lotDone . ' ' .
|
||||
$prodcode . ' ' .
|
||||
$remarks;
|
||||
```
|
||||
|
||||
## 자재 유형별 특성
|
||||
|
||||
### 1. 코일 자재
|
||||
- **테이블**: `i_SUScoil`, `i_bendingcoil`, `i_slatcoil`
|
||||
- **특징**: 중량(kg) 기반 재고 관리
|
||||
- **추가 컬럼**: 두께, 폭, 소재
|
||||
|
||||
### 2. 판재 자재
|
||||
- **테이블**: `i_GIplate`, `i_SUSplate`, `i_platesteel`
|
||||
- **특징**: 면적(m²) 또는 장 단위 관리
|
||||
- **추가 컬럼**: 가로, 세로, 두께
|
||||
|
||||
### 3. 부품 자재
|
||||
- **테이블**: `i_motor`, `i_controller`, `i_bracket`
|
||||
- **특징**: 개수 단위 관리, 모델별 구분
|
||||
- **추가 컬럼**: 모델명, 제조번호
|
||||
|
||||
### 4. 구조재
|
||||
- **테이블**: `i_angle`, `i_pole`, `i_shaft`, `i_recpipe`
|
||||
- **특징**: 길이(m) 단위 관리
|
||||
- **추가 컬럼**: 길이, 단면규격
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### LOT 관리
|
||||
1. **LOT 번호 생성**: `lotnum_generator.php`
|
||||
2. **LOT 완료 처리**: `lotDone` 날짜 설정
|
||||
3. **LOT 추적**: 출하 시 LOT 번호 연결
|
||||
|
||||
### 입고 검사
|
||||
1. 자재 입고 시 검사일(`inspection_date`) 기록
|
||||
2. 합격 시 재고에 반영
|
||||
3. 불합격 시 반품 처리
|
||||
|
||||
### 가격 관리
|
||||
- 구매단가는 부가세 제외 금액 저장
|
||||
- 환율/원자재 가격 변동 반영 필요
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. 테이블 통합
|
||||
```sql
|
||||
-- 5130: 자재 유형별 개별 테이블
|
||||
i_SUSplate, i_GIplate, i_motor, ...
|
||||
|
||||
-- SAM: 단일 테이블 + 카테고리
|
||||
materials (
|
||||
id,
|
||||
tenant_id,
|
||||
category_id, -- categories 테이블 참조
|
||||
lot_no,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 카테고리 계층화
|
||||
```sql
|
||||
-- SAM: 4단계 카테고리 구조
|
||||
material_categories (
|
||||
id,
|
||||
parent_id,
|
||||
name,
|
||||
level, -- 1: 대분류, 2: 중분류, 3: 소분류, 4: 세분류
|
||||
attributes JSON -- 카테고리별 추가 속성 정의
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 속성 동적 관리
|
||||
```sql
|
||||
-- SAM: 카테고리별 동적 속성
|
||||
material_attributes (
|
||||
material_id,
|
||||
attribute_key,
|
||||
attribute_value,
|
||||
attribute_type -- string, number, date, etc.
|
||||
)
|
||||
```
|
||||
|
||||
### 4. LOT 추적 강화
|
||||
```sql
|
||||
-- SAM: LOT 이력 테이블
|
||||
lot_histories (
|
||||
id,
|
||||
lot_id,
|
||||
action, -- created, inspected, used, returned
|
||||
quantity,
|
||||
reference_type, -- output, production
|
||||
reference_id,
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
## 관련 파일 참조
|
||||
- `/instock/insert.php` - INSERT/UPDATE 로직
|
||||
- `/instock/_request.php` - 요청 파라미터 정의
|
||||
- `/instock/list.php` - 목록 조회 쿼리
|
||||
- `/instock/fetch_inspection.php` - 검사 데이터 조회
|
||||
250
projects/legacy-5130/02_PRODUCT.md
Normal file
250
projects/legacy-5130/02_PRODUCT.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# 품목/모델 (Product/Model) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/models/`
|
||||
- **DB 테이블**: `models`, `parts`, `parts_sub`
|
||||
- **주요 기능**: 제품 모델 정의, BOM(Bill of Materials) 관리, 단가 계산
|
||||
|
||||
## 디렉토리 구조
|
||||
```
|
||||
/models/
|
||||
├── _request.php # 요청 파라미터
|
||||
├── _row.php # 행 렌더링
|
||||
├── _part_row.php # 부품 행 렌더링
|
||||
├── _part_sub_row.php # 하위 부품 행 렌더링
|
||||
├── insert.php # 모델/부품 저장
|
||||
├── list.php # 모델 목록
|
||||
├── write_form.php # 모델 등록/수정 폼
|
||||
├── modelslist.php # 모델 리스트 조회
|
||||
├── itemlist.php # 아이템 리스트
|
||||
├── sub_table.php # 하위 부품 테이블
|
||||
├── basic_model.php # 기본 모델 설정
|
||||
├── models.json # 모델 JSON 데이터
|
||||
└── items.json # 아이템 JSON 데이터
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### 1. models 테이블 (모델 마스터)
|
||||
```sql
|
||||
CREATE TABLE models (
|
||||
model_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
model_name VARCHAR(100), -- 모델명
|
||||
major_category VARCHAR(50), -- 대분류 (슬랫, 스크린 등)
|
||||
finishing_type VARCHAR(50), -- 마감 유형
|
||||
description TEXT, -- 설명
|
||||
guiderail_type VARCHAR(50), -- 가이드레일 유형
|
||||
update_log TEXT, -- 수정이력
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
INDEX idx_model_name (model_name),
|
||||
INDEX idx_major_category (major_category)
|
||||
);
|
||||
```
|
||||
|
||||
### 2. parts 테이블 (부품 - 2단계)
|
||||
```sql
|
||||
CREATE TABLE parts (
|
||||
part_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
model_id INT, -- 부모 모델 ID
|
||||
part_name VARCHAR(100), -- 부품명
|
||||
spec VARCHAR(100), -- 규격
|
||||
unit VARCHAR(20), -- 단위
|
||||
quantity DECIMAL(10,2), -- 수량
|
||||
unitprice DECIMAL(15,0), -- 단가
|
||||
memo TEXT, -- 메모
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
FOREIGN KEY (model_id) REFERENCES models(model_id),
|
||||
INDEX idx_model_id (model_id)
|
||||
);
|
||||
```
|
||||
|
||||
### 3. parts_sub 테이블 (하위 부품 - 3단계)
|
||||
```sql
|
||||
CREATE TABLE parts_sub (
|
||||
subpart_id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
part_id INT, -- 부모 부품 ID
|
||||
subpart_name VARCHAR(100), -- 하위 부품명
|
||||
material VARCHAR(100), -- 소재
|
||||
|
||||
-- 가격 계산 필드
|
||||
bendSum DECIMAL(15,0), -- 벤딩 합계
|
||||
plateSum DECIMAL(15,0), -- 판재 합계
|
||||
finalSum DECIMAL(15,0), -- 최종 합계
|
||||
unitPrice DECIMAL(15,0), -- 단가
|
||||
computedPrice DECIMAL(15,0), -- 계산 가격
|
||||
quantity DECIMAL(10,2), -- 수량
|
||||
lineTotal DECIMAL(15,0), -- 행 합계
|
||||
|
||||
image_url VARCHAR(500), -- 이미지 URL
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
FOREIGN KEY (part_id) REFERENCES parts(part_id),
|
||||
INDEX idx_part_id (part_id)
|
||||
);
|
||||
```
|
||||
|
||||
## 계층 구조
|
||||
|
||||
```
|
||||
models (모델)
|
||||
└── parts (부품)
|
||||
└── parts_sub (하위 부품)
|
||||
|
||||
예시:
|
||||
├── KD-SLAT-001 (슬랫 모델)
|
||||
│ ├── 가이드레일 (부품)
|
||||
│ │ ├── 상부 브라켓 (하위 부품)
|
||||
│ │ ├── 하부 브라켓 (하위 부품)
|
||||
│ │ └── 레일 바디 (하위 부품)
|
||||
│ ├── 슬랫 본체 (부품)
|
||||
│ │ ├── 슬랫 코일 (하위 부품)
|
||||
│ │ └── 인터락 (하위 부품)
|
||||
│ └── 구동부 (부품)
|
||||
│ ├── 모터 (하위 부품)
|
||||
│ └── 샤프트 (하위 부품)
|
||||
```
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### 모델 관리 (insert.php)
|
||||
```php
|
||||
// 1단계: 모델 저장
|
||||
if ($mode == "insert") {
|
||||
$sql = "INSERT INTO models (model_name, major_category, finishing_type,
|
||||
description, update_log, guiderail_type) VALUES (?, ?, ?, ?, ?, ?)";
|
||||
}
|
||||
|
||||
// 2단계: 부품 저장 (배열 처리)
|
||||
if(isset($_POST['part_name']) && is_array($_POST['part_name'])) {
|
||||
// 기존 부품과 비교하여 삭제된 부품 처리
|
||||
// 신규 부품 INSERT, 기존 부품 UPDATE
|
||||
}
|
||||
|
||||
// 3단계: 하위 부품 저장
|
||||
if(isset($_POST['subpart_name']) && is_array($_POST['subpart_name'])) {
|
||||
// parent_part_id로 부모 부품과 연결
|
||||
}
|
||||
```
|
||||
|
||||
### 복사 기능
|
||||
```php
|
||||
// 모델 복사 시 하위 구조 전체 복사
|
||||
if ($mode == "copy") {
|
||||
// 1. 모델 복사 → 새 model_id
|
||||
// 2. 부품 복사 → partMapping (old_id → new_id)
|
||||
// 3. 하위 부품 복사 → partMapping 기반 parent_id 변환
|
||||
}
|
||||
```
|
||||
|
||||
### 가격 계산
|
||||
- `bendSum`: 벤딩 공정 비용 합계
|
||||
- `plateSum`: 판재 비용 합계
|
||||
- `finalSum`: bendSum + plateSum
|
||||
- `computedPrice`: 추가 가공비 포함
|
||||
- `lineTotal`: unitPrice × quantity
|
||||
|
||||
## 관련 JSON 데이터
|
||||
|
||||
### models.json
|
||||
```json
|
||||
[
|
||||
{
|
||||
"model_name": "KD-SLAT-001",
|
||||
"slatitem": "슬랫",
|
||||
"pair": "single"
|
||||
},
|
||||
{
|
||||
"model_name": "KD-SCREEN-001",
|
||||
"slatitem": "스크린",
|
||||
"pair": "double"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### items.json
|
||||
```json
|
||||
[
|
||||
{
|
||||
"item_code": "ITM001",
|
||||
"item_name": "가이드레일 A형",
|
||||
"category": "가이드레일"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 관련 디렉토리
|
||||
|
||||
### 단가 관리 디렉토리
|
||||
```
|
||||
/price_angle/ # 앵글 단가
|
||||
/price_bend/ # 벤딩 단가
|
||||
/price_motor/ # 모터 단가
|
||||
/price_pipe/ # 파이프 단가
|
||||
/price_pole/ # 폴 단가
|
||||
/price_raw_materials/ # 원자재 단가
|
||||
/price_screenplate/ # 스크린판 단가
|
||||
/price_shaft/ # 샤프트 단가
|
||||
/price_smokeban/ # 연기차단 단가
|
||||
```
|
||||
|
||||
### 벤딩/가공 관련
|
||||
```
|
||||
/bending/ # 벤딩 작업
|
||||
/bendingfee/ # 벤딩 비용
|
||||
/bendingmap/ # 벤딩 맵
|
||||
/etcbending/ # 기타 벤딩
|
||||
```
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. BOM 구조 개선
|
||||
```sql
|
||||
-- SAM: 재귀적 BOM 구조
|
||||
bom_items (
|
||||
id,
|
||||
tenant_id,
|
||||
parent_id, -- NULL이면 최상위 모델
|
||||
item_type, -- model, assembly, part, material
|
||||
item_code,
|
||||
item_name,
|
||||
quantity,
|
||||
unit_price,
|
||||
level, -- BOM 레벨 (1, 2, 3, ...)
|
||||
sort_order
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 가격 계산 분리
|
||||
```sql
|
||||
-- SAM: 가격 계산 이력 관리
|
||||
price_calculations (
|
||||
id,
|
||||
bom_item_id,
|
||||
calculation_type, -- bending, material, labor
|
||||
base_price,
|
||||
markup_rate,
|
||||
final_price,
|
||||
effective_from,
|
||||
effective_to
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 버전 관리
|
||||
```sql
|
||||
-- SAM: 모델 버전 관리
|
||||
model_versions (
|
||||
id,
|
||||
model_id,
|
||||
version,
|
||||
snapshot JSON, -- BOM 스냅샷
|
||||
created_at,
|
||||
created_by
|
||||
)
|
||||
```
|
||||
|
||||
## 참고 파일
|
||||
- `/models/insert.php` - 3단계 계층 저장 로직
|
||||
- `/models/write_form.php` - BOM 편집 UI
|
||||
- `/common.php:selectModel()` - 모델 선택 헬퍼 함수
|
||||
289
projects/legacy-5130/03_ESTIMATE.md
Normal file
289
projects/legacy-5130/03_ESTIMATE.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# 견적 (Estimate) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/estimate/`
|
||||
- **DB 테이블**: `estimate` (동적 테이블명 가능)
|
||||
- **주요 기능**: 견적서 작성, 단가 자동계산, 견적 이력 관리
|
||||
|
||||
## 디렉토리 구조
|
||||
```
|
||||
/estimate/
|
||||
├── _request.php # 요청 파라미터
|
||||
├── _row.php # 행 렌더링
|
||||
├── insert.php # 견적 저장
|
||||
├── list.php # 견적 목록
|
||||
├── list_unit.php # 단가 목록
|
||||
├── write_form.php # 견적서 작성 폼 (103KB)
|
||||
├── edit.php # 견적 수정
|
||||
├── edit_slat.php # 슬랫 견적 수정
|
||||
├── estimate.php # 견적서 메인
|
||||
├── estimateSlat.php # 슬랫 견적
|
||||
├── estimateUnit.php # 단가 견적
|
||||
├── view.php # 견적 상세
|
||||
├── viewEstimate.php # 견적서 보기
|
||||
├── viewEstimateDetail.php # 견적 상세 보기
|
||||
├── statistics.php # 견적 통계
|
||||
├── fetch_unitprice.php # 단가 조회 (32KB)
|
||||
├── get_estimate_amount.php # 견적 금액 계산
|
||||
├── get_screen_amount.php # 스크린 금액 계산
|
||||
├── get_slat_amount.php # 슬랫 금액 계산
|
||||
├── generate_serial_pjnum.php # 프로젝트 번호 생성
|
||||
├── screen_view_*.php # 스크린 견적 뷰
|
||||
├── slat_view_*.php # 슬랫 견적 뷰
|
||||
└── common/ # 공통 모듈
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### estimate 테이블
|
||||
```sql
|
||||
CREATE TABLE estimate (
|
||||
num INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- 기본 정보
|
||||
pjnum VARCHAR(50), -- 프로젝트 번호 (KD-PR-YYMMDD-NN)
|
||||
indate DATE, -- 등록일
|
||||
orderman VARCHAR(50), -- 담당자
|
||||
outworkplace VARCHAR(200), -- 현장명/거래처
|
||||
|
||||
-- 분류 정보
|
||||
major_category VARCHAR(50), -- 대분류 (슬랫, 스크린)
|
||||
model_name VARCHAR(100), -- 모델명
|
||||
position VARCHAR(50), -- 위치
|
||||
|
||||
-- 규격 정보
|
||||
makeWidth INT, -- 제작 폭 (기본 160)
|
||||
makeHeight INT, -- 제작 높이 (기본 350)
|
||||
maguriWing VARCHAR(20), -- 마구리 윙 (기본 50)
|
||||
|
||||
-- 발주처 정보
|
||||
con_num VARCHAR(50), -- 계약번호
|
||||
secondord VARCHAR(100), -- 2차 발주처
|
||||
secondordman VARCHAR(50), -- 2차 담당자
|
||||
secondordmantel VARCHAR(20), -- 2차 담당자 연락처
|
||||
secondordnum VARCHAR(50), -- 2차 발주번호
|
||||
|
||||
-- 견적 상세 (JSON)
|
||||
estimateList TEXT, -- 스크린 견적 리스트 (JSON)
|
||||
estimateList_auto TEXT, -- 스크린 자동계산 리스트 (JSON)
|
||||
estimateSlatList TEXT, -- 슬랫 견적 리스트 (JSON)
|
||||
estimateSlatList_auto TEXT, -- 슬랫 자동계산 리스트 (JSON)
|
||||
|
||||
-- 금액 정보
|
||||
estimateTotal INT DEFAULT 0, -- 견적 총액
|
||||
EstimateFirstSum INT DEFAULT 0, -- 최초 견적 합계
|
||||
EstimateUpdatetSum INT DEFAULT 0, -- 수정 견적 합계
|
||||
EstimateDiffer INT DEFAULT 0, -- 차액
|
||||
estimateSurang INT DEFAULT 0, -- 수량
|
||||
|
||||
-- 할인 정보
|
||||
EstimateDiscountRate INT DEFAULT 0,-- 할인율
|
||||
EstimateDiscount INT DEFAULT 0, -- 할인금액
|
||||
EstimateFinalSum INT DEFAULT 0, -- 최종 금액
|
||||
|
||||
-- 검사비/부가정보
|
||||
inspectionFee INT DEFAULT 50000, -- 인정검사비
|
||||
steel VARCHAR(50), -- 강종
|
||||
motor VARCHAR(100), -- 모터
|
||||
warranty VARCHAR(100), -- 보증기간
|
||||
|
||||
-- 체크 플래그
|
||||
slatcheck VARCHAR(10), -- 슬랫 체크
|
||||
partscheck VARCHAR(10), -- 부품 체크
|
||||
|
||||
-- 시스템 필드
|
||||
comment TEXT, -- 비고
|
||||
update_log TEXT, -- 수정이력
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
INDEX idx_pjnum (pjnum),
|
||||
INDEX idx_outworkplace (outworkplace),
|
||||
INDEX idx_indate (indate)
|
||||
);
|
||||
```
|
||||
|
||||
## 견적 데이터 구조
|
||||
|
||||
### estimateList JSON 구조
|
||||
```json
|
||||
[
|
||||
{
|
||||
"item_name": "가이드레일",
|
||||
"specification": "A형 65×80",
|
||||
"unit": "EA",
|
||||
"quantity": 2,
|
||||
"unit_price": 150000,
|
||||
"amount": 300000,
|
||||
"remark": ""
|
||||
},
|
||||
{
|
||||
"item_name": "스크린 판넬",
|
||||
"specification": "1.0T × 1200W",
|
||||
"unit": "m²",
|
||||
"quantity": 24.5,
|
||||
"unit_price": 45000,
|
||||
"amount": 1102500,
|
||||
"remark": "SUS304"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### estimateList_auto JSON 구조
|
||||
```json
|
||||
[
|
||||
{
|
||||
"item_code": "AUTO001",
|
||||
"item_name": "벤딩 가공비",
|
||||
"calc_type": "per_meter",
|
||||
"base_value": 120.5,
|
||||
"unit_price": 2500,
|
||||
"amount": 301250
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### 프로젝트 번호 생성
|
||||
```php
|
||||
// generate_serial_pjnum.php
|
||||
function generatePjnum() {
|
||||
// 형식: KD-PR-YYMMDD-NN
|
||||
// KD: 경동
|
||||
// PR: 프로젝트
|
||||
// YYMMDD: 날짜
|
||||
// NN: 일련번호 (01~99)
|
||||
|
||||
$today = date('ymd');
|
||||
$prefix = "KD-PR-{$today}-";
|
||||
|
||||
// 오늘 날짜의 마지막 번호 조회
|
||||
$sql = "SELECT pjnum FROM estimate
|
||||
WHERE pjnum LIKE '{$prefix}%'
|
||||
ORDER BY pjnum DESC LIMIT 1";
|
||||
|
||||
// 일련번호 증가
|
||||
$nextNum = str_pad($lastNum + 1, 2, '0', STR_PAD_LEFT);
|
||||
|
||||
return $prefix . $nextNum;
|
||||
}
|
||||
```
|
||||
|
||||
### 금액 계산
|
||||
```php
|
||||
// insert.php
|
||||
$estimateTotal = intval(str_replace(',', '', $estimateTotal));
|
||||
$EstimateFirstSum = intval(str_replace(',', '', $EstimateFirstSum));
|
||||
$EstimateUpdatetSum = intval(str_replace(',', '', $EstimateUpdatetSum));
|
||||
$EstimateDiffer = intval(str_replace(',', '', $EstimateDiffer));
|
||||
$EstimateFinalSum = intval(str_replace(',', '', $EstimateFinalSum));
|
||||
```
|
||||
|
||||
### 단가 조회 (fetch_unitprice.php)
|
||||
- 모델별 기본 단가
|
||||
- 규격별 가격 가감
|
||||
- 강종(steel)별 가격 계수
|
||||
- 마진율 적용
|
||||
|
||||
## 견적 유형
|
||||
|
||||
### 1. 스크린 견적 (Screen)
|
||||
- **파일**: `estimate.php`, `screen_view_*.php`
|
||||
- **특징**: 면적(m²) 기반 계산
|
||||
- **주요 항목**: 판넬, 가이드레일, 브라켓
|
||||
|
||||
### 2. 슬랫 견적 (Slat)
|
||||
- **파일**: `estimateSlat.php`, `slat_view_*.php`
|
||||
- **특징**: 폭/높이 기반 계산
|
||||
- **주요 항목**: 슬랫 코일, 인터락, 샤프트
|
||||
|
||||
### 3. 단가 견적 (Unit)
|
||||
- **파일**: `estimateUnit.php`, `list_unit.php`
|
||||
- **특징**: 품목별 단가 설정
|
||||
|
||||
## 견적서 출력
|
||||
- `/estimate/print_list.php` - 견적 목록 인쇄
|
||||
- `/estimate/viewEstimate.php` - 견적서 보기
|
||||
- `/estimate/saveExcel.php` - 엑셀 저장
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. 견적 구조 개선
|
||||
```sql
|
||||
-- SAM: 견적 헤더/상세 분리
|
||||
estimates (
|
||||
id,
|
||||
tenant_id,
|
||||
estimate_number, -- 견적번호
|
||||
customer_id, -- 거래처
|
||||
project_name,
|
||||
estimate_date,
|
||||
valid_until, -- 유효기간
|
||||
status, -- draft, sent, accepted, rejected
|
||||
total_amount,
|
||||
discount_rate,
|
||||
discount_amount,
|
||||
final_amount,
|
||||
created_by
|
||||
)
|
||||
|
||||
estimate_items (
|
||||
id,
|
||||
estimate_id,
|
||||
item_type, -- manual, auto_calculated
|
||||
item_code,
|
||||
item_name,
|
||||
specification,
|
||||
unit,
|
||||
quantity,
|
||||
unit_price,
|
||||
amount,
|
||||
sort_order
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 단가표 관리
|
||||
```sql
|
||||
-- SAM: 단가 마스터
|
||||
price_masters (
|
||||
id,
|
||||
tenant_id,
|
||||
category_id,
|
||||
item_code,
|
||||
item_name,
|
||||
base_price,
|
||||
effective_from,
|
||||
effective_to,
|
||||
is_active
|
||||
)
|
||||
|
||||
-- SAM: 단가 조건
|
||||
price_conditions (
|
||||
id,
|
||||
price_master_id,
|
||||
condition_type, -- size, material, quantity
|
||||
condition_value,
|
||||
adjustment_type, -- fixed, percentage
|
||||
adjustment_value
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 견적 이력
|
||||
```sql
|
||||
-- SAM: 견적 버전 관리
|
||||
estimate_versions (
|
||||
id,
|
||||
estimate_id,
|
||||
version,
|
||||
snapshot JSON, -- 견적 전체 스냅샷
|
||||
changed_by,
|
||||
changed_at,
|
||||
change_reason
|
||||
)
|
||||
```
|
||||
|
||||
## 참고 파일
|
||||
- `/estimate/insert.php` - 저장 로직
|
||||
- `/estimate/write_form.php` - 견적서 UI (대용량 파일)
|
||||
- `/estimate/fetch_unitprice.php` - 단가 계산 로직
|
||||
- `/estimate/generate_serial_pjnum.php` - 번호 생성
|
||||
305
projects/legacy-5130/04_PRODUCTION.md
Normal file
305
projects/legacy-5130/04_PRODUCTION.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# 생산/공사 (Production/Work) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/make/`, `/work/`
|
||||
- **DB 테이블**: `work`, 동적 테이블 (`make_*`)
|
||||
- **주요 기능**: 공사 관리, 생산 지시, 작업 진행 추적
|
||||
|
||||
## 디렉토리 구조
|
||||
|
||||
### /make/ (생산 지시)
|
||||
```
|
||||
/make/
|
||||
├── _request.php # 요청 파라미터
|
||||
├── _row.php # 행 렌더링
|
||||
├── insert.php # 데이터 저장
|
||||
├── insert_new.php # 신규 저장
|
||||
├── list.php # 생산 목록
|
||||
├── write.php # 생산 지시 등록
|
||||
├── write_form.php # 생산 지시 폼 (37KB)
|
||||
├── print.php # 인쇄
|
||||
├── print_list.php # 목록 인쇄
|
||||
├── make.js # 자바스크립트 (22KB)
|
||||
├── get_check_done.php # 완료 체크
|
||||
├── get_screenlist.php # 스크린 목록
|
||||
├── update_checkbox.php # 체크박스 업데이트
|
||||
└── load*.php # 데이터 로드
|
||||
```
|
||||
|
||||
### /work/ (공사 관리)
|
||||
```
|
||||
/work/
|
||||
├── _request.php # 요청 파라미터 (91개 변수)
|
||||
├── _row.php # 행 렌더링
|
||||
├── insert.php # 데이터 저장
|
||||
├── list.php # 공사 목록
|
||||
├── write_form.php # 공사 등록 폼
|
||||
├── view.php # 공사 상세
|
||||
├── searchkd.php # 검색
|
||||
├── workerlist.php # 작업자 목록
|
||||
├── savefile.php # 파일 저장
|
||||
└── ...
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### work 테이블 (공사 마스터)
|
||||
```sql
|
||||
CREATE TABLE work (
|
||||
num INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- 공사 기본정보
|
||||
work_state VARCHAR(50), -- 공사상태
|
||||
workplacename VARCHAR(200), -- 현장명
|
||||
address TEXT, -- 현장주소
|
||||
chargedperson VARCHAR(50), -- 공사담당자
|
||||
|
||||
-- 발주처 정보 (1차)
|
||||
firstord VARCHAR(100), -- 1차 발주처 (건설사)
|
||||
firstordman VARCHAR(50), -- 1차 담당자
|
||||
firstordmantel VARCHAR(20), -- 1차 연락처
|
||||
|
||||
-- 발주처 정보 (2차)
|
||||
secondord VARCHAR(100), -- 2차 발주처 (시공사)
|
||||
secondordman VARCHAR(50), -- 2차 담당자
|
||||
secondordmantel VARCHAR(20), -- 2차 연락처
|
||||
|
||||
-- 작업 정보
|
||||
worklist TEXT, -- 작업 목록
|
||||
motormaker VARCHAR(100), -- 모터 제조사
|
||||
power VARCHAR(50), -- 전원
|
||||
|
||||
-- 일정 정보
|
||||
workday DATE, -- 시공 시작일
|
||||
endworkday DATE, -- 시공 완료일
|
||||
cableday DATE, -- 결선 시작일
|
||||
endcableday DATE, -- 결선 완료일
|
||||
|
||||
-- 작업자 정보
|
||||
worker VARCHAR(100), -- 시공팀
|
||||
cablestaff VARCHAR(100), -- 결선팀
|
||||
|
||||
-- AS 정보
|
||||
asday DATE, -- AS 접수일
|
||||
asman VARCHAR(50), -- AS 담당자
|
||||
asendday DATE, -- AS 완료일
|
||||
asproday DATE, -- AS 처리예정일
|
||||
setdate DATE, -- 세팅예정일
|
||||
asorderman VARCHAR(50), -- AS 의뢰자
|
||||
asordermantel VARCHAR(20), -- AS 의뢰자 연락처
|
||||
aslist TEXT, -- AS 내역
|
||||
asresult TEXT, -- AS 결과
|
||||
ashistory TEXT, -- AS 이력
|
||||
as_state VARCHAR(50), -- AS 상태
|
||||
as_step VARCHAR(50), -- AS 단계
|
||||
as_check TINYINT, -- AS 체크
|
||||
aswriter VARCHAR(50), -- AS 등록자
|
||||
asfee TINYINT, -- AS 유/무상
|
||||
asfee_estimate INT, -- AS 유상금액
|
||||
as_checkboxvalue1 CHAR(1), -- AS 체크1
|
||||
as_checkboxvalue2 CHAR(1), -- AS 체크2
|
||||
as_checkboxvalue3 CHAR(1), -- AS 체크3
|
||||
as_checkboxvalue4 CHAR(1), -- AS 체크4
|
||||
|
||||
-- 클레임 정보
|
||||
claimperson VARCHAR(50), -- 클레임 담당자
|
||||
claimtel VARCHAR(20), -- 클레임 연락처
|
||||
claimList TEXT, -- 클레임 리스트 (JSON)
|
||||
|
||||
-- 금액 정보
|
||||
sum_estimate DECIMAL(15,0), -- 견적합계
|
||||
sum_bill DECIMAL(15,0), -- 청구합계
|
||||
sum_receivable DECIMAL(15,0), -- 미수금
|
||||
sum_deposit DECIMAL(15,0), -- 입금합계
|
||||
sum_claimamount DECIMAL(15,0), -- 클레임금액
|
||||
receivable DECIMAL(15,0), -- 미수잔액
|
||||
totalbill DECIMAL(15,0), -- 총청구액
|
||||
decided_estimate DECIMAL(15,0), -- 확정견적
|
||||
total_receivable DECIMAL(15,0), -- 총미수금
|
||||
total_deposit DECIMAL(15,0), -- 총입금액
|
||||
issued_receivable DECIMAL(15,0), -- 발행미수금
|
||||
issued_amount DECIMAL(15,0), -- 발행금액
|
||||
|
||||
-- 보증 정보
|
||||
warrantyFromDate DATE, -- 보증 시작일
|
||||
warrantyToDate DATE, -- 보증 종료일
|
||||
warrantyPeriod VARCHAR(50), -- 보증 기간
|
||||
warrantyMemo TEXT, -- 보증 메모
|
||||
|
||||
-- 인정검사 정보
|
||||
certifiedInspector VARCHAR(50), -- 인정검사원
|
||||
certifiedLabelAttachedDate DATE, -- 인정라벨 부착일
|
||||
|
||||
-- 상태 정보
|
||||
checkbox TINYINT, -- 계약체결여부
|
||||
checkstep VARCHAR(50), -- 진행단계
|
||||
workStatus VARCHAR(50), -- 시공상태
|
||||
cableworkStatus VARCHAR(50), -- 결선상태
|
||||
motorwirestatus VARCHAR(50), -- 모터결선상태
|
||||
|
||||
-- 체크 플래그
|
||||
checkreceivable TINYINT, -- 미수금 체크
|
||||
checkbond TINYINT, -- 채권 체크
|
||||
|
||||
-- JSON 데이터
|
||||
accountList TEXT, -- 회계 리스트 (JSON)
|
||||
estimateList TEXT, -- 견적 리스트 (JSON)
|
||||
equipmentList TEXT, -- 장비 리스트 (JSON)
|
||||
|
||||
-- 기타
|
||||
comment TEXT, -- 비고
|
||||
outputmemo TEXT, -- 출하 메모
|
||||
accountnote TEXT, -- 회계 메모
|
||||
change_worklist TEXT, -- 변경 작업목록
|
||||
as_refer TEXT, -- AS 참조
|
||||
promiseday DATE, -- 약속일
|
||||
|
||||
-- 시스템 필드
|
||||
regist_day DATETIME, -- 등록일
|
||||
update_day DATETIME, -- 수정일
|
||||
update_log TEXT, -- 수정이력
|
||||
searchtag TEXT, -- 검색태그
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
hit INT DEFAULT 0, -- 조회수
|
||||
|
||||
INDEX idx_workplacename (workplacename),
|
||||
INDEX idx_secondord (secondord),
|
||||
INDEX idx_work_state (work_state)
|
||||
);
|
||||
```
|
||||
|
||||
## 공사 진행 상태
|
||||
|
||||
### work_state 상태값
|
||||
| 상태 | 설명 | 조건 |
|
||||
|------|------|------|
|
||||
| 계약전 | 초기 상태 | checkbox = 0 |
|
||||
| 착공전 | 계약 완료 | checkbox = 1 |
|
||||
| 시공중 | 시공 시작 | workday 입력 |
|
||||
| 결선대기 | 시공 완료 | endworkday 입력 |
|
||||
| 결선중 | 결선 시작 | cableday 입력 |
|
||||
| 결선완료 | 결선 완료 | endcableday 입력 |
|
||||
|
||||
### AS 상태 (as_state)
|
||||
| 상태 | 설명 | 조건 |
|
||||
|------|------|------|
|
||||
| 미접수 | 초기 상태 | - |
|
||||
| 접수완료 | AS 접수 | asday 입력 |
|
||||
| 처리예약 | 처리 예정 | asproday 입력 |
|
||||
| 세팅예약 | 세팅 예정 | setdate 입력 |
|
||||
| 처리완료 | AS 완료 | asendday 입력 |
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### 공사 상태 자동 계산
|
||||
```php
|
||||
// as/list.php
|
||||
$state_work = 0;
|
||||
if ($row["checkbox"] == 0) $state_work = 1; // 착공전
|
||||
if (substr($row["workday"], 0, 2) == "20") $state_work = 2; // 시공중
|
||||
if (substr($row["endworkday"], 0, 2) == "20") $state_work = 3; // 결선대기
|
||||
if (substr($row["cableday"], 0, 2) == "20") $state_work = 4; // 결선중
|
||||
if (substr($row["endcableday"], 0, 2) == "20") $state_work = 5; // 결선완료
|
||||
```
|
||||
|
||||
### 생산 지시 처리
|
||||
```php
|
||||
// make/insert.php
|
||||
// screen_state 업데이트
|
||||
$sql = "UPDATE $DB.$tablename SET screen_state=?, update_log=? WHERE num=?";
|
||||
```
|
||||
|
||||
## 관련 디렉토리
|
||||
|
||||
### 벤딩 관련
|
||||
```
|
||||
/bending/ # 벤딩 작업 관리
|
||||
/bendingfee/ # 벤딩 비용
|
||||
/bendingmap/ # 벤딩 맵
|
||||
/etcbending/ # 기타 벤딩
|
||||
```
|
||||
|
||||
### 출력물 관련
|
||||
```
|
||||
/output/ # 출하/출력
|
||||
/egimake/ # EGI 제작
|
||||
/guiderail/ # 가이드레일
|
||||
/shutterbox/ # 셔터박스
|
||||
```
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. 공사/프로젝트 분리
|
||||
```sql
|
||||
-- SAM: 프로젝트 마스터
|
||||
projects (
|
||||
id,
|
||||
tenant_id,
|
||||
project_number,
|
||||
project_name,
|
||||
customer_id,
|
||||
status, -- draft, contracted, in_progress, completed
|
||||
contracted_date,
|
||||
start_date,
|
||||
end_date
|
||||
)
|
||||
|
||||
-- SAM: 공사 단계
|
||||
project_phases (
|
||||
id,
|
||||
project_id,
|
||||
phase_type, -- construction, wiring, testing
|
||||
planned_start,
|
||||
planned_end,
|
||||
actual_start,
|
||||
actual_end,
|
||||
assigned_team,
|
||||
status
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 작업 지시서
|
||||
```sql
|
||||
-- SAM: 작업 지시
|
||||
work_orders (
|
||||
id,
|
||||
project_id,
|
||||
work_order_number,
|
||||
work_type, -- production, assembly, installation
|
||||
status,
|
||||
priority,
|
||||
due_date,
|
||||
assigned_to
|
||||
)
|
||||
|
||||
-- SAM: 작업 상세
|
||||
work_order_items (
|
||||
id,
|
||||
work_order_id,
|
||||
item_id,
|
||||
quantity,
|
||||
completed_quantity,
|
||||
status
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 진행 상태 추적
|
||||
```sql
|
||||
-- SAM: 상태 이력
|
||||
status_histories (
|
||||
id,
|
||||
entity_type, -- project, work_order, phase
|
||||
entity_id,
|
||||
from_status,
|
||||
to_status,
|
||||
changed_by,
|
||||
changed_at,
|
||||
reason
|
||||
)
|
||||
```
|
||||
|
||||
## 참고 파일
|
||||
- `/work/_request.php` - 91개 요청 변수 정의
|
||||
- `/work/insert.php` - 저장 로직
|
||||
- `/make/write_form.php` - 생산 지시 UI
|
||||
- `/as/list.php` - 공사 상태 계산 로직
|
||||
352
projects/legacy-5130/05_SHIPPING.md
Normal file
352
projects/legacy-5130/05_SHIPPING.md
Normal file
@@ -0,0 +1,352 @@
|
||||
# 출하 (Shipping/Output) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/output/`
|
||||
- **DB 테이블**: `output` (메인), `output_extra` (서브)
|
||||
- **주요 기능**: 출하 관리, 배송 추적, 인정검사(ACI), 품질 서류
|
||||
|
||||
## 디렉토리 구조
|
||||
```
|
||||
/output/
|
||||
├── _request.php # 요청 파라미터 (108개)
|
||||
├── _row.php # 행 렌더링
|
||||
├── _row_extra.php # 추가 행 렌더링
|
||||
├── insert.php # 출하 저장 (342줄)
|
||||
├── list.php # 출하 목록
|
||||
├── list_*.php # 용도별 목록 (20개+)
|
||||
│ ├── list_ACI.php # 인정검사 목록
|
||||
│ ├── list_POD.php # 출고증 목록
|
||||
│ ├── list_QCdoc.php # 품질서류 목록
|
||||
│ ├── list_QCsales.php # 품질매출 목록
|
||||
│ ├── list_account.php # 회계 목록
|
||||
│ ├── list_bending.php # 벤딩 목록
|
||||
│ ├── list_bending_mid.php # 벤딩 중간검사
|
||||
│ ├── list_deliveryfee.php # 배송비 목록
|
||||
│ ├── list_document.php # 서류 목록
|
||||
│ ├── list_jointbar.php # 조인트바 목록
|
||||
│ ├── list_order.php # 발주 목록
|
||||
│ ├── list_output.php # 출력 목록
|
||||
│ ├── list_requestACI.php # ACI 요청 목록
|
||||
│ ├── list_screen.php # 스크린 목록
|
||||
│ ├── list_screen_mid.php # 스크린 중간검사
|
||||
│ ├── list_slat.php # 슬랫 목록
|
||||
│ └── list_slat_mid.php # 슬랫 중간검사
|
||||
├── write_form.php # 출하 등록 폼 (107KB)
|
||||
├── write_form_script.php # 스크립트 (267KB)
|
||||
├── view*.php # 각종 뷰 (30개+)
|
||||
├── insert_*.php # 부분 저장
|
||||
├── fetch_*.php # AJAX 데이터 조회
|
||||
└── json/ # JSON 데이터 저장
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### output 테이블 (메인)
|
||||
```sql
|
||||
CREATE TABLE output (
|
||||
num INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- 기본 정보
|
||||
outdate DATE, -- 출하일
|
||||
indate DATE, -- 등록일
|
||||
orderman VARCHAR(50), -- 담당자
|
||||
outworkplace VARCHAR(200), -- 현장명/거래처
|
||||
outputplace VARCHAR(200), -- 출하장소
|
||||
receiver VARCHAR(50), -- 수령자
|
||||
phone VARCHAR(20), -- 연락처
|
||||
delivery VARCHAR(100), -- 배송방법/업체
|
||||
|
||||
-- 분류 정보
|
||||
root VARCHAR(50), -- 경로
|
||||
steel VARCHAR(50), -- 강종
|
||||
motor VARCHAR(100), -- 모터
|
||||
|
||||
-- 상태 정보
|
||||
regist_state VARCHAR(20), -- 등록상태 (등록, 완료)
|
||||
bend_state VARCHAR(20), -- 벤딩상태
|
||||
motor_state VARCHAR(20), -- 모터상태 (준비완료 등)
|
||||
|
||||
-- 발주처 정보
|
||||
con_num VARCHAR(50), -- 계약번호
|
||||
secondord VARCHAR(100), -- 2차 발주처
|
||||
secondordman VARCHAR(50), -- 2차 담당자
|
||||
secondordmantel VARCHAR(20), -- 2차 연락처
|
||||
secondordnum VARCHAR(50), -- 2차 발주번호
|
||||
|
||||
-- 스크린 정보
|
||||
screen VARCHAR(100), -- 스크린 유형
|
||||
screen_su INT, -- 스크린 수량
|
||||
screen_m2 DECIMAL(10,2), -- 스크린 면적(m²)
|
||||
screenlist TEXT, -- 스크린 리스트 (JSON)
|
||||
|
||||
-- 슬랫 정보
|
||||
slat VARCHAR(100), -- 슬랫 유형
|
||||
slat_su INT, -- 슬랫 수량
|
||||
slat_m2 DECIMAL(10,2), -- 슬랫 면적(m²)
|
||||
slatlist TEXT, -- 슬랫 리스트 (JSON)
|
||||
|
||||
-- 제품/LOT 정보
|
||||
prodCode VARCHAR(50), -- 제품코드
|
||||
warrantyNum VARCHAR(50), -- 보증번호
|
||||
lotNum VARCHAR(50), -- LOT 번호
|
||||
warranty VARCHAR(100), -- 보증정보
|
||||
|
||||
-- 인정검사(ACI) 정보
|
||||
ACIregDate DATE, -- ACI 등록일
|
||||
ACIaskDate DATE, -- ACI 신청일
|
||||
ACIdoneDate DATE, -- ACI 완료일
|
||||
ACImemo TEXT, -- ACI 메모
|
||||
ACIcheck TINYINT, -- ACI 체크
|
||||
ACIgroupCode VARCHAR(50), -- ACI 그룹코드
|
||||
ACIgroupName VARCHAR(100), -- ACI 그룹명
|
||||
|
||||
-- 배송비 정보
|
||||
deliveryfeeList TEXT, -- 배송비 리스트 (JSON)
|
||||
|
||||
-- 견적 연결
|
||||
estimate_num INT, -- 연결된 견적번호
|
||||
displayText TEXT, -- 표시 텍스트
|
||||
|
||||
-- 체크 플래그
|
||||
slatcheck VARCHAR(10), -- 슬랫 체크
|
||||
partscheck VARCHAR(10), -- 부품 체크
|
||||
devMode VARCHAR(10), -- 개발자모드
|
||||
|
||||
-- 기타
|
||||
comment TEXT, -- 비고
|
||||
updatecomment TEXT, -- 수정 비고
|
||||
orderdate DATE, -- 발주일
|
||||
|
||||
-- 시스템 필드
|
||||
searchtag TEXT, -- 검색태그
|
||||
update_log TEXT, -- 수정이력
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
INDEX idx_outdate (outdate),
|
||||
INDEX idx_outworkplace (outworkplace),
|
||||
INDEX idx_prodCode (prodCode)
|
||||
);
|
||||
```
|
||||
|
||||
### output_extra 테이블 (상세/견적)
|
||||
```sql
|
||||
CREATE TABLE output_extra (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
parent_num INT, -- output.num 참조
|
||||
|
||||
-- 견적 상세 JSON
|
||||
detailJson TEXT, -- 상세 정보 JSON
|
||||
estimateList TEXT, -- 견적 리스트 JSON
|
||||
estimateSlatList TEXT, -- 슬랫 견적 리스트 JSON
|
||||
estimateList_auto TEXT, -- 자동계산 리스트 JSON
|
||||
estimateSlatList_auto TEXT, -- 슬랫 자동계산 JSON
|
||||
|
||||
-- 금액 정보
|
||||
estimateTotal INT DEFAULT 0, -- 견적 총액
|
||||
EstimateFirstSum INT DEFAULT 0, -- 최초 견적
|
||||
EstimateUpdatetSum INT DEFAULT 0, -- 수정 견적
|
||||
EstimateDiffer INT DEFAULT 0, -- 차액
|
||||
estimateSurang INT DEFAULT 0, -- 수량
|
||||
inspectionFee INT DEFAULT 50000, -- 인정검사비
|
||||
EstimateDiscountRate DECIMAL(5,2), -- 할인율
|
||||
EstimateDiscount INT DEFAULT 0, -- 할인금액
|
||||
EstimateFinalSum INT DEFAULT 0, -- 최종금액
|
||||
ET_unapproved INT DEFAULT 0, -- 비인정 금액
|
||||
ET_total INT DEFAULT 0, -- 총 금액
|
||||
|
||||
-- 규격 정보
|
||||
pjnum VARCHAR(50), -- 프로젝트 번호
|
||||
major_category VARCHAR(50), -- 대분류
|
||||
position VARCHAR(50), -- 위치
|
||||
makeWidth INT, -- 제작 폭
|
||||
makeHeight INT, -- 제작 높이
|
||||
maguriWing VARCHAR(20), -- 마구리 윙
|
||||
|
||||
-- 작업/검사 리스트 (JSON)
|
||||
screen_unapprovedList TEXT, -- 스크린 비인정 리스트
|
||||
slat_unapprovedList TEXT, -- 슬랫 비인정 리스트
|
||||
motorList TEXT, -- 모터 리스트
|
||||
bendList TEXT, -- 벤딩 리스트
|
||||
etcList TEXT, -- 기타 리스트
|
||||
controllerList TEXT, -- 컨트롤러 리스트
|
||||
|
||||
-- 회계 정보
|
||||
accountDate DATE, -- 회계일
|
||||
accountList TEXT, -- 회계 리스트 (JSON)
|
||||
|
||||
FOREIGN KEY (parent_num) REFERENCES output(num),
|
||||
INDEX idx_parent_num (parent_num)
|
||||
);
|
||||
```
|
||||
|
||||
## JSON 데이터 구조
|
||||
|
||||
### screenlist / slatlist
|
||||
```json
|
||||
[
|
||||
{
|
||||
"seq": 1,
|
||||
"item_code": "SCR001",
|
||||
"width": 1200,
|
||||
"height": 2400,
|
||||
"quantity": 2,
|
||||
"area": 5.76,
|
||||
"note": "비고"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### deliveryfeeList
|
||||
```json
|
||||
[
|
||||
{
|
||||
"delivery_date": "2025-01-15",
|
||||
"carrier": "한진택배",
|
||||
"fee": 50000,
|
||||
"paid_by": "발송인"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### motorList / bendList
|
||||
```json
|
||||
[
|
||||
{
|
||||
"model": "KD-M001",
|
||||
"quantity": 1,
|
||||
"status": "완료",
|
||||
"note": ""
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### 출하 등록 프로세스
|
||||
```php
|
||||
// insert.php
|
||||
if ($mode == "insert") {
|
||||
// 1. output 테이블 저장
|
||||
$sql = "INSERT INTO $DB.output (outdate, indate, orderman, ...) VALUES (?, ?, ?, ...)";
|
||||
$output_num = $pdo->lastInsertId();
|
||||
|
||||
// 2. output_extra 테이블 저장
|
||||
$sql2 = "INSERT INTO $DB.output_extra (parent_num, detailJson, ...) VALUES (?, ?, ...)";
|
||||
|
||||
// 3. 첨부파일 연결 (timekey → num)
|
||||
if ($timekey != '') {
|
||||
$sql = "UPDATE $DB.picuploads SET parentnum=? WHERE parentnum=?";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 상태 변경
|
||||
```php
|
||||
// 완료 처리 시 모터 상태 자동 변경
|
||||
if ($regist_state == '완료') {
|
||||
$motor_state = "준비완료";
|
||||
}
|
||||
```
|
||||
|
||||
## 관련 뷰 파일
|
||||
|
||||
### 작업 뷰 (생산 작업지시서)
|
||||
- `viewBendingWork.php` - 벤딩 작업
|
||||
- `viewScreenWork.php` - 스크린 작업
|
||||
- `viewSlatWork.php` - 슬랫 작업
|
||||
|
||||
### 검사 뷰 (중간검사)
|
||||
- `viewMidInspectBending.php` - 벤딩 중간검사
|
||||
- `viewMidInspectScreen.php` - 스크린 중간검사
|
||||
- `viewMidInspectSlat.php` - 슬랫 중간검사
|
||||
|
||||
### 발주/출고 뷰
|
||||
- `viewOrder.php` - 발주서
|
||||
- `viewOutput.php` - 출하서
|
||||
- `viewConfirm.php` - 확인서
|
||||
|
||||
### ACI 뷰
|
||||
- `view_requestACI.php` - ACI 요청
|
||||
- `view_requestACIgroup.php` - ACI 그룹 요청
|
||||
- `view_QCcertificate.php` - 품질인증서
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. 출하 구조 개선
|
||||
```sql
|
||||
-- SAM: 출하 헤더
|
||||
shipments (
|
||||
id,
|
||||
tenant_id,
|
||||
shipment_number,
|
||||
project_id,
|
||||
customer_id,
|
||||
ship_date,
|
||||
status, -- draft, confirmed, shipped, delivered
|
||||
delivery_address,
|
||||
receiver_name,
|
||||
receiver_phone,
|
||||
carrier,
|
||||
tracking_number
|
||||
)
|
||||
|
||||
-- SAM: 출하 상세
|
||||
shipment_items (
|
||||
id,
|
||||
shipment_id,
|
||||
item_type, -- screen, slat, motor, etc.
|
||||
item_code,
|
||||
quantity,
|
||||
lot_number,
|
||||
note
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 인정검사(ACI) 분리
|
||||
```sql
|
||||
-- SAM: 인정검사 관리
|
||||
aci_inspections (
|
||||
id,
|
||||
shipment_id,
|
||||
inspection_number,
|
||||
request_date,
|
||||
inspection_date,
|
||||
result, -- pending, passed, failed
|
||||
inspector,
|
||||
certificate_number,
|
||||
documents JSON -- 첨부문서
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 배송비 관리
|
||||
```sql
|
||||
-- SAM: 배송비 이력
|
||||
delivery_fees (
|
||||
id,
|
||||
shipment_id,
|
||||
carrier,
|
||||
fee_amount,
|
||||
payment_type, -- prepaid, collect
|
||||
paid_date,
|
||||
receipt_number
|
||||
)
|
||||
```
|
||||
|
||||
### 4. 문서 관리
|
||||
```sql
|
||||
-- SAM: 출하 문서
|
||||
shipment_documents (
|
||||
id,
|
||||
shipment_id,
|
||||
document_type, -- work_order, inspection, certificate
|
||||
document_number,
|
||||
generated_at,
|
||||
file_path
|
||||
)
|
||||
```
|
||||
|
||||
## 참고 파일
|
||||
- `/output/insert.php` - 저장 로직 (342줄)
|
||||
- `/output/_request.php` - 108개 요청 변수
|
||||
- `/output/write_form.php` - 대형 UI (107KB)
|
||||
- `/output/write_form_script.php` - 스크립트 (267KB)
|
||||
325
projects/legacy-5130/06_QUALITY.md
Normal file
325
projects/legacy-5130/06_QUALITY.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# 품질/AS (Quality/After-Service) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/as/`
|
||||
- **DB 테이블**: `work` (공사 테이블 내 AS 컬럼 사용)
|
||||
- **주요 기능**: AS 접수, 처리 추적, 클레임 관리, 보증 관리
|
||||
|
||||
## 디렉토리 구조
|
||||
```
|
||||
/as/
|
||||
├── list.php # AS 목록 (54KB)
|
||||
├── view.php # AS 상세 (56KB)
|
||||
├── write_form.php # AS 등록/수정 폼 (54KB)
|
||||
├── func.php # 공통 함수
|
||||
├── delete.php # AS 삭제
|
||||
├── delete_ripple.php # 연관 삭제
|
||||
├── print_area.php # 인쇄 영역
|
||||
├── print_aslist.php # AS 목록 인쇄
|
||||
├── outputlist.php # 출력 목록
|
||||
└── outputview.php # 출력 뷰
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### work 테이블 - AS 관련 컬럼
|
||||
```sql
|
||||
-- AS는 별도 테이블이 아닌 work 테이블의 컬럼으로 관리
|
||||
-- work 테이블에 AS 관련 필드 포함
|
||||
|
||||
-- AS 기본 정보
|
||||
as_check TINYINT, -- AS 체크 (1: AS 대상)
|
||||
as_state VARCHAR(50), -- AS 상태 (미접수, 접수완료, 처리예약, 세팅예약, 처리완료)
|
||||
as_step VARCHAR(50), -- AS 단계
|
||||
|
||||
-- AS 일정 정보
|
||||
asday DATE, -- AS 접수일
|
||||
asproday DATE, -- AS 처리예정일
|
||||
setdate DATE, -- 세팅예정일
|
||||
asendday DATE, -- AS 완료일
|
||||
|
||||
-- AS 담당자 정보
|
||||
asman VARCHAR(50), -- AS 담당자
|
||||
aswriter VARCHAR(50), -- AS 등록자
|
||||
asorderman VARCHAR(50), -- AS 의뢰자
|
||||
asordermantel VARCHAR(20), -- AS 의뢰자 연락처
|
||||
|
||||
-- AS 내용
|
||||
aslist TEXT, -- AS 내역
|
||||
asresult TEXT, -- AS 결과
|
||||
ashistory TEXT, -- AS 이력
|
||||
as_refer TEXT, -- AS 참조
|
||||
|
||||
-- AS 비용
|
||||
asfee TINYINT, -- AS 유/무상 (0: 무상, 1: 유상)
|
||||
asfee_estimate INT, -- AS 유상금액
|
||||
|
||||
-- AS 체크박스
|
||||
as_checkboxvalue1 CHAR(1), -- AS 체크1
|
||||
as_checkboxvalue2 CHAR(1), -- AS 체크2
|
||||
as_checkboxvalue3 CHAR(1), -- AS 체크3
|
||||
as_checkboxvalue4 CHAR(1), -- AS 체크4
|
||||
```
|
||||
|
||||
### 클레임 관련 컬럼
|
||||
```sql
|
||||
-- work 테이블 내 클레임 필드
|
||||
claimperson VARCHAR(50), -- 클레임 담당자
|
||||
claimtel VARCHAR(20), -- 클레임 연락처
|
||||
claimList TEXT, -- 클레임 리스트 (JSON)
|
||||
sum_claimamount DECIMAL(15,0), -- 클레임금액
|
||||
```
|
||||
|
||||
### 보증 관련 컬럼
|
||||
```sql
|
||||
-- work 테이블 내 보증 필드
|
||||
warrantyFromDate DATE, -- 보증 시작일
|
||||
warrantyToDate DATE, -- 보증 종료일
|
||||
warrantyPeriod VARCHAR(50), -- 보증 기간
|
||||
warrantyMemo TEXT, -- 보증 메모
|
||||
```
|
||||
|
||||
### 인정검사 관련 컬럼
|
||||
```sql
|
||||
-- work 테이블 내 인정검사 필드
|
||||
certifiedInspector VARCHAR(50), -- 인정검사원
|
||||
certifiedLabelAttachedDate DATE, -- 인정라벨 부착일
|
||||
```
|
||||
|
||||
## AS 상태 흐름
|
||||
|
||||
### as_state 상태값
|
||||
| 상태 | 설명 | 조건 |
|
||||
|------|------|------|
|
||||
| 미접수 | 초기 상태 | as_check = 1, asday 미입력 |
|
||||
| 접수완료 | AS 접수됨 | asday 입력 |
|
||||
| 처리예약 | 처리 예정 | asproday 입력 |
|
||||
| 세팅예약 | 세팅 예정 | setdate 입력 |
|
||||
| 처리완료 | AS 완료 | asendday 입력 |
|
||||
|
||||
### 상태 전이 다이어그램
|
||||
```
|
||||
[미접수] → [접수완료] → [처리예약] → [처리완료]
|
||||
↘ [세팅예약] ↗
|
||||
```
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### AS 목록 조회 (as/list.php)
|
||||
```php
|
||||
// AS 대상 조회 조건
|
||||
$a = "(as_check = '1') or (asday <> '0000-00-00') order by num desc";
|
||||
|
||||
// 상태별 필터링
|
||||
if($asprocess == "전체") {
|
||||
$sql = "SELECT * FROM chandj.work WHERE " . $a;
|
||||
} elseif($asprocess == "미접수") {
|
||||
$sql = "SELECT * FROM chandj.work WHERE (as_state LIKE '%$asprocess%')
|
||||
AND (as_check = '1') ORDER BY num DESC";
|
||||
} else {
|
||||
$sql = "SELECT * FROM chandj.work WHERE (as_state LIKE '%$asprocess%')
|
||||
ORDER BY num DESC";
|
||||
}
|
||||
```
|
||||
|
||||
### AS 등록 조건
|
||||
- `as_check = 1`: 해당 공사를 AS 대상으로 지정
|
||||
- `asday` 입력 시: 자동으로 "접수완료" 상태로 변경
|
||||
- work 테이블에 직접 UPDATE
|
||||
|
||||
### 유/무상 판단
|
||||
```php
|
||||
// asfee 값에 따른 유/무상 구분
|
||||
if ($asfee == 0) {
|
||||
// 무상 AS
|
||||
} else {
|
||||
// 유상 AS - asfee_estimate 금액 적용
|
||||
}
|
||||
```
|
||||
|
||||
## JSON 데이터 구조
|
||||
|
||||
### claimList (클레임 리스트)
|
||||
```json
|
||||
[
|
||||
{
|
||||
"seq": 1,
|
||||
"claim_date": "2025-01-15",
|
||||
"claim_type": "품질불량",
|
||||
"description": "표면 스크래치",
|
||||
"status": "처리완료",
|
||||
"result": "교체 완료"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### ashistory (AS 이력)
|
||||
```json
|
||||
[
|
||||
{
|
||||
"date": "2025-01-15",
|
||||
"action": "접수",
|
||||
"handler": "홍길동",
|
||||
"note": "고객 불만 접수"
|
||||
},
|
||||
{
|
||||
"date": "2025-01-20",
|
||||
"action": "처리완료",
|
||||
"handler": "김철수",
|
||||
"note": "부품 교체 완료"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 관련 뷰 파일
|
||||
|
||||
### 목록 뷰
|
||||
- `list.php` - AS 전체 목록 (상태별 필터링)
|
||||
- `print_aslist.php` - AS 목록 인쇄
|
||||
|
||||
### 상세 뷰
|
||||
- `view.php` - AS 상세 정보
|
||||
- `outputview.php` - 출력용 뷰
|
||||
|
||||
### 등록/수정 뷰
|
||||
- `write_form.php` - AS 등록/수정 폼
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. AS 테이블 분리
|
||||
```sql
|
||||
-- SAM: AS 독립 테이블
|
||||
after_services (
|
||||
id,
|
||||
tenant_id,
|
||||
project_id, -- work → projects 참조
|
||||
as_number, -- AS 번호 (자동생성)
|
||||
status, -- pending, received, scheduled, completed
|
||||
|
||||
-- 접수 정보
|
||||
received_date,
|
||||
received_by,
|
||||
requester_name,
|
||||
requester_phone,
|
||||
|
||||
-- 처리 정보
|
||||
scheduled_date,
|
||||
setting_date,
|
||||
completed_date,
|
||||
handler_id,
|
||||
|
||||
-- 비용
|
||||
fee_type, -- free, paid
|
||||
fee_amount,
|
||||
|
||||
-- 내용
|
||||
issue_description,
|
||||
result_description,
|
||||
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
```
|
||||
|
||||
### 2. AS 이력 테이블
|
||||
```sql
|
||||
-- SAM: AS 상태 이력
|
||||
after_service_histories (
|
||||
id,
|
||||
after_service_id,
|
||||
from_status,
|
||||
to_status,
|
||||
action, -- received, scheduled, completed, reopened
|
||||
handler_id,
|
||||
note,
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 클레임 테이블 분리
|
||||
```sql
|
||||
-- SAM: 클레임 관리
|
||||
claims (
|
||||
id,
|
||||
tenant_id,
|
||||
project_id,
|
||||
after_service_id, -- AS와 연결 (선택)
|
||||
claim_number,
|
||||
claim_type, -- quality, delivery, etc.
|
||||
claim_date,
|
||||
|
||||
description,
|
||||
status, -- open, investigating, resolved, closed
|
||||
resolution,
|
||||
|
||||
claimed_amount,
|
||||
approved_amount,
|
||||
|
||||
created_at,
|
||||
resolved_at
|
||||
)
|
||||
```
|
||||
|
||||
### 4. 보증 테이블 분리
|
||||
```sql
|
||||
-- SAM: 보증 관리
|
||||
warranties (
|
||||
id,
|
||||
tenant_id,
|
||||
project_id,
|
||||
warranty_number,
|
||||
|
||||
start_date,
|
||||
end_date,
|
||||
period_months,
|
||||
|
||||
coverage_type, -- full, limited, parts_only
|
||||
terms TEXT,
|
||||
|
||||
is_active,
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
### 5. 인정검사 이력
|
||||
```sql
|
||||
-- SAM: 인정검사 이력 (output 테이블 ACI와 연계)
|
||||
certifications (
|
||||
id,
|
||||
tenant_id,
|
||||
project_id,
|
||||
shipment_id, -- output → shipments 참조
|
||||
|
||||
inspector_name,
|
||||
inspection_date,
|
||||
label_attached_date,
|
||||
certificate_number,
|
||||
|
||||
result, -- passed, failed, conditional
|
||||
documents JSON,
|
||||
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
## 특이사항
|
||||
|
||||
### work 테이블 통합 구조
|
||||
5130에서 AS는 별도 테이블이 아닌 `work` (공사) 테이블에 통합:
|
||||
- 장점: 공사-AS 데이터 일체화로 조회 용이
|
||||
- 단점: 하나의 공사에 다수 AS 발생 시 관리 어려움
|
||||
- SAM에서는 1:N 관계로 분리 권장
|
||||
|
||||
### 상태 관리
|
||||
- 상태값이 한글 문자열로 저장 (`미접수`, `접수완료` 등)
|
||||
- SAM에서는 enum 또는 상수 테이블로 정규화 권장
|
||||
|
||||
### 클레임-AS 관계
|
||||
- 현재 구조에서 클레임과 AS가 명확히 구분되지 않음
|
||||
- SAM에서는 claims와 after_services 테이블로 분리하되 연결 가능하도록 설계
|
||||
|
||||
## 참고 파일
|
||||
- `/as/list.php` - AS 목록 쿼리 및 상태 필터링 (54KB)
|
||||
- `/as/view.php` - AS 상세 표시 (56KB)
|
||||
- `/work/_request.php` - AS 관련 91개 변수 정의
|
||||
- `/work/insert.php` - work 테이블 저장 (AS 컬럼 포함)
|
||||
474
projects/legacy-5130/07_ACCOUNTING.md
Normal file
474
projects/legacy-5130/07_ACCOUNTING.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# 회계 (Accounting) 분석
|
||||
|
||||
## 개요
|
||||
- **디렉토리**: `/account/`
|
||||
- **DB 테이블**: `account` (메인), `recordlist` (미수금 약속이력)
|
||||
- **주요 기능**: 금전출납, 미수금 관리, 매출채권 관리, 거래처별 잔액
|
||||
|
||||
## 디렉토리 구조
|
||||
```
|
||||
/account/
|
||||
├── _request.php # 요청 파라미터 (17개)
|
||||
├── _row.php # 행 렌더링
|
||||
├── insert.php # 회계 저장
|
||||
├── insert_bulk.php # 대량 저장
|
||||
├── list.php # 회계 목록 (92KB)
|
||||
├── list_daily.php # 일별 목록 (23KB)
|
||||
├── detail.php # 상세 보기
|
||||
├── modal.php # 모달 팝업
|
||||
├── fetch_modal.php # 모달 데이터 조회 (21KB)
|
||||
├── fetch_balance.php # 잔액 조회
|
||||
├── fetch_options.php # 옵션 조회
|
||||
├── fetch_todoMonthly.php # 월별 할일
|
||||
│
|
||||
├── receivable.php # 미수금 현황 (35KB)
|
||||
├── receivablelist.php # 미수금 목록 (28KB)
|
||||
├── baddebt.php # 대손 관리 (29KB)
|
||||
│
|
||||
├── S_transaction.php # 거래 내역 (30KB)
|
||||
├── s_transaction_sheet.php # 거래 시트 (26KB)
|
||||
├── month_sales.php # 월별 매출 (31KB)
|
||||
├── monthly_balance_popup.php # 월별 잔액 팝업
|
||||
│
|
||||
├── customer_last.php # 거래처 최근 거래 (23KB)
|
||||
├── schedule.php # 일정 관리 (14KB)
|
||||
├── settings.php # 설정 (15KB)
|
||||
│
|
||||
├── saveExcel.php # 엑셀 저장
|
||||
├── downloadExcel.php # 엑셀 다운로드
|
||||
├── order_saveExcel.php # 주문 엑셀 저장
|
||||
├── customer_saveExcel.php # 거래처 엑셀 저장
|
||||
│
|
||||
├── accoutlist.php # 계정 목록
|
||||
├── cardlist.php # 카드 목록
|
||||
├── get_electronic_bills.php # 전자세금계산서 조회
|
||||
│
|
||||
├── accountContents.json # 계정과목 설정 (6KB)
|
||||
├── accoutlist.json # 계정 목록 JSON
|
||||
├── cardlist.json # 카드 목록 JSON
|
||||
├── bankbook.txt # 통장 목록
|
||||
│
|
||||
├── css/ # 스타일시트
|
||||
├── excel/ # 엑셀 출력
|
||||
└── json/ # JSON 데이터
|
||||
```
|
||||
|
||||
## DB 스키마
|
||||
|
||||
### account 테이블
|
||||
```sql
|
||||
CREATE TABLE account (
|
||||
num INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- 기본 정보
|
||||
registDate DATE, -- 거래일
|
||||
dueDate DATE, -- 만기일/결제예정일
|
||||
endorsementDate DATE, -- 배서일 (전자어음)
|
||||
|
||||
-- 입출 구분
|
||||
inoutsep VARCHAR(20), -- 입출구분 (수입/지출)
|
||||
|
||||
-- 내용 정보
|
||||
content VARCHAR(200), -- 내용 (대분류: 거래처 수금, 자재비 등)
|
||||
contentSub VARCHAR(200), -- 내용 상세 (중분류)
|
||||
content_detail TEXT, -- 상세 내용 (적요)
|
||||
|
||||
-- 금액
|
||||
amount DECIMAL(15,0), -- 금액 (콤마 제거 후 저장)
|
||||
|
||||
-- 은행/결제 정보
|
||||
bankbook VARCHAR(100), -- 통장/결제수단
|
||||
|
||||
-- 거래처 정보
|
||||
secondordnum VARCHAR(50), -- 거래처 번호 (발주번호)
|
||||
parentEBNum VARCHAR(50), -- 부모 전자어음 번호
|
||||
|
||||
-- 시스템 필드
|
||||
first_writer VARCHAR(100), -- 최초 작성자 (날짜 + 이름)
|
||||
update_log TEXT, -- 수정이력
|
||||
searchtag TEXT, -- 검색태그
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
INDEX idx_registDate (registDate),
|
||||
INDEX idx_inoutsep (inoutsep),
|
||||
INDEX idx_content (content),
|
||||
INDEX idx_secondordnum (secondordnum)
|
||||
);
|
||||
```
|
||||
|
||||
### recordlist 테이블 (미수금 약속 이력)
|
||||
```sql
|
||||
CREATE TABLE recordlist (
|
||||
num INT AUTO_INCREMENT PRIMARY KEY,
|
||||
secondordnum VARCHAR(50), -- 거래처 번호
|
||||
primisedate DATE, -- 약속일
|
||||
comment TEXT, -- 코멘트
|
||||
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
|
||||
|
||||
INDEX idx_secondordnum (secondordnum)
|
||||
);
|
||||
```
|
||||
|
||||
## 계정과목 구조 (accountContents.json)
|
||||
|
||||
### 수입 계정
|
||||
```json
|
||||
{
|
||||
"수입": {
|
||||
"거래처 수금": {
|
||||
"description": "거래처에서 입금한 금액",
|
||||
"level": 1,
|
||||
"하위계정": ["외상매출금"]
|
||||
},
|
||||
"차입금": {
|
||||
"description": "대출금(개인,은행 등)",
|
||||
"level": 1
|
||||
},
|
||||
"이자": {
|
||||
"description": "결산이자",
|
||||
"level": 1,
|
||||
"하위계정": ["이자수익"]
|
||||
},
|
||||
"최초전월이월": {
|
||||
"description": "금전출납부 시작",
|
||||
"level": 1
|
||||
},
|
||||
"잡이익": {
|
||||
"description": "잡이익",
|
||||
"level": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 지출 계정
|
||||
```json
|
||||
{
|
||||
"지출": {
|
||||
"자재비": {"하위계정": ["외상매입금"]},
|
||||
"급여": {"하위계정": ["임직원급여", "상여금"]},
|
||||
"복리후생비": {"description": "직원 식대외 직원 작업복등"},
|
||||
"소모품비": {"description": "각종 소모품 비용"},
|
||||
"차량유지비": {"description": "유류대, 통행료"},
|
||||
"운반비": {"description": "택배운반비외 각종운반비"},
|
||||
"통신비": {"description": "전화요금, 인터넷요금"},
|
||||
"수도요금": {"하위계정": ["수도광열비"]},
|
||||
"전기요금": {"하위계정": ["수도광열비"]},
|
||||
"보험료": {"description": "차량보험료, 화재보험료등"},
|
||||
"세금과공과금": {"description": "등록면허세, 취득세, 재산세등"},
|
||||
"접대비": {"description": "경조사비용"},
|
||||
"교통비": {"하위계정": ["여비교통비"]},
|
||||
"카드대금": {"하위계정": ["미지급비용"]},
|
||||
"이자비용": {"하위계정": ["국민은행"]},
|
||||
"차입금상환": {"description": "대출에 의한 차입금"},
|
||||
"임차료": {"description": "지급임차료"},
|
||||
"렌트비용": {"하위계정": ["지급임차료"]},
|
||||
"수선비": {"description": "수선비"},
|
||||
"개발비": {"description": "프로그램 개발비용"},
|
||||
"기계장치": {"description": "기계구입"},
|
||||
"선급금": {"description": "미리 지급하는 금액"},
|
||||
"예치금": {"description": "예치금"},
|
||||
"보증금": {"하위계정": ["기타보증금"]},
|
||||
"수수료": {"하위계정": ["지급수수료"]},
|
||||
"외상매출채권(전자어음)": {"description": "외상매출채권(전자어음)"}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 비즈니스 로직
|
||||
|
||||
### 회계 등록 (insert.php)
|
||||
```php
|
||||
// 검색태그 생성
|
||||
$searchtag = $registDate . ' ' . $inoutsep . ' ' . $content . ' ' .
|
||||
$contentSub . ' ' . $amount . $content_detail;
|
||||
|
||||
// INSERT
|
||||
$sql = "INSERT INTO account (
|
||||
registDate, inoutsep, content, content_detail, amount,
|
||||
dueDate, searchtag, update_log, first_writer, bankbook,
|
||||
secondordnum, contentSub, endorsementDate, parentEBNum
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
// 금액에서 콤마 제거
|
||||
$amount = str_replace(',', '', $amount);
|
||||
```
|
||||
|
||||
### 미수금 계산 (receivable.php)
|
||||
```php
|
||||
// 이월 잔액 계산
|
||||
$previousMonthFromDate = date("Y-m-01", strtotime($previousMonth . '01'));
|
||||
$previousMonthToDate = date("Y-m-t", strtotime($previousMonth . '01'));
|
||||
|
||||
// recordlist에서 약속일/코멘트 조회
|
||||
$recordSql = "
|
||||
SELECT secondordnum, primisedate, comment
|
||||
FROM recordlist
|
||||
WHERE (is_deleted IS NULL or is_deleted = 0)
|
||||
ORDER BY num DESC
|
||||
";
|
||||
|
||||
// 거래처별 미수금 = 청구금액 - 입금금액
|
||||
```
|
||||
|
||||
### 잔액 조회 (fetch_balance.php)
|
||||
- 월별 이월 잔액 계산
|
||||
- 거래처별 채권/채무 현황
|
||||
- 전자어음 만기 관리
|
||||
|
||||
## 회계 유형
|
||||
|
||||
### 1. 금전출납 (Daily Cash)
|
||||
- **파일**: `list.php`, `list_daily.php`
|
||||
- **특징**: 일자별 입출금 기록
|
||||
- **주요 기능**: 일계표, 월계표
|
||||
|
||||
### 2. 미수금 관리 (Receivable)
|
||||
- **파일**: `receivable.php`, `receivablelist.php`
|
||||
- **특징**: 거래처별 미수금 추적
|
||||
- **주요 기능**: 이월잔액, 약속일 관리, 대손 처리
|
||||
|
||||
### 3. 거래 내역 (Transaction)
|
||||
- **파일**: `S_transaction.php`, `s_transaction_sheet.php`
|
||||
- **특징**: 거래처별 거래 이력
|
||||
- **주요 기능**: 거래처 원장, 거래 명세
|
||||
|
||||
### 4. 월별 매출 (Monthly Sales)
|
||||
- **파일**: `month_sales.php`
|
||||
- **특징**: 월별 매출 집계
|
||||
- **주요 기능**: 매출 통계, 추이 분석
|
||||
|
||||
## work 테이블 회계 연동
|
||||
|
||||
### work 테이블 내 금액 필드
|
||||
```sql
|
||||
-- 견적/청구 금액
|
||||
sum_estimate DECIMAL(15,0), -- 견적합계
|
||||
decided_estimate DECIMAL(15,0), -- 확정견적
|
||||
|
||||
-- 청구/발행 금액
|
||||
sum_bill DECIMAL(15,0), -- 청구합계
|
||||
totalbill DECIMAL(15,0), -- 총청구액
|
||||
issued_amount DECIMAL(15,0), -- 발행금액
|
||||
|
||||
-- 입금/미수금
|
||||
sum_deposit DECIMAL(15,0), -- 입금합계
|
||||
total_deposit DECIMAL(15,0), -- 총입금액
|
||||
sum_receivable DECIMAL(15,0), -- 미수금
|
||||
total_receivable DECIMAL(15,0), -- 총미수금
|
||||
receivable DECIMAL(15,0), -- 미수잔액
|
||||
issued_receivable DECIMAL(15,0), -- 발행미수금
|
||||
|
||||
-- 클레임
|
||||
sum_claimamount DECIMAL(15,0), -- 클레임금액
|
||||
|
||||
-- JSON 리스트
|
||||
accountList TEXT, -- 회계 리스트 (JSON)
|
||||
estimateList TEXT, -- 견적 리스트 (JSON)
|
||||
```
|
||||
|
||||
### accountList JSON 구조
|
||||
```json
|
||||
[
|
||||
{
|
||||
"date": "2025-01-15",
|
||||
"type": "입금",
|
||||
"amount": 5000000,
|
||||
"memo": "1차 입금"
|
||||
},
|
||||
{
|
||||
"date": "2025-02-15",
|
||||
"type": "청구",
|
||||
"amount": 10000000,
|
||||
"memo": "세금계산서 발행"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## SAM 마이그레이션 포인트
|
||||
|
||||
### 1. 회계 테이블 정규화
|
||||
```sql
|
||||
-- SAM: 회계 전표
|
||||
journal_entries (
|
||||
id,
|
||||
tenant_id,
|
||||
entry_number, -- 전표번호
|
||||
entry_date, -- 전표일자
|
||||
entry_type, -- income, expense, transfer
|
||||
|
||||
-- 계정 정보
|
||||
account_code, -- 계정코드 (계정과목 테이블 참조)
|
||||
sub_account_code, -- 하위계정코드
|
||||
|
||||
-- 금액
|
||||
debit_amount, -- 차변
|
||||
credit_amount, -- 대변
|
||||
|
||||
-- 상대방
|
||||
counterpart_id, -- 거래처 ID
|
||||
counterpart_name,
|
||||
|
||||
-- 결제 정보
|
||||
payment_method, -- cash, bank, card, note
|
||||
bank_account,
|
||||
due_date,
|
||||
|
||||
-- 참조
|
||||
reference_type, -- project, shipment, purchase
|
||||
reference_id,
|
||||
|
||||
description,
|
||||
created_by,
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 계정과목 테이블
|
||||
```sql
|
||||
-- SAM: 계정과목 마스터
|
||||
account_codes (
|
||||
id,
|
||||
tenant_id,
|
||||
code, -- 계정코드
|
||||
name, -- 계정명
|
||||
parent_id, -- 상위 계정
|
||||
level, -- 계층 레벨
|
||||
|
||||
account_type, -- asset, liability, equity, income, expense
|
||||
is_cash_account, -- 현금성 계정 여부
|
||||
is_receivable, -- 매출채권 여부
|
||||
is_payable, -- 매입채무 여부
|
||||
|
||||
description,
|
||||
is_active,
|
||||
sort_order
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 미수금 관리 분리
|
||||
```sql
|
||||
-- SAM: 채권 관리
|
||||
receivables (
|
||||
id,
|
||||
tenant_id,
|
||||
receivable_number,
|
||||
customer_id,
|
||||
|
||||
-- 채권 정보
|
||||
original_amount, -- 원금
|
||||
paid_amount, -- 입금액
|
||||
balance, -- 잔액 (computed)
|
||||
|
||||
-- 일자
|
||||
invoice_date, -- 청구일
|
||||
due_date, -- 만기일
|
||||
|
||||
-- 상태
|
||||
status, -- open, partial, paid, overdue, bad_debt
|
||||
|
||||
-- 약속 관리
|
||||
promised_date,
|
||||
promised_memo,
|
||||
|
||||
-- 참조
|
||||
project_id,
|
||||
invoice_id,
|
||||
|
||||
created_at,
|
||||
closed_at
|
||||
)
|
||||
|
||||
-- SAM: 채권 이력
|
||||
receivable_histories (
|
||||
id,
|
||||
receivable_id,
|
||||
action, -- created, payment, promise, overdue, bad_debt
|
||||
amount,
|
||||
note,
|
||||
created_by,
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
### 4. 전자어음 관리
|
||||
```sql
|
||||
-- SAM: 전자어음
|
||||
electronic_notes (
|
||||
id,
|
||||
tenant_id,
|
||||
note_number, -- 어음번호
|
||||
|
||||
-- 어음 정보
|
||||
drawer, -- 발행인
|
||||
payee, -- 수취인
|
||||
amount,
|
||||
issue_date, -- 발행일
|
||||
due_date, -- 만기일
|
||||
|
||||
-- 배서 정보
|
||||
endorsement_date, -- 배서일
|
||||
endorsee, -- 피배서인
|
||||
|
||||
-- 상태
|
||||
status, -- issued, endorsed, collected, dishonored
|
||||
|
||||
-- 참조
|
||||
parent_note_id, -- 분할 시 부모
|
||||
receivable_id,
|
||||
|
||||
created_at
|
||||
)
|
||||
```
|
||||
|
||||
### 5. 통합 재무 현황
|
||||
```sql
|
||||
-- SAM: 월별 재무 요약 (캐시 테이블)
|
||||
monthly_financial_summaries (
|
||||
id,
|
||||
tenant_id,
|
||||
year_month, -- YYYYMM
|
||||
|
||||
-- 수입
|
||||
total_income,
|
||||
income_by_category JSON,
|
||||
|
||||
-- 지출
|
||||
total_expense,
|
||||
expense_by_category JSON,
|
||||
|
||||
-- 채권/채무
|
||||
receivables_balance,
|
||||
payables_balance,
|
||||
|
||||
-- 현금 흐름
|
||||
cash_beginning,
|
||||
cash_ending,
|
||||
|
||||
calculated_at
|
||||
)
|
||||
```
|
||||
|
||||
## 특이사항
|
||||
|
||||
### 계정과목 JSON 관리
|
||||
- 계정과목이 `accountContents.json` 파일로 관리됨
|
||||
- 2단계 계층구조 (대분류 → 하위계정)
|
||||
- SAM에서는 DB 테이블로 정규화 권장
|
||||
|
||||
### 미수금-약속일 연동
|
||||
- `recordlist` 테이블로 거래처별 약속일/코멘트 관리
|
||||
- 최신 약속만 표시 (ORDER BY num DESC)
|
||||
- SAM에서는 이력 관리로 확장 필요
|
||||
|
||||
### work 테이블 금액 동기화
|
||||
- 공사별 회계 정보가 work 테이블에 집계됨
|
||||
- `accountList` JSON으로 상세 내역 저장
|
||||
- SAM에서는 정규화된 테이블로 관계 설정
|
||||
|
||||
## 참고 파일
|
||||
- `/account/insert.php` - 회계 저장 로직
|
||||
- `/account/_request.php` - 17개 요청 변수
|
||||
- `/account/accountContents.json` - 계정과목 설정
|
||||
- `/account/receivable.php` - 미수금 계산 로직
|
||||
- `/account/fetch_balance.php` - 잔액 조회
|
||||
695
projects/legacy-5130/08_SAM_COMPARISON.md
Normal file
695
projects/legacy-5130/08_SAM_COMPARISON.md
Normal file
@@ -0,0 +1,695 @@
|
||||
# 5130 vs SAM 비교 검증 리포트
|
||||
|
||||
**분석일**: 2025-12-04
|
||||
**분석 범위**: 5130 레거시 시스템 ↔ SAM 멀티테넌트 시스템
|
||||
**목적**: DB Upsert 전략 및 마이그레이션 가이드 도출
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
### 핵심 발견사항
|
||||
|
||||
**✅ SAM에서 잘 구현된 부분**:
|
||||
- 멀티테넌트 격리 (tenant_id + BelongsToTenant 스코프)
|
||||
- 가격 시스템 (price_histories: 시계열, 고객별, 다형성)
|
||||
- 설계 워크플로우 (models → model_versions → bom_templates)
|
||||
- 감사 로그 및 soft delete 일관성
|
||||
|
||||
**⚠️ 5130 → SAM 마이그레이션 시 고려사항**:
|
||||
1. **품목 타입 불일치**: 5130의 23개 자재 테이블 → SAM의 materials 단일 테이블
|
||||
2. **JSON 데이터 정규화**: 5130의 TEXT 컬럼 JSON → SAM의 정규화된 테이블
|
||||
3. **공사-AS 분리 필요**: 5130의 work 통합 테이블 → SAM의 projects + after_services 분리
|
||||
4. **계정과목 정규화**: 5130의 JSON 파일 → SAM의 account_codes 테이블
|
||||
|
||||
**마이그레이션 우선순위**:
|
||||
1. 🔴 자재/품목 (materials/products) - 핵심 마스터
|
||||
2. 🔴 BOM 구조 (product_components/bom_templates)
|
||||
3. 🟡 견적/주문 (estimates → orders 변환)
|
||||
4. 🟡 출하 (output → shipments 변환)
|
||||
5. 🟢 회계 (account → journal_entries 정규화)
|
||||
6. 🟢 품질/AS (work.AS필드 → after_services 분리)
|
||||
|
||||
---
|
||||
|
||||
## 1. 도메인별 상세 비교
|
||||
|
||||
### 1.1 자재 (Material) 비교
|
||||
|
||||
#### 5130 구조
|
||||
```sql
|
||||
-- 자재 유형별 개별 테이블 (23개)
|
||||
i_SUSplate, i_GIplate, i_SUScoil, i_slatcoil, i_bendingcoil,
|
||||
i_angle, i_pole, i_shaft, i_recpipe, i_motor, i_controller, ...
|
||||
|
||||
-- 공통 컬럼
|
||||
num, lot_no, inspection_date, supplier, item_name, specification,
|
||||
unit, received_qty, weight_kg, purchase_price_excl_vat,
|
||||
searchtag, update_log, is_deleted
|
||||
```
|
||||
|
||||
#### SAM 구조
|
||||
```sql
|
||||
-- 단일 materials 테이블
|
||||
materials (
|
||||
id, tenant_id, category_id, name, item_name, material_code,
|
||||
specification, unit, attributes JSON, options JSON,
|
||||
is_inspection, search_tag,
|
||||
created_by, updated_by, deleted_by, created_at, updated_at, deleted_at
|
||||
)
|
||||
|
||||
-- 카테고리로 유형 구분
|
||||
categories (id, parent_id, name, level, attributes JSON)
|
||||
```
|
||||
|
||||
#### 매핑 전략
|
||||
|
||||
| 5130 | SAM | 변환 로직 |
|
||||
|------|-----|----------|
|
||||
| `i_*` 테이블명 | `category_id` | 테이블명 → 카테고리 생성 |
|
||||
| `num` | `id` | 시퀀스 리매핑 |
|
||||
| `lot_no` | - | `lots` 테이블로 분리 |
|
||||
| `supplier` | - | `clients` 테이블 참조 |
|
||||
| `item_name` | `item_name` | 직접 매핑 |
|
||||
| `specification` | `specification` | 직접 매핑 |
|
||||
| `purchase_price` | - | `price_histories` 참조 |
|
||||
| `searchtag` | `search_tag` | 직접 매핑 |
|
||||
| `is_deleted` | `deleted_at` | 0→NULL, 1→timestamp |
|
||||
|
||||
#### DB Upsert 전략
|
||||
```php
|
||||
// 5130 → SAM 마이그레이션
|
||||
public function upsertMaterial(array $data): Material
|
||||
{
|
||||
// 1. 카테고리 매핑 (테이블명 → category_id)
|
||||
$category = $this->getCategoryByTableName($data['table_name']);
|
||||
|
||||
// 2. Upsert 조건: tenant_id + material_code (자연키)
|
||||
return Material::updateOrCreate(
|
||||
[
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'material_code' => $data['lot_no'] ?? $this->generateCode($data),
|
||||
],
|
||||
[
|
||||
'category_id' => $category->id,
|
||||
'name' => $data['item_name'] ?? $data['name'],
|
||||
'item_name' => $data['item_name'],
|
||||
'specification' => $data['specification'],
|
||||
'unit' => $data['unit'],
|
||||
'search_tag' => $data['searchtag'],
|
||||
// 기타 필드...
|
||||
]
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.2 품목/BOM (Product/Model) 비교
|
||||
|
||||
#### 5130 구조
|
||||
```sql
|
||||
-- 3단계 계층 구조
|
||||
models (model_id, model_name, major_category, finishing_type, guiderail_type)
|
||||
parts (part_id, model_id, part_name, spec, unit, quantity, unitprice)
|
||||
parts_sub (subpart_id, part_id, subpart_name, material, bendSum, plateSum, finalSum)
|
||||
```
|
||||
|
||||
#### SAM 구조
|
||||
```sql
|
||||
-- 설계 모델 (Design)
|
||||
models (id, tenant_id, code, name, category_id, lifecycle, is_active)
|
||||
model_versions (id, model_id, version_no, status, effective_from, effective_to)
|
||||
bom_templates (id, model_version_id, name, is_primary, calculation_schema)
|
||||
bom_template_items (id, bom_template_id, ref_type, ref_id, qty, waste_rate, calculation_formula)
|
||||
|
||||
-- 제품 BOM (Production)
|
||||
products (id, tenant_id, code, name, product_type, category_id, unit)
|
||||
product_components (id, parent_product_id, ref_type, ref_id, quantity, sort_order)
|
||||
```
|
||||
|
||||
#### 매핑 전략
|
||||
|
||||
| 5130 | SAM | 변환 로직 |
|
||||
|------|-----|----------|
|
||||
| `models` | `models` + `model_versions` | 버전 관리 추가 |
|
||||
| `parts` | `bom_template_items` | 설계 BOM |
|
||||
| `parts_sub` | `bom_template_items` (중첩) | 3단계 → 2단계 평탄화 |
|
||||
| `unitprice` | `price_histories` | 가격 이력으로 분리 |
|
||||
| `bendSum/plateSum` | `calculation_formula` | 계산식으로 변환 |
|
||||
|
||||
#### 계층 구조 평탄화 로직
|
||||
```php
|
||||
// 5130 3단계 → SAM 2단계 변환
|
||||
public function flattenBomHierarchy(array $model): array
|
||||
{
|
||||
$bomItems = [];
|
||||
|
||||
foreach ($model['parts'] as $part) {
|
||||
// 2단계 부품
|
||||
$bomItems[] = [
|
||||
'ref_type' => 'PRODUCT',
|
||||
'ref_id' => $this->findOrCreateProduct($part)->id,
|
||||
'qty' => $part['quantity'],
|
||||
'sort_order' => count($bomItems),
|
||||
];
|
||||
|
||||
// 3단계 하위 부품 (평탄화)
|
||||
foreach ($part['parts_sub'] ?? [] as $subpart) {
|
||||
$bomItems[] = [
|
||||
'ref_type' => 'MATERIAL',
|
||||
'ref_id' => $this->findOrCreateMaterial($subpart)->id,
|
||||
'qty' => $subpart['quantity'],
|
||||
'sort_order' => count($bomItems),
|
||||
'calculation_formula' => $this->convertFormula($subpart),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $bomItems;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.3 견적 (Estimate) 비교
|
||||
|
||||
#### 5130 구조
|
||||
```sql
|
||||
estimate (
|
||||
num, pjnum, indate, orderman, outworkplace,
|
||||
major_category, model_name, position, makeWidth, makeHeight,
|
||||
estimateList TEXT, -- JSON: 스크린 견적 항목
|
||||
estimateSlatList TEXT, -- JSON: 슬랫 견적 항목
|
||||
estimateList_auto TEXT, -- JSON: 자동계산 항목
|
||||
estimateSlatList_auto TEXT, -- JSON: 슬랫 자동계산
|
||||
estimateTotal, EstimateFirstSum, EstimateFinalSum,
|
||||
EstimateDiscountRate, EstimateDiscount,
|
||||
inspectionFee, steel, motor, warranty
|
||||
)
|
||||
```
|
||||
|
||||
#### SAM 구조
|
||||
```sql
|
||||
-- 견적 헤더/상세 분리
|
||||
estimates (
|
||||
id, tenant_id, estimate_number, customer_id, project_name,
|
||||
estimate_date, valid_until, status, total_amount,
|
||||
discount_rate, discount_amount, final_amount, created_by
|
||||
)
|
||||
|
||||
estimate_items (
|
||||
id, estimate_id, item_type, item_code, item_name,
|
||||
specification, unit, quantity, unit_price, amount, sort_order
|
||||
)
|
||||
```
|
||||
|
||||
#### JSON 데이터 정규화 전략
|
||||
```php
|
||||
// 5130 JSON → SAM 정규화 테이블
|
||||
public function normalizeEstimateItems(array $legacyEstimate): void
|
||||
{
|
||||
// 1. 견적 헤더 생성
|
||||
$estimate = Estimate::create([
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'estimate_number' => $legacyEstimate['pjnum'],
|
||||
'customer_id' => $this->findCustomer($legacyEstimate['secondord']),
|
||||
'project_name' => $legacyEstimate['outworkplace'],
|
||||
'estimate_date' => $legacyEstimate['indate'],
|
||||
'total_amount' => $legacyEstimate['estimateTotal'],
|
||||
'discount_rate' => $legacyEstimate['EstimateDiscountRate'],
|
||||
'final_amount' => $legacyEstimate['EstimateFinalSum'],
|
||||
]);
|
||||
|
||||
// 2. JSON 파싱 및 상세 생성
|
||||
$estimateList = json_decode($legacyEstimate['estimateList'], true) ?? [];
|
||||
foreach ($estimateList as $index => $item) {
|
||||
EstimateItem::create([
|
||||
'estimate_id' => $estimate->id,
|
||||
'item_type' => 'manual',
|
||||
'item_code' => $item['item_code'] ?? null,
|
||||
'item_name' => $item['item_name'],
|
||||
'specification' => $item['specification'] ?? null,
|
||||
'unit' => $item['unit'],
|
||||
'quantity' => $item['quantity'],
|
||||
'unit_price' => $item['unit_price'],
|
||||
'amount' => $item['amount'],
|
||||
'sort_order' => $index,
|
||||
]);
|
||||
}
|
||||
|
||||
// 3. 자동계산 항목 (estimateList_auto)
|
||||
$autoList = json_decode($legacyEstimate['estimateList_auto'], true) ?? [];
|
||||
foreach ($autoList as $index => $item) {
|
||||
EstimateItem::create([
|
||||
'estimate_id' => $estimate->id,
|
||||
'item_type' => 'auto_calculated',
|
||||
// ... 나머지 필드
|
||||
]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.4 생산/공사 (Production/Work) 비교
|
||||
|
||||
#### 5130 구조
|
||||
```sql
|
||||
work (
|
||||
num, work_state, workplacename, address, chargedperson,
|
||||
-- 발주처 (1차/2차)
|
||||
firstord, firstordman, firstordmantel,
|
||||
secondord, secondordman, secondordmantel,
|
||||
-- 일정
|
||||
workday, endworkday, cableday, endcableday,
|
||||
-- 작업자
|
||||
worker, cablestaff,
|
||||
-- AS (통합)
|
||||
asday, asman, asendday, asproday, setdate,
|
||||
aslist TEXT, asresult TEXT, ashistory TEXT, as_state,
|
||||
-- 클레임
|
||||
claimperson, claimtel, claimList TEXT,
|
||||
-- 금액
|
||||
sum_estimate, sum_bill, sum_receivable, sum_deposit,
|
||||
-- 회계 JSON
|
||||
accountList TEXT, estimateList TEXT
|
||||
)
|
||||
```
|
||||
|
||||
#### SAM 구조 제안
|
||||
```sql
|
||||
-- 프로젝트 분리
|
||||
projects (
|
||||
id, tenant_id, project_number, project_name, customer_id,
|
||||
status, contracted_date, start_date, end_date
|
||||
)
|
||||
|
||||
project_phases (
|
||||
id, project_id, phase_type, planned_start, planned_end,
|
||||
actual_start, actual_end, assigned_team, status
|
||||
)
|
||||
|
||||
-- AS 분리
|
||||
after_services (
|
||||
id, tenant_id, project_id, as_number, status,
|
||||
received_date, received_by, requester_name, requester_phone,
|
||||
scheduled_date, completed_date, handler_id,
|
||||
fee_type, fee_amount, issue_description, result_description
|
||||
)
|
||||
|
||||
-- 클레임 분리
|
||||
claims (
|
||||
id, tenant_id, project_id, after_service_id,
|
||||
claim_number, claim_type, claim_date, description,
|
||||
status, resolution, claimed_amount, approved_amount
|
||||
)
|
||||
```
|
||||
|
||||
#### AS 분리 마이그레이션 전략
|
||||
```php
|
||||
// work 테이블의 AS 필드 → after_services 테이블
|
||||
public function extractAfterServices(array $workData): void
|
||||
{
|
||||
// AS 대상 여부 확인
|
||||
if ($workData['as_check'] != 1 && empty($workData['asday'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 프로젝트 먼저 생성/조회
|
||||
$project = $this->findOrCreateProject($workData);
|
||||
|
||||
// AS 레코드 생성
|
||||
AfterService::create([
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'project_id' => $project->id,
|
||||
'as_number' => $this->generateAsNumber(),
|
||||
'status' => $this->mapAsStatus($workData['as_state']),
|
||||
'received_date' => $workData['asday'],
|
||||
'scheduled_date' => $workData['asproday'],
|
||||
'setting_date' => $workData['setdate'],
|
||||
'completed_date' => $workData['asendday'],
|
||||
'requester_name' => $workData['asorderman'],
|
||||
'requester_phone' => $workData['asordermantel'],
|
||||
'handler_id' => $this->findUser($workData['asman']),
|
||||
'fee_type' => $workData['asfee'] == 0 ? 'free' : 'paid',
|
||||
'fee_amount' => $workData['asfee_estimate'] ?? 0,
|
||||
'issue_description' => $workData['aslist'],
|
||||
'result_description' => $workData['asresult'],
|
||||
]);
|
||||
}
|
||||
|
||||
// AS 상태 매핑
|
||||
private function mapAsStatus(string $legacyStatus): string
|
||||
{
|
||||
return match ($legacyStatus) {
|
||||
'미접수' => 'pending',
|
||||
'접수완료' => 'received',
|
||||
'처리예약', '세팅예약' => 'scheduled',
|
||||
'처리완료' => 'completed',
|
||||
default => 'pending',
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.5 출하 (Shipping/Output) 비교
|
||||
|
||||
#### 5130 구조
|
||||
```sql
|
||||
output (
|
||||
num, outdate, indate, orderman, outworkplace, outputplace,
|
||||
receiver, phone, delivery,
|
||||
screen VARCHAR, screen_su, screen_m2, screenlist TEXT,
|
||||
slat VARCHAR, slat_su, slat_m2, slatlist TEXT,
|
||||
ACIregDate, ACIaskDate, ACIdoneDate, ACImemo, ACIgroupCode,
|
||||
deliveryfeeList TEXT,
|
||||
estimate_num, prodCode, lotNum, warrantyNum
|
||||
)
|
||||
|
||||
output_extra (
|
||||
parent_num, detailJson TEXT, estimateList TEXT, estimateSlatList TEXT,
|
||||
estimateTotal, ET_unapproved, ET_total,
|
||||
motorList TEXT, bendList TEXT, controllerList TEXT, accountList TEXT
|
||||
)
|
||||
```
|
||||
|
||||
#### SAM 구조 제안
|
||||
```sql
|
||||
-- 출하 헤더
|
||||
shipments (
|
||||
id, tenant_id, shipment_number, project_id, customer_id,
|
||||
ship_date, status, delivery_address, receiver_name, receiver_phone,
|
||||
carrier, tracking_number
|
||||
)
|
||||
|
||||
-- 출하 상세
|
||||
shipment_items (
|
||||
id, shipment_id, item_type, item_code, quantity, lot_number, note
|
||||
)
|
||||
|
||||
-- ACI 분리
|
||||
aci_inspections (
|
||||
id, shipment_id, inspection_number, request_date, inspection_date,
|
||||
result, inspector, certificate_number, documents JSON
|
||||
)
|
||||
|
||||
-- 배송비 분리
|
||||
delivery_fees (
|
||||
id, shipment_id, carrier, fee_amount, payment_type, paid_date
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1.6 회계 (Accounting) 비교
|
||||
|
||||
#### 5130 구조
|
||||
```sql
|
||||
account (
|
||||
num, registDate, dueDate, inoutsep, content, contentSub,
|
||||
content_detail, amount, bankbook, secondordnum,
|
||||
endorsementDate, parentEBNum,
|
||||
first_writer, update_log, searchtag, is_deleted
|
||||
)
|
||||
|
||||
-- accountContents.json (계정과목)
|
||||
{
|
||||
"수입": {"거래처 수금": {...}, "차입금": {...}, ...},
|
||||
"지출": {"자재비": {...}, "급여": {...}, ...}
|
||||
}
|
||||
```
|
||||
|
||||
#### SAM 구조 제안
|
||||
```sql
|
||||
-- 계정과목 정규화
|
||||
account_codes (
|
||||
id, tenant_id, code, name, parent_id, level,
|
||||
account_type, is_cash_account, is_receivable, is_payable,
|
||||
description, is_active, sort_order
|
||||
)
|
||||
|
||||
-- 회계 전표
|
||||
journal_entries (
|
||||
id, tenant_id, entry_number, entry_date, entry_type,
|
||||
account_code, sub_account_code,
|
||||
debit_amount, credit_amount,
|
||||
counterpart_id, counterpart_name, payment_method, bank_account,
|
||||
due_date, reference_type, reference_id, description, created_by
|
||||
)
|
||||
|
||||
-- 채권 관리
|
||||
receivables (
|
||||
id, tenant_id, receivable_number, customer_id,
|
||||
original_amount, paid_amount, balance,
|
||||
invoice_date, due_date, status, promised_date, promised_memo,
|
||||
project_id, invoice_id
|
||||
)
|
||||
```
|
||||
|
||||
#### 계정과목 JSON → 테이블 변환
|
||||
```php
|
||||
// accountContents.json → account_codes 테이블
|
||||
public function migrateAccountCodes(array $jsonContent): void
|
||||
{
|
||||
// 1. 대분류 (수입/지출)
|
||||
foreach ($jsonContent as $mainType => $accounts) {
|
||||
$mainAccount = AccountCode::create([
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'code' => $mainType === '수입' ? 'INCOME' : 'EXPENSE',
|
||||
'name' => $mainType,
|
||||
'parent_id' => null,
|
||||
'level' => 1,
|
||||
'account_type' => $mainType === '수입' ? 'income' : 'expense',
|
||||
]);
|
||||
|
||||
// 2. 중분류
|
||||
foreach ($accounts as $accountName => $accountData) {
|
||||
$subAccount = AccountCode::create([
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'code' => $this->generateAccountCode($accountName),
|
||||
'name' => $accountName,
|
||||
'parent_id' => $mainAccount->id,
|
||||
'level' => 2,
|
||||
'description' => $accountData['description'] ?? null,
|
||||
]);
|
||||
|
||||
// 3. 하위계정
|
||||
foreach ($accountData['하위계정'] ?? [] as $subAccountName => $subData) {
|
||||
AccountCode::create([
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'code' => $this->generateAccountCode($subAccountName),
|
||||
'name' => is_string($subAccountName) ? $subAccountName : $subData,
|
||||
'parent_id' => $subAccount->id,
|
||||
'level' => 3,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 공통 변환 패턴
|
||||
|
||||
### 2.1 Soft Delete 변환
|
||||
```php
|
||||
// 5130: is_deleted TINYINT → SAM: deleted_at TIMESTAMP
|
||||
$deletedAt = $legacyData['is_deleted'] == 1
|
||||
? Carbon::now()->toDateTimeString()
|
||||
: null;
|
||||
```
|
||||
|
||||
### 2.2 searchtag 변환
|
||||
```php
|
||||
// 5130: searchtag (공백 구분) → SAM: search_tag (동일)
|
||||
// SAM은 Laravel Scout + Meilisearch 권장
|
||||
$searchTag = $legacyData['searchtag'];
|
||||
// 또는 동적 생성
|
||||
$searchTag = implode(' ', array_filter([
|
||||
$data['name'],
|
||||
$data['code'],
|
||||
$data['specification'],
|
||||
// ...
|
||||
]));
|
||||
```
|
||||
|
||||
### 2.3 update_log 변환
|
||||
```php
|
||||
// 5130: update_log TEXT (누적) → SAM: audit_logs 테이블
|
||||
public function migrateUpdateLog(string $entityType, int $entityId, ?string $updateLog): void
|
||||
{
|
||||
if (empty($updateLog)) return;
|
||||
|
||||
// 로그 파싱 (형식: "2025-01-15 10:30:00 - 홍길동 내용")
|
||||
$lines = explode("
", $updateLog);
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) - (\S+) (.*)$/', $line, $matches)) {
|
||||
AuditLog::create([
|
||||
'tenant_id' => $this->tenantId(),
|
||||
'target_type' => $entityType,
|
||||
'target_id' => $entityId,
|
||||
'action' => 'updated',
|
||||
'after' => ['note' => $matches[3]],
|
||||
'actor_id' => $this->findUserByName($matches[2]),
|
||||
'created_at' => $matches[1],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 JSON TEXT → 정규화 테이블
|
||||
```php
|
||||
// 공통 JSON 파싱 유틸
|
||||
public function parseJsonField(?string $jsonText): array
|
||||
{
|
||||
if (empty($jsonText)) return [];
|
||||
|
||||
$decoded = json_decode($jsonText, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
Log::warning("JSON parse error: " . json_last_error_msg());
|
||||
return [];
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 마이그레이션 실행 전략
|
||||
|
||||
### 3.1 단계별 마이그레이션 계획
|
||||
|
||||
#### Phase 1: 마스터 데이터 (1-2주)
|
||||
```
|
||||
1. categories (5130 테이블명 → SAM 카테고리)
|
||||
2. clients (5130 발주처 → SAM 거래처)
|
||||
3. materials (5130 i_* 테이블들 → SAM materials)
|
||||
4. products (5130 models → SAM products)
|
||||
5. account_codes (5130 JSON → SAM account_codes)
|
||||
```
|
||||
|
||||
#### Phase 2: 구조 데이터 (2-3주)
|
||||
```
|
||||
6. bom_templates (5130 parts → SAM bom_template_items)
|
||||
7. product_components (5130 parts_sub → SAM product_components)
|
||||
8. price_histories (5130 unitprice 필드들 → SAM price_histories)
|
||||
```
|
||||
|
||||
#### Phase 3: 트랜잭션 데이터 (3-4주)
|
||||
```
|
||||
9. projects (5130 work → SAM projects)
|
||||
10. project_phases (5130 work 일정필드 → SAM project_phases)
|
||||
11. estimates (5130 estimate → SAM estimates + estimate_items)
|
||||
12. shipments (5130 output → SAM shipments + shipment_items)
|
||||
13. after_services (5130 work.AS필드 → SAM after_services)
|
||||
14. journal_entries (5130 account → SAM journal_entries)
|
||||
```
|
||||
|
||||
#### Phase 4: 검증 및 정리 (1-2주)
|
||||
```
|
||||
15. 데이터 정합성 검증
|
||||
16. 누락 데이터 보정
|
||||
17. 레거시 참조 정리
|
||||
18. 성능 최적화
|
||||
```
|
||||
|
||||
### 3.2 Upsert 전략 요약
|
||||
|
||||
| 도메인 | Upsert Key | 충돌 처리 |
|
||||
|-------|-----------|----------|
|
||||
| materials | tenant_id + material_code | UPDATE |
|
||||
| products | tenant_id + code | UPDATE |
|
||||
| categories | tenant_id + name | UPDATE |
|
||||
| estimates | tenant_id + estimate_number | UPDATE |
|
||||
| shipments | tenant_id + shipment_number | UPDATE |
|
||||
| journal_entries | tenant_id + entry_number | UPDATE |
|
||||
| after_services | tenant_id + as_number | UPDATE |
|
||||
|
||||
### 3.3 롤백 전략
|
||||
```php
|
||||
// 트랜잭션 기반 마이그레이션
|
||||
DB::transaction(function () use ($legacyData) {
|
||||
// 마이그레이션 로직
|
||||
}, 5); // 5회 재시도
|
||||
|
||||
// 실패 시 백업 테이블에서 복원
|
||||
// CREATE TABLE _backup_materials AS SELECT * FROM materials;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 검증 체크리스트
|
||||
|
||||
### 4.1 데이터 정합성 검증
|
||||
```sql
|
||||
-- 1. 레코드 수 비교
|
||||
SELECT '5130' as source, COUNT(*) FROM legacy.i_SUSplate
|
||||
UNION ALL
|
||||
SELECT 'SAM' as source, COUNT(*) FROM sam.materials WHERE category_id = ?;
|
||||
|
||||
-- 2. 금액 합계 비교
|
||||
SELECT SUM(amount) FROM legacy.account WHERE is_deleted = 0
|
||||
UNION ALL
|
||||
SELECT SUM(debit_amount) FROM sam.journal_entries WHERE entry_type = 'expense';
|
||||
|
||||
-- 3. 참조 무결성 검증
|
||||
SELECT pc.id FROM product_components pc
|
||||
LEFT JOIN products p ON pc.ref_type = 'PRODUCT' AND pc.ref_id = p.id
|
||||
LEFT JOIN materials m ON pc.ref_type = 'MATERIAL' AND pc.ref_id = m.id
|
||||
WHERE p.id IS NULL AND m.id IS NULL;
|
||||
```
|
||||
|
||||
### 4.2 비즈니스 로직 검증
|
||||
- [ ] 견적 금액 계산 결과 일치
|
||||
- [ ] BOM 전개 결과 일치
|
||||
- [ ] AS 상태 흐름 정상 작동
|
||||
- [ ] 미수금 계산 결과 일치
|
||||
- [ ] 재고 수량 계산 결과 일치
|
||||
|
||||
### 4.3 성능 검증
|
||||
- [ ] 목록 조회 응답 시간 < 500ms
|
||||
- [ ] BOM 전개 응답 시간 < 1s
|
||||
- [ ] 견적 산출 응답 시간 < 2s
|
||||
|
||||
---
|
||||
|
||||
## 5. 결론
|
||||
|
||||
### 5.1 핵심 권장사항
|
||||
|
||||
1. **단계별 마이그레이션 필수**: 한 번에 전체 마이그레이션은 리스크가 높음
|
||||
2. **JSON 데이터 정규화 우선**: 5130의 TEXT JSON 필드들을 SAM의 정규화된 테이블로 변환
|
||||
3. **AS/클레임 분리**: work 테이블의 AS 필드를 별도 테이블로 분리하여 이력 관리 강화
|
||||
4. **가격 시스템 활용**: SAM의 price_histories 테이블로 가격 이력 통합 관리
|
||||
5. **감사 로그 마이그레이션**: 5130의 update_log를 SAM의 audit_logs로 변환
|
||||
|
||||
### 5.2 예상 공수
|
||||
|
||||
| 단계 | 예상 공수 | 주요 작업 |
|
||||
|-----|---------|----------|
|
||||
| Phase 1 | 1-2주 | 마스터 데이터 마이그레이션 |
|
||||
| Phase 2 | 2-3주 | 구조 데이터 (BOM, 가격) |
|
||||
| Phase 3 | 3-4주 | 트랜잭션 데이터 |
|
||||
| Phase 4 | 1-2주 | 검증 및 정리 |
|
||||
| **합계** | **7-11주** | - |
|
||||
|
||||
### 5.3 다음 액션
|
||||
1. 마이그레이션 스크립트 프로토타입 작성
|
||||
2. 테스트 데이터로 검증
|
||||
3. 운영 데이터 샘플 마이그레이션
|
||||
4. 전체 마이그레이션 실행
|
||||
|
||||
---
|
||||
|
||||
**문서 버전**: v1.0
|
||||
**작성일**: 2025-12-04
|
||||
**작성자**: Claude Code
|
||||
**참조 문서**:
|
||||
- 5130 분석 문서 (01~07)
|
||||
- SAM_Item_DB_API_Analysis_v3_FINAL.md
|
||||
- SAM_Item_Management_DB_Modeling_Analysis.md
|
||||
397
projects/legacy-5130/draw-module.md
Normal file
397
projects/legacy-5130/draw-module.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# Drawing Module API 문서
|
||||
|
||||
## 📋 개요
|
||||
|
||||
Drawing Module은 웹 브라우저에서 사용할 수 있는 독립적인 Canvas 기반 그리기 도구입니다. 모달 형태의 UI를 제공하며, 다양한 그리기 기능과 이미지 편집 기능을 포함합니다.
|
||||
|
||||
## 🚀 빠른 시작
|
||||
|
||||
### 1. 파일 포함
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Bootstrap CSS (선택사항) -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons (선택사항) -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||
<!-- Drawing Module CSS (필수) -->
|
||||
<link href="css/drawingModule.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<!-- jQuery (필수) -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- Drawing Module JS (필수) -->
|
||||
<script src="js/drawingModule.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 2. 기본 사용법
|
||||
|
||||
```javascript
|
||||
// 기본 인스턴스 생성
|
||||
const drawer = new DrawingModule({
|
||||
container: 'body',
|
||||
onSave: (data) => {
|
||||
console.log('저장된 이미지:', data.imageData);
|
||||
console.log('저장 시간:', data.timestamp);
|
||||
}
|
||||
});
|
||||
|
||||
// 그리기 도구 표시
|
||||
drawer.show();
|
||||
```
|
||||
|
||||
## 📊 API 참조
|
||||
|
||||
### 생성자 (Constructor)
|
||||
|
||||
```javascript
|
||||
new DrawingModule(options)
|
||||
```
|
||||
|
||||
#### 옵션 매개변수
|
||||
|
||||
| 옵션 | 타입 | 기본값 | 설명 |
|
||||
|------|------|--------|------|
|
||||
| `container` | string | 'body' | 모달을 생성할 컨테이너 선택자 |
|
||||
| `width` | number | 800 | 모달의 전체 너비 (px) |
|
||||
| `height` | number | 600 | 모달의 전체 높이 (px) |
|
||||
| `canvasWidth` | number | 320 | 캔버스의 실제 너비 (px) |
|
||||
| `canvasHeight` | number | 240 | 캔버스의 실제 높이 (px) |
|
||||
| `title` | string | '그리기 도구' | 모달 헤더 제목 |
|
||||
| `initialImage` | string | null | 초기에 로드할 이미지 URL 또는 데이터 URL |
|
||||
| `onSave` | function | null | 저장 시 호출되는 콜백 함수 |
|
||||
| `onCancel` | function | null | 취소 시 호출되는 콜백 함수 |
|
||||
|
||||
#### 콜백 함수 시그니처
|
||||
|
||||
**onSave 콜백:**
|
||||
```javascript
|
||||
onSave: (data) => {
|
||||
// data.imageData - base64 인코딩된 이미지 데이터
|
||||
// data.timestamp - 저장 시각 (Date 객체)
|
||||
// data.width - 캔버스 너비
|
||||
// data.height - 캔버스 높이
|
||||
}
|
||||
```
|
||||
|
||||
**onCancel 콜백:**
|
||||
```javascript
|
||||
onCancel: () => {
|
||||
// 사용자가 취소 버튼을 클릭했을 때 호출
|
||||
}
|
||||
```
|
||||
|
||||
### 메서드 (Methods)
|
||||
|
||||
#### show()
|
||||
그리기 도구 모달을 표시합니다.
|
||||
|
||||
```javascript
|
||||
drawer.show();
|
||||
```
|
||||
|
||||
#### hide()
|
||||
그리기 도구 모달을 숨깁니다.
|
||||
|
||||
```javascript
|
||||
drawer.hide();
|
||||
```
|
||||
|
||||
#### loadImage(imageUrl)
|
||||
캔버스에 이미지를 로드합니다.
|
||||
|
||||
```javascript
|
||||
drawer.loadImage('path/to/image.png');
|
||||
// 또는 데이터 URL
|
||||
drawer.loadImage('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==');
|
||||
```
|
||||
|
||||
#### clear()
|
||||
캔버스의 모든 내용을 지웁니다.
|
||||
|
||||
```javascript
|
||||
drawer.clear();
|
||||
```
|
||||
|
||||
#### getImageData()
|
||||
현재 캔버스의 이미지 데이터를 반환합니다.
|
||||
|
||||
```javascript
|
||||
const imageData = drawer.getImageData();
|
||||
console.log(imageData); // base64 문자열
|
||||
```
|
||||
|
||||
## 🎨 주요 기능
|
||||
|
||||
### 그리기 모드
|
||||
- **점연결 (Polyline)**: 클릭한 점들을 연결하여 선을 그립니다
|
||||
- **직선 (Line)**: 시작점과 끝점을 클릭하여 직선을 그립니다
|
||||
- **자유선 (Free)**: 마우스를 드래그하여 자유롭게 선을 그립니다
|
||||
|
||||
### 추가 기능
|
||||
- **직각 모드**: 수평/수직선만 그리기 (체크박스로 활성화)
|
||||
- **색상 선택**: 16진수 컬러 피커로 선 색상 변경
|
||||
- **선 굵기 조절**: 1-10px 범위의 슬라이더로 선 굵기 조정
|
||||
- **지우개**: 원형 지우개로 특정 영역 삭제 (크기 조절 가능)
|
||||
- **텍스트 추가**: 클릭한 위치에 텍스트 입력
|
||||
- **실행취소 (Undo)**: 마지막 작업 되돌리기
|
||||
- **초기화**: 캔버스의 모든 내용 삭제
|
||||
- **터치 지원**: 모바일/태블릿 디바이스 터치 이벤트 지원
|
||||
|
||||
## 📱 사용 예제
|
||||
|
||||
### 1. 기본 그리기 도구
|
||||
|
||||
```javascript
|
||||
const basicDrawer = new DrawingModule({
|
||||
container: 'body',
|
||||
onSave: (data) => {
|
||||
// 이미지를 로컬 저장소에 저장
|
||||
localStorage.setItem('drawing', data.imageData);
|
||||
alert('그리기가 저장되었습니다!');
|
||||
}
|
||||
});
|
||||
basicDrawer.show();
|
||||
```
|
||||
|
||||
### 2. 커스텀 크기 캔버스
|
||||
|
||||
```javascript
|
||||
const largeDrawer = new DrawingModule({
|
||||
container: '#myContainer',
|
||||
canvasWidth: 640,
|
||||
canvasHeight: 480,
|
||||
title: '큰 캔버스 그리기',
|
||||
onSave: (data) => {
|
||||
console.log(`캔버스 크기: ${data.width}x${data.height}`);
|
||||
downloadImage(data.imageData, 'large-drawing.png');
|
||||
}
|
||||
});
|
||||
largeDrawer.show();
|
||||
```
|
||||
|
||||
### 3. 이미지 편집
|
||||
|
||||
```javascript
|
||||
const imageEditor = new DrawingModule({
|
||||
container: 'body',
|
||||
initialImage: '/path/to/existing-image.jpg',
|
||||
title: '이미지 편집',
|
||||
onSave: (data) => {
|
||||
// 편집된 이미지를 서버에 업로드
|
||||
uploadImageToServer(data.imageData);
|
||||
},
|
||||
onCancel: () => {
|
||||
console.log('이미지 편집이 취소되었습니다.');
|
||||
}
|
||||
});
|
||||
imageEditor.show();
|
||||
```
|
||||
|
||||
### 4. 서버로 이미지 저장
|
||||
|
||||
```javascript
|
||||
const drawer = new DrawingModule({
|
||||
container: 'body',
|
||||
onSave: (data) => {
|
||||
// AJAX로 서버에 이미지 전송
|
||||
$.ajax({
|
||||
url: '/api/save-drawing',
|
||||
method: 'POST',
|
||||
data: {
|
||||
image: data.imageData,
|
||||
timestamp: data.timestamp.toISOString(),
|
||||
width: data.width,
|
||||
height: data.height
|
||||
},
|
||||
success: function(response) {
|
||||
alert('서버에 저장되었습니다!');
|
||||
console.log('저장된 이미지 ID:', response.imageId);
|
||||
},
|
||||
error: function(error) {
|
||||
alert('저장에 실패했습니다: ' + error.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
drawer.show();
|
||||
```
|
||||
|
||||
### 5. 다중 인스턴스
|
||||
|
||||
```javascript
|
||||
// 동시에 여러 개의 그리기 도구 사용
|
||||
const drawer1 = new DrawingModule({
|
||||
container: 'body',
|
||||
title: '그리기 1',
|
||||
canvasWidth: 200,
|
||||
canvasHeight: 200,
|
||||
onSave: (data) => console.log('Drawing 1 saved')
|
||||
});
|
||||
|
||||
const drawer2 = new DrawingModule({
|
||||
container: 'body',
|
||||
title: '그리기 2',
|
||||
canvasWidth: 300,
|
||||
canvasHeight: 200,
|
||||
onSave: (data) => console.log('Drawing 2 saved')
|
||||
});
|
||||
|
||||
drawer1.show();
|
||||
setTimeout(() => drawer2.show(), 100); // 약간의 지연
|
||||
```
|
||||
|
||||
## 🛠️ 유틸리티 함수
|
||||
|
||||
### 이미지 다운로드 함수
|
||||
|
||||
```javascript
|
||||
function downloadImage(dataUrl, filename) {
|
||||
const link = document.createElement('a');
|
||||
link.download = filename;
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
}
|
||||
|
||||
// 사용법
|
||||
const drawer = new DrawingModule({
|
||||
onSave: (data) => {
|
||||
downloadImage(data.imageData, 'my-drawing.png');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Base64를 Blob으로 변환
|
||||
|
||||
```javascript
|
||||
function dataURLtoBlob(dataURL) {
|
||||
const arr = dataURL.split(',');
|
||||
const mime = arr[0].match(/:(.*?);/)[1];
|
||||
const bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
|
||||
return new Blob([u8arr], {type: mime});
|
||||
}
|
||||
|
||||
// 사용법
|
||||
const drawer = new DrawingModule({
|
||||
onSave: (data) => {
|
||||
const blob = dataURLtoBlob(data.imageData);
|
||||
const formData = new FormData();
|
||||
formData.append('image', blob, 'drawing.png');
|
||||
|
||||
// FormData를 서버에 전송
|
||||
fetch('/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 🎯 파일 구조
|
||||
|
||||
```
|
||||
project/
|
||||
├── test_drawing.php # 테스트 페이지 (PHP)
|
||||
├── css/
|
||||
│ └── drawingModule.css # 스타일시트
|
||||
├── js/
|
||||
│ └── drawingModule.js # 메인 JavaScript 모듈
|
||||
└── drawModule.md # 이 문서
|
||||
```
|
||||
|
||||
## 🔧 커스터마이징
|
||||
|
||||
### CSS 커스터마이징
|
||||
|
||||
주요 CSS 클래스들을 오버라이드하여 스타일을 변경할 수 있습니다:
|
||||
|
||||
```css
|
||||
/* 모달 배경색 변경 */
|
||||
.dm-modal {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
/* 버튼 색상 변경 */
|
||||
.dm-btn-primary {
|
||||
background-color: #custom-color;
|
||||
}
|
||||
|
||||
/* 캔버스 테두리 스타일 변경 */
|
||||
#dmCanvas {
|
||||
border: 3px solid #custom-border-color;
|
||||
}
|
||||
```
|
||||
|
||||
### JavaScript 이벤트 훅
|
||||
|
||||
모듈의 동작을 커스터마이징하려면 콜백을 사용하세요:
|
||||
|
||||
```javascript
|
||||
const drawer = new DrawingModule({
|
||||
onSave: (data) => {
|
||||
// 저장 전 검증
|
||||
if (data.width < 100 || data.height < 100) {
|
||||
alert('그림이 너무 작습니다!');
|
||||
return;
|
||||
}
|
||||
|
||||
// 커스텀 저장 로직
|
||||
customSaveFunction(data);
|
||||
},
|
||||
onCancel: () => {
|
||||
// 취소 시 정리 작업
|
||||
cleanupResources();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 🚨 주의사항
|
||||
|
||||
1. **jQuery 의존성**: 이 모듈은 jQuery에 의존하므로 jQuery를 먼저 로드해야 합니다.
|
||||
|
||||
2. **CSS 파일 필수**: `drawingModule.css` 파일이 없으면 UI가 제대로 표시되지 않습니다.
|
||||
|
||||
3. **브라우저 호환성**: HTML5 Canvas를 지원하는 브라우저에서만 작동합니다.
|
||||
|
||||
4. **이미지 크기 제한**: 매우 큰 캔버스는 브라우저 성능에 영향을 줄 수 있습니다.
|
||||
|
||||
5. **메모리 관리**: 여러 인스턴스를 사용할 때는 사용하지 않는 인스턴스를 적절히 정리하세요.
|
||||
|
||||
## 🐛 문제 해결
|
||||
|
||||
### 일반적인 문제들
|
||||
|
||||
**Q: 모달이 표시되지 않아요.**
|
||||
A: CSS 파일이 제대로 로드되었는지, 그리고 `show()` 메서드를 호출했는지 확인하세요.
|
||||
|
||||
**Q: 그리기가 작동하지 않아요.**
|
||||
A: jQuery가 로드되었는지, 그리고 JavaScript 콘솔에 오류가 없는지 확인하세요.
|
||||
|
||||
**Q: 이미지 저장이 안 돼요.**
|
||||
A: `onSave` 콜백이 제대로 설정되었는지 확인하세요.
|
||||
|
||||
**Q: 모바일에서 터치가 작동하지 않아요.**
|
||||
A: 최신 버전의 모듈을 사용하고 있는지 확인하세요. 터치 이벤트는 자동으로 처리됩니다.
|
||||
|
||||
## 📄 라이선스
|
||||
|
||||
이 모듈은 MIT 라이선스 하에 배포됩니다.
|
||||
|
||||
## 🔄 업데이트 내역
|
||||
|
||||
- **v1.0.0**: 초기 릴리스
|
||||
- 기본 그리기 기능
|
||||
- 모달 UI
|
||||
- 이미지 로드/저장
|
||||
- 터치 지원
|
||||
Reference in New Issue
Block a user