欢迎来到萧静默的博客

书山有路勤为径,学海无涯苦作舟。

SAP采购订单数据获取

最近要配合公司AI做一个采购订单信息获取。

1、根据条件获取采购订单基本信息。

2、得到最早交易记录和最晚交易记录。

3、得出平均含税单价。

4、得出总交易条数。

AI的模型输入因为是不确定的,可能单个问,多个问,各种问,目前定义了采购订单、供应商、物料、日期等维度,这里将传入的参数设为表结构,将表里的内容放到range的low字段,如果为空的,要清空。

DATA: LR_EBELN TYPE RANGE OF EBELN. " 范围内表:存储单值对应的范围
    DATA: LR_BSART TYPE RANGE OF BSART. " 范围内表:存储单值对应的范围
    DATA: LR_EKORG TYPE RANGE OF EKORG. " 范围内表:存储单值对应的范围
    DATA: LR_BUKRS TYPE RANGE OF BUKRS. " 范围内表:存储单值对应的范围
    DATA: LR_LIFNR TYPE RANGE OF LIFNR. " 范围内表:存储单值对应的范围
    DATA: LR_MATNR TYPE RANGE OF MATNR. " 范围内表:存储单值对应的范围
    DATA: LR_DATE TYPE RANGE OF BEDAT. " 开始日期范围内表:存储单值对应的范围

    IF INPUT-MT_GET_PURINFO_REQ IS NOT INITIAL.
      IF INPUT-MT_GET_PURINFO_REQ-EBELN_REQ IS NOT INITIAL.
        LOOP AT INPUT-MT_GET_PURINFO_REQ-EBELN_REQ INTO DATA(LS_EBELN).
          LR_EBELN = VALUE #( BASE LR_EBELN    ( SIGN = 'I' OPTION = 'EQ' LOW = LS_EBELN-EBELN HIGH = '' )  ).
        ENDLOOP.
        SORT LR_EBELN BY LOW. " 可选:排序去重以优化性能
        DELETE ADJACENT DUPLICATES FROM LR_EBELN COMPARING LOW.
        DELETE LR_EBELN WHERE LOW = ''.
      ELSE.
        CLEAR LR_EBELN[]."这个很关键,如果没有值,要清空,才能算没有条件
      ENDIF.

      IF INPUT-MT_GET_PURINFO_REQ-BSART_REQ IS NOT INITIAL.
        LOOP AT INPUT-MT_GET_PURINFO_REQ-BSART_REQ INTO DATA(LS_BSART).
          LR_BSART = VALUE #( BASE LR_BSART    ( SIGN = 'I' OPTION = 'EQ' LOW = LS_BSART-BSART HIGH = '' )  ).
        ENDLOOP.
        SORT LR_BSART BY LOW. " 可选:排序去重以优化性能
        DELETE ADJACENT DUPLICATES FROM LR_BSART COMPARING LOW.
        DELETE LR_BSART WHERE LOW = ''.
      ELSE.
        CLEAR LR_EBELN[].
      ENDIF.

      IF INPUT-MT_GET_PURINFO_REQ-EKORG_REQ IS NOT INITIAL.
        LOOP AT INPUT-MT_GET_PURINFO_REQ-EKORG_REQ INTO DATA(LS_EKORG).
          LR_EKORG = VALUE #( BASE LR_EKORG    ( SIGN = 'I' OPTION = 'EQ' LOW = LS_EKORG-EKORG HIGH = '' )  ).
        ENDLOOP.
        SORT LR_EKORG BY LOW. " 可选:排序去重以优化性能
        DELETE ADJACENT DUPLICATES FROM LR_EKORG COMPARING LOW.
        DELETE LR_EKORG WHERE LOW = ''.
      ELSE.
        CLEAR LR_EKORG[].
      ENDIF.

      IF INPUT-MT_GET_PURINFO_REQ-BUKRS_REQ IS NOT INITIAL.
        LOOP AT INPUT-MT_GET_PURINFO_REQ-BUKRS_REQ INTO DATA(LS_BUKRS).
          LR_BUKRS = VALUE #( BASE LR_BUKRS    ( SIGN = 'I' OPTION = 'EQ' LOW = LS_BUKRS-BUKRS HIGH = '' )  ).
        ENDLOOP.
        SORT LR_BUKRS BY LOW. " 可选:排序去重以优化性能
        DELETE ADJACENT DUPLICATES FROM LR_BUKRS COMPARING LOW.
        DELETE LR_BUKRS WHERE LOW = ''.
      ELSE.
        CLEAR LR_BUKRS[].
      ENDIF.

      IF INPUT-MT_GET_PURINFO_REQ-LIFNR_REQ IS NOT INITIAL.
        LOOP AT INPUT-MT_GET_PURINFO_REQ-LIFNR_REQ INTO DATA(LS_LIFNR).
          LIFNR = LS_LIFNR-LIFNR .
          LIFNR = |{ LIFNR ALPHA = IN }|.
          LR_LIFNR = VALUE #( BASE LR_LIFNR    ( SIGN = 'I' OPTION = 'EQ' LOW = LIFNR HIGH = '' )  ).
        ENDLOOP.
        SORT LR_LIFNR BY LOW. " 可选:排序去重以优化性能
        DELETE ADJACENT DUPLICATES FROM LR_LIFNR COMPARING LOW.
        DELETE LR_LIFNR WHERE LOW = ''.
      ELSE.
        CLEAR LR_LIFNR[].
      ENDIF.

      IF INPUT-MT_GET_PURINFO_REQ-MATNR_REQ IS NOT INITIAL.
        LOOP AT INPUT-MT_GET_PURINFO_REQ-MATNR_REQ INTO DATA(LS_MATNR).
          MATNR = LS_MATNR-MATNR.
          MATNR = |{ MATNR ALPHA = IN WIDTH = 18 }|.
          LR_MATNR = VALUE #( BASE LR_MATNR    ( SIGN = 'I' OPTION = 'EQ' LOW = MATNR HIGH = '' )  ).
        ENDLOOP.
        SORT LR_MATNR BY LOW. " 可选:排序去重以优化性能
        DELETE ADJACENT DUPLICATES FROM LR_MATNR COMPARING LOW.
        DELETE LR_MATNR WHERE LOW = ''.
      ELSE.
        CLEAR LR_MATNR[].
      ENDIF.
      "起始日期为2000年,终止日期为9999年
      IF INPUT-MT_GET_PURINFO_REQ-FDATE IS INITIAL AND INPUT-MT_GET_PURINFO_REQ-EDATE IS NOT INITIAL.
        LR_DATE = VALUE #( BASE LR_DATE    ( SIGN = 'I' OPTION = 'BT' LOW = '20000000' HIGH = INPUT-MT_GET_PURINFO_REQ-EDATE )  ).
      ELSEIF INPUT-MT_GET_PURINFO_REQ-FDATE IS NOT INITIAL AND INPUT-MT_GET_PURINFO_REQ-EDATE IS  INITIAL.
        LR_DATE = VALUE #( BASE LR_DATE    ( SIGN = 'I' OPTION = 'BT' LOW = INPUT-MT_GET_PURINFO_REQ-FDATE HIGH = '99999999' )  ).
      ELSEIF INPUT-MT_GET_PURINFO_REQ-FDATE IS INITIAL AND INPUT-MT_GET_PURINFO_REQ-EDATE IS  INITIAL.
        LR_DATE = VALUE #( BASE LR_DATE    ( SIGN = 'I' OPTION = 'BT' LOW = '20000000' HIGH = '99999999' )  ).
      ELSEIF INPUT-MT_GET_PURINFO_REQ-FDATE IS NOT INITIAL AND INPUT-MT_GET_PURINFO_REQ-EDATE IS NOT INITIAL.
        LR_DATE = VALUE #( BASE LR_DATE    ( SIGN = 'I' OPTION = 'BT' LOW = INPUT-MT_GET_PURINFO_REQ-FDATE HIGH = INPUT-MT_GET_PURINFO_REQ-EDATE   )  ).
      ENDIF.

