구매부터 지급까지: 구매오더 데이터 템플릿
구매부터 지급까지: 구매오더 데이터 템플릿
- 수집 권장 속성
- 추적할 주요 활동
- SAP ECC 데이터 추출 안내
구매부터 지급까지: 구매오더 속성
| 이름 | 설명 | ||
|---|---|---|---|
| 구매 오더 PurchaseOrder | 구매 오더(PO) 문서의 고유 식별자로, 조달 프로세스를 추적하는 기본 케이스로 사용됩니다. | ||
| 설명 구매 오더 번호는 생성부터 최종 입고 및 완료까지 모든 활동을 연결하는 중심 식별자입니다. 고유한 PO 번호 하나가 조달 프로세스의 단일 사례를 나타냅니다. process mining에서는 이 속성을 바탕으로 각 구매의 전체 진행 과정을 재구성합니다. 개별 주문의 주기 시간, 프로세스 변형, 규정 준수 여부를 상세히 분석할 수 있어 전체 프로세스 모델의 기반이 됩니다. 중요한 이유 관련 이벤트를 모두 연결하는 기본 식별자이므로 개별 구매 오더의 전체 수명 주기를 분석할 수 있습니다. 확보 방법 테이블: EKKO, 필드: EBELN 예시 450001762345000176244500017625 | |||
| 이벤트 시간 EventTime | 활동이 발생한 정확한 날짜와 시간입니다. | ||
| 설명 이 타임스탬프는 PO 승인이나 입고 전기와 같은 이벤트가 발생한 정확한 시점을 나타냅니다. 케이스 내 모든 활동의 시간 순서를 확인하는 데 사용됩니다. 타임스탬프는 시간 기반 분석의 토대입니다. 활동 간 주기 시간 계산, 지연 파악, 프로세스 처리량 분석, 서비스 수준 계약(SLA) 대비 성과 측정에 활용됩니다. 중요한 이유 이 타임스탬프는 주기 시간과 병목 등 기간 기반 지표를 계산하고 이벤트를 시간순으로 정렬하는 데 중요합니다. 확보 방법 EKKO-AEDAT(변경일), CDHDR-UDATE/UTIME(변경 로그 타임스탬프), EKBE-BUDAT(전기일) 등 SAP 테이블의 여러 날짜 및 시간 필드에서 가져옵니다. 예시 2023-04-15T10:05:31Z2023-04-16T14:22:00Z2023-05-01T09:00:15Z | |||
| 활동 Activity | 구매 오더 수명 주기에서 발생한 특정 업무 이벤트 또는 단계의 이름입니다. | ||
| 설명 이 속성은 '구매 오더 생성', '구매 오더 승인', '입고 전기'와 같은 프로세스의 개별 단계를 나타냅니다. 각 활동이 이어지는 순서가 구매 오더별 프로세스 흐름을 구성합니다. 활동의 순서와 빈도, 활동 간 소요 시간을 분석하는 것이 process mining의 핵심입니다. 이를 통해 병목, 재작업 반복, 표준 프로세스와의 차이를 찾아 개선과 표준화를 추진할 수 있습니다. 중요한 이유 활동은 프로세스의 단계를 정의합니다. 활동의 순서와 시점을 분석하면 실제 프로세스 흐름과 병목, 표준에서 벗어난 부분을 파악할 수 있습니다. 확보 방법 변경 내역의 CDHDR/CDPOS, 입고 및 송장의 EKBE, 구매 요청의 EBAN 등 여러 SAP 테이블과 트랜잭션 로그에서 가져옵니다. 데이터를 생성하려면 사용자 지정 로직이나 추출 프로그램이 필요한 경우가 많습니다. 예시 구매 오더 생성구매 오더 승인입고 전기 | |||
| 공급업체 번호 VendorNumber | 공급업체를 식별하는 고유 번호입니다. | ||
| 설명 상품이나 서비스를 조달하는 공급업체를 고유하게 식별하는 코드입니다. 조달 프로세스의 주요 마스터 데이터입니다. 이 속성은 공급업체별 분석에 필요합니다. 공급업체의 납품 성과를 평가하고, 공급업체별 납품 소요 시간을 비교하며, 지출 패턴을 분석할 수 있습니다. '공급업체 납품 성과' 대시보드의 기본 분석 기준입니다. 중요한 이유 공급업체 성과를 분석해 신뢰할 수 있는 공급업체와 지연 또는 품질 문제를 일으키는 공급업체를 파악할 수 있습니다. 확보 방법 테이블: EKKO, 필드: LIFNR 예시 100345V-20598700112 | |||
| 문서 유형 DocumentType | 구매 오더의 유형을 구분하는 코드입니다. | ||
| 설명 문서 유형은 구매 오더의 번호 범위, 필드 선택, 전체 프로세스 흐름을 제어하는 SAP 설정입니다. 예를 들어 표준 PO, 서비스 PO, 재고 운송 오더에 서로 다른 유형을 지정할 수 있습니다. 문서 유형에 따라 의도적으로 다른 프로세스를 따르는 경우가 많으므로 분석에 유용한 기준입니다. 문서 유형별로 필터링하면 주기 시간과 프로세스 흐름을 더 정확하게 비교할 수 있습니다. 중요한 이유 표준 구매, 서비스 구매, 반품 등 구매 프로세스 유형을 구분합니다. 유형마다 처리 경로와 성과 기준이 다를 수 있습니다. 확보 방법 테이블: EKKO, 필드: BSART 예시 NBFOUB | |||
| 사용자 이름 UserName | 활동을 실행한 사람의 사용자 ID입니다. | ||
| 설명 이 속성은 문서를 생성, 변경 또는 승인한 직원의 SAP 사용자 이름을 기록합니다. 자동화된 단계에서는 시스템 또는 배치 사용자 ID가 표시될 수 있습니다. 사용자별 분석을 통해 교육이 필요한 영역, 성과가 높은 담당자 또는 잠재적인 규정 준수 문제를 파악할 수 있습니다. 업무량 분배와 승인 매트릭스 준수 여부를 보여주는 대시보드를 구성하고 팀이나 개인의 성과를 이해하는 데도 중요합니다. 중요한 이유 사용자 작업을 담당자별로 연결해 사용자 성과와 업무량, 규정 준수 절차 준수 여부를 분석할 수 있습니다. 확보 방법 테이블: EKKO, 필드: ERNAM(생성자); 테이블: CDHDR, 필드: USERNAME(변경자). 예시 JSMITHMBROWNBATCH_USER | |||
| 자재 그룹 MaterialGroup | 특성이 비슷한 자재나 서비스를 분류하는 기준입니다. | ||
| 설명 자재 그룹 또는 구매 범주는 조달 대상인 상품이나 서비스의 유형을 분류하는 데 사용합니다. 예를 들면 'IT 하드웨어', '사무용품', '전문 서비스'가 있습니다. 이 속성은 지출 분석과 조달 패턴 파악에 중요합니다. 범주별로 프로세스를 필터링해 처리 방식, 승인 담당자, 공급업체를 분석할 수 있습니다. '구매 오더 금액 분석' 대시보드의 주요 분석 기준입니다. 중요한 이유 상품 또는 서비스 범주별로 프로세스를 나누어 지출 유형에 따른 처리 방식, 주기 시간, 공급업체의 차이를 확인할 수 있습니다. 확보 방법 테이블: EKPO, 필드: MATKL 예시 00101IT_HWCONSULT | |||
| 주문 금액 OrderAmount | 구매 오더의 개별 항목에 대한 총 금액입니다. | ||
| 설명 이 속성은 구매 오더의 특정 항목에 대한 총액으로, 수량에 순가격을 곱해 계산합니다. PO 전체 금액을 구하려면 항목별 금액을 합산해야 합니다. 주문 금액별로 프로세스를 분석하면 더 엄격한 통제나 별도의 승인 경로가 필요한 고액 거래를 파악할 수 있습니다. '구매 오더 금액 분석' 대시보드에 활용되며, 재무 영향이 큰 주문을 중심으로 프로세스 개선의 우선순위를 정하는 데 도움이 됩니다. 중요한 이유 구매 건별 재무 영향을 수치화해 고액 주문의 우선순위를 정하고 비용 절감 기회를 찾을 수 있습니다. 확보 방법 테이블: EKPO, 필드: NETWR(순 주문 금액). 예시 1500.00250.7512345.50 | |||
| 회사 코드 CompanyCode | 구매를 시작한 법인 또는 회사를 식별하는 코드입니다. | ||
| 설명 회사 코드는 SAP에서 독립된 법인을 나타냅니다. 모든 거래가 회사 코드 단위로 전기되므로 기본적인 조직 단위로 사용됩니다. 회사 코드별로 프로세스를 분석하면 사업부나 국가별 조달 효율과 규정 준수 여부를 비교할 수 있습니다. 한 법인의 우수 사례를 다른 곳에 적용하거나, 프로세스에 어려움을 겪는 조직을 파악하는 데 도움이 됩니다. 중요한 이유 법인을 나타내며 조직 내 여러 부문의 프로세스 성과 비교와 규정 준수 확인에 활용됩니다. 확보 방법 테이블: EKKO, 필드: BUKRS 예시 10002100US01 | |||
| 거부 사유 RejectionReason | 구매요청 또는 구매오더가 거부된 이유를 설명하는 코드나 문구입니다. | ||
| 설명 이 속성에는 승인 워크플로에서 구매오더가 거부될 때 제시된 구체적인 사유가 기록됩니다. 재작업과 지연의 근본 원인을 파악하는 데 중요한 정보입니다. 거부 사유를 분석하면 가격 오류, 예산 초과, 규정에 맞지 않는 공급업체 선정 등 반복되는 문제를 찾을 수 있습니다. 이를 바탕으로 근본 원인을 해결하고, 최초 PO 작성의 품질을 높이며, 승인 프로세스를 간소화할 수 있습니다. 중요한 이유 승인이 실패한 이유를 직접 파악할 수 있어 재작업을 줄이고 승인 소요 시간을 단축하기 위한 개선에 활용할 수 있습니다. 확보 방법 이 정보는 찾기 어려울 수 있습니다. 긴 텍스트 필드에 저장되어 있거나 사용자 지정 워크플로 설정에 따라 위치가 달라질 수 있으며, 확인하려면 구체적인 구현 지식이 필요한 경우가 많습니다. 예시 가격 오류예산 초과중복 요청 | |||
| 공급업체명 VendorName | 공급업체의 법적 명칭입니다. | ||
| 설명 공급업체 번호보다 사용자가 이해하기 쉬운 공급업체 이름입니다. 일반적으로 공급업체 마스터 데이터에서 가져옵니다. 공급업체 번호는 데이터 연결과 고유 식별에 사용하고, 공급업체명은 사용자용 대시보드와 보고서에 사용합니다. 공급업체 코드를 잘 모르는 현업 사용자도 분석 결과를 쉽게 이해할 수 있습니다. 중요한 이유 공급업체를 알아보기 쉬운 이름으로 표시해 현업 사용자가 대시보드와 보고서를 쉽게 이해할 수 있습니다. 확보 방법 테이블: LFA1, 필드: NAME1. EKKO-LIFNR과 LFA1-LIFNR을 연결해야 합니다. 예시 Staples Inc.Global Tech SolutionsOffice Supply Co. | |||
| 구매 그룹 PurchasingGroup | 조달 활동을 담당하는 구매 담당자 또는 담당자 그룹입니다. | ||
| 설명 구매 그룹은 특정 구매 활동을 담당하는 구매 담당자 또는 팀을 나타냅니다. 공급업체의 주요 연락 창구 역할을 합니다. 이 속성을 사용하면 구매 조직보다 세부적으로 분석할 수 있습니다. 구매 담당자별 업무량 분포와 성과 차이를 파악해 리소스 배분과 교육 계획에 반영할 수 있습니다. 중요한 이유 구매 담당자나 팀별로 구매 책임자를 세부적으로 파악할 수 있어 업무량과 성과를 분석하는 데 도움이 됩니다. 확보 방법 테이블: EKKO, 필드: EKGRP 예시 001002N01 | |||
| 구매 요청 PurchaseRequisition | 구매 오더에 앞서 생성된 구매 요청의 식별자입니다. | ||
| 설명 이 속성은 구매 오더와 이를 시작한 구매 요청을 연결합니다. 모든 PO에 선행 구매 요청이 있는 것은 아닙니다. 이 연결 정보는 '구매 요청에서 주문으로 전환' 대시보드와 'PR에서 PO로 전환율' KPI를 분석하는 데 중요합니다. 최초 요청부터 공식 주문 생성까지 상위 프로세스의 효율을 측정하고, 구매 요청 없이 생성된 규정 미준수 PO를 찾을 수 있습니다. 중요한 이유 PO와 원래 요청을 연결해 PR에서 PO로 전환되는 프로세스를 분석하고, 사전 구매 요청 없이 생성된 PO를 식별할 수 있습니다. 확보 방법 테이블: EKPO, 필드: BANFN 예시 1001589010015891 | |||
| 구매 조직 PurchasingOrganization | 가격 협상과 자재 또는 서비스 조달을 담당하는 조직 단위입니다. | ||
| 설명 구매 조직은 SAP에서 조달 활동을 담당하는 주요 조직 단위입니다. 회사 전체를 중앙에서 담당하거나 플랜트 또는 지역별로 분산해 운영할 수 있습니다. 구매 조직별 프로세스 성과를 분석하면 조달팀의 효율성을 비교할 수 있습니다. 조직 단위별 주기 시간, 재작업률, 비용을 비교해 우수 사례와 지원이 필요한 영역을 파악할 수 있습니다. 중요한 이유 조달 담당 팀을 식별해 조직 단위별 성과를 비교하고 분석할 수 있습니다. 확보 방법 테이블: EKKO, 필드: EKORG 예시 1000US01DE01 | |||
| 소스 시스템 SourceSystem | 데이터를 추출한 시스템입니다. | ||
| 설명 이 속성은 데이터의 출처를 나타내며, 일반적으로 SAP ECC 인스턴스 식별자(예: 'ECC_PROD_100')를 사용합니다. 시스템이 여러 개인 환경에서는 데이터 소스를 구분하는 데 도움이 됩니다. 데이터 거버넌스와 계보를 관리하려면 소스 시스템을 파악해야 합니다. 데이터 무결성을 확인하고 추출 또는 품질 문제를 해결하는 데 도움이 되며, 특히 여러 ERP 시스템이나 모듈의 데이터를 병합할 때 유용합니다. 중요한 이유 데이터의 출처를 식별합니다. 데이터 거버넌스와 검증, 여러 시스템에 걸친 분석 관리에 중요합니다. 확보 방법 일반적으로 데이터 추출 과정에서 데이터 세트의 출처를 표시하기 위해 추가하는 고정값입니다. 예시 SAP_ECC_PRODECC_EU_100S4H_FIN | |||
| 승인 후 변경 여부 IsPostApprovalChange | 최초 승인 후 구매오더(PO)가 변경되었는지 나타내는 플래그입니다. | ||
| 설명 같은 PO에서 '구매오더 승인' 활동 이후 '구매오더 변경' 활동이 확인되면 이 불리언 속성은 true입니다. 프로세스 후반에 발생한 문제성 변경을 구분하는 데 도움이 됩니다. 이 계산 필드는 '승인 후 PO 변경률' KPI와 '구매오더 재작업 및 변경' 대시보드에 직접 활용됩니다. 지연과 재승인을 유발할 수 있는 변경의 규모와 영향을 파악하고, 최초 사양이나 범위 설정 과정의 문제를 찾을 수 있습니다. 중요한 이유 승인 후 재작업을 직접 측정하는 지표로, 프로세스 안정성과 효율성을 평가하는 데 중요합니다. 비율이 높으면 앞선 요구사항 정의 단계에 문제가 있을 수 있습니다. 확보 방법 이 계산 속성은 이벤트 로그에 기록된 활동 순서를 바탕으로 산출됩니다. 예시 truefalse | |||
| 요청 납품일 RequestedDeliveryDate | 사업 부문에서 공급업체에 상품이나 서비스를 납품해 달라고 요청한 날짜입니다. | ||
| 설명 구매 오더에 지정된 목표 납품일입니다. 실제 납품 성과를 측정할 때 기준으로 사용합니다. 이 날짜는 '정시 입고율' KPI를 계산하는 데 필요합니다. 실제 입고일과 요청 납품일을 비교하면 공급업체의 신뢰도와 내부 입고 처리 효율을 정량적으로 측정할 수 있으며, '공급업체 납품 성과' 대시보드에도 활용됩니다. 중요한 이유 납품 목표일로, 정시 납품 KPI를 계산하고 공급업체의 신뢰도를 평가하는 데 필요합니다. 확보 방법 테이블: EKPO, 필드: EINDT 예시 2023-06-102023-07-222023-08-01 | |||
| 정시 납품 여부 IsOnTimeDelivery | 요청한 납품일 당일 또는 그 전에 물품을 입고했는지 나타내는 플래그입니다. | ||
| 설명 '물품 입고 전기' 활동의 타임스탬프가 '요청 납품일'과 같거나 이전이면 이 불리언 속성은 true입니다. PO 품목별 납품 성과를 명확하게 구분할 수 있습니다. 이 속성은 '정시 물품 입고율' KPI의 기반이 됩니다. 정시 납품과 지연 납품을 쉽게 집계하고 필터링할 수 있어 공급업체 성과와 내부 입고 효율을 간편하게 분석할 수 있습니다. 중요한 이유 납품 적시성을 성공 또는 실패로 명확하게 측정해 공급업체 성과 KPI와 대시보드에 활용할 수 있습니다. 확보 방법 물품 입고 전기일(EKBE-BUDAT)과 요청 납품일(EKPO-EINDT)을 비교해 산출하는 계산 속성입니다. 예시 truefalse | |||
| 최종 데이터 갱신 LastDataUpdate | 소스 시스템에서 데이터를 마지막으로 갱신한 시점을 나타내는 타임스탬프입니다. | ||
| 설명 이 속성은 가장 최근에 데이터를 추출하거나 갱신한 날짜와 시간을 기록합니다. 분석 대상 데이터가 얼마나 최신인지 확인할 수 있습니다. 대시보드에 이 정보를 표시하면 사용자가 분석 결과가 거의 실시간 데이터에 기반하는지, 과거 시점의 데이터에 기반하는지 알 수 있습니다. 데이터의 기준 시점을 명확히 해 의사결정에 대한 기대치를 조정할 수 있습니다. 중요한 이유 데이터의 최신성을 알려 사용자가 분석 결과가 현재 운영 상태를 반영하는지 파악할 수 있도록 합니다. 확보 방법 실행 시 데이터 추출 또는 ETL 프로세스에서 생성해 추가하는 타임스탬프입니다. 예시 2023-10-27T02:00:00Z2023-10-28T02:00:00Z | |||
| 통화 Currency | 구매 오더 금액의 통화 코드입니다. | ||
| 설명 이 속성은 구매 오더 금액의 통화를 지정합니다. 예를 들어 USD, EUR 또는 GBP가 해당합니다. 모든 금액을 해석하는 데 필요한 정보입니다. 글로벌 조직의 재무 분석에서는 통화 정보가 필수입니다. 주문 금액을 정확하게 합산하고 비교할 수 있으며, 금액 기준 KPI는 해당 통화를 고려해 해석해야 합니다. 중요한 이유 모든 금액의 통화 정보를 제공해 정확한 재무 분석을 지원합니다. 다국적 조직에서 특히 중요합니다. 확보 방법 테이블: EKKO, 필드: WAERS 예시 USDEURJPY | |||
| 플랜트 Plant | 물품을 납품받을 실제 장소 또는 플랜트입니다. | ||
| 설명 플랜트는 생산 시설, 창고 또는 물품이나 서비스를 받는 기타 장소를 나타내는 조직 단위입니다. 플랜트별로 분석하면 조달 프로세스의 지역별 차이를 파악할 수 있습니다. 특정 지역의 공급업체 납품 시간이 다른 지역과 어떻게 다른지 확인하거나, 입고 처리가 비효율적인 플랜트를 찾아 물품 입고의 적시성을 분석할 수 있습니다. 중요한 이유 납품 장소를 지정합니다. 지역별 프로세스 차이와 물류 성과를 분석할 때 유용합니다. 확보 방법 테이블: EKPO, 필드: WERKS 예시 100011002000 | |||
구매부터 지급까지: 구매오더 활동
| 활동 | 설명 | ||
|---|---|---|---|
| 구매 오더 생성 | 이 활동은 공급업체와의 구속력 있는 계약인 공식 구매 오더 문서가 생성된 시점을 나타냅니다. 사용자가 ME21N과 같은 트랜잭션에서 PO를 생성하고 저장하면 명시적 이벤트로 기록되며, EKKO 및 EKPO 테이블에 항목이 생성됩니다. | ||
| 중요한 이유 구매 오더 수명 주기의 공식적인 시작점입니다. PR에서 PO로 전환되는 시간과 주문 이행까지 걸리는 전체 시간을 측정하는 주요 기준점입니다. 확보 방법 해당 PO 번호(EKKO-EBELN)에 대해 구매 오더 헤더 테이블(EKKO)의 생성일(EKKO-AEDAT)을 기준으로 기록합니다. 기록 신규 구매 오더마다 EKKO 테이블의 생성 타임스탬프를 사용합니다. 이벤트 유형 explicit | |||
| 구매 오더 승인 | 구매 오더를 공급업체에 보낼 수 있도록 최종 승인한 상태를 나타냅니다. 일반적으로 PO의 릴리스 상태가 '완전 릴리스' 또는 '승인' 상태로 변경된 시점을 기준으로 추론합니다. | ||
| 중요한 이유 이 활동은 PO 승인 주기 KPI를 계산하고 승인 워크플로의 병목을 파악하는 데 중요합니다. 공급업체에 주문을 보내는 등 대부분의 후속 활동을 진행하기 위한 선행 조건입니다. 확보 방법 구매 오더 헤더 테이블(EKKO)의 변경 로그(CDHDR/CDPOS)를 추적해 최종 릴리스 코드가 적용된 시점이나 전체 릴리스 상태 표시기(EKKO-FRGKE)가 '릴리스됨'으로 설정된 시점을 확인합니다. 기록 PO의 전체 릴리스 상태(EKKO-FRGKE)가 최종 승인 상태로 변경된 타임스탬프를 확인합니다. 이벤트 유형 inferred | |||
| 구매 오더 완료 | 구매 오더 항목의 납품이 모두 완료된 상태를 나타냅니다. 일반적으로 구매 오더 항목의 '납품 완료' 표시가 자동 또는 수동으로 설정된 시점을 기준으로 추론합니다. | ||
| 중요한 이유 주문 이행 프로세스의 논리적인 종료점입니다. 생성부터 완료까지의 전체 PO 주기를 계산하는 데 필요합니다. 확보 방법 구매 오더 항목의 '납품 완료' 표시(EKPO-ELIKZ)가 'X'로 설정된 시점을 기록한 변경 문서(CDHDR/CDPOS)를 바탕으로 추론합니다. 마지막 항목이 완료로 표시되면 전체 PO가 완료된 것으로 볼 수 있습니다. 기록 변경 문서에서 EKPO-ELIKZ 플래그가 설정된 타임스탬프를 확인합니다. 이벤트 유형 inferred | |||
| 구매 오더를 공급업체에 전송 | 승인된 구매 오더를 EDI, 이메일 또는 인쇄 등의 방식으로 공급업체에 공식 전송한 시점을 나타냅니다. 출력 메시지가 성공적으로 처리되면 메시지 제어 테이블에 명시적 이벤트로 기록됩니다. | ||
| 중요한 이유 공급업체의 납품 소요 시간 측정을 시작하는 주요 기준점입니다. 이 이벤트부터 입고까지 걸리는 시간을 분석하면 공급업체의 성과와 납기 준수 여부를 평가할 수 있습니다. 확보 방법 메시지 상태 테이블(NAST)에 기록됩니다. 해당 PO 출력 유형의 처리 상태(NAST-VSTAT)가 '1'(성공적으로 처리됨)인 경우 NAST-DATVR 및 NAST-UHRVR에서 타임스탬프를 가져올 수 있습니다. 기록 PO 출력 메시지의 처리 타임스탬프를 NAST 테이블에서 가져옵니다. 이벤트 유형 explicit | |||
| 구매 요청 생성 | 이 활동은 상품이나 서비스에 대한 공식 요청이 생성된 시점을 나타냅니다. 사용자가 ME51N과 같은 트랜잭션에서 새 구매 요청 문서를 저장하면 명시적 이벤트로 기록되며, EBAN 테이블에 고유한 레코드가 생성됩니다. | ||
| 중요한 이유 조달 프로세스의 주요 시작점입니다. 이 이벤트부터 구매 오더 생성까지 걸리는 시간을 분석하면 내부 수요를 실제 주문으로 전환하는 효율을 측정할 수 있습니다. 확보 방법 구매 요청 헤더 테이블(EBAN)에 항목이 생성될 때 기록됩니다. 이벤트의 타임스탬프는 생성일(EBAN-BADAT)과 시간입니다. 기록 생성일을 기준으로 EBAN 테이블의 신규 항목을 식별합니다. 이벤트 유형 explicit | |||
| 입고 전기 | 특정 구매 오더에 따라 공급업체의 상품을 실제로 인수한 시점을 나타냅니다. MIGO와 같은 트랜잭션에서 입고를 전기하면 자재 문서가 생성되고 재고가 갱신됩니다. | ||
| 중요한 이유 공급업체 납품 성과를 추적하고 송장 검증 프로세스의 시작을 확인하는 주요 기준점입니다. 정시 입고율과 입고 적시성을 계산하는 데 사용됩니다. 확보 방법 자재 문서가 생성될 때 기록됩니다. 이벤트 타임스탬프는 자재 문서 헤더 테이블(MKPF)의 전기일(MKPF-BUDAT) 또는 생성일(MKPF-CPUDT)이며, 항목 테이블(MSEG)을 통해 PO와 연결됩니다. 기록 PO를 참조하는 자재 문서의 전기 또는 생성 타임스탬프를 MKPF 테이블에서 가져옵니다. 이벤트 유형 explicit | |||
| 구매 오더 거부 | 승인자가 승인 워크플로 중 구매 오더를 거부할 때 발생합니다. PO 릴리스 전략 데이터의 상태 변경을 바탕으로 거부가 발생한 시점을 추론합니다. | ||
| 중요한 이유 거부 내역을 추적하면 PO 데이터 품질 문제, 정책 미준수 또는 승인 매트릭스의 문제를 파악할 수 있습니다. 거부는 재작업으로 이어지는 경우가 많아 전체 주기를 늘립니다. 확보 방법 구매 오더 릴리스 상태에 대한 변경 문서(CDHDR/CDPOS)에서 추론합니다. 일반적으로 릴리스 코드가 취소되거나 특정 거부 상태가 설정되면 거부로 기록됩니다. 기록 릴리스 코드 취소 또는 거부를 나타내는 상태 변경이 있는지 변경 로그를 확인합니다. 이벤트 유형 inferred | |||
| 구매 오더 변경 | 최초 생성 후 구매 오더의 수량, 가격 또는 납품일 등을 수정한 경우를 나타냅니다. 이러한 변경은 SAP 변경 문서 시스템에 명시적으로 기록됩니다. | ||
| 중요한 이유 특히 승인 후 변경이 잦다면 프로세스 비효율, 초기 계획 미흡 또는 범위 확대를 나타낼 수 있습니다. 이 활동은 PO 재작업 및 변경 대시보드와 관련 KPI를 구성하는 데 필요합니다. 확보 방법 구매 오더 객체(EINKBELEG)의 변경 문서 헤더(CDHDR) 및 항목(CDPOS) 테이블에 명시적으로 기록됩니다. 변경이 발생할 때마다 타임스탬프가 포함된 새 항목이 생성됩니다. 기록 구매 오더 번호와 연결된 CDHDR 및 CDPOS 테이블에서 변경 이벤트와 타임스탬프를 추출합니다. 이벤트 유형 explicit | |||
| 구매 오더 삭제 | 구매 오더 항목을 취소하거나 논리적으로 삭제해 입고 또는 송장 처리와 같은 후속 처리를 막는 경우를 나타냅니다. PO 항목에 삭제 표시가 설정된 시점을 기준으로 추론합니다. | ||
| 중요한 이유 주문이 취소되었음을 나타내는 종료 활동입니다. 주문이 삭제된 이유와 시점을 분석하면 수요 계획이나 공급업체 선정의 문제를 파악할 수 있습니다. 확보 방법 구매 오더 항목의 삭제 표시(EKPO-LOEKZ)가 'L'로 설정된 기록이 있는 변경 문서(CDHDR/CDPOS)를 바탕으로 추론합니다. 기록 변경 문서에서 EKPO-LOEKZ 플래그가 설정된 타임스탬프를 확인합니다. 이벤트 유형 inferred | |||
| 구매 오더 승인 요청 | 생성되거나 변경된 구매 오더가 설정된 릴리스 전략에 따라 승인을 위해 제출된 상태를 나타냅니다. 릴리스 전략이 시작되고 PO가 승인 대기 상태가 되면 이 이벤트를 추론합니다. | ||
| 중요한 이유 PO 생성 시점과 승인 절차 시작 시점을 구분하면 승인 주기 KPI를 정확하게 측정할 수 있습니다. 승인 워크플로가 시작되기까지의 지연도 확인할 수 있습니다. 확보 방법 구매 오더(EINKBELEG 객체)의 변경 문서(CDHDR/CDPOS)에서 릴리스 상태가 처음 설정된 기록을 확인하거나, 전체 릴리스 상태(EKKO-FRGKE)가 승인 절차가 진행 중임을 나타내는 값으로 처음 설정된 시점을 기준으로 추론합니다. 기록 PO의 릴리스 전략을 시작하는 첫 번째 변경 문서 항목을 식별합니다. 이벤트 유형 inferred | |||
| 구매 요청 승인 | 구매 요청을 구매 오더로 전환할 수 있도록 공식 승인한 상태를 나타냅니다. SAP의 릴리스 전략 워크플로에서 추적하는 구매 요청 데이터의 릴리스 상태 필드 변경을 바탕으로 이 이벤트를 추론합니다. | ||
| 중요한 이유 승인 내역을 추적하면 주문 전 단계의 병목을 파악하고 승인 정책 준수 여부를 확인할 수 있습니다. 이 단계의 지연은 전체 조달 주기에 직접 영향을 줍니다. 확보 방법 구매 요청 테이블(EBAN)의 변경 로그에서 추론합니다. 특히 릴리스 상태 필드(예: EBAN-FRGZU)의 변경을 확인하거나, EBAN 객체에 대한 CDHDR/CDPOS 변경 문서를 분석합니다. 기록 EBAN 릴리스 상태 필드의 변경 문서를 추적해 최종 승인 타임스탬프를 확인합니다. 이벤트 유형 inferred | |||
| 상품 반품 | 품질 문제나 오배송 등으로 이미 입고한 상품을 공급업체에 반품하는 경우를 나타냅니다. 반품 전용 이동 유형으로 자재 문서를 전기하면 명시적 이벤트로 기록됩니다. | ||
| 중요한 이유 이 활동은 공급업체 품질이나 주문 정확도 문제를 보여주며, 프로세스 재작업을 나타내는 주요 지표입니다. 입고 차이율 KPI를 계산하는 데도 중요합니다. 확보 방법 반품 이동 유형(예: 공급업체 반품 납품에 사용하는 '122')을 사용하면 자재 문서 테이블(MKPF/MSEG)에 기록됩니다. 타임스탬프는 전기일(MKPF-BUDAT)입니다. 기록 원래 PO를 참조하는 반품 이동 유형(예: 122)의 자재 문서를 식별합니다. 이벤트 유형 explicit | |||
| 서비스 확인 입력 | 서비스 구매 오더의 경우, 서비스가 제공되었음을 확인하는 활동입니다. ML81N과 같은 트랜잭션에서 서비스 입력 시트(Service Entry Sheet)를 생성하면 명시적 이벤트로 기록됩니다. | ||
| 중요한 이유 서비스에 대한 입고에 해당하며 서비스 오더의 이행을 추적하는 데 필요합니다. 서비스 대금 지급을 위한 재무 프로세스가 시작됩니다. 확보 방법 서비스 입력 시트 헤더 테이블(ESSR)의 생성일(ESSR-ERDAT)을 기준으로 기록합니다. 구매 오더와의 연결 정보는 ESLL 테이블에 있습니다. 기록 PO와 연결된 서비스 입력 시트의 생성 타임스탬프를 ESSR 테이블에서 가져옵니다. 이벤트 유형 explicit | |||
| 품질 검사 수행 | 입고된 상품에 품질 검사가 수행되었음을 나타냅니다. 일반적으로 입고 시 생성된 검사 로트에 대해 품질 관리 모듈에서 사용 결정이 내려진 시점을 기준으로 추론합니다. | ||
| 중요한 이유 품질이 중요한 업종에서는 검사에 걸린 시간과 결과를 분석하는 데 도움이 됩니다. 이 단계가 지연되면 입고부터 사용 가능 상태가 되기까지 병목이 발생할 수 있습니다. 확보 방법 품질 관리 모듈의 데이터를 바탕으로 추론합니다. 입고 시 검사 로트가 생성되고(QALS 테이블), 타임스탬프가 포함된 사용 결정이 생성되면(QAVE 테이블) 해당 활동이 기록됩니다. 기록 자재 문서와 연결된 검사 로트에 대해 QAVE 테이블에서 사용 결정 타임스탬프를 확인합니다. 이벤트 유형 inferred | |||
데이터 추출 가이드
단계
- ABAP 프로그램 생성: 트랜잭션 코드 SE38을 사용해 ABAP Editor를 엽니다. 새 프로그램 이름(예: Z_PM_PO_EXTRACT)을 입력하고 'Create'를 클릭합니다. 'Process Mining PO Data Extraction'과 같은 제목을 입력하고 유형을 'Executable Program'으로 설정합니다.
- 선택 화면 정의: 프로그램에서 선택 화면 매개변수를 정의합니다. 이를 통해 사용자가 추출할 데이터를 필터링할 수 있습니다. 주요 매개변수에는 구매 오더 생성일 범위, 회사 코드(BUKRS), 구매 문서 유형(BSART)이 포함됩니다.
- 데이터 구조 정의: 최종 이벤트 로그 형식에 맞는 내부 테이블 구조를 선언합니다. 이 구조에는 PurchaseOrder, Activity, EventTime, UserName, VendorNumber, OrderAmount, MaterialGroup, CompanyCode, DocumentType 등 필수 및 권장 속성이 포함되어야 합니다.
- 데이터 선택 로직 구현: 필수 활동 14개 각각의 데이터를 선택하는 핵심 ABAP 로직을 작성합니다. EKKO, EKPO, EKBE, EBAN, CDHDR, CDPOS, NAST 등 여러 SAP 테이블을 조회해야 합니다. 코드를 체계적으로 관리하려면 활동마다 별도의 서브루틴(PERFORM)을 사용합니다.
- 구매 요청 데이터 선택: EBAN 테이블을 조회해 'Purchase Requisition Created' 이벤트를 찾고 EKPO 테이블을 통해 구매 오더와 연결합니다. 변경 로그 테이블(CDHDR, CDPOS)에서 릴리스 상태 필드의 변경을 추적해 'Purchase Requisition Approved' 이벤트를 식별합니다.
- 구매 오더 주요 이벤트 선택: EKKO 및 EKPO 테이블을 조회해 'Purchase Order Created' 이벤트를 찾습니다. 오브젝트 EINKBELEG의 변경 로그 테이블(CDHDR, CDPOS)을 사용해 릴리스 지시자 및 삭제 플래그와 같은 특정 필드의 변경을 기준으로 'Purchase Order Changed', 'Purchase Order Approved', 'Purchase Order Rejected', 'Purchase Order Completed', 'Purchase Order Deleted' 이벤트를 추출합니다.
- 구매 오더 전달 이벤트 선택: NAST 테이블에서 구매 오더가 성공적으로 전송된 레코드를 찾아 'Purchase Order Sent to Vendor' 활동을 수집합니다.
- 입고 및 서비스 이벤트 선택: EKBE 테이블에서 자재 문서 전기를 조회하고 이동 유형 범주를 기준으로 'Goods Receipt Posted' 및 'Goods Returned' 활동을 식별합니다. 서비스 입력 시트를 수집하려면 ESSR 및 ESLL을 조회해 'Services Confirmation Entered' 활동을 찾습니다.
- 품질 관리 이벤트 선택: Quality Management 모듈을 사용하는 경우 QALS 및 QAVE 테이블을 조회해 구매 오더와 연결된 검사 로트의 사용 결정 시점을 확인하고, 이를 'Quality Inspection Performed' 활동으로 기록합니다.
- 데이터 통합 및 형식 지정: 각 선택 작업에서 가져온 데이터를 하나의 최종 내부 테이블로 통합합니다. EventTime 필드의 형식이 일관적인지 확인합니다(예: YYYY-MM-DDTHH:MI:SS).
- 파일 다운로드 구현: 최종 내부 테이블을 파일로 다운로드하는 기능을 추가합니다. 권장 형식은 탭으로 구분된 파일 또는 CSV이며, GUI_DOWNLOAD 함수 모듈을 사용해 생성할 수 있습니다.
- 실행 및 저장: 트랜잭션 SE38 또는 SA38을 사용해 프로그램을 실행합니다. 선택 조건을 입력하고 보고서를 실행합니다. 메시지가 표시되면 결과 파일을 .csv 확장자로 로컬 컴퓨터에 저장합니다. 이제 업로드할 수 있습니다.
구성
- 날짜 범위: 추출할 날짜 범위를 지정해야 합니다. 일반적으로 구매오더 생성일(EKKO-AEDAT)을 기준으로 합니다. 데이터량과 프로세스 분석 범위를 고려할 때 3~6개월부터 시작하는 것이 좋습니다.
- 회사 코드(BUKRS): 하나 이상의 회사 코드를 필터링해 관련 법인만 추출합니다. 성능과 분석 적합성을 위해 중요한 매개변수입니다.
- 구매 문서 유형(BSART): 특정 문서 유형(예: 표준 PO인 'NB')을 필터링해 표준 프로세스에 집중하고, 필요한 경우 특수 조달 유형을 제외합니다.
- 데이터 세분성: 구매오더 품목 수준으로 데이터를 추출합니다. Case ID는 구매오더 번호(EBELN)입니다. 품목 수준의 물품 입고를 포함한 모든 이벤트는 이 기본 Case ID에 연결됩니다.
- 성능 고려 사항: 데이터가 많으면 프로그램을 백그라운드 작업(SM36)으로 예약해 시간 초과 오류를 방지합니다. 특히 CDHDR 및 CDPOS와 같이 WHERE 절에서 사용하는 주요 필드에 데이터베이스 인덱스가 있는지 확인합니다.
- 사전 요건: 보고서를 실행하는 사용자에게는 ABAP Workbench(SE38) 접근 권한과 프로그램 실행 권한이 필요합니다. EKKO, EKPO, EKBE, CDHDR, CDPOS, EBAN, NAST, ESSR 및 QM 테이블을 포함한 모든 관련 테이블에 대한 읽기 권한도 필요합니다.
샘플 쿼리 abap
REPORT Z_PM_PO_EXTRACT.
TABLES: ekko, ekpo, eban.
*&---------------------------------------------------------------------*
*& Data Structures for Event Log
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_event_log,
purchaseorder TYPE ebeln,
activity TYPE string,
eventtime TYPE timestamp,
username TYPE ernam,
vendornumber TYPE lifnr,
orderamount TYPE netwr_ak,
materialgroup TYPE matkl,
companycode TYPE bukrs,
documenttype TYPE bsart,
END OF ty_event_log.
DATA: gt_event_log TYPE TABLE OF ty_event_log.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS: s_aedat FOR ekko-aedat OBLIGATORY, " PO Creation Date
s_bukrs FOR ekko-bukrs, " Company Code
s_bsart FOR ekko-bsart, " PO Document Type
s_ebeln FOR ekko-ebeln. " PO Number
*&---------------------------------------------------------------------*
*& Main Processing Block
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM get_po_headers.
IF gt_event_log IS NOT INITIAL.
PERFORM get_pr_created.
PERFORM get_pr_approved.
PERFORM get_po_created.
PERFORM get_po_release_events. " Approved, Rejected, Approval Requested
PERFORM get_po_sent_to_vendor.
PERFORM get_po_changed.
PERFORM get_goods_receipt_posted.
PERFORM get_services_confirmed.
PERFORM get_quality_inspection.
PERFORM get_goods_returned.
PERFORM get_po_completed.
PERFORM get_po_deleted.
PERFORM download_to_csv.
ELSE.
MESSAGE 'No Purchase Orders found for the given criteria.' TYPE 'I'.
ENDIF.
*&---------------------------------------------------------------------*
*& Form GET_PO_HEADERS (Base data)
*&---------------------------------------------------------------------*
FORM get_po_headers.
SELECT h~ebeln, h~lifnr, h~bukrs, h~bsart, p~netwr, p~matkl
FROM ekko AS h
INNER JOIN ekpo AS p ON h~ebeln = p~ebeln
INTO TABLE @DATA(lt_po_base)
WHERE h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND h~bsart IN @s_bsart
AND h~ebeln IN @s_ebeln.
SORT lt_po_base BY ebeln.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PR_CREATED
*&---------------------------------------------------------------------*
FORM get_pr_created.
DATA: lt_pr_events TYPE TABLE OF ty_event_log.
SELECT p~ebeln AS purchaseorder,
'Purchase Requisition Created' AS activity,
b~erdat AS event_date,
'000000' AS event_time,
b~ernam AS username,
h~lifnr AS vendornumber,
p~netwr AS orderamount,
p~matkl AS materialgroup,
h~bukrs AS companycode,
h~bsart AS documenttype
FROM ekpo AS p
JOIN eban AS b ON p~banfn = b~banfn AND p~bnfpo = b~bnfpo
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE p~ebeln IN @s_ebeln
AND p~banfn IS NOT NULL AND p~banfn <> ''
AND h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND h~bsart IN @s_bsart
INTO TABLE @DATA(lt_pr_created).
LOOP AT lt_pr_created ASSIGNING FIELD-SYMBOL(<fs_pr>).
DATA(ls_event) = CORRESPONDING ty_event_log(<fs_pr>).
CONCATENATE <fs_pr>-event_date <fs_pr>-event_time INTO DATA(lv_ts).
CONVERT DATE <fs_pr>-event_date TIME '000000' INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PR_APPROVED
*&---------------------------------------------------------------------*
FORM get_pr_approved.
DATA: lt_pr_list TYPE TABLE OF eban-banfn.
SELECT DISTINCT p~banfn FROM ekpo AS p
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE h~aedat IN @s_aedat
AND h~bukrs IN @s_bukrs
AND p~banfn IS NOT NULL AND p~banfn <> ''
INTO TABLE @lt_pr_list.
IF lt_pr_list IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime, p~fname, p~value_new
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectid = p~objectid AND h~changenr = p~changenr
FOR ALL ENTRIES IN @lt_pr_list
WHERE h~objectclas = 'BANF'
AND h~objectid = @lt_pr_list-table_line
AND p~tabname = 'EBAN'
AND p~fname = 'FRGZU'
INTO TABLE @DATA(lt_cd_pr).
LOOP AT lt_cd_pr ASSIGNING FIELD-SYMBOL(<fs_cd>) WHERE <fs_cd>-value_new = 'X'.
SELECT SINGLE p~ebeln, p~netwr, p~matkl, h~lifnr, h~bukrs, h~bsart
FROM ekpo AS p
JOIN ekko AS h ON p~ebeln = h~ebeln
WHERE p~banfn = @<fs_cd>-objectid(10)
INTO @DATA(ls_po_info).
IF sy-subrc = 0.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = ls_po_info-ebeln
activity = 'Purchase Requisition Approved'
username = <fs_cd>-username
vendornumber = ls_po_info-lifnr
orderamount = ls_po_info-netwr
materialgroup = ls_po_info-matkl
companycode = ls_po_info-bukrs
documenttype = ls_po_info-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_CREATED
*&---------------------------------------------------------------------*
FORM get_po_created.
LOOP AT lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>).
SELECT SINGLE aedat, ernam FROM ekko INTO @DATA(ls_ekko)
WHERE ebeln = @<fs_po>-ebeln.
IF sy-subrc = 0.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Created'
username = ls_ekko-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE ls_ekko-aedat TIME '000000' INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDIF.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_RELEASE_EVENTS
*&---------------------------------------------------------------------*
FORM get_po_release_events.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime, p~value_new
FROM cdhdr AS h
JOIN cdpos AS p ON h~objectid = p~objectid AND h~changenr = p~changenr
WHERE h~objectclas = 'EINKBELEG'
AND h~objectid IN lt_ebeln
AND p~tabname = 'EKKO'
AND p~fname = 'FRGKE'
INTO TABLE @DATA(lt_cd_po).
LOOP AT lt_cd_po ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
CASE <fs_cd>-value_new.
WHEN '2' OR 'R'. " Final Release
ls_event-activity = 'Purchase Order Approved'.
WHEN '1'. " Blocked
ls_event-activity = 'Purchase Order Rejected'.
WHEN OTHERS. " Any other change implies a pending state
ls_event-activity = 'Purchase Order Approval Requested'.
ENDCASE.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_SENT_TO_VENDOR
*&---------------------------------------------------------------------*
FORM get_po_sent_to_vendor.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT objky, erdat, eruhr, ernam
FROM nast
WHERE kapol = 'EF' AND objky IN lt_ebeln AND vstat = '1'
INTO TABLE @DATA(lt_nast).
LOOP AT lt_nast ASSIGNING FIELD-SYMBOL(<fs_nast>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_nast>-objky.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Sent to Vendor'
username = <fs_nast>-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_nast>-erdat TIME <fs_nast>-eruhr INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_CHANGED
*&---------------------------------------------------------------------*
FORM get_po_changed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT DISTINCT objectid, username, udate, utime
FROM cdhdr
WHERE objectclas = 'EINKBELEG' AND objectid IN lt_ebeln AND tcode <> 'ME21N' AND tcode <> 'ME22'
INTO TABLE @DATA(lt_cdhdr_chg).
LOOP AT lt_cdhdr_chg ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Changed'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_GOODS_RECEIPT_POSTED
*&---------------------------------------------------------------------*
FORM get_goods_receipt_posted.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT k~ebeln, m~cpudt, m~cputm, m~usnam, k~bewtp
FROM ekbe AS k JOIN mkpf AS m ON k~belnr = m~mblnr AND k~gjahr = m~mjahr
WHERE k~ebeln IN lt_ebeln AND k~bewtp = 'E' AND k~shkzg = 'S'
INTO TABLE @DATA(lt_gr).
LOOP AT lt_gr ASSIGNING FIELD-SYMBOL(<fs_gr>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_gr>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Goods Receipt Posted'
username = <fs_gr>-usnam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_gr>-cpudt TIME <fs_gr>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_SERVICES_CONFIRMED
*&---------------------------------------------------------------------*
FORM get_services_confirmed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT l~ebeln, h~erdat, h~eruhr, h~ernam
FROM essr AS h JOIN esll AS l ON h~lblni = l~lblni
WHERE l~ebeln IN lt_ebeln
INTO TABLE @DATA(lt_ses).
LOOP AT lt_ses ASSIGNING FIELD-SYMBOL(<fs_ses>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_ses>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Services Confirmation Entered'
username = <fs_ses>-ernam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_ses>-erdat TIME <fs_ses>-eruhr INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_QUALITY_INSPECTION
*&---------------------------------------------------------------------*
FORM get_quality_inspection.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT q~ebeln, v~vdatum, v~vzeit, v~vname
FROM qals AS q JOIN qave AS v ON q~prueflos = v~prueflos
WHERE q~ebeln IN lt_ebeln
INTO TABLE @DATA(lt_qm).
LOOP AT lt_qm ASSIGNING FIELD-SYMBOL(<fs_qm>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_qm>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Quality Inspection Performed'
username = <fs_qm>-vname
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_qm>-vdatum TIME <fs_qm>-vzeit INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_GOODS_RETURNED
*&---------------------------------------------------------------------*
FORM get_goods_returned.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT k~ebeln, m~cpudt, m~cputm, m~usnam
FROM ekbe AS k JOIN mkpf AS m ON k~belnr = m~mblnr AND k~gjahr = m~mjahr
WHERE k~ebeln IN lt_ebeln AND k~bwart = '122'
INTO TABLE @DATA(lt_ret).
LOOP AT lt_ret ASSIGNING FIELD-SYMBOL(<fs_ret>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_ret>-ebeln.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Goods Returned'
username = <fs_ret>-usnam
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_ret>-cpudt TIME <fs_ret>-cputm INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_COMPLETED
*&---------------------------------------------------------------------*
FORM get_po_completed.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime
FROM cdhdr AS h JOIN cdpos AS p ON h~changenr = p~changenr AND h~objectid = p~objectid
WHERE h~objectclas = 'EINKBELEG' AND h~objectid IN lt_ebeln AND p~tabname = 'EKPO' AND p~fname = 'ELIKZ' AND p~value_new = 'X'
INTO TABLE @DATA(lt_cd_comp).
LOOP AT lt_cd_comp ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Completed'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form GET_PO_DELETED
*&---------------------------------------------------------------------*
FORM get_po_deleted.
DATA: lt_ebeln TYPE RANGE OF ebeln, ls_ebeln LIKE LINE OF lt_ebeln.
LOOP AT lt_po_base INTO DATA(ls_po_base).
ls_ebeln-sign = 'I'. ls_ebeln-option = 'EQ'. ls_ebeln-low = ls_po_base-ebeln.
APPEND ls_ebeln TO lt_ebeln.
ENDLOOP.
IF lt_ebeln IS INITIAL. RETURN. ENDIF.
SELECT h~objectid, h~username, h~udate, h~utime
FROM cdhdr AS h JOIN cdpos AS p ON h~changenr = p~changenr AND h~objectid = p~objectid
WHERE h~objectclas = 'EINKBELEG' AND h~objectid IN lt_ebeln AND p~tabname = 'EKPO' AND p~fname = 'LOEKZ' AND p~value_new = 'L'
INTO TABLE @DATA(lt_cd_del).
LOOP AT lt_cd_del ASSIGNING FIELD-SYMBOL(<fs_cd>).
READ TABLE lt_po_base ASSIGNING FIELD-SYMBOL(<fs_po>) WITH KEY ebeln = <fs_cd>-objectid.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(ls_event) = VALUE ty_event_log(
purchaseorder = <fs_po>-ebeln
activity = 'Purchase Order Deleted'
username = <fs_cd>-username
vendornumber = <fs_po>-lifnr
orderamount = <fs_po>-netwr
materialgroup = <fs_po>-matkl
companycode = <fs_po>-bukrs
documenttype = <fs_po>-bsart
).
CONVERT DATE <fs_cd>-udate TIME <fs_cd>-utime INTO TIME STAMP ls_event-eventtime TIME ZONE sy-zonlo.
APPEND ls_event TO gt_event_log.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form DOWNLOAD_TO_CSV
*&---------------------------------------------------------------------*
FORM download_to_csv.
DATA: lv_filename TYPE string.
DATA: lt_fieldnames TYPE TABLE OF string.
APPEND 'PurchaseOrder' TO lt_fieldnames.
APPEND 'Activity' TO lt_fieldnames.
APPEND 'EventTime' TO lt_fieldnames.
APPEND 'UserName' TO lt_fieldnames.
APPEND 'VendorNumber' TO lt_fieldnames.
APPEND 'OrderAmount' TO lt_fieldnames.
APPEND 'MaterialGroup' TO lt_fieldnames.
APPEND 'CompanyCode' TO lt_fieldnames.
APPEND 'DocumentType' TO lt_fieldnames.
DATA(lv_header) = REDUCE string( INIT h = '' FOR f IN lt_fieldnames NEXT h = h && f && cl_abap_char_utilities=>horizontal_tab ).
REPLACE LAST OCCURRENCE OF cl_abap_char_utilities=>horizontal_tab IN lv_header WITH cl_abap_char_utilities=>cr_lf.
DATA(lv_file_content) = lv_header.
LOOP AT gt_event_log ASSIGNING FIELD-SYMBOL(<fs_log>).
DATA lv_line TYPE string.
DATA lv_eventtime_str TYPE string.
lv_eventtime_str = |{ <fs_log>-eventtime TIMESTAMP = ISO }|.
lv_line = <fs_log>-purchaseorder && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-activity && cl_abap_char_utilities=>horizontal_tab &&
lv_eventtime_str && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-username && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-vendornumber && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-orderamount && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-materialgroup && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-companycode && cl_abap_char_utilities=>horizontal_tab &&
<fs_log>-documenttype && cl_abap_char_utilities=>cr_lf.
CONCATENATE lv_file_content lv_line INTO lv_file_content.
ENDLOOP.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = 'C:\temp\po_event_log.csv'
filetype = 'ASC'
CHANGING
data_tab = lv_file_content. 단계
- 데이터베이스 연결 설정: SAP ECC 데이터베이스에 연결할 읽기 전용 자격 증명과 연결 정보(호스트 이름, 포트, 데이터베이스 이름)를 확보합니다. DBeaver, SQL Developer, SSMS와 같은 클라이언트 도구가 설치되어 있는지 확인합니다.
- SAP 스키마 확인: 데이터베이스에 연결해 테이블이 있는 기본 SAP 스키마를 확인합니다. 일반적으로 SAPSR3, SAPHANADB 또는 시스템별 이름을 사용합니다. 사용자 기본 스키마가 아니라면 쿼리의 모든 테이블 이름 앞에 이 스키마를 붙여야 합니다.
- SQL 쿼리 검토: 제공된 SQL 스크립트를 클라이언트 도구에서 엽니다. 이 쿼리는 여러 SAP 테이블을 조인해 구매-지급 프로세스에서 서로 다른 활동 14개를 추출하도록 구성되어 있습니다.
- 쿼리 매개변수 맞춤 설정: 스크립트 앞부분에서 PO_BASE 공통 테이블 식(CTE)을 찾습니다. 추출 범위를 지정하려면 자리표시자 값을 수정합니다.
- [START_DATE] 및 [END_DATE]: 분석할 날짜 범위를 설정합니다(예: '20230101' 및 '20230630'). AEDAT(변경일) 필드를 기준으로 필터링하는 것이 좋습니다.
- [COMPANY_CODE_1], [COMPANY_CODE_2]: 포함할 SAP 회사 코드를 지정합니다.
- [DOC_TYPE_1], [DOC_TYPE_2]: 포함할 구매오더 문서 유형을 지정합니다.
- [Your SAP Schema]: 스크립트 전체에서 이 자리표시자를 실제 SAP 스키마 이름으로 바꿉니다.
- 쿼리 실행: 수정한 SQL 스크립트를 SAP 데이터베이스에서 실행합니다. 실행 시간은 날짜 범위, 데이터 양, 데이터베이스 성능에 따라 달라집니다.
- 결과 확인: 쿼리 실행이 끝나면 결과를 간단히 검토합니다. 행 수가 적절한지 확인하고 PurchaseOrder, Activity, EventTime과 같은 주요 열에 예상한 값이 있는지 살펴봅니다.
- 데이터를 CSV로 내보내기: SQL 클라이언트에서 전체 결과를 CSV 파일로 내보냅니다. 문자 깨짐을 방지하려면 UTF-8 인코딩을 사용합니다.
- 업로드 준비: CSV 파일의 열 머리글이 필수 속성 이름과 정확히 일치하는지 확인합니다: PurchaseOrder, Activity, EventTime, UserName, VendorNumber, OrderAmount, MaterialGroup, CompanyCode, DocumentType.
- process mining 도구에 업로드: 완성된 CSV 파일을 process mining 애플리케이션에 업로드해 분석하고 시각화합니다.
구성
- 사전 요건: SAP ECC 기반 데이터베이스에 직접 읽기 전용으로 접근할 수 있어야 합니다. EKKO, EKPO, EKBE, EBAN, CDHDR, CDPOS, NAST 등의 테이블을 조회할 수 있는 권한이 필요합니다.
- 날짜 범위 필터링: 데이터량을 제한하려면 날짜 범위를 반드시 필터링해야 합니다. 일반적으로 EKKO.AEDAT(PO 변경일)을 기준으로 3~6개월 범위부터 시작합니다. 날짜 범위를 지나치게 넓게 설정하면 쿼리 실행 시간이 크게 늘어날 수 있습니다.
- 주요 데이터 필터: 분석 범위를 적절히 설정하려면 EKKO.BUKRS(회사 코드)와 EKKO.BSART(문서 유형)를 항상 필터링합니다. 관련 법인과 비즈니스 프로세스만 조회할 수 있습니다.
- 성능 고려 사항: 이 쿼리는 변경 이력 테이블(CDHDR, CDPOS)을 포함해 용량이 큰 여러 테이블을 조인하므로 리소스를 많이 사용할 수 있습니다. 시스템 성능에 영향을 주지 않도록 사용량이 적은 시간대에 실행하거나 복제된 비운영 데이터베이스에서 실행하는 것이 좋습니다.
- 변경 문서 로깅: '승인', '거부', '완료', '변경' 활동의 정확도는 SAP에서 관련 필드의 변경 문서 로깅이 활성화되어 있는지에 따라 달라집니다. SAP 관리자에게 트랜잭션 SCDO를 통해 로깅이 활성화되어 있는지 확인하세요.
샘플 쿼리 sql
WITH PO_BASE AS (
SELECT
H.EBELN, -- Purchase Order Number
I.EBELP, -- Purchase Order Item
H.LIFNR, -- Vendor Number
H.BUKRS, -- Company Code
H.BSART, -- Document Type
I.NETWR, -- Order Amount (Item Level)
I.MATKL, -- Material Group
I.BANFN, -- Purchase Requisition Number
I.BNFPO -- Purchase Requisition Item
FROM [Your SAP Schema].EKKO AS H
JOIN [Your SAP Schema].EKPO AS I ON H.EBELN = I.EBELN
WHERE H.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' -- Filter on PO Change Date, e.g., '20230101' and '20231231'
AND H.BUKRS IN ('[COMPANY_CODE_1]', '[COMPANY_CODE_2]') -- Specify Company Codes
AND H.BSART IN ('[DOC_TYPE_1]', '[DOC_TYPE_2]') -- Specify PO Document Types
)
-- 1. Purchase Requisition Created
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Requisition Created' AS "Activity",
TO_TIMESTAMP(CONCAT(pr.ERDAT, '000000'), 'YYYYMMDDHH24MISS') AS "EventTime", -- Time is not available in EBAN
pr.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EBAN pr ON po.BANFN = pr.BANFN AND po.BNFPO = pr.BNFPO
WHERE po.BANFN IS NOT NULL AND po.BANFN <> ''
UNION ALL
-- 2. Purchase Requisition Approved
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Requisition Approved' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'BANF' AND ch.OBJECTID = po.BANFN
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EBAN' AND cp.FNAME = 'FRGZU' AND cp.VALUE_NEW = 'X' -- Release indicator set to 'released'
UNION ALL
-- 3. Purchase Order Created
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Created' AS "Activity",
TO_TIMESTAMP(CONCAT(ekko.ERDAT, ' ', ekko.ERZET), 'YYYYMMDD HH24MISS') AS "EventTime",
ekko.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKKO ekko ON po.EBELN = ekko.EBELN
UNION ALL
-- 4. Purchase Order Approval Requested / 5. Approved / 6. Rejected (from Change Docs)
SELECT
po.EBELN AS "PurchaseOrder",
CASE
WHEN cp.VALUE_NEW > cp.VALUE_OLD THEN 'Purchase Order Approval Requested'
WHEN cp.VALUE_NEW = ekko.FRGKE AND ekko.FRGKE = 'R' THEN 'Purchase Order Approved'
ELSE 'Purchase Order Rejected' -- Simplified logic, may need adjustment
END AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKKO ekko ON po.EBELN = ekko.EBELN
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID = po.EBELN
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKKO' AND cp.FNAME = 'FRGZU' -- Release status
UNION ALL
-- 7. Purchase Order Sent to Vendor
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Sent to Vendor' AS "Activity",
TO_TIMESTAMP(CONCAT(na.ERDAT, ' ', na.ERUHR), 'YYYYMMDD HH24MISS') AS "EventTime",
na.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].NAST na ON na.OBJKY = po.EBELN AND na.KSCHL = '[Your PO Output Type]' -- e.g., 'NEU'
WHERE na.VSTAT = '1' -- Successfully processed
UNION ALL
-- 8. Purchase Order Changed
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Changed' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID = po.EBELN
WHERE ch.TCODE IN ('ME22', 'ME22N') -- Filter for change transactions
UNION ALL
-- 9. Goods Receipt Posted
SELECT
ekbe.EBELN AS "PurchaseOrder",
'Goods Receipt Posted' AS "Activity",
TO_TIMESTAMP(CONCAT(mkpf.CPUDT, ' ', mkpf.CPUTM), 'YYYYMMDD HH24MISS') AS "EventTime",
mkpf.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM [Your SAP Schema].EKBE AS ekbe
JOIN [Your SAP Schema].MKPF AS mkpf ON ekbe.BELNR = mkpf.MBLNR AND ekbe.GJAHR = mkpf.MJAHR
JOIN PO_BASE AS po ON ekbe.EBELN = po.EBELN AND ekbe.EBELP = po.EBELP
WHERE ekbe.BEWTP = 'E' -- Goods Receipt
AND ekbe.SHKZG = 'S' -- Debit/Credit Indicator: Goods Receipt
UNION ALL
-- 10. Services Confirmation Entered
SELECT
po.EBELN AS "PurchaseOrder",
'Services Confirmation Entered' AS "Activity",
TO_TIMESTAMP(CONCAT(essr.ERDAT, ' ', essr.ERZET), 'YYYYMMDD HH24MISS') AS "EventTime",
essr.ERNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKBE ekbe ON po.EBELN = ekbe.EBELN AND po.EBELP = ekbe.EBELP
JOIN [Your SAP Schema].ESSR essr ON ekbe.LBLNI = essr.LBLNI
WHERE ekbe.BEWTP = 'L' -- Service Entry Sheet
UNION ALL
-- 11. Quality Inspection Performed
SELECT
po.EBELN AS "PurchaseOrder",
'Quality Inspection Performed' AS "Activity",
TO_TIMESTAMP(CONCAT(qave.VDATUM, ' ', qave.VZEIT), 'YYYYMMDD HH24MISS') AS "EventTime",
qave.VNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].EKBE ekbe ON po.EBELN = ekbe.EBELN AND po.EBELP = ekbe.EBELP
JOIN [Your SAP Schema].QALS qals ON qals.MBLNR = ekbe.BELNR AND qals.MJAHR = ekbe.GJAHR
JOIN [Your SAP Schema].QAVE qave ON qals.PRUEFLOS = qave.PRUEFLOS
WHERE ekbe.BEWTP = 'E' -- Linked to a Goods Receipt
UNION ALL
-- 12. Goods Returned
SELECT
ekbe.EBELN AS "PurchaseOrder",
'Goods Returned' AS "Activity",
TO_TIMESTAMP(CONCAT(mkpf.CPUDT, ' ', mkpf.CPUTM), 'YYYYMMDD HH24MISS') AS "EventTime",
mkpf.USNAM AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM [Your SAP Schema].EKBE AS ekbe
JOIN [Your SAP Schema].MKPF AS mkpf ON ekbe.BELNR = mkpf.MBLNR AND ekbe.GJAHR = mkpf.MJAHR
JOIN PO_BASE AS po ON ekbe.EBELN = po.EBELN AND ekbe.EBELP = po.EBELP
WHERE ekbe.BEWTP = 'E' -- Goods Movement
AND ekbe.SHKZG = 'H' -- Debit/Credit Indicator: Return
AND ekbe.BWART = '122' -- Movement type for return to vendor
UNION ALL
-- 13. Purchase Order Completed
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Completed' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID LIKE CONCAT(po.EBELN, po.EBELP, '%')
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKPO' AND cp.FNAME = 'ELIKZ' AND cp.VALUE_NEW = 'X' -- Delivery completed indicator
UNION ALL
-- 14. Purchase Order Deleted
SELECT
po.EBELN AS "PurchaseOrder",
'Purchase Order Deleted' AS "Activity",
TO_TIMESTAMP(CONCAT(ch.UDATE, ' ', ch.UTIME), 'YYYYMMDD HH24MISS') AS "EventTime",
ch.USERNAME AS "UserName",
po.LIFNR AS "VendorNumber",
po.NETWR AS "OrderAmount",
po.MATKL AS "MaterialGroup",
po.BUKRS AS "CompanyCode",
po.BSART AS "DocumentType"
FROM PO_BASE po
JOIN [Your SAP Schema].CDHDR ch ON ch.OBJECTCLASS = 'EINKBELEG' AND ch.OBJECTID LIKE CONCAT(po.EBELN, po.EBELP, '%')
JOIN [Your SAP Schema].CDPOS cp ON ch.OBJECTCLASS = cp.OBJECTCLASS AND ch.OBJECTID = cp.OBJECTID AND ch.CHANGENR = cp.CHANGENR
WHERE cp.TABNAME = 'EKPO' AND cp.FNAME = 'LOEKZ' AND cp.VALUE_NEW = 'L'; -- Deletion indicator 단계
- 사전 준비 및 연결: 타사 ETL 도구에 SAP 인증 커넥터가 설치되어 있고 라이선스가 있는지 확인합니다. ETL 도구의 관리 콘솔에서 SAP ECC 시스템에 연결을 설정합니다. 애플리케이션 서버 호스트, 시스템 번호, 클라이언트 ID와 적절한 RFC 및 테이블 읽기 권한이 있는 전용 SAP 사용자 계정이 필요합니다.
- 원본 테이블 확인: ETL 작업 또는 데이터 흐름에서 필요한 SAP 테이블을 데이터 소스로 지정합니다. 주요 테이블은 EKKO(구매오더 헤더), EKPO(구매오더 품목), EBAN(구매요청), CDHDR(변경 문서 헤더), CDPOS(변경 문서 항목), MSEG(문서 세그먼트: 자재), MKPF(자재 문서 헤더), NAST(메시지 상태), ESSR(서비스 입력 시트 헤더), QALS(검사 로트)입니다.
- '구매오더 생성' 추출: EKKO 테이블을 원본으로 하는 데이터 흐름을 만듭니다. 원하는 날짜 범위(예: AEDAT 사용)와 조직 범위(예: 회사 코드의 BUKRS, 문서 유형의 BSART)를 기준으로 레코드를 필터링합니다. EKKO.EBELN을 PurchaseOrder에, '구매오더 생성'을 Activity에 매핑하고 AEDAT와 ERZET을 결합해 EventTime을 구성합니다. 나머지 필수 속성도 매핑합니다.
- '입고 전기' 추출: MSEG를 원본으로 하는 별도의 데이터 흐름을 만들고 MBLNR 및 MJAHR을 기준으로 MKPF와 조인합니다. '101'과 같은 관련 이동 유형을 필터링합니다. MSEG.EBELN을 PurchaseOrder에, '입고 전기'를 Activity에 매핑하고 MKPF.CPUDT 및 MKPF.CPUTM을 EventTime으로 사용합니다.
- 변경 기반 이벤트 추출(승인, 변경, 삭제): CDHDR와 CDPOS를 CHANGENR 기준으로 조인해 데이터 흐름을 만듭니다. 이 데이터 소스 하나로 여러 활동을 도출할 수 있습니다.
- OBJECTCLAS = 'EINKBELEG' 및 TABNAME = 'EKPO'로 필터링합니다.
- **'구매오더 승인'**은 릴리스 상태 필드(예: FNAME = 'FRGZU')의 변경 중 새 값(VALUE_NEW)이 최종 승인을 나타내는 항목을 필터링합니다.
- **'구매오더 삭제'**는 삭제 표시자(FNAME = 'LOEKZ')의 변경 중 새 값이 'L'인 항목을 필터링합니다.
- **'구매오더 변경'**은 다른 활동에 사용된 특정 상태 필드를 제외하고 관련 필드 변경을 필터링합니다.
- 모든 이벤트의 EventTime에는 CDHDR.UDATE 및 CDHDR.UTIME을 사용합니다.
- '구매요청' 이벤트 추출: EBAN에서 '구매요청 생성' 데이터 흐름을 만듭니다. 이 이벤트를 PurchaseOrder 케이스에 연결하려면 구매요청 번호(BANFN)와 품목(BNFPO)을 기준으로 EBAN을 EKPO와 조인합니다. '구매요청 승인'에는 OBJECTCLAS = 'BANF'인 CDHDR/CDPOS를 사용합니다. 최종 구매오더와 이벤트가 연결되도록 신중하게 매핑해야 합니다.
- '구매오더를 공급업체에 발송' 추출: NAST 테이블을 원본으로 하는 데이터 흐름을 만듭니다. OBJECTKEY(구매오더 번호 포함), 관련 출력 유형(KSCHL), 성공 처리 상태(VSTAT = '1')를 기준으로 필터링합니다. EventTime에는 ERDAT 및 UHR을 사용합니다.
- 활동 데이터 흐름 통합: ETL 도구의 'Union' 또는 'Merge' 변환을 사용해 앞 단계에서 만든 각 데이터 흐름의 결과를 합칩니다. 모든 흐름에서 열 이름과 데이터 유형이 일치하는지 확인합니다(PurchaseOrder, Activity, EventTime 등).
- 데이터 유형 및 형식 변환: EventTime 열을 일관된 타임스탬프 형식(예: YYYY-MM-DD HH:MM:SS)으로 변환합니다. OrderAmount는 표준 소수 형식으로 변환합니다.
- 대상 위치 지정: 통합 데이터 흐름의 대상 또는 'sink'를 설정합니다. 일반적으로 CSV나 Parquet 같은 플랫 파일을 사용합니다. 구분 기호, 텍스트 한정자, 머리글 옵션을 설정합니다.
- 실행 및 검증: 전체 ETL 작업을 실행합니다. 출력 파일에 활동 14개가 모두 포함되어 있는지, 행 수가 적절한지, 주요 속성이 올바르게 채워졌는지 확인합니다.
- 예약 및 내보내기: 검증이 끝나면 데이터 최신 상태를 유지하도록 ETL 작업을 정기적으로(예: 매일 밤) 실행하도록 예약합니다. 생성된 파일을 process mining 도구에 업로드할 수 있습니다.
구성
- 사전 요건: ECC용 SAP 인증 커넥터가 포함된 상용 ETL 도구(예: Informatica PowerCenter, Talend, SAP Data Services)가 필요합니다. 필요한 테이블에 접근할 수 있도록 S_RFC 및 S_TABU_DIS 권한이 부여된 SAP 대화 사용자 또는 시스템 사용자를 준비합니다.
- SAP 연결: 커넥터에 SAP 애플리케이션 서버, 시스템 번호, 클라이언트, 사용자 및 비밀번호를 설정해야 합니다. Secure Network Communications(SNC) 사용을 권장합니다.
- 기간 필터: 데이터 양을 제한하려면 기간 필터를 반드시 적용해야 합니다. 일반적으로 최근 3~12개월의 EKKO.AEDAT(구매 오더 생성일)를 필터링합니다. SAP에서 불필요하게 많은 데이터를 추출하지 않도록 원본 시스템에서 필터를 적용합니다.
- 조직 범위 필터: EKKO.BUKRS(회사 코드)를 항상 필터링하고, 특정 사업부에 맞춰 분석 범위를 좁히려면 EKPO.WERKS(플랜트) 또는 EKKO.EKORG(구매 조직)도 필터링합니다.
- 문서 유형 필터: EKKO.BSART를 사용해 분석 대상 구매 오더 유형만 포함하고, 표준 P2P 프로세스에 해당하지 않는 재고 이전이나 기타 내부 문서는 제외합니다.
- 성능 조정: 변경 문서 테이블(CDHDR, CDPOS)에서 데이터를 추출하면 속도가 느릴 수 있습니다. OBJECTCLAS, OBJECTID, UDATE 필터가 적용되었는지 확인합니다. 데이터 전송 속도를 최적화하려면 SAP 커넥터의 'Packet Size' 설정을 조정합니다. 규모가 매우 큰 시스템에서는 초기 전체 이력 데이터를 적재한 뒤 정기적으로 변경분을 적재하는 방식을 고려합니다.
샘플 쿼리 sql
/*
This is a logical representation of the transformations performed within the ETL tool.
The tool's graphical interface will be used to configure these separate data flows, which are then combined with a UNION transformation.
Placeholders like [Your ETL Tool Functions] and [Filter Values] must be configured in the tool.
*/
-- 1. Purchase Requisition Created
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Requisition Created' AS Activity,
[Your ETL Tool Functions].DateTime(eban.ERDAT, eban.ERZET) AS EventTime,
eban.ERNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM EBAN AS eban
INNER JOIN EKPO AS ekpo ON eban.BANFN = ekpo.BANFN AND eban.BNFPO = ekpo.BNFPO
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 2. Purchase Requisition Approved (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Requisition Approved' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EBAN AS eban ON cdhdr.OBJECTID = eban.BANFN
INNER JOIN EKPO AS ekpo ON eban.BANFN = ekpo.BANFN AND eban.BNFPO = ekpo.BNFPO
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'BANF' AND cdpos.TABNAME = 'EBAN' AND cdpos.FNAME = 'FRGZU' AND cdpos.VALUE_NEW = '[Final Release Indicator for PR]'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 3. Purchase Order Created
SELECT
EBELN AS PurchaseOrder,
'Purchase Order Created' AS Activity,
[Your ETL Tool Functions].DateTime(AEDAT, ERZET) AS EventTime,
ERNAM AS UserName,
LIFNR AS VendorNumber,
NULL AS OrderAmount, -- Amount is at item level
NULL AS MaterialGroup, -- Attribute is at item level
BUKRS AS CompanyCode,
BSART AS DocumentType
FROM EKKO
WHERE AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 4. Purchase Order Approval Requested / 5. Approved / 6. Rejected (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
CASE
WHEN cdpos.VALUE_NEW = '[Final Release Code]' THEN 'Purchase Order Approved'
WHEN cdpos.VALUE_NEW = '[Rejection Release Code]' THEN 'Purchase Order Rejected'
ELSE 'Purchase Order Approval Requested'
END AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKKO AS ekko ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKKO' AND cdpos.FNAME = 'FRGKE'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 7. Purchase Order Sent to Vendor
SELECT
ekko.EBELN AS PurchaseOrder,
'Purchase Order Sent to Vendor' AS Activity,
[Your ETL Tool Functions].DateTime(nast.ERDAT, nast.UHR) AS EventTime,
nast.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM NAST AS nast
INNER JOIN EKKO AS ekko ON nast.OBJKY = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE nast.KAPPL = 'EF' AND nast.VSTAT = '1' AND nast.KSCHL IN ([Your PO Output Types])
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 8. Purchase Order Changed (inferred from change documents, simplified example)
SELECT DISTINCT
ekko.EBELN AS PurchaseOrder,
'Purchase Order Changed' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKKO AS ekko ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekko.EBELN
INNER JOIN EKPO AS ekpo ON ekko.EBELN = ekpo.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.FNAME NOT IN ('FRGKE', 'FRGZU', 'LOEKZ', 'ELIKZ')
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 9. Goods Receipt Posted
SELECT
mseg.EBELN AS PurchaseOrder,
'Goods Receipt Posted' AS Activity,
[Your ETL Tool Functions].DateTime(mkpf.CPUDT, mkpf.CPUTM) AS EventTime,
mkpf.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM MSEG AS mseg
INNER JOIN MKPF AS mkpf ON mseg.MBLNR = mkpf.MBLNR AND mseg.MJAHR = mkpf.MJAHR
INNER JOIN EKPO AS ekpo ON mseg.EBELN = ekpo.EBELN AND mseg.EBELP = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE mseg.BWART = '101' AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 10. Services Confirmation Entered
SELECT
essr.EBELN AS PurchaseOrder,
'Services Confirmation Entered' AS Activity,
[Your ETL Tool Functions].DateTime(essr.ERDAT, essr.ERZET) AS EventTime,
essr.ERNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM ESSR AS essr
INNER JOIN EKKO AS ekko ON essr.EBELN = ekko.EBELN
INNER JOIN EKPO AS ekpo ON essr.EBELN = ekpo.EBELN AND essr.EBELP = ekpo.EBELP
WHERE ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 11. Quality Inspection Performed
SELECT
qals.EBELN AS PurchaseOrder,
'Quality Inspection Performed' AS Activity,
[Your ETL Tool Functions].DateTime(qals.PASTRTERM, '000000') AS EventTime, -- Time is often not available
qals.PRUEFER AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM QALS AS qals
INNER JOIN EKKO AS ekko ON qals.EBELN = ekko.EBELN
INNER JOIN EKPO AS ekpo ON qals.EBELN = ekpo.EBELN AND qals.EBELP = ekpo.EBELP
WHERE qals.VCODE <> '' -- A usage decision code exists
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 12. Goods Returned
SELECT
mseg.EBELN AS PurchaseOrder,
'Goods Returned' AS Activity,
[Your ETL Tool Functions].DateTime(mkpf.CPUDT, mkpf.CPUTM) AS EventTime,
mkpf.USNAM AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM MSEG AS mseg
INNER JOIN MKPF AS mkpf ON mseg.MBLNR = mkpf.MBLNR AND mseg.MJAHR = mkpf.MJAHR
INNER JOIN EKPO AS ekpo ON mseg.EBELN = ekpo.EBELN AND mseg.EBELP = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE mseg.BWART = '122' AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 13. Purchase Order Completed (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Order Completed' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKPO AS ekpo ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekpo.EBELN AND SUBSTRING(cdhdr.OBJECTID, 11, 5) = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKPO' AND cdpos.FNAME = 'ELIKZ' AND cdpos.VALUE_NEW = 'X'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]);
UNION ALL
-- 14. Purchase Order Deleted (inferred from change documents)
SELECT
ekpo.EBELN AS PurchaseOrder,
'Purchase Order Deleted' AS Activity,
[Your ETL Tool Functions].DateTime(cdhdr.UDATE, cdhdr.UTIME) AS EventTime,
cdhdr.USERNAME AS UserName,
ekko.LIFNR AS VendorNumber,
ekpo.NETWR AS OrderAmount,
ekpo.MATKL AS MaterialGroup,
ekko.BUKRS AS CompanyCode,
ekko.BSART AS DocumentType
FROM CDHDR AS cdhdr
INNER JOIN CDPOS AS cdpos ON cdhdr.CHANGENR = cdpos.CHANGENR
INNER JOIN EKPO AS ekpo ON SUBSTRING(cdhdr.OBJECTID, 1, 10) = ekpo.EBELN AND SUBSTRING(cdhdr.OBJECTID, 11, 5) = ekpo.EBELP
INNER JOIN EKKO AS ekko ON ekpo.EBELN = ekko.EBELN
WHERE cdhdr.OBJECTCLAS = 'EINKBELEG' AND cdpos.TABNAME = 'EKPO' AND cdpos.FNAME = 'LOEKZ' AND cdpos.VALUE_NEW = 'L'
AND ekko.AEDAT BETWEEN '[START_DATE]' AND '[END_DATE]' AND ekko.BUKRS IN ([YOUR_COMPANY_CODES]); 시작할 준비가 되셨나요?
이 템플릿을 활용하면 SAP ECC의 구매부터 지급까지 구매오더 프로세스를 개선하는 데 필요한 기준을 마련할 수 있습니다. 지금 데이터를 활용해 인사이트를 찾고 효율성을 높여 보세요.
P2P 구매오더 프로세스 개선: 지금 무료 체험을 시작하세요
병목을 해소하고 처리 시간을 30% 이상 단축하세요.
신용카드 없이 몇 분 만에 시작할 수 있습니다.