本文介绍了在K/3 Cloud系统中,如何使用Web API接口构建参数以保存采购订单,并详细演示了如何设置单据头和单据体中的各个字段参数。示例代码提供了如何构建JSON格式的请求参数,并通过ApiClient调用登录和保存接口的方法。代码强调了字段Key大小写敏感性、基础资料字段的填值方式,以及如何创建与源单之间的关联关系。最终,通过调用Execute方法保存采购订单并返回结果。
需求背景:
K/3 Cloud提供了Web API接口,供第三方程序调用,以实现与第三方系统之间的数据集成。
调用Web API接口虽然简单,但是构建参数却非常复杂,与各单据上的字段密切相关。
K/3 Cloud内置了一个Web API接口说明功能,提供了示例代码,演示如何调用各单据的各种操作。
遗憾的是,示例代码中的参数,包含了全部单据头字段,但没有包括单据体字段,完全按照此示例代码调用接口,往往会保存失败。
案例说明:
本案例,基于采购订单的保存接口,演示如何构建各种字段参数,单据体字段参数。
以便读者在K/3 Cloud内置的Web API接口示例代码基础上,据此类推,自行构建出各种单据,Web API保存接口需要的,包含了单据体字段的完整参数。
为方便阅读,本案例仅构建了采购订单必须的字段参数,其他类似的字段,直接忽略。
示例代码:
//*********************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Newtonsoft.Json.Linq;
using Kingdee.BOS.WebApi.Client;
//*********************************************************
///
/// 采购订单
///
private string Sample2015121401()
{
try
{
// K/3 Cloud业务站点URL
// using Kingdee.BOS.WebApi.Client; // (需引用Kingdee.BOS.WebApi.Client.dll)
ApiClient client = new ApiClient(this.txtWebSite.Text);
// 调用登录接口:
// 参数说明:
// dbid : 数据中心id。到管理中心数据库搜索:
// select FDataCenterId, * from T_BAS_DataCenter
// userName : 用户名
// password :原始密码(未加密)
// loid : 语言id,中文为2052,中文繁体为3076,英文为1033
var loginResult = client.Login(
this.txtDbId.Text,
this.txtUser.Text,
this.txtPassword.Text,
2052);
string result = "登录失败,请检查与站点地址、数据中心Id,用户名及密码!";
// 登陆成功,开始保存数据
if (loginResult == true)
{
// 开始构建Web API参数对象
// 参数根对象:包含Creator、NeedUpDateFields、Model这三个子参数
// using Newtonsoft.Json.Linq; // (需引用Newtonsoft.Json.dll)
JObject jsonRoot = new JObject();
// Creator: 创建用户
jsonRoot.Add("Creator", "Demo");
// NeedUpDateFields: 哪些字段需要更新?为空则表示参数中全部字段,均需要更新
jsonRoot.Add("NeedUpDateFields", new JArray(""));
// Model: 单据详细数据参数
JObject model = new JObject();
jsonRoot.Add("Model", model);
// 开始设置单据字段值
// 必须设置的字段:主键、单据类型、主业务组织,各必录且没有设置默认值的字段
// 特别注意:字段Key大小写是敏感的,建议从BOS设计器中,直接复制字段的标识属性过来
// 单据主键:必须填写,系统据此判断是新增还是修改单据;新增单据,填0
model.Add("FID", 0);
// 采购组织:必须填写,是基础资料字段
JObject basedata = new JObject();
basedata.Add("FNumber", "101.2");
model.Add("FPurchaseOrgId", basedata);
// 单据类型:必须填写,是基础资料字段
// 基础资料类型字段填值,必须再构建一个JObject对象,设置基础资料编码
basedata = new JObject();
basedata.Add("FNumber", "CGDD01_SYS");
model.Add("FBillTypeID", basedata);
// 单据编号:可以忽略,由系统根据编码规则自动生成
model.Add("FBillNo", "JDCGDD1605190001");
//采购日期(FDate)
model.Add("FDate", DateTime.Today);
// 录入业务上要求必须提前设置的字段
// 这些字段通常无需由用户手工录入,提前设好默认值,如汇率类型、本位币等
// 汇率类型(FExchangeTypeId):基础资料
basedata = new JObject();
basedata.Add("FNumber", "HLTX01_SYS");
model.Add("FExchangeTypeId", basedata);
// 本位币(FLocalCurrId):基础资料
basedata = new JObject();
basedata.Add("FNumber", "PRE001");
model.Add("FLocalCurrId", basedata);
// 按手工录入顺序,录入其他关键业务字段
// 供应商(FSupplierId):基础资料
basedata = new JObject();
basedata.Add("FNumber", "VEN00002");
model.Add("FSupplierId", basedata);
// 其他单据头字段,非必录,本示例代码忽略
// 开始构建单据体参数:集合参数JArray
JArray entryRows = new JArray();
// 把单据体行集合,添加到model中,以单据体Key为标识
string entityKey = "FPOOrderEntry";
model.Add(entityKey, entryRows);
// 通过循环创建单据体行:示例代码仅创建一行
for (int i = 0; i <= 0; i++)
{
// 添加新行,把新行加入到单据体行集合
JObject entryRow = new JObject();
entryRows.Add(entryRow);
// 给新行,设置关键字段值
// 单据体主键:必须填写,系统据此判断是新增还是修改行
entryRow.Add("FEntryID", 0);
//物料(FMaterialId):基础资料,填写编码
basedata = new JObject();
basedata.Add("FNumber", "1.01.001.0070");
entryRow.Add("FMaterialId", basedata);
// 单位(FUnitId):基础资料,填写编码
basedata = new JObject();
basedata.Add("FNumber", "Pcs");
entryRow.Add("FUnitId", basedata);
// 数量(FQty):数量字段
entryRow.Add("FQty", 10);
// 单价(FPrice):单价字段
entryRow.Add("FPrice", 11.7);
// 其他单据体字段,非必录,本示例代码忽略
// 创建与源单之间的关联关系,以支持上查与反写源单
// 本示例演示创建与采购申请单之间的关联关系
// 源单类型、源单编号
entryRow.Add("FSrcBillTypeId", "PUR_Requisition");
entryRow.Add("FSrcBillNo", "CGSQ000009");
// 创建Link行集合
JArray linkRows = new JArray();
// 添加到单据体行中:Link子单据体标识 = 关联主单据体标识(POOrderEntry) + _Link
string linkEntityKey = string.Format("{0}_Link", entityKey);
entryRow.Add(linkEntityKey, linkRows);
// 创建Link行:
// 如有多条源单行,则分别创建Link行记录各条源单行信息
JObject linkRow = new JObject();
linkRows.Add(linkRow);
// 填写Link行上的字段值
// 特别说明:Link子单据体上字段的标识,必须在前面增加子单据体标识
// FFlowId : 业务流程图,可选
string fldFlowIdKey = string.Format("{0}_FFlowId", linkEntityKey);
linkRow.Add(fldFlowIdKey, "");
// FFlowLineId :业务流程图路线,可选
string fldFlowLineIdKey = string.Format("{0}_FFlowLineId", linkEntityKey);
linkRow.Add(fldFlowLineIdKey, "");
// FRuleId :两单之间的转换规则内码,必填
// 可以通过如下SQL语句到数据库获取
// select FID, *
// from T_META_CONVERTRULE
// where FSOURCEFORMID = 'PUR_Requisition'
// and FTARGETFORMID = 'PUR_PurchaseOrder'
// and FDEVTYPE = 0;
string fldRuleIdKey = string.Format("{0}_FRuleId", linkEntityKey);
linkRow.Add(fldRuleIdKey, "PUR_Requisition-PUR_PurchaseOrder");
// FSTableName :必填,源单单据体表格编码,通过如下语句获取:
// SELECT FTableNumber
// FROM t_bf_tabledefine
// WHERE fformid = 'PUR_Requisition'
// AND fentitykey = 'FEntity'
// 如果如上语句未返回结果,请到K/3 Cloud中,手工选单一次,后台会自动产生表格编码
string fldSTableNameKey = string.Format("{0}_FSTableName", linkEntityKey);
linkRow.Add(fldSTableNameKey, "T_PUR_ReqEntry");
// FSBillId :必填,源单单据内码
string fldSBillIdKey = string.Format("{0}_FSBillId", linkEntityKey);
linkRow.Add(fldSBillIdKey, 100011);
// FSId : 必填,源单单据体行内码。如果源单主关联实体是单据头,则此属性也填写源单单据内码
string fldSIdKey = string.Format("{0}_FSId", linkEntityKey);
linkRow.Add(fldSIdKey, 100029);
// FEntity_Link_FBaseQtyOld :数量原始携带值,下推时,从源单带了多少下来 // 在合并下推时,系统会把多个源行的数量,合并后填写在单据体数量字段上的;
// 合并后对各源单行的反写,需要使用合并前的数量进行反写,也就是本字段上记录的数量
// 因此,如果有合并下推,本字段就必须填写,否则反写不准确
// 如果没有合并下推,单据体数量会直接反写到唯一的源行上,本字段就不需填写
string fldBaseQtyOldKey = string.Format("{0}_FBaseUnitQtyOld", linkEntityKey);
linkRow.Add(fldBaseQtyOldKey, 10);
// FEntity_Link_FBaseQty :数量实际携带值,下推后,用户可以手工修改数量值;此字段存储最终的数量值
// 可选字段:
// 在保存时,系统会自动把单据体上数量值,更新到此字段;因此,这个字段可以不用填写(即使填写了,也会被覆盖)
string fldBaseQtyKey = string.Format("{0}_FBaseUnitQty", linkEntityKey);
linkRow.Add(fldBaseQtyKey, 10);
}
// 调用Web API接口服务,保存采购订单
result = client.Execute
"Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save",
new object[] {"PUR_PurchaseOrder", jsonRoot.ToString() });
}
return result;
}
catch(Exception exp)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("程序运行遇到了未知的错误:");
sb.Append("错误提示:").AppendLine(exp.Message);
sb.Append("错误堆栈:").AppendLine(exp.StackTrace);
return sb.ToString();
}
}
推荐阅读