获取采购订单数据

SELECT EKPO~EBELN,
         EKPO~EBELP,
         EKKO~BUKRS,
         T001~BUTXT,
         EKKO~EKORG,
         T024E~EKOTX,
         EKKO~BSART,
         EKKO~LIFNR,
         LFA1~NAME1,
         EKKO~BEDAT,
         EKPO~MATNR,
         MAKT~MAKTX,
         EKPO~MENGE,
         EKPO~MEINS,
         EKPO~PEINH,
         EKPO~NETWR AS SUMPRICE_NO_TAX,"未税总值
         EKPO~BRTWR AS SUMPRICE_TAX, "含税总值
         EKPO~MWSKZ,
*         EKPO~EBELP AS ZTAX,
         EKKO~WAERS,
        CASE WHEN EKPO~PEINH = 0 THEN 0
         ELSE DIVISION( EKPO~NETPR ,EKPO~PEINH,3 ) END AS UNPRICE_NO_TAX, "未税单价
        CASE WHEN EKPO~MENGE = 0 THEN 0
         ELSE DIVISION( EKPO~BRTWR ,EKPO~MENGE,3 ) END AS UNPRICE_TAX,"总金额除以数量=含税单价
         EKKO~LANDS
    FROM EKPO
    INNER JOIN EKKO ON EKKO~EBELN = EKPO~EBELN
    LEFT JOIN MAKT ON MAKT~MATNR = EKPO~MATNR
    LEFT JOIN T024E ON T024E~EKORG = EKKO~EKORG
    LEFT JOIN LFA1 ON LFA1~LIFNR = EKKO~LIFNR
    LEFT JOIN T001 ON T001~BUKRS = EKKO~BUKRS

    WHERE EKKO~EBELN IN @LR_EBELN
          AND  EKKO~BSART IN @LR_BSART
          AND  EKKO~EKORG IN @LR_EKORG
          AND  EKKO~BUKRS IN @LR_BUKRS
          AND  EKKO~LIFNR IN @LR_LIFNR
          AND  EKPO~MATNR IN @LR_MATNR
          AND EKKO~BEDAT IN @LR_DATE
          AND EKPO~LOEKZ <> 'X'           " 排除已删除项目
       INTO CORRESPONDING FIELDS OF TABLE @T_PURINFO.

