B1服务层脚本引擎扩展开发问题

2020-09-14 07:01发布

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


尊敬的专家,

开发SE扩展程序我经常会遇到错误,我不太了解为什么。 我检查了所有本可以找到的文档,并花了大量时间进行谷歌搜索,但是对于我来说,有些要点仍然不清楚。 我准备了几个示例,因此,我希望社区(甚至SAP支持人员或解决方案架构师团队的人员)可以阐明这种行为的原因。 所有这些示例都在SAP B1 9.3 PL 03中进行了测试

示例1:

对我来说,这可能是最奇怪的问题。 在论坛和文档中的所有示例中,您都可以在脚本开头找到以下行:

 var ServiceLayerContext = require('ServiceLayerContext.js'); 

只需要实例化此对象,它就可以正常工作。 以下内容也是如此:

 var slContext = require('ServiceLayerContext.js'); 

但是,如果我将此变量称为" serviceLayerContext",则在实例化并调用方法" startTransaction()"后会收到奇怪的错误: 脚本错误:调用函数'POST'失败[TypeError:this.contextHandle .startTransaction不是函数]。

这是我的代码,其中会重现此错误:

 var http = require('HttpModule.js');
//要求使用不同于ServiceLayerContext的名称
 var serviceLayerContext = require('ServiceLayerContext.js');

 函数GET()
 {
 }

 函数DELETE(){
 }

 函数PATCH(){
 }

 函数POST()
 {
    //实例化
     var slObj = new serviceLayerContext();

    //开始交易
     slObj.startTransaction();
    //立即回滚
     如果(slObj.isInTransaction())slObj.rollbackTransaction();

   /*设置HTTP响应*/
     http.response.setContentType(http.ContentType.APPLICATION_JSON);
     http.response.setStatus(http.HttpStatus.HTTP_OK);
     http.response.setContent({status:'success'});
     http.response.send();
 }
 

如果我调用此脚本,则会得到以下响应正文:

 {
     "错误":{
         "代码":512,
         "信息": {
             " lang":" zh-cn",
             "" value":"脚本错误:调用函数'POST'失败[TypeError:this.contextHandle.startTransaction不是函数]。"
         }
     }
 }
 

如果我将serviceLayerContext上下文重命名为ServiceLayerContext(例如slContext),一切都会顺利进行。

这是预期的行为还是我做错了什么?

示例2

在论坛和文档中的所有示例中,仅使用入口点功能。 在上传的JS文件中编写附加功能是否有限制? 原因如果我在方法函数之后编写函数,则会遇到意外行为(有时会导致错误,有时不会出错)。 通常是关于编译和意外令牌的错误(我得到了包括ILLEGAL在内的所有令牌的错误)

这是一个重现问题的代码示例:

 var http = require('HttpModule.js');

 函数GET(){
 }

 函数PATCH(){
 }

 函数DELETE(){
 }

 函数POST(){
    //测试要记录的对象
     var obj =
     {
 属性1:1
 属性2:是,
 Property3:"测试",
 Property4:函数(值){返回true;  },
 Property5:函数(值){返回true;  },
 Property6:函数(值){返回true;  },
 Property7:函数(值){返回true;  },
 Property8:函数(值){返回true;  },
 Property9:函数(值){返回true;  },
 Property10:函数(值){返回true;  },
 Property11:函数(值){返回true;  },
 Property12:函数(值){返回true;  },
 Property13:函数(值){返回true;  }
     };
    
     logObject('Test',obj);

   /*设置HTTP响应*/
     http.response.setContentType(http.ContentType.APPLICATION_JSON);
     http.response.setStatus(http.HttpStatus.HTTP_OK);
     http.response.setContent({result:'success'});
     http.response.send();
 }

//在日志文件中记录对象。 如果property是函数-将其记录为'Func'
 函数logObject(objName,obj)
 {
 var replacer =函数(键,值)
 {
//如果属性是函数,则获取'Func'值
 如果(typeof值==='函数')
 {
 返回'Func';
 }
 返回值
 };


 var stringToLog ='';
 尝试
 {
 stringToLog = JSON.stringify(obj,replacer,2);
 }
 赶上(exc)
 {
 stringToLog ='无法序列化对象';
 }


//日志字符串
 console.log(objName +':'+ stringToLog);
 }


 

如果我调用此脚本,则会收到以下响应:

 {
     "错误":{
         "代码":511,
         "信息": {
             " lang":" zh-cn",
             ""值":"脚本错误:编译错误[SyntaxError:意外的标识符]。"
         }
     }
 }
 

如果我在POST函数中移动函数的逻辑,一切都会顺利进行。

示例3:

此错误可能与进入点之外的函数和变量有关,但我对结果感到非常惊讶。 这是我的脚本文字:

//需要必要的实体
//需要处理http调用
 var http = require('HttpModule.js');
//调用SL实体/动作是必需的
 var ServiceLayerContext = require('ServiceLayerContext.js');
//实体代理对象
 var Customer = require('EntityType/BusinessPartner');

//结果对象
 var result = {
 IsSuccess:是的,
 ErrorMsg:",
 BookingSapCode:'',
 CustomerSapCode:"
 };

//输入对象的验证器
 var inputValidator =
 {
 BookingId:函数(值){返回true;  },
 BookingSapCode:函数(值){返回true;  },
 IsCanceled:函数(值){返回true;  },
 日期:函数(值){返回isNaN(Date.parse(value));  },
 电子邮件:函数(值){返回true;  },
 电话:函数(值){返回true;  },
 CustomerId:函数(值){返回true;  },
 标题:函数(值){返回true;  },
 名称:函数(值){返回true;  },
 姓:函数(值){返回true;  },
 CustomerSapCode:函数(值){返回true;  },
 CustomerSapSeries:函数(值){返回true;  },
 详细信息:函数(值)
 {
//检查是否为数组
 如果(!Array.isArray(value))返回false;

//实例化SL上下文
 var slContext = new ServiceLayerContext();

//对于每个ItemCode检查此项目是否存在
 value.forEach(函数(元素)
 {
 如果(!checkItemCode(element.SapItemCode,slContext))返回false;
 });

 返回true;
 }
 };

//===================================进入点===========  =======================================//

 函数GET(){

 }

 函数DELETE(){

 }


 函数PATCH(){

 }


 函数POST(){
 console.log('开始执行');

//获取请求的正文
 logObject('val',inputValidator);
 var inputObject = getBody(inputValidator);
 logObject('inputObj',inputObject); //记录输入对象以检查数据

   /*设置HTTP响应*/
     http.response.setContentType(http.ContentType.APPLICATION_JSON);
     http.response.setStatus(http.HttpStatus.HTTP_OK);
     http.response.setContent(result);
     http.response.send();
 }


//===================================私人功能==========  =======================================//


 函数checkItemCode(itemCode,slContext)
 {
 返回true;
 }


//===================================常见功能===========  =======================================//


//获取主体并通过传递的"验证器"验证结构。
//验证器将所有属性显示为验证函数
 函数getBody(validator)
 {
//尝试从身体获取数据
 var jsonObj = http.request.getJsonObj();
 如果(!jsonObj)
 {
         抛出http.ScriptException(http.HttpStatus.HTTP_BAD_REQUEST,"无法从请求有效内容中获取JSON格式的内容");
 }


//只有存在变量
     如果(typeofvalidator!=='undefined')
     {
     var错误= validateObject(jsonObj,验证器);
 logObject('错误',错误);
     如果(errors.length> 0)
     {
 抛出http.ScriptException(http.HttpStatus.HTTP_BAD_REQUEST,"输入对象无效:" + errors.join('|'));
     }
     }


//返回反序列化的主体
 返回jsonObj;
 }


//通过模式验证对象
 函数validateObject(object,schema){
 var错误= Object.keys(模式)
 .map(功能(属性)
 {
 varvalidator = {}; //属性的验证函数
 var isMissing = false;


 if(object [property] === undefined)//如果object没有此属性-函数总是返回false
 {
 验证程序=函数(值){return false};
 isMissing = true;
 }
 其他
 {
 验证者=模式[属性]; //获取验证功能
 }


 return {property:property,isValid:validator(object [property]),isMissing:isMissing};
 })
 .reduce(功能(错误,属性检查)
 {
 如果(propertyCheck.isValid ===否)
 {
 errors.push(propertyCheck.property +(propertyCheck.isMissing?"丢失。":"无效。"));
 }
    
 返回错误;
 },[]);
 返回错误;
 }


//在{SL Installation Path}/logs/script/*中记录对象
 函数logObject(name,obj)
 {
 var replacer =(键,值)=> {
//如果有函数,请给我们该函数的代码
 如果(typeof值==='函数')
 {
 返回'Func';
 }
 返回值
 };

//检查是否没有序列化错误
 var stringToLog ='';
 尝试
 {
 stringToLog = name +':'+ JSON.stringify(obj,replacer,2);
 }
 赶上(exc)
 {
 stringToLog = name +':无法序列化-'+排除;
 }

//日志字符串
 console.log(stringToLog);
 }

 

