Tuesday 17 April 2007

SAP via Delphi Re-executing the same SAP function

After running the examples from BAPI / RFC with Delphi, I run into the following problem: Each time the Button2Click function was called the grid would show the results already displayed plus any data returned from SAP after the current call. A little bit of debugging showed that the table returned from the SAPFunctions object in statement Table := Funct.tables.item('DATA'), was the one that would not get initialized prior to Funct.call(). Aa I have no clues regarding the available methods of the table or the SAPFunctions object that would allow me to clear the table data before each call, I ended up rewriting the example performing the following changes.

  1. Create one connection object and retain it throughout the entire program session during FormCreate.
  2. Create and destroy a SAPFunctions object at each invocation of the ExecuteButtonClick() function. The way the table returned always has new data returned from SAP. This has been the only way I could avoid the problem of not initializing the returned table. Since I use similar code to perform data transfers between SAP and an other Oracle database at user defined intervals , this optin was more or less a one way.
The actual code of the get cost centers example now looks like this :
unit MainUni;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, OleCtrls, SAPLogonCtrl_TLB, Grids,
 StdCtrls, ComCtrls, ExtCtrls, Buttons;

type
 TFormMain = class(TForm)
   PanelLogin: TPanel;
   StatusBar: TStatusBar;
   ButtonExec: TButton;
   Grid: TStringGrid;
   SAPLogonControl: TSAPLogonControl;
   BitBtnClose: TBitBtn;
   procedure ButtonExecClick(Sender: TObject);
   procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
   Table, Funct, Connection : VARIANT ;
 public
   { Public declarations }
 end;

var
 FormMain: TFormMain;

implementation
{$R *.dfm}

Uses
  SAPFunctionsOCX_TLB;

procedure TFormMain.FormCreate(Sender: TObject);
  begin
     (* create a new connection object to be used
      * for all sessions
      *)
     Connection                  := SAPLogonControl.newConnection;
     Connection.System           := 'R3Q';
     Connection.Client           := '100';
     Connection.ApplicationServer:= 'sapqa_prd.shelman.int';
     Connection.SystemNumber     := '00';
     Connection.Language         := 'EN' ;
  end;

procedure TFormMain.ButtonExecClick(Sender: TObject);
  var
     txt : String;
     r : integer;
     SAPFunctions: TSAPFunctions;
  begin
     SAPFunctions := nil;

     // parameter "true" = SilentLogOn
     if Connection.LogOn(0, false) = true then
        try
           (* Create a new SAPFunctions obejct and
            * assign the existing connection to it
            *)
           SAPFunctions := TSAPFunctions.Create(Self);
           SAPFunctions.Connection := Connection;

           Funct := SAPFunctions.add('RFC_READ_TABLE');
           Funct.exports('QUERY_TABLE').value := 'CSKT';

           // attempt to call
           if not Funct.call then
              // called failed display the error in the statusbar
              StatusBar.SimpleText := Funct.Exception
           else begin
              // Call is successfull display returned data
              Table := Funct.tables.item('DATA');
              grid.rowCount := Table.rowcount + 1;
              grid.cells[0,0] := 'RecNo';
              grid.cells[1,0] := 'Client';
              grid.cells[2,0] := 'CostCent-No';
              grid.cells[3,0] := 'CostCent-Des.';
              for r := 1 to grid.rowCount -1 do begin
                 txt := Table.value(r,1);
                 grid.cells[0,r] := IntToStr(r);
                 grid.cells[1,r] := copy(txt,0,3);
                 grid.cells[2,r] := copy(txt,9,10);
                 grid.cells[3,r] := copy(txt,27,20);
              end;
           end;
        finally
           // close connection
           Connection.LogOff;
           // get rid of the SAPFunctions Object
           SAPFunctions.Free;
        end
     else
        StatusBar.SimpleText := 'Unable to login';
  end;

end.

No comments :