Added rfq chart and rfq rank chart widgets page #100
136
app/Filament/Widgets/RfqChart.php
Normal file
136
app/Filament/Widgets/RfqChart.php
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Widgets;
|
||||||
|
|
||||||
|
use App\Models\RequestQuotation;
|
||||||
|
use App\Models\RfqTransporterBid;
|
||||||
|
use Filament\Facades\Filament;
|
||||||
|
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
|
||||||
|
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||||
|
|
||||||
|
class RfqChart extends BaseWidget
|
||||||
|
{
|
||||||
|
// protected function getStats(): array
|
||||||
|
// {
|
||||||
|
// $transporter = session('transport_name');
|
||||||
|
// $rfqNumber = session('rfq_number');
|
||||||
|
|
||||||
|
// if (!$transporter || !$rfqNumber) {
|
||||||
|
// return [
|
||||||
|
// Stat::make('Total Freight Charge', '-'),
|
||||||
|
// Stat::make('Rank', '-'),
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $selectedRfq = RequestQuotation::query()
|
||||||
|
// ->where('transporter_name', $transporter)
|
||||||
|
// ->where('rfq_number', $rfqNumber)
|
||||||
|
// ->first();
|
||||||
|
|
||||||
|
// if (!$selectedRfq) {
|
||||||
|
// return [
|
||||||
|
// Stat::make('Total Freight Charge', '-'),
|
||||||
|
// Stat::make('Rank', '-'),
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $myAmount = (float) $selectedRfq->total_freight_charge;
|
||||||
|
|
||||||
|
// $rank = RequestQuotation::query()
|
||||||
|
// ->whereRaw(
|
||||||
|
// 'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
|
||||||
|
// [$myAmount]
|
||||||
|
// )
|
||||||
|
// ->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
|
||||||
|
// ->distinct()
|
||||||
|
// ->count() + 1;
|
||||||
|
|
||||||
|
// $medal = match (true) {
|
||||||
|
// $rank == 1 => '🥇',
|
||||||
|
// $rank == 2 => '🥈',
|
||||||
|
// $rank == 3 => '🥉',
|
||||||
|
// default => '',
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return [
|
||||||
|
// Stat::make(
|
||||||
|
// 'Total Freight Charge',
|
||||||
|
// number_format($selectedRfq->total_freight_charge, 2)
|
||||||
|
// )
|
||||||
|
// ->description('Transporter: ' . $selectedRfq->transporter_name)
|
||||||
|
// ->color($rank == 1 ? 'success' : 'primary'),
|
||||||
|
|
||||||
|
// Stat::make(
|
||||||
|
// 'Rank',
|
||||||
|
// trim("{$medal} #{$rank}")
|
||||||
|
// )
|
||||||
|
// ->description('Among all transporters')
|
||||||
|
// ->color(
|
||||||
|
// $rank == 1 ? 'success' :
|
||||||
|
// ($rank <= 3 ? 'warning' : 'gray')
|
||||||
|
// ),
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
protected function getStats(): array
|
||||||
|
{
|
||||||
|
$transporter = session('transport_name');
|
||||||
|
$rfqNumber = session('rfq_id');
|
||||||
|
|
||||||
|
if (!$transporter || !$rfqNumber) {
|
||||||
|
return [
|
||||||
|
Stat::make('Total Freight Charge', '-'),
|
||||||
|
Stat::make('Rank', '-'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$selectedRfq = RfqTransporterBid::query()
|
||||||
|
->where('transporter_name', $transporter)
|
||||||
|
->where('request_quotation_id', $rfqNumber)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$selectedRfq) {
|
||||||
|
return [
|
||||||
|
Stat::make('Total Freight Charge', '-'),
|
||||||
|
Stat::make('Rank', '-'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$myAmount = (float) $selectedRfq->total_freight_charge;
|
||||||
|
|
||||||
|
$rank = RfqTransporterBid::query()
|
||||||
|
->whereRaw(
|
||||||
|
'CAST(total_freight_charge AS DECIMAL(10,2)) < ?',
|
||||||
|
[$myAmount]
|
||||||
|
)
|
||||||
|
->selectRaw('CAST(total_freight_charge AS DECIMAL(10,2))')
|
||||||
|
->distinct()
|
||||||
|
->count() + 1;
|
||||||
|
|
||||||
|
$medal = match (true) {
|
||||||
|
$rank == 1 => '🥇',
|
||||||
|
$rank == 2 => '🥈',
|
||||||
|
$rank == 3 => '🥉',
|
||||||
|
default => '',
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
Stat::make(
|
||||||
|
'Total Freight Charge',
|
||||||
|
number_format($selectedRfq->total_freight_charge, 2)
|
||||||
|
)
|
||||||
|
->description('Transporter: ' . $selectedRfq->transporter_name)
|
||||||
|
->color($rank == 1 ? 'success' : 'primary'),
|
||||||
|
|
||||||
|
Stat::make(
|
||||||
|
'Rank',
|
||||||
|
trim("{$medal} #{$rank}")
|
||||||
|
)
|
||||||
|
->description('Among all transporters')
|
||||||
|
->color(
|
||||||
|
$rank == 1 ? 'success' :
|
||||||
|
($rank <= 3 ? 'warning' : 'gray')
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
205
app/Filament/Widgets/RfqRankChart.php
Normal file
205
app/Filament/Widgets/RfqRankChart.php
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Widgets;
|
||||||
|
|
||||||
|
use App\Models\RfqTransporterBid;
|
||||||
|
use Filament\Widgets\ChartWidget;
|
||||||
|
use Illuminate\Support\Js;
|
||||||
|
|
||||||
|
class RfqRankChart extends ChartWidget
|
||||||
|
{
|
||||||
|
protected static ?string $heading = 'Chart';
|
||||||
|
|
||||||
|
// protected function getData(): array
|
||||||
|
// {
|
||||||
|
// $rfqId = session('rfq_id');
|
||||||
|
|
||||||
|
// if (!$rfqId) {
|
||||||
|
// return [
|
||||||
|
// 'datasets' => [],
|
||||||
|
// 'labels' => [],
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Get bids ordered by lowest freight charge
|
||||||
|
// $bids = RfqTransporterBid::query()
|
||||||
|
// ->where('request_quotation_id', $rfqId)
|
||||||
|
// ->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC')
|
||||||
|
// ->get();
|
||||||
|
|
||||||
|
// // $labels = [];
|
||||||
|
// // $ranks = [];
|
||||||
|
|
||||||
|
// // $rank = 1;
|
||||||
|
// // foreach ($bids as $bid) {
|
||||||
|
// // $labels[] = $bid->transporter_name;
|
||||||
|
// // $ranks[] = $rank++;
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // return [
|
||||||
|
// // 'datasets' => [
|
||||||
|
// // [
|
||||||
|
// // 'label' => 'Rank (Lower is Better)',
|
||||||
|
// // 'data' => $ranks,
|
||||||
|
// // 'fill' => false,
|
||||||
|
// // 'tension' => 0.3,
|
||||||
|
// // ],
|
||||||
|
// // ],
|
||||||
|
// // 'labels' => $labels,
|
||||||
|
// // ];
|
||||||
|
// $labels = [];
|
||||||
|
// $ranks = [];
|
||||||
|
// $colors = [];
|
||||||
|
|
||||||
|
// $rank = 1;
|
||||||
|
// foreach ($bids as $bid) {
|
||||||
|
// $labels[] = $bid->transporter_name;
|
||||||
|
// $ranks[] = $rank;
|
||||||
|
|
||||||
|
// // Rank-based colors
|
||||||
|
// $colors[] = match ($rank) {
|
||||||
|
// 1 => '#FFD700', // Gold
|
||||||
|
// 2 => '#C0C0C0', // Silver
|
||||||
|
// 3 => '#CD7F32', // Bronze
|
||||||
|
// default => '#3B82F6', // Blue
|
||||||
|
// };
|
||||||
|
|
||||||
|
// $rank++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return [
|
||||||
|
// 'datasets' => [
|
||||||
|
// [
|
||||||
|
// 'label' => 'Rank (1 = Best)',
|
||||||
|
// 'data' => $ranks,
|
||||||
|
|
||||||
|
// // 🎨 Styling
|
||||||
|
// 'borderColor' => '#3B82F6',
|
||||||
|
// 'backgroundColor' => $colors,
|
||||||
|
// 'pointBackgroundColor' => $colors,
|
||||||
|
// 'pointBorderColor' => '#000',
|
||||||
|
// 'pointRadius' => 7,
|
||||||
|
// 'pointHoverRadius' => 10,
|
||||||
|
// 'borderWidth' => 3,
|
||||||
|
// 'tension' => 0.4,
|
||||||
|
// 'fill' => false,
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
// 'labels' => $labels,
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected function getData(): array
|
||||||
|
{
|
||||||
|
$rfqId = session('rfq_id');
|
||||||
|
|
||||||
|
if (!$rfqId) {
|
||||||
|
return [
|
||||||
|
'datasets' => [],
|
||||||
|
'labels' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 1: Get bids sorted by freight charge (for ranking)
|
||||||
|
*/
|
||||||
|
$rankedBids = RfqTransporterBid::query()
|
||||||
|
->where('request_quotation_id', $rfqId)
|
||||||
|
->orderByRaw('CAST(total_freight_charge AS DECIMAL(10,2)) ASC')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$rankMap = [];
|
||||||
|
$rank = 1;
|
||||||
|
|
||||||
|
foreach ($rankedBids as $bid) {
|
||||||
|
$rankMap[$bid->id] = $rank++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* STEP 2: Get bids in natural order (for wave effect)
|
||||||
|
* You can change orderBy to:
|
||||||
|
* - created_at
|
||||||
|
* - transporter_name
|
||||||
|
*/
|
||||||
|
$chartBids = RfqTransporterBid::query()
|
||||||
|
->where('request_quotation_id', $rfqId)
|
||||||
|
->orderBy('id')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$labels = [];
|
||||||
|
$amounts = [];
|
||||||
|
$colors = [];
|
||||||
|
|
||||||
|
$ranks = [];
|
||||||
|
|
||||||
|
foreach ($chartBids as $bid) {
|
||||||
|
$labels[] = $bid->transporter_name;
|
||||||
|
$amounts[] = (float) $bid->total_freight_charge;
|
||||||
|
|
||||||
|
$rank = $rankMap[$bid->id];
|
||||||
|
$ranks[] = $rank;
|
||||||
|
|
||||||
|
$colors[] = match ($rank) {
|
||||||
|
1 => '#FFD700',
|
||||||
|
2 => '#C0C0C0',
|
||||||
|
3 => '#CD7F32',
|
||||||
|
default => '#2563EB',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => 'Freight Charge',
|
||||||
|
'data' => $amounts,
|
||||||
|
'rankData' => $ranks,
|
||||||
|
|
||||||
|
'borderColor' => '#2563EB',
|
||||||
|
'backgroundColor' => $colors,
|
||||||
|
'pointBackgroundColor' => $colors,
|
||||||
|
'pointBorderColor' => '#000',
|
||||||
|
'pointRadius' => 7,
|
||||||
|
'pointHoverRadius' => 11,
|
||||||
|
'borderWidth' => 3,
|
||||||
|
'tension' => 0.45,
|
||||||
|
'fill' => false,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'labels' => $labels,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'plugins' => [
|
||||||
|
'datalabels' => [
|
||||||
|
'anchor' => 'start',
|
||||||
|
'align' => 'start',
|
||||||
|
'offset' => -15,
|
||||||
|
'color' => '#000',
|
||||||
|
'font' => [
|
||||||
|
'weight' => 'bold',
|
||||||
|
],
|
||||||
|
'formatter' => Js::from("function(value) { return Number(value); }"),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'scales' => [
|
||||||
|
'y' => [
|
||||||
|
'beginAtZero' => true,
|
||||||
|
'ticks' => [
|
||||||
|
'stepSize' => 0.5,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getType(): string
|
||||||
|
{
|
||||||
|
return 'bar';
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user