Fms-Java版开发实录:29 合同中的明细数据汇总

Fms-Java版开发实录:29 合同中的明细数据汇总

由于现在已经有了Journal类,现在可以给Contract添加一些方法和判断,然后修改合同的详情页和展示列表,让合同对象把所属明细记录都汇总起来,进行一些展示和判断

由于现在已经有了Journal类,现在可以给Contract添加一些方法和判断,然后修改合同的详情页和展示列表,让合同对象把所属明细记录都汇总起来,进行一些展示和判断。

Journal类列表

由于目前Journal类是挂在合同下边,所以根据合同列出对应的明细记录是我要要继续编写的功能,控制器比较简单:

    // 明细记录列表
    @GetMapping("/contract/{cid}/list")
    public String journalList(@PathVariable("cid") int cid, Model model) {
        Contract contract = contractService.getContractById(cid);
        Set<Budget> budgets = contract.getBudgets();
        Budget budget = (Budget) (budgets.toArray()[0]);
        Project project = budget.getProject();
        Set<Journal> journals = contract.getJournals();
        model.addAttribute("project", project);
        model.addAttribute("contract", contract);
        model.addAttribute("journals", journals);
        model.addAttribute("count", journals.size());
        model.addAttribute("contractData", contractService.getContractData(cid));
        return "pms/journal/journalList";
    }

页面也不复杂,如下:

<main class="container">
    <nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb" class="mt-3">
        <ol class="breadcrumb">
            <li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list" th:href="@{/pms/project/list}"
                                                               class="link-secondary">项目管理</a></li>
            <li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
                                                               th:href="${project.absoluteUrl()}"
                                                               class="link-secondary">[[${project.projectName}]]</a>
            </li>
            <li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
                                                               th:href="${project.contractListUrl()}"
                                                               class="link-secondary">合同列表</a>
            </li>
            <li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
                                                               th:href="${contract.absoluteUrl()}"
                                                               class="link-secondary">[[${contract.name}]]</a>
            </li>
            <li class="breadcrumb-item" aria-current="page"><a href="/pms/project/list"
                                                               th:href="${contract.journalListUrl()}"
                                                               class="link-secondary">明细记录列表</a>
            </li>
        </ol>
    </nav>
    <div class="row py-1">
        <div class="col-sm-4"></div>
        <div th:if="${created}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
            [[${created}]]
        </div>
        <div th:if="${updated}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
            [[${updated}]]
        </div>
        <div th:if="${deleted}" class="text-center alert alert-success col-12 col-sm-4" role="alert">
            [[${deleted}]]
        </div>
        <div class="col-sm-4"></div>
    </div>
    <p>
        <a class="btn btn-primary" href="#" th:href="${contract.addJournalUrl()}"><i class="fas fa-plus"></i>&nbsp;新增明细记录</a>
    </p>
    <table class="table table-hover table-responsive" th:if="${count != 0}">
        <thead>
        <tr>
            <th>序号</th>
            <th>结算说明</th>
            <th>凭证号</th>
            <th>净现金流</th>
            <th>确认收入</th>
            <th>履约成本</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="journal, control:${journals}">
            <td th:text="${control.count}"></td>
            <td><a href="#" th:href="${journal.absoluteUrl()}" th:text="${journal.getDescription()}"></a></td>
            <td th:text="${journal.getNoteDate().getYear() +'-'+ journal.getNoteDate().getMonth() + '-' + #numbers.formatDecimal(journal.getNoteNumber(),4,0,'POINT')}"></td>
            <td th:text="${#numbers.formatDecimal(journal.getCash(),1,'COMMA',2,'POINT')}"></td>
            <td th:text="${#numbers.formatDecimal(journal.getRevenuePL(),1,'COMMA',2,'POINT')}"></td>
            <td><span th:text="${#numbers.formatDecimal(journal.getContractCost(),1,'COMMA',2,'POINT')}"></td>
        </tr>
        <tr>
            <td class="text-center" th:text="合计" colspan="3"></td>
            <td class="text-primary"
                th:text="${#numbers.formatDecimal(contractData.totalCash,1,'COMMA',2,'POINT')}"></td>
            <td class="text-primary"
                th:text="${#numbers.formatDecimal(contractData.totalRevenue,1,'COMMA',2,'POINT')}"></td>
            <td class="text-primary"
                th:text="${#numbers.formatDecimal(contractData.totalContractCost,1,'COMMA',2,'POINT')}"></td>
        </tr>
        </tbody>
    </table>

