Today weโll build a dashboard that visually compares actual sales vs forecasted predictions, and highlight any significant deviations โ helping you track accuracy and adjust strategy.
๐ Step 1: Join actual & forecasted sales by date
In SalesController.php
:
use App\Models\Sale;
use App\Models\ForecastResult;
use Illuminate\Support\Facades\DB;
public function index()
{
// Historical daily sales
$sales = Sale::select(
DB::raw('DATE(sale_date) as date'),
DB::raw('SUM(amount) as total')
)
->groupBy('date')
->orderBy('date')
->get();
// Forecast data
$forecast = ForecastResult::orderBy('forecast_date')->get();
// Align data
$dates = $forecast->pluck('forecast_date')->map(fn($d) => date('d M', strtotime($d)));
$actual = $dates->map(function ($d) use ($sales) {
return $sales->firstWhere('date', date('Y-m-d', strtotime($d)))->total ?? null;
});
$predicted = $forecast->pluck('yhat');
$lower = $forecast->pluck('yhat_lower');
$upper = $forecast->pluck('yhat_upper');
return view('sales.index', compact('dates', 'actual', 'predicted', 'lower', 'upper'));
}
๐ Step 2: Update Chart.js to compare datasets
In sales/index.blade.php
, replace chart setup:
<canvas id="forecastChart" height="120"></canvas>
<script>
const ctx = document.getElementById('forecastChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: @json($dates),
datasets: [
{
label: 'Actual Sales',
data: @json($actual),
borderColor: 'rgba(54, 162, 235, 1)',
backgroundColor: 'transparent',
tension: 0.3,
spanGaps: true
},
{
label: 'Predicted Sales',
data: @json($predicted),
borderColor: 'rgba(255, 99, 132, 1)',
borderDash: [5, 5],
tension: 0.3
},
{
label: 'Lower Bound',
data: @json($lower),
borderColor: 'rgba(200, 200, 200, 0.5)',
fill: '+1',
hidden: true
},
{
label: 'Upper Bound',
data: @json($upper),
borderColor: 'rgba(200, 200, 200, 0.5)',
fill: '-1',
hidden: true
}
]
},
options: {
responsive: true,
plugins: {
legend: { position: 'top' },
tooltip: { mode: 'index', intersect: false }
},
scales: {
y: { beginAtZero: true }
}
}
});
</script>
๐ Step 3: Interpret deviations manually or with GPT
In your insight generator (optional), add:
if (abs($actual - $predicted) > threshold) {
$alert[] = "Sales on $date deviated significantly.";
}
Or use GPT again with a custom prompt:
“Compare actual sales vs predicted, highlight major gaps.”
โ Output
Your dashboard now clearly shows:
- Actual vs Predicted sales lines
- Visual gaps or convergence
- Confidence band range (optional)
โ Up next (Day 9): weโll add CSV and PDF reports, allowing you to export forecasts and visual insights for management or reporting.