案例:自定义bos下推产品入库单,并实现勾稽
自定义bos单如下
下面将分解开发过程:
创建选单关系:请不要再bos设计器里添加新单推老单的选单关系,该工具对老单支持不够;只能通过再数据库中插入数据来实现功能;
查找下游单据(老单)的模板ID;select FID,FTemplateID,* from ICTransactionType where FName = '产品入库',
FID=2,FTemplateID='A02'
再ictemplateentry中查找表体字段
查找上游单据bos单据的单据类型:
FID=200000013,表头物理表FTableName='t_bos200000013',主键FPrimaryKey ='FID'
bos单的模型Fkey字段标记,ffieldname字段物理表字段名
第一步:创建选单关系:
INSERT INTO ICClassLink(FSourClassTypeID,FDestClassTypeID,FSourBillShowIndex,FAllowCopy,FAllowCheck,FAllowForceCheck,FFlowControl,FDeCondition,FCondition,FDeHCondition,FDeBCondition,FSourBillFID,FSourBillFEntryID,FSourBillFBillNo,FObjectName,FObjectType,FObjectID,FIsUsed,FUsePage,FDefaultPage,FSRCIDKey,FSRCEntryIDKey,FSRCBillNoKey,FSRCClassIDKey,FISUserDefine,FDestTranTypeID,FSourTranTypeID,FSelectListID,FMustSelected,FSystemReserved,FROB,FFieldName,FRemark,FUseSpec,FSrcDestPage,FSrcPage,FToRed,FSourTypeID,FDestTypeID,FLookUpConditionUp,FLookUpConditionDown,FDefault,FUnControl,FParaValue) VALUES (200000013,-2,0,0,1,0,0,'','FQTY>FQTY1','','','FID','','FBillNo','',0,0,2,',1,',',1,','FSourceInterID','FSourceEntryID','FSourceBillNo','FSourceTranType',1,2,200000013,200000013,0,0,0,'200000013','<FAction=,CanMultiSelBill;/>',-1,0,0,0,0,0,'','',0,6,0)
GO
FSourClassTypeID 填写上游bos单据的类型200000013
FDestClassTypeID 填写下游老单的类型ID -2;老单需要再FID前加上负号(-)
FAllowcopy:复制关系
FAllowCheck:勾稽
FAllowForceCheck:强制勾稽
开发时使用勾稽即可;FAllowCheck=1,其它=0
FCondition:FQty>FQty1(bos单中FQty,FQty1分别对应生产数量、累计入库数量);指必须符合这个条件时才可以下推;
FSourBillFID:FID 上游单据主键
FSourbillFEntryID:空 (表头推表体,这里可以不用填)
FSourcBillFBillNo:FBillNo 上游单据的单据编号字段
--可以通过脚本select FKey,* from ICClassTableInfo where FClassTypeID = 200000013来查询字段的Key
FISused:2启用
FUsePage:,1, 仅表头
FDefualtPage:,1, 仅表头
FSrcIDKey:下游单据的物理表字段用于存上游单据内码
FSRCEntryIDKey:'FSourceEntryID',下游单据的物理表字段用于存上游单据分录ID
FSRCBillNoKey:'FSourceBillNo'下游单据的物理表字段用于存上游单据编号
FSRCClassIDKey:'FSourceTranType'下游单据的物理表字段用于存上游单据类型
FDestTranTypeID:产品入库的FID(查产品入库单模板时查出来的FID值)
FSourTranTypeID:上游bos单单据类型id
FSelectListID:上游bos单单据类型id
FFieldName:icclasslink中定义的ffieldname,建议使用200000013与bos单的单据类一致
FRemark:'<FAction=,CanMultiSelBill;/>'固定值,表示可同时选多个单一起下推
当你完成上面的操作后,再200000013序时簿上就会出现 下推-产品入库 这个菜单了;
第二步:添加下推的值映射关系:
比如将bos单表头的物料携带到产品入库表体的物料字段上:
当下游单据是老单时,在下游单据加载上游数据的数据包时,拼接Sql时需要用到ICTableRelation,ICSelbills;
ICTableRelation用于拼接这个sql的from部分
ICSelbills用于拼接这个sql的select部分
insert into ICTableRelation(FTypeID,FInterID,FTableName,FTableNameAlias,FFieldName,FTableName11,FTableNameAlias11,FFieldName11,FLogic,FBillID,FFieldID,FMode,FIndex,FCondition,FLeftParentheses,FRightParentheses,FLogicOperator,FISConst,FConstType,FSubFilter)
values(0,0,'t_BOS200000013','v1','FBASE','t_ICItem','t4','FItemID','*=','A02','200000013',0,0,'','','','=',0,0,'')
FTableName,上游单据的表头物理表字段
FTableNameAlias : v1 上游单据物理表别称,一般使用v1
FFieldName,FBASE上游单据物料字段的物理表字段名称
FTableName11 : t_icitem 关联表(物料基础资料)物理表
FTableName11:t_icitem 别称 t4 ,可以随意命名
FFieldName11:fitemid 物料的主键
flogic:*= 表示left join
FBillID:产品入库单的模板ID
FFieldID:icclasslink中定义的ffieldname,建议使用200000013与bos单的单据类一致
FLogicOperator:=
这种配置再拼sql的where部分会是这样
from t_BOS200000013 v1
left join t_icitem t4 on v1.FBASE = t4.fitemid
接下来是select部分:
不管选单时要携带任意字段,这2条记录是必须插入的
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited)
values('A02',200000013,'',-200,-1,'FInterID','FID','t_BOS200000013','v1','',0,0)
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited)
values('A02',200000013,'',-1,-1,'FBillNo','FBillNo','t_BOS200000013','v1','',0,0)
FID, 产品入库单的模板ID
FFieldName:icclasslink中定义的ffieldname,建议使用200000013与bos单的单据类一致
这2条记录比较特殊需要单据说明
第一条记录 标记选单关系中上游单据的主键
FSelType:-200 bos单的主键定义
FDK:-1 固定-1
FColName:数据包的字段别名必须是FInterID
FName:bos单主键物理表字段
FTableName:t_BOS200000013字段来源物理表
FTableAlias:v1 与ICTableRelation定义的别名要保持一致
第二条记录 标记选单关系上游单据的单据编号字段
FSelType -1 固定
FDK:-1 固定-1
FColName:数据包的字段别名必须是FBillNo
FName:bos单单据编号物理表字段
FTableName:t_BOS200000013字段来源物理表
FTableAlias:v1 与ICTableRelation定义的别名要保持一致
接下来配置物料携带:
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited)
values('A02',200000013,'FItemID',0,0,'FItemID','FITEMID','t_ICItem','t4','',0,0)
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited)
values('A02',200000013,'FItemID',0,0,'FItemNUMBER','FNUMBER','t_ICItem','t4','',0,0)
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited)
values('A02',200000013,'FItemID',0,0,'FItemNAME','FNAME','t_ICItem','t4','',0,0)
FDstCtlField:FItemID 下游单据物料字段,因为物料是基础资料类型字段,所以不能只携带内码到下游,还需要再数据包中配置名称和编码来
FDK 1 编码 2名称
FTableName:字段来源t_ICItem
FTableAlias : t4 与ICTableRelation定义的别名要保持一致
再拼凑select脚本时就会是这样
v1.FID as FInterID,v1.FbillNo as fbillno,t4.FITEMID as FItemID ,t4.FNUMBERas FItemNUMBER,t4.FNAME as FItemNAME
执行完上述脚本之后,点击下推看看效果;
打开sqlserver跟踪器,会看到这样一条脚本
t4.FUnitGroupID这个是系统自动添加的,只要转换关系中存在t_icitem,就会自动创建这个字段的输出,供携带单位使用
下推后的效果
已同样的方法我们把单位插入进来(开发可以先自己配置一次,再往下看,检验一下是否已经掌握携带关系配置)
...
...
确定单位物理表select * from t_ItemClass 查询结果t_MeasureUnit
insert into ICTableRelation(FTypeID,FInterID,FTableName,FTableNameAlias,FFieldName,FTableName11,FTableNameAlias11,FFieldName11,FLogic,FBillID,FFieldID,FMode,FIndex,FCondition,FLeftParentheses,FRightParentheses,FLogicOperator,FISConst,FConstType,FSubFilter) values(0,1,'t_BOS200000013','v1','FBase1','t_MeasureUnit','t7','FMeasureUnitID','*=','A02','200000013',0,0,'','','','=',0,0,'')
--单位也是基础资料因此也需要插3条记录
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FUnitID',0,0,'FUnitID','FMeasureUnitID','t_MeasureUnit','t7','',0,0) Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FUnitID',0,0,'FUnitNUMBER','FNUMBER','t_MeasureUnit','t7','',0,0) Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FUnitID',0,0,'FUnitNAME','FNAME','t_MeasureUnit','t7','',0,0)
接下来是把应收数量、实收数量携带下来,这2个字段直接来源于bos单表头物理表字段,所以只需要各插入一行记录即可,也不需要额外再ICTableRelation添加记录,只需要插入ICSelbills记录即可;
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FAuxQtyMust',0,0,'FAuxQtyMust','FQty','t_BOS200000013','v1','',0,0) Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FAuxQty',0,0,'FAuxQty','FQty','t_BOS200000013','v1','',0,0)
先不考虑勾稽这种场景,仅考虑把值携带下去,后面会讲如何扣减;
下推单据,后保存一下数据;
看看后台的记录,下游单据是否记录了上游单据的内码ID
发现并没有把上游单据ID记录下来;如果没有这些记录是无法做到反写勾稽扣减的;
删掉单据,改进选单关系,把上游的单据内码,单据类型,单据编号携带下来;脚本与数量类似;
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'fsourcetrantype',0,0,'fsourcetrantype','FClassTypeID','t_BOS200000013','v1','',0,0) Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'fsourceinterid',0,0,'fsourceinterid','FID','t_BOS200000013','v1','',0,0) Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'fsourcebillno',0,0,'fsourcebillno','FBillNo','t_BOS200000013','v1','',0,0)
这里必须要解释一下,因为最开始我们已经插入过单据编号和内码的记录了,但是那是作为选单标识添加的;这里是作为携带字段
FSelType 0表示字段携带到下游的表体字段;
FColName不要用fbillno和finterid,因为FColName字段不能重复,可以随意命名,建议使用跟下游字段一样的字段名;
重新下推单据保存之后
这个时候,已经可以再单据t_200000013的序时簿上下查能够查到刚才保存的单据了;
第三步:勾稽实现:
首先bos单上需要有一个字段来存已下推的数量;在本例中,用累计入库数量来表示;完成了第一步和第二步配置之后,并下推保存了一张单据(如上图);
看看上游单据的累计入库数量是否发生了变化?
为了方便演示,再叙事上配置一个关联信息配置,再一个页面内同时看到上下游单据;
累计入库数量并没有发生变化;
此处尤其复杂,需要好好理解
--反写到累计入库数量,以及关闭标志自动更新;
效果如下:
insert into ICWriteBackTemplate(FSrcTranType,FDestTranType,FExecuteIndex,FSrcField,FSrcCommitField,FSrcAuxCommitField,FSrcUnitIDField,FDestField,FSrcBillKey,FSrcEntryKey,FDestBillKey,FDestEntryKey,FSrcKeyWord,FDestKeyWord,FOperator,FSaveCheckAction,FUpdateStatusField,FSourceInterIDField,FSourceEntryIDField,FSrcEntryTable) values(200000013,2,10,'[HEAD].FQty','FQty1','','FBase1','[Entry].FAuxQty','FID','','FInterID','FEntryID','FBASE','FItemID','+','','[HEAD].FInteger','FSourceInterID','','t_BOS200000013')
(本例子的场景是表头对表体,反写是写到表头,本文不介绍表体到表体的选单)
FSrcTranType:上游单据类型id
FDestTranType:下游单据类型id
FExecuteIndex:10随便填,如果有多个反写则会按FExecuteIndex从小到大顺序执行
FSrcField:FQty,上游表头数量源头字段,需要用[HEAD]前缀,用于后面反写关闭标记;
FSrcCommitField:FQty1 上游单据的累计下推数量在本例用是累计入库数量;
FSrcAuxCommitField:空;(大多数客户开发bos单据的时候不会再bos单上给每个数量字段对应的基本单位数量;这就要求客户自己再使用的过程中下推后不要改单位;避免出现反写时数据异常,因此本例按无基本单位数量的情况来说明)
FSrcUnitIDField:上游单据单位字段
FDestField:下游数量字段[Entry].FAuxQty,因为是表头推表体,下游的数量再表体,因此要用[Entry]前缀,FAuxQty是常用单位数量,(界面上显示的数量值),为什么不用fqty(基本单位入库数量),因为咱们2开很少使用基本单位数量,扣减上游数量都是用常用单位来弄的,实际上这是一种不规范的开发行为;
FSrcBillKey:FID 上游单据主键字段
FSrcEntryKey:空 (表头对表体不需要使用到上游单据的表体)
FDestBillKey:下游单据的主键
FSrcEntryKey:下游单据的分录号字段
FSrcKeyWord:上游单据关键字,本例中是物料(必填字段)
FDestKeyWord:下游单据表体物料字段
FOperator:+号,固定值
FUpdateStatusField:上游单据关闭字段[HEAD].FInteger,表头字段需要用[HEAD]标记
FSourceInterIDField:下游单据表体中存上游单据内码的字段
FSourceEntryIDField:空
FSrcEntryTable:'t_BOS200000013',上游单据表头物理表名称
第四步:如何限制累计入库数量不能大于我上游单据的原始数量
再sqlserver跟踪器中,跟踪下游单据保存脚本发现有这样一条脚本
set nocount on
declare @fcheck_fail int
declare @fsrccommitfield_prevalue decimal(28,13)
declare @fsrccommitfield_endvalue decimal(28,10)
declare @maxorder int
update src set @fsrccommitfield_prevalue= isnull(abs(src.fqty1),0), @fsrccommitfield_endvalue=@fsrccommitfield_prevalue+dest.fauxqty,
@fcheck_fail=case when isnull(@maxorder,0)=1 then 0 else (case when (1=1) then @fcheck_fail else -1 end) end,
src.fqty1= case when src.fqty < 0 then -1 * @fsrccommitfield_endvalue else @fsrccommitfield_endvalue end
from t_bos200000013 src
inner join (
select u1.fsourceinterid as fsourceinterid,u1.fsourcetrantype,u1.fitemid,sum(u1.fauxqty) as fauxqty from icstockbillentry u1 where u1.finterid=1961 group by u1.fsourceinterid,u1.fsourcetrantype,u1.fitemid
) dest on dest.fsourceinterid = src.fid and dest.fitemid = src.fbase
如果将1=1配置为@fsrccommitfield_endvalue < src.fqty;即累计入库数量>原始单据数量时令@fcheck_fail=-1
将刚才的writebacktemplate脚本进行改造:
delete ICWriteBackTemplate where FSrcTranType = 200000013 insert into ICWriteBackTemplate(FSrcTranType,FDestTranType,FExecuteIndex,FSrcField,FSrcCommitField,FSrcAuxCommitField,FSrcUnitIDField,FDestField,FSrcBillKey,FSrcEntryKey,FDestBillKey,FDestEntryKey,FSrcKeyWord,FDestKeyWord,FOperator,FSaveCheckAction,FUpdateStatusField,FSourceInterIDField,FSourceEntryIDField,FSrcEntryTable,FCheckExpression_Save) values(200000013,2,10,'[HEAD].FQty','FQty1','','FBase1','[Entry].FAuxQty','FID','','FInterID','FEntryID','FBASE','FItemID','+','','[HEAD].FInteger','FSourceInterID','','t_BOS200000013','@fsrccommitfield_endvalue<[srctable].FQty')
插入前记得先删掉之前的writebacktemplate记录,即向FCheckExpression_Save插入@fsrccommitfield_endvalue<[srctable].FQty;
表示符合表达式条件时容许保存,根据反写的脚本可以知道@fsrccommitfield_endvalue表示加上这张单据累计入库数量
[srctable].FQty表示上游单据的原始数量;
[srctable]会再实际脚本中被替换成src
[srcheadtable] 会被替换成srchead
[desttable]会被替换成dest
只接受以上3中[xxx]的输入
改造后效果如下,
这次下推10个(已经累计下推了8个了)那么根据我们预计效果应该是禁止保存,
第五步:下推时的默认数量配置,
单据已经累计入库8个了,那么下次下推希望默认的应收数量和实收数量为2(即原始数量-累计入库数量);
调整选单关系ICSelbills,再上面的步骤中已经介绍过,这个表是用来存原始数据包构建sql时的select部分;
我们需要改造select xxxxx. FQty as FAuxQty,FQty as FAuxQtyMust.xxxxx
变成select xxxxx. FQty - FQty1 as FAuxQty,FQty - FQty1 as FAuxQtyMust.xxxxx
改造之前的脚本(先删掉对应记录再插入)
Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FAuxQtyMust',0,0,'FAuxQtyMust','FQty','t_BOS200000013','v1','FQty - FQty1',0,0) Insert into ICSelbills(FID,FFieldName,FDstCtlField,FSelType,FDK,FColName,FName,FTableName,FTableAlias,FAction,FROB,FAllowEdited) values('A02',200000013,'FAuxQty',0,0,'FAuxQty','FQty','t_BOS200000013','v1','FQty - FQty1',0,0)
如果FAction不为空,则再拼接select时会用FAction来替换FName,
那么我们只需要将FAction插入FQty - FQty1即可;
再来看效果:
备注:如果再修改后台数据时,k3并未关闭,那么请在执行完脚本之后再任务管理器中杀掉k3cacheclient.exe进程,保证下次打开单据时是最新的模型;如果之前你再bos设计器建立了选单关系,请自行删掉(清理本文中涉及到的物理表数据),让他还原到一个未配置选单关系的状态;
完;
推荐阅读