Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

aldesrahim's avatar

Validate Running Balance

Hi everyone.

Let say i have a table of transactions, that has columns ID, Date, Quantity. But for the sake of clarity, i will add "Qty Balance" column to this sample for a better view or understanding.

+----+------------+----------+-------------+
| ID |    Date    | Quantity | Qty Balance |
+----+------------+----------+-------------+
|  1 | 2023-01-01 |       10 |          10 |
|  2 | 2023-01-01 |       10 |          20 |
|  3 | 2023-01-01 |       10 |          30 |
|  4 | 2023-01-01 |      -20 |          10 |
|  5 | 2023-01-01 |        5 |          15 |
|  6 | 2023-01-02 |        5 |          20 |
|  7 | 2023-01-02 |        5 |          25 |
|  8 | 2023-01-02 |        5 |          30 |
|  9 | 2023-01-03 |      -30 |           0 |
| 10 | 2023-01-03 |       10 |          10 |
| 11 | 2023-01-03 |        5 |          15 |
| 12 | 2023-01-03 |        5 |          20 |
| 13 | 2023-01-03 |       10 |          30 |
| 14 | 2023-01-04 |       20 |          50 |
| 15 | 2023-01-04 |       10 |          60 |
| 16 | 2023-01-04 |       15 |          75 |
| 17 | 2023-01-04 |      -75 |           0 |
| 18 | 2023-01-04 |        5 |           5 |
| 19 | 2023-01-04 |       10 |          15 |
| 20 | 2023-01-05 |       -5 |          10 |
+----+------------+----------+-------------+

So, this is a historical of multiple transactions of an item, let say Item X, i've search so many reference to validate the running balance when i am updating a single row (1), or inserting a new row in the middle (2). But what i've found that it always need an iteration to calculate the running balance and if it find a negative value, then just throw an exception.

There is 2 cases of this, but i think it will have the same solutions. The first one is

  1. Update a row in the middle
  2. Insert a new or in the middle

It will become a problem if i am updating or inserting a subtraction, if it's an addition then it's fine.

So lets jump to the example, when i am updating a row in the middle, let say i am updating row with an ID of 3, i will update it's quantity from 10 to 4 (it is a subtraction). It will make running balance at ID 9 a negative number, and i need to validate this and throw an error. Data will look like this:

+----+------------+----------+-------------+
| ID |    Date    | Quantity | Qty Balance |
+----+------------+----------+-------------+
|  1 | 2023-01-01 |       10 |          10 |
|  2 | 2023-01-01 |       10 |          20 |
|  3 | 2023-01-01 |        4 |          24 |
|  4 | 2023-01-01 |      -20 |           4 |
|  5 | 2023-01-01 |        5 |           9 |
|  6 | 2023-01-02 |        5 |          14 |
|  7 | 2023-01-02 |        5 |          19 |
|  8 | 2023-01-02 |        5 |          24 |
|  9 | 2023-01-03 |      -30 |          -6 |
| 10 | 2023-01-03 |       10 |           4 |
| 11 | 2023-01-03 |        5 |           9 |
| 12 | 2023-01-03 |        5 |          14 |
| 13 | 2023-01-03 |       10 |          24 |
| 14 | 2023-01-04 |       20 |          44 |
| 15 | 2023-01-04 |       10 |          54 |
| 16 | 2023-01-04 |       15 |          69 |
| 17 | 2023-01-04 |      -75 |          -6 |
| 18 | 2023-01-04 |        5 |          -1 |
| 19 | 2023-01-04 |       10 |           9 |
| 20 | 2023-01-05 |       -5 |           4 |
+----+------------+----------+-------------+

How do i achive this using raw or eloquent methods ? Thank you

Edit: "Qty Balance" is not an existing column, it's just an example to easily understand the calculation.

0 likes
9 replies
tangtang's avatar

@aldesrahim

it is advisable not to edit transactions that have already occurred, unless there is no recent transaction data other than that specific transaction. editing transactions, especially those from several months ago (just for example), may complicate the accuracy and auditability of financial records, and it could necessitate a substantial number of recalculations due to intervening transactions.

instead, it is recommended to add new data with information serving as corrective data for the incorrect entry. the new data can be distinguished by incorporating a specific code or serial, facilitating easy recognition of corrective transactions.

this approach helps preserve the integrity of historical records and ensures a transparent audit trail. editing data from months ago, for instance, could introduce complexities and require a significant number of calculations to maintain accurate running balances and historical consistency.

aldesrahim's avatar

@tangtang

Thank you for the answer, in my particular example, we are accepting if the user wants to edit their data, since it is like a personal financial tracker, but we need to validate the data since the balance must not be a negative number since it will make the transaction invalid.

Let say we use your approach by inserting a new data as a correction, in my case, it will make the app flow much wider and we cant comprehend that at the moment.

Also i might thinking of a solution where i need to only calculate the balance if there is a quantity subtraction and checks if it return a negative number, but i dont quite understand how to implement that or is that a best approach to solve my current problem.

tangtang's avatar

@aldesrahim

well, if that's the case

you can check this code reference

public function updateTransaction($id, $newQuantity)
    {
        $transaction = Transaction::find($id);

        if (!$transaction) {
			// add the message not found data here . . . .
        }

        // get the running balance before the update
        $previousBalance = Transaction::where('id', '>=', $id)->sum('quantity');

        // calculate the new balance after the update
        $newBalance = $previousBalance - $transaction->quantity + $newQuantity;

		// this is the core for negative result
        // validate the new balance
        if ($newBalance < 0) {
            // throw an message for invalid balance here . . . . .
        }

		// your other code here to update the other balance . . . .
    }
aldesrahim's avatar

@tangtang

After some test, by using this example:

ID: 3, Update qty to 4, i found this result, which is returns as expected

+-----+------------------------+
|   3 | ID                     |
| -10 | $previousBalance       |
|  10 | $transaction->quantity |
|   4 | $newQuantity           |
| -16 | $newBalance            |
+-----+------------------------+

But if i update to 12 instead of 4 (as an addition), it's still throw an error

+-----+------------------------+
|   3 | ID                     |
| -10 | $previousBalance       |
|  10 | $transaction->quantity |
|  12 | $newQuantity           |
|  -8 | $newBalance            |
+-----+------------------------+
tangtang's avatar

@aldesrahim

the code in my response just checked the Quantity column may as represent the Qty Balance in result, but seems like even with addition the result is still negative number.

well . . . .

another way is, you can still save the negative number in database table column Qty Balance, after that check if there an negative number in Qty Balance, if there is negative throw a message and rollback the transaction.

this is the reference

$negativeBalance = Transaction::where('id', '>=', $id)->where('qty_balance', '<', 0)->exists();
if ($negativeBalance) {
		// message here
		// and after the message
		// rollback the transaction to the recent state
}

but still this code is lack of range and parameter, this code will update all the transaction with id is more than selected id, imagine if there more 200 row after the selected id.

that's why I suggest not to edit transactions that have already occurred, unless there is no recent transaction data other than that specific transaction.

1 like
aldesrahim's avatar

@tangtang

Thank you for the answer, although in my case "Qty balance" is not stored in the database, because i think it's really hard to maintain the data integrity if i have the qty balance stored in the database.

i appreciate your advice, and thank you for giving me references. Cheers.

jlrdw's avatar

With out reading through everything, Qty Balance should be a derived column.

aldesrahim's avatar

@jlrdw

Thanks for the answer, but, unfortunately "Qty Balance" is not an existing column, it's just an example to easily understand the calculation.

Please or to participate in this conversation.