</main>

对于每个合同,我认为比较重要的是货币资金、合同履约成本、确认收入、应付账款这四个项目,在其明细记录列表中展示前三个,但是对于合同来说需要汇总合同下所有明细记录的合计。接下来就来修改这方面的内容。

修改Contract

Contract类添加一些新的方法,用于返回其汇总的结果:

    public BigDecimal totalCash() {
        BigDecimal result = new BigDecimal("0.00");
        for (Journal journal : journals) {
            result = result.add(journal.getCash());
        }
        return result;
    }

    public BigDecimal totalRevenue() {
        BigDecimal result = new BigDecimal("0.00");
        for (Journal journal : journals) {
            result = result.add(journal.getRevenuePL());
        }
        return result;
    }

    public BigDecimal totalContractCost() {
        BigDecimal result = new BigDecimal("0.00");
        for (Journal journal : journals) {
            result = result.add(journal.getContractCost());
        }
        return result;
    }

    public BigDecimal totalAccountPayable() {
        BigDecimal result = new BigDecimal("0.00");
        for (Journal journal : journals) {
            result = result.add(journal.getAccountPayable());
        }
        return result;
    }

    // 判断是否超过合同价
    public boolean isOverPaid() {
        // 如果是开口合同,就返回false
        if (isOpen) {
            return false;
        }


        if (finalPrice == null) {
            return totalPrice.compareTo(totalCash().abs()) < 0;
        } else {
            return finalPrice.compareTo(totalCash().abs()) < 0;
        }
    }

前边四个方法用于计算合同所有合并的现金流,收入,履约成本和应付账款的余额,未来也会用于在合同列表页中展示。

最后一个方法是用来判断合同是否超付,其判断原理是如果合同为开口合同,则永远不会出现超付。如果还没有结算价,则判断总价和付款的绝对值大小,如果总价小,那就属于超付或者超出了合同价的收款。如果有结算价,则不使用合同价,而使用结算价来进行判断。

修改ContractData

ContractData中,需要添加与Journal类相关的内容,如下:

    // 以下是明细记录合计
    // 现金收付
    private BigDecimal totalCash= new BigDecimal("0.00");

    // 合同履约成本
    private BigDecimal totalContractCost = new BigDecimal("0.00");

    // 累计收入
    private BigDecimal totalRevenue = new BigDecimal("0.00");

    // 累计应付账款
    private BigDecimal totalAccountPayable = new BigDecimal("0.00");

    public BigDecimal getTotalCash() {
        return totalCash;
    }

    public void setTotalCash(BigDecimal totalCash) {
        this.totalCash = totalCash;
    }

    public BigDecimal getTotalContractCost() {
        return totalContractCost;
    }

    public void setTotalContractCost(BigDecimal totalContractCost) {
        this.totalContractCost = totalContractCost;
    }

    public BigDecimal getTotalRevenue() {
        return totalRevenue;
    }

    public void setTotalRevenue(BigDecimal totalRevenue) {
        this.totalRevenue = totalRevenue;
    }

    public BigDecimal getTotalAccountPayable() {
        return totalAccountPayable;
    }

    public void setTotalAccountPayable(BigDecimal totalAccountPayable) {
        this.totalAccountPayable = totalAccountPayable;
    }

    // 收款与结算不符
    public boolean isPotentialReceiveError() {
        System.out.println(totalReceived);
        System.out.println(contract.totalCash());
        if (receiptSettlements.size() == 0) {
            return false;
        }
        return !totalReceived.equals(contract.totalCash());
    }

    // 付款与结算不符
    public boolean isPotentialPaidError() {
        if (paymentSettlements.size() == 0) {
            return false;
        }
        return !totalPaid.equals(contract.totalCash().abs());
    }

