碰到了一个金蝶KIS专业版“物料先采用批次管理并采用加权平均法计价后取消物料批次管理”问题,经和客户充分沟通,期间自己也分几次进行了SQL语句的执行测试,最终到2026年1月初解决,经过1月份期末的成本计算,生成凭证,结转下期,都是正常的。
为了把问题描述清楚,因此文字的内容有点多,盘点方案那一块的数据在执行SQL语句更新时总是报错,原因是违反了唯一性的数据约束,但考虑到实际情况是确实存在这种重复的可能性,所以最终就没有放上来,但该盘点方案数据对其他数据没有影响,所以分享出来希望能为有需要且有耐心看完的朋友提供些许帮助。
一、场景
客户使用KIS专业版16.0,除了总账和报表模块外,还使用了采购,仓存,存货核算,销售等模块。在2025年在进行账套初始化时,设置的参数是分仓核算,单据审核后更新库存。
根据我了解到的情况,建议存货的计价方法选择加权平均法,但业务部门后来表示,需要对物料按批次进行管理,对此,我和财务谈了按批次管理时,选择加权平均法的不足之外,建议如果确实需要进行批次管理,存货的计价方法更改为分批认定法比较合理,这样兼顾成本的计算的准确,满足批次管理的要求,但当时财务表示和关联企业一样,还是用加权平均法。
在完成初始化,正式上线使用。在使用到第3个月时,客户反映,但结账到下一期时,期初就会有期初异常余额的记录,我检查了各类报表以及成本计算的数据,物料收发明细表的数据对于各个批次的计算逻辑是:如果各个批次的入库成本不一致,则存货的出库成本按加权平均法计算出来是一致的,举例如下:
假设A物料,单价精度为小数点后6位,在2025年3月份,分别入库和出库的数量和成本如下:
2025-3-6,采购入库单数量为10个,批号为20250306-1,不含税的单位成本为12元,成本为120元
2025-3-9,采购入库单数量为20个,批号为20250309-2,不含税的单位成本为13元,成本为260元
2025-3-17,采购入库单数量为30个,批号为20250317-3,不含税的单位成本为15元,成本为450元
以上入库的总数量和总成本为60个,830元,加权平均成本约为830/60=13.833333元。
月末进行加权平均计算后出库数据如下:
2025-3-7,领料出库单数量为8个,批号为20250306-1,成本为110.67元。
2025-3-12,领料出库单数量为6个,批号为20250306-1的有2个,批号为20250309-2的有4个,成本为83元。
2025-3-18,领料出库单数量为18个,批号为20250309-2的有16个,批号为20250317-3的有2个,成本为248元。
查询出的月末结存的数量和成本如下:
批号为20250306-1的A物料,数量为0个,成本约为:120-13.83333310=-18.33元,是负数
批号为20250309-2的A物料,数量为0个,成本约为:260-13.83333320=-16.67元,是负数
批号为20250317-3的A物料,数量为28个,成本约为:450-13.833333*2=422.33元,是正数
月末结账时没有出现成本调整的提示,但结转到第4期时,期初会有异常余额的记录分别是:
批号为20250306-1的A物料,数量为0个,成本约为:-18.33元,是负数
批号为20250309-2的A物料,数量为0个,成本约为:-16.67元,是负数
需要对上述异常记录进行成本调整。
我把账套备份后再进行恢复,在恢复的账套反结账到第3期,删除存货核算模块自动生成的凭证,然后再进行成本计算,检查发现确实没有成本异常的记录,再重新在存货核算模块生成凭证后结账到第4期,确实在第4期出现了有期初异常余额的记录。
预计以上情况在后来的各个会计期间,随着入库出库的频繁,出现的记录条数会越来越多,对此,我给客户进行了讲解,客户也不想重新初始化处理,于是我提出了相关要求:
为了保证在同一个会计年度会计政策的一致性,因此到2025年12月末,在所有的存货相关的工作,包括单据,凭证全部生成,异常余额也完成调整,到等结账的状态时,可以选择按以下方案解决:
第1种方案:
在KIS专业版前台对库存数据进行调整,生成凭证,调整完成后,在账套的SQL数据库后台修改存货计价方法为分批认定法,下一年度以及以后所有期间都按批次进行管理,按分批认定法进行成本计算,2025年度物料批次信息仍然存在,但存货计价方法是加权平均法,财务需要写一个会计政策调整的说明文档备查。
第2种方案:
在账套的SQL数据库后台取消存货的批次管理,2025年已有批次的,全部取消批次,原有单据上的数据除了没有批次外,其他数据不会作任何变动,账套数据库的SQL后台凡是涉及到批次的表数据,对同一物料,同一期间,同一仓库,不同批次,全部进行汇总处理,全部完成后,下一年度以及以后所有期间仍然按加权平均法进行成本计算,财务需要写一个会计政策调整的说明文档备查。
从工作量和难度分析,我倾向于采用第1种方案,工作量小,难度小,风险低。
客户在综合考虑后,选择了第2种方案。
二、在完成SQL语句测试后,2026年1月初为客户账套解决了以上的问题,以下为相关的SQL后台语句:
--注:以下语句在执行前,请先备份账套,然后在恢复的账套中进行测试,测试无误后再到正式账套中执行,以下语句仅适用于金蝶KIS专业版16.0,补丁号更新到2025年第3季度,即2025年9月12日正式发版的的综合补丁PT180484,其他版本或补丁号仅供参考。
--1.ICInvInitial初始化表处理
--1.1将ICInvInitial初始余额表数据按字段进行汇总,并生成临时表,注:KIS专业版的最新版的ICInvInitial表中新增了两个字段FFieldCompose和FExpireDate,以前老版本没有这两个字段:
SELECT FBrNo,FPeriod,FStockID,FItemID,CONVERT(VARCHAR(200),'') AS FBatchNo,SUM(FBegQty) AS FBegQty,SUM(FReceive) AS FReceive,SUM(FSend) AS FSend,
SUM(FYtdReceive) AS FYtdReceive, SUM(FYtdSend) AS FYtdSend,SUM(FEndQty) AS FEndQty, SUM(FBegBal) AS FBegBal,
SUM(FDebit) AS FDebit,SUM(FCredit) AS FCredit,SUM(FYtdDebit) AS FYtdDebit,SUM(FYtdCredit) AS FYtdCredit,SUM(FEndBal) AS FEndBal,
SUM(FBegDiff) AS FBegDiff,SUM(FReceiveDiff) AS FReceiveDiff,SUM(FSendDiff) AS FSendDiff,FBillInterID,FUnitID,
SUM(FAuxBegQty) AS FAuxBegQty,SUM(FYtdBegQty) AS FYtdBegQty,SUM(FYtdAuxBegQty) AS FYtdAuxBegQty,SUM(FYtdAuxReceive) AS FYtdAuxReceive,
SUM(FYtdAuxSend) AS FYtdAuxSend,SUM(FYtdBegBal) AS FYtdBegBal,SUM(FYtdBegDiff) AS FYtdBegDiff, SUM(FYtdReceiveDiff) AS FYtdReceiveDiff,
SUM(FYtdSendDiff) AS FYtdSendDiff,FKFDate,FKFPeriod,FSPID,SUM(FSecBegQty) AS FSecBegQty,SUM(FSecReceive) As FSecReceive,
SUM(FSecSend) AS FSecSend,SUM(FSecYtdReceive) AS FSecYtdReceive,SUM(FSecYtdSend) AS FSecYtdSend,SUM(FSecEndQty) AS FSecEndQty,
FSecUnitID,FStockInDate,FAuxPropID,0 AS FSecCoefficient,SUM(FAuxUnitBegQty) AS FAuxUnitBegQty,SUM(FYtdAuxUnitBegQty) AS FYtdAuxUnitBegQty,
SUM(FYtdAuxUnitSend) AS FYtdAuxUnitSend,SUM(FYtdAuxUnitReceive) AS FYtdAuxUnitReceive,FSNListID,CONVERT(VARCHAR(200),'') AS FFieldCompose,CONVERT(VARCHAR(200),'') AS FExpireDate
INTO #TempICInvInitial
FROM ICInvInitial GROUP BY FBrNo,FPeriod,FStockID,FItemID,FBillInterID,FUnitID,FKFDate,FKFPeriod,FSPID,FSecUnitID,FStockInDate,FAuxPropID,FSNListID
--1.2清空ICInvInitial表数据,并重建表结构:
TRUNCATE TABLE ICInvInitial
--1.3把上述临时表数据重新插入到ICInvInitial表
INSERT INTO ICInvInitial SELECT * FROM #TempICInvInitial
--1.4对ICInvInitial表中的辅助换算率进行计算,如果
UPDATE ICInvInitial SET FSecCoefficient = CASE WHEN FSecBegQty<>0 THEN FBegQty/FSecBegQty ELSE 0 END
--1.4删除临时表
DROP TABLE #TempICInvInitial
--2.ICBal余额表处理
--2.1将ICBal表数据汇总生成临时表
SELECT FBrNo,FYear,FPeriod,FItemID,CONVERT(VARCHAR(200),'') AS FBatchNo,SUM(FBegQty) AS FBegQty,SUM(FReceive) AS FReceive,SUM(FSend) AS FSend,
SUM(FYtdReceive) AS FYtdReceive, SUM(FYtdSend) AS FYtdSend,SUM(FEndQty) AS FEndQty, SUM(FBegBal) AS FBegBal,
SUM(FDebit) AS FDebit,SUM(FCredit) AS FCredit,SUM(FYtdDebit) AS FYtdDebit,SUM(FYtdCredit) AS FYtdCredit,SUM(FEndBal) AS FEndBal,
SUM(FBegDiff) AS FBegDiff,SUM(FReceiveDiff) AS FReceiveDiff,SUM(FSendDiff) AS FSendDiff,SUM(FEndDiff) AS FEndDiff,
FBillInterID,FEntryID,FStockGroupID,SUM(FYtdReceiveDiff) AS FYtdReceiveDiff,SUM(FYtdSendDiff) AS FYtdSendDiff,
SUM(FSecBegQty) AS FSecBegQty,SUM(FSecReceive) As FSecReceive,SUM(FSecSend) AS FSecSend,SUM(FSecYtdReceive) AS FSecYtdReceive,
SUM(FSecYtdSend) AS FSecYtdSend,SUM(FSecEndQty) AS FSecEndQty,FStockInDate,FAuxPropID
INTO #TempICBal
FROM ICBal GROUP BY FBrNo,FYear,FPeriod,FItemID,FBillInterID,FEntryID,FStockGroupID,FStockInDate,FAuxPropID
--2.2清空ICBal表数据,并重建表结构:
TRUNCATE TABLE ICBal
--2.3把上述临时表数据重新插入到ICBal表
INSERT INTO ICBal SELECT * FROM #TempICBal
--2.4删除临时表
DROP TABLE #TempICBal
--3.ICInvBal库存余额表
--3.1将ICInvBal表数据汇总生成临时表
SELECT FBrNo,FYear,FPeriod,FStockID,FItemID,CONVERT(VARCHAR(200),'') AS FBatchNo,SUM(FBegQty) AS FBegQty,SUM(FReceive) AS FReceive,SUM(FSend) AS FSend,
SUM(FYtdReceive) AS FYtdReceive, SUM(FYtdSend) AS FYtdSend,SUM(FEndQty) AS FEndQty, SUM(FBegBal) AS FBegBal,
SUM(FDebit) AS FDebit,SUM(FCredit) AS FCredit,SUM(FYtdDebit) AS FYtdDebit,SUM(FYtdCredit) AS FYtdCredit,SUM(FEndBal) AS FEndBal,
SUM(FBegDiff) AS FBegDiff,SUM(FReceiveDiff) AS FReceiveDiff,SUM(FSendDiff) AS FSendDiff,SUM(FEndDiff) AS FEndDiff,FBillInterID,FStockPlaceID,
FKFPeriod,FKFDate,SUM(FYtdReceiveDiff) AS FYtdReceiveDiff,SUM(FYtdSendDiff) AS FYtdSendDiff,SUM(FSecBegQty) AS FSecBegQty,SUM(FSecReceive) As FSecReceive,
SUM(FSecSend) AS FSecSend,SUM(FSecYtdReceive) AS FSecYtdReceive,SUM(FSecYtdSend) AS FSecYtdSend,SUM(FSecEndQty) AS FSecEndQty,
FAuxPropID,FStockInDate
INTO #TempICInvBal
FROM ICInvBal GROUP BY FBrNo,FYear,FPeriod,FStockID,FItemID,FBillInterID,FStockPlaceID,FKFPeriod,FKFDate,FAuxPropID,FStockInDate
--3.2清空ICInvBal表数据,并重建表结构:
TRUNCATE TABLE ICInvBal
--3.3把上述临时表数据重新插入到ICInvBal表
INSERT INTO ICInvBal SELECT * FROM #TempICInvBal
--3.4删除临时表
DROP TABLE #TempICInvBal
-----------===================
--4.poInvBal虚仓余额表,根据实际情况,如果没有数据就不用处理
--4.1将poInvBal表数据汇总生成临时表
SELECT FBrNo,FYear,FPeriod,FStockID,FItemID,CONVERT(VARCHAR(200),'') AS FBatchNo,SUM(FBegQty) AS FBegQty,
SUM(FReceive) AS FReceive,SUM(FSend) AS FSend,
SUM(FYtdReceive) AS FYtdReceive, SUM(FYtdSend) AS FYtdSend,SUM(FEndQty) AS FEndQty, SUM(FBegBal) AS FBegBal,
SUM(FDebit) AS FDebit,SUM(FCredit) AS FCredit,SUM(FYtdDebit) AS FYtdDebit,SUM(FYtdCredit) AS FYtdCredit,
SUM(FEndBal) AS FEndBal,
SUM(FBegDiff) AS FBegDiff,SUM(FReceiveDiff) AS FReceiveDiff,SUM(FSendDiff) AS FSendDiff,SUM(FEndDiff) AS FEndDiff,FBillInterID,
FKFPeriod,FKFDate,sum(FSPID) FSPID,sum(FDCSPID) FDCSPID,SUM(FSecBegQty) AS FSecBegQty,SUM(FSecReceive) As FSecReceive,
SUM(FSecSend) AS FSecSend,SUM(FSecYtdReceive) AS FSecYtdReceive,SUM(FSecYtdSend) AS FSecYtdSend,
SUM(FSecEndQty) AS FSecEndQty,
FAuxPropID
INTO #TemppoInvBal
FROM poInvBal GROUP BY FBrNo,FYear,FPeriod,FStockID,FItemID,FBillInterID,FKFPeriod,FKFDate,FAuxPropID
--4.2清空poInvBal表数据,并重建表结构:
TRUNCATE TABLE poInvBal
--4.3把上述临时表数据重新插入到poInvBal表
INSERT INTO poInvBal SELECT * FROM #TemppoInvBal
--4.4删除临时表
DROP TABLE #TemppoInvBal
--insert into poInvBal select * from poInvBalback
--5.ICInventory表,实仓即时库存表
--5.1将ICInventory表数据汇总生成临时表
SELECT FBrNo,FItemID,CONVERT(VARCHAR(200),'') AS FBatchNo,FStockID,SUM(FQty) AS FQty,SUM(FBal) AS FBal,
FStockPlaceID,FKFPeriod,FKFDate,SUM(FQtyLock) AS FQtyLock,FAuxPropID,SUM(FSecQty) AS FSecQty
INTO #TempIcInventory
FROM ICInventory GROUP BY FBrNo,FItemID,FStockID,FStockPlaceID,FKFPeriod,FKFDate,FAuxPropID
--5.2清空ICInventory表数据,并重建表结构:
TRUNCATE TABLE ICInventory
--5.3把上述临时表数据重新插入到ICInventory表
INSERT INTO ICInventory SELECT * FROM #TempIcInventory
--5.4删除临时表
DROP TABLE #TempIcInventory
--6.POInventory代管库存表,虚仓即时库存表,根据实际情况,如果没有数据就不用处理
--6.1将数据汇总转入临时表
SELECT FBrNo,FItemID,CONVERT(VARCHAR(200),'') AS FBatchNo,FStockID,SUM(FQty) AS FQty,SUM(FBal) AS FBal,
FStockPlaceID,FKFPeriod,FKFDate,FStockTypeID,FAuxPropID,SUM(FSecQty) AS FSecQty
INTO #TempPOInventory
FROM POInventory GROUP BY FBrNo,FItemID,FStockID,FStockPlaceID,FKFPeriod,FKFDate,FStockTypeID,FAuxPropID
--6.2清空POInventory表数据,并重建表结构:
TRUNCATE TABLE POInventory
--6.3把上述临时表数据重新插入到POInventory表
INSERT INTO POInventory SELECT * FROM #TempPOInventory
--6.4删除临时表
DROP TABLE #TempPOInventory
--7.清除物料批次属性,t_ICItem物料视图
UPDATE t_ICItem SET FBatchManager = 0 WHERE FBatchManager = 1
--8.清除供应链库存单据分录表中的【批号】
UPDATE ICStockBillentry SET FBatchNo=CONVERT(VARCHAR(200), '') WHERE FBatchNo IS NOT null
--9.清除物料通用属性设置中的【批号】勾选
UPDATE t_ICItemCommonProp SET FBatchManager = 0 WHERE FBatchManager = 1

