金蝶K3Cloud(星空)销售订单导入二次开发
一、前言
公司采购,购买使用了金蝶K3Cloud的ERP系统。把财务,供应链,销售,仓库等都在上面做了。但是另一方面,标准化的东西很难适合所有的公司,都会或多或少的进行简单的二次开发。而金蝶官方的二次开发费用又高得吓人。而且,公司需求也会一直变,不可能每次都要找原厂的人来开发。所以2018年6月的时候,公司付费,参加了金蝶总部的一场三天培训。也只是学了一点皮毛。
二、需求
目前公司采用我用Java开发的客服销售系统。提供给外网客户进行在线下单。同时,需要每隔一段时间,同步外网的订单到金蝶的K3系统中,实现半自动化。我是通过两种方式进行二次开发的。跟他们推荐的那种用C#写dll插件不一样,我由于是半路出家,采用的是非侵入式二次开发。就是通过WebAPI进行订单的导入。再通过直接查询SQLServer数据库的方式,查询销售出库数据,展示给客户和做数据分析。
三、WebAPI介绍
1. 新建一个普通的C# winform工程
添加引用,【Kingdee.BOS.WebApi.Client.dll】这个可以到K3的安装目录下搜索找到这个dll库。
2. 查询当前数据中心(账套)ID
在登录的时候,点击【查看http数据】
3. 查询当前请求业务对象ID和对应参数
这个WebAPISDK功能,需要是administrator管理员权限的才有对应的菜单。
比如选中一个功能,就可以看到对应的参数说明和示例
由于不同的公司,对应的业务数据和字段不太一样。所以,还可以通过点击上面的【在线测试WebAPI】,进行数据生成
四、代码部分
下面是举例,我的部分代码
登录和退出
1 /// <summary> 2 /// 登陆 3 /// </summary> 4 /// <param name="conf"></param> 5 /// <returns></returns> 6 public static K3CloudApiClient K3Login(ConfigModel conf) 7 { 8 K3CloudApiClient client = new K3CloudApiClient(conf.CONF_URL); 9 bool loginResult = client.Login(conf.CONF_DBID, conf.CONF_USERNAME, 10 conf.CONF_PASSWORD, conf.CONF_ICID ); 11 if (!loginResult) 12 { 13 return null; 14 } 15 return client; 16 } 17 /// <summary> 18 /// 登出 19 /// </summary> 20 /// <param name="client"></param> 21 public static void K3Logout(K3CloudApiClient client) 22 { 23 if(client != null) 24 { 25 client.Logout(); 26 } 27 }
检查物料是否存在
1 /// <summary> 2 /// 检查该物料在K3系统中是否存在 3 /// </summary> 4 /// <param name="client"></param> 5 /// <param name="chipname">型号</param> 6 /// <returns></returns> 7 public static Boolean checkChipname(K3CloudApiClient client, string chipname) 8 { 9 string responseData = string.Empty; 10 string formid = "BD_MATERIAL"; 11 string requestData = "{\"CreateOrgId\":\"0\",\"Number\":\"" + chipname + "\",\"Id\":\"\"}"; 12 responseData = client.View(formid, requestData); 13 Dictionary<string, object> mate = getObject(responseData); 14 string status = getJSONValue(mate, "Result"); 15 mate = getObject(status); 16 status = getJSONValue(mate, "ResponseStatus"); 17 if(status == null || status == "") 18 { 19 return true; 20 } 21 mate = getObject(status); 22 string ret = getJSONValue(mate, "IsSuccess"); 23 ret = ret.ToUpper(); 24 if(ret == "FALSE") 25 { 26 return false; 27 } 28 return true; 29 }
根据编码获取对应客户信息
1 /// <summary> 2 /// 获取K3系统中厂商信息 3 /// </summary> 4 /// <param name="client"></param> 5 /// <param name="cust_id"></param> 6 /// <returns></returns> 7 public static CustomerModel getCustomerModel(K3CloudApiClient client, string cust_id) 8 { 9 CustomerModel model = new CustomerModel(); 10 string responseDate = string.Empty; 11 string formid = "BD_Customer"; 12 string requestData = "{\"CreateOrgId\":\"0\",\"Number\":\"" + cust_id + "\",\"Id\":\"\"}"; 13 responseDate = client.View(formid, requestData); 14 Dictionary<string, object> cust = getObject(responseDate); 15 string tmp = getJSONValue(cust, "Result"); 16 cust = getObject(tmp); 17 string status = getJSONValue(cust, "ResponseStatus"); 18 if (status != null && status != "") 19 { 20 MessageController.showErrorMessage("厂商ID:[" + cust_id + "]错误,请确认"); 21 return null; 22 } 23 tmp = getJSONValue(cust, "Result"); 24 cust = getObject(tmp); 25 tmp = getJSONValue(cust, "BD_CUSTCONTACT"); 26 List<Dictionary<string, object>> contacts = getListObject(tmp); 27 string addr = ""; 28 string addr_id = ""; 29 string fname = ""; 30 string loc_id = ""; 31 for(int i=0; i<contacts.Count; i++) 32 { 33 if(addr_id == "") 34 { 35 addr_id = getJSONValue(contacts[i], "NUMBER"); 36 } 37 if(addr == "") 38 { 39 addr = getJSONValue(contacts[i], "ADDRESS"); 40 } 41 tmp = getJSONValue(contacts[i], "TContact"); 42 Dictionary<String, object> cont = getObject(tmp); 43 if (cont == null) continue; 44 if(loc_id == "") 45 { 46 loc_id = getJSONValue(cont, "Number"); 47 tmp = getJSONValue(cont, "Name"); 48 List<Dictionary<string, object>> name = getListObject(tmp); 49 if (name.Count >= 1) 50 { 51 fname = getJSONValue(name[0], "Value"); 52 } 53 } 54 } 55 56 model.addr = addr; 57 model.addr_id = addr_id; 58 model.cust_id = cust_id; 59 model.fname = fname; 60 model.loc_id = loc_id; 61 62 return model; 63 }
保存销售订单
1 /// <summary> 2 /// 保存订单信息 3 /// </summary> 4 /// <param name="client"></param> 5 /// <param name="order"></param> 6 /// <returns></returns> 7 public static Boolean saveK3SaleOrder(K3CloudApiClient client, K3SaleOrderModel order) 8 { 9 string formid = "SAL_SaleOrder"; 10 string requestData = JsonConvert.SerializeObject(order); 11 string responseData = client.Save(formid, requestData); 12 Dictionary<string, object> result = getObject(responseData); 13 string tmp = getJSONValue(result, "Result"); 14 result = getObject(tmp); 15 string status = getJSONValue(result, "ResponseStatus"); 16 Dictionary<string, object> res = getObject(status); 17 string isSuccess = getJSONValue(res, "IsSuccess"); 18 isSuccess = isSuccess.ToUpper(); 19 Boolean flag = false; 20 if(isSuccess == "TRUE") 21 { 22 string number = getJSONValue(result, "Number"); 23 RET_MESSAGE = "导入成功订单号:[" + number + "]"; 24 flag = true; 25 } 26 else 27 { 28 string errors = getJSONValue(res, "Errors"); 29 RET_MESSAGE = errors; 30 } 31 //打印日志 32 return flag; 33 }
上面这个保存订单,最关键的还是 K3SaleOrderModel 这个模型,这个模型要跟上面WebAPI示例里面返回的字段一一对应。才能保证保存订单成功。
K3SaleOrderModel
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SaleOrderTool.Model 7 { 8 /// <summary> 9 /// K3销售订单 完整提交模型 10 /// </summary> 11 class K3SaleOrderModel 12 { 13 public K3SaleOrderModel() 14 { 15 this.Model = new K3SaleOrderBillModel(); 16 } 17 public string Creator { get; set; } 18 public List<FNumberModel> NeedUpDateFields { get; set; } 19 public List<FNumberModel> NeedReturnFields { get; set; } 20 public string IsDeleteEntry { get; set; } 21 public string SubsystemId { get; set; } 22 public string IsVerifyBaseDataField { get; set; } 23 public K3SaleOrderBillModel Model { get; set; } 24 } 25 }
K3SaleOrderBillModel
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SaleOrderTool.Model 7 { 8 /// <summary> 9 /// K3销售订单 订单模型 10 /// </summary> 11 class K3SaleOrderBillModel 12 { 13 public K3SaleOrderBillModel() 14 { 15 this.FBillTypeID = new FNumberModel(); 16 this.FSaleOrgId = new FNumberModel(); 17 this.FCustId = new FNumberModel(); 18 this.FHeadDeliveryWay = new FNumberModel(); 19 this.FReceiveId = new FNumberModel(); 20 this.FHeadLocId = new FNumberModel(); 21 this.FCorrespondOrgId = new FNumberModel(); 22 this.FSaleDeptId = new FNumberModel(); 23 this.FSaleGroupId = new FNumberModel(); 24 this.FSalerId = new FNumberModel(); 25 this.FSettleId = new FNumberModel(); 26 this.FReceiveContact = new FNameModel(); 27 this.FChargeId = new FNumberModel(); 28 this.FSalePhaseID = new FNumberModel(); 29 this.F_PAEZ_Base = new FNumberModel(); 30 this.FSaleOrderFinance = new FSaleOrderFinanceModel(); 31 this.FSaleOrderEntry = new List<FSaleOrderEntryModel>(); 32 } 33 public string Fid { get; set; } 34 public FNumberModel FBillTypeID { get; set; } 35 public string FBillNo { get; set; } 36 public string FDate { get; set; } 37 public FNumberModel FSaleOrgId { get; set; } 38 public FNumberModel FCustId { get; set; } 39 public FNumberModel FHeadDeliveryWay { get; set; } 40 public FNumberModel FReceiveId { get; set; } 41 public FNumberModel FHeadLocId { get; set; } 42 public FNumberModel FCorrespondOrgId { get; set; } 43 public FNumberModel FSaleDeptId { get; set; } 44 public FNumberModel FSaleGroupId { get; set; } 45 public FNumberModel FSalerId { get; set; } 46 public string FReceiveAddress { get; set; } 47 public FNumberModel FSettleId { get; set; } 48 public FNameModel FReceiveContact { get; set; } 49 public FNumberModel FChargeId { get; set; } 50 public string FNetOrderBillNo { get; set; } 51 public int FNetOrderBillId { get; set; } 52 public int FOppID { get; set; } 53 public FNumberModel FSalePhaseID { get; set; } 54 public Boolean Fisinit { get; set; } 55 public string FNote { get; set; } 56 public Boolean FIsMobile { get; set; } 57 public FNumberModel F_PAEZ_Base { get; set; } 58 public FSaleOrderFinanceModel FSaleOrderFinance { get; set; } 59 public List<FSaleOrderEntryModel> FSaleOrderEntry { get; set; } 60 } 61 }
其他的Model 略
五、其他
从网上下载了一份Java的WebAPI调用参考代码
InvokeHelper.java
1 import java.io.BufferedReader; 2 import java.io.DataOutputStream; 3 import java.io.InputStreamReader; 4 import java.net.HttpURLConnection; 5 import java.net.URL; 6 import java.util.Date; 7 import java.util.HashMap; 8 import java.util.Map; 9 import java.util.UUID; 10 11 import org.json.JSONArray; 12 import org.json.JSONObject; 13 14 public class InvokeHelper { 15 16 // K3 Cloud WebSite URL Example "http://192.168.19.113/K3Cloud/" 17 public static String POST_K3CloudURL = "http://192.168.19.113/K3Cloud/"; 18 19 // Cookie 值 20 private static String CookieVal = null; 21 22 private static Map map = new HashMap(); 23 static { 24 map.put("Save", 25 "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc"); 26 map.put("View", 27 "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.View.common.kdsvc"); 28 map.put("Submit", 29 "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Submit.common.kdsvc"); 30 map.put("Audit", 31 "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Audit.common.kdsvc"); 32 map.put("UnAudit", 33 "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.UnAudit.common.kdsvc"); 34 map.put("StatusConvert", 35 "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.StatusConvert.common.kdsvc"); 36 } 37 38 // HttpURLConnection 39 private static HttpURLConnection initUrlConn(String url, JSONArray paras) 40 throws Exception { 41 URL postUrl = new URL(POST_K3CloudURL.concat(url)); 42 HttpURLConnection connection = (HttpURLConnection) postUrl 43 .openConnection(); 44 if (CookieVal != null) { 45 connection.setRequestProperty("Cookie", CookieVal); 46 } 47 if (!connection.getDoOutput()) { 48 connection.setDoOutput(true); 49 } 50 connection.setRequestMethod("POST"); 51 connection.setUseCaches(false); 52 connection.setInstanceFollowRedirects(true); 53 connection.setRequestProperty("Content-Type", "application/json"); 54 DataOutputStream out = new DataOutputStream( 55 connection.getOutputStream()); 56 57 UUID uuid = UUID.randomUUID(); 58 int hashCode = uuid.toString().hashCode(); 59 60 JSONObject jObj = new JSONObject(); 61 62 jObj.put("format", 1); 63 jObj.put("useragent", "ApiClient"); 64 jObj.put("rid", hashCode); 65 jObj.put("parameters", chinaToUnicode(paras.toString())); 66 jObj.put("timestamp", new Date().toString()); 67 jObj.put("v", "1.0"); 68 69 out.writeBytes(jObj.toString()); 70 out.flush(); 71 out.close(); 72 73 return connection; 74 } 75 76 // Login 77 public static boolean Login(String dbId, String user, String pwd, int lang) 78 throws Exception { 79 80 boolean bResult = false; 81 82 String sUrl = "Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc"; 83 84 JSONArray jParas = new JSONArray(); 85 jParas.put(dbId);// 帐套Id 86 jParas.put(user);// 用户名 87 jParas.put(pwd);// 密码 88 jParas.put(lang);// 语言 89 90 HttpURLConnection connection = initUrlConn(sUrl, jParas); 91 // 获取Cookie 92 String key = null; 93 for (int i = 1; (key = connection.getHeaderFieldKey(i)) != null; i++) { 94 if (key.equalsIgnoreCase("Set-Cookie")) { 95 String tempCookieVal = connection.getHeaderField(i); 96 if (tempCookieVal.startsWith("kdservice-sessionid")) { 97 CookieVal = tempCookieVal; 98 break; 99 } 100 } 101 } 102 103 BufferedReader reader = new BufferedReader(new InputStreamReader( 104 connection.getInputStream())); 105 String line; 106 System.out.println(" ============================= "); 107 System.out.println(" Contents of post request "); 108 System.out.println(" ============================= "); 109 while ((line = reader.readLine()) != null) { 110 String sResult = new String(line.getBytes(), "utf-8"); 111 System.out.println(sResult); 112 bResult = line.contains("\"LoginResultType\":1"); 113 } 114 System.out.println(" ============================= "); 115 System.out.println(" Contents of post request ends "); 116 System.out.println(" ============================= "); 117 reader.close(); 118 119 connection.disconnect(); 120 121 return bResult; 122 } 123 124 // Save 125 public static void Save(String formId, String content) throws Exception { 126 Invoke("Save", formId, content); 127 } 128 129 // View 130 public static void View(String formId, String content) throws Exception { 131 Invoke("View", formId, content); 132 } 133 134 // Submit 135 public static void Submit(String formId, String content) throws Exception { 136 Invoke("Submit", formId, content); 137 } 138 139 // Audit 140 public static void Audit(String formId, String content) throws Exception { 141 Invoke("Audit", formId, content); 142 } 143 144 // UnAudit 145 public static void UnAudit(String formId, String content) throws Exception { 146 Invoke("UnAudit", formId, content); 147 } 148 149 // StatusConvert 150 public static void StatusConvert(String formId, String content) 151 throws Exception { 152 Invoke("StatusConvert", formId, content); 153 } 154 155 private static void Invoke(String deal, String formId, String content) 156 throws Exception { 157 158 String sUrl = map.get(deal).toString(); 159 JSONArray jParas = new JSONArray(); 160 jParas.put(formId); 161 jParas.put(content); 162 163 HttpURLConnection connectionInvoke = initUrlConn(sUrl, jParas); 164 165 BufferedReader reader = new BufferedReader(new InputStreamReader( 166 connectionInvoke.getInputStream())); 167 168 String line; 169 System.out.println(" ============================= "); 170 System.out.println(" Contents of post request "); 171 System.out.println(" ============================= "); 172 while ((line = reader.readLine()) != null) { 173 String sResult = new String(line.getBytes(), "utf-8"); 174 System.out.println(sResult); 175 } 176 System.out.println(" ============================= "); 177 System.out.println(" Contents of post request ends "); 178 System.out.println(" ============================= "); 179 reader.close(); 180 181 connectionInvoke.disconnect(); 182 } 183 184 /** 185 * 把中文转成Unicode码 186 * 187 * @param str 188 * @return 189 */ 190 public static String chinaToUnicode(String str) { 191 String result = ""; 192 for (int i = 0; i < str.length(); i++) { 193 int chr1 = (char) str.charAt(i); 194 if (chr1 >= 19968 && chr1 <= 171941) {// 汉字范围 \u4e00-\u9fa5 (中文) 195 result += "\\u" + Integer.toHexString(chr1); 196 } else { 197 result += str.charAt(i); 198 } 199 } 200 return result; 201 } 202 }
InvokeTest.java
1 public class InvokeTest { 2 3 public static void main(String[] args) throws Exception { 4 InvokeHelper.POST_K3CloudURL = "http://192.168.19.113/K3Cloud/"; 5 String dbId = "55bb19192ebcde"; 6 String uid = "Demo"; 7 String pwd = "888888"; 8 int lang = 2052; 9 10 if (InvokeHelper.Login(dbId, uid, pwd, lang)) { 11 12 // 销售订单保存测试 13 // 业务对象Id 14 String sFormId = "SAL_SaleOrder"; 15 //需要保存的数据 16 // 如下字段可能需要根据自己实际值做修改 17 // FCustId FSalerId FMaterialId FUnitID 18 String sContent = "{\"Creator\":\"String\",\"NeedUpDateFields\":[\"FBillTypeID\",\"FDate\",\"FBusinessType\",\"FSaleOrgId\",\"FCustId\",\"FSettleCurrId\",\"FSalerId\",\"SAL_SaleOrder__FSaleOrderEntry\",\"FMaterialId\",\"FSettleOrgIds\",\"FUnitID\",\"FQty\",\"SAL_SaleOrder__FSaleOrderFinance\",\"FSettleCurrId\",\"FLocalCurrId\",\"FIsIncludedTax\",\"FBillTaxAmount\",\"FBillAmount\",\"FBillAllAmount\",\"FExchangeTypeId\",\"FExchangeRate\"],\"Model\":{\"FID\":0,\"FBillTypeID\":{\"FNumber\":\"XSDD01_SYS\"},\"FBusinessType\":\"NORMAL\",\"FSaleOrgId\":{\"FNUMBER\":\"100\"},\"FCustId\":{\"FNUMBER\":\"CUST0001\"},\"FSettleCurrId\":{\"FNUMBER\":\"PRE001\"},\"FSalerId\":{\"FNUMBER\":\"0002\"},\"SAL_SaleOrder__FSaleOrderFinance\":{\"FExchangeRate\":6.8123},\"SAL_SaleOrder__FSaleOrderEntry\":[{\"FMaterialId\":{\"FNUMBER\":\"001\"},\"FSettleOrgIds\":{\"FNUMBER\":\"100\"},\"FUnitID\":{\"FNumber\":\"个\"},\"FQty\":10}]}}"; 19 InvokeHelper.Save(sFormId, sContent); 20 21 System.out.println("hola success"); 22 } 23 } 24 }
本文地址:https://www.cnblogs.com/wunaozai/p/13819707.html
个人主页:https://www.wunaozai.com/
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |