KoolReport's Forum

Official Support Area, Q&As, Discussions, Suggestions and Bug reports.
Forum's Guidelines

Using a button to generate an Excel Download #3466

Open Wayland Games opened this topic on on Dec 3, 2025 - 4 comments

Wayland Games commented on Dec 3, 2025

Hi there,

I have a dashboard which I would like to include a button which when clicked generates an Excel spreadsheet to download. I've created a Button class:

<?php

namespace Pulse\Button;

use Carbon\Carbon;
use koolreport\dashboard\inputs\Button;
use koolreport\excel\ExcelExportable;
use Pulse\DataSource\WaylandOrderwiseDB;

class DownloadOutstandingLinesButton extends Button
{
	use ExcelExportable;

	public function onInit(): void
	{
		$this->text("Download")
			->type("primary")
			->onClick(function() {
				return WaylandOrderwiseDB::rawSQL("
				SELECT
				  vad_description,
				  oli_qty_tbsent,
				  oli_foreign_gross,
				  oli_foreign_vat,
				  oli_foreign_net,
				  os_description
				FROM 
					order_line_item
				    INNER JOIN order_header ON oli_oh_id = oh_id
				    INNER JOIN order_status ON oh_os_id = os_id
				    INNER JOIN variant_detail ON oli_vad_id = vad_id
				WHERE 
					oli_qty_tbsent > 0 
					AND oh_os_id IN(1, 4)
			")
			->run()
			->sort(['vad_description' => 'asc'])
			->exportToExcel()
			->toBrowser(sprintf("outstanding_orders_%s", Carbon::now('Europe/London')->format('Y-m-d')));
		});
	}
}

However I'm getting the following error:

Message: Call to undefined method koolreport\core\DataStore::exportToExcel()

I thought as I included the trait use ExcelExportable it would be fine?

Could someone point me in the direction of how I could do this please?

Wayland Games commented on Dec 10, 2025

Hi, it's been a week, has anyone been able to provide some help if this is achievable?

Sebastian Morales commented on Dec 12, 2025

Sorry for the late reply! Pls check our Dashboard demo's excel export at the following link and see if you can modify it for your situation:

KoolReport Dashboard excel export

If there is any issue with applying this example for your case let us know, we will find a solution for you.

Wayland Games commented on Dec 17, 2025

No worries, apologies for my late reply also!

That link was extremely helpful, thank you. I'm so close now, however it's just not downloading the table, I've inspected the HTML and I can see an event tied to it but nothing happens in the console log nor does any AJAX requests happen.

Here's the code for my dashboard now (apologies it's a lot):

<?php

namespace Pulse\Dashboard;

use koolreport\dashboard\Client;
use koolreport\dashboard\containers\Html;
use koolreport\dashboard\containers\Panel;
use koolreport\dashboard\containers\Row;
use koolreport\dashboard\Dashboard;
use koolreport\dashboard\inputs\Dropdown;
use Pulse\DateRangePicker\NetGrossTaxSalesDateInput;
use Pulse\SimpleCard\AmazonGrossSalesCard;
use Pulse\SimpleCard\AmazonNetSalesCard;
use Pulse\SimpleCard\AmazonTaxSalesCard;
use Pulse\SimpleCard\EbayGrossSalesCard;
use Pulse\SimpleCard\EbayNetSalesCard;
use Pulse\SimpleCard\EbayTaxSalesCard;
use Pulse\SimpleCard\OutstandingGrossSalesCard;
use Pulse\SimpleCard\OutstandingNetSalesCard;
use Pulse\SimpleCard\OutstandingTaxSalesCard;
use Pulse\SimpleCard\TradeEUGrossSalesCard;
use Pulse\SimpleCard\TradeEUNetSalesCard;
use Pulse\SimpleCard\TradeEUTaxSalesCard;
use Pulse\SimpleCard\TradeROWGrossSalesCard;
use Pulse\SimpleCard\TradeROWNetSalesCard;
use Pulse\SimpleCard\TradeROWTaxSalesCard;
use Pulse\SimpleCard\TradeUKGrossSalesCard;
use Pulse\SimpleCard\TradeUKNetSalesCard;
use Pulse\SimpleCard\TradeUKTaxSalesCard;
use Pulse\Table\OutstandingLinesTable;

