-
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* ➕ Add dompdf dep * ✨ Add Report Manager and notification * ✨ Add task schedule to be last day of every month
- Loading branch information
1 parent
a6cbe2c
commit 8492e24
Showing
10 changed files
with
1,056 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<?php | ||
|
||
namespace App\BusinessLogic; | ||
|
||
use App\Contracts\ReportManager as ReportManagerContract; | ||
use App\Domain\Ranges\CurrentMonth; | ||
use App\Domain\Ranges\LastMonth; | ||
use App\Models\Brand; | ||
use App\Models\Category; | ||
use App\Models\Transaction; | ||
|
||
class ReportManager implements ReportManagerContract | ||
{ | ||
protected $data = []; | ||
|
||
public function generate() | ||
{ | ||
$newBrands = Brand::whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])->pluck('name'); | ||
|
||
$currentMonthRange = new CurrentMonth; | ||
$lastMonthRange = new LastMonth; | ||
|
||
$this->addSection('Overview', $this->getOverviewData()); | ||
|
||
foreach(Category::all() as $category) | ||
{ | ||
$brandsData = []; | ||
|
||
foreach($category->brands as $brand) { | ||
$totalCurrentMonth = $brand->transactions()->whereBetween('created_at', [$currentMonthRange->start(), $currentMonthRange->end()])->sum('amount'); | ||
$totalLastMonth = $brand->transactions()->whereBetween('created_at', [$lastMonthRange->start(), $lastMonthRange->end()])->sum('amount'); | ||
$change = ! $totalLastMonth ? '-' : number_format(($totalCurrentMonth / $totalLastMonth - 1) * 100, 2); | ||
|
||
$brandsData[] = [ | ||
'name' => $brand->name, | ||
'total_current_month' => $totalCurrentMonth, | ||
'total_previous_month' => $totalLastMonth, | ||
'change' => $change, | ||
'change_color' => $this->getChangeColor($change, $category->type), | ||
'is_new' => $newBrands->contains($brand->name) | ||
]; | ||
} | ||
|
||
$brandsData = $this->calculateAndAddAllBrandsData($brandsData, $category); | ||
|
||
$this->addSection($category->name, $brandsData); | ||
} | ||
|
||
return $this->data; | ||
} | ||
|
||
protected function addSection($sectionName, $data) | ||
{ | ||
$this->data[$sectionName] = $data; | ||
} | ||
|
||
protected function getChangeColor($change, $type) | ||
{ | ||
if($change == '-') { | ||
return 'gray'; | ||
} | ||
|
||
if($type == Category::INCOME) { | ||
return $change >= 0 ? 'green' : 'red'; | ||
} | ||
|
||
return $change >= 0 ? 'red' : 'green'; | ||
} | ||
|
||
protected function calculateAndAddAllBrandsData($brandsData, $category) | ||
{ | ||
$allCurrentMonth = array_reduce($brandsData, function ($carry, $item) { | ||
$carry += $item['total_current_month']; | ||
|
||
return $carry; | ||
}); | ||
|
||
$allLastMonth = array_reduce($brandsData, function ($carry, $item) { | ||
$carry += $item['total_previous_month']; | ||
|
||
return $carry; | ||
}); | ||
|
||
$change = ! $allLastMonth ? '-' : number_format(($allCurrentMonth / $allLastMonth - 1) * 100, 2); | ||
|
||
return array_merge([[ | ||
'name' => 'All', | ||
'total_current_month' => $allCurrentMonth, | ||
'total_previous_month' => $allLastMonth, | ||
'change' => $change, | ||
'change_color' => $this->getChangeColor($change, $category->type) | ||
]], $brandsData); | ||
} | ||
|
||
protected function getOverviewData() | ||
{ | ||
return [ | ||
$this->getTotalCash(), | ||
$this->getTotalIncome(), | ||
$this->getTotalExpenses(), | ||
]; | ||
} | ||
|
||
protected function getTotalCash() | ||
{ | ||
$totalIncome = Transaction::income()->sum('amount'); | ||
$totalExpenses = Transaction::expenses()->sum('amount'); | ||
|
||
$totalIncomeExcludingThisMonth = Transaction::income()->where('created_at', '<', now()->startOfMonth())->sum('amount'); | ||
$totalExpensesExcludingThisMonth = Transaction::expenses()->where('created_at', '<', now()->startOfMonth())->sum('amount'); | ||
|
||
$totalCashTillNow = $totalIncome - $totalExpenses; | ||
$totalCashExcludingThisMonth = $totalIncomeExcludingThisMonth - $totalExpensesExcludingThisMonth; | ||
|
||
$change = ! $totalCashExcludingThisMonth ? '-' : number_format(($totalCashTillNow / $totalCashExcludingThisMonth - 1) * 100, 2); | ||
|
||
return [ | ||
'name' => 'Total Cash', | ||
'total_current_month' => $totalCashTillNow, | ||
'total_previous_month' => $totalCashExcludingThisMonth, | ||
'change' => $change, | ||
'change_color' => $this->getChangeColor($change, 'INCOME') | ||
]; | ||
} | ||
|
||
protected function getTotalIncome() | ||
{ | ||
$total = Transaction::income()->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])->sum('amount'); | ||
$totalExcludingThisMonth = Transaction::income()->whereBetween('created_at', [now()->subMonth()->startOfMonth(), now()->subMonth()->endOfMonth()])->sum('amount'); | ||
|
||
$change = ! $totalExcludingThisMonth ? '-' : number_format(($total / $totalExcludingThisMonth - 1) * 100, 2); | ||
|
||
return [ | ||
'name' => 'Total Income', | ||
'total_current_month' => $total, | ||
'total_previous_month' => $totalExcludingThisMonth, | ||
'change' => $change, | ||
'change_color' => $this->getChangeColor($change, 'INCOME') | ||
]; | ||
} | ||
|
||
protected function getTotalExpenses() | ||
{ | ||
$total = Transaction::expenses()->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])->sum('amount'); | ||
$totalExcludingThisMonth = Transaction::expenses()->whereBetween('created_at', [now()->subMonth()->startOfMonth(), now()->subMonth()->endOfMonth()])->sum('amount'); | ||
|
||
$change = ! $totalExcludingThisMonth ? '-' : number_format(($total / $totalExcludingThisMonth - 1) * 100, 2); | ||
|
||
return [ | ||
'name' => 'Total Expenses', | ||
'total_current_month' => $total, | ||
'total_previous_month' => $totalExcludingThisMonth, | ||
'change' => $change, | ||
'change_color' => $this->getChangeColor($change, 'EXPENSES') | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
namespace App\Console\Commands; | ||
|
||
use App\Models\User; | ||
use Illuminate\Console\Command; | ||
use App\Notifications\FinanceMonthlyReportNotification; | ||
|
||
class ReportCommand extends Command | ||
{ | ||
/** | ||
* The name and signature of the console command. | ||
* | ||
* @var string | ||
*/ | ||
protected $signature = 'finance:report'; | ||
|
||
/** | ||
* The console command description. | ||
* | ||
* @var string | ||
*/ | ||
protected $description = 'Report the finance data for the current month'; | ||
|
||
/** | ||
* Create a new command instance. | ||
* | ||
* @return void | ||
*/ | ||
public function __construct() | ||
{ | ||
parent::__construct(); | ||
} | ||
|
||
/** | ||
* Execute the console command. | ||
* | ||
* @return int | ||
*/ | ||
public function handle() | ||
{ | ||
User::first()->notify(new FinanceMonthlyReportNotification); | ||
|
||
return 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?php | ||
|
||
namespace App\Contracts; | ||
|
||
interface ReportManager | ||
{ | ||
public function generate(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
|
||
namespace App\Notifications; | ||
|
||
use App\Contracts\ReportManager; | ||
use App\Services\PdfRenderer; | ||
use Illuminate\Bus\Queueable; | ||
use Illuminate\Contracts\Queue\ShouldQueue; | ||
use Illuminate\Notifications\Messages\MailMessage; | ||
use Illuminate\Notifications\Notification; | ||
|
||
class FinanceMonthlyReportNotification extends Notification | ||
{ | ||
use Queueable; | ||
|
||
/** | ||
* Create a new notification instance. | ||
* | ||
* @return void | ||
*/ | ||
public function __construct() | ||
{ | ||
// | ||
} | ||
|
||
/** | ||
* Get the notification's delivery channels. | ||
* | ||
* @param mixed $notifiable | ||
* @return array | ||
*/ | ||
public function via($notifiable) | ||
{ | ||
return ['mail']; | ||
} | ||
|
||
/** | ||
* Get the mail representation of the notification. | ||
* | ||
* @param mixed $notifiable | ||
* @return \Illuminate\Notifications\Messages\MailMessage | ||
*/ | ||
public function toMail($notifiable) | ||
{ | ||
$data = [ | ||
'sections' => app(ReportManager::class)->generate(), | ||
'currency' => config('finance.currency'), | ||
'month' => now()->format('M Y') | ||
]; | ||
|
||
return (new MailMessage) | ||
->subject('Finance report for ' . $data['month']) | ||
->line('Please find the finance report attachment for ' . $data['month']) | ||
->attachData(PdfRenderer::render('report', $data), 'finance-report.pdf'); | ||
} | ||
|
||
/** | ||
* Get the array representation of the notification. | ||
* | ||
* @param mixed $notifiable | ||
* @return array | ||
*/ | ||
public function toArray($notifiable) | ||
{ | ||
return [ | ||
// | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace App\Services; | ||
|
||
use Dompdf\Dompdf; | ||
use Dompdf\Options; | ||
use Illuminate\Support\Facades\View; | ||
|
||
class PdfRenderer | ||
{ | ||
public static function render($view, $data) | ||
{ | ||
if (! defined('DOMPDF_ENABLE_AUTOLOAD')) { | ||
define('DOMPDF_ENABLE_AUTOLOAD', false); | ||
} | ||
|
||
$dompdfOptions = new Options(); | ||
$dompdfOptions->setChroot(base_path()); | ||
|
||
$dompdf = new Dompdf($dompdfOptions); | ||
$dompdf->setPaper('A4'); | ||
|
||
$dompdf->loadHtml(View::make($view, $data)->render()); | ||
$dompdf->render(); | ||
|
||
return (string) $dompdf->output(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.