前边几个比较简单,就是计算几个合计,最后两个方法是判断如果存在收款结算或者付款结算记录,会比较一下相关的金额是否相等,如果不相等,就会显示一个警告标志,提示用户进行检查。由于这些不一定是硬性错误,所以不在合同列表页进行提示,仅在合同详情页内进行提示。

修改ContractService

上边两个类都准备好之后,最后就可以来修改ContractService,组装新的ContractData:


contractData.setJournals(contract.getJournals());

// 以下是明细记录部分
contract.getJournals().forEach(journal -> {
    contractData.setTotalCash(contractData.getTotalCash().add(journal.getCash()));
});

contract.getJournals().forEach(journal -> {
    contractData.setTotalContractCost(contractData.getTotalContractCost().add(journal.getContractCost()));
});

contract.getJournals().forEach(journal -> {
    contractData.setTotalRevenue(contractData.getTotalRevenue().add(journal.getRevenuePL()));
});

contract.getJournals().forEach(journal -> {
    contractData.setTotalAccountPayable(contractData.getTotalAccountPayable().add(journal.getAccountPayable()));
});

这样就添加了新的信息,在合同详情页就可以使用这个新的ContractData对象了。

修改页面

需要修改的页面包括合同的详情页,添加一个新的表:

<h2 th:if="${contractData.getJournals().size()!=0}" class="mt-2">合同执行情况</h2>
<table th:if="${contractData.getJournals().size()!=0}" class="table table-sm table-striped"
       th:object="${contractData}">
    <thead>
    <tr>
        <th>属性</th>
        <th>金额</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td>现金流</td>
        <td th:text="${#numbers.formatDecimal(contractData.totalCash,1,'COMMA',2,'POINT')}"></td>
    </tr>
    <tr>
        <td>累计确认收入</td>
        <td th:text="${#numbers.formatDecimal(contractData.totalRevenue,1,'COMMA',2,'POINT')}"></td>
    </tr>
    <tr>
        <td>累计履约成本</td>
        <td th:text="${#numbers.formatDecimal(contractData.totalContractCost,1,'COMMA',2,'POINT')}"></td>
    </tr>
    <tr>
        <td>应付账款余额</td>
        <td th:text="${#numbers.formatDecimal(contractData.totalAccountPayable,1,'COMMA',2,'POINT')}"></td>
    </tr>
    </tbody>
</table>

这个表就是展示刚刚编写的合计数,之后还需要在项目合同和预算合同列表,添加累计收付款和应付账款余额两列:

<table class="table table-hover" th:if="${count != 0}">
        <thead>
        <tr>
            <th>序号</th>
            <th>合同编号</th>
            <th>合同名称</th>
            <th>合同总价</th>
            <th>累计收付款</th>
            <th>应付账款</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="contract, control:${contracts}">
            <td th:text="${control.count}"></td>
            <td th:text="${contract.number}"></td>
            <td><a href="" th:href="${contract.absoluteUrl()}">[[${contract.name}]]</a></td>
            <td th:text="${#numbers.formatDecimal(contract.totalPrice,1,'COMMA',2,'POINT')}"></td>
            <td >[[${#numbers.formatDecimal(contract.totalCash(),1,'COMMA',2,'POINT')}]]&nbsp;<span th:if="${contract.isOverPaid()}"><i class="fas fa-exclamation-triangle text-danger"></i></span></td>
            <td th:text="${#numbers.formatDecimal(contract.totalAccountPayable(),1,'COMMA',2,'POINT')}"></td>
            <td>
                <a href="#" th:href="${contract.addJournalUrl()}">新增明细</a>&nbsp;
            </td>
        </tr>
        </tbody>
    </table>

由于Journal类还有一个外键连接到预算,所以很显然,对于Budget类也需要添加类似的方法,对于一个预算类,我实际上只需要知道合同履约成本,和资金支付就可以了。这里代码就不再具体放了。

接下来,就把Journal类的修改和删除补完,然后来补上最后一块,就是项目汇总数据。

LICENSED UNDER CC BY-NC-SA 4.0
Comment