From 7acb3694085d73a75bbbf551d26759251b37583d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 6 Aug 2024 08:22:00 +1000 Subject: [PATCH] Calculations for cards on dashbaord --- app/Services/Chart/ChartCalculations.php | 186 +++++++++++++++++----- app/Services/Chart/ChartService.php | 12 +- app/Services/Template/TemplateService.php | 2 +- 3 files changed, 150 insertions(+), 50 deletions(-) diff --git a/app/Services/Chart/ChartCalculations.php b/app/Services/Chart/ChartCalculations.php index f8af770d90ff..c3d9487fe3c5 100644 --- a/app/Services/Chart/ChartCalculations.php +++ b/app/Services/Chart/ChartCalculations.php @@ -11,10 +11,12 @@ namespace App\Services\Chart; +use App\Models\Expense; use App\Models\Invoice; use App\Models\Payment; use App\Models\Quote; use App\Models\Task; +use Illuminate\Contracts\Database\Eloquent\Builder; /** * Class ChartCalculations. @@ -174,53 +176,144 @@ trait ChartCalculations public function getLoggedTasks($data): int|float { - //tasks with at least 1 timelog entry. + + $q = $this->taskQuery($data); + + return $this->taskCalculations($q, $data); + + } + + public function getPaidTasks($data): int|float + { + $q = $this->taskQuery($data); + $q->whereHas('invoice', function ($query){ + $query->where('status_id', 4)->where('is_deleted', 0); + }); + + return $this->taskCalculations($q, $data); + + } + + public function getInvoicedTasks($data): int|float + { + + $q = $this->taskQuery($data); + $q->whereHas('invoice'); + + return $this->taskCalculations($q, $data); + + } + + /** + * All Expenses + */ + public function getLoggedExpenses($data): int|float + { + $q = $this->expenseQuery($data); + + return $this->expenseCalculations($q, $data); + } + + + /** + * Expenses that should be invoiced - but are not yet invoiced. + */ + public function getPendingExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->where('should_be_invoiced', true)->whereNull('invoice_id'); + return $this->expenseCalculations($q, $data); + } + + /** + * Invoiced. + */ + public function getInvoicedExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->whereNotNull('invoice_id'); + return $this->expenseCalculations($q, $data); + } + + /** + * Paid. + */ + public function getPaidExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->whereNotNull('payment_date'); + return $this->expenseCalculations($q, $data); + } + + /** + * Paid. + */ + public function getInvoicedPaidExpenses($data): int|float + { + + $q = $this->expenseQuery($data); + $q->whereNotNull('invoice_id')->whereNotNull('payment_date'); + return $this->expenseCalculations($q, $data); + } + + private function expenseCalculations(Builder $query, array $data): int|float + { $result = 0; - $calculated = collect(); - - $q = Task::query() - ->withTrashed() - ->where('company_id', $this->company->id) - ->where('is_deleted',0); - - if(in_array($data['period'], ['current,previous'])) { - $q->whereBetween('calculated_start_date', [$data['start_date'], $data['end_date']]); - } - - if($data['calculation'] != 'count' && $data['format'] == 'money') - { - if($data['currency_id'] != '999') - { - - $q->whereHas('client', function ($query) use ($data){ - $query->where('settings->currency_id', $data['currency_id']); - }); - - } - - $calculated = $this->taskMoneyCalculator($q, $data); - - } - - if($data['calculation'] != 'count' && $data['format'] == 'time') - { - $calculated = $q->get()->map(function ($t){ - return $t->calcDuration(); - }); - } - + $calculated = $this->expenseCalculator($query, $data); + match ($data['calculation']) { 'sum' => $result = $calculated->sum(), 'avg' => $result = $calculated->avg(), - 'count' => $result = $q->count(), + 'count' => $result = $query->count(), default => $result = 0, }; return $result; + } + private function expenseCalculator(Builder $query, array $data) + { + + return $query->get() + ->when($data['currency_id'] == '999', function ($collection) { + $collection->map(function ($e) { + /** @var \App\Models\Expense $e */ + return $e->amount * $e->exchange_rate; + }); + }) + ->when($data['currency_id'] != '999', function ($collection) { + + $collection->map(function ($e) { + + /** @var \App\Models\Expense $e */ + return $e->amount; + }); + + }); + + } + + private function expenseQuery($data): Builder + { + $query = Expense::query() + ->withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted', 0); + + if(in_array($data['period'], ['current,previous'])) { + $query->whereBetween('date', [$data['start_date'], $data['end_date']]); + } + + return $query; + } + + //////////////////////////////////////////////////////////////// private function taskMoneyCalculator($query, $data) { @@ -240,24 +333,28 @@ trait ChartCalculations } - public function getInvoicedTasks($data): int|float + private function taskQuery($data): Builder { - - $result = 0; - $calculated = collect(); - $q = Task::query() ->withTrashed() ->where('company_id', $this->company->id) - ->where('is_deleted', 0) - ->whereHas('invoice'); - + ->where('is_deleted', 0); + if(in_array($data['period'], ['current,previous'])) { $q->whereBetween('calculated_start_date', [$data['start_date'], $data['end_date']]); } - if($data['calculation'] != 'count' && $data['format'] == 'money') { + return $q; + } + + private function taskCalculations(Builder $q, array $data): int|float + { + + $result = 0; + $calculated = collect(); + + if($data['calculation'] != 'count' && $data['format'] == 'money') { if($data['currency_id'] != '999') { $q->whereHas('client', function ($query) use ($data) { @@ -286,4 +383,5 @@ trait ChartCalculations return $result; } + } \ No newline at end of file diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index f22183f255aa..792fd87baa08 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -224,6 +224,8 @@ class ChartService * period - current/previous * calculation - sum/count/avg * + * May require currency_id + * * date_range - this_month * or * start_date - end_date @@ -241,11 +243,11 @@ class ChartService 'unapproved_quotes' => $results = $this->getUnapprovedQuotes($data), 'logged_tasks' => $results = $this->getLoggedTasks($data), 'invoiced_tasks' => $results = $this->getInvoicedTasks($data), - 'paid_tasks' => $results = 0, - 'logged_expenses' => $results = 0, - 'pending_expenses' => $results = 0, - 'invoiced_expenses' => $results = 0, - 'invoice_paid_expenses' => $results = 0, + 'paid_tasks' => $results = $this->getPaidTasks($data), + 'logged_expenses' => $results = $this->getLoggedExpenses($data), + 'pending_expenses' => $results = $this->getPendingExpenses($data), + 'invoiced_expenses' => $results = $this->getInvoicedExpenses($data), + 'invoice_paid_expenses' => $results = $this->getInvoicedPaidExpenses($data), default => $results = 0, }; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index c511409993ca..f30302435dc1 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -124,7 +124,7 @@ class TemplateService $this->twig->addFilter($filter); $allowedTags = ['if', 'for', 'set', 'filter']; - $allowedFilters = ['escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format']; + $allowedFilters = ['escape', 'e', 'upper', 'lower', 'capitalize', 'filter', 'length', 'merge','format_currency', 'format_number','format_percent_number','map', 'join', 'first', 'date', 'sum', 'number_format','nl2br']; $allowedFunctions = ['range', 'cycle', 'constant', 'date',]; $allowedProperties = ['type_id']; $allowedMethods = ['img','t'];