所以,我的想法是我要验证我的请求正文。 为此,我使用方法而不是属性声明了一个蓝图对象。 这种方法检查我的请求对象的数据。

但是,我总是会遇到一些缺少某些字段的异常情况。 这是我的回复:

 {
     "错误":{
         "代码":600,
         "信息": {
             " lang":" zh-cn",
             " value":"输入对象无效:缺少CustomerSapSereries。"
         }
     }
 }
 

但是我的架构对象中没有 CustomerSapSereries 属性。 因此,在测试期间,当我更改了一些代码段时(以我与此观点无关的拙见),我将一些属性重命名了(用Titltle代替Title和CustomerSerieses而不是CustomerSeries)。 这确实使我感到困惑,我很高兴对以下行为的原因做出任何澄清。

更新:

我猜想serviceLayerContext的问题是因为此变量在引擎中使用。

 function getContextHandle(){
         返回serviceLayerContext;
     }
 

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


尊敬的专家,

开发SE扩展程序我经常会遇到错误,我不太了解为什么。 我检查了所有本可以找到的文档,并花了大量时间进行谷歌搜索,但是对于我来说,有些要点仍然不清楚。 我准备了几个示例,因此,我希望社区(甚至SAP支持人员或解决方案架构师团队的人员)可以阐明这种行为的原因。 所有这些示例都在SAP B1 9.3 PL 03中进行了测试

示例1:

对我来说,这可能是最奇怪的问题。 在论坛和文档中的所有示例中,您都可以在脚本开头找到以下行:

 var ServiceLayerContext = require('ServiceLayerContext.js'); 

只需要实例化此对象,它就可以正常工作。 以下内容也是如此:

 var slContext = require('ServiceLayerContext.js'); 

但是,如果我将此变量称为" serviceLayerContext",则在实例化并调用方法" startTransaction()"后会收到奇怪的错误: 脚本错误:调用函数'POST'失败[TypeError:this.contextHandle .startTransaction不是函数]。

这是我的代码,其中会重现此错误:

 var http = require('HttpModule.js');
//要求使用不同于ServiceLayerContext的名称
 var serviceLayerContext = require('ServiceLayerContext.js');

 函数GET()
 {
 }

 函数DELETE(){
 }

 函数PATCH(){
 }

 函数POST()
 {
    //实例化
     var slObj = new serviceLayerContext();

    //开始交易
     slObj.startTransaction();
    //立即回滚
     如果(slObj.isInTransaction())slObj.rollbackTransaction();

   /*设置HTTP响应*/
     http.response.setContentType(http.ContentType.APPLICATION_JSON);
     http.response.setStatus(http.HttpStatus.HTTP_OK);
     http.response.setContent({status:'success'});
     http.response.send();
 }
 

如果我调用此脚本,则会得到以下响应正文:

 {
     "错误":{
         "代码":512,
         "信息": {
             " lang":" zh-cn",
             "" value":"脚本错误:调用函数'POST'失败[TypeError:this.contextHandle.startTransaction不是函数]。"
         }
     }
 }
 

如果我将serviceLayerContext上下文重命名为ServiceLayerContext(例如slContext),一切都会顺利进行。

这是预期的行为还是我做错了什么?

示例2

在论坛和文档中的所有示例中,仅使用入口点功能。 在上传的JS文件中编写附加功能是否有限制? 原因如果我在方法函数之后编写函数,则会遇到意外行为(有时会导致错误,有时不会出错)。 通常是关于编译和意外令牌的错误(我得到了包括ILLEGAL在内的所有令牌的错误)

这是一个重现问题的代码示例:

 var http = require('HttpModule.js');

 函数GET(){
 }

 函数PATCH(){
 }

 函数DELETE(){
 }

 函数POST(){
    //测试要记录的对象
     var obj =
     {
 属性1:1
 属性2:是,
 Property3:"测试",
 Property4:函数(值){返回true;  },
 Property5:函数(值){返回true;  },
 Property6:函数(值){返回true;  },
 Property7:函数(值){返回true;  },
 Property8:函数(值){返回true;  },
 Property9:函数(值){返回true;  },
 Property10:函数(值){返回true;  },
 Property11:函数(值){返回true;  },
 Property12:函数(值){返回true;  },
 Property13:函数(值){返回true;  }
     };
    
     logObject('Test',obj);

   /*设置HTTP响应*/
     http.response.setContentType(http.ContentType.APPLICATION_JSON);
     http.response.setStatus(http.HttpStatus.HTTP_OK);
     http.response.setContent({result:'success'});
     http.response.send();
 }

//在日志文件中记录对象。 如果property是函数-将其记录为'Func'
 函数logObject(objName,obj)
 {
 var replacer =函数(键,值)
 {
//如果属性是函数,则获取'Func'值
 如果(typeof值==='函数')
 {
 返回'Func';
 }
 返回值
 };


 var stringToLog ='';
 尝试
 {
 stringToLog = JSON.stringify(obj,replacer,2);
 }
 赶上(exc)
 {
 stringToLog ='无法序列化对象';
 }


//日志字符串
 console.log(objName +':'+ stringToLog);
 }


 

如果我调用此脚本,则会收到以下响应:

 {
     "错误":{
         "代码":511,
         "信息": {
             " lang":" zh-cn",
             ""值":"脚本错误:编译错误[SyntaxError:意外的标识符]。"
         }
     }
 }
 

如果我在POST函数中移动函数的逻辑,一切都会顺利进行。

示例3:

此错误可能与进入点之外的函数和变量有关,但我对结果感到非常惊讶。 这是我的脚本文字:

//需要必要的实体
//需要处理http调用
 var http = require('HttpModule.js');
//调用SL实体/动作是必需的
 var ServiceLayerContext = require('ServiceLayerContext.js');
//实体代理对象
 var Customer = require('EntityType/BusinessPartner');

//结果对象
 var result = {
 IsSuccess:是的,
 ErrorMsg:",
 BookingSapCode:'',
 CustomerSapCode:"
 };

//输入对象的验证器
 var inputValidator =
 {
 BookingId:函数(值){返回true;  },
 BookingSapCode:函数(值){返回true;  },
 IsCanceled:函数(值){返回true;  },
 日期:函数(值){返回isNaN(Date.parse(value));  },
 电子邮件:函数(值){返回true;  },
 电话:函数(值){返回true;  },
 CustomerId:函数(值){返回true;  },
 标题:函数(值){返回true;  },
 名称:函数(值){返回true;  },
 姓:函数(值){返回true;  },
 CustomerSapCode:函数(值){返回true;  },
 CustomerSapSeries:函数(值){返回true;  },
 详细信息:函数(值)
 {
//检查是否为数组
 如果(!Array.isArray(value))返回false;

//实例化SL上下文
 var slContext = new ServiceLayerContext();

//对于每个ItemCode检查此项目是否存在
 value.forEach(函数(元素)
 {
 如果(!checkItemCode(element.SapItemCode,slContext))返回false;
 });

 返回true;
 }
 };

//===================================进入点===========  =======================================//

 函数GET(){

 }

 函数DELETE(){

 }


 函数PATCH(){

 }


 函数POST(){
 console.log('开始执行');

//获取请求的正文
 logObject('val',inputValidator);
 var inputObject = getBody(inputValidator);
 logObject('inputObj',inputObject); //记录输入对象以检查数据

   /*设置HTTP响应*/
     http.response.setContentType(http.ContentType.APPLICATION_JSON);
     http.response.setStatus(http.HttpStatus.HTTP_OK);
     http.response.setContent(result);
     http.response.send();
 }


//===================================私人功能==========  =======================================//


 函数checkItemCode(itemCode,slContext)
 {
 返回true;
 }


//===================================常见功能===========  =======================================//


//获取主体并通过传递的"验证器"验证结构。
//验证器将所有属性显示为验证函数
 函数getBody(validator)
 {
//尝试从身体获取数据
 var jsonObj = http.request.getJsonObj();
 如果(!jsonObj)
 {
         抛出http.ScriptException(http.HttpStatus.HTTP_BAD_REQUEST,"无法从请求有效内容中获取JSON格式的内容");
 }


//只有存在变量
     如果(typeofvalidator!=='undefined')
     {
     var错误= validateObject(jsonObj,验证器);
 logObject('错误',错误);
     如果(errors.length> 0)
     {
 抛出http.ScriptException(http.HttpStatus.HTTP_BAD_REQUEST,"输入对象无效:" + errors.join('|'));
     }
     }


//返回反序列化的主体
 返回jsonObj;
 }


//通过模式验证对象
 函数validateObject(object,schema){
 var错误= Object.keys(模式)
 .map(功能(属性)
 {
 varvalidator = {}; //属性的验证函数
 var isMissing = false;


 if(object [property] === undefined)//如果object没有此属性-函数总是返回false
 {
 验证程序=函数(值){return false};
 isMissing = true;
 }
 其他
 {
 验证者=模式[属性]; //获取验证功能
 }


 return {property:property,isValid:validator(object [property]),isMissing:isMissing};
 })
 .reduce(功能(错误,属性检查)
 {
 如果(propertyCheck.isValid ===否)
 {
 errors.push(propertyCheck.property +(propertyCheck.isMissing?"丢失。":"无效。"));
 }
    
 返回错误;
 },[]);
 返回错误;
 }


//在{SL Installation Path}/logs/script/*中记录对象
 函数logObject(name,obj)
 {
 var replacer =(键,值)=> {
//如果有函数,请给我们该函数的代码
 如果(typeof值==='函数')
 {
 返回'Func';
 }
 返回值
 };

//检查是否没有序列化错误
 var stringToLog ='';
 尝试
 {
 stringToLog = name +':'+ JSON.stringify(obj,replacer,2);
 }
 赶上(exc)
 {
 stringToLog = name +':无法序列化-'+排除;
 }

//日志字符串
 console.log(stringToLog);
 }

 

所以,我的想法是我要验证我的请求正文。 为此,我使用方法而不是属性声明了一个蓝图对象。 这种方法检查我的请求对象的数据。

但是,我总是会遇到一些缺少某些字段的异常情况。 这是我的回复:

 {
     "错误":{
         "代码":600,
         "信息": {
             " lang":" zh-cn",
             " value":"输入对象无效:缺少CustomerSapSereries。"
         }
     }
 }
 

但是我的架构对象中没有 CustomerSapSereries 属性。 因此,在测试期间,当我更改了一些代码段时(以我与此观点无关的拙见),我将一些属性重命名了(用Titltle代替Title和CustomerSerieses而不是CustomerSeries)。 这确实使我感到困惑,我很高兴对以下行为的原因做出任何澄清。

更新:

我猜想serviceLayerContext的问题是因为此变量在引擎中使用。

 function getContextHandle(){
         返回serviceLayerContext;
     }
 

付费偷看设置
发送
4条回答
粗暴的香蕉
1楼 · 2020-09-14 08:04.采纳回答

Sergey,谢谢您的提问。

将来,请将问题分为不同的问题。 您可能会以这种方式得到快速解答:)

示例1-脚本引擎中的保留名称

您已经发现了问题。 对于此类(无证件)案件,请随时通过树液支持举起事件。 我将领导我们的发展,以记录下这一限制。

示例2:附加函数声明

引擎期望每个HTTP方法有一个功能,就是这样。 这就是为什么您得到错误。 您可能可以 trick 带有函数表达式的编译器。 像

 var foo = function(bar){返回键* 2} 

像这样称呼

 foo(2)//返回4 

示例3:奇怪的错误消息

除了上一个示例中提到的内容外,我不知道这种情况的发生。 您可以处理其中的一些检查,例如应用程序上的" validobject"吗? 这样可以给您更多的控制权和更轻松的故障排除方法。

樱桃小丸子0093
2楼-- · 2020-09-14 07:50

嗨,Ralph,

感谢您的回答! 如果您不介意,我对您的答案还有其他疑问。

示例1:

谢谢,当我检查现有模块时,已经澄清了一点。 有保留的变量名称列表吗? 我敢打赌,这不是唯一会引发错误的人。 如果您可以与社区共享此列表,以防止脚本出现意外行为,我将不胜感激。

示例2:

感谢我在文档中没有找到任何限制的指针。 因此,如果我想重用一些代码块,比如说在POST和PATCH之间,我可以声明一个函数变量吗? 那是唯一的方法吗? 顺便说一句,我可以为此使用箭头功能吗? 喜欢:

 var foo =(bar)=> {返回键* 2;} 

相同的东西,但是我不确定它是否得到正式支持。

示例3:

那只是一个例子。 我想在服务器上添加此检查,以确保JSON是正确的,以防止更改客户端但忘记服务器的任何错误。 那只是一种情况,如果我可以使用变量但不能使用函数,我仍然可以做到这一点。

在此先感谢您。

太Q了
3楼-- · 2020-09-14 07:44

您好,Sergei,

感谢您提供的宝贵宝贵意见。
请注意9.3是从PL04开始正式发布的版本。
请考虑升级您的测试环境。

Thiago的致谢。

小灯塔
4楼-- · 2020-09-14 08:06

Thiago,您好,

感谢您的评论。 我非常感谢SAP在这个问题上的帮助。 我在本PL中的问题是否有任何变化? 我检查了变更日志,但没有发现任何相关内容。 我检查了此文档: https://help.sap.com/http .svc/rc/542eec5fd4454d988ce8fb0ebbcd8437/9.3/zh-CN/SAP_Business_One_93_TopResolutions.pdf

一周热门 更多>