T_PURINFO这个表建个结构或者直接@data都可以

获取最早最晚平均价,这里使用了新语法

IF T_PURINFO IS NOT INITIAL.
        "1. 全局最早/最晚日期(不区分物料)
        DATA(LV_MIN_DATE) = REDUCE D( INIT MIN = CONV d( '99991231' ) FOR WA IN T_PURINFO NEXT MIN = NMIN( VAL1 = MIN VAL2 = WA-BEDAT ) ).
        DATA(LV_MAX_DATE) = REDUCE D( INIT MAX = CONV d( '00000000' ) FOR WA IN T_PURINFO NEXT MAX = NMAX( VAL1 = MAX VAL2 = WA-BEDAT ) ).

        LOOP AT T_PURINFO INTO DATA(LS_PURINFO).
          "标记最早最晚行
          LS_PURINFO-EARLIESTTXN = COND #( WHEN LS_PURINFO-BEDAT = LV_MIN_DATE THEN '1' ELSE '' ).
          LS_PURINFO-LATESTTXN = COND #( WHEN LS_PURINFO-BEDAT = LV_MAX_DATE THEN '9' ELSE '' ).

          "取税率及含税价
          SELECT SINGLE KNUMH INTO @DATA(LS_KNUMH) FROM A003 WHERE MWSKZ = @LS_PURINFO-MWSKZ AND ALAND = @LS_PURINFO-LANDS.
          SELECT SINGLE KBETR INTO @DATA(LS_KBETR) FROM KONP WHERE KNUMH = @LS_KNUMH.
          LS_PURINFO-ZTAX = LS_KBETR / 1000.
          IF LS_PURINFO-EKORG = '1010' OR LS_PURINFO-EKORG = '1011' OR LS_PURINFO-EKORG = '1020' OR LS_PURINFO-EKORG = '1030'.
            "含税单价
            LS_PURINFO-UNPRICE_TAX = LS_PURINFO-UNPRICE_NO_TAX * ( 1 +  LS_KBETR / 1000 ).
            "含税总金额
            LS_PURINFO-SUMPRICE_TAX = LS_PURINFO-SUMPRICE_NO_TAX * ( 1 +  LS_KBETR / 1000 ).
          ENDIF.
          MODIFY T_PURINFO FROM LS_PURINFO.
          CLEAR:LS_PURINFO,LS_KNUMH,LS_KBETR.
        ENDLOOP.
        "取行数
        DESCRIBE TABLE T_PURINFO LINES DATA(LV_LINE).
        "取平均价表
        T_PURINFO_MAL = CORRESPONDING #( T_PURINFO ).
        DELETE T_PURINFO_MAL WHERE MATNR IS INITIAL.
        SORT T_PURINFO_MAL BY MATNR.
        " 使用 FOR GROUPS 按物料分组,累加单价并计数
        LT_AVG_PRICE = VALUE #(
          FOR GROUPS GRP_MATNR  OF <WA> IN T_PURINFO_MAL  " 分组标识改为 grp_matnr(避免冲突)
          GROUP BY <WA>-MATNR                             " 按内表字段 matnr 分组(明确引用字段)
          ( MATNR1     = GRP_MATNR                        " 用分组标识赋值(对应当前组的 matnr 值)
            AVGPRICE = REDUCE BWERT( INIT P = 0
                                       FOR <LINE> IN GROUP GRP_MATNR   " 引用修改后的分组标识
                                       NEXT P = P + <LINE>-UNPRICE_TAX )  " 累加单价
            COUNT     = REDUCE I( INIT C = 0
                                  FOR <LINE> IN GROUP GRP_MATNR
                                  NEXT C = C + 1 )                  " 统计行数
          )
        ).

        " 计算平均值
        LOOP AT LT_AVG_PRICE ASSIGNING FIELD-SYMBOL(<AVG>).
          IF <AVG>-COUNT > 0.
