Skip to content

Commit

Permalink
feat: add expense detail table
Browse files Browse the repository at this point in the history
  • Loading branch information
jesusantguerrero committed Jan 31, 2023
1 parent a5eb87d commit 8b50c5d
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 113 deletions.
176 changes: 147 additions & 29 deletions src/Helpers/ReportHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Insane\Journal\Models\Core\Account;
use Insane\Journal\Models\Core\Category;
use Insane\Journal\Models\Core\Transaction;
use Insane\Journal\Models\Invoice\Invoice;

Expand Down Expand Up @@ -92,7 +93,7 @@ public static function getExpensesByPeriod($teamId, $startDate, $endDate) {
->get();
}

public static function getAccountTransactionsByPeriod(int $teamId, array $accounts, $startDate = null, $endDate = null) {
public static function getTransactionsByAccount(int $teamId, array $accounts, $startDate = null, $endDate = null, $groupBy = "display_id") {
$endDate = $endDate ?? Carbon::now()->endOfMonth()->format('Y-m-d');
$startDate = $startDate ?? Carbon::now()->startOfMonth()->format('Y-m-d');

Expand All @@ -108,7 +109,16 @@ public static function getAccountTransactionsByPeriod(int $teamId, array $accoun
->orWhereIn('categories.display_id', $accounts)
->orWhereIn('g.display_id', $accounts);
})
->selectRaw('sum(COALESCE(amount * transaction_lines.type, 0)) as total,
->selectRaw('
sum(COALESCE(amount * transaction_lines.type, 0)) as total,
SUM(CASE
WHEN transaction_lines.type > 0 THEN amount
ELSE 0
END) as income,
SUM(CASE
WHEN transaction_lines.type < 0 THEN amount
ELSE 0
END) outcome,
date_format(transactions.date, "%Y-%m-01") as date,
categories.name,
categories.id,
Expand All @@ -121,7 +131,16 @@ public static function getAccountTransactionsByPeriod(int $teamId, array $accoun
->join(DB::raw('categories g'), 'g.id', 'categories.parent_id')
->get();

$resultGroup = $results->groupBy('display_id');
return $results->groupBy($groupBy);


}

public static function getAccountTransactionsByPeriod(int $teamId, array $accounts, $startDate = null, $endDate = null, $groupBy = "display_id") {
$endDate = $endDate ?? Carbon::now()->endOfMonth()->format('Y-m-d');
$startDate = $startDate ?? Carbon::now()->startOfMonth()->format('Y-m-d');

$resultGroup = self::getTransactionsByAccount($teamId, $accounts, $startDate, $endDate);

return array_map(function ($account) use ($resultGroup) {
return $resultGroup[$account][0] ?? [
Expand All @@ -135,34 +154,10 @@ public static function getChartTransactionsByPeriod(int $teamId, array $accounts
$endDate = $endDate ?? Carbon::now()->endOfMonth()->format('Y-m-d');
$startDate = $startDate ?? Carbon::now()->startOfMonth()->format('Y-m-d');

$results = DB::table('transaction_lines')
->whereBetween('transaction_lines.date', [$startDate, $endDate])
->where([
'transaction_lines.team_id' => $teamId,
'transactions.status' => 'verified'
])
->where(function($query) use ($accounts) {
$query
->whereIn('accounts.display_id', $accounts)
->orWhereIn('categories.display_id', $accounts)
->orWhereIn('g.display_id', $accounts);
})
->selectRaw('sum(COALESCE(amount * transaction_lines.type * accounts.type, 0)) as total,
date_format(transactions.date, "%Y-%m-01") as date,
categories.name,
categories.id,
categories.display_id,
g.display_id groupName'
)->groupByRaw('date_format(transactions.date, "%Y-%m"), categories.id')
->join('accounts', 'accounts.id', '=', 'transaction_lines.account_id')
->join('categories', 'accounts.category_id', '=', 'categories.id')
->join('transactions', 'transactions.id', '=', 'transaction_id')
->join(DB::raw('categories g'), 'g.id', 'categories.parent_id')
->groupBy('categories.display_id')
->get()->groupBy('groupName');
$results = self::getTransactionsByAccount($teamId, $accounts, $startDate, $endDate, "groupName");

return collect($accounts)->reduce(function ($groups, $account) use ($results) {
$groups[$account] = isset($results[$account]) ? $results[$account][0]->total : 0;
$groups[$account] = isset($results[$account]) ? $results[$account][0] : [];
return $groups;
});
}
Expand Down Expand Up @@ -234,5 +229,128 @@ public function debtors($teamId) {
->take(5)
->groupBy('invoices.client_id', 'clients.names', 'clients.id')
->get();
}

public static function getReportCategories(string $reportName) {

$categoriesGroups = [
"income" => ["income"],
"expense" => ["expenses"],
"tax" => ["liabilities"],
"cash-flow" => ["assets", "liabilities", "equity"],
"balance-sheet" => ["assets", "liabilities", "equity"],
"income-statement" => ["income", "expenses"],
"account-balance" => ["assets", "liabilities", "income", "expenses", "equity"],
];

return $categoriesGroups[$reportName];
}

public static function getGeneralLedger($teamId, $reportName, $config = []) {
$categories = self::getReportCategories($reportName);
$categoryData = Category::whereIn('display_id', $categories)->get();

$categoryIds = $categoryData->pluck('id')->toArray();


$accountQuery = DB::table('categories')
->whereIn('categories.parent_id', $categoryIds)
->selectRaw('group_concat(accounts.id) as account_ids, group_concat(accounts.name) as account_names')
->joinSub(DB::table('accounts')->where('team_id', $teamId), 'accounts','category_id', '=', 'categories.id')
->get()
->pluck('account_ids');


if (isset($config['account_id'])) {
$accountQuery->whereIn('accounts.id', [$config['account_id']]);
}

$accountIds = $accountQuery->toArray();


$accountIds = explode(",", $accountIds[0]);

$balanceByAccounts = DB::table('transaction_lines')
->whereIn('transaction_lines.account_id', $accountIds)
->selectRaw("
SUM(amount * transaction_lines.type) as total,
SUM(CASE
WHEN transaction_lines.type > 0 THEN amount
ELSE 0
END) as income,
SUM(CASE
WHEN transaction_lines.type < 0 THEN amount
ELSE 0
END) outcome,
group_concat(date) dates,
transaction_lines.account_id,
accounts.id,
accounts.name,
accounts.display_id,
categories.display_id category,
gl.display_id ledger,
gl.id ledger_id
")
->join('accounts', 'accounts.id', '=', 'transaction_lines.account_id')
->join('categories', 'accounts.category_id', 'categories.id')
->join(DB::raw('categories gl'), 'categories.parent_id', 'gl.id')
->groupBy('transaction_lines.account_id')
->orderBy(DB::raw("gl.index, categories.index"));


if (isset($config['dates'])) {
$balanceByAccounts = $balanceByAccounts->whereBetween('transaction_lines.date', $config['dates']);
}

$accountsWithActivity = $config['account_id'] ? [$config['account_id']] : $balanceByAccounts->pluck('id')->toArray();

// @todo Analyze this, since I think I just will display subcategories with account transactions I just need to group the first query and the last.
$categoryAccounts = Category::where([
'depth' => 1,
])
->whereIn('parent_id', $categoryIds)
->hasAccounts($accountsWithActivity)
->with(['accounts' => function ($query) use ($teamId, $accountsWithActivity) {
$query->where('team_id', '=', $teamId);
$query->whereIn('id', $accountsWithActivity);
},
'category'
])
->get()
->toArray();

$balance = $balanceByAccounts->get()->toArray();

$categoryAccounts = array_map(function ($subCategory) use ($balance) {
$total = [];
if (isset($subCategory['accounts'])) {
foreach ($subCategory['accounts'] as $accountIndex => $account) {
$index = array_search($account['id'], array_column($balance, 'id'));
if ($index !== false ) {
$subCategory['accounts'][$accountIndex]['balance'] = $balance[$index]->total;
$subCategory['accounts'][$accountIndex]['income'] = $balance[$index]->income;
$subCategory['accounts'][$accountIndex]['outcome'] = $balance[$index]->outcome;
$total[] = $balance[$index]->total;
}
}
}
$subCategory['total'] = array_sum($total);
return $subCategory;
}, $categoryAccounts);


$ledger = DB::table('categories')
->whereIn('categories.display_id', $categories)
->selectRaw('sum(COALESCE(total, 0)) total, categories.alias, categories.display_id, categories.name')
->leftJoinSub($balanceByAccounts, 'balance', function($join) {
$join->on('categories.id', 'balance.ledger_id');
})->groupBy('categories.id');

$ledger = $ledger->get();

return [
"ledger" => $ledger,
"categoryAccounts" => $categoryAccounts
];
}
}
88 changes: 11 additions & 77 deletions src/Http/Controllers/AccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Insane\Journal\Contracts\DeleteAccounts;
use Insane\Journal\Events\AccountCreated;
use Insane\Journal\Events\AccountUpdated;
use Insane\Journal\Helpers\ReportHelper;
use Insane\Journal\Models\Core\Account;
use Insane\Journal\Models\Core\AccountDetailType;
use Insane\Journal\Models\Core\Category;
Expand Down Expand Up @@ -188,88 +189,21 @@ public function statementsIndex(Request $request, string $category = "income") {
]);
}

public function statements(Request $request, string $category = "income") {
$categories = [
"income" => ["income"],
"expense" => ["expenses"],
"tax" => ["liabilities"],
"balance-sheet" => ["assets", "liabilities", "equity"],
"income-statement" => ["income", "expenses"],
"account-balance" => ["assets", "liabilities", "income", "expenses", "equity"],
];

$categoryData = Category::whereIn('display_id', $categories[$category] )->get();

$categoryIds = $categoryData->pluck('id')->toArray();

$accountIds = DB::table('categories')
->whereIn('categories.parent_id', $categoryIds)
->selectRaw('group_concat(accounts.id) as account_ids, group_concat(accounts.name) as account_names')
->joinSub(DB::table('accounts')->where('team_id', $request->user()->current_team_id), 'accounts','category_id', '=', 'categories.id')
->get()->pluck('account_ids')->toArray();


$accountIds = explode(",", $accountIds[0]);

$balanceByAccounts = DB::table('transaction_lines')
->whereIn('transaction_lines.account_id', $accountIds)
->selectRaw("
sum(amount * transaction_lines.type) as total,
transaction_lines.account_id,
accounts.id,
accounts.name,
accounts.display_id,
categories.display_id category,
g.display_id ledger,
g.id ledger_id
")
->join('accounts', 'accounts.id', '=', 'transaction_lines.account_id')
->join('categories', 'accounts.category_id', 'categories.id')
->join(DB::raw('categories g'), 'categories.parent_id', 'g.id')
->groupBy('transaction_lines.account_id');
public function statements(Request $request, string $reportName = "income") {
$filters = $request->query('filters');
$accountId = $filters ? $filters['account'] : null;

// all the accounts with balance are here


$categoryAccounts = Category::where([
'depth' => 1,
])
->whereIn('parent_id', $categoryIds)
->with([
'accounts' => function ($query) use ($request) {
$query->where('team_id', '=', $request->user()->current_team_id);
},
'category'
])->get()->toArray();

$balance = $balanceByAccounts->get()->toArray();
$categoryAccounts = array_map(function ($subCategory) use ($balance) {
$total = [];
if (isset($subCategory['accounts'])) {
foreach ($subCategory['accounts'] as $accountIndex => $account) {
$index = array_search($account['id'], array_column($balance, 'id'));
if ($index !== false ) {
$subCategory['accounts'][$accountIndex]['balance'] = $balance[$index]->total;
$total[] = $balance[$index]->total;
}
}
}
$subCategory['total'] = array_sum($total);
return $subCategory;
}, $categoryAccounts);


$ledger = DB::table('categories')
->whereIn('categories.display_id', $categories[$category])
->selectRaw('sum(COALESCE(total, 0)) total, categories.alias, categories.display_id, categories.name')
->leftJoinSub($balanceByAccounts, 'balance', function($join) {
$join->on('categories.id', 'balance.ledger_id');
})->groupBy('categories.id')->get();
[
"ledger" => $ledger,
"categoryAccounts" => $categoryAccounts
] = ReportHelper::getGeneralLedger(request()->user()->current_team_id, $reportName, [
"account_id" => $accountId
]);

return Jetstream::inertia()->render($request, config('journal.statements_inertia_path') . '/Category', [
"categories" => $categoryAccounts,
"ledger" => $ledger->groupBy('display_id'),
'categoryType' => $category
'categoryType' => $reportName
]);
}
}
47 changes: 47 additions & 0 deletions src/Jobs/Invoice/CreateExpenseDetails.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Insane\Journal\Jobs\Invoice;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Insane\Journal\Models\Invoice\Invoice;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class CreateExpenseDetails implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

protected $invoice;
protected $formData;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Invoice $invoice, $formData)
{
$this->invoice = $invoice;
$this->formData = $formData;
}

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
if (isset($this->formData['expense_details']) && $this->invoice->type == Invoice::DOCUMENT_TYPE_BILL) {
$expense = $this->formData['expense_details'];
$this->invoice->expenseDetails()->create([
'customer_id' => $expense['customer_id'],
'payment_account_id' => $expense['customer_id'],
'is_personal' => $expense['is_personal'],
'is_billable' => $expense['is_billable'],
'expense_type' => $expense['expense_type']
]);
}
}
}
Loading

0 comments on commit 8b50c5d

Please sign in to comment.