SAP / PyRFC

Asynchronous, non-blocking SAP NW RFC SDK bindings for Python
http://sap.github.io/PyRFC
Apache License 2.0
501 stars 133 forks source link

pyrfc throws TypeError when adding on BORIDENT-OBJECT KEY (allowed string OR struct sofmk) #290

Closed Manuk63 closed 1 year ago

Manuk63 commented 1 year ago

Bug Description

In special case of using function module "BINARY_RELATION_CREATE_COMMIT" pyrfc throws TypeError when OBJ_ROLEB-OBJKEY is a structure of type "SOFMK". Data type of OBJ_ROLEB-OBJKE normaly is CHAR, but also possiby is "SOFMK" (see code below).

Following Code is working SAP internal:

* Create main BO object_a
    data: lo_is_object_a type borident.

    lo_is_object_a-objkey = p_equnr.
    lo_is_object_a-objtype = botype.

* Create attachment BO object_b
    data: lo_is_object_b type borident.

*    LO_IS_OBJECT_B-OBJKEY = LV_MESSAGE_KEY.
*    LO_IS_OBJECT_B-OBJTYPE = DOCTY.
    data: ls_folmen_k type sofmk.
    data: lv_ep_note type borident-objkey.
    ls_folmen_k-foltp = ls_fol_id-objtp.
    ls_folmen_k-folyr = ls_fol_id-objyr.
    ls_folmen_k-folno = ls_fol_id-objno.
    ls_folmen_k-doctp = ls_obj_id-objtp.
    ls_folmen_k-docyr = ls_obj_id-objyr.
    ls_folmen_k-docno = ls_obj_id-objno.
    lv_ep_note = ls_folmen_k.

    lo_is_object_b-objtype = 'MESSAGE'.
    lo_is_object_b-objkey = lv_ep_note.
    call function 'BINARY_RELATION_CREATE_COMMIT'
      exporting
        obj_rolea      = lo_is_object_a
        obj_roleb      = lo_is_object_b
        relationtype   = 'ATTA'

You can reproduce Bug using following Python code:

class SapRFC:
    def __init__(self):

        try:
            self.conn = pyrfc.Connection(user="USER", passwd=PWD", 
                ashost="HOST", sysnr="SYSNR", 
                client ="CLIENT",lang="DE")

        except Exception as e:
            raise Exception("Connection failed. Error {error}".format(error=e))

    def Upload(self):
        description = self.conn.get_function_description("BINARY_RELATION_CREATE_REMOTE")

        # attachments

        #file to binary
        #ToDo
        content = [{"LINE" : "31"}]

        #get folder id
        param = {"REGION" : "B"}                                          
        responseFolder = self.conn.call("SO_FOLDER_ROOT_ID_GET",**param)

        #Insert object
        param = {"FOLDER_ID" : responseFolder["FOLDER_ID"],
                "OBJECT_TYPE" : "EXT",
                "OBJECT_HD_CHANGE" : {"OBJSNS" : "O",
                    "OBJLA" : "DE",
                    "OBJDES" : "Titel_Testdockument",
                    "OBJLEN" : str(len(content)*255),
                    "FILE_EXT": "TXT"},
                "OBJCONT" : content
                }

        responseInsert = self.conn.call("SO_OBJECT_INSERT",**param)

        param = {   "OBJ_ROLEA" : {
                        "OBJKEY" :  "40468620",
                        "OBJTYPE" : "EQUI"},
                    "OBJ_ROLEB" : {
                        "OBJKEY" :  {"FOLTP" : responseFolder["FOLDER_ID"]["OBJTP"],
                            "FOLYR" : responseFolder["FOLDER_ID"]["OBJYR"],
                            "FOLNO" : responseFolder["FOLDER_ID"]["OBJNO"],
                            "DOCTP" : responseInsert["OBJECT_ID"]["OBJTP"],
                            "DOCYR" : responseInsert["OBJECT_ID"]["OBJYR"],
                            "DOCNO" : responseInsert["OBJECT_ID"]["OBJNO"]},
                        "OBJTYPE" :  "MESSAGE"},
                    "RELATIONTYPE" : "ATTA"}    
        responseRelation = self.conn.call("BINARY_RELATION_CREATE_COMMIT",**param)

You will get following exception: image

I'm using pyrfc 2.7.0 running on windows client.

bsrdjan commented 1 year ago

Example does not show RFC parameters data values, sent from Python to ABAP. Could you please provide example with RFC parameters real data, working in SE37 test transaction and not working from Python?

If you don't have access to ABAP system, you can print RFC parameters' values in Python, before RFC call and copy it here

bsrdjan commented 1 year ago

The error is caused by passing a structure to OBJ_ROLEB-OBJKEY

