Added: Laravel Debugbar & Charts In Dashboard

This commit is contained in:
Fahim 2021-08-10 01:23:24 +06:00
parent e98ade9ffb
commit 870f52505d
14 changed files with 585 additions and 61 deletions

View File

@ -41,7 +41,7 @@
</tr>
<tr>
<th>Cost</th>
<td>{{ format_currency($product->product_price) }}</td>
<td>{{ format_currency($product->product_cost) }}</td>
</tr>
<tr>
<th>Price</th>

View File

@ -12,10 +12,12 @@ if (!function_exists('format_currency')) {
return $value;
}
if (settings()->default_currency_position == 'prefix') {
$formatted_value = settings()->currency->symbol . number_format((float) $value, 2, settings()->currency->decimal_separator, settings()->currency->thousand_separator);
$settings = settings();
if ($settings->default_currency_position == 'prefix') {
$formatted_value = $settings->currency->symbol . number_format((float) $value, 2, $settings->currency->decimal_separator, $settings->currency->thousand_separator);
} else {
$formatted_value = number_format((float) $value, 2, settings()->currency->decimal_separator, settings()->currency->thousand_separator) . settings()->currency->symbol;
$formatted_value = number_format((float) $value, 2, $settings->currency->decimal_separator, $settings->currency->thousand_separator) . $settings->currency->symbol;
}
return $formatted_value;

View File

@ -3,26 +3,133 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Modules\Expense\Entities\Expense;
use Modules\Product\Entities\Product;
use Modules\Purchase\Entities\Purchase;
use Modules\PurchasesReturn\Entities\PurchaseReturn;
use Modules\Sale\Entities\Sale;
use Modules\SalesReturn\Entities\SaleReturn;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
public function index() {
$sales = Sale::sum('total_amount');
$sale_returns = SaleReturn::sum('total_amount');
$purchase_returns = PurchaseReturn::sum('total_amount');
$product_costs = 0;
foreach (Sale::with('saleDetails')->get() as $sale) {
foreach ($sale->saleDetails as $saleDetail) {
$product_costs += $saleDetail->product->product_cost;
}
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
return view('home');
$revenue = ($sales - $sale_returns) / 100;
$profit = $revenue - $product_costs;
return view('home', [
'revenue' => $revenue,
'sale_returns' => $sale_returns / 100,
'purchase_returns' => $purchase_returns / 100,
'profit' => $profit
]);
}
public function currentMonthChart() {
$currentMonthSales = Sale::whereMonth('date', date('m'))
->whereYear('date', date('Y'))
->sum('total_amount') / 100;
$currentMonthPurchases = Purchase::whereMonth('date', date('m'))
->whereYear('date', date('Y'))
->sum('total_amount') / 100;
$currentMonthExpenses = Expense::whereMonth('date', date('m'))
->whereYear('date', date('Y'))
->sum('amount') / 100;
return response()->json([
'sales' => $currentMonthSales,
'purchases' => $currentMonthPurchases,
'expenses' => $currentMonthExpenses
]);
}
public function salesPurchasesChart() {
$sales = $this->salesChartData();
$purchases = $this->purchasesChartData();
return response()->json(['sales' => $sales, 'purchases' => $purchases]);
}
public function salesChartData() {
// Build an array of the dates we want to show, the oldest first
$dates = collect();
foreach (range(-6, 0) as $i) {
$date = Carbon::now()->addDays($i)->format('d-m-y');
$dates->put($date, 0);
}
$date_range = Carbon::today()->subDays(6);
// Get the sales counts
$sales = Sale::where('date', '>=', $date_range)
->groupBy(DB::raw("DATE_FORMAT(date,'%d-%m-%y')"))
->orderBy('date', 'asc')
->get([
DB::raw(DB::raw("DATE_FORMAT(date,'%d-%m-%y') as date")),
DB::raw('SUM(total_amount) AS count'),
])
->pluck('count', 'date');
// Merge the two collections;
$dates = $dates->merge($sales);
$data = [];
$days = [];
foreach ($dates as $key => $value) {
$data[] = $value / 100;
$days[] = $key;
}
return response()->json(['data' => $data, 'days' => $days]);
}
public function purchasesChartData() {
// Build an array of the dates we want to show, the oldest first
$dates = collect();
foreach (range(-6, 0) as $i) {
$date = Carbon::now()->addDays($i)->format('d-m-y');
$dates->put($date, 0);
}
$date_range = Carbon::today()->subDays(6);
// Get the purchases counts
$purchases = Purchase::where('date', '>=', $date_range)
->groupBy(DB::raw("DATE_FORMAT(date,'%d-%m-%y')"))
->orderBy('date', 'asc')
->get([
DB::raw(DB::raw("DATE_FORMAT(date,'%d-%m-%y') as date")),
DB::raw('SUM(total_amount) AS count'),
])
->pluck('count', 'date');
// Merge the two collections;
$dates = $dates->merge($purchases);
$data = [];
$days = [];
foreach ($dates as $key => $value) {
$data[] = $value / 100;
$days[] = $key;
}
return response()->json(['data' => $data, 'days' => $days]);
}
}

View File

@ -44,7 +44,7 @@ class ProductTable extends Component
}
break;
default:
return session()->flash('message', 'Something went wrong!');;
return session()->flash('message', 'Something went wrong!');
}
array_push($this->products, $product);

