구매 대금 지급 프로세스의 구매 오더 데이터 템플릿
구매 대금 지급 프로세스의 구매 오더 데이터 템플릿
- 상세 분석에 권장되는 속성
- 프로세스에서 추적할 주요 활동
- 단계별 데이터 추출 안내
구매 대금 지급 프로세스의 구매 오더 속성
| 이름 | 설명 | ||
|---|---|---|---|
| 구매 오더 PurchaseOrderNumber | 구매 오더(PO)의 고유 식별자로, 조달 수명 주기를 추적하는 기본 케이스 ID입니다. | ||
| 설명 구매 오더 번호는 최초 생성부터 최종 입고와 완료까지 관련된 모든 활동을 연결하는 중심 식별자입니다. process mining 분석에서 케이스 식별자로 사용됩니다. 분석 시 이 번호를 기준으로 이벤트를 그룹화하면 각 구매 오더의 진행 과정을 재구성할 수 있습니다. 이를 통해 처리 시간을 계산하고 프로세스 변형을 분석하며, 개별 오더에서 발생하는 병목이나 편차를 파악할 수 있습니다. 중요한 이유 모든 조달 이벤트를 하나의 전체 프로세스로 연결하는 데 필요한 식별자로, 구매 오더 수명 주기를 상세히 분석할 수 있습니다. 확보 방법 SAP S/4HANA 테이블 EKKO의 EBELN 필드에서 확인할 수 있습니다. 예시 450001712345000171244500017125 | |||
| 이벤트 시간 EventTime | 활동이 발생한 시점을 나타내는 타임스탬프입니다. | ||
| 설명 이 속성은 프로세스의 각 활동이 발생한 정확한 날짜와 시간을 기록합니다. process mining에서 시간 기반 분석을 수행하는 데 필수적입니다. 이벤트 시간은 활동을 시간순으로 정렬해 프로세스 흐름을 구성하는 데 사용됩니다. 또한 활동 간 처리 시간, 대기 시간, 작업 시간 등 기간 기반 지표를 계산하는 기준이며, 이러한 지표는 성과 분석과 병목 파악에 중요합니다. 중요한 이유 이 타임스탬프는 이벤트를 올바른 순서로 정렬하고 처리 시간, 리드 타임, 대기 시간을 포함한 성과 지표를 계산하는 데 중요합니다. 확보 방법 생성일(EKKO-AEDAT, 변경 사항의 경우)이나 전기일(MKPF-BUDAT, 입고의 경우)처럼 특정 활동과 관련된 타임스탬프 필드입니다. 여러 테이블의 데이터를 결합해야 하는 경우가 많습니다. 예시 2023-04-15T10:00:00Z2023-04-15T14:30:00Z2023-05-01T09:15:00Z | |||
| 활동 ActivityName | 구매 오더 프로세스에서 발생한 업무 이벤트 또는 단계의 이름입니다. | ||
| 설명 이 속성은 '구매 오더 생성', '구매 오더 승인', '입고 전기'와 같이 구매 오더 수명 주기에서 발생한 특정 작업이나 상태 변경을 나타냅니다. 활동이 이어지는 순서가 프로세스 흐름을 구성합니다. 활동의 순서와 빈도를 분석하는 것이 process mining의 기본입니다. 실제 프로세스를 파악하고 설계된 모델과 비교하며, 병목(예: '송장 접수' 후 긴 대기 시간)을 찾고 재작업(예: '구매 오더 변경'의 반복)을 측정할 수 있습니다. 중요한 이유 프로세스의 단계를 정의하므로 전체 흐름을 시각화하고 분석하며, 변형과 병목을 파악할 수 있습니다. 확보 방법 일반적으로 주요 업무 단계를 나타내기 위해 EKKO/EKPO의 상태 필드나 CDHDR/CDPOS의 변경 문서 로그 등 여러 테이블과 필드를 조합해 도출합니다. 예시 구매 오더 생성구매 오더 승인입고 전기송장 접수 | |||
| 소스 시스템 SourceSystem | 데이터를 추출한 소스 시스템을 식별합니다. | ||
| 설명 이 속성은 이벤트 데이터가 발생한 시스템을 지정합니다. 예를 들면 'SAP S/4HANA 운영 시스템' 또는 'SAP ECC'입니다. 여러 시스템을 사용하는 환경에서는 데이터 계보를 추적하고 문제를 해결하며 서로 다른 소스의 데이터를 올바르게 해석하는 데 이 필드가 중요합니다. 데이터의 맥락을 파악하고 특정 시스템 환경의 데이터만 분석하도록 필터링할 수도 있습니다. 중요한 이유 데이터의 출처에 관한 정보를 제공하므로 여러 시스템 환경에서 데이터 거버넌스, 검증 및 분석에 중요합니다. 확보 방법 일반적으로 데이터 추출, 변환, 적재(ETL) 과정에서 데이터 세트의 출처를 표시하기 위해 추가하는 고정값입니다. 예시 S4H_PROD_100ECC_EU_200S4H_US_300 | |||
| 최근 데이터 갱신 시각 LastDataUpdate | 소스 시스템에서 데이터를 마지막으로 새로 고치거나 추출한 시각입니다. | ||
| 설명 이 속성은 분석 중인 데이터의 최신성을 나타냅니다. SAP S/4HANA에서 데이터를 가장 최근에 가져온 날짜와 시간을 보여줍니다. 마지막 데이터 갱신 시각을 알면 분석 정보가 얼마나 최신인지 판단할 수 있습니다. 실시간 정보인지 특정 시점의 스냅샷인지 파악해 결과를 올바르게 해석하고, 분석에 기반한 조치가 적절한지 판단할 수 있습니다. 중요한 이유 데이터의 최신성을 알려주므로 분석 결과의 맥락과 활용도를 올바르게 판단할 수 있습니다. 확보 방법 데이터 추출, 변환, 적재(ETL) 과정에서 추가하는 메타데이터 타임스탬프입니다. 예시 2024-05-21T02:00:00Z2024-05-20T02:00:00Z2024-05-19T02:00:00Z | |||
| 공급업체 ID VendorId | 상품이나 서비스를 제공하는 공급업체의 고유 식별자입니다. | ||
| 설명 공급업체 ID는 구매 오더를 특정 공급업체와 연결하는 주요 마스터 데이터입니다. 조달 과정에서 연락, 납품, 대금 지급에 사용됩니다. process mining에서는 공급업체별로 성과를 나누어 분석할 수 있습니다. '공급업체 리드 타임 성과'와 '공급업체별 상품 반품률' 대시보드에 활용하면 신뢰도가 높은 공급업체와 지연 또는 품질 문제를 일으킬 수 있는 공급업체를 파악할 수 있습니다. 중요한 이유 공급업체별 성과 분석을 지원해 성과가 높은 업체와 낮은 업체를 파악하고 공급망을 최적화할 수 있습니다. 확보 방법 SAP S/4HANA 테이블 EKKO의 LIFNR 필드에 있습니다. 예시 100023100045100088 | |||
| 구매 오더 문서 유형 DocumentType | 일반 구매 오더, 서비스 구매 오더, 재고 운송 오더 등 구매 오더 유형을 구분하는 분류입니다. | ||
| 설명 문서 유형은 SAP의 주요 구성 요소로, 구매 오더의 프로세스 흐름, 번호 범위, 필드를 제어합니다. 이를 통해 기업은 다양한 상황에 맞게 조달 프로세스를 설정할 수 있습니다. 문서 유형별 프로세스 분석은 프로세스 변형을 이해하는 데 중요합니다. 예를 들어 일반 상품 구매 오더와 서비스 구매 오더 또는 재고 이전 오더의 프로세스는 상당히 다를 수 있습니다. 이 속성으로 각 프로세스 흐름을 필터링하고 비교해 구체적인 개선 기회를 찾을 수 있습니다. 중요한 이유 구매 오더를 유형별로 분류해 조달 프로세스를 비교하고, 프로세스 흐름과 처리 시간의 차이를 파악할 수 있습니다. 확보 방법 SAP S/4HANA 테이블 EKKO의 BSART 필드에 있습니다. 예시 일반 구매 오더프레임워크 오더재고 운송 오더 | |||
| 구매 요청 PurchaseRequisitionNumber | 구매 오더를 시작한 구매 요청(PR)의 식별자입니다. | ||
| 설명 이 속성은 구매 오더를 최초 구매 요청과 연결합니다. 구매 요청 없이 직접 생성된 구매 오더에는 이 값이 없을 수 있습니다. 이 연결 정보는 최초 요청부터 조달 프로세스 전체를 분석하는 데 필요합니다. '구매 요청 승인 시간'과 같은 KPI를 지원하며, 사전 승인된 구매 요청 없이 구매 오더를 생성하는 무단 구매를 파악하는 데도 중요합니다. 중요한 이유 구매 오더를 최초 요청과 연결해 전체 프로세스를 분석하고 규정을 따르지 않은 무단 구매를 파악할 수 있습니다. 확보 방법 SAP S/4HANA 테이블 EKPO(구매 오더 항목 수준)의 BANFN 필드에 있습니다. 예시 1001005110010052 | |||
| 사용자 UserName | 특정 활동을 수행한 사용자의 식별자입니다. | ||
| 설명 이 속성은 문서를 생성, 변경 또는 승인한 SAP 사용자 ID를 기록해 시스템에서 수행된 작업을 추적할 수 있게 합니다. 사용자별 분석으로 교육 필요성, 업무량 분배, 개인별 성과를 파악할 수 있습니다. 예를 들어 특정 사용자가 승인 지연이나 승인 후 잦은 변경과 지속적으로 연관되는지 확인할 수 있으며, 이를 바탕으로 리소스 관리와 프로세스 개선을 검토할 수 있습니다. 중요한 이유 책임 소재를 명확히 하고 개인 또는 팀 단위의 성과 분석을 지원해 교육 기회나 리소스 제약을 파악할 수 있습니다. 확보 방법 EKKO의 ERNAM(생성자) 필드나 변경 문서 테이블의 사용자 필드(CDHDR-USERNAME)에서 확인할 수 있습니다. 예시 CB9980000012JSMITHRROE | |||
| 요청 납품일 RequestedDeliveryDate | 사업 부문이 공급업체에 상품이나 서비스를 납품해 달라고 요청한 날짜입니다. | ||
| 설명 이 속성은 구매 오더에서 합의한 목표 납품일을 지정하며, 공급업체 납품 성과를 측정하는 기준이 됩니다. process mining에서는 이 날짜를 실제 입고일('입고 전기' 타임스탬프)과 비교해 '공급업체 정시 납품률' KPI를 계산합니다. 날짜 차이를 분석하면 공급업체의 신뢰도를 평가하고 공급망 위험을 관리할 수 있습니다. 중요한 이유 공급업체 정시 납품 성과를 측정하는 기준으로, 공급망 관리와 운영 계획에 중요한 KPI입니다. 확보 방법 납품 일정 테이블 EKET의 EINDT 필드에서 확인할 수 있습니다. 예시 2023-06-012023-06-152023-07-01 | |||
| 총 순액 TotalNetAmount | 세금과 운송비를 제외한 구매 오더의 총 금액입니다. | ||
| 설명 이 속성은 구매 오더의 순 금액을 나타냅니다. 조달 거래 규모를 보여주는 주요 재무 수치입니다. 이 금액은 구매 오더를 금액별로 분류해(고액과 소액) 프로세스 경로가 다른지 확인하는 등 재무 분석에 중요합니다. 재무 위험이 크거나 사업에 미치는 영향이 큰 고액 주문을 우선 분석하는 데도 사용할 수 있습니다. 중요한 이유 금액을 기준으로 구매 오더를 나누어 분석하고 지출 규모가 큰 영역의 프로세스 개선을 우선할 수 있습니다. 확보 방법 SAP S/4HANA 테이블 EKKO의 NETWR 필드에서 확인할 수 있습니다. 예시 1500.0025000.50125.75 | |||
| 공급업체 정시 납품 SupplierOnTimeDelivery | 입고가 요청 납기일 당일 또는 그 전에 전기되었는지 나타내는 계산 플래그입니다. | ||
| 설명 'Goods Receipt Posted' 활동의 타임스탬프와 'Requested Delivery Date'를 비교해 계산하는 불리언 속성입니다. 입고가 요청 납기일 당일 또는 그 전에 처리되면 'true'로 표시됩니다. 이 속성은 '공급업체 정시 납품률' KPI를 지원합니다. 정시 또는 지연 납품을 쉽게 필터링할 수 있어 공급업체 성과 대시보드와 평가에 활용할 수 있습니다. 중요한 이유 공급업체의 신뢰도를 직접 측정하는 기준으로, 정시 납품 KPI를 산출하고 공급업체 성과를 효과적으로 관리할 수 있습니다. 확보 방법 'Goods Receipt Posted' 활동의 타임스탬프와 'RequestedDeliveryDate' 속성을 비교해 계산합니다. 예시 truefalse | |||
| 구매 그룹 PurchasingGroup | 특정 조달 활동을 담당하는 구매 담당자 그룹입니다. | ||
| 설명 구매 그룹은 특정 구매 활동, 자재 또는 공급업체를 담당하는 구매 담당자 한 명 또는 여러 명을 의미합니다. 공급업체의 주요 연락 창구이기도 합니다. 이 속성을 사용하면 구매 조직보다 세분화된 수준에서 업무량과 성과를 분석할 수 있습니다. 업무가 과중한 팀을 찾고, 구매 담당자 그룹별 효율성을 측정하며, 비정상 구매와 같은 프로세스 이탈이 잦은 그룹을 파악할 수 있습니다. 중요한 이유 구매 담당자 그룹별 성과를 세부적으로 살펴보고 팀 단위의 업무량, 효율성, 프로세스 준수 여부를 분석할 수 있습니다. 확보 방법 이 속성은 SAP S/4HANA 테이블 EKKO의 EKGRP 필드에 있습니다. 예시 001002N00 | |||
| 구매 조직 PurchasingOrganization | 자재와 서비스를 조달하고 공급업체와 협상하는 조직 단위입니다. | ||
| 설명 구매 조직은 조달을 담당하는 주요 조직 단위입니다. 본사, 회사 또는 플랜트 수준으로 구성할 수 있으며 모든 구매 활동을 담당합니다. 구매 조직별로 프로세스를 분석하면 조달 팀이나 지역별 효율성과 성과를 평가할 수 있습니다. 조직 단위 간 공급업체 협상, 프로세스 준수 또는 승인 지연의 차이도 확인할 수 있습니다. 중요한 이유 조달 부서나 지역별 성과를 비교해 모범 사례와 개선이 필요한 영역을 파악할 수 있습니다. 확보 방법 이 속성은 SAP S/4HANA 테이블 EKKO의 EKORG 필드에 있습니다. 예시 10101710US01 | |||
| 비정상 구매 여부 IsMaverickSpend | 승인된 구매 요청 없이 구매 오더가 생성되었는지 나타내는 계산 플래그입니다. | ||
| 설명 데이터 처리 중 계산되는 불리언 플래그입니다. 구매 오더에 연결된 구매 요청이 없거나 표준 승인 워크플로를 거치지 않고 구매 오더를 생성한 경우 'true'로 설정됩니다. 이 속성은 '비정상 구매 식별' 대시보드와 관련 KPI를 지원합니다. 규정을 준수하지 않은 구매 행위의 규모를 파악하고, 특정 부서나 사용자 그룹을 대상으로 조달 정책과 통제를 강화할 수 있습니다. 중요한 이유 규정을 준수하지 않은 구매를 직접 식별해 프로세스 이탈 규모를 파악하고 재무 통제와 조달 정책을 적용할 수 있습니다. 확보 방법 특정 문서 유형에서 'PurchaseRequisitionNumber' 값이 없는지 확인하거나 이벤트 순서를 분석해 계산하는 필드입니다. 예시 truefalse | |||
| 자재 번호 MaterialNumber | 조달 대상인 특정 자재 또는 상품의 식별자입니다. | ||
| 설명 자재 번호는 SAP의 각 자재 마스터 레코드에 부여되는 고유 코드입니다. 조달, 재고 관리, 판매 등 해당 자재와 관련된 모든 거래에 사용됩니다. 자재 번호나 자재 그룹별 분석을 통해 품목군별 조달 현황을 파악할 수 있습니다. 특정 자재의 조달 프로세스가 비효율적이거나 리드 타임이 길고 반품이 잦은지 확인해 카테고리 관리에 활용할 수 있습니다. 중요한 이유 품목군별 분석을 통해 특정 제품이나 자재와 관련된 프로세스 문제 또는 공급업체 성과 문제를 파악할 수 있습니다. 확보 방법 이 속성은 SAP S/4HANA 테이블 EKPO의 MATNR 필드에 있습니다. 예시 원자재 100-100FG210컨설팅 서비스 | |||
| 재작업 여부 IsRework | 승인 후 변경이나 상품 반품 등 구매 오더에 재작업이 발생했는지 나타내는 계산 플래그입니다. | ||
| 설명 구매 오더별 활동 순서를 분석해 계산하는 불리언 속성입니다. 'Purchase Order Approved' 이벤트 이후에 'Purchase Order Changed' 이벤트가 발생하거나 'Goods Returned' 이벤트가 있으면 'true'로 표시됩니다. 이 플래그를 사용하면 '일괄 처리율' KPI를 간편하게 계산할 수 있습니다. 수작업 개입이나 수정이 필요했던 모든 구매 오더를 쉽게 필터링하고 시각화해 재작업의 비용과 빈도를 파악할 수 있습니다. 중요한 이유 재작업이 발생한 사례를 표시해 프로세스 비효율의 규모를 파악할 수 있습니다. 일괄 처리율을 계산하고 이탈의 근본 원인을 찾는 데 유용합니다. 확보 방법 활동 순서를 기준으로 계산하는 필드입니다. 승인 후 'Purchase Order Changed' 이벤트가 발생했는지 또는 'Goods Returned' 이벤트가 있는지 확인합니다. 예시 truefalse | |||
| 플랜트 Plant | 상품을 배송하거나 서비스를 제공하는 운영 시설 또는 장소입니다. | ||
| 설명 SAP에서 플랜트는 상품을 생산하거나 보관하고 서비스를 수행하는 물리적 장소입니다. 물류와 계획 수립에 중요한 요소입니다. 플랜트별로 프로세스를 분석하면 지역이나 사업장에 따른 조달 프로세스의 차이를 파악할 수 있습니다. 예를 들어 특정 플랜트의 배송 시간이 더 길거나 상품 반품률이 더 높은지 확인해 현지 물류 또는 품질 관리 문제를 찾을 수 있습니다. 중요한 이유 장소별 분석을 통해 운영 사업장, 플랜트 또는 창고 간 프로세스 성과 차이를 확인할 수 있습니다. 확보 방법 이 속성은 SAP S/4HANA 테이블 EKPO의 WERKS 필드에 있습니다. 예시 10101710DE01 | |||
| 항목 범주 ItemCategory | 일반, 위탁, 외주 가공, 서비스 등 구매 오더 항목의 유형을 분류합니다. | ||
| 설명 항목 범주는 특정 자재나 서비스를 조달하고 처리하는 방식을 결정합니다. 입고와 송장 검증 등 후속 단계에도 영향을 줍니다. 이 속성은 구매 대상에 따른 프로세스 변형을 분석하는 데 중요합니다. 예를 들어 서비스 항목은 서비스 입력 시트가 필요하므로 일반 재고 항목과 프로세스가 크게 다릅니다. 항목 범주별로 분석하면 이러한 차이를 파악하고 개선 대상을 구체적으로 정할 수 있습니다. 중요한 이유 상품, 서비스, 외주 등 조달 유형을 구분해 프로세스의 변형을 설명합니다. 확보 방법 이 속성은 SAP S/4HANA 테이블 EKPO의 PSTYP 필드에 있습니다. 예시 093 | |||
| 회사 코드 CompanyCode | 구매 오더를 생성하는 법인 또는 회사의 식별자입니다. | ||
| 설명 회사 코드는 조직 내 독립적인 회계 단위를 나타냅니다. 구매 오더와 관련된 모든 재무 거래는 특정 회사 코드에 전기됩니다. 법인별로 조달 프로세스를 필터링하고 비교할 수 있게 해주는 기본 조직 속성입니다. 회사 코드별 분석을 통해 조직 내 프로세스 실행의 불일치, 효율성 차이 또는 규정 준수율의 편차를 파악할 수 있습니다. 중요한 이유 법인별로 프로세스 분석을 구분해 사업 부문 간 성과와 규정 준수 수준을 비교할 수 있습니다. 확보 방법 이 속성은 SAP S/4HANA 테이블 EKKO의 BUKRS 필드에 있습니다. 예시 101017102000 | |||
구매 대금 지급 프로세스의 구매 오더 활동
| 활동 | 설명 | ||
|---|---|---|---|
| 구매 오더 생성 | 구매 요청을 참조하거나 참조하지 않고 공식 구매 오더 문서를 생성하는 단계입니다. 구매 오더 문서를 시스템에 처음 저장할 때 이벤트가 명시적으로 기록됩니다. | ||
| 중요한 이유 특히 무단 구매를 분석할 때 이 활동을 프로세스의 대체 시작점으로 사용할 수 있습니다. 전체 구매 오더 처리 시간을 추적하는 기본 이벤트이기도 합니다. 확보 방법 구매 오더 헤더 테이블 EKKO에 기록됩니다. 문서의 생성일(AEDAT)과 시간은 이 테이블에 저장됩니다. 기록 구매 오더 문서의 생성 타임스탬프(AEDAT)는 EKKO 테이블에 저장됩니다. 이벤트 유형 explicit | |||
| 구매 오더 승인 | 구매 오더에 필요한 내부 승인이 모두 완료되어 공급업체에 발행할 수 있는 상태입니다. 구매 오더의 승인 전략에 따른 상태 변경으로 확인합니다. | ||
| 중요한 이유 승인 효율과 승인 후 재작업을 측정하는 주요 단계입니다. 구매 오더 생성부터 승인까지 걸린 시간을 분석하면 내부 프로세스의 지연을 파악할 수 있습니다. 확보 방법 EKKO 테이블의 승인 지시자(FRGKE)로 확인합니다. 이 필드가 '승인됨' 상태로 변경된 시각은 변경 이력(CDHDR/CDPOS)에서 확인합니다. 기록 EKKO 테이블의 승인 지시자(FRGKE) 필드에 대한 변경 로그로 확인합니다. 이벤트 유형 inferred | |||
| 구매 오더 완료 | 물류 관점에서 구매 오더 항목이 종료된 상태를 나타냅니다. '납품 완료'와 '최종 송장' 지시자가 모두 설정되면 완료로 간주합니다. | ||
| 중요한 이유 구매 오더 수명 주기 분석의 종료점입니다. 이 이벤트까지 걸린 시간을 측정하면 조달 운영의 전체 처리 시간을 확인할 수 있습니다. 확보 방법 구매 오더 항목 테이블 EKPO의 상태 플래그로 확인합니다. '납품 완료' 지시자(ELIKZ)와 '최종 송장' 지시자(EREKZ)가 모두 참으로 설정되면 이벤트가 발생합니다. 기록 EKPO의 ELIKZ 및 EREKZ 필드가 모두 완료로 설정된 변경 로그를 통해 확인합니다. 이벤트 유형 inferred | |||
| 구매 요청 생성 | 이 활동은 상품이나 서비스를 공식적으로 요청하며 조달 프로세스를 시작합니다. 사용자가 새 구매 요청 문서를 저장할 때(예: 트랜잭션 ME51N 사용) 이벤트가 명시적으로 기록됩니다. | ||
| 중요한 이유 많은 구매 오더 수명 주기에서 이 이벤트가 주요 시작점입니다. 이 이벤트부터 구매 오더 생성까지 걸린 시간을 분석하면 소싱과 내부 처리의 지연을 파악할 수 있습니다. 확보 방법 EBAN(구매 요청) 테이블에 기록됩니다. 생성 이벤트의 타임스탬프는 EBAN 객체의 변경 이력 테이블 CDHDR 및 CDPOS에서 확인할 수 있습니다. 기록 EBAN 테이블에 문서가 생성될 때 이벤트가 기록됩니다. 이벤트 유형 explicit | |||
| 구매 요청 승인 | 관리자나 지정된 승인자가 구매 요청을 공식적으로 승인한 상태입니다. 일반적으로 요청 문서의 상태 변경을 통해 확인하며, 구매 오더로 전환할 준비가 되었음을 나타냅니다. | ||
| 중요한 이유 승인 처리 시간을 추적하고 병목을 파악하는 데 중요한 단계입니다. 이 단계의 지연은 구매 오더를 생성해 공급업체에 보내는 시점에 직접 영향을 줍니다. 확보 방법 EBAN 테이블의 승인 상태 필드(예: FRGZU, 승인 지시자)로 확인합니다. 최종 승인 상태가 설정된 시각은 해당 변경을 기록한 변경 문서(CDHDR/CDPOS)에서 가져옵니다. 기록 EBAN 테이블의 승인 상태 필드에 대한 변경 로그(CDHDR/CDPOS)로 확인합니다. 이벤트 유형 inferred | |||
| 송장 접수 | 공급업체 송장을 SAP 시스템에 입력하고 해당 구매 오더와 연결하는 단계입니다. 회계 문서를 생성하는 명시적 재무 전기입니다. | ||
| 중요한 이유 조달 프로세스와 매입금 프로세스를 연결하는 주요 단계입니다. 입고부터 송장 처리까지 걸린 시간을 분석할 수 있습니다. 확보 방법 회계 문서는 BKPF(헤더) 테이블에 생성되며, 개별 항목은 BSEG 또는 통합 분개장 ACDOCA에 저장됩니다. RSEG 테이블에서 구매 오더와 연결됩니다. 기록 회계 문서 헤더 테이블 BKPF의 문서 입력일(CPUDT)입니다. 이벤트 유형 explicit | |||
| 입고 전기 | 공급업체에서 상품을 실제로 인수하고 그 내용을 시스템에 입력하는 단계입니다. 구매 오더 이력을 갱신하는 명시적 트랜잭션입니다. | ||
| 중요한 이유 이 단계에서 공급업체 납기 기간이 끝나고 내부 송장 검증 프로세스가 시작됩니다. 정시 납품률을 추적하는 데 필요한 주요 단계입니다. 확보 방법 자재 문서로 기록되며, 헤더는 MKPF 테이블, 항목은 MSEG 테이블에 저장됩니다. 특정 이동 유형(예: 101)으로 구매 오더 이력 테이블 EKBE에 연결됩니다. 기록 EKBE를 통해 연결된 자재 문서 헤더(MKPF)의 전기일(BUDAT)입니다. 이벤트 유형 explicit | |||
| 구매 오더 변경 | 구매 오더를 처음 생성한 후 수량, 가격 또는 납품일 등을 변경한 활동입니다. 시스템 변경 로그에 명시적으로 기록됩니다. | ||
| 중요한 이유 특히 승인 후 변경을 추적하면 프로세스 비효율, 재작업, 규정 준수 문제를 파악할 수 있습니다. 변경이 잦다면 초기 요구사항이 부정확했을 가능성이 있습니다. 확보 방법 구매 오더 객체(EINKBELEG)의 변경 문서 테이블 CDHDR(헤더) 및 CDPOS(항목)에 기록됩니다. 변경할 때마다 상세 로그 항목이 생성됩니다. 기록 EKKO 또는 EKPO 테이블의 주요 필드가 변경되면 이벤트가 기록되며, CDHDR/CDPOS에서 확인할 수 있습니다. 이벤트 유형 explicit | |||
| 구매 오더 삭제 | 구매 오더 항목 또는 문서 전체를 취소하거나 논리적으로 삭제하는 단계입니다. 사용자가 문서에 삭제 플래그를 설정하면 기록됩니다. | ||
| 중요한 이유 프로세스의 대체 종료점으로, 실패나 취소를 나타냅니다. 구매 오더가 삭제된 이유를 분석하면 수요 계획이나 요구사항 정의의 문제를 찾을 수 있습니다. 확보 방법 구매 오더 헤더(EKKO) 또는 항목(EKPO) 테이블의 삭제 지시자 플래그(LOEKZ)에서 가져옵니다. 타임스탬프는 변경 문서(CDHDR/CDPOS)에서 확인합니다. 기록 삭제 플래그(LOEKZ)가 설정된 시점의 변경 문서(CDHDR/CDPOS) 타임스탬프입니다. 이벤트 유형 explicit | |||
| 구매 오더를 공급업체에 발송 | EDI, 이메일 또는 인쇄물 등으로 구매 오더를 공급업체에 전달하는 시점입니다. 시스템의 출력 관리 로그에 이벤트가 기록되는 경우가 많습니다. | ||
| 중요한 이유 이 활동은 공급업체 납기 기간의 실제 시작점입니다. 공급업체가 주문을 받은 시점부터 성과를 정확히 측정하는 데 중요합니다. 확보 방법 구매 문서에 발송된 메시지를 기록하는 출력 제어 테이블 NAST에서 가져옵니다. 관련 출력 유형(예: EDI, 이메일)의 날짜와 시간을 사용할 수 있습니다. 기록 NAST 테이블에서 구매 오더에 대해 처음 성공적으로 발송된 출력 메시지의 타임스탬프입니다. 이벤트 유형 inferred | |||
| 상품 반품 | 품질 문제, 파손 또는 오배송 등으로 이미 입고된 상품을 공급업체에 반품한 경우입니다. 반품을 위한 취소 자재 이동으로 명시적으로 기록됩니다. | ||
| 중요한 이유 이 활동은 재작업과 공급업체 품질 또는 주문 정확도 문제를 보여줍니다. 특정 공급업체나 자재의 반품이 잦다면 문제가 있다는 신호입니다. 확보 방법 특정 반품 이동 유형(예: 122)을 사용하는 자재 문서로 기록됩니다. 이벤트는 MKPF/MSEG에 저장되고 EKBE 이력 테이블에서 구매 오더와 연결됩니다. 기록 EKBE에서 반품 이동 유형이 적용된 자재 문서의 전기일입니다. 이벤트 유형 explicit | |||
| 서비스 확인 입력 | 구매 오더에 명시된 서비스가 제공되었음을 확인하는 활동입니다. 서비스 입력 시트를 생성할 때 명시적으로 기록됩니다. | ||
| 중요한 이유 서비스 조달에서는 입고에 해당하는 단계입니다. 서비스 제공 기간을 추적하고 공급업체 대금을 제때 지급하는 데 중요합니다. 확보 방법 서비스 입력 시트를 생성할 때 기록되며, 데이터는 ESSR(헤더) 및 ESLL(항목) 테이블에 저장됩니다. 생성일을 타임스탬프로 사용합니다. 기록 ESSR 테이블에 저장된 서비스 입력 시트 문서의 생성일입니다. 이벤트 유형 explicit | |||
| 송장 지급 | 지급 실행이나 수동 지급을 통해 공급업체 송금을 최종 정산하는 단계입니다. 반제 문서를 생성하는 명시적 재무 트랜잭션입니다. | ||
| 중요한 이유 기술적으로는 지급 프로세스에 속하지만, 이 활동을 포함하면 구매-지급 주기 전체를 파악할 수 있습니다. 지급 조건과 지급 성과를 분석하는 데 중요합니다. 확보 방법 지급은 BKPF/ACDOCA에 반제 문서로 기록됩니다. BSEG 또는 ACDOCA 테이블의 송장 항목에 있는 반제일(AUGDT)이 지급 이벤트를 나타냅니다. 기록 BSEG 또는 ACDOCA에서 확인할 수 있는 송장 문서의 반제일(AUGDT)입니다. 이벤트 유형 explicit | |||
데이터 추출 가이드
단계
- 사전 요건 및 액세스: SAP S/4HANA 시스템에서 Core Data Services(CDS) 뷰를 조회할 수 있는 권한이 있는 사용자 계정을 준비합니다. SAP HANA Studio, Eclipse용 ABAP Development Tools(ADT) 또는 SAP HANA 데이터베이스에 SQL 연결을 지원하는 타사 데이터 추출 도구를 통해 액세스할 수 있습니다.
- 시스템 연결 정보 확인: SAP S/4HANA 시스템에 연결하는 데 필요한 호스트, 인스턴스 번호, 인증 정보를 확인합니다.
- 데이터베이스 연결: 원하는 SQL 클라이언트에서 CDS 뷰가 있는 SAP S/4HANA 데이터베이스에 연결합니다.
- SQL 쿼리 준비: 이 문서의 쿼리 섹션에 있는 전체 SQL 쿼리를 복사해 SQL 편집기에 붙여 넣습니다. 이 쿼리는 필요한 활동과 속성을 모두 추출하도록 작성되었습니다.
- 필터 매개변수 설정: 쿼리에서 자리표시자 값을 찾습니다. _start_date와 _end_date를 분석할 기간으로 바꿉니다(예: '20230101', '20231231'). poh.CompanyCode 필터에는 분석할 회사 코드를 지정합니다.
- 쿼리 실행: 수정한 SQL 쿼리를 S/4HANA 데이터베이스에서 실행합니다. 데이터 양과 지정한 기간에 따라 실행에 시간이 걸릴 수 있습니다.
- 결과 사전 검토: 쿼리 실행이 끝나면 SQL 클라이언트에서 결과를 간단히 확인합니다. 여러 활동이 포함되어 있는지, 타임스탬프가 올바르게 입력되었는지, 케이스 ID(PurchaseOrderNumber)가 일관적인지 점검합니다.
- 데이터 내보내기: SQL 도구에서 전체 결과를 CSV(쉼표로 구분된 값) 파일로 내보냅니다. 문자 인코딩 문제를 방지하려면 UTF-8을 사용합니다.
- 업로드 준비: ProcessMind에 업로드하기 전에 CSV 파일을 열어 열 머리글이 데이터 요구사항에 정의된 속성(PurchaseOrderNumber, ActivityName, EventTime 등)과 정확히 일치하는지 확인합니다. 내보내기 도구에서 열 이름이 변경되었다면 수정합니다.
- ProcessMind에 업로드: 완성된 CSV 파일을 ProcessMind 프로젝트에 업로드합니다. 가져오는 과정에서 파일의 열을 해당 케이스 ID, 활동, 타임스탬프 필드에 매핑합니다.
구성
- 사용되는 주요 CDS View: 추출 로직은 의미가 명확한 표준 CDS 뷰를 사용합니다. 주요 뷰는 다음과 같습니다.
- I_PurchaseOrderItemAPI01: 구매 오더 품목의 기본 데이터
- I_PurchaseRequisitionItemAPI01: 구매 요청 세부 정보
- I_MaterialDocumentItem: 입고 및 반품과 같은 자재 이동
- I_ServiceEntrySheetAPI01: 서비스 확인 이벤트
- I_SupplierInvoiceAPI01: 공급업체 송장 정보
- I_OperationalAcctgDocItem: 지급 추적을 위해 송장과 재무 문서를 연결하는 데이터
- I_ChangeDocument: 구매 오더 변경 내역
- 기간 필터링: 성능과 데이터 양을 관리하려면 기간 필터를 반드시 적용해야 합니다. 쿼리는 구매 오더 생성일(PurchaseOrderDate)에 _start_date와 _end_date 자리표시자를 사용합니다. 처음에는 3~6개월의 데이터를 대상으로 시작하는 것이 좋습니다.
- 조직 필터링: 관련 사업부만 추출하도록 CompanyCode 필터를 항상 적용해야 합니다. 범위를 더 좁히려면 기본 PO_base 공통 테이블 식에 PurchaseOrderType 또는 PurchasingOrganization 필터를 추가할 수 있습니다.
- 사전 요건: 쿼리를 실행하는 사용자에게는 위에 나열된 모든 CDS 뷰에 대한 SELECT 권한이 필요합니다. 일반적으로 S/4HANA의 특정 업무 또는 분석 역할을 통해 해당 뷰에 액세스할 수 있습니다. 권한이 없으면 쿼리가 실패합니다.
샘플 쿼리 sql
WITH PO_base AS (
SELECT
poh.PurchaseOrder AS PurchaseOrderNumber,
poi.PurchaseOrderItem AS PurchaseOrderItem,
poh.CompanyCode,
poh.PurchaseOrderType AS DocumentType,
poh.Supplier AS VendorId,
poh.PurchaseOrderDate,
poi.PurchaseRequisition AS PurchaseRequisitionNumber,
poi.NetPriceAmount * poi.OrderQuantity AS TotalNetAmount, -- Note: This is item-level net amount
poh.CreationDate AS POCreationDate,
poh.CreationTime AS POCreationTime,
poh.LastChangeDateTime AS POLastChangeDateTime,
poi.IsDeleted,
poi.DeliveryIsCompleted,
poi.FinalInvoiceIsExpected,
poi.GoodsReceiptIsExpected,
poi.LastGoodsReceiptDate,
poi.LastInvoiceReceiptDate
FROM I_PurchaseOrderAPI01 poh
JOIN I_PurchaseOrderItemAPI01 poi
ON poh.PurchaseOrder = poi.PurchaseOrder
WHERE
poh.PurchaseOrderDate BETWEEN '_start_date' AND '_end_date' -- Placeholder: e.g., '20230101' and '20230630'
AND poh.CompanyCode IN ('[YourCompanyCode]') -- Placeholder: e.g., '1010'
)
-- 1. Purchase Requisition Created
SELECT
po.PurchaseOrderNumber,
'Purchase Requisition Created' AS ActivityName,
CAST(CONCAT(pr.CreationDate, 'T', pr.CreationTime) AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem, -- Placeholder
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
pr.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate, -- Available in PR, add if needed
po.DocumentType
FROM I_PurchaseRequisitionItemAPI01 pr
JOIN PO_base po
ON pr.PurchaseRequisition = po.PurchaseRequisitionNumber AND pr.PurchaseRequisitionItem = po.PurchaseOrderItem
UNION ALL
-- 2. Purchase Requisition Approved
SELECT
po.PurchaseOrderNumber,
'Purchase Requisition Approved' AS ActivityName,
CAST(CONCAT(pr.PurReqnReleaseDate, 'T', '000000') AS TIMESTAMP) AS EventTime, -- Time is not available in this view
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
NULL AS UserName, -- Approver info requires complex joins
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_PurchaseRequisitionItemAPI01 pr
JOIN PO_base po
ON pr.PurchaseRequisition = po.PurchaseRequisitionNumber AND pr.PurchaseRequisitionItem = po.PurchaseOrderItem
WHERE
pr.PurReqnReleaseDate IS NOT NULL
UNION ALL
-- 3. Purchase Order Created
SELECT
po.PurchaseOrderNumber,
'Purchase Order Created' AS ActivityName,
CAST(CONCAT(po.POCreationDate, 'T', po.POCreationTime) AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
poh.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
poi.RequestedDeliveryDate,
po.DocumentType
FROM PO_base po
JOIN I_PurchaseOrderAPI01 poh ON po.PurchaseOrderNumber = poh.PurchaseOrder
JOIN I_PurchaseOrderItemAPI01 poi ON po.PurchaseOrderNumber = poi.PurchaseOrder AND po.PurchaseOrderItem = poi.PurchaseOrderItem
UNION ALL
-- 4. Purchase Order Approved
SELECT DISTINCT
po.PurchaseOrderNumber,
'Purchase Order Approved' AS ActivityName,
CAST(poh.ReleaseDate AS TIMESTAMP) AS EventTime, -- Assuming ReleaseDate reflects final approval
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
NULL AS UserName, -- Approver info requires complex joins
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
poi.RequestedDeliveryDate,
po.DocumentType
FROM PO_base po
JOIN I_PurchaseOrderAPI01 poh ON po.PurchaseOrderNumber = poh.PurchaseOrder
JOIN I_PurchaseOrderItemAPI01 poi ON po.PurchaseOrderNumber = poi.PurchaseOrder AND po.PurchaseOrderItem = poi.PurchaseOrderItem
WHERE poh.ReleaseDate IS NOT NULL
UNION ALL
-- 5. Purchase Order Sent to Vendor
SELECT DISTINCT
po.PurchaseOrderNumber,
'Purchase Order Sent to Vendor' AS ActivityName,
CAST(poh.ReleaseDate AS TIMESTAMP) AS EventTime, -- Using ReleaseDate as a proxy for sending time
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
NULL AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
poi.RequestedDeliveryDate,
po.DocumentType
FROM PO_base po
JOIN I_PurchaseOrderAPI01 poh ON po.PurchaseOrderNumber = poh.PurchaseOrder
JOIN I_PurchaseOrderItemAPI01 poi ON po.PurchaseOrderNumber = poi.PurchaseOrder AND po.PurchaseOrderItem = poi.PurchaseOrderItem
WHERE poh.ReleaseDate IS NOT NULL
UNION ALL
-- 6. Purchase Order Changed
SELECT DISTINCT
ch.OBJECTID AS PurchaseOrderNumber,
'Purchase Order Changed' AS ActivityName,
CAST(CONCAT(ch.ChangeDocumentDate, 'T', ch.ChangeDocumentTime) AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
ch.UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_ChangeDocument ch
JOIN PO_base po ON ch.OBJECTID = po.PurchaseOrderNumber
WHERE
ch.ObjectClassName = 'EINKBELEG' -- Object Class for Purchase Documents
AND CAST(CONCAT(ch.ChangeDocumentDate, 'T', ch.ChangeDocumentTime) AS TIMESTAMP) > CAST(CONCAT(po.POCreationDate, 'T', po.POCreationTime) AS TIMESTAMP)
UNION ALL
-- 7. Goods Receipt Posted
SELECT
po.PurchaseOrderNumber,
'Goods Receipt Posted' AS ActivityName,
CAST(CONCAT(md.PostingDate, 'T', md.CreationTime) AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
md.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_MaterialDocumentItem md
JOIN PO_base po
ON md.PurchaseOrder = po.PurchaseOrderNumber AND md.PurchaseOrderItem = po.PurchaseOrderItem
WHERE
md.GoodsMovementType = '101'
UNION ALL
-- 8. Services Confirmation Entered
SELECT
po.PurchaseOrderNumber,
'Services Confirmation Entered' AS ActivityName,
CAST(se.PostingDate AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
se.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_ServiceEntrySheetAPI01 se
JOIN PO_base po
ON se.PurchaseOrder = po.PurchaseOrderNumber AND se.PurchaseOrderItem = po.PurchaseOrderItem
UNION ALL
-- 9. Goods Returned
SELECT
po.PurchaseOrderNumber,
'Goods Returned' AS ActivityName,
CAST(CONCAT(md.PostingDate, 'T', md.CreationTime) AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
md.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_MaterialDocumentItem md
JOIN PO_base po
ON md.PurchaseOrder = po.PurchaseOrderNumber AND md.PurchaseOrderItem = po.PurchaseOrderItem
WHERE
md.GoodsMovementType = '122'
UNION ALL
-- 10. Invoice Received
SELECT
po.PurchaseOrderNumber,
'Invoice Received' AS ActivityName,
CAST(inv.PostingDate AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
inv.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_SupplierInvoiceAPI01 inv
JOIN PO_base po
ON inv.PurchaseOrderReference = po.PurchaseOrderNumber
WHERE
inv.DebitCreditCode = 'H' -- 'H' for Credit (Supplier Invoice)
UNION ALL
-- 11. Invoice Paid
SELECT
po.PurchaseOrderNumber,
'Invoice Paid' AS ActivityName,
CAST(doc.ClearingDate AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
doc.CreatedByUser AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM I_SupplierInvoiceAPI01 inv
JOIN I_OperationalAcctgDocItem doc
ON inv.AccountingDocument = doc.AccountingDocument
JOIN PO_base po
ON inv.PurchaseOrderReference = po.PurchaseOrderNumber
WHERE
doc.IsCleared = 'X' AND doc.ClearingDate IS NOT NULL
UNION ALL
-- 12. Purchase Order Completed
SELECT
po.PurchaseOrderNumber,
'Purchase Order Completed' AS ActivityName,
CAST(GREATEST(po.LastGoodsReceiptDate, po.LastInvoiceReceiptDate) AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
'SYSTEM' AS UserName,
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM PO_base po
WHERE
po.DeliveryIsCompleted = 'X'
AND (po.FinalInvoiceIsExpected = 'X' OR po.GoodsReceiptIsExpected = '') -- Logic for completion
AND GREATEST(po.LastGoodsReceiptDate, po.LastInvoiceReceiptDate) IS NOT NULL
UNION ALL
-- 13. Purchase Order Deleted
SELECT
po.PurchaseOrderNumber,
'Purchase Order Deleted' AS ActivityName,
CAST(po.POLastChangeDateTime AS TIMESTAMP) AS EventTime,
'[Your S/4HANA System ID]' AS SourceSystem,
CURRENT_UTCTIMESTAMP AS LastDataUpdate,
po.VendorId,
NULL AS UserName, -- User who set the flag is in change docs
po.TotalNetAmount,
po.PurchaseRequisitionNumber,
NULL AS RequestedDeliveryDate,
po.DocumentType
FROM PO_base po
WHERE
po.IsDeleted = 'X' 단계
- EKKO와 EKPO가 있는 SAP HANA 스키마에 직접 SQL로 액세스할 수 있는지 확인하고 필요한 읽기 권한을 확보합니다. 스키마와 연결 자리표시자를 시스템에 설정된 값으로 바꿉니다.
- [Start timestamp]와 [End timestamp]를 사용해 추출 기간을 지정합니다. 최초 적재에는 3~6개월을 권장합니다. 보고 범위에 필요한 경우에만 회사 코드와 문서 유형 필터를 적용합니다.
- EKKO와 EKPO에서 구매 오더를 조회하고 구매 오더 번호, 공급업체, 문서 유형, 회사 코드, 생성일, 생성 시간 및 품목 수준 속성을 유지합니다. EKPO의 순액을 집계해 구매 오더 수준의 TotalNetAmount를 계산합니다.
- EBAN에서 구매 요청 생성 및 승인 이벤트를 추출합니다. EKPO에서 확인할 수 있는 구매 요청 번호와 품목 참조를 사용해 구매 요청과 구매 오더를 연결합니다. 릴리스 구성에 따라 승인 지표와 타임스탬프가 다르므로, [Configure based on your system]에 현재 SAP 릴리스 전략에 맞는 승인 상태 및 타임스탬프 식을 설정합니다.
- 구매 오더 생성, 승인, 변경, 삭제 및 완료 이벤트를 추출합니다. 생성 이벤트에는 EKKO 생성일과 시간을 사용합니다. 승인, 변경 및 삭제 이벤트에는 릴리스 이력 또는 변경 이력 데이터가 필요합니다. 선택한 스키마에서 관련 이력을 확인할 수 없다면 [Your table name]과 [Your column name]을 사용해 해당 데이터 원본 식을 설정합니다.
- 해당 출력, 자재 문서, 서비스 입력, 송장, 회계 및 반제 데이터 원본에서 공급업체 통지, 입고, 서비스 확인, 반품, 송장 수령 및 송장 지급 이벤트를 추출합니다. EKKO와 EKPO만으로는 이 데이터 원본을 확인할 수 없으므로 쿼리에 시스템별 객체를 지정하는 자리표시자가 포함되어 있습니다.
- 모든 원본 이벤트를 동일한 이벤트 로그 구조로 정규화합니다. 각 행에는 PurchaseOrderNumber, ActivityName, EventTime, SourceSystem, LastDataUpdate, VendorId, UserName, TotalNetAmount, PurchaseRequisitionNumber, RequestedDeliveryDate, DocumentType이 있어야 합니다. 원본에 유효한 이벤트가 여러 건 있으면 해당 활동의 여러 발생 건을 모두 유지합니다.
- 타임스탬프를 검증하고 원본 행이 완전히 동일한 경우에만 중복을 제거합니다. 원본 기록이 없는 활동을 추정해 추가하지 않습니다. ProcessMind는 이벤트 로그를 그대로 읽으므로 프로세스 시각화에 표시되는 모든 활동은 명시적인 행으로 존재해야 합니다.
- 헤더 행 하나와 일관된 열 이름을 포함해 결과를 구분 기호로 나눈 파일 또는 데이터베이스 결과 집합으로 내보냅니다. ProcessMind 업로드 설정에서 지원하는 타임스탬프 형식을 사용하고 PurchaseOrderNumber는 텍스트로 유지합니다. 설정된 ProcessMind 데이터 연결을 통해 전체 이벤트 로그를 업로드합니다.
구성
- 원본 객체: EKKO와 EKPO는 구매 오더 헤더 및 품목의 확인된 원본입니다. 구매 요청, 릴리스 상태, 변경 이력, 출력, 자재 이동, 서비스 입력 시트, 송장, 지급 및 반제에 필요한 추가 객체는 SAP S/4HANA 릴리스와 활성 데이터 모델에 맞게 설정해야 합니다.
- 케이스 식별자: 케이스 식별자로 PurchaseOrderNumber를 사용합니다. 품목 수준 이벤트는 구매 오더 번호에 연결하고, 필요한 경우 품목 참조를 원본별 추가 열에 보관합니다.
- 기간: 처음에는 3~6개월을 대상으로 합니다. 과거 데이터를 적재할 때는 더 짧은 기간으로 나누어 처리하고, 누락을 방지하도록 겹치는 기간의 경계를 대조합니다.
- 필터: 필요한 범위에 맞춰 Company Code, Document Type, VendorId, 구매 조직, 구매 그룹 및 이벤트 날짜 필터를 설정합니다. 회사 코드와 문서 유형 필터에는 대상 시스템에서 유효한 값을 사용해야 합니다.
- 이벤트 의미: 관련 문서 필드나 로그를 사용할 수 있으면 생성 및 삭제 이벤트를 명시적으로 기록할 수 있습니다. 승인 및 완료는 상태 기반 이벤트이므로 상태 타임스탬프를 설정해야 합니다. 근거가 되는 이벤트 타임스탬프 없이 현재 상태만으로 행을 만들지 않습니다.
- 성능: 이벤트 날짜와 조직 범위를 초기에 필터링하고, 가능한 경우 이벤트 원본과 조인하기 전에 EKPO를 집계합니다. 과거 데이터가 많으면 기간을 나누어 실행합니다. 적절한 데이터베이스 통계를 유지하고 품목, 회계 및 변경 이력 원본 간의 제한 없는 조인을 피합니다.
- 새로 고침 타임스탬프: 실행할 때마다 모든 행의 LastDataUpdate에 추출 실행 시각을 설정합니다.
- 사전 요건: SAP HANA 연결, 설정된 모든 원본 객체에 대한 읽기 권한, 관련 구매·재고 관리·서비스 조달·송장 검증·매입금 데이터에 대한 액세스, 선택한 파일 또는 결과 집합을 가져올 수 있는 ProcessMind 연결이 필요합니다.
- 시스템별 설정: 쿼리의 대괄호로 표시된 모든 원본 자리표시자를 대상 SAP S/4HANA 시스템에서 승인된 테이블, 뷰, 열 또는 식으로 바꿉니다. 쿼리나 추출 설정에 인증 정보를 노출하지 않습니다.
샘플 쿼리 sql
WITH
params AS (
SELECT
CAST('[Start timestamp]' AS TIMESTAMP) AS start_ts,
CAST('[End timestamp]' AS TIMESTAMP) AS end_ts,
CAST(CURRENT_TIMESTAMP AS TIMESTAMP) AS last_data_update,
CAST('[Source system]' AS NVARCHAR(100)) AS source_system
FROM DUMMY
),
po_base AS (
SELECT
h.MANDT,
h.EBELN AS PurchaseOrderNumber,
h.LIFNR AS VendorId,
h.BSART AS DocumentType,
h.BUKRS AS CompanyCode,
CAST(h.AEDAT AS DATE) AS POChangedDate,
CAST(h.AEDAT AS TIMESTAMP) AS POChangedTimestamp,
CAST(h.ERNAM AS NVARCHAR(100)) AS POCreatedBy,
CAST(h.BEDAT AS DATE) AS PODate,
CAST(h.EBELN AS NVARCHAR(20)) AS PurchaseOrderKey,
CAST(SUM(COALESCE(i.NETWR, 0)) AS DECIMAL(23, 2)) AS TotalNetAmount,
CAST(MIN(i.BEDNR) AS NVARCHAR(20)) AS PurchaseRequisitionNumber,
CAST(MIN(i.EINDT) AS DATE) AS RequestedDeliveryDate
FROM EKKO h
INNER JOIN EKPO i
ON i.MANDT = h.MANDT
AND i.EBELN = h.EBELN
WHERE h.AEDAT >= (SELECT start_ts FROM params)
AND h.AEDAT < (SELECT end_ts FROM params)
AND h.BUKRS IN ([Company Code filter])
AND h.BSART IN ([Document Type filter])
GROUP BY
h.MANDT,
h.EBELN,
h.LIFNR,
h.BSART,
h.BUKRS,
h.AEDAT,
h.ERNAM,
h.BEDAT
),
po_items AS (
SELECT
i.MANDT,
i.EBELN AS PurchaseOrderNumber,
i.EBELP,
i.BANFN AS PurchaseRequisitionNumber,
i.BEDNR,
i.EINDT AS RequestedDeliveryDate
FROM EKPO i
),
events AS (
SELECT
p.PurchaseOrderNumber,
'Purchase Requisition Created' AS ActivityName,
CAST(r.[Purchase requisition creation timestamp] AS TIMESTAMP) AS EventTime,
s.source_system AS SourceSystem,
s.last_data_update AS LastDataUpdate,
p.VendorId,
CAST(r.[Purchase requisition created by] AS NVARCHAR(100)) AS UserName,
p.TotalNetAmount,
CAST(r.[Purchase requisition number] AS NVARCHAR(20)) AS PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your requisition source table or view] r
ON r.[Client] = p.MANDT
AND r.[Purchase requisition number] = p.PurchaseRequisitionNumber
CROSS JOIN params s
WHERE r.[Purchase requisition creation timestamp] >= s.start_ts
AND r.[Purchase requisition creation timestamp] < s.end_ts
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Requisition Approved' AS ActivityName,
CAST(r.[Purchase requisition approval timestamp] AS TIMESTAMP) AS EventTime,
s.source_system,
s.last_data_update,
p.VendorId,
CAST(r.[Purchase requisition approver] AS NVARCHAR(100)),
p.TotalNetAmount,
CAST(r.[Purchase requisition number] AS NVARCHAR(20)),
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your requisition approval history table or view] r
ON r.[Client] = p.MANDT
AND r.[Purchase requisition number] = p.PurchaseRequisitionNumber
CROSS JOIN params s
WHERE r.[Purchase requisition approval timestamp] >= s.start_ts
AND r.[Purchase requisition approval timestamp] < s.end_ts
AND r.[Approval status] = '[Approved status value]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Order Created',
CAST(p.PODate AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
p.POCreatedBy,
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
CROSS JOIN params s
WHERE p.PODate >= CAST(s.start_ts AS DATE)
AND p.PODate < CAST(s.end_ts AS DATE)
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Order Approved',
CAST(a.[Purchase order approval timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(a.[Approver] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your purchase order release history table or view] a
ON a.[Client] = p.MANDT
AND a.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE a.[Purchase order approval timestamp] >= s.start_ts
AND a.[Purchase order approval timestamp] < s.end_ts
AND a.[Release status] = '[Approved release status value]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Order Sent to Vendor',
CAST(o.[Output timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(o.[Output user] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your purchase order output source table or view] o
ON o.[Client] = p.MANDT
AND o.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE o.[Output timestamp] >= s.start_ts
AND o.[Output timestamp] < s.end_ts
AND o.[Output status] = '[Successfully processed output status]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Order Changed',
CAST(c.[Change timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(c.[Changed by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your purchase order change history table or view] c
ON c.[Client] = p.MANDT
AND c.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE c.[Change timestamp] >= s.start_ts
AND c.[Change timestamp] < s.end_ts
AND c.[Change indicator] = '[Changed indicator value]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Goods Receipt Posted',
CAST(g.[Goods movement timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(g.[Posted by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your goods movement source table or view] g
ON g.[Client] = p.MANDT
AND g.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE g.[Goods movement timestamp] >= s.start_ts
AND g.[Goods movement timestamp] < s.end_ts
AND g.[Movement type] IN ([Goods receipt movement types])
AND g.[Reversal indicator] IS NULL
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Services Confirmation Entered',
CAST(v.[Service entry timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(v.[Entered by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your service entry sheet source table or view] v
ON v.[Client] = p.MANDT
AND v.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE v.[Service entry timestamp] >= s.start_ts
AND v.[Service entry timestamp] < s.end_ts
AND v.[Service entry status] = '[Accepted service entry status]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Goods Returned',
CAST(g.[Goods movement timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(g.[Posted by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your goods movement source table or view] g
ON g.[Client] = p.MANDT
AND g.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE g.[Goods movement timestamp] >= s.start_ts
AND g.[Goods movement timestamp] < s.end_ts
AND g.[Movement type] IN ([Goods return movement types])
AND g.[Reversal indicator] IS NULL
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Invoice Received',
CAST(i.[Invoice posting timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(i.[Posted by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your supplier invoice source table or view] i
ON i.[Client] = p.MANDT
AND i.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE i.[Invoice posting timestamp] >= s.start_ts
AND i.[Invoice posting timestamp] < s.end_ts
AND i.[Invoice status] = '[Posted invoice status]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Invoice Paid',
CAST(i.[Clearing timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(i.[Cleared by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your supplier invoice clearing source table or view] i
ON i.[Client] = p.MANDT
AND i.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE i.[Clearing timestamp] >= s.start_ts
AND i.[Clearing timestamp] < s.end_ts
AND i.[Clearing status] = '[Cleared status value]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Order Completed',
CAST(x.[Completion timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(x.[Completion user] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your purchase order item status source table or view] x
ON x.[Client] = p.MANDT
AND x.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE x.[Completion timestamp] >= s.start_ts
AND x.[Completion timestamp] < s.end_ts
AND x.[Delivery completed indicator] = '[Set indicator value]'
AND x.[Final invoice indicator] = '[Set indicator value]'
UNION ALL
SELECT
p.PurchaseOrderNumber,
'Purchase Order Deleted',
CAST(d.[Deletion timestamp] AS TIMESTAMP),
s.source_system,
s.last_data_update,
p.VendorId,
CAST(d.[Deleted by] AS NVARCHAR(100)),
p.TotalNetAmount,
p.PurchaseRequisitionNumber,
p.RequestedDeliveryDate,
p.DocumentType
FROM po_base p
INNER JOIN [Your purchase order deletion history table or view] d
ON d.[Client] = p.MANDT
AND d.[Purchase order number] = p.PurchaseOrderNumber
CROSS JOIN params s
WHERE d.[Deletion timestamp] >= s.start_ts
AND d.[Deletion timestamp] < s.end_ts
AND d.[Deletion indicator] = '[Set deletion indicator value]'
)
SELECT
PurchaseOrderNumber,
ActivityName,
EventTime,
SourceSystem,
LastDataUpdate,
VendorId,
UserName,
TotalNetAmount,
PurchaseRequisitionNumber,
RequestedDeliveryDate,
DocumentType
FROM events
WHERE PurchaseOrderNumber IS NOT NULL
AND ActivityName IS NOT NULL
AND EventTime IS NOT NULL
ORDER BY PurchaseOrderNumber, EventTime, ActivityName; 단계
- 요구사항 및 설계: 필수 및 권장 속성을 포함해 이벤트 로그 파일의 최종 데이터 구조를 정의합니다. 필수 활동 13개 각각의 데이터를 가져오는 데 사용할 SAP 테이블(예: EKKO, EKPO, EKBE, CDHDR, CDPOS, BKPF)을 문서화합니다.
- 프로그램 생성: SAP GUI에서 트랜잭션 코드 SE38 또는 SE80을 사용해 ABAP 편집기로 이동합니다. 예를 들어 Z_PM_PO_EXTRACT라는 새 실행 프로그램을 만듭니다.
- 선택 화면 정의: 보고서의 선택 화면을 작성합니다. 사용자가 추출할 데이터를 필터링할 수 있도록 구매 오더 생성일 범위(P_AEDAT), 회사 코드(P_BUKRS), 구매 문서 유형(P_BSART) 매개변수를 포함합니다.
- 데이터 선언: 프로그램에 필요한 내부 테이블과 데이터 구조를 정의합니다. 여기에는 요구사항 단계에서 정의한 구조에 맞는 최종 이벤트 로그용 내부 테이블이 포함됩니다.
- 데이터 선택 로직 구현: 필수 활동 13개 각각의 데이터를 선택하는 ABAP 로직을 작성합니다. 필요한 경우 관련 SAP 테이블을 조인해 SELECT 문을 구성합니다. 변경 기반 이벤트는 변경 로그 테이블 CDHDR와 CDPOS에서 읽습니다.
- 데이터 변환 및 매핑: 가져온 각 레코드의 SAP 테이블 필드를 최종 이벤트 로그 내부 테이블의 해당 열에 매핑합니다. 처리 중인 이벤트에 따라 ActivityName을 설정합니다(예: 'Purchase Order Created'). 날짜와 시간 필드를 일관된 EventTime 타임스탬프 형식으로 변환합니다.
- 이벤트 데이터 통합: 활동 유형 13개를 모두 처리한 뒤 모든 데이터가 하나의 통합 내부 테이블에 모였는지 확인합니다. 이 테이블이 선택한 구매 오더의 전체 이벤트 로그가 됩니다.
- 파일 출력 구현: 최종 내부 테이블을 파일로 저장하는 기능을 추가합니다. 사용자가 파일을 로컬 컴퓨터에 CSV로 저장하도록 cl_gui_frontend_services=>gui_download 메서드를 사용하거나, 백그라운드 처리용으로 OPEN DATASET을 사용해 SAP 애플리케이션 서버에 저장하는 방법을 권장합니다.
- 트랜잭션 코드 생성(선택 사항): 업무 사용자가 프로그램에 쉽게 액세스할 수 있도록 트랜잭션 코드 SE93을 사용해 사용자 지정 트랜잭션 코드(예: ZPM_PO_EXTRACT)를 만들고 ABAP 프로그램을 실행하도록 설정합니다.
- 백그라운드 작업 예약: 데이터가 많거나 추출을 자동화하려면 트랜잭션 코드 SM36을 사용해 프로그램을 백그라운드 작업으로 예약합니다. 출력 파일은 프로그램 로직에 지정된 애플리케이션 서버 경로에 저장됩니다.
구성
- 선택 기준: 데이터를 효과적으로 필터링할 수 있도록 프로그램에 선택 매개변수를 포함해야 합니다. 주요 필터는 다음과 같습니다.
- 기간: 구매 오더 생성일(EKKO-AEDAT)의 기간을 필수로 지정합니다. 데이터 양과 보고서 성능을 관리하려면 3~6개월부터 시작하는 것이 좋습니다.
- 회사 코드(BUKRS): 법인이 여러 개인 조직에서 추출 범위를 좁히는 데 필요합니다.
- 구매 문서 유형(BSART): 표준 구매 오더, 기본 계약, 재고 운송 오더 등 특정 구매 오더 유형을 필터링해 분석 범위를 지정합니다.
- 변경 로그 읽기: 'Purchase Order Approved' 또는 'Purchase Order Changed'와 같은 활동을 추출하려면 SAP 변경 로그 테이블(CDHDR, CDPOS)을 읽어야 합니다. 이 작업은 리소스를 많이 사용할 수 있습니다. ABAP 로직에서 필요한 객체 클래스(EINKBELEG, BANF)와 테이블 및 필드 조합만 선택하도록 최적화해야 합니다.
- 권한: 보고서를 실행하는 사용자 또는 기술 계정에는 자재 관리(MM), 재무 회계(FI) 및 시스템 전반의 테이블을 포함해 여러 SAP 모듈에 걸친 광범위한 읽기 권한이 필요합니다. 대상 테이블에는 EKKO, EKPO, EBAN, EKBE, BKPF, BSAK, RBKP, NAST, CDHDR, CDPOS 등이 있습니다.
- 백그라운드 실행: 몇 개월을 초과하는 데이터를 추출하거나 트랜잭션이 많은 시스템에서 실행하는 경우, 대화형 프로세스 시간 초과를 방지하도록 프로그램을 항상 백그라운드에서 실행합니다.
샘플 쿼리 abap
REPORT z_pm_po_extract.
" ====================================================================
" SELECTION SCREEN
" ====================================================================
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
SELECT-OPTIONS: s_aedat FOR sy-datum OBLIGATORY.
SELECT-OPTIONS: s_bukrs FOR ekko-bukrs.
SELECT-OPTIONS: s_bsart FOR ekko-bsart.
PARAMETERS: p_sysid TYPE string DEFAULT '[Your SAP System ID]'.
SELECTION-SCREEN END OF BLOCK b1.
" ====================================================================
" DATA DECLARATIONS
" ====================================================================
TYPES: BEGIN OF ty_event_log,
purchaseordernumber TYPE ebeln,
activityname TYPE string,
eventtime TYPE timestamp,
sourcesystem TYPE string,
lastdataupdate TYPE timestamp,
vendorid TYPE lifnr,
username TYPE ernam,
totalnetamount TYPE netwr,
purchaserequisitionnumber TYPE banfn,
requesteddeliverydate TYPE eedat,
documenttype TYPE bsart,
END OF ty_event_log.
DATA: lt_event_log TYPE TABLE OF ty_event_log,
ls_event_log TYPE ty_event_log.
DATA: lt_ekko TYPE TABLE OF ekko,
lt_ekpo TYPE TABLE OF ekpo.
" ====================================================================
" START OF SELECTION
" ====================================================================
START-OF-SELECTION.
" Get current timestamp for LastDataUpdate
GET TIME STAMP FIELD ls_event_log-lastdataupdate.
ls_event_log-sourcesystem = p_sysid.
" --- Initial Data Selection: Purchase Orders in Scope ---
SELECT * FROM ekko INTO TABLE lt_ekko
WHERE aedat IN s_aedat
AND bukrs IN s_bukrs
AND bsart IN s_bsart.
IF lt_ekko IS INITIAL.
MESSAGE 'No Purchase Orders found for the given criteria.' TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
SELECT * FROM ekpo INTO TABLE lt_ekpo
FOR ALL ENTRIES IN lt_ekko
WHERE ebeln = lt_ekko-ebeln.
" --- 1. Purchase Requisition Created ---
SELECT ban.banfn, ban.erdat, ban.erzet, ban.ernam,
ekpo.ebeln, ekpo.netwr, ekpo.eindt, ekpo.bsart, ekpo.lifnr, ekko.bukrs
FROM eban AS ban
INNER JOIN ekpo AS ekpo ON ban.banfn = ekpo.banfn AND ban.bnfpo = ekpo.bnfpo
INNER JOIN ekko AS ekko ON ekpo.ebeln = ekko.ebeln
WHERE ekko.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_pr_created).
LOOP AT lt_pr_created INTO DATA(ls_pr_created).
ls_event_log-purchaseordernumber = ls_pr_created-ebeln.
ls_event_log-activityname = 'Purchase Requisition Created'.
CONVERT DATE ls_pr_created-erdat TIME ls_pr_created-erzet INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-vendorid = ls_pr_created-lifnr.
ls_event_log-username = ls_pr_created-ernam.
ls_event_log-totalnetamount = ls_pr_created-netwr.
ls_event_log-purchaserequisitionnumber = ls_pr_created-banfn.
ls_event_log-requesteddeliverydate = ls_pr_created-eindt.
ls_event_log-documenttype = ls_pr_created-bsart.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 2. Purchase Requisition Approved (via Change Docs on Release Indicator) ---
SELECT h.objectid, h.udate, h.utime, h.username
FROM cdhdr AS h
INNER JOIN cdpos AS p ON h.objectclas = p.objectclas AND h.objectid = p.objectid AND h.changenr = p.changenr
INNER JOIN ekpo AS ekpo ON h.objectid = ekpo.banfn
INNER JOIN ekko AS ekko ON ekpo.ebeln = ekko.ebeln
WHERE h.objectclas = 'BANF'
AND p.tabname = 'EBAN'
AND p.fname = 'FRGZU'
AND p.value_new = 'X' "Configure based on your system release indicator for 'Approved'
AND ekko.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_pr_approved).
LOOP AT lt_pr_approved INTO DATA(ls_pr_approved).
SELECT SINGLE ebeln FROM ekpo INTO ls_event_log-purchaseordernumber WHERE banfn = ls_pr_approved-objectid.
ls_event_log-activityname = 'Purchase Requisition Approved'.
CONVERT DATE ls_pr_approved-udate TIME ls_pr_approved-utime INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_pr_approved-username.
" Other attributes can be populated with another SELECT if needed.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 3. Purchase Order Created ---
LOOP AT lt_ekko INTO DATA(ls_ekko_created).
ls_event_log-purchaseordernumber = ls_ekko_created-ebeln.
ls_event_log-activityname = 'Purchase Order Created'.
CONVERT DATE ls_ekko_created-aedat TIME ls_ekko_created-erzet INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-vendorid = ls_ekko_created-lifnr.
ls_event_log-username = ls_ekko_created-ernam.
ls_event_log-totalnetamount = ls_ekko_created-rlwrt.
ls_event_log-purchaserequisitionnumber = ''. "Can be enriched later if needed
ls_event_log-requesteddeliverydate = ''. "Can be enriched from EKPO
ls_event_log-documenttype = ls_ekko_created-bsart.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 4. Purchase Order Approved (via Change Docs on Release Indicator) ---
SELECT h.objectid, h.udate, h.utime, h.username
FROM cdhdr AS h
INNER JOIN cdpos AS p ON h.objectclas = p.objectclas AND h.objectid = p.objectid AND h.changenr = p.changenr
WHERE h.objectclas = 'EINKBELEG'
AND p.tabname = 'EKKO'
AND p.fname = 'FRGKE'
AND p.value_new = 'R' "R for Released
AND h.objectid IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_po_approved).
LOOP AT lt_po_approved INTO DATA(ls_po_approved).
ls_event_log-purchaseordernumber = ls_po_approved-objectid.
ls_event_log-activityname = 'Purchase Order Approved'.
CONVERT DATE ls_po_approved-udate TIME ls_po_approved-utime INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_po_approved-username.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 5. Purchase Order Sent to Vendor ---
SELECT n.objky, n.vstat, n.datvr, n.uhrvr, e.ernam
FROM nast AS n
INNER JOIN ekko AS e ON n.objky = e.ebeln
WHERE n.kappl = 'EF' "Application for Purchasing
AND n.kschl = '[Your PO Output Type]' "e.g. NEU
AND n.vstat = '1' "Successfully processed
AND n.objky IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_po_sent).
LOOP AT lt_po_sent INTO DATA(ls_po_sent).
ls_event_log-purchaseordernumber = ls_po_sent-objky.
ls_event_log-activityname = 'Purchase Order Sent to Vendor'.
CONVERT DATE ls_po_sent-datvr TIME ls_po_sent-uhrvr INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_po_sent-ernam.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 6. Purchase Order Changed ---
SELECT objectid, udate, utime, username FROM cdhdr
WHERE objectclas = 'EINKBELEG'
AND tcode IN ('ME22', 'ME22N')
AND objectid IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_po_changed).
LOOP AT lt_po_changed INTO DATA(ls_po_changed).
ls_event_log-purchaseordernumber = ls_po_changed-objectid.
ls_event_log-activityname = 'Purchase Order Changed'.
CONVERT DATE ls_po_changed-udate TIME ls_po_changed-utime INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_po_changed-username.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 7. Goods Receipt Posted & 9. Goods Returned ---
SELECT e.ebeln, m.budat, m.cpudt, m.cputm, m.usnam, b.shkzg, b.bwart
FROM mkpf AS m
INNER JOIN mseg AS s ON m.mblnr = s.mblnr AND m.mjahr = s.mjahr
INNER JOIN t156 AS t ON s.bwart = t.bwart
INNER JOIN ekbe AS e ON s.ebeln = e.ebeln AND s.ebelp = e.ebelp AND s.mblnr = e.belnr AND s.mjahr = e.gjahr
WHERE e.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
AND e.bwart IN ('101', '102', '122', '123') "GR, GR Reversal, Return
INTO TABLE @DATA(lt_goods_mvmt).
LOOP AT lt_goods_mvmt INTO DATA(ls_goods_mvmt).
ls_event_log-purchaseordernumber = ls_goods_mvmt-ebeln.
IF ls_goods_mvmt-bwart = '101'.
ls_event_log-activityname = 'Goods Receipt Posted'.
ELSE.
ls_event_log-activityname = 'Goods Returned'.
ENDIF.
CONVERT DATE ls_goods_mvmt-cpudt TIME ls_goods_mvmt-cputm INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_goods_mvmt-usnam.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 8. Services Confirmation Entered ---
SELECT h.erdat, h.erzeit, h.ernam, l.ebeln
FROM essr AS h
INNER JOIN esll AS l ON h.lblni = l.lblni
WHERE l.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_services).
LOOP AT lt_services INTO DATA(ls_services).
ls_event_log-purchaseordernumber = ls_services-ebeln.
ls_event_log-activityname = 'Services Confirmation Entered'.
CONVERT DATE ls_services-erdat TIME ls_services-erzeit INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_services-ernam.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 10. Invoice Received ---
SELECT r.ebeln, r.cpudt, r.cputm, r.usnam
FROM rbkp AS r
WHERE r.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_invoice_rcvd).
LOOP AT lt_invoice_rcvd INTO DATA(ls_invoice_rcvd).
ls_event_log-purchaseordernumber = ls_invoice_rcvd-ebeln.
ls_event_log-activityname = 'Invoice Received'.
CONVERT DATE ls_invoice_rcvd-cpudt TIME ls_invoice_rcvd-cputm INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_invoice_rcvd-usnam.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 11. Invoice Paid ---
SELECT b.ebeln, s.augdt, s.augbl, b.usnam
FROM rbkp AS b
INNER JOIN bseg AS e ON b.belnr = e.belnr AND b.gjahr = e.gjahr
INNER JOIN bsak AS s ON e.bukrs = s.bukrs AND e.belnr = s.belnr AND e.gjahr = s.gjahr AND e.buzei = s.buzei
WHERE b.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
AND s.augdt IS NOT NULL
INTO TABLE @DATA(lt_invoice_paid).
LOOP AT lt_invoice_paid INTO DATA(ls_invoice_paid).
ls_event_log-purchaseordernumber = ls_invoice_paid-ebeln.
ls_event_log-activityname = 'Invoice Paid'.
CONVERT DATE ls_invoice_paid-augdt INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_invoice_paid-usnam.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- 12. Purchase Order Completed & 13. Purchase Order Deleted (via Change Docs) ---
SELECT h.objectid, h.udate, h.utime, h.username, p.fname
FROM cdhdr AS h
INNER JOIN cdpos AS p ON h.changenr = p.changenr
INNER JOIN ekpo AS ekpo ON h.objectid = |{ ekpo.ebeln }{ ekpo.ebelp }|
WHERE h.objectclas = 'EINKBELEG'
AND p.tabname = 'EKPO'
AND p.fname IN ('ELIKZ', 'EREKZ', 'LOEKZ')
AND p.value_new = 'X'
AND ekpo.ebeln IN @( VALUE #( FOR ls_ekko IN lt_ekko ( ls_ekko-ebeln ) ) )
INTO TABLE @DATA(lt_po_status_change).
LOOP AT lt_po_status_change INTO DATA(ls_po_status_change).
ls_event_log-purchaseordernumber = substring( val = ls_po_status_change-objectid, off = 0, len = 10 ).
CASE ls_po_status_change-fname.
WHEN 'LOEKZ'.
ls_event_log-activityname = 'Purchase Order Deleted'.
WHEN 'ELIKZ' OR 'EREKZ'.
"This logic may need refinement to check if both are now set.
ls_event_log-activityname = 'Purchase Order Completed'.
ENDCASE.
CONVERT DATE ls_po_status_change-udate TIME ls_po_status_change-utime INTO TIME STAMP ls_event_log-eventtime TIME ZONE sy-zonlo.
ls_event_log-username = ls_po_status_change-username.
APPEND ls_event_log TO lt_event_log.
ENDLOOP.
" --- Final Output to CSV ---
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = 'C:\temp\po_event_log.csv'
filetype = 'ASC'
CHANGING
data_tab = lt_event_log. 시작할 준비가 되셨나요?
이 템플릿을 바탕으로 process mining을 시작할 수 있습니다. SAP S/4HANA 데이터를 분석해 개선 기회를 찾고 구매부터 지급까지(P2P) 프로세스를 개선해 보세요.
P2P 구매 오더 프로세스 개선, 처리 주기를 단축하세요
비효율을 줄여 P2P 구매 오더 처리 주기를 30% 단축하세요.
신용카드가 필요하지 않습니다. 몇 분이면 설정을 마칠 수 있습니다.