业务流程.案例.指定业务对象全单据激活
【场景】指定业务对象全单据激活
历史版本业务流程归档按照流程实例归档,当出现业务流程图时并不会归档到一起,导致归档后全流程跟踪无法看全之类的逻辑;
历史的处理方案是让客户手动激活异常单据,或者全激活的逻辑。
手动激活过于繁琐;全激活又不适用于数据量大的客户;
以下提供一个指定业务对象全激活的场景
【方案】请在专业人士指导下使用
(0)先确定激活的单据节点
A -----》 B
B ----- 》C ------》D
常见的跨流程图流程如上,需要找到跨流程的节点,激活的同时把上和下流程都能够同时激活,激活一次就能完整。
(1)确定好单据节点后,准备待激活流程数据表
```sql
--<0>创建 需要处理的修复表, FPKID 主键,FTABLENUMBER表标识,FTID表主键,FStatus状态,FDatetime更新时间
create table T_TMP_RECOVERYSPEC20240626
(
FPKID VARCHAR(50) NOT NULL Primary key,
FTABLENUMBER VARCHAR(50) NOT NULL,
FTID BIGINT NOT NULL,
FStatus INT NOT NULL,
FDatetime DateTime NULL
);
--<1>以采购订单为例,导入所有单据分录,作为需要处理的流程数据
INSERT INTO T_TMP_RECOVERYSPEC20240626
SELECT NEWID() as FPKID, 't_PUR_POOrderEntry' as FTableNumber ,FENTRYID as FTID, 0 as FStatus, null as FDatetime FROM T_PUR_POORDERENTRY;
```
(2)准备好待激活流程数据表后,创建执行计划进行激活
创建执行计划,关联的组件 Fk.App.Core.ScheduleService.RecoverySpecService, Fk.App.Core.ScheduleService
生成好表后,将当前表作为执行计划的参数传入
```json
{"TableName":"T_TMP_RECOVERYSPEC20240626"}
```
![image.webp](/download/010031d1b93c70c2493abbf3ae3c92e48f18.webp)
(3)运行验证,根据第一次测试的执行时间略微调整执行间隔和异常恢复间隔
```sql
--<2>查询当前各状态的记录数
select '0' as FStatus,count(1) from T_TMP_RECOVERYSPEC20240626 where FStatus = 0
union all
select '1' as FStatus,count(1) from T_TMP_RECOVERYSPEC20240626 where FStatus = 1
union all
select '2' as FStatus,count(1) from T_TMP_RECOVERYSPEC20240626 where FStatus = 2
--<3>扫描当前表中处理后的记录数
/*
--联查脚本,不建议使用,因为原表只有主键索引
select count(1) from T_TMP_RECOVERYSPEC20240626 mlog
inner join T_BF_INSTANCEENTRY node on mlog.FTABLENUMBER = node.FTTABLENAME and mlog.FTID = node.FTID
*/
--直接查询原表脚本
select 'T_BF_INSTANCEENTRY' as tablename,count(1) from T_BF_INSTANCEENTRY where FTTABLENAME = 't_PUR_POOrderEntry'
union
select 'T_BF_INSTANCEENTRYhis' as tablename,count(1) from T_BF_INSTANCEENTRYhis node inner join T_BF_TABLEDEFINE td on node.FTTABLEID = td.FSEQ where td.FTABLENUMBER = 't_PUR_POOrderEntry'
union
select 'T_BF_INSTENTRYBACKUP' as tablename,count(1) from T_BF_INSTENTRYBACKUP node inner join T_BF_TABLEDEFINE td on node.FTTABLEID = td.FSEQ where td.FTABLENUMBER = 't_PUR_POOrderEntry'
union
select 'T_BF_INSTARCHIVELOG' as tablename,count(1) from T_BF_INSTARCHIVELOG bffile inner join T_BF_TABLEDEFINE td on bffile.FTTABLEID = td.FSEQ where td.FTABLENUMBER = 't_PUR_POOrderEntry'
```
![20240626 1451.webp](/download/01008060815d760e469685fcd72a1dede332.webp)
【参考代码】
引用工程
![image.webp](/download/01006d770b8692bc46e58f5d351be4b06829.webp)
```csharp
using Kingdee.BOS;
using Kingdee.BOS.App.Core;
using Kingdee.BOS.App.Data;
using Kingdee.BOS.Contracts;
using Kingdee.BOS.Core;
using Kingdee.BOS.Util;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Fk.App.Core.ScheduleService
{
public class RecoverySpecService : IScheduleService
{
public static class TmpConst
{
public static string FPKID = "FPKID";
public static string FTableNumber = "FTableNumber";
public static string FTID = "FTID";
public static string FStatus = "FStatus";
public static string FDatetime = "FDatetime";
public enum Status
{
Ready = 0,
Running = 1,
Finish = 2,
}
public static int Day_Running2Ready = 5;
public static int BatchCnt_Read = 1000;
public static int BatchCnt_Run = 100;
}
public void Run(Context ctx, Schedule schedule)
{
var param = RecoverySpecParam.ConvertFromJsonString(schedule.Parameters);
if (param == null || param.TableName.IsNullOrEmptyOrWhiteSpace())
return;
param.Context = ctx;
DateTime curDateTime = new TimeService().GetSystemDateTime(ctx);
/*
* <0>处理一天前的运行状态变为准备状态
*/
string sqlRun2Ready = string.Format("UPDATE {0} Set FStatus = 0 WHERE FStatus = 1 AND FDatetime < @FDatetime", param.TableName);
List<SqlParam> paramList = new List<SqlParam>();
paramList.Add(new SqlParam("@FDatetime", KDDbType.DateTime, curDateTime.AddDays(TmpConst.Day_Running2Ready)));
DBUtils.Execute(ctx, sqlRun2Ready, paramList);
/*
* <1>获取前N条记录做激活
*/
Dictionary<string, List<RecoveryItem>> tableNumberPkList = new Dictionary<string, List<RecoveryItem>>();
string sqlGetReady = string.Format("SELECT TOP {1} FPKID,FTableNumber,FTID FROM {0} WHERE FStatus = 0", param.TableName, TmpConst.BatchCnt_Read);
using (var dr = DBUtils.ExecuteReader(ctx, sqlGetReady))
{
while (dr.Read())
{
string pkId = dr.GetValue<string>(TmpConst.FPKID);
string tableNumber = dr.GetValue<string>(TmpConst.FTableNumber);
long tid = dr.GetValue<long>(TmpConst.FTID);
if (!tableNumberPkList.ContainsKey(tableNumber))
tableNumberPkList[tableNumber] = new List<RecoveryItem>();
var item = new RecoveryItem()
{
PkId = pkId,
TableNumber = tableNumber,
TID = tid
};
tableNumberPkList[tableNumber].Add(item);
}
}
if (tableNumberPkList.IsEmpty())
return;
/*
* <2>激活逻辑
*/
foreach (var tableNumerPair in tableNumberPkList)
{
string tableNumber = tableNumerPair.Key;
List<RecoveryItem> recoveryItemList = tableNumerPair.Value;
List<RecoveryItem> curTurnRunList = new List<RecoveryItem>();
for (int i = 0; i < recoveryItemList.Count; ++i)
{
var recoveryItem = recoveryItemList[i];
if (!ConvertStataus(param, recoveryItem.PkId, TmpConst.Status.Ready, TmpConst.Status.Running))
continue;
curTurnRunList.Add(recoveryItem);
if (curTurnRunList.Count >= TmpConst.BatchCnt_Run)
{
MoveInstToCurBatch(param, curTurnRunList);
curTurnRunList.Clear();
}
}
if (curTurnRunList.Count >= 0)
{
MoveInstToCurBatch(param, curTurnRunList);
}
}
}
private bool ConvertStataus(RecoverySpecParam param, string pkId, TmpConst.Status oldStatus, TmpConst.Status newStataus)
{
string strSql = string.Format("UPDATE {0} SET FStatus = @FNewStatus, FDatetime = GetDate() WHERE FPKID = @FPKID AND FStatus = @FOldStatus", param.TableName);
List<SqlParam> paramList = new List<SqlParam>();
paramList.Add(new SqlParam("@FNewStatus", KDDbType.Int32, (int)newStataus));
paramList.Add(new SqlParam("@FPKID", KDDbType.AnsiString, pkId));
paramList.Add(new SqlParam("@FOldStatus", KDDbType.Int32, (int)oldStatus));
int cnt = DBUtils.Execute(param.Context, strSql, paramList);
return cnt == 1;
}
private void MoveInstToCurBatch(RecoverySpecParam param, List<RecoveryItem> recoveryItemList)
{
if (param == null || recoveryItemList == null || recoveryItemList.IsEmpty())
return;
var bfServiceType = TypesContainer.GetOrRegister("Kingdee.BOS.App.Core.BusinessFlow.Repositories.BFHisDataRepository,Kingdee.BOS.App.Core");
var bfService = Activator.CreateInstance(bfServiceType, param.Context);
var method = bfService.GetType().GetMethod("MoveInstToCurrTable");
string tableNumber = recoveryItemList.FirstOrDefault().TableNumber;
var tidList = recoveryItemList.Select(x => x.TID).ToList();
object[] paramArray = { tableNumber, tidList };
bool hasError = false;
using (var scope = new KDTransactionScope(System.Transactions.TransactionScopeOption.Required))
{
for (int i = 0; i < recoveryItemList.Count; ++i)
{
if (!ConvertStataus(param, recoveryItemList[i].PkId, TmpConst.Status.Running, TmpConst.Status.Finish))
{
hasError = true;
break;
}
}
if (hasError)
return;
method.Invoke(bfService, paramArray);
scope.Complete();
}
}
}
[Serializable]
public class RecoverySpecParam
{
/*
* 要处理的表结构
create table T_TMP_RECOVERYSPEC20240626
(
FPKID VARCHAR(50) NOT NULL Primary key,
FTABLENUMBER VARCHAR(50) NOT NULL,
FTID BIGINT NOT NULL,
FStatus INT NOT NULL,
FDatetime DateTime NULL
);
INSERT INTO T_TMP_RECOVERYSPEC20240626
SELECT NEWID() as FPKID, 't_PUR_POOrderEntry' as FTableNumber ,FENTRYID as FTID, 0 as FStatus, null as FDatetime FROM T_PUR_POORDERENTRY;
*/
public string TableName;
[JsonIgnore]
public Context Context;
public static RecoverySpecParam ConvertFromJsonString(string jsonString)
{
if (jsonString == null || jsonString.Trim().Length <= 0)
return null;
return JsonConvert.DeserializeObject<RecoverySpecParam>(jsonString);
}
}
public class RecoveryItem
{
public string PkId;
public string TableNumber;
public long TID;
}
}
```
业务流程.案例.指定业务对象全单据激活
【场景】指定业务对象全单据激活历史版本业务流程归档按照流程实例归档,当出现业务流程图时并不会归档到一起,导致归档后全流程跟踪无法看...
点击下载文档
本文2024-09-16 18:26:27发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-22154.html
您需要登录后才可以发表评论, 登录登录 或者 注册
最新文档
热门文章