复式记账分页问题

Double Entry Accounting pagination issue

带有分页的复式记账系统存在一个非常严重的问题,我认为这很常见,但我仍然没有找到解决问题的方法。

您可以使用此 link 阅读有关 simple Double Entry Accounting systems 的信息,就像我用 Laravel 和 [=53= 制作的一样]AngularJS.

在这个系统中,预期的结果(例如)是这样的:

ID      In       Out    Balance
1      100.00    0.00   100.00
2       10.00    0.00   110.00
3        0.00   70.00    40.00
4        5.00    0.00    45.00
5        0.00   60.00   -15.00
6       20.00    0.00     5.00

如果您在一个页面中显示所有交易,那么跟踪累积函数内的余额非常容易,最后一笔交易中的余额就是您当天结束时的当前余额。

例如,对于特定日期范围 $fromDate->$toDate,我们喜欢:

$balanceYesterday = DB::table('journal')->where('date', '<', $fromDate)
        ->join('transactions','transactions.journal_id','journal.id')->where('transactions.type', "=", 0) /* 0 means the account of the company */
        ->select(DB::raw('SUM(amount) as total_balance'))
        ->first()->total_balance;

现在我们有昨天的余额,我们依靠它在累积循环中计算之后的余额,直到过程结束,达到$toDate;

$currentBalance = $currentBalance + $currentTransaction->amount;
$currentTransactionBalance = $currentBalance;

现在,当您有大量交易时,真正的问题就开始了,您需要对它们进行分页 $journal = $journal->paginate(100);,假设每页 100 个交易,系统将按预期在第一页工作,因为我们已经可以计算出 $balanceYesterday 并依靠它来计算每笔交易后的新余额,直到第一页的 100 笔交易结束。

下一页会出现问题不知道第一页上一笔交易的最后余额是多少,所以会从[=17重新开始=],使得整个table计算错误

我首先修复的是,将最后一笔交易amount(在前端)作为参数转移到下一页,并作为起始金额重新计算,就是这样最好的解决方案,因为我只使用 << PREVNEXT >> 按钮,所以很容易修复它。

但我最近发现,如果我有带页码的分页,这个变通方法将不起作用,因为用户想翻页浏览期刊,现在不可能知道最后的余额具体页面,系统会显示错误的计算。

我正在尝试做的事情 正在寻找一种方法来计算特定交易的余额,不管它是信用还是借记,我正在寻找一种方法来了解在特定日期完成特定交易后余额是多少,我不想添加新的余额列并保存其中的余额,用户正在做不时对交易进行大量修改和编辑,这会破坏一切,因为少量修改会影响之后的所有余额,我不能以任何方式依赖交易 ID,因为交易可能有不同的随机日期,所以不会按 ID 排序,但可能会按日期或帐户所有者或类型等其他字段排序..

这个问题我已经摸不着头脑了大概4个月了,上网查了也没有找到解决办法,希望经过这么长的解释,我的问题已经清楚了,希望有人能帮我解决,请..

谢谢。

您应该能够为每条记录的余额制定一个真值陈述,只要您知道计算该有序列表中每个点的余额总和的顺序是什么。

当然,这会带来巨大的开销,因为您需要为显示的每条记录查询整个 table,但首先必须能够做到这一点。正如您在示例中所示,只要您不分页即可。

您可以为分页做的是预先计算每条记录的余额并将其与原始记录相关联地存储。这会使您的数据去规范化,但好处是创建分页相当简单。

我相信此时你唯一真正需要的是计算从分页数据集开始(所有记录,而不仅仅是当前页面的记录)到显示的第一条记录之前的所有事务的总和当前页面。

您可以通过查找整个数据集开始和当前页面交易之间发生的交易数量,通过 LIMIT 检索它们并将它们相加来获得此信息。

您首先要了解的是分页查询的确切约束条件。由于我们想要获取除当前页面之外的另一个分页记录子集,因此您需要确保两个查询的结果顺序相同。重用查询构建器对象会有所帮助(调整以匹配您的实际分页查询):

$baseQuery = DB::table('journal')
    ->join('transactions', 'transactions.journal_id', 'journal.id')
    ->where('date', '>', $fromDate)
    ->where('date', '<', $toDate)
    ->where('transactions.type', "=", 0)
    ->orderBy('date', 'asc');
    // Note that we aren't fetching anything here yet.

然后,获取分页结果集。这将执行两个查询:一个用于记录总数,另一个用于特定页面的交易。

$paginatedTransactions = $baseQuery->paginate(100);

从这里,我们可以确定我们需要为哪些记录检索以前的余额。返回的分页对象是LengthAwarePaginator的一个实例,它知道总共有多少条记录,页数,当前页数等等

使用这些信息,我们只需做一些数学运算即可获取所需的记录数:

total records needed = (current page - 1) * records per page

假设用户在第 5 页,他们将看到记录 401 - 500,因此我们需要检索之前的 400 条记录。

// If we're on Page 1, or there are not enough records to
// paginate, we don't need to calculate anything.
if ($paginatedTransactions->onFirstPage() || ! $paginatedTransactions->hasPages()) {
    // Don't need to calculate a previous balance. Exit early here!
}

// Use helper methods from the Paginator to calculate
// the number of previous transactions.
$limit = ($paginatedTransactions->currentPage() - 1) * $paginatedTransactions->perPage();

现在我们有了数据集中发生在当前页面之前的交易数量,我们可以再次使用基本查询来检索和计算总和:

$previousBalance = $baseQuery->limit($limit)->sum('amount');

Adding a highlight here to explain that using your database to perform the SUM calculations will be a big performance benefit, rather than doing it in a loop in PHP. Take advantage of the DB as often as you can!

将此余额添加到您的原始 "yesterday" 余额中,您应该有一个准确的分页交易的开始余额。

注意:所有根据理论伪编码的内容,可能需要调整。如果有问题或问题,很乐意修改。