BOS运行时-编码规则-单据编号跳号原因原创
金蝶云社区-Howhy
Howhy
79人赞赏了该文章 847次浏览 未经作者许可,禁止转载编辑于2023年05月25日 18:25:15

    星空标准功能提供编码规则来生成单据编号,当设置了默认编码规则后,一般是保存时,自动生成单据编号。由于星空的机制是,先生成单据编号。提供给各个业务使用,各个业务提供插件在校验库存或者其他逻辑。当这些逻辑校验不通过时,对应编号的流水号已经被占用,生成下一单时,不再使用原编号。

    因为以上机制,星空保存或者其他逻辑,生成编号与保存不是事务一致性,后续保存失败时,编号的流水号不会回滚。因此,星空不保证生成的编号一定连续。这种机制类似与,你到银行办理业务,到取号机取号(流水号)。但是最终没有真的去办理业务(异常情况),银行系统按照最终办理业务的流水号来看,有一部分流水号断开了。

   又因为,星空的上级操作日志仅记录成功的日志,失败回滚的数据,无法在上机操作日志上查询。所以导致一部分业务要求单据编号严格连续场景无法支持。

   为了支持以上场景,可以考虑在编码规则开启自动补号,延时计算(考虑并发设计的方案)。因为自动补号是延时的,那么按照每天作为编码依据生成的流水号,可能是断开的。比如今天20230525001一次生成,当生成到20230525005时,业务校验失败,导致最终20230525005没有保存到数据库里面。这个时候,补号自动计算服务还没有计算。下一次生成的流水号是20230525006,并且保存到数据库。当第二天,我们来查看20230525的数据时,发现20230525005这个流水号没有在系统中,而20230525006在系统中。当时上机操作日志中,没有任何20230525005日志(因为保存失败, 不会记录上机操作日志)。


    基于以上场景,如果系统保留日志,即可以在上机操作日志中查看到所有单据生成记录,可以在对应的单据上,增加以下服务插件,参考代码如下,在保存服务插件,增加此插件后,那么保存失败的单据编号也会出现在上机操作日志里面,提供给审计等要求单据编号严格连续的情况。

using Kingdee.BOS.App;
using Kingdee.BOS.Contracts;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.Log;
using System.ComponentModel;
using Kingdee.BOS.Util;
using Kingdee.BOS.Orm.DataEntity;
using System.Text;
using System;

namespace Cloud.BOS.Support.AppService
{
    /// <summary>
    /// 记录可能跳号的日志服务插件
    /// </summary>
    [Description("记录单跳号日志")]
    public class SkipBillNoLogAppPlugIn : AbstractOperationServicePlugIn
    {
        public override void BeginOperationTransaction(BeginOperationTransactionArgs e)
        {
            base.BeginOperationTransaction(e);
            WriteLog(e.DataEntitys, false);
        }

        public override void EndOperationTransaction(EndOperationTransactionArgs e)
        {
            base.EndOperationTransaction(e);
        }

        public override void RollbackData(OperationRollbackDataArgs e)
        {
            base.RollbackData(e);
            WriteLog(e.DataEntitys, true);
        }

        private void WriteLog(DynamicObject[] objs, bool isRollback)
        {
            if (objs == null || objs.Length == 0) return;
            var dataObj = objs[0];
            var billNoField = BusinessInfo.GetBillNoField();
            if (billNoField == null) return;

            if (dataObj.DynamicObjectType.Properties.Contains(billNoField.PropertyName)
                && !dataObj[billNoField.PropertyName].IsNullOrEmptyOrWhiteSpace())
            {
                var strDesc = string.Format("编号日志,编号:{0}", dataObj[billNoField.PropertyName]);
                if (isRollback)
                {
                    strDesc += string.Format(" 详细堆栈信息:{0}", GetStackTrace());
                }
                LogObject logObj = new LogObject()
                {
                    pkValue = dataObj["Id"].ToString(),
                    Description = strDesc,
                    OperateName = FormOperation.OperationName,
                    ObjectTypeId = BusinessInfo.GetForm().Id,
                    SubSystemId = BusinessInfo.GetForm().SubsysId,
                    Environment = OperatingEnvironment.BizOperate
                };
                ILogService logService = ServiceHelper.GetService<ILogService>();
                logService.WriteLog(Context, logObj);
            }
        }

        private string GetStackTrace()
        {
            System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
            System.Diagnostics.StackFrame[] sfs = st.GetFrames();
            if (sfs == null) return string.Empty;

            StringBuilder sb = new StringBuilder();
            for (int i = 1; i < sfs.Length; ++i)
            {
                if (System.Diagnostics.StackFrame.OFFSET_UNKNOWN == sfs[i].GetILOffset()) continue;
                var method = sfs[i].GetMethod();
                var fullName = method.DeclaringType == null ? string.Empty : method.DeclaringType.FullName;

                sb.AppendFormat("{0} {1}{2}", fullName, method.Name, Environment.NewLine);
            }

            var str = sb.ToString();

            if (str.Length > 1990)
            {
                str = str.Substring(0, 1900);
            }
            return str;
        }
    }
}



赞 79