Emre Göçmen Blog

SAP ABAP'den Claude AI Entegrasyonu: Akıllı Üretim Raporu Oluşturma

5 dk. okuma
413 görüntülenme
0 yorum

Emre Göçmen

Yazar

SAP ABAP'den Claude AI Entegrasyonu: Akıllı Üretim Raporu Oluşturma

SAP üretim verilerini analiz edip yöneticilere otomatik rapor göndermek yaygın bir ihtiyaçtır. Bu yazıda, üretim verilerini Claude API ile analiz eden ve sonuçları mail olarak ileten tam bir ABAP uygulaması geliştireceğiz.

Uygulamamız dört ana sınıftan oluşacak:

  • lcl_production_data: Üretim verilerini toplar ve özetler

  • lcl_claude_api: Claude API ile iletişim kurar

  • lcl_mail_sender: Mail gönderimini yönetir

  • lcl_application: Tüm süreci koordine eder

Şimdi adım adım ilerleyelim.

Adım 1: Program Tanımı ve Tip Bildirimleri

İlk olarak programımızı tanımlıyor ve ihtiyaç duyacağımız veri tiplerini oluşturuyoruz. Üretim verileri, özet bilgileri ve API yanıtı için ayrı yapılar tanımlıyoruz.

*&---------------------------------------------------------------------*
*& Report ZPP_PRODUCTION_AI_REPORT
*&---------------------------------------------------------------------*
*& Üretim verilerini Claude API ile analiz eder ve mail gönderir
*&---------------------------------------------------------------------*
REPORT zpp_production_ai_report.


*----------------------------------------------------------------------*
* Tip Tanımlamaları
*----------------------------------------------------------------------*
TYPES:
  BEGIN OF gty_production,
    aufnr     TYPE aufnr,
    matnr     TYPE matnr,
    maktx     TYPE maktx,
    werks     TYPE werks_d,
    gamng     TYPE gamng,
    gmein     TYPE meins,
    budat     TYPE budat,
    lmnga     TYPE lmnga,
    xmnga     TYPE xmnga,
    rmnga     TYPE rmnga,
  END OF gty_production,

  gty_t_production TYPE STANDARD TABLE OF gty_production WITH EMPTY KEY,

  BEGIN OF gty_summary,
    budat        TYPE budat,
    plan_qty     TYPE gamng,
    actual_qty   TYPE lmnga,
    scrap_qty    TYPE xmnga,
    rework_qty   TYPE rmnga,
    efficiency   TYPE decfloat16,
    scrap_rate   TYPE decfloat16,
  END OF gty_summary,

  gty_t_summary TYPE STANDARD TABLE OF gty_summary WITH EMPTY KEY,

  BEGIN OF gty_content,
    type TYPE string,
    text TYPE string,
  END OF gty_content,

  gty_t_content TYPE STANDARD TABLE OF gty_content WITH EMPTY KEY,

  BEGIN OF gty_api_response,
    id          TYPE string,
    type        TYPE string,
    model       TYPE string,
    role        TYPE string,
    content     TYPE gty_t_content,
    stop_reason TYPE string,
  END OF gty_api_response.

gty_production: AFKO, AFPO ve AFRU tablolarından çekeceğimiz ham üretim verileri için kullanılır. Üretim emri numarası, malzeme, planlanan miktar, gerçekleşen miktar, fire ve yeniden işleme miktarlarını içerir.

gty_summary: Günlük bazda hesaplanacak özet verileri tutar. Verimlilik ve fire oranı bu yapıda hesaplanır.

gty_api_response: Claude API'den dönen JSON yanıtını parse etmek için kullanılır. API yanıtındaki content dizisi içinde text alanını okuyacağız.

Adım 2: Üretim Veri Sınıfı

Bu sınıf, SAP'den üretim verilerini çeker ve günlük bazda özet hesaplar. Constructor'da tarih aralığı alır ve hemen veri çekme ile özet hesaplama işlemlerini başlatır.

*----------------------------------------------------------------------*
* Üretim Veri Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_production_data DEFINITION FINAL.

  PUBLIC SECTION.

    METHODS constructor
      IMPORTING
        iv_date_from TYPE datum
        iv_date_to   TYPE datum.

    METHODS get_data
      RETURNING VALUE(rt_data) TYPE gty_t_production.

    METHODS get_summary
      RETURNING VALUE(rt_summary) TYPE gty_t_summary.

  PRIVATE SECTION.

    DATA mv_date_from TYPE datum.
    DATA mv_date_to   TYPE datum.
    DATA mt_data      TYPE gty_t_production.
    DATA mt_summary   TYPE gty_t_summary.

    METHODS select_data.
    METHODS calculate_summary.

ENDCLASS.


CLASS lcl_production_data IMPLEMENTATION.

  METHOD constructor.
    mv_date_from = iv_date_from.
    mv_date_to   = iv_date_to.
    select_data( ).
    calculate_summary( ).
  ENDMETHOD.


  METHOD select_data.
    SELECT afko~aufnr,
           afpo~matnr,
           makt~maktx,
           afpo~pwerk AS werks,
           afko~gamng,
           afko~gmein,
           afru~budat,
           afru~lmnga,
           afru~xmnga,
           afru~rmnga
      FROM afko
      INNER JOIN afpo
        ON afpo~aufnr = afko~aufnr
      INNER JOIN afru
        ON afru~aufnr = afko~aufnr
      LEFT OUTER JOIN makt
        ON  makt~matnr = afpo~matnr
        AND makt~spras = @sy-langu
      WHERE afru~budat BETWEEN @mv_date_from AND @mv_date_to
        AND afru~stokz = @abap_false
      INTO CORRESPONDING FIELDS OF TABLE @mt_data.
  ENDMETHOD.


  METHOD calculate_summary.
    DATA ls_summary TYPE gty_summary.
    CLEAR mt_summary.

    LOOP AT mt_data ASSIGNING FIELD-SYMBOL(<ls_data>)
         GROUP BY <ls_data>-budat
         ASSIGNING FIELD-SYMBOL(<lo_group>).

      CLEAR ls_summary.
      ls_summary-budat = <lo_group>.

      LOOP AT GROUP <lo_group> ASSIGNING FIELD-SYMBOL(<ls_item>).
        ADD <ls_item>-gamng TO ls_summary-plan_qty.
        ADD <ls_item>-lmnga TO ls_summary-actual_qty.
        ADD <ls_item>-xmnga TO ls_summary-scrap_qty.
        ADD <ls_item>-rmnga TO ls_summary-rework_qty.
      ENDLOOP.

      IF ls_summary-plan_qty > 0.
        ls_summary-efficiency = ls_summary-actual_qty / ls_summary-plan_qty * 100.
      ENDIF.

      IF ls_summary-actual_qty > 0.
        ls_summary-scrap_rate = ls_summary-scrap_qty / ls_summary-actual_qty * 100.
      ENDIF.

      APPEND ls_summary TO mt_summary.
    ENDLOOP.

    SORT mt_summary BY budat.
  ENDMETHOD.


  METHOD get_data.
    rt_data = mt_data.
  ENDMETHOD.


  METHOD get_summary.
    rt_summary = mt_summary.
  ENDMETHOD.

ENDCLASS.


select_data metodu: AFKO (üretim emri başlığı), AFPO (üretim emri kalemi), AFRU (üretim teyidi) ve MAKT (malzeme tanımı) tablolarını birleştirerek verileri çeker. stokz = false filtresi ile iptal edilmemiş teyitleri alırız.


calculate_summary metodu: GROUP BY sözdizimi ile verileri tarihe göre gruplar. Her gün için planlanan, gerçekleşen, fire ve yeniden işleme miktarlarını toplar. Ardından verimlilik ve fire oranını hesaplar.

Adım 3: Claude API İstemci Sınıfı

Bu sınıf, Claude API ile HTTP üzerinden iletişim kurar. API anahtarı, endpoint ve model bilgileri sabit olarak tanımlanır.

*----------------------------------------------------------------------*
* Claude API İstemci Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_claude_api DEFINITION FINAL.

  PUBLIC SECTION.

    CONSTANTS gc_api_key     TYPE string VALUE 'sk-ant-api03-XXXXXXXXXXXXXXXXXXXXXXXX'.
    CONSTANTS gc_api_url     TYPE string VALUE 'https://api.anthropic.com/v1/messages'.
    CONSTANTS gc_api_version TYPE string VALUE '2023-06-01'.
    CONSTANTS gc_model       TYPE string VALUE 'claude-sonnet-4-5-20250929'.

    CLASS-METHODS analyze
      IMPORTING
        it_summary       TYPE gty_t_summary
      RETURNING
        VALUE(rv_result) TYPE string.

  PRIVATE SECTION.

    CLASS-METHODS create_request_body
      IMPORTING
        it_summary     TYPE gty_t_summary
      RETURNING
        VALUE(rv_body) TYPE string.

    CLASS-METHODS parse_response
      IMPORTING
        iv_json        TYPE string
      RETURNING
        VALUE(rv_text) TYPE string.

ENDCLASS.


CLASS lcl_claude_api IMPLEMENTATION.

  METHOD analyze.
    DATA lo_http_client TYPE REF TO if_http_client.
    DATA lv_response    TYPE string.
    DATA lv_status      TYPE i.

    cl_http_client=>create_by_url(
      EXPORTING
        url    = gc_api_url
        ssl_id = 'ANONYM'
      IMPORTING
        client = lo_http_client
      EXCEPTIONS
        OTHERS = 1 ).

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE cx_sy_create_object_error.
    ENDIF.

    lo_http_client->propertytype_logon_popup = if_http_client=>co_disabled.
    lo_http_client->request->set_method( if_http_request=>co_request_method_post ).

    lo_http_client->request->set_header_field(
      name  = 'Content-Type'
      value = 'application/json' ).

    lo_http_client->request->set_header_field(
      name  = 'x-api-key'
      value = gc_api_key ).

    lo_http_client->request->set_header_field(
      name  = 'anthropic-version'
      value = gc_api_version ).

    lo_http_client->request->set_cdata( create_request_body( it_summary ) ).

    lo_http_client->send(
      EXCEPTIONS
        OTHERS = 1 ).

    IF sy-subrc <> 0.
      lo_http_client->close( ).
      RAISE EXCEPTION TYPE cx_sy_create_object_error.
    ENDIF.

    lo_http_client->receive(
      EXCEPTIONS
        OTHERS = 1 ).

    IF sy-subrc <> 0.
      lo_http_client->close( ).
      RAISE EXCEPTION TYPE cx_sy_create_object_error.
    ENDIF.

    lv_status = lo_http_client->response->get_header_field( '~status_code' ).
    lv_response = lo_http_client->response->get_cdata( ).
    lo_http_client->close( ).

    IF lv_status = 200.
      rv_result = parse_response( lv_response ).
    ELSE.
      rv_result = |HTTP Hata: { lv_status }|.
    ENDIF.
  ENDMETHOD.


  METHOD create_request_body.
    DATA lv_json TYPE string.

    lv_json = /ui2/cl_json=>serialize(
      data        = it_summary
      pretty_name = /ui2/cl_json=>pretty_mode-low_case ).

    REPLACE ALL OCCURRENCES OF '\' IN lv_json WITH '\\'.
    REPLACE ALL OCCURRENCES OF '"' IN lv_json WITH '\"'.
    REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN lv_json WITH '\n'.
    REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN lv_json WITH '\n'.

    rv_body =
      `{` &&
      `"model":"` && gc_model && `",` &&
      `"max_tokens":4096,` &&
      `"messages":[{` &&
        `"role":"user",` &&
        `"content":"Asagidaki uretim verilerini analiz et. ` &&
        `Verimlilik, fire orani ve dikkat edilmesi gereken noktalari belirle. ` &&
        `Sonuclari Turkce yonetici ozeti formatinda sun:\n\n` && lv_json && `"` &&
      `}]` &&
      `}`.
  ENDMETHOD.


  METHOD parse_response.
    DATA ls_response TYPE gty_api_response.

    /ui2/cl_json=>deserialize(
      EXPORTING
        json = iv_json
      CHANGING
        data = ls_response ).

    READ TABLE ls_response-content INDEX 1 INTO DATA(ls_content).
    IF sy-subrc = 0.
      rv_text = ls_content-text.
    ENDIF.
  ENDMETHOD.

ENDCLASS.

analyze metodu: HTTP client oluşturur, gerekli header'ları ayarlar ve POST isteği gönderir. Yanıt başarılı ise parse_response ile içeriği çıkarır.

create_request_body metodu: Özet verilerini JSON'a dönüştürür ve Claude API formatına uygun request body oluşturur. Özel karakterler escape edilir.

parse_response metodu: API yanıtındaki content dizisinden text alanını okur ve döndürür.

Adım 4: Mail Gönderim Sınıfı

Bu sınıf, CL_BCS sınıfını kullanarak mail gönderimini gerçekleştirir.

*----------------------------------------------------------------------*
* Mail Gönderim Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_mail_sender DEFINITION FINAL.

  PUBLIC SECTION.

    CLASS-METHODS send
      IMPORTING
        iv_subject TYPE clike
        iv_body    TYPE string
        it_emails  TYPE string_table
      RAISING
        cx_send_req_bcs.

ENDCLASS.


CLASS lcl_mail_sender IMPLEMENTATION.

  METHOD send.
    DATA lt_body      TYPE soli_tab.
    DATA lo_document  TYPE REF TO cl_document_bcs.
    DATA lo_request   TYPE REF TO cl_bcs.
    DATA lo_sender    TYPE REF TO cl_sapuser_bcs.
    DATA lo_recipient TYPE REF TO if_recipient_bcs.
    DATA lv_email     TYPE adr6-smtp_addr.

    SPLIT iv_body AT cl_abap_char_utilities=>newline INTO TABLE lt_body.

    lo_document = cl_document_bcs=>create_document(
      i_type    = 'RAW'
      i_text    = lt_body
      i_subject = CONV so_obj_des( iv_subject ) ).

    lo_request = cl_bcs=>create_persistent( ).
    lo_request->set_document( lo_document ).

    lo_sender = cl_sapuser_bcs=>create( sy-uname ).
    lo_request->set_sender( lo_sender ).

    LOOP AT it_emails INTO DATA(ls_email).
      lv_email = ls_email.
      lo_recipient = cl_cam_address_bcs=>create_internet_address( lv_email ).
      lo_request->add_recipient( lo_recipient ).
    ENDLOOP.

    lo_request->set_send_immediately( abap_true ).
    lo_request->send( ).

    COMMIT WORK AND WAIT.
  ENDMETHOD.

ENDCLASS.

send metodu: Mail içeriğini satırlara böler, doküman oluşturur, alıcıları ekler ve hemen gönderim yapar. COMMIT WORK AND WAIT ile işlemin tamamlanması beklenir.

Adım 5: Ana Uygulama Sınıfı

Bu sınıf, tüm süreci koordine eder. Veri toplama, analiz ve mail gönderimi adımlarını sırayla çalıştırır.

*----------------------------------------------------------------------*
* Ana Uygulama Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_application DEFINITION FINAL.

  PUBLIC SECTION.

    CLASS-METHODS run
      IMPORTING
        iv_date_from TYPE datum
        iv_date_to   TYPE datum
        it_emails    TYPE string_table.

ENDCLASS.


CLASS lcl_application IMPLEMENTATION.

  METHOD run.
    DATA lo_production TYPE REF TO lcl_production_data.
    DATA lt_summary    TYPE gty_t_summary.
    DATA lv_analysis   TYPE string.
    DATA lv_subject    TYPE string.

    " Üretim verilerini topla
    lo_production = NEW lcl_production_data(
      iv_date_from = iv_date_from
      iv_date_to   = iv_date_to ).

    lt_summary = lo_production->get_summary( ).

    IF lt_summary IS INITIAL.
      MESSAGE 'Seçilen tarih aralığında veri bulunamadı' TYPE 'S' DISPLAY LIKE 'W'.
      RETURN.
    ENDIF.

    " Claude API ile analiz et
    TRY.
        lv_analysis = lcl_claude_api=>analyze( lt_summary ).
      CATCH cx_root INTO DATA(lx_error).
        MESSAGE lx_error->get_text( ) TYPE 'E'.
        RETURN.
    ENDTRY.

    " Mail gönder
    lv_subject = |Üretim Raporu: { iv_date_from DATE = USER } - { iv_date_to DATE = USER }|.

    TRY.
        lcl_mail_sender=>send(
          iv_subject = lv_subject
          iv_body    = lv_analysis
          it_emails  = it_emails ).

        MESSAGE 'Rapor başarıyla gönderildi' TYPE 'S'.

      CATCH cx_send_req_bcs INTO DATA(lx_mail).
        MESSAGE lx_mail->get_text( ) TYPE 'E'.
    ENDTRY.
  ENDMETHOD.

