### 说明 期末结账功能目前的设计是,在总账期末结账界面点击“结账”按钮,服务端依次检查各个模块,如果存在异常,则提示 用户,用户可以选择通过“继续结账”忽略掉这些异常;否则就依次结账各个模块。 由于涉及的模块较多,且分属不同代码模块。因此当点击结账时,通过发布事件的方式,其余模块捕获事件做结账前检测、结账时动作。 代码在`com.usoftchina.saas.finance.controller.LedgerController.endGeneralLedger` ``` BeforePeriodEndEvent beforePeriodEndEvent = new BeforePeriodEndEvent(currentPeriod, nextPeriod); // 结账前事件,其他模块通过该事件做结账前检测 SpringContextHolder.getContext().publishEvent(beforePeriodEndEvent); if (beforePeriodEndEvent.hasError() || beforePeriodEndEvent.hasWarn()) { return Result.error(beforePeriodEndEvent); } PeriodEndEvent periodEndEvent = new PeriodEndEvent(currentPeriod, nextPeriod); // 结账事件,其他模块通过该事件做结账动作 SpringContextHolder.getContext().publishEvent(periodEndEvent); ``` 反结账也是通过事件,通知其他模块。 ``` PeriodUnEndEvent periodUnEndEvent = new PeriodUnEndEvent(currentPeriod, prevPeriod); // 反结账事件,其他模块通过该事件做反结账动作 SpringContextHolder.getContext().publishEvent(periodUnEndEvent); ``` > #### 结账前检测 - 应收 扩展代码在`com.usoftchina.saas.money.listener.ArPeriodEndListener.beforePeriodEndEvent` ``` @EventListener(BeforePeriodEndEvent.class) public void beforePeriodEndEvent(BeforePeriodEndEvent event) { // 当期存在未审核的单据 checkUnAudit(event); // 当期存在未生成凭证的单据 checkUnVoucher(event); // 当期应收期末与总账应收账款科目余额不一致 checkRecBalance(event); // 当期预收期末与总账预收账款科目余额不一致 checkPreRecBalance(event); } ``` - 应付 扩展代码在`com.usoftchina.saas.money.listener.ApPeriodEndListener.beforePeriodEndEvent` ``` @EventListener(BeforePeriodEndEvent.class) public void beforePeriodEndEvent(BeforePeriodEndEvent event) { // 当期存在未审核的单据 checkUnAudit(event); // 当期存在未生成凭证的单据 checkUnVoucher(event); // 当期应付期末与总账应收账款科目余额不一致 checkPayBalance(event); // 当期预收期末与总账预收账款科目余额不一致 checkPreRecBalance(event); } ``` - 库存 扩展代码在`com.usoftchina.saas.storage.listener.StPeriodEndListener.beforePeriodEndEvent` ``` @EventListener(BeforePeriodEndEvent.class) public void beforePeriodEndEvent(BeforePeriodEndEvent event) { // 当期存在未审核的出入库单 checkUnAudit(event); // 当期存在未生成凭证的单据 checkUnVoucher(event); // 当期库存余额与总账存货科目余额不一致 checkBalance(event); } ``` 制造版补充扩展代码在`com.usoftchina.saas.make.listener.MakePeriodEndListener.beforePeriodEndEvent` ``` @EventListener(BeforePeriodEndEvent.class) public void beforePeriodEndEvent(BeforePeriodEndEvent event) { String appId = BaseContextHolder.getAppId(); if ("make-app".equals(appId)) { // 当期存在未审核的报废单 checkUnAudit(event); } } ``` - 成本 制造版补充扩展代码在`com.usoftchina.saas.finance.listener.CoPeriodEndListener.beforePeriodEndEvent` ``` @EventListener(BeforePeriodEndEvent.class) public void beforePeriodEndEvent(BeforePeriodEndEvent event) { String appId = BaseContextHolder.getAppId(); if ("make-app".equals(appId)) { // 当期成本表制造工单(期末金额+期末报废结余)与总账生产成本:直接材料科目余额不一致 checkBalance(event); // 当期成本表外协工单(期末金额+期末报废结余)与总账委托加工物资科目余额不一致 checkOsBalance(event); } } ``` - 总账 扩展代码在`com.usoftchina.saas.finance.listener.GlPeriodEndListener.beforePeriodEndEvent` ``` @EventListener(BeforePeriodEndEvent.class) @Order(100) public void beforePeriodEndEvent(BeforePeriodEndEvent event) { // 当期存在未审核的凭证 checkUnAudit(event); // 当期存在断号的凭证 checkBrokenNumber(event); // 当期银行余额与总账银行现金科目余额不一致 checkBankBalance(event); // 存在未结转损益余额 checkLossBalance(event); } ``` > #### 结账 - 库存/应收/应付/成本 扩展代码在`com.usoftchina.saas.biz.listener.BizPeriodEndListener.onPeriodEndEvent` ``` @EventListener(PeriodEndEvent.class) @Order(1) public void onPeriodEndEvent(PeriodEndEvent event) { // 该方法调用的是sp_end存储过程,该过程囊括了库存/应收/应付/成本的期末数据结转 endProductService.endAccount(event.getCurrentPeriod()); } ``` - 总账 扩展代码在`com.usoftchina.saas.finance.listener.GlPeriodEndListener.onPeriodEndEvent` ``` @EventListener(PeriodEndEvent.class) @Order(100) public void onPeriodEndEvent(PeriodEndEvent event) { ledgerService.end(event.getCurrentPeriod()); } ``` > #### 反结账 - 库存/应收/应付/成本 扩展代码在`com.usoftchina.saas.biz.listener.BizPeriodEndListener.onPeriodUnEndEvent` ``` @EventListener(PeriodUnEndEvent.class) @Order(1) public void onPeriodUnEndEvent(PeriodUnEndEvent event) { endProductService.unEndAccount(event.getCurrentPeriod()); } ``` - 总账 扩展代码在`com.usoftchina.saas.finance.listener.GlPeriodEndListener.onPeriodUnEndEvent` ``` @EventListener(PeriodUnEndEvent.class) @Order(100) public void onPeriodUnEndEvent(PeriodUnEndEvent event) { ledgerService.unEnd(event.getCurrentPeriod()); } ```