纷享API接口参考资料
https://blog.csdn.net/qq_34723088/article/details/105406509
金蝶API接口参考资料
https://blog.csdn.net/qq_34723088/article/details/106186595
看客主要看流程吧,示例代码看看就好,毕竟上面的API接口会持续更新,业务代码也肯定不会一成不变
0 共用运行参数 & 方法
引用
PS.如有特殊编码则需要参照【客户类别】添加Dictionary<string, string> 以及参照例子修改FenxiangCodeToJinDie 方法即可
/// <summary>
/// 同步运行参数 & 方法
/// </summary>
public static class SynRunningParams
{
/// <summary>
/// 金蝶登录名称
/// </summary>
public const string JindieLoginName = "??";
/// <summary>
/// 金蝶登录密码
/// </summary>
public const string JindieLoginPassword = "??";
/// <summary>
/// 纷享操作人id
/// </summary>
public const string currentOpenUserId = FenXiangXiaoKeHelper.testOpenUserId;
/// <summary>
/// 金蝶分页查询单页最大行数
/// </summary>
public const int JindieLimit = 2000;
/// <summary>
/// 纷享分页查询单页最大行数
/// </summary>
public const int FenXiangLimit = 100;
/// <summary>
/// 接口超时等待秒数
/// </summary>
public const int waitSec = 2;
/// <summary>
/// 默认过滤器(无过滤)
/// </summary>
public static Filter defaultFilter = new Filter("name", new List<string> { "" }, Operator.NIN);
/// <summary>
/// 默认排序器
/// </summary>
public static List<Order> defaultOrders = new List<Order>{new Order("name"),};
/// <summary>
/// 客户类别(key:纷享的返回值;value:金蝶的返回值)
/// </summary>
public static readonly Dictionary<string, string> account_types = new Dictionary<string, string>() {
{"0","KHLB001_SYS" },// 普通销售客户
{"1","KHLB002_SYS" },// 寄售客户
{"2","KHLB003_SYS" },// 内部结算客户
{"3","TPLB004_SYS" },// 经销商客户
{"4","TPLB005_SYS" },// 重要客户
{"5","TPLB006_SYS" },// 一般客户
};
/// <summary>
/// 获取处理信息
/// </summary>
/// <param name="hasUpdateCount"></param>
/// <param name="hasAddCount"></param>
/// <param name="stopwatch"></param>
/// <param name="sumCount"></param>
public static string GetHandleMsg(int hasHandleCount, Stopwatch stopwatch, int sumCount)
{
if (hasHandleCount > 0)
{
long takeTime = stopwatch.ElapsedMilliseconds;
long surplusTime = takeTime / hasHandleCount * sumCount - takeTime;
return "处理速度:" + (takeTime / hasHandleCount) + " ms/项 ,总处理(" + hasHandleCount + ")时间: " + GetTimeStringByLong(takeTime) + ",预计剩余(" + (sumCount - hasHandleCount) + ")时间:" + GetTimeStringByLong(surplusTime);
}
return null;
}
/// <summary>
/// 纷享参数编码转换到金蝶
/// </summary>
/// <param name="fenxiangFieldName"></param>
/// <param name="fenxiangDataValue"></param>
/// <returns></returns>
public static string FenxiangCodeToJinDie(string fenxiangFieldName, string fenxiangDataValue)
{
switch (fenxiangFieldName)
{
case "account_type":
fenxiangDataValue = account_types[fenxiangDataValue];
break;
default:
break;
}
return fenxiangDataValue;
}
/// <summary>
/// long转换为时间信息
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string GetTimeStringByLong(long time)
{
time = Math.Abs(time);
return time / 1000 / 60 + " min " + time % (1000 * 60) / 1000 + " s";
}
/// <summary>
/// 同步准备
/// </summary>
public static void BeforeStart()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
FenXiangXiaoKeHelper.AutoUpdateCorpAccess_test();// 定时更新纷享身份参数
FenXiangXiaoKeHelper.currentOpenUserId = currentOpenUserId;// 执行人userId
#region 金蝶登录校验
Console.WriteLine("正在金蝶登录验证...");
JObject loginReturn = JinDieAPIHelper.ValidateLogin(JindieLoginName, JindieLoginPassword);
stopwatch.Stop();
bool isLoginSuccess = loginReturn["LoginResultType"].ToString() == "1";
//Console.WriteLine(loginReturn);
if (!isLoginSuccess) throw new Exception("登录失败!");
Console.WriteLine("金蝶账户【" + JindieLoginName + "】登录验证成功!");
#endregion
Console.WriteLine("登录验证耗时: " + stopwatch.ElapsedMilliseconds + "ms");
}
/// <summary>
/// 去除开头和结尾的双引号
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string RemoveDoubleQuotes(string str)
{
string fxObjName = str;
if (fxObjName.StartsWith("\"") && fxObjName.EndsWith("\""))
{
fxObjName = fxObjName.Remove(0, 1);
fxObjName = fxObjName.Remove(fxObjName.Length - 1, 1);
}
return fxObjName;
}
}
/// <summary>
/// 同步对象
/// </summary>
public enum SynObject
{
[Description("客户")]
Customer = 1,
[Description("物料")]
Material = 2,
}
1 金蝶→纷享
1.1 流程
PS.下文中:
【FenXiangXiaoKeHelper】&【HttpHelper】详见 https://blog.csdn.net/qq_34723088/article/details/105406509
【JinDieAPIHelper】详见 https://blog.csdn.net/qq_34723088/article/details/106186595
1.2 代码实现
1.2.1 同步执行代码类【SynJindieDataToFenxiang】
/// <summary>
/// 同步金蝶数据到纷享
/// </summary>
public class SynJindieDataToFenxiang
{
/// <summary>
/// 运行对象参数
/// </summary>
public static readonly Dictionary<SynObject, object[]> ObjectParameters = new Dictionary<SynObject, object[]>
{
{
SynObject.Customer,
new object[]
{
"客户",// 0.对象名称
"BD_Customer",// 1.金蝶FormId
// 2.金蝶查询结果字段列表FieldKeys(也是同步字段列表,第一个必须为两个平台的共同唯一标识,后方的必须为同步到纷享的字段)
"FNAME,FNUMBER,FTPCorporater,FFAX,FTEL,FTAXREGISTERCODE,FCOUNTRY,FGROUPCUSTID,FSALDEPTID.FNAME,FCreateOrgId.Fname",
"",// 3.金蝶过滤参数FilterString
new int[]{ 0},// 4.查重字段索引,索引号对应【2】索引(多个则空格隔开,查重为&&关系),至少有一个0
"AccountObj",// 5.纷享APIName
false,// 6.是否预设对象
new List<string>() { "_id", "name", "account_no","field_3ksIG__c"},// 7.纷享查询返回字段,第一个元素固定为【"_id"】,第2个元素后方开始为金蝶同步到纷享的字段,请对照【2】的字段顺序添加
typeof(Customer),// 8.纷享转换对象类型
}
},
{
SynObject.Material,
new object[]
{
"物料",
"BD_MATERIAL",
"FNAME,FNUMBER,FCreateOrgId.Fname",
"",
new int[1,2],
"SPUObj",
false,
new List<string>() { "_id", "name" },
typeof(Material),
}
},
};
/// <summary>
/// 金蝶数据同步到纷享
/// </summary>
/// <param name="synObject"></param>
public static void SynObjectsToFenXiang(SynObject synObject)
{
object[] parameters = ObjectParameters[synObject];
string objCnName = (string)parameters[0]; // 0.对象运行名称
string jindieApiName = (string)parameters[1]; // 1.金蝶FormId
string jindieFieldNames = (string)parameters[2];// 2.金蝶查询结果字段列表FieldKeys
string jindieFilters = (string)parameters[3];// 3.金蝶过滤参数FilterString
int[] duplicateIndexs = (int[])parameters[4];// 4.纷享查重字段索引
string fenxiangApiName = (string)parameters[5];// 5.纷享APIName
bool isFenxiangObject = (bool)parameters[6];// 6.是否预设对象
List<string> fenxiangReturnFields = (List<string>)parameters[7];// 7.纷享查询返回字段
Type fenxiangType = (Type)parameters[8];// 8.纷享转换对象类型
Stopwatch stopwatch = new Stopwatch();// 计时器
try
{
SynRunningParams.BeforeStart();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
int jindieStartRow = 0;
List<List<object>> newQueryObjects;
stopwatch.Restart();
Console.WriteLine("正在查询金蝶【" + objCnName + "】信息...");
Dictionary<string, object> jinDieObjectDics = new Dictionary<string, object>();// 去重字段查重
Queue<List<object>> JinDieObjects = new Queue<List<object>>();
do
{
newQueryObjects = JinDieAPIHelper.ExecuteBillQuery(jindieApiName, jindieFieldNames, SynRunningParams.JindieLimit + "", jindieStartRow + "", "0", jindieFilters);
foreach (List<object> newQueryObject in newQueryObjects)
{
if (newQueryObject[0] == null) continue;
string key = newQueryObject[0].ToString();
for (int i = 1; i < duplicateIndexs.Length; i++)
{
key += "_" + newQueryObject[i].ToString();
}
if (!jinDieObjectDics.ContainsKey(key))
{
jinDieObjectDics.Add(key, null);
JinDieObjects.Enqueue(newQueryObject);
}
}
jindieStartRow += SynRunningParams.JindieLimit;
Console.WriteLine("当前已查出条数:" + jinDieObjectDics.Count);
} while (newQueryObjects.Count == SynRunningParams.JindieLimit);
jinDieObjectDics.Clear();
stopwatch.Stop();
int sumCount = JinDieObjects.Count();
if (sumCount == 0)
{
Console.WriteLine("由于金蝶查询结果为空,结束同步,如有疑问请联系管理员检查【" + objCnName + "】金蝶查询过滤器;");
return;
}
Console.WriteLine("查询金蝶【" + objCnName + "】信息(" + sumCount + ")耗时: " + stopwatch.ElapsedMilliseconds + "ms");
stopwatch.Restart();// 处理纷享计时开始
double partCount = Math.Ceiling(sumCount * 1.0 / SynRunningParams.FenXiangLimit);// 批次数
int totalCount = 0;// 总处理计数
int hasUpdateCount = 0;// 更新计数
int hasAddCount = 0;// 新增计数
Dictionary<string, string> failUpdateNameList = new Dictionary<string, string>();// 更新失败信息记录
Dictionary<string, string> failAddNameList = new Dictionary<string, string>();// 添加失败信息记录
for (int i = 0; i < partCount; i++)// 分批查询纷享中对应对象名称的信息
{
int getCount = Math.Min(JinDieObjects.Count, SynRunningParams.FenXiangLimit);// 获取数量
//if (getCount == 0) continue;// 刚好整数倍时最后一次循环获取数量为0
Queue<List<object>> handlingObjects = new Queue<List<object>>();
List<string> names = new List<string>();// 待处理对象名称(标识),没更新的就进入新增
for (int j = 0; j < getCount; j++)
{
List<object> getList = JinDieObjects.Dequeue();
handlingObjects.Enqueue(getList);
names.Add(getList[0].ToString().Trim());
}
List<Filter> filters = new List<Filter>() { new Filter(fenxiangReturnFields[1], names, Operator.IN) };
List<Order> orders = new List<Order>() { new Order(fenxiangReturnFields[1]) };
JObject returnJObject = null;
while (true)
{
Console.WriteLine("正在查询(" + (i + 1) + "/" + partCount + ")纷享【" + objCnName + "】列表信息...");
try
{
returnJObject = FenXiangXiaoKeHelper.QueryObjectList(fenxiangApiName, filters, fenxiangReturnFields, SynRunningParams.FenXiangLimit, 0, orders, isFenxiangObject);
break;
}
catch (Exception ex)
{
if (ex.Message == "操作超时" || ex.Message.Contains("errorCode=30004"))
{
Console.WriteLine("查询纷享【" + objCnName + "】列表信息失败!" + SynRunningParams.waitSec + "s后重新尝试...\n" + ex.Message);
Thread.Sleep(SynRunningParams.waitSec * 1000);
}
else
{
Console.WriteLine("查询纷享【" + objCnName + "】列表信息失败!\n" + ex.Message);
break;
}
}
}
if (returnJObject == null) continue;
JToken dataList = returnJObject["data"]["dataList"];
List<JToken> fenxiangObjects = null;
if (dataList != null)
{
fenxiangObjects = dataList.ToList();
}
while (handlingObjects.Count > 0 && handlingObjects.Peek() != null)
{
List<object> jindieObjectData = handlingObjects.Dequeue();
string objectName = jindieObjectData[0].ToString().Trim();
JToken fenxiangObjectData = null;
fenxiangObjects.RemoveAll((obj) =>// 使用两个平台对象共有的唯一标识获取处理对象
{
string jindieValue = jindieObjectData[0].ToString().Trim();
string fenxiangValue = FenXiangXiaoKeHelper.GetFenxiangValue(obj, fenxiangReturnFields[1]);
if (jindieValue != fenxiangValue)
{
return false;
}
fenxiangObjectData = obj;
return true;
});
if (fenxiangObjectData == null)// 如果不能在纷享查询结果中找到同名对象则对比更新字段信息后更新
{
new Thread(new ThreadStart(() =>// 可先收集后统一新增
{
while (true)
{
Console.WriteLine("新增【" + objCnName + "】【" + objectName + "】信息中...");
try
{
dynamic data_json = Activator.CreateInstance(fenxiangType, jindieObjectData, null);
FenXiangXiaoKeHelper.AddObject(data_json.fenxiangObject);
Interlocked.Increment(ref hasAddCount);
Console.WriteLine("新增【" + objCnName + "】【" + objectName + "】信息成功!");
break;
}
catch (Exception ex)
{
if (ex.Message == "操作超时" || ex.Message.Contains("errorCode=30004"))
{
Console.WriteLine("新增【" + objCnName + "】【" + objectName + "】信息失败!" + SynRunningParams.waitSec + "s后重新尝试...\n" + ex.Message);
Thread.Sleep(SynRunningParams.waitSec * 1000);
}
else
{
Console.WriteLine("新增【" + objCnName + "】【" + objectName + "】信息失败!\n" + ex.Message);
failAddNameList.Add(objectName, ex.Message);
break;
}
}
}
Console.WriteLine(SynRunningParams.GetHandleMsg(totalCount, stopwatch, sumCount));
Interlocked.Increment(ref totalCount);
})).Start();
}
else
{
new Thread(new ThreadStart(() =>
{
bool isNeedToUpdata = false;// 是否需要更新=金蝶对应字段值是否与纷享对应字段值不一样
for (int j = 2; j < fenxiangReturnFields.Count && !isNeedToUpdata; j++)// 跳过[0]id和[1]唯一标识
{
string fenxiangDataValue = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData,fenxiangReturnFields[j]);
string jindieValue = jindieObjectData[j - 1].ToString().Trim();
if (fenxiangDataValue == null)
{
isNeedToUpdata = !string.IsNullOrEmpty(jindieValue);
}
else
{
isNeedToUpdata = jindieValue != fenxiangDataValue;
}
}
if (!isNeedToUpdata)
{
// Console.WriteLine("【" + objectName + "】无信息更新...");
Interlocked.Increment(ref totalCount);
return;
}
//new Thread(new ThreadStart(() =>// 可先收集后统一更新
//{
string objectId = SynRunningParams.RemoveDoubleQuotes(fenxiangObjectData[fenxiangReturnFields[0]].ToString());
while (true)
{
Console.WriteLine("更新【" + objCnName + "】【" + objectName + "】信息中...");
try
{
dynamic data_json = Activator.CreateInstance(fenxiangType, jindieObjectData, objectId);
FenXiangXiaoKeHelper.UpdateObject(data_json.fenxiangObject, isFenxiangObject);
Interlocked.Increment(ref hasUpdateCount);
Console.WriteLine("更新【" + objCnName + "】【" + objectName + "】信息成功!");
break;
}
catch (Exception ex)
{
int waitSec = 2;
if (ex.Message == "操作超时" || ex.Message.Contains("errorCode=30004"))
{
Console.WriteLine("更新【" + objCnName + "】【" + objectName + "】信息失败!" + waitSec + "s后重新尝试...\n" + ex.Message);
Thread.Sleep(waitSec * 1000);
}
else
{
Console.WriteLine("更新【" + objCnName + "】【" + objectName + "】信息失败!\n" + ex.Message);
failUpdateNameList.Add(objectName, ex.Message);
break;
}
}
}
Console.WriteLine(SynRunningParams.GetHandleMsg(totalCount, stopwatch, sumCount));
Interlocked.Increment(ref totalCount);
//})).Start();
})).Start();
}
}
}
while (Interlocked.CompareExchange(ref totalCount, sumCount, sumCount) < sumCount)
{
Thread.Sleep(100);
}
if (failUpdateNameList.Any())
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("============更新失败【" + objCnName + "】列表:\n");
foreach (var name_exMsg in failUpdateNameList)
{
stringBuilder.Append(name_exMsg.Key + ":" + name_exMsg.Value + "\n");
}
Console.WriteLine(stringBuilder);
failUpdateNameList.Clear();
}
if (failAddNameList.Any())
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("============新增失败【" + objCnName + "】列表:\n");
foreach (var name_exMsg in failAddNameList)
{
stringBuilder.Append(name_exMsg.Key + ":" + name_exMsg.Value + "\n");
}
Console.WriteLine(stringBuilder);
failAddNameList.Clear();
}
Console.WriteLine("总处理数:" + totalCount);
Console.WriteLine("更新数:" + hasUpdateCount);
Console.WriteLine("新增数:" + hasAddCount);
stopwatch.Stop();
}
}
/// <summary>
/// 纷享客户对象(例子)
/// </summary>
class Customer
{
/// <summary>
/// 纷享预设对象data_object对象格式
/// </summary>
/// <param name="list">金蝶返回对象list</param>
/// <param name="id"></param>
public Customer(List<object> list, string id)
{
fenxiangObject = new
{
dataObjectApiName = "AccountObj",// 自定义常量
name = list[0].ToString().Trim(),// 按金蝶接口的结果集序号获取
account_no = list[1].ToString(),
field_3ksIG__c = list[2].ToString(),
_id = id,// 更新时用的特定参数
remark = "syn_time:" + DateTime.Now.ToString(),// 自定义参数值
};
}
public object fenxiangObject = null;
}
/// <summary>
/// 纷享物料对象(待改)
/// </summary>
class Material
{
public Material(List<object> list, string id)
{
fenxiangObject = new
{
dataObjectApiName = "SPUObj",
name = list[0].ToString(),
batch_sn = "test",
_id = id,
is_spec = false,
standard_price = "12.18",
unit = "1",
remark = "syn_time:" + DateTime.Now.ToString(),
category = "23",
product_line = "1",
sku = new
{
name = list[0],
product_status = 1,
price = 13.2,
},
};
}
public object fenxiangObject = null;
}
1.2.2 配置同步对象步骤:
1)在【SynRunningParams】新增同步对象调用枚举
2)按照例子新增纷享object_data对象
3)根据例子新增参数字典
下图圈出参数分别为【1】,【2】步新增的代码
4)*按需添加异常处理
详见ctrl+F的catch部分
以及【SynObjectsToFenXiang】最后的异常处理
5)运行方法调用
1.2.3 运行效果
至于日志格式、【定时更新CorpAccessToken】之类的看官们自己按需自改;
2 纷享→金蝶
2.1 流程
PS.由于金蝶不同纷享,可以批量保存(保存=更新+新增),所以同步到金蝶的步骤是先准备好所有更新的数据再更新,对于多组织结构的对象则逐个更新
2.2 代码实现
2.2.1 同步执行代码类【SynFenxiangDataToJindie】
/// <summary>
/// 同步纷享数据到金蝶
/// </summary>
public class SynFenxiangDataToJindie
{
/// <summary>
/// 运行对象参数
/// </summary>
public static readonly Dictionary<SynObject, object[]> ObjectParameters = new Dictionary<SynObject, object[]>
{
{
SynObject.Customer,
new object[]
{
"客户",// 0.对象运行名称
"AccountObj",// 1.纷享APIName
false,// 2.是否预设对象
new List<string>() {"name", "account_type", "field_3ksIG__c"}, // 3.纷享查询结果字段列表(也是同步字段列表,第一个必须为名称)
new List<Filter>{ },// 4.纷享过滤器(不设置过滤时为null或元素空即可)
new int[]{ 0,1},// 5.纷享查重字段索引,索引号对应【3】索引
"BD_Customer",// 6.金蝶FormId
"FCUSTID,FNAME,FCustTypeId.FNumber,FTPCorporater",// 7.金蝶查询字段列表FieldKeys:第一个必须为表单主键(决定【新增/更新】),第二个必须开始对应【3】的字段)
new List<string>() { "FNAME", "FCustTypeId", "FTPCorporater" },// 8.金蝶更新字段列表NeedUpDateFields,对应【3】的字段
"",// 9.金蝶过滤参数FilterString
typeof(SaveCustomerModel),// 10.金蝶【保存操作请求model参数】
}
},
};
/// <summary>
/// 金蝶数据同步到纷享
/// </summary>
/// <param name="synObject"></param>
public static void SynObjectsToJindie(SynObject synObject)
{
object[] parameters = ObjectParameters[synObject];
string objCnName = parameters[0].ToString(); // 0.对象运行名称
string fenxiangApiName = (string)parameters[1]; // 1.纷享APIName
bool isCustomgObject = (bool)parameters[2];// 2.是否预设对象
List<string> fenxiangReturnFields = (List<string>)parameters[3];// 3.纷享查询结果字段列表
List<Filter> filters = (List<Filter>)parameters[4];// 4.纷享过滤器
int[] duplicateIndexs = (int[])parameters[5];// 5.纷享查重字段索引
string jindieApiName = (string)parameters[6];// 6.金蝶FormId
string jindieFieldNames = (string)parameters[7];// 7.金蝶查询结果字段列表FieldKeys
List<string> needUpDateFields = (List<string>)parameters[8];// 8.金蝶更新字段列表 NeedUpDateFields
string jindieFilterString = (string)parameters[9];// 9.金蝶过滤参数FilterString
Type jindieModelType = (Type)parameters[10];// 10.金蝶转换对象类型
if (filters == null)
{
filters = new List<Filter> {
SynRunningParams.defaultFilter
};
}
else if (!filters.Any((filter) =>
{
return filter.field_name == SynRunningParams.defaultFilter.field_name;
}))
{
filters.Add(SynRunningParams.defaultFilter);
}
Stopwatch stopwatch = new Stopwatch();
try
{
SynRunningParams.BeforeStart();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
stopwatch.Restart();
Console.WriteLine("正在查询纷享【" + objCnName + "】信息...");
Dictionary<string, object> fenxiangObjectDics = new Dictionary<string, object>();// 去重字段查重
Queue<JToken> fenxiangObjects = new Queue<JToken>();
int queryCount = 0;
int fenxiangStartRow = 0;
JObject newQueryJObject;
do
{
while (true)
{
try
{
newQueryJObject = FenXiangXiaoKeHelper.QueryObjectList(fenxiangApiName, filters, fenxiangReturnFields, SynRunningParams.FenXiangLimit, fenxiangStartRow, SynRunningParams.defaultOrders, isCustomgObject);
JToken fenxiangQueryData = newQueryJObject["data"];
if (fenxiangQueryData == null) continue;// 正常不触发
JToken fenxiangQueryDataList = fenxiangQueryData["dataList"];
if (fenxiangQueryDataList != null && fenxiangQueryDataList.HasValues)
{
List<JToken> dataList = fenxiangQueryDataList.Children().ToList();
queryCount = dataList.Count;
foreach (JToken data in dataList)
{
string keyString = "";
foreach (int duplicateIndex in duplicateIndexs)
{
JToken duplicateString = data[fenxiangReturnFields[duplicateIndex]];
if (duplicateString != null)
{
keyString += SynRunningParams.RemoveDoubleQuotes(duplicateString.ToString()).Trim() + "_";
}
}
if (!fenxiangObjectDics.ContainsKey(keyString))
{
fenxiangObjectDics.Add(keyString, null);
fenxiangObjects.Enqueue(data);
}
}
}
Console.WriteLine("当前已查出条数:" + fenxiangObjects.Count);
break;
}
catch (Exception ex)
{
if (ex.Message == "操作超时" || ex.Message.Contains("errorCode=30004"))
{
Console.WriteLine("查询纷享【" + objCnName + "】列表信息失败!" + SynRunningParams.waitSec + "s后重新尝试...\n" + ex.Message);
Thread.Sleep(SynRunningParams.waitSec * 1000);
}
else
{
Console.WriteLine("查询纷享【" + objCnName + "】列表信息失败!\n" + ex.Message);
break;
}
}
}
fenxiangStartRow += SynRunningParams.FenXiangLimit;
} while (queryCount == SynRunningParams.FenXiangLimit);
int sumCount = fenxiangObjects.Count;
fenxiangObjectDics.Clear();
stopwatch.Stop();
if (sumCount == 0)
{
Console.WriteLine("由于纷享查询结果为空(耗时: " + stopwatch.ElapsedMilliseconds + "ms),结束同步,如有疑问请联系管理员检查【" + objCnName + "】纷享查询过滤器;");
return;
}
Console.WriteLine("查询纷享【" + objCnName + "】信息(" + sumCount + ")耗时: " + stopwatch.ElapsedMilliseconds + "ms");
double partCount = Math.Ceiling(sumCount * 1.0 / SynRunningParams.FenXiangLimit);// 批次数
int totalCount = 0;// 总处理计数
int waitForUpdateCount = 0;// 更新计数
int waitForAddCount = 0;// 新增计数
Queue<object> jindieModels = new Queue<object>();
for (int i = 0; i < partCount; i++)// 分批查询纷享中对应对象名称的信息
{
int getCount = Math.Min(fenxiangObjects.Count, SynRunningParams.FenXiangLimit);// 获取数量
//if (getCount == 0) continue;// 刚好整数倍时最后一次循环获取数量为0
Queue<JToken> handlingObjects = new Queue<JToken>();
List<string> names = new List<string>();// 待处理对象名称(标识),没更新的就进入新增
for (int j = 0; j < getCount; j++)
{
JToken getJToken = fenxiangObjects.Dequeue();
handlingObjects.Enqueue(getJToken);
names.Add(FenXiangXiaoKeHelper.GetFenxiangValue(getJToken, fenxiangReturnFields[0]));
}
List<List<object>> jindieObjects = new List<List<object>>(); ;
List<List<object>> jindieNewQueryObjects = null;
int jindieStartRow = 0;
if (!string.IsNullOrWhiteSpace(jindieFilterString))
{
jindieFilterString = " AND ";
}
StringBuilder stringBuilder = new StringBuilder(jindieFilterString);
stringBuilder.Append(" FNAME IN( ");
foreach (string name in names)
{
stringBuilder.Append("'");
stringBuilder.Append(name);
stringBuilder.Append("',");
}
stringBuilder.Remove(stringBuilder.Length - 1, 1);
stringBuilder.Append(")");
Console.WriteLine("正在查询(" + (i + 1) + "/" + partCount + ")金蝶【" + objCnName + "】列表信息...");
do
{
try
{
stopwatch.Restart();// 处理金蝶计时开始
jindieNewQueryObjects = JinDieAPIHelper.ExecuteBillQuery(jindieApiName, jindieFieldNames, SynRunningParams.JindieLimit + "", jindieStartRow + "", "0", stringBuilder.ToString());
jindieStartRow += SynRunningParams.JindieLimit;
jindieObjects.AddRange(jindieNewQueryObjects);
Console.WriteLine("查询金蝶【" + objCnName + "】(" + (i + 1) + "/" + partCount + ")列表信息成功!耗时:" + stopwatch.ElapsedMilliseconds + "ms");
}
catch (Exception ex)
{
Console.WriteLine("查询金蝶【" + objCnName + "】(" + (i + 1) + "/" + partCount + ")列表信息失败!耗时:" + stopwatch.ElapsedMilliseconds + "ms\n" + ex.Message);
continue; ;// TODO 后续处理
}
} while (jindieNewQueryObjects.Count == SynRunningParams.JindieLimit);
while (handlingObjects.Count > 0 && handlingObjects.Peek() != null)
{
JToken fenxiangObjectData = handlingObjects.Dequeue();
string objectName = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData, fenxiangReturnFields[0]);
List<object> jindieObjData = null;
List<long> jindieIds = new List<long>();
jindieObjects.RemoveAll((obj) =>
{
string jindieValue = obj[1].ToString().Trim();
string fenxiangValue = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData, fenxiangReturnFields[0]);
if (jindieValue != fenxiangValue)
{
return false;
}
jindieIds.Add((long)obj[0]);
jindieObjData = obj;
return true;
});
if (jindieIds.Count > 0)// 如果不能在纷享查询结果中找到同名对象则对比更新字段信息后更新
{
bool isNeedToUpdata = false;// 是否需要更新=金蝶对应字段值是否与纷享对应字段值不一样
for (int j = 1; j < fenxiangReturnFields.Count && !isNeedToUpdata; j++)
{
string fenxiangDataValue = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData, fenxiangReturnFields[j]);
string jindieValue = jindieObjData[j + 1] + "";
if (fenxiangDataValue == null)
{
isNeedToUpdata = !string.IsNullOrWhiteSpace(jindieValue);
}
else
{
fenxiangDataValue = SynRunningParams.FenxiangCodeToJinDie(fenxiangReturnFields[j], fenxiangDataValue);
isNeedToUpdata = jindieValue != fenxiangDataValue;
}
}
if (!isNeedToUpdata)
{
//Console.WriteLine("【" + objectName + "】无信息更新...");
Interlocked.Increment(ref totalCount);
continue;
}
Queue<object> updateQueue = new Queue<object>();
foreach (long id in jindieIds)
{
updateQueue.Enqueue(Activator.CreateInstance(jindieModelType, fenxiangObjectData, id.ToString())); ;
Interlocked.Increment(ref waitForUpdateCount);
Interlocked.Increment(ref totalCount);
Console.WriteLine("即将更新【" + objectName+":"+ id + "】");// TODO 可能显示组织会好点
}
jindieModels.Enqueue(updateQueue);
}
else// TODO 新增到哪个组织?
{
jindieModels.Enqueue(Activator.CreateInstance(jindieModelType, fenxiangObjectData, "0"));
Interlocked.Increment(ref waitForAddCount);
Interlocked.Increment(ref totalCount);
Console.WriteLine("即将新增:" + objectName);
}
}
}
Console.WriteLine("即将新增:" + waitForAddCount);
Console.WriteLine("即将更新:" + waitForUpdateCount);
partCount = Math.Ceiling(jindieModels.Count * 1.0 / SynRunningParams.JindieLimit);// 批次数
for (int i = 0; i < partCount; i++)
{
int getCount = Math.Min(jindieModels.Count, SynRunningParams.JindieLimit);// 获取数量
List<object> saveModels = new List<object>();// 批量处理
Queue<object> singleSaveModels = new Queue<object>();// 逐条处理
for (int j = 0; j < getCount; j++)
{
object jindieObject = jindieModels.Dequeue();
if (jindieObject is Queue<object>)
{
while (((Queue<object>)jindieObject).Count > 0)
{
singleSaveModels.Enqueue(((Queue<object>)jindieObject).Dequeue());
}
}
else
{
saveModels.Add(jindieObject);
}
}
int updatingCount = singleSaveModels.Count;// 正在逐条更新的数量
while (singleSaveModels.Any())
{
object model = singleSaveModels.Dequeue();
new Thread(new ThreadStart(() =>
{
string modelName = "";
string modelId = "";
Stopwatch st= new Stopwatch();// 处理金蝶计时开始
st.Start();
try
{
JObject modelObject = JsonConvert.DeserializeObject<JObject>(new JavaScriptSerializer().Serialize(model));
modelName = modelObject["FName"].ToString();
modelId = modelObject["FCUSTID"].ToString();
Console.WriteLine("开始更新金蝶对象【" + SynRunningParams.RemoveDoubleQuotes(modelName) + ":" + SynRunningParams.RemoveDoubleQuotes(modelId) + "】...");
JObject singleResultJObject = JinDieAPIHelper.Save(new SaveJson(needUpDateFields, model), jindieApiName);
JToken responseStatusJToken = singleResultJObject["Result"]["ResponseStatus"];
JToken errors = responseStatusJToken["Errors"];
StringBuilder stringBuilder = new StringBuilder("【" + modelName + ":" + modelId + "】");
if (errors.HasValues)
{
stringBuilder.Append("错误信息:");
foreach (JToken error in errors.ToList())
{
stringBuilder.Append(error["Message"]);
}
}
JToken successEntitys = responseStatusJToken["SuccessEntitys"];
if (successEntitys.HasValues)
{
stringBuilder.Append("更新执行成功!耗时:" + st.ElapsedMilliseconds + "ms");
}
Console.WriteLine(stringBuilder);
}
catch (Exception ex)
{
Console.WriteLine("更新金蝶【" + objCnName + "】【" + modelName + ":" + modelId + "】信息失败!耗时:" + st.ElapsedMilliseconds + "ms\n" + ex.Message);
return;// TODO 后续处理
}
Interlocked.Decrement(ref updatingCount);
})).Start();
}
if (saveModels.Any())
{
try
{
stopwatch.Restart();// 处理金蝶计时开始
Console.WriteLine("开始批量保存金蝶对象...");
JObject batchResultJObject = JinDieAPIHelper.BatchSave(new BatchSaveJson(needUpDateFields, saveModels), jindieApiName);
JToken responseStatusJToken = batchResultJObject["Result"]["ResponseStatus"];
JToken errors = responseStatusJToken["Errors"];
StringBuilder stringBuilder = new StringBuilder();
if (errors.HasValues)
{
stringBuilder.Append("错误信息:");
foreach (JToken error in errors.ToList())
{
stringBuilder.Append(error["Message"]);
}
}
JToken successEntitys = responseStatusJToken["SuccessEntitys"];
if (successEntitys.HasValues)
{
stringBuilder.Append("批量保存执行成功数:" + successEntitys.ToList().Count);
}
Console.WriteLine(stringBuilder);
}
catch (Exception ex)
{
Console.WriteLine("批量保存金蝶【" + objCnName + "】(" + (i + 1) + "/" + partCount + ")列表信息失败!耗时:" + stopwatch.ElapsedMilliseconds + "ms\n" + ex.Message);
continue; ;// TODO 后续处理
}
}
while (updatingCount > 0)
{
Thread.Sleep(100);
}
Console.WriteLine("保存金蝶【" + objCnName + "】(" + (i + 1) + "/" + partCount + ")列表信息成功!耗时:" + stopwatch.ElapsedMilliseconds + "ms");
}
}
}
2.2.2 配置同步对象步骤(类同1.2.2):
1)在【SynRunningParams】新增同步对象调用枚举
2)按照API新增金蝶Model对象
这里我是根据API文档把对应Json放到https://www.bejson.com/convert/json2csharp/生成的【SaveCustomerModel】,下面将其构造方法样例列出
public SaveCustomerModel(JToken fenxiangObjectData, string FCUSTID, string FNumber)
{
this.FCUSTID = FCUSTID;
this.FNumber = FNumber;
string accountType = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData, "account_type");
if (accountType == null) accountType = "0";
FCustTypeId = new FCustTypeId{ FNumber = SynRunningParams.account_types[accountType]};
FName = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData, "name");
FTPCorporater = FenXiangXiaoKeHelper.GetFenxiangValue(fenxiangObjectData, "field_3ksIG__c")+"";
}
3)根据例子新增参数字典
下图圈出参数分别为【1】,【2】步新增的代码
4)*按需添加异常处理
详见ctrl+F的catch部分
5) 运行方法调用
2.2.3运行效果