class NetGrossTaxSalesKPIBoard extends Dashboard
{
	protected function widgets(): array
	{
		return [
			Row::create()->sub([
				NetGrossTaxSalesDateInput::create()->width(1/3),
			]),
			Row::create()->sub([
				Panel::create()->type('primary')->header("eBay Breakdown")->sub([
					Row::create()->sub([
						EbayGrossSalesCard::create()->width(1/3)->lazyLoading(true),
						EbayNetSalesCard::create()->width(1/3)->lazyLoading(true),
						EbayTaxSalesCard::create()->width(1/3)->lazyLoading(true),
					]),
				]),
			]),
			Row::create()->sub([
				Panel::create()->type('primary')->header("Amazon Breakdown")->sub([
					Row::create()->sub([
						AmazonGrossSalesCard::create()->width(1/3)->lazyLoading(true),
						AmazonNetSalesCard::create()->width(1/3)->lazyLoading(true),
						AmazonTaxSalesCard::create()->width(1/3)->lazyLoading(true),
					]),
				]),
			]),
			Row::create()->sub([
				Panel::create()->type('primary')->header("Outstanding Items Breakdown")->sub([
					Row::create()->sub([
						OutstandingGrossSalesCard::create()->width(1/3)->lazyLoading(true),
						OutstandingNetSalesCard::create()->width(1/3)->lazyLoading(true),
						OutstandingTaxSalesCard::create()->width(1/3)->lazyLoading(true),
					]),
					Html::div([
						Dropdown::create("exporting")
							->title("Export")
							->align("right")
							->items([
								Dropdown::menuItem()
									->text("Data to Excel")
									->icon("far fa-file-excel")
									->onClick(
										Client::widget(OutstandingLinesTable::CLASS_NAME)
											->exportToXLSX("Outstanding Lines")
									),
								Dropdown::menuItem()
									->text("Data to CSV")
									->icon("fa fa-file-csv")
									->onClick(
										Client::widget(OutstandingLinesTable::CLASS_NAME)
											->exportToCSV("Outstanding Lines")
									),
							]),
					])->class("text-right")->width(1/4),
					Row::create()->sub([
						Panel::create()->type('primary')->header("Outstanding Lines")->sub([
							OutstandingLinesTable::create()
								->lazyLoading(true)
								->xlsxExportable(true)
								->csvExportable(true),
						])
					]),
				]),
			]),
			Row::create()->sub([
				Panel::create()->type('primary')->header("UK Trade Breakdown")->sub([
					Row::create()->sub([
						TradeUKGrossSalesCard::create()->width(1/3)->lazyLoading(true),
						TradeUKNetSalesCard::create()->width(1/3)->lazyLoading(true),
						TradeUKTaxSalesCard::create()->width(1/3)->lazyLoading(true),
					]),
				]),
			]),
			Row::create()->sub([
				Panel::create()->type('primary')->header("EU Trade Breakdown")->sub([
					Row::create()->sub([
						TradeEUGrossSalesCard::create()->width(1/3)->lazyLoading(true),
						TradeEUNetSalesCard::create()->width(1/3)->lazyLoading(true),
						TradeEUTaxSalesCard::create()->width(1/3)->lazyLoading(true),
					]),
				]),
			]),
			Row::create()->sub([
				Panel::create()->type('primary')->header("ROW Trade Breakdown")->sub([
					Row::create()->sub([
						TradeROWGrossSalesCard::create()->width(1/3)->lazyLoading(true),
						TradeROWNetSalesCard::create()->width(1/3)->lazyLoading(true),
						TradeROWTaxSalesCard::create()->width(1/3)->lazyLoading(true),
					]),
				]),
			]),
		];
	}
}

And here's the table class specifically:

<?php

namespace Pulse\Table;

use koolreport\dashboard\fields\Currency;
use koolreport\dashboard\fields\Number;
use koolreport\dashboard\fields\Text;
use koolreport\dashboard\widgets\Table;
use Pulse\DataSource\WaylandOrderwiseDB;

class OutstandingLinesTable extends Table
{
	public const string CLASS_NAME = 'OutstandingLinesTable';

	protected function onInit(): void
	{
		$this->showFooter(true);
		$this->pageSize(10);
	}

	protected function dataSource()
	{
		return WaylandOrderwiseDB::rawSQL("
            SELECT
				vad_description AS [Name],
				vad_variant_code AS [SKU],
				oli_qty_tbsent AS [Qty To Be Sent],
				oli_foreign_gross AS [Gross Value],
				oli_foreign_vat AS [VAT Value],
				oli_foreign_net AS [Net Value],
				os_description AS [Order Status]
			FROM 
				order_line_item
			    INNER JOIN order_header ON oli_oh_id = oh_id
			    INNER JOIN order_status ON oh_os_id = os_id
			    INNER JOIN variant_detail ON oli_vad_id = vad_id
			WHERE 
				oli_qty_tbsent > 0 
				AND oh_os_id IN(1, 4)  
        ")->run()->sort(['Name' => 'asc']);
	}

	protected function fields(): array
	{
		return [
			Text::create("Name")->footerText("<b>Total</b>"),
			Text::create("SKU"),
			Number::create("Qty To Be Sent")->decimals(0)->footer("sum"),
			Currency::create("Gross Value")->GBP()->symbol()->decimals(2)->footer("sum"),
			Currency::create("Net Value")->GBP()->symbol()->decimals(2)->footer("sum"),
			Currency::create("VAT Value")->GBP()->symbol()->decimals(2)->footer("sum"),
			Text::create("Order Status"),
		];
	}
}
Wayland Games commented on Dec 17, 2025

Nevermind, I fixed it. I was missing

protected function export()
	{
		return ExportHandler::create()
			->storage(dirname(__DIR__) . "/storage/koolreport_exports")
			->engine(
				XLSXEngine::create('ExcelEngine'),
				CSVEngine::create('CsvEngine')
			);
	}

in my App.php class. I must've missed that in the docs somewhere!

Build Your Excellent Data Report

Let KoolReport help you to make great reports. It's free & open-source released under MIT license.

Download KoolReport View demo
solved

Excel