개요 및 학습 흐름
I_FunctionalLocation은 SAP Plant Maintenance(PM) 영역에서 설비·구조물의 물리적 위치를 계층적으로 표현하는 CDS 뷰 엔터티입니다. 기존 IFLOT(Functional Location Master) 테이블과 텍스트 테이블(IFLOTX)을 결합하여, 상위-하위 관계를 가진 트리 형태로 자산을 추적할 수 있게 해줍니다. 이 글에서는 IFLOT의 구조부터 시작하여 CDS 뷰의 정의, 계층 탐색 쿼리, 작업지시(Work Order)·예방정비(Preventive Maintenance) 연계 시나리오까지 단계별로 정리합니다.
- IFLOT 테이블과 I_FunctionalLocation 뷰의 매핑 관계 이해
- 기능 위치 계층(Superior Functional Location) 탐색 방식 학습
- 실무 PM 시나리오에서 ABAP/CDS 쿼리 작성 실습
- 성능·권한·다국어 처리 등 운영 환경 고려사항 확인
알아두면 좋은 사전 지식
이 글은 ABAP CDS 뷰의 기본 구문(define view entity, association, annotation), SE11/SE16N으로 SAP 표준 테이블을 조회한 경험, 그리고 PM 모듈의 기본 용어(Equipment, Functional Location, Work Order)에 익숙한 독자를 대상으로 합니다. ADT(ABAP Development Tools in Eclipse) 환경에서 CDS 뷰를 열고 Data Preview를 실행할 수 있어야 실습이 원활합니다.
실행 환경과 준비물
다음 환경에서 동작을 확인하는 것을 권장합니다.
- SAP S/4HANA 2022 또는 2023 (On-Premise) / SAP S/4HANA Cloud Public Edition
- ABAP Platform 7.58 이상 (CDS View Entity 지원)
- SAP HANA DB (Calculation Engine 기반 푸시다운)
- ADT(Eclipse) — ABAP Development Tools 3.40 이상
- PM 모듈 라이선스 및 IFLOT 데이터 권한(Authorization Object: I_TCODE, I_SWERK, I_INGRP 등)
S/4HANA 1909 이하 환경에서는 일부 필드가 다르거나 I_FunctionalLocation이 존재하지 않을 수 있으므로, ADT의 "Where-Used"로 시스템에서 직접 확인해야 합니다. 일반적으로 SAP S/4HANA 2020부터 PM 관련 Released CDS 뷰가 본격적으로 공개되었습니다.
핵심 개념과 동작 원리
Functional Location(기능 위치)은 "어디에 설치되어 있는가"를 표현하는 개념입니다. 예를 들어 정유공장이라면 "공장 A → 1번 라인 → 압축기 섹션 → P-101 펌프 위치" 같은 계층이 만들어지고, 그 자리(=위치)에 어떤 장비(Equipment)가 들어가도 위치 자체는 그대로 유지됩니다. 즉, 위치는 "주소"이고 장비는 "거주자"에 해당합니다.
이 주소 정보를 저장하는 마스터 테이블이 IFLOT이며, 주요 컬럼은 다음과 같습니다.
TPLNR— Functional Location 번호 (코드형 식별자)TPLKZ— Structure Indicator (구조 식별 규칙)TPLMA— Superior Functional Location (상위 위치)FLTYP— Functional Location CategorySWERK— Maintenance PlantSTORT— Location (Plant 내 위치)BEBER— Plant Section
I_FunctionalLocation 뷰는 이 IFLOT을 베이스로 텍스트 테이블(IFLOTX), 카테고리·플랜트 마스터 등에 association을 걸어 의미 있는 필드 이름(FunctionalLocation, SuperiorFunctionalLocation, MaintenancePlant 등)으로 노출합니다. 계층 탐색은 self-association을 통해 가능하며, 한 행의 SuperiorFunctionalLocation이 또 다른 행의 FunctionalLocation과 연결되는 재귀 구조입니다.
비유하자면 IFLOT은 "건물 호수 대장"이고, I_FunctionalLocation은 그 대장에 "건물명·층·옆방 호수"까지 자동으로 붙여 보여주는 한 장의 종합 명함이라고 생각할 수 있습니다.
실전 예제 1단계 — 기본 조회
먼저 가장 단순한 형태로 특정 플랜트의 기능 위치 목록을 가져옵니다. 화학 공장 "1010"에서 운영 중인 기능 위치를 조회한다고 가정합니다.
REPORT zpm_floc_basic_demo.
DATA: lt_floc TYPE TABLE OF i_functionallocation.
SELECT FunctionalLocation,
FunctionalLocationName,
MaintenancePlant,
SuperiorFunctionalLocation,
FunctionalLocationCategory
FROM i_functionallocation
WHERE MaintenancePlant = '1010'
AND FunctionalLocationCategory = 'M'
INTO TABLE @lt_floc
UP TO 50 ROWS.
LOOP AT lt_floc INTO DATA(ls_floc).
WRITE: / ls_floc-functionallocation,
ls_floc-functionallocationname,
ls_floc-superiorfunctionallocation.
ENDLOOP.
여기서 FunctionalLocationCategory = 'M'은 "기계 설비"용 카테고리를 의미하며, 사이트별로 'A', 'B' 등 별도 코드를 운영하기도 합니다. 조회 결과의 SuperiorFunctionalLocation 컬럼이 비어 있는 행이 곧 "최상위 노드"입니다.
실전 예제 2단계 — 계층 트리 펼치기와 텍스트 결합
실무에서는 단순 목록보다 "어떤 위치 아래에 어떤 하위 위치가 있는지"를 트리 형태로 보여줘야 할 때가 많습니다. CDS 뷰를 새로 만들어 self-association을 이용한 1-depth 펼치기를 구현하고, 다국어 텍스트도 함께 처리해 봅니다.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'PM Functional Location Tree'
define view entity ZC_PMFLocTreeView
as select from I_FunctionalLocation as Parent
association [0..*] to I_FunctionalLocation as _Child
on _Child.SuperiorFunctionalLocation = Parent.FunctionalLocation
association [0..1] to I_FunctionalLocationText as _Text
on _Text.FunctionalLocation = Parent.FunctionalLocation
and _Text.Language = $session.system_language
{
key Parent.FunctionalLocation as FLocCode,
Parent.MaintenancePlant as Plant,
Parent.SuperiorFunctionalLocation as ParentFLoc,
Parent.FunctionalLocationCategory as Category,
_Text.FunctionalLocationName as DisplayName,
cast( '' as abap.char( 1 ) ) as HasChildrenFlag,
_Child
}
이 뷰를 호출하는 ABAP 측 로직에서는 자식 노드 존재 여부를 판단하고, 예외·로깅을 함께 처리합니다.
METHOD expand_one_level.
TRY.
SELECT FROM zc_pmfloctreeview
FIELDS FLocCode, DisplayName, ParentFLoc, Category
WHERE ParentFLoc = @iv_parent_floc
AND Plant = @iv_plant
INTO TABLE @DATA(lt_children).
IF lt_children IS INITIAL.
MESSAGE i001(zpm_log) WITH iv_parent_floc.
RETURN.
ENDIF.
LOOP AT lt_children ASSIGNING FIELD-SYMBOL(<fs>).
APPEND VALUE #( level = iv_level + 1
floc = <fs>-floccode
name = <fs>-displayname
parent = <fs>-parentfloc )
TO ct_tree.
ENDLOOP.
CATCH cx_sy_open_sql_db INTO DATA(lx_db).
cl_bali_log_handler=>save( iv_object = 'ZPM'
iv_subobject = 'FLOC_READ'
iv_message = lx_db->get_text( ) ).
RAISE EXCEPTION TYPE zcx_pm_floc_read.
ENDTRY.
ENDMETHOD.
핵심은 $session.system_language를 사용해 사용자 로그온 언어에 맞는 텍스트를 자동 매핑하고, 빈 결과·DB 예외를 분리해 처리한다는 점입니다.
실전 예제 3단계 — 작업지시·예방정비 연계 운영
운영 환경에서는 단일 위치 조회를 넘어, "특정 기능 위치 하위 전체에 걸린 미완료 Work Order"를 한 번에 보고 싶다는 요구가 자주 들어옵니다. 이 시나리오는 재귀 CTE 또는 AMDP(SQLScript 푸시다운)로 풀어내는 것이 일반적입니다.
CLASS zcl_pm_floc_orders DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
TYPES: BEGIN OF ty_result,
floc TYPE i_functionallocation-functionallocation,
order_id TYPE i_maintenanceorder-maintenanceorder,
order_status TYPE c LENGTH 4,
priority TYPE c LENGTH 1,
END OF ty_result,
tt_result TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY.
CLASS-METHODS read_open_orders
IMPORTING VALUE(iv_root_floc) TYPE i_functionallocation-functionallocation
EXPORTING VALUE(et_result) TYPE tt_result.
ENDCLASS.
CLASS zcl_pm_floc_orders IMPLEMENTATION.
METHOD read_open_orders BY DATABASE PROCEDURE
FOR HDB LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING i_functionallocation i_maintenanceorder.
floc_tree = WITH RECURSIVE tree( floc, parent ) AS (
SELECT functionallocation, superiorfunctionallocation
FROM i_functionallocation
WHERE functionallocation = :iv_root_floc
UNION ALL
SELECT f.functionallocation, f.superiorfunctionallocation
FROM i_functionallocation AS f
JOIN tree AS t
ON f.superiorfunctionallocation = t.floc
)
SELECT floc FROM tree;
et_result =
SELECT o.functionallocation AS floc,
o.maintenanceorder AS order_id,
o.maintenanceorderstatus AS order_status,
o.priority AS priority
FROM i_maintenanceorder AS o
INNER JOIN :floc_tree AS t
ON o.functionallocation = t.floc
WHERE o.maintenanceorderstatus <> 'CLSD';
ENDMETHOD.
ENDCLASS.
이 AMDP는 DB 레이어에서 한 번의 호출로 트리 전개와 조인을 끝내기 때문에, ABAP 측에서 반복 SELECT를 도는 방식보다 일반적으로 응답 속도가 크게 빠릅니다. 단위 테스트는 ABAP Unit으로 cl_osql_test_environment를 사용해 IFLOT·I_MaintenanceOrder를 mocking하면 PRD 데이터와 분리해 검증할 수 있습니다.
자주 부딪히는 문제와 FAQ
운영 중 다음과 같은 함정이 반복적으로 보고됩니다.
- TPLNR 외부/내부 포맷 혼동 — IFLOT의 TPLNR은 내부 포맷(공백 패딩)으로 저장되고, 화면 표시는 변환 루틴
CONVERSION_EXIT_TPLNR_OUTPUT을 거칩니다. CDS에서 비교할 때는 반드시 내부 포맷 값을 사용하세요. - 텍스트 누락 — IFLOTX에 로그온 언어 행이 없으면 DisplayName이 공백으로 나옵니다.
$session.system_language대신 fallback 언어를 LEFT OUTER JOIN으로 한 번 더 거는 패턴이 권장됩니다. - 계층 무한 루프 — 잘못된 데이터로 A→B→A 같은 순환이 생기면 재귀 CTE가 폭주합니다. OPTION MAXRECURSION 안전장치나 깊이 컬럼을 두어 차단하세요.
FAQ 1. I_FunctionalLocation을 SELECT했는데 Released API와 다른 컬럼이 보입니다. → SAP S/4HANA Cloud의 Released CDS는 더 제한적입니다. ADT에서 API State annotation을 확인하고, 가능하면 외부 API용 API_FUNCTIONLOC OData 서비스를 사용하는 편이 안전합니다.
FAQ 2. 장비(Equipment)와 어떻게 연결하나요? → EQUI 테이블의 TPLNR 필드가 현재 설치된 FLoc을 가리킵니다. CDS 측에서는 I_Equipment 뷰와 association을 걸어 _InstalledAtFunctionalLocation 형태로 탐색합니다.
FAQ 3. 트리 깊이가 10단계가 넘어 화면이 느립니다. → UI에서는 lazy expand(클릭 시 한 단계씩 펼치기)를 적용하고, DB 레이어에서는 첫 진입 시 SuperiorFunctionalLocation IS INITIAL 루트만 로딩하도록 분리하는 패턴이 일반적입니다.
이어서 살펴보면 좋은 주제
I_FunctionalLocation을 익혔다면 다음 단계로 확장해 보길 권장합니다. (1) I_Equipment·I_MaintenanceOrder와의 조인을 활용한 Fiori Elements 기반 List Report 개발, (2) BOM(Bill of Material)과 연계한 자재·예비품 추적, (3) Asset Central Foundation을 통한 Cloud Asset Hierarchy 연동, (4) RAP(ABAP RESTful Application Programming Model)로 FLoc 등록/수정 서비스 만들기, (5) Embedded Analytics로 FLoc 단위 가동률·MTBF KPI 대시보드 구성. 특히 RAP + Draft를 사용하면 PM 마스터 데이터 편집 UX를 표준 패턴으로 빠르게 구현할 수 있습니다.
댓글 0
아직 댓글이 없습니다.