SpringBoot+Vue3 凭证生命周期设计:审核、过账、冲销与反过账怎样保持账目一致
凭证状态说明谁确认了什么,账簿余额说明哪笔分录真正生效。两者必须由同一套操作规则连接。
图1|imagegen独立生成的1500×1000概念图。500元与图内日期均为假设,不是系统记录;“原凭证保持留痕”表示保留分录并建立红冲关联,原单红冲标记仍会更新。图中并发提示是验收边界。
一、一张凭证审核了,为什么账簿还没有变化
会计录了一张500元费用凭证,主管完成审核。
业务同事打开科目余额表,发现费用仍未增加,以为系统漏记了。
另一个同事看到“已过账”,想直接把500改成450,又被系统拦住。
这两个现象其实来自同一条设计:确认凭证与使分录入账是两个不同动作,入账后的更正需要显式撤回或补充记录。
在RuoYi Office中,可以从凭证录入进入详情,查看分录与借贷合计;从账簿查询看余额,再从财务设置的审计日志追查操作。
这条路径适合会计日常核对,也适合Java团队审查生命周期实现。
本文基于2026年11月1日当前工作树的Spring Boot 3体系源码。
本地5800/48080运行环境使用既有资产教程包,未从当前源码重新构建。
因此,“源码执行链”和“现有界面展示”分别记录,不拿它们互相替代。
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
第10篇已经讨论账套、科目与期间,第12篇已经讨论来源与模板取数。
这里从“凭证已经存在”开始,聚焦它怎样进入账面,以及错账怎样留下可以解释的更正链。
二、先把状态与红字标记分开
暂存、已审核、已过账、已作废是凭证状态;普通、红字、已被红冲是另一组标记。
原凭证被红冲以后仍是已过账,原分录继续留在历史记录中。
新增的红字凭证也是已过账,靠负金额抵减,而不是把原状态改成“作废”。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这张表表达源码规则,不是本次已点击通过的操作清单。
尤其作废入口没有统一调用期间可记账校验,不能将其他操作的期间限制自动套到它身上。
状态图|按当前服务整理。原单红冲时保留已过账,另建红单;Mermaid源文件存于过程目录。
状态图中红冲的自环指原单状态保持已过账,并不表示没有新增记录。
反过账也只退到已审核,若要修改手工凭证,还要先反审核。
状态图与主图共同表达状态变化;精简ER进一步解释字段关系。
图2|本次只读查看既有凭证id=32,2026-08转-0001,借贷合计各500。列表观察为已过账、普通,来源FI504-2026090600008;详情只证明现有展示,不是本文执行审核过账的结果,也不是报销id=3的成功链。
审核确认责任,不提前累计发生额
人工审核先确认暂存态,再检查账套、期间与制单审核分离。
审核方法没有调用余额服务,已审核不会自动改变余额。
这让财务可以在复核完成后单独决定何时过账。
源码摘录1:FinanceVoucherServiceImpl.java,359—382行,连续原文;完整路径与SHA-256见来源审计。
private void doAudit(Long id, boolean skipSeparation) {FinanceVoucherDO voucher = validateVoucherExists(id);if (!FinanceVoucherStatusEnum.DRAFT.getStatus().equals(voucher.getStatus())) {throw exception(VOUCHER_STATUS_FORBIDDEN);}FinanceBookDO book = bookValidator.validateEnabled(voucher.getBookId());periodService.validatePostable(book.getId(), voucher.getVoucherDate());Long userId = SecurityFrameworkUtils.getLoginUserId();// 制单审核分离是内控要求,账套级可关;系统自动生成的凭证不受此限if (!skipSeparation && Boolean.TRUE.equals(book.getMakerAuditorSeparate())&& ObjUtil.equals(userId, voucher.getMakerId())) {throw exception(VOUCHER_MAKER_AUDITOR_SAME);}voucherMapper.updateById(FinanceVoucherDO.builder().id(id).status(FinanceVoucherStatusEnum.AUDITED.getStatus()).auditorId(userId).auditorName(SecurityFrameworkUtils.getLoginUserNickname()).auditTime(LocalDateTime.now()).build());auditLogService.log(voucher.getBookId(), voucher.getCompanyId(), AUDIT_BIZ_TYPE, id,voucher.getVoucherNoText(), "AUDIT",StrUtil.format("审核凭证 {}", voucher.getVoucherNoText()));}
这里的skipSeparation有实际含义:自动审核和红冲内部审核会传入true。
它跳过的是制单人与审核人相同的限制,并没有跳过账套和期间校验。
不能因此宣传“所有审核都强制双人分离”。
模板组合也需要按控制流判断:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
核对位置是模板服务315—318行,以及凭证服务630—635行。
来源队列标为“已生成”也不等于“已过账”:即使凭证停在暂存或已审核,生成服务仍会标记来源已生成,防止顺序重复制证。
三、过账要同时改变余额与凭证状态
过账的业务承诺是:成功时余额包含本张分录,凭证也处于已过账;失败时不留下半张生效的账。
代码顺序是先校验,后调用余额服务,再改凭证状态、更新来源、写审计。
这些写入需要在正常Spring代理调用和同一事务资源下共同提交。
源码摘录2:FinanceVoucherServiceImpl.java,410—429行,连续原文;完整路径与SHA-256见来源审计。
private void doPost(Long id) {FinanceVoucherDO voucher = validateVoucherExists(id);if (FinanceVoucherStatusEnum.POSTED.getStatus().equals(voucher.getStatus())) {throw exception(VOUCHER_ALREADY_POSTED);}if (!FinanceVoucherStatusEnum.AUDITED.getStatus().equals(voucher.getStatus())) {throw exception(VOUCHER_NOT_AUDITED);}bookValidator.validateEnabled(voucher.getBookId());periodService.validatePostable(voucher.getBookId(), voucher.getVoucherDate());List<FinanceVoucherItemDO> items = voucherItemMapper.selectListByVoucherId(id);balanceService.post(voucher, items);voucherMapper.updateById(FinanceVoucherDO.builder().id(id).status(FinanceVoucherStatusEnum.POSTED.getStatus()).posterId(SecurityFrameworkUtils.getLoginUserId()).posterName(SecurityFrameworkUtils.getLoginUserNickname()).postTime(LocalDateTime.now()).build());
这段连续源码展示余额与状态的相邻关系。
后续430—436行更新来源并写POST日志;对外postVoucher在404—408行声明回滚事务。
余额服务的post也有事务声明,默认传播加入外层事务,没有声明独立提交。
图3|按源码整理的事务时序示意,原始Mermaid保存在过程目录。尚未对产品执行余额失败、日志失败或数据库断连注入。
时序上,余额先写并不意味着其他请求应该提前看到未提交的中间状态。
实际可见性还取决于数据库隔离与事务配置,本次没有连接业务库检查隔离级别。
同样,单凭@Transactional存在,不能宣布跨服务资源、代理入口与所有失败路径已经验收。
同一张凭证内,先汇总再更新
余额服务先把分录归并成科目增量。
每个末级科目的祖先链一并累计,辅助余额按科目与辅助键另行归并。
反过账复用这条路径,只把每条金额再取一次负值。
源码摘录3:FinanceBalanceServiceImpl.java,81—103行,连续原文;完整路径与SHA-256见来源审计。
// 1. 先把分录汇总成「科目 → 借贷增量」,同一科目在一张凭证里出现多次只更新一次Map<Long, Delta> subjectDeltas = new LinkedHashMap<>();Map<String, AuxDelta> auxDeltas = new LinkedHashMap<>();for (FinanceVoucherItemDO item : items) {BigDecimal amount = FinanceBalanceUtils.nullToZero(item.getAmount());if (reverse) {amount = amount.negate();}// 祖先链一起累加,父科目余额就等于下级汇总,账簿查询不必递归for (FinanceSubjectDO subject : resolveChain(context, item.getSubjectId())) {subjectDeltas.computeIfAbsent(subject.getId(), id -> new Delta(subject)).add(item.getDirection(), amount);}if (StrUtil.isNotBlank(item.getAuxKey())) {FinanceSubjectDO subject = context.subjects.get(item.getSubjectId());if (subject != null) {auxDeltas.computeIfAbsent(item.getSubjectId() + "#" + item.getAuxKey(),key -> new AuxDelta(subject, item.getAuxKey(), item.getAuxData())).add(item.getDirection(), amount);}}}
随后105—115行落库,科目与辅助各自执行“确保余额行存在、SQL增量、向后重算”。
科目增量用debit_amount = debit_amount + (...)和贷方同类表达式,避免不同凭证更新同一余额时简单覆盖发生额。
首次建行会捕获唯一键冲突,schema基线也包含科目、辅助余额维度唯一索引。
但这些机制只解决了部分问题:余额行增量不覆盖,不等于同一凭证只累计一次。
后续重算会读取已有期间余额并按ID更新期初、累计与期末;跨期并发补录、不同辅助更新顺序仍应集成验证。
图4|精简逻辑ER。余额是分录按维度归并的结果,图中连接不代表全部存在物理外键。红冲关系与业务来源关系必须分别保存。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
四、用一组独立数字,复算过账与更正
下面全部是独立假设,不取自截图账套,也没有写入任何财务数据库。
假设8月存在一张费用确认凭证V1:借费用500,贷其他应付款500。
两个科目期初均为零,不考虑税、付款、结转与其他业务。
这只是生命周期案例,不重复第12篇模板如何取数。
同期撤回与重新过账
|
|
|
|
|
|
|
|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
反过账撤回的是本张凭证对余额的贡献,不是把整个科目的余额清零。
如果还有另一张费用200元已过账,撤回V1后应保留那200元。
父科目与对应辅助组合也应撤回同一增量,不能只改总账。
余额统一可以按“借为正、贷为负”理解:
带符号期末 = 带符号期初 + 本期借方发生 - 本期贷方发生费用:0 + 500 - 0 = +500(借)应付款:0 + 0 - 500 = -500(贷)反过账后:两条对应发生额各减回500,余额贡献回到0
表中的期末是“金额+方向”展示,不是让所有数据库余额字段都存负数。
源码通过FinanceBalanceUtils在带符号计算与金额、方向字段之间转换。
父子科目不能全层相加,否则会把同一笔发生额重复统计。
同月红冲与正确凭证
假设V1已过账后发现应记450元,采用“全额红冲,再记正确凭证V2”的方案。
该方案与原单改金额的区别,在于原500与红字-500均可追溯。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这不是把借贷方向互换:换成贷费用500、借应付500也能影响净余额,但会改变借贷发生额的列口径。
当前产品红冲明确采用原方向负金额。
因此验收时除了净余额,还要比对借方、贷方发生额及红冲关系。
跨月红冲不会抹去原月
如果8月已经关闭,红冲日期指定为可记账的9月:8月费用借方仍为500,9月费用借方为-500。
假设9月没有其他发生,费用的9月期初为借500,期末回到零。
年度净发生归零,8月原始发生仍然存在。
红冲请求未指定日期时,源码默认使用原凭证日期。
原月已关闭则默认日期会被期间校验拦截,不能宣传系统会自动寻找当前开放月份。
要在制度允许的更正日期明确操作,本次只分析规则,没有执行跨期红冲。
五、更正要保留原单、红字与来源三种关系
红冲不是修改原单,也不是解除原始业务单据的事实责任。
原凭证保留sourceType、sourceId、sourceQueueId;红字复制这些来源,并用redSourceId指回原凭证。
成功后原单写入redTargetId,红字标记变为“已被红冲”。
红字分录复制业务坐标,金额取负
代码保留科目、方向、辅助组合、币种、汇率与现金流项目。
本币金额、原币金额和数量取负,单价保留。
这些字段决定红冲是否真正落到原来的核算位置。
源码摘录4:FinanceVoucherServiceImpl.java,543—565行,连续原文;完整路径与SHA-256见来源审计。
for (FinanceVoucherItemDO originItem : originItems) {FinanceVoucherItemDO redItem = FinanceVoucherItemDO.builder().seq(originItem.getSeq()).summary(StrUtil.format("红冲:{}", StrUtil.blankToDefault(originItem.getSummary(), reason))).subjectId(originItem.getSubjectId()).subjectCode(originItem.getSubjectCode()).subjectName(originItem.getSubjectName()).direction(originItem.getDirection())// 红字凭证保持原方向、金额取负,账簿上体现为对应方向的冲减.amount(originItem.getAmount().negate()).auxKey(originItem.getAuxKey()).auxData(originItem.getAuxData()).currencyCode(originItem.getCurrencyCode()).exchangeRate(originItem.getExchangeRate()).origAmount(originItem.getOrigAmount() == null ? null : originItem.getOrigAmount().negate()).quantity(originItem.getQuantity() == null ? null : originItem.getQuantity().negate()).price(originItem.getPrice()).cashFlowItem(originItem.getCashFlowItem()).build();assembly.items.add(redItem);}insertWithVoucherNo(assembly, red);saveItems(assembly, red);
红冲不会按最新科目映射重新解释原分录。
这对追溯有价值,也意味着“原科目被停用或辅助对象变更后怎样处理”应纳入隔离环境测试。
红冲入口直接复制分录,不能把手工组装时的全部科目有效性校验当成红冲已经重复执行。
建红单、过账和标记原单要共同成功
入口先建红字暂存凭证并保存分录,再自动审核过账,最后更新原单关联与RED审计。
它不把红字半成品作为正常成功结果留给用户。
源码摘录5:FinanceVoucherServiceImpl.java,567—581行,连续原文;完整路径与SHA-256见来源审计。
// 红冲的目的就是把账冲平,因此红字凭证直接审核并过账,不留半成品状态doAudit(red.getId(), true);doPost(red.getId());voucherMapper.updateById(FinanceVoucherDO.builder().id(origin.getId()).redFlag(FinanceVoucherRedFlagEnum.REVERSED.getFlag()).redTargetId(red.getId()).build());auditLogService.log(book.getId(), book.getCompanyId(), AUDIT_BIZ_TYPE, origin.getId(),origin.getVoucherNoText(), "RED",StrUtil.format("红冲凭证 {},生成红字凭证 {},原因:{}", origin.getVoucherNoText(),red.getVoucherNoText(), reason));return red.getId();}
红冲方法497—499行声明事务;内部doAudit、doPost是同对象私有调用,依赖外层事务,而不是各自重新开事务。
如果过账或日志异常向外传播,预期回滚红单、余额、来源与原单标记。
这里仍是源码上的原子性目标,本次没有做数据库故障注入来证明实际部署满足它。
来源队列的当前指针不是完整历史
过账会调用markVoucherGenerated把来源指针更新到当前凭证。
红字复制sourceQueueId并执行过账,来源指针因此也可能指向红单。
业务侧撤销的另一路径在红冲后把来源重置待生成;直接红冲入口没有同样的最终重置。
selectBySourceQueueId按ID倒序取最新凭证,不筛普通或红字。
所以“按来源找凭证”不一定永远拿到原单。
追溯原单、红字和新正确凭证,应分别检查双向红冲ID、来源身份及来源当前指针。
反过账同样会把来源标成待生成,而原凭证仍存在且是已审核。
如果随后重新生成来源,再对旧凭证重新过账,是否会出现两个有效结果,不能只看队列状态判断。
生成入口按来源状态防重,没有等价于“所有历史凭证中只允许一个生效结果”的完整证明。
这是隔离环境应优先验证的组合路径,不是本次真实账套已发生重复的结论。
红字反过账是额外的验收点
当前反过账禁止的是“已被红冲”的原凭证,对redFlag为RED的已过账凭证没有同样拦截。
如果红字被反过账,余额会撤回负增量;但这段路径没有同步清理原单redTargetId与已被红冲标记。
从算术看,原500与红-500本已抵零,撤回红字后净额又回到500。
这说明“先处理红字凭证”的注释不等于完整恢复链已经闭合。
必须在隔离环境核对后续能否再次红冲、来源指向谁、原单如何解除关联,制定明确的更正制度。
本文不为写稿修产品,也不会把这条路径描述成已验收的标准操作。
六、账簿与审计,要各自证明一件事
凭证详情证明分录内容,余额表证明聚合结果,审计证明已记录的操作责任。
三者不能互相替代,尤其不能用一条POST日志代替余额对账。
图5|本次只读查看P1操作学习账2026-08余额表:2241贷方500,5602及其末级560203借方500,末级合计500/500。它与图2处于同账套期间,属于既有结果核对,不是本次执行过账的前后对比,也未验全部账簿报表。
余额表主要从科目余额表读取;明细类账簿通过selectPostedList选择已过账凭证,再取分录。
两条取数路径应能按同账套、同期间、同科目与辅助口径核对。
凭证汇总服务则会汇总未作废凭证,不只已过账,不能直接把凭证汇总金额当作已过账余额。
图6|本次只读查看既有POST日志,业务对象转-0001,借贷合计500,操作时间2026-09-06 21:51:04。响应bizId=32可关联图2既有凭证;这是历史记录,不是本次执行过账或红冲的成功证据。前后快照显示“无”,未人为补造冲销记录。
审计服务有beforeData和afterData字段,但凭证生命周期调用的是简化重载,前后数据传入null。
现有证据足以说明“保存动作、说明、操作者、IP和时间”,不足以说明“每次分录修改都有完整前后快照”。
需要完整更正复盘时,应把原凭证分录、红单分录、关联ID与业务材料一起保留。
同事务写审计还有另一面:失败导致事务回滚时,成功动作日志也会回滚。
不能因此推断失败尝试自动有一条永久财务审计记录。
失败接口日志、业务告警与审计日志是不同证据来源,需要分别设计与验收。
七、重复请求要分顺序与并发验证
状态检查能拒绝已完成操作的顺序重试,但不能天然阻止两个请求同时通过旧状态。
当前doPost先普通selectById,再增余额,最后updateById。
本路径未见凭证行锁、带旧状态条件的原子抢占、版本字段或统一操作幂等键。
凭证号唯一索引约束的是号码,不是同一凭证过账次数。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
结账服务确实存在按账套的分布式锁;本次核对的凭证过账路径没有参与同一个锁。
因此不能从“结账有锁”推导“结账与所有记账操作已经互斥”。
这些是从控制流得到的候选风险,不是对现有业务库压测所得的故障报告。
独立交错模型,单位元:A读取凭证=已审核;B也读取凭证=已审核A累加借500、贷500;B再累加借500、贷500A写已过账;B也写已过账最终状态只有一个“已过账”,发生额却可能累计1000
可选改进思路是在隔离分支中统一凭证与期间的加锁顺序,或用带预期状态的原子更新抢占操作资格。
若使用条件更新,必须检查影响行数,并让抢占、余额、状态、来源、日志处于同一事务。
还需要明确定义超时重试:返回原结果,还是返回“已处理”,不能让客户端靠报错猜余额。
这些是二开建议,本文没有把它们加进产品代码。
本地模型实际验了什么
本次运行model-checks.mjs,使用整数分、自建对象与断言完成15项检查。
它没有加载产品服务,没有Spring、MyBatis、Redis或数据库。
因此“全部通过”只代表模型中的算术和指定交错符合预期。
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
可复查的运行记录是过程目录model-validation.json。
源码连续摘录另有逐字、行号与SHA-256校验,不拿自建模型冒充原始产品测试。
八、把失败路径写进交付验收
采购验收应检查操作后的状态、发生额、余额、来源和日志,而不只看按钮提示成功。
以下写操作均应在独立账套或隔离数据库执行,本篇没有在现有财务数据库执行它们。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
批量审核、过账通过self代理逐张调用,单张事务分开。
但批量循环只捕获ServiceException;数据库等其他异常可能终止后续处理,之前成功的张数可能已提交。
客户端遇到整批请求异常,不能直接假设整批全部没做,需要逐张查询结果。
反审核、反过账代码将审核人或过账人字段设置为null再updateById。
实际数据库是否清空,还取决于MyBatis字段更新策略;相关字段未见显式ALWAYS配置,本次未执行SQL核验。
不能仅凭builder里写了null,就承诺界面上旧操作人时间一定清除。
原始操作留痕应以审计为依据,同时测试状态字段与展示字段的一致性。
P1学习账套2026-08曾出现报表“不平衡,差额-500.00”,损益未结转也阻断月结。
这些现象本篇保留未定性,没有改库或修产品,也没有裁掉提示来制造通过证据。
一张凭证借贷平衡,只证明该凭证合计相等,不能证明报表、结转与月结全部通过。
九、按只读路线体验,再决定隔离验收范围
在线体验入口见文末演示地址,演示账号按页面提示使用。
本地已启动的5800环境,本次使用开发演示账号admin,只读取现成数据。
可以按下面顺序核对页面:
-
凭证管理→凭证录入,先确认账套和期间。 -
打开既有详情,核对分录方向、金额和借贷合计。 -
账簿查询→科目余额表,核对同口径期间与科目层级。 -
财务设置→审计日志,查看已有动作详情与说明。 -
记录来源号和红冲关联;没有记录时转入隔离验收清单。
本篇不建议为了跟文中步骤而在现有账套点审核、过账、红冲、反过账或结账。
开发接手时可按实际交付说明启动后端与PC端;命令只作定位,本次没有重启共享服务。
cd E:\ruoyi-office\ruoyi-officemvn -P boot -DskipTests compile# 按交付配置启动 yudao-server# 另一个终端启动 PC 管理端cd E:\ruoyi-office\ruoyi-office-vbenpnpm dev:antd
财务源码属于实际商业交付范围,公开仓库不代表所有财务模块都包含或可以免费商用。
对Java团队,源码的价值是可以定位真实事务边界、扩展更正政策并建立回归样例;这些工作需要与授权范围和交付清单一起确认。
FAQ
1. 审核凭证以后,科目余额为什么没有增加?
审核确认凭证,过账才累计余额。当前审核方法只更新状态、审核人与日志;必须完成过账,分录才进入已过账明细和余额更新路径。
2. 反审核、反过账和红冲有什么区别?
反审核把已审核退回暂存,不动余额;反过账撤回原增量并退回已审核;红冲保留原已过账记录,新增同方向负金额凭证,建立原单与红单关联。不同路径的期间与来源策略要分别验收。
3. 已过账凭证可以直接改金额吗?
当前修改入口只允许暂存,来源生成凭证还禁止直接改分录。手工凭证若制度允许,可在开放期间先反过账再反审核;已关闭期间通常需要按允许日期红冲并建立正确记录,不能绕开期间规则直接改库。
4. 加了事务和SQL自增,是否就不会重复过账?
不能这样推导。事务处理一次操作的共同提交,SQL自增防止增量覆盖;同一凭证的两个并发请求还需要共同的准入保护。本篇发现候选缺口,未完成产品并发压测。
5. 有审计日志,是否表示每次修改都有完整快照?
不一定。当前凭证调用简化日志接口,前后数据为空,主要记录动作、说明、用户与时间。完整更正追溯还应保留原分录、红字分录、来源身份和关联ID,并在隔离环境验收。
来源与本次边界
资料与配图完整定位见来源说明,包含文件SHA-256、连续摘录行号、截图路由和验证材料。
设计图由当前执行链整理,主图为AI生成;没有使用外部产品图片,没有把生成图当实测界面。
本篇参考账套、科目与期间建模、业务单据自动制证及前篇来源审计,聚焦生命周期而非重复取数模板。
报销id=3及预算id=7历史流程缺失问题不在本次修复范围,现有运行包也未重新构建。
本次完成只读页面取证、源码核查、自建金额模型及文章双端预览。
没有创建保存财务单据,没有审批、付款、核销、制证、审核、过账、红冲、反过账、结转、改库或压力测试。
文章布局通过只说明图文可读,不代表财务产品采购验收通过。
你们更正错账时,最难统一的是期间政策、红字撤回,还是来源单据再次生成的规则?