"OBJ_ROLEB" : {
                        "OBJKEY" :  {"FOLTP" : responseFolder["FOLDER_ID"]["OBJTP"],
                            "FOLYR" : responseFolder["FOLDER_ID"]["OBJYR"],
                            "FOLNO" : responseFolder["FOLDER_ID"]["OBJNO"],
                            "DOCTP" : responseInsert["OBJECT_ID"]["OBJTP"],
                            "DOCYR" : responseInsert["OBJECT_ID"]["OBJYR"],
                            "DOCNO" : responseInsert["OBJECT_ID"]["OBJNO"]},

OBJKEY is not of type structure but CHAR70, see below

abap get MME binary_relation_create_commit
//
// BINARY_RELATION_CREATE_COMMIT var: 1  struct: 3  table: 1  exception: 3
//
// abap api
//

// prettier-ignore
const parameters = {

// IMPORT PARAMETERS

RELATIONTYPE      :           "", // CHAR (4) Relationship type
OBJ_ROLEA         :           {}, // BORIDENT Role Object A
OBJ_ROLEB         :           {}, // BORIDENT Role Object B

// TABLE PARAMETERS

// BINREL_ATTRIB  :           [], // BRELATTR Attributes

// EXPORT PARAMETERS

// BINREL         :           {}, // GBINREL Relationship and Roles

// EXCEPTION PARAMETERS

// INTERNAL_ERROR                  // no text (en)
// NO_MODEL                        // no text (en)
// UNKNOWN                         // no text (en)
};

const result = await client.call("BINARY_RELATION_CREATE_COMMIT", parameters);

//
// IMPORT PARAMETERS
//

// BORIDENT  Role Object A

// prettier-ignore
const OBJ_ROLEA = {
  OBJKEY                           :   "", // CHAR (70) Object key
  OBJTYPE                          :   "", // CHAR (10) Object Type SU3=OBJ
  LOGSYS                           :   "", // CHAR (10) ALPHA=ALPHA Logical system
};

// BORIDENT  Role Object B

// prettier-ignore
const OBJ_ROLEB = {
  OBJKEY                           :   "", // CHAR (70) Object key
  OBJTYPE                          :   "", // CHAR (10) Object Type SU3=OBJ
  LOGSYS                           :   "", // CHAR (10) ALPHA=ALPHA Logical system
};

//
// TABLE PARAMETERS
//

// BRELATTR  Attributes
const BINREL_ATTRIB = [];

// prettier-ignore
const BINREL_ATTRIB_line = {
  ATTRIBUT                         :   "", // CHAR (10) Object Relationship Service : attribute of a link
  POSNR                            :   "", // NUMC (4) Position of the field in the table
  GATTRDATA                        :   "", // CHAR (250) Object relationship: generic attribute structure bin. relat.
};

//
// EXPORT PARAMETERS
//

// GBINREL  Relationship and Roles

// prettier-ignore
const BINREL = {
  UTCTIME                          :  "0", // DEC (15) UTC Time Stamp in Short Form (YYYYMMDDhhmmss)
};
Manuk63 commented 1 year ago

@bsrdjan

Thanks for response.

Thats true, OBJKEY is type CHAR70. But the ABAP code below does not pass char to OBJKEY. It pass structure type sofmk and it works well:

    data: lo_is_object_b type borident.
    data: ls_folmen_k type sofmk.
    data: lv_ep_note type borident-objkey.
    ls_folmen_k-foltp = ls_fol_id-objtp.
    ls_folmen_k-folyr = ls_fol_id-objyr.
    ls_folmen_k-folno = ls_fol_id-objno.
    ls_folmen_k-doctp = ls_obj_id-objtp.
    ls_folmen_k-docyr = ls_obj_id-objyr.
    ls_folmen_k-docno = ls_obj_id-objno.
    lv_ep_note = ls_folmen_k.

    lo_is_object_b-objtype = 'MESSAGE'.
    lo_is_object_b-objkey = lv_ep_note.

_ls_folmenk (type sofmk) is assigned to _lv_epnote (type borident-objkey), which is assigned to _lo_is_objectb-objkey. How can I do this from remote without ABAP? I thought it might be a bug, but I#m not a ABAP developer.

Maby somone can help me?

bsrdjan commented 1 year ago

How can I do this from remote without ABAP?

You can try in Python to concatenate SOFMK structure fields into OBJKEY string and pass as a string from Python.

SOFMK fields

FOLTP   Type    CHAR    3   Objekt Mappe: Objekttyp aus der ID.
FOLYR   Type    CHAR    2   Objekt Mappe: Jahr aus der ID.
FOLNO   Type    CHAR    12  Objekt Mappe: Nummer aus der ID.
DOCTP   Type    CHAR    3   Objekt: Objekttyp aus der ID.
DOCYR   Type    CHAR    2   Objekt: Jahr aus der ID.
DOCNO   Type    CHAR    12  Objekt: Nummer aus der ID.
FORTP   Type    CHAR    3   Weiterleitender: Objekttyp aus der ID.
FORYR   Type    CHAR    2   Weiterleitender: Jahr aus der ID.
FORNO   Type    CHAR    12  Weiterleitender: Nummer aus der ID.

If it does not work you can post question to SAP Community: https://answers.sap.com/questions/9707327/finding-parameters-for-binaryrelationcreate.html

Manuk63 commented 1 year ago

How can I do this from remote without ABAP?

You can try in Python to concatenate SOFMK structure fields into OBJKEY string and pass as a string from Python.

I tried something like that. But it doesn't work. I posted my question to the SAP community: Question Thanks for your help.