创建模块数据
  版本: 1.2 | 发布日期: 07/02/2024
# 引言
创建模块单据基本上有两种方法。
第一种方法是根据模块数据字典的格式从头开始构建,并填写所有必要信息。
第二种方法是通过API获取一个完全空白的结构,然后查阅数据字典来填写必要的字段。
我们建议采用后一种方法。
# 目的
阅读本章后,你应该能够:
- 通过 Web 服务创建模块单据
 - 了解 aiM18 中的数据字典
 - 掌握创建模块单据的最佳做法
 
# 场景
Chris Wong 是 ABC 水果公司的 IT 经理。顾客可以在网上商店订购水果:


Chris 每天收集从网上商店收到的订单,并将数据传递给销售部门,以便将数据输入 aiM18 ERP 系统。
销售部经理抱怨数据量太大。
手动输入数据非常耗时。
除了使用 aiM18 ERP 系统提供的导入功能外,Chris 还决定在保存实体服务的帮助下自动执行这一流程。
# 参考文档
以下内容演示了如何将 单据 保存到特定模块。
请参阅完整文档.
HTTP 请求
PUT http://[server]/jsf/rfws/entity/s/save/[module]?menuCode=[menuCode]
参数
| 名字 | 类型 | 说明 | 
|---|---|---|
| authorization | String(Header) |  必填. 通过 OAuth 获取的访问令牌 | 
| client_id | String(Header) |  必填. aiM18 授权应用列表中的Client ID | 
| module | String(Path) |  必填. 模块类型,例如‘员工’,可以在数据字典中找到 | 
| menuCode | String(Query) |  必填. 菜单编号,例如‘员工’,可以在数据字典中找到 | 
| param | jsonString(Query) |  特殊操作的附加参数 | 
| entity | jsonString(Query) |  简化的实体 JSON,结构请参考下文。请注意,JSON需要使用 URL 编码. | 
| entitys_in_entity | String(Body) |  简化的实体 JSON,结构请参考下文。建议在请求体中传实体 JSON。如果要处理多个实体,请传一个简化的实体 JSON 数组。 | 
大多数参数都很直观,可以从字面上理解。
如果找不到authorization和client_id,请查看 此处。
下面我们将重点解释的参数是entity。
entity基本上是一个包含你要保存的表和值的 JSON。
通常我们通过 JSON 化 SqlEntity 来获取它。
{
	"employeepic": {
			"values": [ ]
	},
	"employee_attach": {
			"values": [ ]
	},
	"employee": {
			"values": [
				{"code": "000171","desc": "abcd"}
			]
	}
}
通过利用 aiM18 中提供的数据字典,你可以获得模块所需的所有表信息。
在这种情况下,我们需要填写表Sales Order 和 S.O. (Product)。

Sales Order 的表名是 mainso.

为了成功保存SqlEntity,我们至少必须输入所有标记的必填字段。
所有其他字段都是可选的。
示例数据如下
{
	"mainso": {
	  "values": [
		{
		  "flowTypeId": 1,
		  "code": "MYDEMOSO_001",
		  "tDate": "2018-08-10 00:00:00",
		  "cusId": 1,
		  "curId": 2,
		  "rate": 7.5,
		  "staffId": 11
		}
	  ]
	}
}
FAQ 1:
如何找出 cusId(客户)?转到常见问题解答部分查看解决方案。
S.O. (Product) 的表名是 sot.

同样,先填写必填字段,再填写可选字段。
示例数据如下
{
	"mainso": {
	  "values": [
		 "flowTypeId": 1,
		 "code": "MYDEMOSO_001",
		 "tDate": "2018-08-10 00:00:00",
		 "cusId": 1,
		 "curId": 2,
		 "rate": 7.5,
		 "staffId": 11
	  ]
	},
	"sot": {
	  "values": [
		{
			"proId": 1,
			"unitId": 2,
			"qty": 10
		},
		{
			"proId": 2,
			"unitId": 3,
			"qty": 7
		}
	  ]
	}
}
FAQ 2:
如何找出 proId (产品) 或 unitId (产品单位)?转到常见问题解答部分查看解决方案。
现在你应该准备好提交你的请求了。
回到场景,Chris 将网上商店与 aiM18 Web服务集成。