View File

@ -31,6 +31,10 @@ class ProductTable extends Component
}
public function generateBarcodes(Product $product, $quantity) {
if ($quantity > 100) {
return session()->flash('message', 'Max quantity is 100 per barcode generation!');
}
$this->barcodes = [];
for ($i = 1; $i <= $quantity; $i++) {

View File

@ -24,6 +24,7 @@
"yajra/laravel-datatables": "^1.5"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.6",
"facade/ignition": "^2.5",
"fakerphp/faker": "^1.9.1",
"laravel/sail": "^1.0.1",
@ -69,7 +70,7 @@
"preferred-install": "dist",
"sort-packages": true,
"platform": {
"php": "8.0"
"php": "7.4"
}
},
"minimum-stability": "dev",

220
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "81cce1ef2defb71f07fb109dda14cc2c",
"content-hash": "646db8c9d7e97562bbf1eacf7731e23e",
"packages": [
{
"name": "asm89/stack-cors",
@ -7222,6 +7222,91 @@
}
],
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.6.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "70b89754913fd89fef16d0170a91dbc2a5cd633a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/70b89754913fd89fef16d0170a91dbc2a5cd633a",
"reference": "70b89754913fd89fef16d0170a91dbc2a5cd633a",
"shasum": ""
},
"require": {
"illuminate/routing": "^6|^7|^8",
"illuminate/session": "^6|^7|^8",
"illuminate/support": "^6|^7|^8",
"maximebf/debugbar": "^1.16.3",
"php": ">=7.2",
"symfony/debug": "^4.3|^5",
"symfony/finder": "^4.3|^5"
},
"require-dev": {
"mockery/mockery": "^1.3.3",
"orchestra/testbench-dusk": "^4|^5|^6",
"phpunit/phpunit": "^8.5|^9.0",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.5-dev"
},
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
"autoload": {
"psr-4": {
"Barryvdh\\Debugbar\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "PHP Debugbar integration for Laravel",
"keywords": [
"debug",
"debugbar",
"laravel",
"profiler",
"webprofiler"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.2"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2021-06-14T14:29:26+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.4.0",
@ -7732,6 +7817,71 @@
},
"time": "2021-07-13T14:20:58+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.17.1",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "0a3532556be0145603f8a9de23e76dc28eed7054"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/0a3532556be0145603f8a9de23e76dc28eed7054",
"reference": "0a3532556be0145603f8a9de23e76dc28eed7054",
"shasum": ""
},
"require": {
"php": "^7.1|^8",
"psr/log": "^1.0",
"symfony/var-dumper": "^2.6|^3|^4|^5"
},
"require-dev": {
"phpunit/phpunit": "^7.5.20 || ^9.4.2"
},
"suggest": {
"kriswallsmith/assetic": "The best way to manage assets",
"monolog/monolog": "Log using Monolog",
"predis/predis": "Redis storage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.17-dev"
}
},
"autoload": {
"psr-4": {
"DebugBar\\": "src/DebugBar/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Debug bar in the browser for php application",
"homepage": "https://github.com/maximebf/php-debugbar",
"keywords": [
"debug",
"debugbar"
],
"support": {
"issues": "https://github.com/maximebf/php-debugbar/issues",
"source": "https://github.com/maximebf/php-debugbar/tree/v1.17.1"
},
"time": "2021-08-01T09:19:02+00:00"
},
{
"name": "mockery/mockery",
"version": "1.4.3",
@ -9671,6 +9821,74 @@
],
"time": "2020-09-28T06:39:44+00:00"
},
{
"name": "symfony/debug",
"version": "v4.4.27",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "2f9160e92eb64c95da7368c867b663a8e34e980c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/2f9160e92eb64c95da7368c867b663a8e34e980c",
"reference": "2f9160e92eb64c95da7368c867b663a8e34e980c",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "^1|^2|^3"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides tools to ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v4.4.27"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-07-22T07:21:39+00:00"
},
{
"name": "theseer/tokenizer",
"version": "1.2.0",

View File

@ -9,5 +9,161 @@
@endsection
@section('content')
<div class="container-fluid mb-4">
<div class="row">
<div class="col-md-6 col-lg-3">
<div class="card border-0">
<div class="card-body p-0 d-flex align-items-center shadow-sm">
<div class="bg-gradient-primary p-4 mfe-3 rounded-left">
<i class="bi bi-bar-chart font-2xl"></i>
</div>
<div>
<div class="text-value text-primary">{{ format_currency($revenue) }}</div>
<div class="text-muted text-uppercase font-weight-bold small">Revenue</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card border-0">
<div class="card-body p-0 d-flex align-items-center shadow-sm">
<div class="bg-gradient-warning p-4 mfe-3 rounded-left">
<i class="bi bi-arrow-return-left font-2xl"></i>
</div>
<div>
<div class="text-value text-warning">{{ format_currency($sale_returns) }}</div>
<div class="text-muted text-uppercase font-weight-bold small">Sales Return</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card border-0">
<div class="card-body p-0 d-flex align-items-center shadow-sm">
<div class="bg-gradient-success p-4 mfe-3 rounded-left">
<i class="bi bi-arrow-return-right font-2xl"></i>
</div>
<div>
<div class="text-value text-success">{{ format_currency($purchase_returns) }}</div>
<div class="text-muted text-uppercase font-weight-bold small">Purchases Return</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card border-0">
<div class="card-body p-0 d-flex align-items-center shadow-sm">
<div class="bg-gradient-info p-4 mfe-3 rounded-left">
<i class="bi bi-trophy font-2xl"></i>
</div>
<div>
<div class="text-value text-info">{{ format_currency($profit) }}</div>
<div class="text-muted text-uppercase font-weight-bold small">Profit</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-7">
<div class="card border-0 shadow-sm h-100">
<div class="card-header">
Sales & Purchases of Last 7 Days
</div>
<div class="card-body">
<canvas id="salesPurchasesChart"></canvas>
</div>
</div>
</div>
<div class="col-lg-5">
<div class="card border-0 shadow-sm h-100">
<div class="card-header">
{{ now()->format('F, Y') }}
</div>
<div class="card-body">
<canvas id="currentMonthChart"></canvas>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('third_party_scripts')
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.min.js"
integrity="sha512-asxKqQghC1oBShyhiBwA+YgotaSYKxGP1rcSYTDrB0U6DxwlJjU59B67U8+5/++uFjcuVM8Hh5cokLjZlhm3Vg=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
@endsection
@push('page_scripts')
<script>
$(document).ready(function () {
let chart1 = document.getElementById('salesPurchasesChart');
$.get('{{ route('sales-purchases.chart') }}', function (response) {
let salesPurchasesChart = new Chart(chart1, {
type: 'bar',
data: {
labels: response.sales.original.days,
datasets: [{
label: 'Sales',
data: response.sales.original.data,
backgroundColor: [
'#6366F1',
],
borderColor: [
'#6366F1',
],
borderWidth: 1
},
{
label: 'Purchases',
data: response.purchases.original.data,
backgroundColor: [
'#A5B4FC',
],
borderColor: [
'#A5B4FC',
],
borderWidth: 1
}
]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
});
let chart2 = document.getElementById('currentMonthChart');
$.get('{{ route('current-month.chart') }}', function (response) {
let currentMonthChart = new Chart(chart2, {
type: 'doughnut',
data: {
labels: ['Sales', 'Purchases', 'Expenses'],
datasets: [{
data: [response.sales, response.purchases, response.expenses],
backgroundColor: [
'#F59E0B',
'#0284C7',
'#EF4444',
],
hoverBackgroundColor: [
'#F59E0B',
'#0284C7',
'#EF4444',
],
}]
},
});
});
});
</script>
@endpush

View File

@ -48,6 +48,12 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/1.4.0/perfect-scrollbar.js"></script>
<script src="{{ asset('vendor/datatables/buttons.server-side.js') }}"></script>
<script>
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
@include('sweetalert::alert')
@yield('third_party_scripts')

View File

@ -10,13 +10,13 @@
</ul>
<ul class="c-header-nav ml-auto mr-4">
<li class="c-header-nav-item mx-2 mr-3">
<li class="c-header-nav-item mr-3">
<a class="btn btn-primary btn-pill" href="#">
<i class="bi bi-cart mr-1"></i> POS System
</a>
</li>
<li class="c-header-nav-item dropdown d-md-down-none mx-2">
<li class="c-header-nav-item dropdown d-md-down-none mr-2">
<a class="c-header-nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
<i class="bi bi-bell" style="font-size: 20px;"></i>
<span class="badge badge-pill badge-danger">0</span>
@ -32,10 +32,13 @@
<li class="c-header-nav-item dropdown">
<a class="c-header-nav-link" data-toggle="dropdown" href="#" role="button"
aria-haspopup="true" aria-expanded="false">
<span class="mr-2 font-weight-bold">{{ auth()->user()->name }}</span>
<div class="c-avatar">
<div class="c-avatar mr-2">
<img class="c-avatar rounded-circle" src="{{ auth()->user()->getFirstMediaUrl('avatars') }}" alt="Profile Image">
</div>
<div class="d-flex flex-column">
<span class="font-weight-bold">{{ auth()->user()->name }}</span>
<span class="font-italic">Online <i class="bi bi-circle-fill text-success" style="font-size: 11px;"></i></span>
</div>
</a>
<div class="dropdown-menu dropdown-menu-right pt-0">
<div class="dropdown-header bg-light py-2"><strong>Account</strong></div>

View File

@ -1,4 +1,14 @@
<div>
@if (session()->has('message'))
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<div class="alert-body">
<span>{{ session('message') }}</span>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
</div>
@endif
<div class="card">
<div class="card-body">
<div class="table-responsive-md">
@ -7,7 +17,9 @@
<tr class="align-middle">
<th class="align-middle">Product Name</th>
<th class="align-middle">Code</th>
<th class="align-middle">Quantity</th>
<th class="align-middle">
Quantity <i class="bi bi-question-circle-fill text-info" data-toggle="tooltip" data-placement="top" title="Max Quantity: 100"></i>
</th>
</tr>
</thead>
<tbody>
@ -16,8 +28,7 @@
<td class="align-middle">{{ $product->product_name }}</td>
<td class="align-middle">{{ $product->product_code }}</td>
<td class="align-middle text-center" style="width: 200px;">
<input wire:model="quantity" class="form-control" type="number" min="1"
value="{{ $quantity }}">
<input wire:model="quantity" class="form-control" type="number" min="1" max="100" value="{{ $quantity }}">
</td>
@else
<td colspan="3" class="text-center">
@ -29,14 +40,21 @@
</table>
</div>
<div class="mt-3">
<button
wire:click="generateBarcodes({{ $product }}, {{ $quantity }})"
type="button" class="btn btn-primary"><i class="bi bi-upc-scan"></i> Generate Barcodes
<button wire:click="generateBarcodes({{ $product }}, {{ $quantity }})" type="button" class="btn btn-primary">
<i class="bi bi-upc-scan"></i> Generate Barcodes
</button>
</div>
</div>
</div>
<div wire:loading wire:target="generateBarcodes" class="w-100">
<div class="d-flex justify-content-center">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
@if(!empty($barcodes))
<div class="text-right mb-3">
<button wire:click="getPdf" wire:loading.attr="disabled" type="button" class="btn btn-primary">

View File

@ -14,8 +14,8 @@
</div>
</div>
<div wire:loading wire:target="query" class="card position-absolute mt-1" style="z-index: 1;left: 0;right: 0;">
<div class="card-body">
<div wire:loading wire:target="query" class="card position-absolute mt-1 border-0" style="z-index: 1;left: 0;right: 0;">
<div class="card-body shadow">
<div class="d-flex justify-content-center">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
@ -27,8 +27,8 @@
@if(!empty($query))
<div wire:click="resetQuery" class="position-fixed w-100 h-100" style="left: 0; top: 0; right: 0; bottom: 0;z-index: 1;"></div>
@if($searchResults->isNotEmpty())
<div class="card position-absolute mt-1" style="z-index: 2;left: 0;right: 0;">
<div class="card-body">
<div class="card position-absolute mt-1" style="z-index: 2;left: 0;right: 0;border: 0;">
<div class="card-body shadow">
<ul class="list-group list-group-flush">
@foreach($searchResults as $result)
<li class="list-group-item list-group-item-action">
@ -41,10 +41,10 @@
</div>
</div>
@else
<div class="card position-absolute mt-1" style="z-index: 1;left: 0;right: 0;">
<div class="card-body">
<div class="card position-absolute mt-1 border-0" style="z-index: 1;left: 0;right: 0;">
<div class="card-body shadow">
<div class="alert alert-warning mb-0">
No Results....
No Product Found....
</div>
</div>
</div>

View File

@ -14,5 +14,12 @@ Route::get('/', function () {
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home')->middleware('auth');
Route::get('/home', 'HomeController@index')
->name('home')->middleware('auth');
Route::get('/sales-purchases/chart-data', 'HomeController@salesPurchasesChart')
->name('sales-purchases.chart')->middleware('auth');
Route::get('/current-month/chart-data', 'HomeController@currentMonthChart')
->name('current-month.chart')->middleware('auth');

2
storage/debugbar/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore