1. 后端JSF函数开发说明

JSF函数采用javascript作为脚本语言, 支持ES 2017语法,只能使用javascript的基本功能,以及端提供的sdk函数。有关sdk函数说明参考附2: backend SDK函数

JSF按使用场景,有不同的上下文变量和返回值, 目前backend仅支持流程调用这一种后端场景函数, 实际在编写JSF函数时,只需要提供函数体即可。

2. 流程场景函数

流程场景函数,是在一个单据执行的工作流程过程中,可以调用的函数,比如单据生效后调用,单据弃审后调用等。

2.1. 场景函数的模板:

function ${funcName}(userContext, objectType, objectId, variables) {
    ${jsfContent}
}

2.2. 场景函数的参数说明

字段名称 字段说明 类型 必填 备注
userContext 只读当前用户上下文对象 object Y 当前调用的上下文对象, 不需要用户传递,为只读类型, 它包括的字段参考附1: 上下文对象
objectType 当前流程的单据对象类型 string Y -
objectId 当前流程的单据对象ID string Y -
variables 流程中设置的变量 object 它是和一KV结构, key为变量名,value为变量值对象(比如J: {"var1": {"type": "String", "value": "var1Value"}}

2.3. 场景函数返回值规则

返回值说明:通常的返回值格式如下:

    {
        status: "success|error|warning", //函数是否成功执行的状态
         code: "",  //如果执行不成功时,提供的错误码
         message: "",  //如果执行不成功时,提供的错误提示信息
         description: "",  //如果执行不成功时,提供的错误详细描述
         data: null,  //成功时需要返回的数据对象
         ars: null, //如果出错时,需要返回的其他错误数据
     }

返回会是的属性说明:

字段名称 字段说明 类型 必填 备注
status 执行函数状态 string Y 函数是否成功执行的状态, 取值为 success/error/warning
code 错误码 string - 如果执行不成功时,提供的错误码
message 错误信息 string - 如果执行不成功时,提供的错误提示信息
description 错误描述 string - 如果执行不成功时,提供的错误详细描述
data 返回的数据 any - 成功时需要返回的数据对象
args 错误附加参数 map - 如果出错时,需要返回的其他错误数据
logs 函数中输出的日志信息 array - 函数中输出的日志信息

如果JSF函数体没有返回数据,或者返回的数据中没有status字段,则默认jsf函数执行成功, 会设置status=success, 并将返回对象当前data, 即:

return {status: "success", data: {id:"123"}}; 等价于: return {id: "123"};');

2.4. 场景函数示例:

a) 收款单增加额外的逻辑检查,如果收款部门为’AA'并且收款金额>100时,检查不通过,打回单据,并显示错误信息为“XX部门收款不能超过100"。

if (objectType != 'Receipt') {
    return;
}
var result = await query(objectType, ['id'], `id = '${objectId}' and ownerDept.name = 'AA' and amount > 100`);
if (result.status != 'success') {
    return result;
}
if (result.data.length == 1) {
    return {
        status: 'error',
        message: 'AA部门收款不能超过100'
    };
}
return true;

说明: objectType, objectId为参数, query为backend SDK函数

b) 执行一个插入Comment的操作及删除自动插入的评论操作

return create('Comment', {
  objectType: objectType,
  objectId: objectId,
  content: '这是一个自动增加的评论'
});

c) 执行一个删除自动添加的评论的操作

var result = await query('Comment', ['id'], `objectType = '${objectType}' and objectId = '${objectId}' and content='这是一个自动增加的评论'`);
if (result.status != 'success') {
    return result;
}
if(result.data.length != 0){
  return remove('Comment', result.data[0].id);
}

d) 发票增加额外弃审检查,发票金额>1000,不允许弃审,并提供弃审错误信息“发票金额大于1000,不允许弃审”。

if (objectType != 'Invoice') {
    return;
}
var result = await query(objectType, ['id'], `id = '${objectId}' and amount > 1000`);
if (result.status != 'success') {
    return result;
}
if (result.data.length == 1) {
    return {
        status: 'error',
        message: '发票金额大于1000,不允许弃审'
    };
}
return true;

3. 附1: 上下文对象

上下文对象为JSF函数运行时上下文信息对象, 它包括以下内容:

{
    rootRequestId: string; //根请求ID, 如果当前请求是别的请求触发的,保存的别的请求的requestId, 以便输出日志时,用来跟踪调用链
    requestId: string; //当前请法求ID, 当前请求的唯一标识, 相同的requestId,以同样的参数调用时,后端会进行幂等处理,只响应第一次成功调用结果
    tenantId: string; //当前租户ID
    userId: string; //当前用户ID
    departmentId: string; //当前用户所属部门ID
    currentRoleId: string; //当前用户使用的角色ID
    currentOrgId: string; //当前的组织ID
    isDisableDataScope: boolean; //是否禁用数据权限
    roles: Map<string, boolean>; //当前用户具有的角色信息, key为角色ID, value表示该角色是否有管理员身份
}

4. 附2: backend SDK函数

目前backend sdk支持以下函数

  • 查询对象:query(objectType: string, fields: string[], criteriaStr: string, sorts: object, offset: number, limit: number, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>
  • 新增对象:create(objectType: string, data: object, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>
  • 修改对象: update(objectType: string, data: object, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>
  • 删除对象: remove(objectType: string, id: string, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>
  • Gql查询:graphql(gql: string, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>
  • 通用api调用: restapi(appName: string, method: string, url: string, data: object, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>
  • 新增变更单:change((objectType: string, data: object, headers: Map<string, string>): Promise<RestResponse>
  • 异步批量触发jsf函数:batch(objectType: string,execUserId:string,criteriaStr:string,bindVers:Map<String,Object>,batchSize:Integer,jsfDefName:string,remarks:string,headers:Map<string,string>): Promise<RestResponse>

其中返回值 RestResponse对象结构为:

{
    status: string;
    code: string;
    message: string;
    description: string;
    data: any;
    args: any;
}

字段说明如下:

字段名称 字段说明 类型 必填 备注
status 执行函数状态 string Y 函数是否成功执行的状态, 取值为 success/error/warning
code 错误码 string - 如果执行不成功时,提供的错误码
message 错误信息 string - 如果执行不成功时,提供的错误提示信息
description 错误描述 string - 如果执行不成功时,提供的错误详细描述
data 返回的数据 any - 成功时需要返回的数据对象
args 错误附加参数 map - 如果出错时,需要返回的其他错误数据

4.1. 查询对象 query:

query(objectType: string, fields: string[], criteriaStr: string, sorts: object, offset, limit: number, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>

参数说明:

字段名称 字段说明 类型 必填 备注
objectType 查询对象名 string Y
fields 查询的字段列表 string[] Y 至少指定一个字段
criteriaStr 查询条件表达式 string - 指定查询的eql条件表达式, 与postgresql sql条件表达式一致, 只字段使用的是对象属性名,并且支持级联(a.b.c), 不指定条件表示无条件查询
sorts 排序 object - 查询的排序,为要排序的字段列表, 结构示例:[{name: "name"} {name: "createdTime", isDesending: true}]
offset 查询起始行 integer - 从0开始的起始行,不指定表示从0开始
limit 返回最大的行数 integer - 不指定表示返回所有记录,但受系统最大行10000限制
asAdmin 以管理员权限运行 boolean - 如果不指定或者为false,表示以当前用户身份执行
headers 附加的请求头 Map<string,string> - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

成功执行后返回值中data值为查询的对象的数据列表

执行 query('User', ['id', 'name', 'createdTime'], "id='1'") 返回值示例:

{
  "status": "success",
  "code": null,
  "message": null,
  "description": null,
  "data": [
    {
      "id": "1",
      "name": "小企",
      "createdTime": 1626916982389
    }
  ],
  "args": null
}

4.1.1. 新增对象 create:

create(objectType: string, data: object, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>

参数说明:

字段名称 字段说明 类型 必填 备注
objectType 新增对象名 string Y
data 新增对象结构化数据 object Y 为一个Json对象,包括key为字段名,值为字段值的数据项
asAdmin 以管理员权限运行 boolean - 如果不指定或者为false,表示以当前用户身份执行
headers 附加的请求头 Map<string,string> - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

成功执行后返回值中data值新增加的对象的ID

执行 create('Role', {code: '001', name: 'manager'}) 返回值示例:

{
  "status": "success",
  "code": null,
  "message": null,
  "description": null,
  "data": "NEP8HV515KG0008",
  "args": null
}

执行 create('User', {code: '001', name: 'testuser'}) 执行出错返回值示例:

{
  "status": "error",
  "code": "0010",
  "message": "提交的数据存在问题",
  "description": "Object validation found 2 problems, error codes: [0011, baseapp-200108]",
  "data": null,
  "args": {
    "problems": {
      "default": {
        "ERROR": [
          {
            "fieldPath": "department",
            "type": "error",
            "code": "0011",
            "message": "字段的值必须指定"
          },
          {
            "fieldPath": "jobRelationships",
            "type": "error",
            "code": "baseapp-200108",
            "message": "用户任职记录中必须包含一条主职记录",
            "args": {
              "jobRelationships": "用户任职记录中必须包含一条主职记录"
            }
          }
        ]
      }
    }
  }
}

4.2. 修改对象 update:

update(objectType: string, data: object, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>

参数说明:

字段名称 字段说明 类型 必填 备注
objectType 新增对象名 string Y
data 修改对象结构化数据 object Y 为一个Json对象,包括key为字段名,值为字段值的数据项, 其中id必须指定,表示要修改的对象ID
asAdmin 以管理员权限运行 boolean - 如果不指定或者为false,表示以当前用户身份执行
headers 附加的请求头 Map<string,string> - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

执行 update('Role', {id: 'NEP8HV515KG0008', code: '001', name: 'manager2'}) 返回值示例:

{
  "status": "success",
  "code": null,
  "message": null,
  "description": null,
  "data": "",
  "args": null
}

4.3. 删除对象 remove:

remove(objectType: string, id: string, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>

参数说明:

字段名称 字段说明 类型 必填 备注
objectType 新增对象名 string Y
id 删除的对象的ID string Y
asAdmin 以管理员权限运行 boolean - 如果不指定或者为false,表示以当前用户身份执行
headers 附加的请求头 Map<string,string> - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

执行 remove('Role','NEP8HV515KG0008') 返回值示例:

{
  "status": "success",
  "code": null,
  "message": null,
  "description": null,
  "data": "",
  "args": null
}

执行 remove('Role','NEP8HV515KG0008') 出错返回值示例:

{
  "status": "error",
  "code": "0100",
  "message": "对象不存在或已被删除",
  "description": "entity Role not found: NEP8HV515KG0008",
  "data": null,
  "args": {
    "objectType": "Role",
    "objectId": "NEP8HV515KG0008"
  }
}

4.4. Gql查询 graphql:

graphql(gql: string, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>

参数说明:

字段名称 字段说明 类型 必填 备注
gql gql查询语法 string Y
asAdmin 以管理员权限运行 boolean - 如果不指定或者为false,表示以当前用户身份执行
headers 附加的请求头 Map<string,string> - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

执行 graphql('{User{id,name}}') 返回值示例:

{
  "status": "success",
  "code": null,
  "message": null,
  "description": null,
  "data": {
    "User": [
      {
        "id": "1",
        "name": "小企"
      }
    ]
  },
  "args": null,
  "logs": []
}

执行 graphql('{User{id,name1}} 出错返回值示例:

{
  "status": "error",
  "code": "400",
  "message": "查询出错",
  "description": "[{\"message\":\"Validation error of type FieldUndefined: Field 'name1' in type 'UserSchemaType' is undefined\",\"locations\":[{\"line\":1,\"column\":10}],\"description\":\"Field 'name1' in type 'UserSchemaType' is undefined\",\"validationErrorType\":\"FieldUndefined\"}]",
  "data": null,
  "args": null,
  "logs": []
}

4.5. 通用api调用 restapi:

restapi(appName: string, method: string, url: string, data: object, asAdmin: boolean, headers: Map<string, string>): Promise<RestResponse>

该方法为支持特定的场景使用的方法,可以访问租户服务的api, 调用成功后,返回值的data中为接口实际的返回结果。

参数说明:

字段名称 字段说明 类型 必填 备注
appName restapi所在的服务名,eg: baseapp string Y
method 请求类型:get,post,put,delete string Y
url restapi相对于服务的url, 比如:"/User/1" string Y
data 主求数据 string - 如果是get提供的是kv值对照,做为url查询参数, 其他方式请求为提供的json数据
asAdmin 以管理员权限运行 boolean - 如果不指定或者为false,表示以当前用户身份执行
headers 附加的请求头 Map<string,string> - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

执行 restapi('graphql', 'post', '/', {query:'{User{id,name}}'}) 返回值示例:

{
  "status": "success",
  "code": null,
  "message": null,
  "description": null,
  "data": {
    "data": {
      "User": [
        {
          "id": "1",
          "name": "小企"
        }
      ]
    },
    "errors": []
  },
  "args": null,
  "logs": []
}

4.6. 新增变更单 change:

change(objectType: string, data: object, headers: Map<string, string>): Promise<RestResponse>

change 函数支持: 自定义单据新增变更单

参数说明:

字段名称 字段说明 类型 必填 备注
objectType 新增变更单对象 string Y
data 对象结构化数据 object Y 数据以增量形式来提交,其中baseBillId 和baseBillItemId无需指定,系统会自动根据id 补齐,和修改接口参数一致
headers 附加的请求头 Map - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

执行 change('CsZiDingYiBianGengDan01', {id: 'NEP8HV515KG0008', code: '001', name: 'manager2'}) 返回示例值:

{
    "status":"success",
    "code":null,
    "message":null,
    "description":null,
    "data":"SXTF6662XC500EH", // 新增的变更单id
    "args":null
}

执行 change('CsZiDingYiBianGengDan01', {id: 'NEP8HV515KG0008', code: '001', name: 'manager2'}) 执行出错返回值示例:

{
    "status":"error",
    "code":"500",
    "message":"服务器端运行您的请求出现错误!",
    "description":"post http://inventory/inventory/PickingApply/changeBill: NoSuchElementException No value present",
    "data":null,
    "args":null
}

4.7. 异步批量触发jsf函数 batch:

batch(objectType: string,execUserId:string,criteriaStr:string,bindVers:Map<String,Object>,batchSize:Integer,jsfDefName:string,remarks:string,headers:Map<string,string>): Promise<RestResponse>

异步批量触发jsf函数。当jsf 函数批量处理大量数据时,可以考虑使用此函数来拆分,防止jsf 函数执行超时。

参数说明:

字段名称 字段说明 类型 必填 备注
objectType jsf 待处理的对象 string Y
execUserId 执行人 string Y 以执行人的身份触发jsf 函数
criteriaStr 包含占位符的gql查询条件 string Y
headersbindVars 查询条件中的占位符绑定变量 Map -
batchSize 每批数据量大小 Integer - 默认值10
jsfDefName jsf 函数名 string Y 异步批量调用的jsf 函数
remarks 备注 string -
headers 附加的请求头 Map - 可以指定附件的请求头,目前支持: Ignore-Warn=true, 表示忽略警告错误

执行 batch("CsZiDingYiBianGengDan01", "GK63GT50E7U0032", "billFullStatus=:billStatusTest", { billStatusTest: "BillStatus.draft" }, 1, "testJsfDSL", "测试一下", null); 返回示例值:

{
  "status":"success",
      "code":null,
      "message":null,
      "description":null,
      "data":"J1SF6662XC5007X", // 用于查询异步任务的执行情况
      "args":null
}

可以根据返回的J1SF6662XC5007X 使用 GQL 查看异步任务的执行情况

{
  JsfBatch(criteriaStr:"id='J1SF6662XC5007X'") {
  id
  backlogNbr // 按criteriaStr查询出的符合条件的记录总数
  asyncTaskId
  asyncTask{
  beanName
  params
  isCompleted
  successRate
  asyncTaskItems{
  batchNo
  lastErrorMsg
}
}
}
}

执行 batch("CsZiDingYiBianGengDan01", "GK63GT50E7U0032", "billFullStatus=:billStatusTest", { billStatusTest: "BillStatus.draft" }, 1, "testJsfDSL", "测试一下", null); 执行出错返回值示例:

{
  "status":"error",
      "code":"500",
      "message":"服务器端运行您的请求出现错误!",
      "description":"post http://baseapp/baseapp/JsfBatch: StringIndexOutOfBoundsException String index out of range: -1",
      "data":null,
      "args":null
}

results matching ""

    No results matching ""