订单确认后,会向 aiM18 ERP 系统发送以下 HTTP 请求。
销售订单自动保存。
相应请求:
MediaType jsonMT = MediaType.parse("application/json; charset=utf-8");
RequestBody rb = RequestBody.create(jsonMT,
{
       "sot": {
		   "values": [
				{ "proId": "1",  "qty": "5",  "unitId": "1" },
				{ "proId": "2",  "qty": "4",  "unitId": "1" },
				{ "proId": "3",  "qty": "2",  "unitId": "1" },
				{ "proId": "4",  "qty": "10",  "unitId": "1" }
		   ]
       },
       "mainso": {
		   "values": [
			   {
				   "flowTypeId": "1",
				   "code": "OLDSOOO1",
				   "tDate": "2018-01-01 00:00:00",
				   "cusId": "1", "curId": "1",
				   "rate": "1", "staffId": "1"
			   }
		   ]
       }
}
Request request = new Request.Builder()
       .url("http://[server]]/jsf/rfws/entity/s/save/oldso?menuCode=oldso")
       .put(formBody)
       .addHeader("authorization", "Bearer MjZhZGNjMDctODVhZS00MmE0LWI3ZmEtNzRhMTQ")
       .addHeader("client_id", "C-SGF2aWQncyBhcHBsaWNhdGlvbjIwMTctMDItMTAxNjc=")
       .addHeader("cache-control", "no-cache")
       .build();
Response response = client.newCall(request).execute();
相应响应:
HttpResponseProxy{
HTTP/1.1 200 OK
[
   Connection: keep-alive,
   X-Powered-By: Undertow/1,
   Server: WildFly/9,
   Content-Type: application/json;charset=UTF-8,
   Content-Length: 2,
   Date: Thu, 09 Aug 2018 04:59:18 GMT
]
ResponseEntityProxy {
[
   Content-Type: application/json;charset=UTF-8,
   Content-Length: 2,
   Chunked: false
]}
}
# 最佳做法
虽然你可以通过数据字典获取模块的所有表和字段信息,但这种方法仍然有点麻烦。
创建模块单据的最佳做法是通过另一个 API 获取一个空结构并用数据填充它。
步骤如下:
- 通过API获取空结构
 - 如果你使用 Java 编程,你可以将 前面的 API 返回的 JSON 结果直接转换为 SqlEntity
 - 操作 SqlEntity,例如修改值和填充表的行
 - 将 SqlEntity 转换为 JSON 格式,这是保存实体服务的
entity参数。 
# FAQ
- 如何找出那些 xxxxId?
 
提供了用于查找 ID 的 Web 服务
详细教程请参考通过编号获取Id Web服务或搜索数据。
- 如何从响应中了解错误信息?
 
具体原因可阅读 error_info.messageData.info_desc。
如果不够清楚,请咨询我们的支持人员并从您的回复中向我们提供以下错误消息。
{
    error_info: {
	 "autoClose":true
	 "closable":true
	 "delayClose":3000,
	 "detailSet":false,
	 "htmlMessage":false,
	 "locator": [ {"locator":"sot.qty."2"} ],
	 "messageData": {
		 "exception":"", "htmlMessage":false
		 "id":101203,
		 "info_desc":"<Quantity> of <Product> cannot be 0",
		 "jsonStr":"",
		 "key":"ce01_core_101203",
		 "locators": [ {
				 "colName":"qty",
				 "id":0,
				 "locatorKey":"sot.qty.2",
				 "row":2,
				 "tableName":"sot",
				 "type":"Field" } ],
		 "pass":false,
		 "trace":"
				  [TradeModuleChecker.checkSetting_791]-
				  [CheckerLib.runChecker_225]-
				  [CawEntityCurdAction.updateEntity_107]-
				  [CawEntityInterceptor.logCall_42]-
				  [view129.updateEntity_-1]
		 ",
		 "type":"Error"
	 },
	 "messageKey":"ce01_core_101203",
	 "type":"ERROR"
     }
}