diff --git a/문서/README.md b/문서/README.md new file mode 100644 index 0000000..62bcb2f --- /dev/null +++ b/문서/README.md @@ -0,0 +1,25 @@ +# saman-statis (사내 ERP 그룹웨어 통계 시스템) + +본 프로젝트는 사내 ERP 내에서 사용되는 통계 및 데이터 시각화 기능을 제공하는 내부 시스템입니다. PHP와 Smarty 템플릿 엔진을 기반으로 구축되었으며, 프론트엔드는 JavaScript, CSS, W2UI Grid, JqGrid 등을 활용하여 구성되어 있습니다. + +--- + +## 🛠 기술 스택 (Tech Stack) + +* **DB:** Oracle 11g +* **Backend:** PHP 5.2.12 +* **Template Engine:** Smarty +* **Frontend:** JavaScript, HTML5, CSS3, +* **Web Server:** Apache + +--- + +## 📂 디렉토리 구조 (Directory Structure) + +```text +├── Satis/ # 핵심 로직 및 모듈 폴더(Controller, model) +├── Smarty/ # Smarty 템플릿 파일 (.tpl) 및 컴파일 폴더 +├── SmartyConfig.php # Smarty 엔진 설정 및 초기화 파일 +├── index.php # 시스템 메인 진입점 (Entry Point) +├── index_org.php # 백업 또는 원본 인덱스 파일 +└── phpinfo.php # 서버 환경 확인용 스크립트 (운영 환경에서는 삭제 권장) \ No newline at end of file diff --git a/문서/architecture_high.md b/문서/architecture_high.md new file mode 100644 index 0000000..96aa484 --- /dev/null +++ b/문서/architecture_high.md @@ -0,0 +1,172 @@ +# (주)삼안 ERP 및 그룹웨어 시스템 (Satis) 하이레벨 아키텍처 (High-Level Architecture) + +본 문서는 (주)삼안의 **ERP 및 그룹웨어 시스템(`saman-statis` / `Satis`)** 프로젝트의 전체 하이레벨 아키텍처(HLA) 명세서입니다. +시스템의 전체 개요, 계층형 구조, 기술 스택, 업무 도메인뿐만 아니라 **인프라/배포 아키텍처, 보안/인증 아키텍처, 외부 시스템 연동 구조**를 종합적으로 포함합니다. +*(참고: 압축파일 `*.zip`은 분석에서 제외하였습니다.)* + +--- + +## 1. 프로젝트 개요 (Project Overview) + +* **프로젝트명**: 삼안 ERP / 그룹웨어 (`saman-statis` / `Satis`) +* **운영 도메인**: `satis2.samaneng.com`, `erp.samaneng.com` +* **시스템 성격**: 엔지니어링/건설 분야 기업 자원 관리(ERP) 및 통합 그룹웨어 +* **주요 기능**: 인사/급여, 회계/전표, 프로젝트/현장 공정, 영업/기성, 전자결재, 고정자산, 출장 정산, 경영분석 등 + +--- + +## 2. 하이레벨 시스템 아키텍처 (High-Level System Architecture) + +```mermaid +graph TD + subgraph Client Tier + Browser["Web Browser
(HTML5, jQuery, jqGrid, w2ui)"] + end + + subgraph Web / Presentation Tier + WebServer["Web Server
(Windows Server / APM_Setup)"] + Smarty["Smarty Template Engine v2.6
(Smarty/templates/Satis/*.tpl)"] + end + + subgraph Application Tier + Controller["MVC Controllers
(Satis/sys/controller/*)"] + AuthModule["Security & Auth Engine
(AuthClass.php / Session)"] + BizLogic["Business Models & Utility
(Satis/sys/model/*, OracleClass.php)"] + end + + subgraph Data & Integration Tier + OracleDB[("Main Oracle Database
(OCI Connection)")] + iCubeDB[("Douzone iCube ERP
(MS-SQL: DZICUBE)")] + IntranetDB[("Intranet Database
(MySQL: hallaerp)")] + end + + Browser <-->|HTTPS / HTTP| WebServer + WebServer <--> Smarty + WebServer <--> Controller + Controller <--> AuthModule + Controller <--> BizLogic + BizLogic <-->|OCI Connection| OracleDB + BizLogic <-->|MS-SQL Driver| iCubeDB + BizLogic <-->|MySQL Driver| IntranetDB +``` + +--- + +## 3. 계층별 기술 스택 (Layered Tech Stack) + +| 계층 (Layer) | 구성 기술 및 디렉토리 | 설명 | +| :--- | :--- | :--- | +| **Presentation Tier** | `Smarty 2.6`, `Smarty/templates/Satis/` | Server-Side Rendering (SSR) 뷰 템플릿 엔진 (`.tpl`) | +| **Client UI Tier** | `jQuery`, `jqGrid`, `w2ui`, `Satis/js/` | 엔지니어링/회계 대용량 동적 그리드 및 사용자 인터랙션 처리 | +| **Application Tier** | `PHP 5.x`, `Satis/sys/controller/` | Custom MVC Controller (`ActionMode` 라우팅 파라미터 처리) | +| **Security Tier** | `Satis/sys/util/AuthClass.php` | 세션 보안, CSRF Anti-Forgery Token 검증, 접근 권한 통제 | +| **Persistence Tier** | `OracleClass.php`, `Satis/inc/*.inc` | Oracle OCI, MS-SQL(iCube), MySQL 다중 DB 연결 지원 | + +--- + +## 4. 인프라 및 배포 아키텍처 (Infrastructure & Deployment Architecture) + +```mermaid +graph LR + subgraph Infrastructure Layout + WebSvr["Web Application Server
(APM_Setup / Windows Server)"] + OracleSvr[("Oracle Database Server
(Main ERP Data)")] + iCubeSvr[("Douzone iCube Server
(MS-SQL 192.168.13.50:5539)")] + MySQLSvr[("Intranet MySQL Server
(erp.samaneng.com / hallaerp)")] + end + + WebSvr -->|OCI Client| OracleSvr + WebSvr -->|MS-SQL TCP 5539| iCubeSvr + WebSvr -->|MySQL TCP 3306| MySQLSvr +``` + +* **서버 환경**: Windows Server 기반 APM (Apache + PHP + MySQL) 단일/이중화 실행 환경 (`D:/APM_Setup/htdocs/`) +* **PHP 실행 옵션**: + * 메모리 제한 해제 (`ini_set("memory_limit", -1)`)를 통한 대용량 프로젝트/연말정산 엑셀 보고서 생성 지원 + * 캐시 무효화 헤더 설정 (`Expires: 0`, `Cache-Control: no-cache`)을 통한 세션 및 보안 강화 +* **경로 및 컴파일 구조**: + * Smarty 템플릿 컴파일 경로: `D:/APM_Setup/htdocs/Smarty/templates_c` + * 템플릿 설정 경로: `SmartyConfig.php` 관리 + +--- + +## 5. 보안 및 인증 아키텍처 (Security & Authentication Architecture) + +```mermaid +sequenceDiagram + autonumber + actor User as 사용자 + participant Controller as Login Controller + participant Auth as AuthClass + participant Session as PHP Session + participant DB as Oracle DB + + User->>Controller: 로그인 요청 (ID / Password) + Controller->>DB: 사용자 정보 및 권한 검증 + DB-->>Controller: 인증 성공 반환 + Controller->>Auth: Auth_TokenGenerater() 호출 + Auth->>Session: Session ID & Token 생성/저장 + Session-->>User: Session Cookie 발급 (private) + + Note over User, Controller: 후속 요청 시 Token 및 Session 권한 검증 (Auth_TokenChecker) +``` + +1. **세션 및 인증 관리 (Session Management)** + * PHP 세션 생성 (`session_start()`, `session_cache_limiter('private')`) + * 사용자 식별자 관리: `$_SESSION['satis_user_id']`, `$_SESSION['satis_user_deptcode']`, `$_SESSION['satis_user_name']` +2. **CSRF 방어 및 난수 토큰 (Token Security)** + * `AuthClass.php` 내 10자리 영문/숫자 난수 토큰 생성기 (`Auth_TokenGenerater`) 및 검증기 (`Auth_TokenChecker`) 탑재 + * 비인가 접근 시 자동 세션 파기 (`session_destroy()`) 및 로그인 페이지 전환 (`auth_move_page.tpl`) +3. **역할 기반 권한 통제 (RBAC / Role-Based Access Control)** + * `AuthClass` 및 `GetUserInfo.php`를 통해 사용자 직급/부서/권한 등급별 메뉴 접근 권한 세분화 + +--- + +## 6. 외부 시스템 연동 아키텍처 (External System Integration Architecture) + +이 시스템은 단일 DB에 의존하지 않고, 사내 타 이종(Heterogeneous) 시스템과 실시간 연결되는 하이브리드 데이터 아키텍처를 가집니다. + +```mermaid +graph TD + SatisCore["Satis ERP Core System"] + + SatisCore <-->|OCI Native Connection| OracleSystem["메인 그룹웨어/ERP DB (Oracle)"] + SatisCore <-->|MS-SQL Driver (Port 5539)| iCubeSystem["더존 iCube ERP (MS-SQL: DZICUBE)
IP: 192.168.13.50"] + SatisCore <-->|MySQL Driver (Port 3306)| IntranetSystem["인트라넷 시스템 (MySQL: hallaerp)
Host: erp.samaneng.com"] +``` + +1. **더존 iCube ERP 연동 (`saman_icube_dbcon.inc`)** + * **연동 목적**: 사내 더존 회계/인사 ERP 데이터와의 실시간 동기화 및 전표 전송 + * **접속 방식**: Dedicated MS-SQL Connection (`192.168.13.50:5539`, DB명: `DZICUBE`) +2. **사내 인트라넷 연동 (`dbcon.inc`)** + * **연동 목적**: 인트라넷 기존 데이터 및 파일 연결 + * **접속 방식**: MySQL Connection (`erp.samaneng.com`, DB명: `hallaerp`) +3. **메인 Oracle DB 연동 (`OracleClass.php`)** + * **연동 목적**: Satis 그룹웨어 고유의 결재, 인사, 프로젝트, 출장, 자산 관리 데이터 처리 + * **접속 방식**: Oracle OCI8 라이브러리 및 커스텀 트랜잭션 바인딩 처리 + +--- + +## 7. 주요 업무 도메인 서브시스템 (Business Subsystems) + +| 도메인 구분 | 서브시스템 모듈 | 아키텍처적 역할 및 주요 처리 기능 | +| :--- | :--- | :--- | +| **회계/재무** | `Account` | 전표 생성/승인, 예산 관리, 결산, 재무제표, 법인세/부가세, 원가 계산 | +| **인사/급여** | `Person` | 인사기록, 근태 관리, 급여/상여 계산, 연말정산(`yeta_data`) 처리 | +| **프로젝트/공정** | `Project`, `Project_work` | 엔지니어링 프로젝트 현장 관리, 공정률 계산, 기성 산출, 수주/매출 처리 | +| **전자결재/문서** | `Document`, `Sign` | 전자결재 작성, 양식/결재선 관리, 전자서명 및 인장 관리 | +| **영업/구매** | `Sale`, `Purchase` | 수주/매출 관리, 자재 구매 신청 및 발주 처리 | +| **자산/도서/출장** | `Asset`, `Book`, `Travel` | 고정자산 추적, 도서 대여 관리, 국내/외 출장 신청 및 여비 정산 | +| **시스템 관리** | `Supervisor`, `Common` | 전체 공정/부서/직급 코드 관리 (`CommonCodeList.php`), 관리자 권한 설정 | + +--- + +## 8. 아키텍처 총평 및 고려사항 (Architectural Evaluation) + +1. **강점 (Strengths)**: + * **명확한 모듈화**: 업무 도메인별 Controller, Model, View가 체계적으로 분리되어 있어 대규모 ERP 시스템의 확장성이 확보되어 있습니다. + * **이종 DB 유연성**: Oracle, MS-SQL(더존 iCube), MySQL을 동시에 연동하는 하이브리드 데이터 아키텍처를 안정적으로 운영합니다. + * **대용량 그리드 최적화**: `jqGrid` 라이브러리와 메모리 해제 조치(`ini_set`)를 통해 수만 건 이상의 공정/회계 데이터 조회를 지원합니다. +2. **향후 아키텍처 개선 제언 (Future Roadmap)**: + * **PHP 버전을 현대화**: Classic PHP 드라이버(`mssql_*`, `mysql_*`)를 최신 `PDO` 또는 `sqlsrv`/`mysqli`로 마이그레이션 권장. + * **하드코딩된 DB 접속 정보 격리**: `saman_icube_dbcon.inc` 등의 DB 계정 정보를 `.env` 또는 보안 설정 파일로 분리 관리 권장. diff --git a/문서/architecture_low.md b/문서/architecture_low.md new file mode 100644 index 0000000..348a8fa --- /dev/null +++ b/문서/architecture_low.md @@ -0,0 +1,614 @@ +# (주)삼안 ERP 및 그룹웨어 시스템 (Satis) 초상세 로우레벨 분석 명세서 v2 + +본 문서는 (주)삼안의 **ERP 및 그룹웨어 시스템 (`saman-statis` / `Satis`)**의 실제 소스 코드를 직접 분석한 +**초상세 로우레벨(Ultra-Detailed Low-Level) 구현 명세서**입니다. +`OracleClass.php` 전체 메소드 명세, 전자결재 알고리즘, 문서번호 채번 방식, 인코딩 파이프라인, 결재 서명 렌더링, +시스템 글로벌 변수, DB 데이터 모델, 보안 핸들링 등을 실제 소스 코드 기반으로 완전히 명세합니다. + +--- + +## 1. 모듈별 컨트롤러 & 뷰 맵핑 딕셔너리 (Module Controller-View Map) + +### 1.1 회계 관리 모듈 (`Account`) — 30개 컨트롤러 +| 컨트롤러 (`Satis/sys/controller/Account/`) | 대응 View (`Smarty/templates/Satis/Account/`) | 주요 기능 | +| :--- | :--- | :--- | +| `AccountSlipTemp_Controller.php` | `AccountSlipTemp.tpl` | 임시전표 작성/조회/수정/결재 상신 | +| `AccountSlipConfirmed_Controller.php` | `AccountSlipConfirmed.tpl` | 확정전표 조회 및 결재 상태 확인 | +| `AccountSlipAutoManager_Controller.php` | `AccountSlipAutoManager.tpl` | 더존 iCube ERP 자동전표 전송 | +| `AccountBalanceStatement_Controller.php` | `AccountBalanceStatement.tpl` | 합계잔액시산표 생성 | +| `AccountFinancialStatement_Controller.php` | `AccountFinancialStatement.tpl` | 손익계산서(P/L) / 대차대조표(B/S) | +| `AccountGisungCalculation_Controller.php` | `AccountGisungCalculation.tpl` | 프로젝트 기성 청구금액 산출 | +| `AccountJointOfficeBudgetManager_Controller.php` | `AccountJointOfficeBudget.tpl` | 공동도급(JV) 예산/지분율 원가 관리 | +| `AccountFixAsset_Controller.php` | `AccountFixAsset.tpl` | 고정자산 감가상각비/대장 관리 | +| `AccountCorporateTax_Controller.php` | `AccountCorporateTax.tpl` | 법인세 계산 및 세무 조정 | +| `AccountWithHoldingTax_Controller.php` | `AccountWithHoldingTax.tpl` | 원천세 신고 / 원천징수 영수증 | +| `AccountVAT_Controller.php` | `AccountVAT.tpl` | 부가가치세 신고 데이터 집계 | +| `AccountCostCalculation_Controller.php` | `AccountCostCalculation.tpl` | 원가 계산 및 분석 | +| `AccountCostManagement_Controller.php` | `AccountCostManagement.tpl` | 원가 관리 현황 | +| `AccountFundPlan_Controller.php` | `AccountFundPlan.tpl` | 자금 계획 관리 | +| `AccountDepositsManager_Controller.php` | `AccountDepositsManager.tpl` | 예금/차입금 관리 | +| `AccountLoanManager_Controller.php` | `AccountLoanManager.tpl` | 대출 관리 | +| `AccountSecurities_Controller.php` | `AccountSecurities.tpl` | 유가증권 관리 | +| `AccountEntertainmentExpenses_Controller.php` | `AccountEntertainmentExpenses.tpl` | 접대비 관리 | +| `AccountCarManager_Controller.php` | `AccountCarManager.tpl` | 차량 운행/유지비 관리 | +| `AccountDailyWorkTask_Controller.php` | `AccountDailyWorkTask.tpl` | 일일 업무 실적 처리 | +| `AccountSummary_Controller.php` | `AccountSummary.tpl` | 회계 요약 현황 | +| `AccountSummaryReport_Controller.php` | `AccountSummaryReport.tpl` | 회계 종합 보고서 | +| `AccountDeadlineManager_Controller.php` | `AccountDeadlineManager.tpl` | 결산 기한 관리 | +| `AccountMonthSupplementary_Controller.php` | `AccountMonthSupplementary.tpl` | 월별 추가 분개 관리 | +| `AccountBillCheckManager_Controller.php` | `AccountBillCheckManager.tpl` | 어음/수표 관리 | +| `AccountFinaCode_Controller.php` | `AccountFinaCode.tpl` | 재무 코드 관리 | +| `AccountFundCode_Controller.php` | `AccountFundCode.tpl` | 자금 코드 관리 | +| `AccountAssetCode_Controller.php` | `AccountAssetCode.tpl` | 자산 코드 관리 | +| `FinalClosing_Controller.php` | `FinalClosing.tpl` | 결산 확정 처리 | +| `AccountGisungCalculation_Controller.php` | `AccountGisungCalculation.tpl` | 기성 계산 처리 | + +### 1.2 인사/급여 관리 모듈 (`Person`) — 23개 컨트롤러 +| 컨트롤러 (`Satis/sys/controller/Person/`) | 대응 View (`Smarty/templates/Satis/Person/`) | 주요 기능 | +| :--- | :--- | :--- | +| `PersonInfoManager_Controller.php` | `PersonInfoManager.tpl` | 인사기록 카드, 신상정보, 이력 관리 | +| `PersonAppointment_Controller.php` | `PersonAppointment.tpl` | 발령 처리 (입사/퇴사/이동/승진/전보) | +| `PersonInsaLicense_Controller.php` | `PersonInsaLicense.tpl` | 엔지니어링 기술자 자격증 관리 | +| `PersonCode_Controller.php` | `PersonCode.tpl` | 인사 코드 마스터 관리 | +| `PersonTime_Controller.php` | `PersonTime.tpl` | 근태 관리 (연차/야근/출퇴근) | +| `PersonPayBase_Controller.php` | `PersonPayBase.tpl` | 급여 기준 정보 설정 | +| `PersonPayBasic_Controller.php` | `PersonPayBasic.tpl` | 기본급/수당 항목 설정 | +| `PersonPaymentCalculation_Controller.php` | `PersonPaymentCalculation.tpl` | 월 급여/상여 계산 엔진 | +| `PersonPaymentReport_Controller.php` | `PersonPaymentReport.tpl` | 급여명세서 / 부서별 지급 총괄 | +| `PersonSlipPaymentManager_Controller.php` | `PersonSlipPaymentManager.tpl` | 급여 전표 연동 처리 | +| `PersonRetirementPay_Controller.php` | `PersonRetirementPay.tpl` | 퇴직금 계산 및 충당금 정산 | +| `PersonYearEndTax_Controller.php` | `PersonYearEndTax.tpl` | 연말정산 (`yeta_data` 연동) | +| `PersonInsaReport_Controller.php` | `PersonInsaReport.tpl` | 인사 현황 보고서 | +| `PersonInsaStatusReport_Controller.php` | `PersonInsaStatusReport.tpl` | 인사 상태 보고서 | +| `PersonOrganiz_Controller.php` | `PersonOrganiz.tpl` | 조직도 관리 | +| `Duzon_link_controller.php` | `Duzon_link.tpl` | 더존 인사/급여 ERP 데이터 싱크 | +| `auth_pay_controller.php` | `auth_pay.tpl` | 급여 지급 권한 처리 | +| `emp_check_controller.php` | `emp_check.tpl` | 재직 여부 확인 | + +### 1.3 프로젝트/현장 공정 모듈 (`Project`) — 15개 컨트롤러 +| 컨트롤러 (`Satis/sys/controller/Project/`) | 대응 View (`Smarty/templates/Satis/Project/`) | 주요 기능 | +| :--- | :--- | :--- | +| `Project_Controller.php` | `Project.tpl` | 프로젝트 마스터 등록/관리 | +| `ProjectOrderContract_Controller.php` | `ProjectOrderContract.tpl` | 수주 계약, 변경 계약, 공동도급 지분율 | +| `ProjectOrderGisung_Controller.php` | `ProjectOrderGisung.tpl` | 기성 청구 / 수금 / 미수금 | +| `ProjectMenHour_Controller.php` | `ProjectMenHour.tpl` | M/M 공수 집계 및 원가 배부 | +| `ProjectCostStatus_Controller.php` | `ProjectCostStatus.tpl` | 투입 원가(인건비/직접비/경비) 현황 | +| `ProjectCostTotal_Controller.php` | `ProjectCostTotal.tpl` | 원가 합계 현황 | +| `ProjectPrePayment_Controller.php` | `ProjectPrePayment.tpl` | 선급금 신청/수금/정산 | +| `ProjectStatus_Controller.php` | `ProjectStatus.tpl` | 프로젝트 진행 현황 | +| `ProjectBaseCode_Controller.php` | `ProjectBaseCode.tpl` | 프로젝트 기본 코드 관리 | +| `ProjectPartner_Controller.php` | `ProjectPartner.tpl` | 협력업체 관리 | +| `DeptAssessment_Controller.php` | `DeptAssessment.tpl` | 부서 평가 관리 | +| `TargetManagement_Controller.php` | `TargetManagement.tpl` | 수주 목표 관리 | +| `PrinterCopy_Controller.php` | `PrinterCopy.tpl` | 인쇄 출력 처리 | + +--- + +## 2. 핵심 클래스 전체 메소드 명세 (OracleClass.php — 1,392라인) + +`Satis/sys/util/OracleClass.php`는 시스템 전체 Oracle DB 연동의 핵심 클래스입니다. +실제 소스 분석 기반의 **전체 메소드 분류표**입니다. + +### 2.1 DB 커넥션 및 기본 쿼리 메소드 + +| 메소드명 | 설명 | +| :--- | :--- | +| `OracleClass($smarty)` | 생성자. OCI 커넥션 생성. `oci_connect('satis', 'SATIS11707808', 'samandb')` | +| `db_close_oracle()` | 커넥션 명시적 해제. `oci_close()` | +| `Query($i_azsql)` | SQL 파싱 및 실행 후 Statement 핸들 반환. | +| `fetch_array($stmt)` | `oci_fetch_array($stmt, OCI_BOTH)` — 연관+인덱스 배열 동시 반환 | +| `ExcuteQuery($i_azsql)` | DML 단순 실행 (반환값 없음) | +| `LoadSql($i_azsql)` | 레거시 `ociparse/ociexecute/ocifetchinto` API 기반 단일 컬럼 조회 | +| `LoadConfigData($i_azsql)` | 설정 데이터를 `name=value` 포맷으로 직접 `echo` 출력 | +| `__destruct()` | PHP 소멸자: Statement 자동 해제 + 커넥션 자동 close | + +### 2.2 Stored Procedure (저장 프로시저) 조회 메소드 + +| 메소드명 | 인자 | 반환 방식 | 특이사항 | +| :--- | :--- | :--- | :--- | +| `LoadProcedure($sql, $title, $short_array)` | SQL, Smarty 변수명 | `$query_data` 배열 + Smarty assign | 기본 프로시저 호출 메소드 | +| `LoadProcedure_old($sql, $title, $short_array)` | SQL, Smarty 변수명 | `$query_data` 배열 | `$_short` 축약형 컬럼 지원 (구버전) | +| `LoadProcedure_new($sql, $title, $short_array, $return_type)` | SQL, 변수명, 반환 타입 | `array` / `json` / `jsonchart` / `print_r` / Smarty | 출력 타입 지정 가능 | +| `LoadProcedure_new2($sql, $title, $short_array, $return_type)` | SQL, 변수명, 반환 타입 | 단일 Row 전용 | 단건 조회용 최적화 | +| `LoadProcedure_empty($sql, $title, $load_type, $return_type)` | SQL, 변수명, 로드타입 | `$query_data` 배열 | `w2ui` 모드 시 `recid` 자동 부여 | +| `LoadProcedure_broken_cp949($sql, $title, $load_type, $return_type)` | SQL, 변수명, 로드타입 | `$query_data` 배열 | CP949 인코딩 깨짐 데이터 처리용 | +| `LoadProcedureAjax($sql)` | SQL | `print_r(urldecode(json_encode($data)))` | Ajax 요청 전용 JSON 직접 출력 | +| `LoadProcedureApi($sql, $output_type)` | SQL, 출력 타입 | `array` / `json` / `jsonchart` | API/외부 호출 전용 | +| `Get_ProcedureData($Param01~05)` | 최대 5개 파라미터 | `array` | `usp_get_procedure_data` 프로시저 공통 호출 래퍼 | +| `executeSelect($sql)` | SQL | 구조화된 결과 객체 (`success`, `rows`, `columns`, `error`) | 최신 트랜잭션 안전 조회 함수 (2025-07-25 추가) | + +### 2.3 DML 실행 메소드 (INSERT / UPDATE / DELETE) + +| 메소드명 | 설명 | 에러 반환 방식 | +| :--- | :--- | :--- | +| `ProcedureExcuteQuery($sql)` | 프로시저 DML 실행, 에러 시 `echo` | `echo '-----'.$err['message']` | +| `ProcedureExcuteQuery_new($sql, $encode_type, $return_type)` | 인코딩 선택(`utf8`/`euckr`) 후 DML 실행 | echo 출력 | +| `ProcedureExcuteQuery_boolean($sql)` | DML 실행 후 `true`/`false` 반환 | boolean | +| `ProcedureExcuteQuery_boolean2($sql)` | DML 실행 후 `result`/`error` 구조체 반환 | 배열 구조체 | +| `ProcedureExcuteQuery_ErrorCheck($sql, $memberId, $date, $returnYN, $encode_type, $output_msg)` | 프로시저 실행 후 `Common_Confirm_Error` 프로시저로 이중 에러 검증 | `echo` 또는 `return` | +| `ProcedureExcuteQuery_Return($sql, $ReturnContent)` | DML 후 `RESULT_CODE` / `RESULT_MSG` / `ALL` 선택 반환 | 문자열 또는 배열 | +| `ProcedureExcuteQuery_ExcReturn($sql, $ReturnContent)` | 최신 try-catch 기반 DML. Oracle 에러코드 한국어 메시지 매핑 | JSON 또는 한국어 에러 문자열 | +| `executeDml($sql)` | 트랜잭션 안전 DML 실행 (2025-07-25 신규 추가) | 구조화된 결과 객체 | +| `ProcedureExcuteQuery_ErrorPrint($sql, $encode_type, $return_type)` | 에러 발생 시 콘솔 출력 | `echo` | + +### 2.4 Oracle 에러코드 → 한국어 메시지 매핑 테이블 + +`ProcedureExcuteQuery_ExcReturn()` 내부의 `$ErrorKind_Array`로 Oracle ORA- 에러 코드를 사용자 친화적 한국어 메시지로 변환합니다. + +```php +$ErrorKind_Array = [ + "-1" => "존재하는 내용입니다. 확인 후 입력해 주세요.", // ORA-00001: DUP_VAL_ON_INDEX + "-1400" => "빈값을 입력 할 수 없습니다.", // NOT NULL 위반 + "-1722" => "숫자자리에 문자를 입력할 수 없습니다.", // INVALID_NUMBER + "-1407" => "빈값을 입력 할 수 없습니다.", // NOT NULL 위반 (다른 컬럼) + "-1438" => "숫자값이 너무 커서 입력할 수 없습니다.", // 숫자 정밀도 초과 + "-12899" => "글자가 너무 길어 입력할 수 없습니다.", // VARCHAR2 길이 초과 + "-6550" => "필수항목이 입력되지 않았습니다.", // PL/SQL 컴파일 에러 + "-6511" => "(CURSOR_ALREADY_OPEN) : 커서가 이미 OPEN 상태", + "-6502" => "(VALUE_ERROR) : 수치 또는 값 오류", + "-1476" => "(ZERO_DIVIDE) : 0으로 나눌때", + "-1017" => "(LOGIN_DENIED) : 잘못된 사용자 이름이나 비밀번호로 로그인 시도", + "-1422" => "(TOO_MANY_ROWS) : SELECT INTO 결과가 두 건 이상", +]; +``` + +### 2.5 문자 인코딩 변환 메소드 (CP949 ↔ UTF-8 파이프라인) + +Oracle DB는 `CP949 (EUC-KR)` 인코딩을 사용하고, 웹 화면은 `UTF-8`로 구성되어 있어 양방향 변환이 필수입니다. + +```mermaid +graph LR + DB["Oracle DB (CP949/EUC-KR)"] + PHP["PHP Application (UTF-8)"] + Browser["Web Browser (UTF-8)"] + + DB -->|HangleEncode: ICONV cp949→UTF-8| PHP + PHP -->|HangleEncodeUTF8_EUCKR: ICONV UTF-8→cp949| DB + PHP -->|HangleEncodeAjax: cp949→UTF-8 Ajax 전용| Browser +``` + +| 메소드명 | 변환 방향 | 비고 | +| :--- | :--- | :--- | +| `HangleEncode($item)` | `CP949 → UTF-8` | 공백은 ` `로 대체 | +| `HangleEncode_empty($item)` | `CP949 → UTF-8` | 공백 대체 없음 | +| `HangleEncodeAjax($item)` | `CP949 → UTF-8` | Ajax 응답 전용 | +| `HangleEncodeUTF8_EUCKR($item)` | `UTF-8 → CP949` | SQL 삽입 시 한글 보호 | +| `bear3StrCut($str, $len, $tail)` | — | 멀티바이트 문자열 정규식 자르기 (`preg_match`) | +| `resizeString($str, $size, $addStr)` | — | `mb_strlen/mb_substr` 기반 UTF-8 자르기 | + +### 2.6 로그 기록 메소드 + +```php +function OracleLogWrite($msg, $menu) { + // 로그 파일 경로: Satis/sys/log/YYYY-MM-DD_{메소드명}.txt + $cfile = "../../log/" . date("Y-m-d") . "_" . $menu . ".txt"; + + // 기존 파일 내용 읽기 → 새 내용 추가 → 파일 쓰기 + if (file_exists($cfile)) { + $fd = fopen($cfile, 'r'); + $con = fread($fd, filesize($cfile)); + fclose($fd); + } + $fp = fopen($cfile, 'w'); + $cond = $con . date("Y-m-d H:i:s") . " " . $msg . "\n"; + fwrite($fp, $cond); + fclose($fp); +} +``` + +> **로그 파일 명명 규칙**: `YYYY-MM-DD_{호출된메소드명}.txt` +> 예: `2026-07-20_LoadProcedure.txt`, `2026-07-20_ExcuteQuery_new.txt` + +### 2.7 최신 트랜잭션 안전 메소드 (2025-07-25 추가, 김병철) + +```php +function executeSelect($sql) { + try { + set_error_handler(array($this, 'custom_error_handler')); + $stmt = oci_parse($this->connection, $this->HangleEncodeUTF8_EUCKR($sql)); + + // Ref Cursor 포함 여부 자동 감지 + if (strpos($sql, ":entries") !== false) { + $entries = oci_new_cursor($this->connection); + oci_bind_by_name($stmt, ":entries", $entries, -1, OCI_B_CURSOR); + oci_execute($stmt, OCI_DEFAULT); + oci_execute($entries); + $fetchResult = $this->fetchResults($entries, $result); + } else { + oci_execute($stmt, OCI_DEFAULT); + $fetchResult = $this->fetchResults($stmt, $result); + } + $result["rows"] = $fetchResult[0]; + $result["columns"] = $fetchResult[1]; + + } catch (Exception $e) { + oci_rollback($this->connection); // 에러 시 자동 롤백 + $this->makeErrorResult($result, $stmt, $e->getMessage()); + + // Oracle 에러코드 20000 이상 = 사용자 정의 예외 → DB 에러로그 삽입 + if ($result["error"]["datas"]["oci_error_data"]["code"] >= 20000) { + $this->insertSmErrorLog($_SESSION["satis_user_id"], $errorMessage); + } + } + restore_error_handler(); + return $result; +} +``` + +--- + +## 3. 전자결재 엔진 알고리즘 (`Satis/inc/approval_function.php` — 1,224라인) + +### 3.1 전자결재 상태 머신 (State Machine) + +```mermaid +stateDiagram-v2 + [*] --> CREATE : 기안 문서 작성 (DOC_STATUS_CREATE) + + CREATE --> TEMP : 임시저장 (TEMP-00001) + CREATE --> APPROVE: 결재 상신 (PROCESS_APPROVE=1) + TEMP --> APPROVE: 상신 실행 + + state APPROVE { + [*] --> DEPT : 부서내결재 (부서내 / PROCESS_CODE) + DEPT --> RECV : 부서접수 (RECEIVE) + RECV --> SANCTION: 결의부서내 (SANCTION_CODE) + SANCTION --> FINISH_LOOP: 처리부서내 (SANCTION_CODE2) + } + + APPROVE --> BACK : 이전 결재자 반송 (PROCESS_BACK="BACK") + APPROVE --> RETURN : 부결/반송 (PROCESS_RETURN="RETURN") + APPROVE --> FINISH : 최종 승인 (PROCESS_FINISH="FINISH") + APPROVE --> DECISION : 전결 (PROCESS_DECISION="FINISH-DECISION") + + BACK --> APPROVE : 재결재 + RETURN --> CREATE : 재기안 + FINISH --> [*] + DECISION --> [*] +``` + +### 3.2 전체 상태 상수 정의 (`approval_var.php`) + +```php +/* 결재 진행 상태 코드 */ +$PROCESS_APPROVE = 1; // 결재진행중 +$PROCESS_TEMPORARY = "TEMP-"; // 임시저장 (형식: TEMP-00001 또는 TEMP-00001-T02211) +$PROCESS_ACCEPT = "ACCEPT"; // 가결 +$PROCESS_REJECTION = "REJECT"; // 부결 (기능삭제됨) +$PROCESS_RETURN = "RETURN"; // 반송 (재기안 가능) +$PROCESS_BACK = "BACK"; // 반송 - 이전 결재자에게 재전달 +$PROCESS_FINISH = "FINISH"; // 최종 결재완료 +$PROCESS_DECISION = "FINISH-DECISION"; // 전결 처리 +$PROCESS_RECEIVE = "RECEIVE"; // 부서접수 대기 +$PROCESS_CANCEL = "CANCEL"; // 기안취소 +$PROCESS_DELETE = "DELETE"; // 기안 삭제 + +/* 문서 편집 상태 코드 */ +$DOC_STATUS_CREATE = "CREATE"; // 새 기안 문서 작성 +$DOC_STATUS_EDIT = "EDIT"; // 기안 문서 편집 +$DOC_STATUS_VIEW = "VIEWER"; // 기안 문서 보기 (편집불가) +$DOC_STATUS_APPROVE = "APPROVE"; // 결재함 문서 결재하기 +$DOC_STATUS_ACCEPT = "ACCEPT"; // 부서 문서 접수하기 + +/* 결재 라인 위치 코드 */ +$PROCESS_CODE = "부서내"; // 부서내 결재 진행 중 +$TEMPORARY_CODE = "부서내임시저장"; // 임시저장 코드 +$SANCTION_CODE = "결의부서내"; // 결의부서 결재 진행 중 +$SANCTION_CODE2 = "처리부서내"; // 처리부서 결재 진행 중 +$STEP_NO = 9; // 최대 결재 단계 수 +``` + +### 3.3 문서 번호 채번 알고리즘 (Serial Number Generation) + +결재 상신 시 문서번호가 자동으로 채번되는 두 가지 방식이 있습니다. + +#### A. 임시저장 문서번호 (`TempSerialNo` / `TempSerialNo2`) + +```php +// 형식: "TEMP-00001" 또는 "TEMP-00001-T02211" +function TempSerialNo() { + // SanctionDoc_tbl에서 TEMP-로 시작하는 마지막 번호 조회 + $res04 = mysql_query("SELECT * FROM SanctionDoc_tbl WHERE DocSN LIKE 'TEMP-%' ORDER BY DocSN DESC LIMIT 0,1", $db); + if (mysql_num_rows($res04) > 0) { + $aa = mysql_result($res04, 0, "DocSN"); + $bb = split("TEMP-", $aa); + return "TEMP-" . sprintf("%05d", ($bb[1] + 1)); // 5자리 zero-padding + } else { + return "TEMP-" . sprintf("%05d", 1); // 최초: TEMP-00001 + } +} + +// TempSerialNo2: 사번 suffix 포함 형식 (TEMP-00001-T02211) +// split("-", "TEMP-00021-T02211") → $bb[1] = "00021" +``` + +#### B. 결재 상신 문서번호 (`NewSerialNo` / `NewSerialNo2`) + +```php +// 형식: "2026-00001" 또는 "2026-00001-T02211" +function NewSerialNo() { + $NewKey = date('Y-'); // "2026-" + $res04 = mysql_query("SELECT * FROM SanctionDoc_tbl WHERE DocSN LIKE '$NewKey%' ORDER BY DocSN DESC LIMIT 0,1", $db); + if (mysql_num_rows($res04) > 0) { + $aa = mysql_result($res04, 0, "DocSN"); + $bb = split($NewKey, $aa); // "2026-00005" → $bb[1] = "00005" + return $NewKey . sprintf("%05d", ($bb[1] + 1)); // "2026-00006" + } else { + return $NewKey . sprintf("%05d", 1); // 최초: "2026-00001" + } +} +``` + +### 3.4 결재선 순회 알고리즘 (`NextSanctionState`) + +결재 진행 시 현재 결재 위치를 다음 결재자로 이동시키는 핵심 알고리즘입니다. + +```php +function NextSanctionState($Tmp_Sanction, $Tmp_SanctionState) { + // $Tmp_Sanction = "A001:B002:RECEIVE:C003:D004:FINISH" (결재선 배열, ':' 구분) + // $Tmp_SanctionState = "1:부서내:A001:2026-07-20" (현재 단계:코드:사번:날짜) + + $TmpState = split(":", $Tmp_SanctionState); + $Start = $TmpState[0]; // 현재 결재 인덱스 + + // RECEIVE 위치(index) 먼저 탐색 + for ($i = $Start; $i < count($TmpArr); $i++) { + if ($TmpArr[$i] == $PROCESS_RECEIVE) { + $RECEIVE_INDEX = $i; break; + } + } + + // 다음 결재자 상태 결정 + for ($i = $Start; $i < count($TmpArr); $i++) { + switch ($TmpArr[$i]) { + case $PROCESS_RECEIVE: // 부서접수로 넘김 + $Res_SanctionState = ($i+1).":".$PROCESS_RECEIVE.":".$TmpState[2].":".date('Y-m-d'); + break; + case $PROCESS_FINISH: // 결재 완료 + $Res_SanctionState = ($i+1).":".$PROCESS_FINISH.":".$TmpState[2].":".date('Y-m-d'); + break; + default: // 다음 결재자에게 넘김 + // RECEIVE 이후면 처리부서내(SANCTION_CODE2), 이전이면 결의부서내(SANCTION_CODE) + $SANCTION_CODE_ = ($i > $RECEIVE_INDEX) ? $SANCTION_CODE2 : $SANCTION_CODE; + $Res_SanctionState = ($i+1).":".$SANCTION_CODE_.":".$TmpArr[$i].":".date('Y-m-d'); + break; + } + break; // 첫 번째 유효 결재자만 처리 + } + return $Res_SanctionState; +} +``` + +### 3.5 결재 서명/인장 렌더링 알고리즘 (`FindSanctionState` / `FindSanctionState2`) + +결재 문서 화면에서 결재자 서명 이미지(인장) 또는 텍스트를 표시하는 렌더링 로직입니다. + +```php +function FindSanctionState2($TmpSN, $sName, $sGroup) { + // SanctionState_tbl에서 해당 결재자의 결재 이력 조회 + $azSQL = "SELECT * FROM SanctionState_tbl WHERE DocSN='$TmpSN' AND MemberNo LIKE '%$sName%'"; + + $SanctionState = mysql_result($res06, 0, "SanctionState"); + $src_photo = "../../../erpphoto/$MemberNo.jpg"; // 결재자 서명 사진 경로 + + // 대리결재 감지 + if ($sGroup == "결의부서내") { + if (strpos(mysql_result($res06, 0, "MemberNo"), "대결") !== false) { + $Member_Name .= "-대결"; // 대리결재 표시 + } + } + + if ($SanctionState == "ACCEPT" || $SanctionState == "FINISH-DECISION") { + if (file_exists($src_photo)) { + // 서명 이미지 존재 시: + return "
$Member_Name
($SanctionDate)"; + } else { + // 서명 없음 시: 빨간색 텍스트("승인" 또는 "전결") + $ok_str = ($SanctionState == "ACCEPT") ? "승인" : "전결"; + return "$ok_str

$Member_Name
($SanctionDate)"; + } + } else { + return "

$Member_Name
(미결)"; // 아직 결재 안 됨 + } +} +``` + +### 3.6 공통 코드 룩업 함수 목록 (`approval_function.php`) + +전자결재 처리 중 MySQL `intranet_tbl` / `member_tbl` / `SystemConfig_Tbl`을 조회하는 헬퍼 함수 목록입니다. + +| 함수명 | 조회 테이블 | 반환값 | +| :--- | :--- | :--- | +| `MemberNo2Ip($mCode)` | `intranet_tbl` | 사번으로 IP 주소 반환 (끝자리 0/1이면 공백) | +| `MemberNo2BossIP($Tmp_Sanction, $Step)` | `intranet_tbl` | 결재선 특정 스텝의 결재자 IP | +| `MemberNo2Name($mCode)` | `member_tbl` | 사번 → 한글 성명 | +| `MemberNo2Rank($mCode)` | `member_tbl`, `SystemConfig_Tbl` | 사번 → 직급명 | +| `MemberNo2GroupCode($mCode)` | `member_tbl` | 사번 → 부서코드 (2자리 zero-pad) | +| `MemberNo2GroupName($mCode)` | `member_tbl`, `SystemConfig_Tbl` | 사번 → 부서명 | +| `MemberNo2SiteName($mCode)` | `systemconfig_tbl` | 사번 → 현장명 (TeamLeader 기준) | +| `DocCode2Name($DocCode)` | `systemconfig_tbl` | 결재 서식 코드 → 서식명 | +| `ProjectCode2Name($mCode)` | `project_tbl` | 프로젝트 코드 → 약칭 | +| `ProjectCode2Bridge($mCode, $no)` | `project_cs_summary_tbl` | 교량 프로젝트 약칭 | +| `Code2Name($mCode, $dbSysKey, $Kind)` | `SystemConfig_Tbl` | 일반 코드 → 명칭 (`Kind=0`) 또는 설명 (`Kind=1`) | +| `Group2Manager($mCode)` | `SystemConfig_Tbl` | 부서코드 → 부서장 사번 (`Note` 컬럼) | +| `ProcessingState($TmpSN, $tmpState, $mCode)` | `SanctionDoc_tbl` | 현재 결재 상태를 한국어 명칭으로 변환 | +| `FindSanctionDate($TmpSN, $TmpMemberNo)` | `SanctionState_tbl` | 특정 결재자의 결재일자 반환 | +| `TempState($mCode)` | — | 임시저장 상태 문자열 생성 (`0:부서내임시저장:A001:YYYY-MM-DD`) | + +--- + +## 4. 시스템 글로벌 변수 및 초기화 파일 (`DefaultInformation.php`) + +모든 컨트롤러에서 `include "../../util/DefaultInformation.php"`로 로드되는 +**시스템 기본 정보 세션 초기화 파일**입니다. + +```php +/* 화면 요청 정보 */ +$smarty->assign('auth_page_id', $_REQUEST['target_id']); +$smarty->assign('auth_page_devYN2', 'Y'); +$smarty->assign('satis_user_id', $_SESSION['satis_user_id']); + +/* 개발자 화이트리스트 (devYN='Y' 권한 부여) */ +$devUserList = [ + "203155" => "한정규", + "216070" => "정명준", + "209171" => "신지호", + "216011" => "장계석", + "221064" => "김병철", + "223158" => "김진선", +]; + +/* 로그인 사용자가 개발자 목록에 있으면 devYN='Y' 설정 */ +if (array_key_exists($_SESSION['satis_user_id'], $devUserList)) { + $smarty->assign('auth_page_devYN', 'Y'); +} + +/* 회사 기본 정보 */ +$site_code = "SAMAN"; // 회사 영문 식별 코드 +$site_name = "삼안"; +$Corporation_name = "(주)삼안"; +$company_registration_number = "211-81-25425"; // 사업자등록번호 +$smarty->assign('site_code', $site_code); +$smarty->assign('site_name', $site_name); +$smarty->assign('Corporation_name', $Corporation_name); +$smarty->assign('company_registration_number', $company_registration_number); +``` + +--- + +## 5. 공통 헬퍼 함수 라이브러리 (`Satis/inc/function.php` — 1,093라인) + +| 함수명 | 설명 | +| :--- | :--- | +| `str_cutting($str, $len)` | 멀티바이트 문자열 자르기 (한글 2바이트 처리, 생략 시 `...` 추가) | +| `substr1($str, $len)` | str_cutting의 Trailing 없는 단순 잘라내기 버전 | +| `ConfigName($category, $code)` | `config_tbl` 코드 → 명칭 반환 | +| `ConfigName2($category, $code)` | `config_tbl` 코드 → 설명(desc) 반환 | +| `Code2Name($mCode, $dbSysKey, $Kind)` | `SystemConfig_Tbl` 일반 코드 → 명칭 반환 | +| `change_code($pcode)` | 연도 코드 `XX`를 실제 연도(2자리)로 치환 | + +--- + +## 6. 데이터베이스 스키마 상세 (MySQL 인트라넷 DB — `hallaerp`) + +`approval_function.php`의 실제 SQL 쿼리 분석으로 도출한 인트라넷 MySQL DB 테이블 구조입니다. + +| 테이블명 | 주요 컬럼 | 역할 | +| :--- | :--- | :--- | +| `member_tbl` | `MemberNo`, `KorName`, `RankCode`, `GroupCode`, `WorkPosition` | 사원 기본 정보 (`WorkPosition='9'` = 퇴직자) | +| `intranet_tbl` | `MemberNo`, `UseIP` | 사원 네트워크 IP 정보 | +| `SanctionDoc_tbl` | `DocSN`, `DocCode`, `PG_Date`, `DocTitle`, `DocStatus` | 전자결재 문서 마스터 | +| `SanctionState_tbl` | `DocSN`, `MemberNo`, `SanctionOrder`, `SanctionState`, `SanctionDate` | 결재자별 결재 이력 | +| `SystemConfig_Tbl` | `SysKey`, `Code`, `Name`, `Description`, `Note` | 시스템 공통 코드 사전 (부서코드, 직급코드, 결재서식 등) | +| `project_tbl` | `ProjectCode`, `ProjectNickname` | 프로젝트 약칭 | +| `project_cs_summary_tbl` | `ProjectCode`, `no`, `Item` | 교량/구조물 프로젝트 세부 항목 | +| `config_tbl` | `category`, `code`, `name`, `desc` | 화면별 코드 설정 | + +--- + +## 7. 예외 처리 & 보안 핸들링 상세 (`AuthClass.php` — 591라인) + +### 7.1 CSRF 토큰 생성 알고리즘 +```php +function Auth_TokenGenerater($assign_boolean = false) { + // 62자 문자풀에서 10자리 난수 토큰 생성 + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $randomString = ''; + for ($i = 0; $i < 10; $i++) { + $randomString .= $characters[rand(0, 61)]; + } + if ($assign_boolean) { + $_SESSION['Token'] = $randomString; // 서버 세션에 저장 + $this->smarty->assign('Token', $randomString); // 뷰로 전달 (히든 필드 렌더링) + } else { + return $randomString; + } +} +``` + +### 7.2 토큰 검증 흐름 +```mermaid +sequenceDiagram + autonumber + actor User + participant Controller + participant AuthClass + participant Session + + User->>Controller: 폼 제출 (Token 파라미터 포함) + Controller->>AuthClass: Auth_TokenChecker($Token, $page_move=true) + AuthClass->>Session: $_SESSION['Token'] 조회 + alt 토큰 일치 + AuthClass->>Controller: Smarty assign('Token', ...) 후 정상 처리 + else 토큰 불일치 + AuthClass->>Session: session_destroy() 세션 파기 + AuthClass->>User: auth_move_page.tpl 출력 (로그인 페이지 이동) + AuthClass->>Controller: exit() 강제 종료 + end +``` + +### 7.3 세션 변수 목록 + +| 세션 키 | 설명 | +| :--- | :--- | +| `$_SESSION['satis_user_id']` | 로그인 사원번호 (예: `"221064"`) | +| `$_SESSION['satis_user_name']` | 로그인 사원 성명 | +| `$_SESSION['satis_user_deptcode']` | 사원 부서코드 | +| `$_SESSION['satis_user_deptname']` | 사원 부서명 | +| `$_SESSION['Token']` | CSRF Anti-Forgery Token (10자리 난수) | +| `$_SESSION['Title']` | 현재 화면 제목 | +| `$_SESSION['Auth']` | 권한 레벨 | +| `$_SESSION['Type']` | 사용자 유형 | + +--- + +## 8. 핵심 소스 파일 사전 (Source File Dictionary — 전체) + +| 파일 경로 | 용량 / 라인 | 핵심 역할 | +| :--- | :--- | :--- | +| `Satis/sys/util/OracleClass.php` | 46KB / 1,392라인 | Oracle OCI 커넥션, Ref Cursor 조회/DML, 인코딩 변환 | +| `Satis/sys/util/AuthClass.php` | 18KB / 591라인 | 세션 토큰 생성/검증, CSRF 방어 | +| `Satis/sys/util/CommonCodeList.php` | 294KB | 시스템 공통 코드 PHP 배열 인메모리 캐시 | +| `Satis/inc/approval_function.php` | 35KB / 1,224라인 | 전자결재 상태 처리, 결재선 순회, 서명 렌더링 | +| `Satis/inc/function.php` | 30KB / 1,093라인 | 문자열 처리, 코드룩업, 공통 헬퍼 함수 | +| `Satis/inc/function_intranet.php` | 33KB | 인트라넷 전용 헬퍼 함수 | +| `Satis/inc/approval_var.php` | 1.6KB / 29라인 | 전자결재 상태 상수 정의 | +| `Satis/inc/dbcon.inc` | 0.4KB | 인트라넷 MySQL 커넥션 (`erp.samaneng.com/hallaerp`) | +| `Satis/inc/saman_icube_dbcon.inc` | 0.5KB | 더존 iCube MS-SQL 커넥션 (`192.168.13.50:5539/DZICUBE`) | +| `Satis/sys/util/DefaultInformation.php` | 1.3KB | 시스템 글로벌 변수, 개발자 권한, 회사 정보 초기화 | +| `SmartyConfig.php` | 0.3KB | Smarty 엔진 경로 설정 | +| `Satis/sys/util/PrintAgent.php` | 1KB | 인쇄 에이전트 유틸리티 | +| `Satis/sys/util/ReportViewExcel.php` | 2.8KB | Excel 보고서 출력 처리 | + +--- + +## 9. M/M (Man-Month) 투입 공수 및 원가 배부 공식 + +엔지니어링 업계 특성상 프로젝트별 인건비 원가 배부는 투입 M/M 비율을 기준으로 계산됩니다. + +$$\text{Project}_{i} \text{ 원가 배부액} = \text{직원 월 급여} \times \left( \frac{\text{Project}_{i} \text{ 투입 M/M}}{\displaystyle\sum_{j=1}^{n} \text{Project}_{j} \text{ 투입 M/M}} \right)$$ + +**처리 흐름**: +1. `PersonPaymentCalculation`: 직원의 당월 급여 총액 및 4대보험 회사 부담금 계산 +2. `ProjectMenHour`: 해당 월 직원의 프로젝트별 투입 M/M 입력 +3. Oracle 저장 프로시저: 비율 계산 → 각 프로젝트 원가 테이블 자동 배부 +4. `AccountGisungCalculation`: 프로젝트 기성 청구 시 누적 원가 반영 + +--- + +## 10. 로우레벨 개발 시 주의사항 + +> [!CAUTION] +> **SQL Injection 위험**: `approval_function.php` 및 `function.php`의 MySQL 함수들은 대부분 `$mCode` 값을 필터링 없이 SQL에 직접 삽입합니다. 수정 시 반드시 `mysql_real_escape_string()` 또는 PDO Prepared Statement로 교체해야 합니다. + +> [!WARNING] +> **레거시 드라이버**: `mysql_connect()`, `mssql_connect()` 등 PHP 7.x에서 완전히 제거된 드라이버를 사용합니다. PHP 5.6 이하 환경에서만 실행 가능합니다. + +> [!WARNING] +> **하드코딩된 개발자 화이트리스트**: `DefaultInformation.php`에 개발자 사번이 하드코딩되어 있습니다. 인사 이동 시 소스 직접 수정이 필요합니다. + +> [!NOTE] +> **Oracle 트랜잭션**: `ProcedureExcuteQuery()`는 `OCI_COMMIT_ON_SUCCESS`(자동 커밋) 모드로 동작합니다. 여러 DML을 하나의 트랜잭션으로 묶으려면 `OCI_DEFAULT` 모드의 `executeDml()` / `executeSelect()`를 사용해야 합니다. + +> [!NOTE] +> **Session 의존성**: 모든 컨트롤러 로직은 `session_start()` → `GetUserInfo.php` → `DefaultInformation.php` 순서로 초기화가 완료되어야 합니다. 순서가 바뀌면 `$_SESSION['satis_user_id']`가 null이 되어 개발자 권한 판별이 실패합니다.