SAP / node-rfc

Asynchronous, non-blocking SAP NW RFC SDK bindings for Node.js
Apache License 2.0
252 stars 73 forks source link

node-rfc internal error: wrapString (Thai Language) #57

Closed potcharapon closed 6 years ago

potcharapon commented 6 years ago

Trying to display the customer's name on a webpage by calling BAPI_CUSTOMER_GETDETAIL2. The message saved on the record is ทดสอบสร้างลูกค้าจากภายนอกครั้งที่ 31 วันที่ 20180821 เวลา 15:38 which then concatenated into parts, 35 char each. i.e.

name_1: 'ทดสอบสร้างลูกค้าจากภายนอกครั้งที่ 3' name_2: '1 วันที่ 20180821 เวลา 15:38'

After the record is saved.Viewing the data via SAP GUI calling BAPI_CUSTOMER_CREATEFROMDATA1 to check. The result is correctly displayed:

CUSTOMERADDRESS.NAME: 'ทดสอบสร้างลูกค้าจากภายนอกครั้งที่ 3' CUSTOMERADDRESS.NAME_2: '1 วันที่ 20180821 เวลา 15:38'

Then we went back and check the record using the function BAPI_CUSTOMER_GETDETAIL2 the error occurs:

CUSTOMERADDRESS.NAME: 'node-rfc internal error: wrapString' CUSTOMERADDRESS.NAME_2: '1 วันที่ 20180821 เวลา 15:38'

Example

From SAP GUI

Function BAPI_CUSTOMER_GETDETAIL2
Export Parameter:  CUSTOMERADDRESS
Field: NAME Value: ‘ทดสอบสร้างลูกค้าจากภายนอกครั้งที่ 3’
Field: NAME_2 Value: ‘1 วันที่ 20180821 เวลา 15:38’

From node-rfc

Function BAPI_CUSTOMER_GETDETAIL2
Response : {
    CUSTOMERADDRESS: {
        …
        NAME: 'node-rfc internal error: wrapString',
        NAME_2: '1 วันที่ 20180821 เวลา 15:38',
        …
    }, {
        …
    }
}

File

sapRFC.js

const config = require('./config');
const rfc = require('node-rfc');
const connParams = {
     user: config.sap.user,
     passwd: config.sap.passwd,
     ashost: config.sap.ashost,
     sysnr: config.sap.sysnr,
     client: config.sap.client,
     lang: 2
};
const clientSAP = new rfc.Client(connParams, true);
module.exports = clientSAP;

model_sap.js

const Promise = require('bluebird');
const _ = require('lodash');
const sapRFC = require('../config/sapRFC');
const modelSAP = {
    sapConnect: function () {
        return new Promise(function (resolve, reject) {
            if (sapRFC) {
                sapRFC.close(function (err) { console.error(err) });
                if (!sapRFC.ping()) {
                    return sapRFC.connect(function (err) {
                        if (err) return reject(err);
                        return resolve(true);
                    });
                } else {
                    return resolve(true);
                }
            } else {
                throw Error('Error Connect SAP!');
            }
        });
    },
    sapCustomerGet: function (CUSTOMERNO, USER) {
        return new Promise(function (resolve, reject) {
            if (!CUSTOMERNO) return reject('CUSTOMERNO Invalid');
            return modelSAP.sapConnect().then(function (_stauts) {
                var response = {};
                return new Promise(function (resolve2, reject2) {
                    var objSAP = {
                        CUSTOMERNO: (parseInt(CUSTOMERNO)).pad(10),
                        COMPANYCODE: '1000'
                    };
                    if (USER.hasOwnProperty('sale_company')) {
                        if (USER.sale_company) objSAP.COMPANYCODE = USER.sale_company;
                    }
                    return sapRFC.invoke('BAPI_CUSTOMER_GETDETAIL2', objSAP, function (err, res) {
                        if (err) return reject2(err)
                        response  = res;
                        return modelLogSAP.saveByData(USER.id, 'sapCustomerGet', 'BAPI_CUSTOMER_GETDETAIL2', objSAP, res, res.RETURN).then(function () {s
                            return resolve2(res);
                        });
                    });
                }).then(function (_status) {
                    sapRFC.close(function (err) { console.error(err) });
                    return resolve(response);
                });
            }).catch(function (error) {
                console.error('### Error model modelSAP.sapCustomerGet', error);
                return reject(error)
            });
        });
    }
}
module.exports = modelSAP;
bsrdjan commented 6 years ago

Please try the node-rfc@next release (1.0.0-rc2) with the fix added. The wrapString logic worked so far with 3 bytes per unicode character, per string in average. That was obviously not enough in this case and the fix added the fallback to 6 bytes, in case 3 bytes not enough. The fallback should become active in case when 3 bytes in average are not enough and when the unicode strings fills the full, or almost full length, of ABAP field.

Commit: 23a5e922ca15d72124d3947f8cd7dfa2382198c6

thaicyber commented 6 years ago

node-rfc@next release (1.0.0-rc2) Test wrapString support thai language

thaicyber commented 6 years ago

function error.

client.close() image

client.ping() image

bsrdjan commented 6 years ago

ping() and close() are now non-blocking and require a callback function as argument. Thanks for finding this, will add to CHANGES.

Using callback API, you could provide a dummy like ping( () => {} ), like in unit test examples.

Promise API requires no arguments, as in this unit test, or you could also consider async/await.

As a side note, there are two methods to check if the connection is still alive.

isAlive getter (unit test) indicates if SAP NW RFC library still "considers" the connection open. It is not absolutely reliable because the firewall may silently have closed the connection, without notifying endpoints.

ping() is the only absolutely reliable method but also the most expensive (slowest) one, because of the full request/response cycle it has to perform, to check if the connection is really open.

In many cases isAlive is enough and much faster.

potcharapon commented 6 years ago

@bsrdjan. Thank you for solve this issue. I try it and woking very well.

potcharapon commented 6 years ago