0

I have used SAP Connector for Microsoft .Net v2 to successfully send already formatted IDOCS to SAP.

Today I upgraded to the latest version of the connector. Unfortunately, this SAPIDocSender is not there anymore.

How should I now send those IDOCS to SAP?

Thanks for your help!

EDIT: Thanks! Unfortunately I want to avoid building the IDOC like it is described in the other Thread.

In v2 there was an option to send the whole IDOC string including all segments:

private static void SendIdoc()
{     
    SAP.Connector.RfcTID myTid = SAP.Connector.RfcTID.NewTID();  
    string connectionString = "ASHOST=xxxx SYSNR=xx CLIENT=xxx USER=xxx PASSWD=xxx LANG=xx";
    string upperString = connectionString.ToUpper();
    SAP.Connector.SAPIDocSender sapiDocSender = new SAPIDocSender(upperString);
    sapiDocSender.SubmitIDoc(@"C:\Users\xxx\Documents\testidoc.txt", myTid);
    sapiDocSender.ConfirmTID(myTid);
}
Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
Fabio Lucia
  • 85
  • 1
  • 5
  • Possible duplicate of [How to create and send Idocs to SAP using SAP .Net Connector 3](http://stackoverflow.com/questions/34896202/how-to-create-and-send-idocs-to-sap-using-sap-net-connector-3) – Dirk Trilsbeek Feb 16 '16 at 15:17
  • See above edit. Thanks again! – Fabio Lucia Feb 16 '16 at 16:03
  • it's not that more difficult. You already have all the data in the file for both the control record (first line of your file) and the data records. It is all fixed length and you only need to manually fill the first few fields for data records and the fields for the control record. Afaik there is no dedicated idoc helper in the NCo library anymore. – Dirk Trilsbeek Feb 16 '16 at 18:06
  • Thansk! What do you mean by " you only need to manually fill the first few fields for data"? I need to fill every single line, right? Somoene has any example with a real IDOC? – Fabio Lucia Feb 17 '16 at 07:31
  • yes, you have to fill each line. But the tables you fill contain a few static fields common to all idoc types and the idoc segment specific data is all contained in one long character field called SDATA. If you look at structure EDI_DD40 (the structure for parameter IDOC_DATA_REC_40 in the function module), you'll see it only has 7 fields. The first 6 have to be filled individually and the rest of the idoc line goes to field SDATA. So it is just a matter of reading 6 substrings and then moving the rest of the line to SDATA. – Dirk Trilsbeek Feb 17 '16 at 08:50

3 Answers3

2

as far as I know there is now idoc helper in the current Net Connector 3. But if you have a file containing a valid idoc, you already have all the information you need.

The basics about sending Idocs to the SAP system are described here already, so I won't go into detail about that in this answer. To send your idoc file, you have to manually fill the control record (first line of your idoc) and the data records.

The control table requires some manual labor. Fortunately the control record is the same on all idocs, so you don't have to consider the idoc type your sending.

var fileStream = System.IO.File.OpenRead(fullFilepath);
var streamReader = new System.IO.StreamReader(fileStream);
string control = streamReader.ReadLine();

controlTable.Append();
controlTable.CurrentRow.SetValue("TABNAM", control.Substring(0, 10));
controlTable.CurrentRow.SetValue("MANDT", control.Substring(10, 3));
controlTable.CurrentRow.SetValue("DOCNUM", control.Substring(13, 16));
controlTable.CurrentRow.SetValue("DOCREL", control.Substring(29, 4));
controlTable.CurrentRow.SetValue("STATUS", control.Substring(33, 2));
controlTable.CurrentRow.SetValue("DIRECT", control.Substring(35, 1));
controlTable.CurrentRow.SetValue("OUTMOD", control.Substring(36, 1));
controlTable.CurrentRow.SetValue("EXPRSS", control.Substring(37, 1));
controlTable.CurrentRow.SetValue("TEST", control.Substring(38, 1));
controlTable.CurrentRow.SetValue("IDOCTYP", control.Substring(39, 30));
controlTable.CurrentRow.SetValue("CIMTYP", control.Substring(69, 30));
controlTable.CurrentRow.SetValue("MESTYP", control.Substring(99, 30));
controlTable.CurrentRow.SetValue("MESCOD", control.Substring(129, 3));
controlTable.CurrentRow.SetValue("MESFCT", control.Substring(132, 3));
controlTable.CurrentRow.SetValue("STD", control.Substring(135, 1));
controlTable.CurrentRow.SetValue("STDVRS", control.Substring(136, 6));
controlTable.CurrentRow.SetValue("STDMES", control.Substring(142, 6));
controlTable.CurrentRow.SetValue("SNDPOR", control.Substring(148, 10));
controlTable.CurrentRow.SetValue("SNDPRT", control.Substring(158, 2));
controlTable.CurrentRow.SetValue("SNDPFC", control.Substring(160, 2));
controlTable.CurrentRow.SetValue("SNDPRN", control.Substring(162, 10));
controlTable.CurrentRow.SetValue("SNDSAD", control.Substring(172, 21));
controlTable.CurrentRow.SetValue("SNDLAD", control.Substring(193, 70));
controlTable.CurrentRow.SetValue("RCVPOR", control.Substring(263, 10));
controlTable.CurrentRow.SetValue("RCVPRT", control.Substring(273, 2));
controlTable.CurrentRow.SetValue("RCVPFC", control.Substring(275, 2));
controlTable.CurrentRow.SetValue("RCVPRN", control.Substring(277, 10));
controlTable.CurrentRow.SetValue("RCVSAD", control.Substring(287, 21));
controlTable.CurrentRow.SetValue("RCVLAD", control.Substring(308, 70));
controlTable.CurrentRow.SetValue("REFMES", control.Substring(420, 14));

var dataLine = streamReader.ReadLine();
while (dataLine != null) {

    dataTable.Append();
    dataTable.CurrentRow.SetValue("SEGNAM", dataLine.SubString(0, 30));
    dataTable.CurrentRow.SetValue("MANDT", dataLine.SubString(30, 3));
    dataTable.CurrentRow.SetValue("DOCNUM", dataLine.SubString(33, 16));
    dataTable.CurrentRow.SetValue("SEGNUM", dataLine.SubString(49, 6));
    dataTable.CurrentRow.SetValue("PSGNUM", dataLine.SubString(55, 6));
    dataTable.CurrentRow.SetValue("HLEVEL", dataLine.SubString(61, 2));
    dataTable.CurrentRow.SetValue("SDATA", dataLine.SubString(63, dataLine.Length - 63));

    dataLine = streamReader.ReadLine();
}

this snippet expects a single idoc in the file. If you have multiple idocs in one file, you need to split them by looking for the control record (the control record line usually starts with "EDI_DC40").

Community
  • 1
  • 1
Dirk Trilsbeek
  • 5,873
  • 2
  • 25
  • 23
  • Hi Dirk! In the meantime i just tried nearly the same. Seems to work fine. Thanks again! Will post a snippet containing the code to get the Metadata dynamically from the Table. – Fabio Lucia Feb 17 '16 at 09:36
1

Based on Dirk's answer I just created 2 Methods to fill the control & data tables dynamically by using the Metadata available :

    private static void AddControlToIdocTable(ref IRfcTable control, string controlLine)
    {
        var lineType = control.Metadata.LineType;

        //Append a new Control Row
        control.Append();

        //Creates an empty array with the Count of the different fields the RfcTable consists of
        string[] columns = new string[control.Metadata.LineType.FieldCount];

        for (int i = 0; i < columns.Length; i++)
        {
            //Get the Type containg the structure of the field
            var type = lineType[i];

            //If NucOffset + NucLength is not bigger then the length of the current control line
            //we append the substring of the control line using those values (Offset + Length)
            if(controlLine.Length >= (type.NucOffset + type.NucLength))
                control.CurrentRow.SetValue(type.Name, controlLine.Substring(type.NucOffset, type.NucLength));
        }
    }

    private static void AddDataToIdocTable(ref IRfcTable records, List<string> dataLines)
    {
        var lineType = records.Metadata.LineType;

        //Creates an empty array with the Count of the different fields the RfcTable consists of
        string[] columns = new string[records.Metadata.LineType.FieldCount];

        foreach (string dataLine in dataLines)
        {
            //Append a new Data Row for every data line
            records.Append();
            for (int i = 0; i < columns.Length; i++)
            {
                //Get the Type containg the structure of the field
                var type = lineType[i];

                //If NucOffset + NucLength is not bigger then the length of the current control line
                //we append the substring of the control line using those values (Offset + Length)
                if (dataLine.Length >= (type.NucOffset + type.NucLength))
                    records.CurrentRow.SetValue(type.Name, dataLine.Substring(type.NucOffset, type.NucLength));
            }
        }
    }

Will post some further details after testing. Thanks!

Fabio Lucia
  • 85
  • 1
  • 5
1

I worked with Fabio's code for a few minutes, and read the SAP documentation, and came up with this method of populating the tables. (The control and data tables are of the same class)

    private void AppendRecordToTable(IRfcTable idocTable, string textRecord)
    {
        var structure = idocTable.Metadata.LineType.CreateStructure();
        foreach (var field in structure)
        {
            var fieldMeta = field.Metadata;
            var fieldValue = CreateFieldValue(fieldMeta, textRecord);
            structure.SetValue(fieldMeta.Name, fieldValue);
        }
        idocTable.Append(structure);
    }

    private string CreateFieldValue(RfcFieldMetadata fieldMeta, string record)
    {
        if (record.Length < fieldMeta.NucOffset)
            return new string(' ', fieldMeta.NucLength);
        if (record.Length < fieldMeta.NucOffset + fieldMeta.NucLength)
            return record.Substring(fieldMeta.NucOffset).PadRight(fieldMeta.NucLength);
        return record.Substring(fieldMeta.NucOffset, fieldMeta.NucLength);
    }
Bob Hodge
  • 63
  • 7