실제로 SAP 유지보수를 하다면 과거 재고를 알고 싶어 하는 니즈가 많습니다.
여러분들도 한번쯤은 요청을 받은 내용일 것이라 생각합니다.
이런 요구사항이 있을때는 제일 먼저 이야기 하는것인 MB5B가 있습니다. 스탠다드 프로그램이죠~
이것을 소개해 드리면 "이미 이런것이 있었군요. 라고 하며 확인 해 보겠다고 합니다."
하지만 십중팔구는 "좋긴한데요... 제가 원하는것과는 잘 안맞는것 같아요." 라고 답변이 옵니다.
물론 MB5B 좋은 레포트긴 하지만 아마도 활용도는 떨어집니다.
말이 길었지만 아래와 같은 이야기를 많이 할것입니다.
- '기초 재고'의 의미: MB5B의 '기초 재고(Opening Stock)'는 조회 시작일의 00:00시 재고가 아니라, 전일 마감 재고를 의미합니다. 예를 들어 7월 5일을 조회 시작일로 지정하면, 리포트의 기초 재고는 7월 4일 마감 시점의 재고입니다.
- 배치(Batch) 재고의 한계: 배치 관리 품목의 경우, 과거 시점의 특정 배치 번호 재고를 정확히 추적하기 어렵습니다.
- 특수 재고(Special Stock) 조회: 공급업체 위탁 재고(Consignment Stock), 프로젝트 재고(Project Stock) 등 특수 재고 유형을 선택해서 조회할 수 있지만, 복잡한 이동 거래가 얽혀 있는 경우 데이터의 정확성이 떨어지거나 사용자가 의도한 결과와 다를 수 있습니다.
- 사용하기 불편한점, 원하는 것만 보여야 하는데 조회 조건부터 복잡합니다.
그래서 이번 내용은 CBO개발을 해 보겠습니다.
먼저, ABAP Development Tools (ADT) for Eclipse를 사용하여 CDS 뷰를 만드는 방법입니다.
1. 새 데이터 정의(DDL) 파일 생성
- 왼쪽 Project Explorer 뷰에서 CDS 뷰를 생성할 패키지(Package)를 찾으세요.
- 해당 패키지에 마우스 오른쪽 버튼을 클릭한 후, [ New → Other ABAP Repository Object ] 를 선택합니다.
- Core Data Services 폴더를 열고 [ Data Definition ]을 선택한 후 Next를 클릭합니다.
- Name(CDS 뷰 이름, ZCDS_Material_Stock)과 Description(시점별 재고)을 입력하고 Finish를 클릭합니다.
템플릿 코드가 자동으로 생성됩니다.
2. CDS 뷰 코드 작성
- 핵심 Annotation 추가:
- @AbapCatalog.sqlViewName: SAP 시스템 내부(SE11)에서 사용할 SQL 뷰 이름을 지정합니다. (필수)
- @AbapCatalog.compiler.compareFilter: true: CDS 뷰와 ABAP 프로그램 간의 필터 조건 일치 여부를 컴파일러가 확인합니다
- @AbapCatalog.preserveKey: true: CDS 뷰의 키 필드 속성을 유지하고 전파합니다.
- @AccessControl.authorizationCheck: #NOT_REQUIRED: 이 뷰에 접근할 때 자동 권한 체크를 하지 않습니다.
- @EndUserText.label: '시점별 재고': 사용자에게 보이는 CDS 뷰의 이름입니다.
- @Metadata.ignorePropagatedAnnotations: true: 하위 객체에서 자동으로 전파되는 메타데이터 어노테이션을 무시합니다.
- 뷰 정의 (DEFINE VIEW):
- DEFINE VIEW [뷰 이름] AS SELECT FROM [데이터 소스]: 어떤 뷰를 만들지, 그리고 어떤 테이블이나 다른 CDS 뷰를 조회할지 정의합니다.
- 필드 목록 작성:
- { } 안에 가져올 필드들을 쉼표(,)로 구분하여 나열합니다.
- AS 키워드를 사용해 필드의 별칭(Alias)을 지정할 수 있습니다.
- CDS View
@AbapCatalog.sqlViewName: 'Z_V_MAT_STOCK'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '시점별 재고'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.representativeKey: 'Material'
DEFINE VIEW ZCDS_MATERIAL_STOCK
WITH PARAMETERS
P_KeyDate : abap.dats, // 기준일 파라미터
P_Language: spras // 언어 키 파라미터
AS SELECT FROM C_MaterialStockAtPostingDate(P_KeyDate: $parameters.P_KeyDate) AS Stock
-- 자재 기본 정보 연결
ASSOCIATION [1..1] TO I_Material AS _Material ON $projection.Material = _Material.Material
-- 자재 텍스트(내역) 연결
ASSOCIATION [0..1] TO I_MaterialText AS _MaterialText ON $projection.Material = _MaterialText.Material
AND _MaterialText.Language = $parameters.P_Language
-- 자재 평가(단가) 정보 연결
ASSOCIATION [0..1] TO I_MaterialValuation AS _Valuation ON $projection.Material = _Valuation.Material
AND $projection.Plant = _Valuation.ValuationArea
{
key Stock.Material,
key Stock.Plant,
key Stock.StorageLocation,
key Stock.Batch,
_Material.OldMaterialNumber,
_MaterialText.MaterialName,
Stock.StockQuantity,
_Valuation.MovingAveragePrice,
CAST(Stock.StockQuantity * _Valuation.MovingAveragePrice AS abap.curr(15,2)) AS StockValue,
_Valuation.Currency,
cast('' as lgpla) as StorageBin,
cast('' as char30) as BatchCharacteristic
}
WHERE Stock.StockQuantity <> 0
스탠다드로 제공되는 CDS뷰를 활용해서 만들어놨습니다.
3. ALV 리포트 프로그램 개발 (ABAP Source Code)
레포트에 코드로 대신하겠습니다.
*&---------------------------------------------------------------------*
*& Report Z_HISTORICAL_STOCK
*& @description 시점별 재고 조회
*&---------------------------------------------------------------------*
REPORT z_historical_stock.
*--- 조회 조건 정의 (Selection Screen) ---*
PARAMETERS:
p_keydt TYPE datum OBLIGATORY. "기준일
SELECT-OPTIONS:
s_werks FOR z_i_historical_stock-Plant OBLIGATORY, "플랜트
s_matnr FOR z_i_historical_stock-Material, "자재번호
s_lgort FOR z_i_historical_stock-StorageLocation, "저장위치
s_batch FOR z_i_historical_stock-Batch. "배치번호 (수정)
*--- 메인 로직 시작 ---*
START-OF-SELECTION.
" 1. 조회 조건 확인
IF p_keydt IS INITIAL OR s_werks IS INITIAL.
MESSAGE '기준일과 플랜트는 필수 입력 항목입니다.' TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
" 2. CDS 뷰에서 데이터 조회
SELECT *
FROM ZCDS_MATERIAL_STOCK( p_keydate = @p_keydt, p_language = @sy-langu )
WHERE
Plant IN @s_werks AND
Material IN @s_matnr AND
StorageLocation IN @s_lgort AND
Batch IN @s_batch " WHERE 조건에 배치번호 추가
INTO TABLE @DATA(lt_stock_data).
" 3. 조회 결과 확인 및 ALV 출력
IF lt_stock_data IS INITIAL.
MESSAGE '조회된 데이터가 없습니다.' TYPE 'S'.
RETURN.
ENDIF.
TRY.
" ALV 객체 생성 및 데이터 전달
cl_salv_table=>factory(
IMPORTING
r_salv_table = DATA(lo_alv)
CHANGING
t_table = lt_stock_data ).
" ALV 기능 설정
DATA(lo_functions) = lo_alv->get_functions( ).
lo_functions->set_all( abap_true ).
" ALV 컬럼 헤더 텍스트 최적화
DATA(lo_columns) = lo_alv->get_columns( ).
lo_columns->set_optimize( abap_true ).
" ALV 화면에 출력
lo_alv->display( ).
CATCH cx_salv_msg INTO DATA(lx_salv_msg).
MESSAGE lx_salv_msg->get_text( ) TYPE 'E'.
ENDTRY.
아마 사용중인 HANA 라도 버전에 따라 제공되고 안되는 CDS View가 존재합니다.
위에 사용한 뷰가 없다면 만들어서 사용하면 됩니다.
코드만 간단히 소개 해 드릴겠습니다.
사용 할려는 뷰에 필드가 없거나 맞지 않아서 Z_I_MBEWDATA, Z_I_PLANTCURRENCY 2개를 만들어서 조합했습니다.
@AbapCatalog.sqlViewName: 'Z_V_MAT_STOCK'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '시점별 재고'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.representativeKey: 'Material'
define view ZCDS_MATERIAL_STOCK
with parameters
P_KeyDate : abap.dats,
P_Language: spras
as select from ZCDS_MATERIAL_STOCK_TF( P_Client: $session.client, P_KeyDate: $parameters.P_KeyDate ) as Stock
association [0..1] to I_MaterialText as _MaterialText on $projection.Material = _MaterialText.Material
and _MaterialText.Language = $parameters.P_Language
association [0..1] to mara as _Mara on $projection.Material = _Mara.matnr
association [0..1] to Z_I_MbewData as _MbewData on $projection.Material = _MbewData.matnr
and $projection.Plant = _MbewData.bwkey
association [0..1] to Z_I_PlantCurrency as _CurrencyInfo on $projection.Plant = _CurrencyInfo.Plant
{
key Stock.Material,
key Stock.Plant,
key Stock.StorageLocation,
key Stock.Batch,
_Mara.meins as MaterialBaseUnit,
_CurrencyInfo.Currency,
_Mara.bismt as OldMaterialNumber,
_MaterialText.MaterialName,
@Semantics.quantity.unitOfMeasure: 'MaterialBaseUnit'
Stock.StockQuantity,
@Semantics.amount.currencyCode: 'Currency'
_MbewData.verpr as MovingAveragePrice,
@Semantics.amount.currencyCode: 'Currency'
(Stock.StockQuantity * _MbewData.verpr) as StockValue,
cast('' as lgpla) as StorageBin,
cast('' as char30) as BatchCharacteristic
}
where Stock.StockQuantity <> 0
Z_I_MBEWDATA, Z_I_PLANTCURRENCY
@AbapCatalog.sqlViewName: 'Z_V_MBEW_DATA'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'MBEW 필드 조회용'
define view Z_I_MbewData as select from mbew {
// 키 필드
key matnr, // 자재번호
key bwkey, // 평가 영역 (플랜트)
// 필요한 데이터 필드
verpr // 이동 평균 단가
}
@AbapCatalog.sqlViewName: 'Z_V_PLANT_CURR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '플랜트-통화 매핑 뷰'
define view Z_I_PlantCurrency as select from t001k
association [0..1] to t001 as _CompanyCode on t001k.bukrs = _CompanyCode.bukrs
{
key t001k.bwkey as Plant,
_CompanyCode.waers as Currency
}
나중에 CDS뷰를 활용하는 법과 생성하는 법을 따로 올리겠습니다.
감사합니다.
'ABAP' 카테고리의 다른 글
[ABAP] 출력 제어(Output Control) - Inbound Delivery 및 Invoice 생성하기 (0) | 2025.07.10 |
---|---|
[ABAP] Part 2 - 시점별 재고 ( 전통적인ABAP + ALV 리포트) (0) | 2025.07.05 |
[ABAP] 표준 자재 검색(F4)에 나만의 탭 추가하기 (Append Search Help) (0) | 2025.07.02 |
[ABAP] 재고는 있는데 재고 부족? BAPI 이슈 해결 (0) | 2025.06.29 |
[ABAP] 엑셀로 구매정보레코드(Info Record) 대량 생성/변경 (0) | 2025.06.29 |