pluck('id')->toArray(); $yesterday = clone $start; $yesterday->subDay(); // get balances for start. $startSet = $this->getSet($ids, $yesterday); // a special consideration for accounts that did exist on this exact day. // we also grab the balance from today just in case, to see if that changes things. // it's a fall back for users who (rightly so) start keeping score at the first of // the month and find the first report lacking / broken. $backupSet = $this->getSet($ids, $start); // and end: $endSet = $this->getSet($ids, $end); $accounts->each( function (Account $account) use ($startSet, $endSet, $backupSet) { /** * The balance for today always incorporates transactions * made on today. So to get todays "start" balance, we sub one * day. */ $account->startBalance = '0'; $account->endBalance = '0'; $currentStart = $startSet->filter( function (Account $entry) use ($account) { return $account->id == $entry->id; } ); // grab entry from current backup as well: $currentBackup = $backupSet->filter( function (Account $entry) use ($account) { return $account->id == $entry->id; } ); if ($currentStart->first()) { $account->startBalance = $currentStart->first()->balance; } else { if (is_null($currentStart->first()) && !is_null($currentBackup->first())) { $account->startBalance = $currentBackup->first()->balance; } } $currentEnd = $endSet->filter( function (Account $entry) use ($account) { return $account->id == $entry->id; } ); if ($currentEnd->first()) { $account->endBalance = $currentEnd->first()->balance; } } ); // summarize: foreach ($accounts as $account) { $startAmount = bcadd($startAmount, $account->startBalance); $endAmount = bcadd($endAmount, $account->endBalance); $diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance)); } $object = new AccountCollection; $object->setStart($startAmount); $object->setEnd($endAmount); $object->setDifference($diff); $object->setAccounts($accounts); return $object; } /** * @param array $ids * @param Carbon $date * * @return Collection */ private function getSet(array $ids, Carbon $date): Collection { Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->whereIn('accounts.id', $ids) ->whereNull('transaction_journals.deleted_at') ->whereNull('transactions.deleted_at') ->where('transaction_journals.date', '<=', $date->format('Y-m-d')) ->groupBy('accounts.id') ->get(['accounts.id', DB::raw('SUM(`transactions`.`amount`) as `balance`')]); } }