ENDCLASS.

run metodu: Üç ana adımı sırayla yürütür. Her adımda hata kontrolü yapılır ve kullanıcıya bilgi mesajları gösterilir.

Adım 6: Seçim Ekranı ve Program Başlangıcı

Son olarak kullanıcı arayüzünü ve programın giriş noktasını tanımlıyoruz.

*----------------------------------------------------------------------*
* Seçim Ekranı
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
  PARAMETERS p_from TYPE datum.
  PARAMETERS p_to   TYPE datum.
SELECTION-SCREEN END OF BLOCK b1.

SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-002.
  PARAMETERS p_mail1 TYPE ad_smtpadr.
  PARAMETERS p_mail2 TYPE ad_smtpadr.
  PARAMETERS p_mail3 TYPE ad_smtpadr.
SELECTION-SCREEN END OF BLOCK b2.


*----------------------------------------------------------------------*
* Program Başlangıcı
*----------------------------------------------------------------------*
START-OF-SELECTION.

  DATA lt_emails TYPE string_table.

  IF p_mail1 IS NOT INITIAL.
    APPEND CONV string( p_mail1 ) TO lt_emails.
  ENDIF.

  IF p_mail2 IS NOT INITIAL.
    APPEND CONV string( p_mail2 ) TO lt_emails.
  ENDIF.

  IF p_mail3 IS NOT INITIAL.
    APPEND CONV string( p_mail3 ) TO lt_emails.
  ENDIF.

  IF lt_emails IS INITIAL.
    MESSAGE 'En az bir mail adresi girilmelidir' TYPE 'E'.
  ENDIF.

  lcl_application=>run(
    iv_date_from = p_from
    iv_date_to   = p_to
    it_emails    = lt_emails ).

Seçim ekranında tarih aralığı ve üç mail adresi için alanlar bulunur. Program başlangıcında girilen mail adresleri bir tabloya aktarılır ve lcl_application=>run metodu çağrılır.

Ön Gereksinimler

SSL Sertifikası

STRUST işlem kodunda SSL Client (Anonymous) düğümüne api.anthropic.com sertifikasını ekleyin.

API Anahtarı

Anthropic Console'dan API anahtarınızı alın ve gc_api_key sabitine yazın.

Background Job Oluşturma

SM36 işlem kodunda:

AlanDeğerJob NameZPP_DAILY_REPORTJob ClassCProgramZPP_PRODUCTION_AI_REPORTVariantDAILYStart TimeHer gün 18:00

API Detayları

ParametreDeğerEndpointhttps://api.anthropic.com/v1/messagesModelclaude-sonnet-4-5-20250929API Version2023-06-01Max Tokens4096

Sonuç

Bu yazıda, SAP üretim verilerini Claude API ile analiz eden ve sonuçları mail olarak ileten tam bir ABAP uygulaması geliştirdik. Uygulama nesne yönelimli tasarım prensipleriyle yazıldı ve background job olarak çalışmaya uygun.

Aynı mimari, kalite bildirimleri, stok hareketleri veya satış verileri gibi farklı veri setleri için kolayca uyarlanabilir.

Yorumlar

0

Yorum yapmak için giriş yapmalısınız.

Henüz yorum bulunmamaktadır.

İlk yorumu yapan siz olun.

Emre Göçmen

Yazar & Geliştirici

SAP ABAP & Full Stack geliştirici olarak deneyimlerim, becerilerim ve kariyer yolculuğum hakkında blog yazılarım.

Kategori

SAP

SAP

Yazılardan Haberdar Olun

Yeni yazılardan ilk siz haberdar olmak için e-posta bültenime abone olun.

SAP ABAP Claude AI Entegrasyonu | Yapay Zeka ile Üretim Raporu Oluşturma