*          <AVG>-AVG_PRICE = <AVG>-AVG_PRICE / <AVG>-COUNT.
            APPEND VALUE #( MATNR1    = <AVG>-MATNR1
                    AVGPRICE = <AVG>-AVGPRICE / <AVG>-COUNT )
           TO OUTPUT-MT_GET_PURINFO_RES-AVGDATA.
          ELSE.
            APPEND VALUE #( MATNR1    = <AVG>-MATNR1
                     AVGPRICE = 0 )
            TO OUTPUT-MT_GET_PURINFO_RES-AVGDATA.
          ENDIF.
        ENDLOOP.



        OUTPUT-MT_GET_PURINFO_RES-E_SUCC = 'S'.
        OUTPUT-MT_GET_PURINFO_RES-TOTALCOUNT = LV_LINE.
        OUTPUT-MT_GET_PURINFO_RES-E_MESSAGE = '成功查到数据!'.
        OUTPUT-MT_GET_PURINFO_RES-DATA_RES = CORRESPONDING #( T_PURINFO ).

取最小最大日期的语法解释

各部分作用:

    1. REDUCE #( ... )
      函数式操作符,用于通过遍历集合(内表T_PURINFO)计算单个结果(最小日期)。#表示自动推导结果类型(此处为日期类型D),这里用了显示REDUCE D和CONV d。
    2. INIT MIN = CONV d'99991231' )
      初始化累加变量min,赋值为最大可能的日期(9999 年 12 月 31 日),确保后续第一次比较时,内表中的日期会被正确选中。
    3. FOR WA IN T_PURINFO
      遍历内表T_PURINFO,wa为当前行工作区。
    4. NEXT MIN = NMIN( VAL1 MIN VAL2 = WA-BEDAT )
      每次迭代的计算逻辑:nmin函数返回两个值中的较小者,用当前行的buy_datemin比较,更新min为更小的日期。

取平均价的语法解释

1. 整体结构:lt_avg_price = VALUE #( ... )

  • VALUE #() 是 ABAP 的内表构建表达式,用于动态创建并填充内表lt_avg_price
  • # 表示自动推导内表类型(需与lt_avg_price的结构匹配,至少包含matnravg_pricecount三个字段)。

2. 分组逻辑:FOR GROUPS GRP_MATNR  OF <WA> IN T_PURINFO_MAL  GROUP BY <WA>-MATNR   

  • 这是核心的分组操作,作用是将原始内表lt_purchase按物料号(matnr)拆分成多个小组:
    • lt_purchase:原始采购数据内表(包含物料号matnr、单价price等字段)。
    • <wa>:遍历lt_purchase时的临时行工作区。
    • GROUP BY matnr:指定分组关键字为matnr(即相同物料号的行被归为同一组)。
    • GROUPS GRP_MATNR :为每个分组定义一个标识matnr(方便后续引用该分组)。

3. 分组内的字段计算

每个分组会生成lt_avg_price中的一行记录,包含 3 个字段:
    • matnr = matnr
      直接取当前分组的物料号(即分组关键字的值),作为结果表的物料标识。
    • avg_price = REDUCE BWERT( ... )
      计算当前分组内的 **“总单价”**:
      • REDUCE BWERT( ... ):函数式操作符,用于累加计算单个结果(类型为BWERT,即单价类型)。
      • INIT p = 0:初始化累加器p为 0。
      • FOR <line> IN GROUP GRP_MATNR:遍历当前名为matnr的分组内的每一行(<line>为分组内的行工作区)。
      • NEXT p = p + <line>-UNPRICE_TAX:每次迭代将分组内当前行的price(单价)累加到p中,最终p为该物料所有行的 “总单价”。
    • count = REDUCE i( ... )
      计算当前分组内的 **“购买次数”**(即该物料在lt_purchase中的总行数):
      • REDUCE i( ... ):累加计算整数结果(类型为i,整数)。
      • INIT c = 0:初始化计数器c为 0。
      • FOR <line> IN GROUP GRP_MATNR:遍历当前分组内的每一行。
      • NEXT c = c + 1:每次迭代计数器c加 1,最终c为该物料的总行数(购买次数)。

PO输入参数

image

 PO输出参数

image

 

posted @ 2025-09-17 14:15  萧静默  阅读(160)  评论(0)    收藏  举报