Server side export report

Add PDF and Excel export for report
Change generation of CSV to laravel-excel
Remove dompdf to use mpdf instand
This commit is contained in:
Gilbert Paquin 2017-08-01 00:44:12 -04:00
parent 0997f94cbc
commit 8ace6ad1ea
7 changed files with 383 additions and 543 deletions

View File

@ -8,6 +8,7 @@ use Input;
use Str; use Str;
use Utils; use Utils;
use View; use View;
use Excel;
/** /**
* Class ReportController. * Class ReportController.
@ -53,6 +54,7 @@ class ReportController extends BaseController
} }
$action = Input::get('action'); $action = Input::get('action');
$format = Input::get('format');
if (Input::get('report_type')) { if (Input::get('report_type')) {
$reportType = Input::get('report_type'); $reportType = Input::get('report_type');
@ -104,7 +106,7 @@ class ReportController extends BaseController
$params['report'] = $report; $params['report'] = $report;
$params = array_merge($params, $report->results()); $params = array_merge($params, $report->results());
if ($isExport) { if ($isExport) {
return self::export($reportType, $params['displayData'], $params['columns'], $params['reportTotals']); return self::export($format, $reportType, $params);
} }
} else { } else {
$params['columns'] = []; $params['columns'] = [];
@ -117,56 +119,81 @@ class ReportController extends BaseController
} }
/** /**
* @param $format
* @param $reportType * @param $reportType
* @param $data * @param $params
* @param $columns * @todo: Add summary to export
* @param $totals
*/ */
private function export($reportType, $data, $columns, $totals) private function export($format, $reportType, $params)
{ {
if (! Auth::user()->hasPermission('view_all')) { if (! Auth::user()->hasPermission('view_all')) {
exit; exit;
} }
$date = date('Y-m-d'); $format = strtolower($format);
$data = $params['displayData'];
$columns = $params['columns'];
$totals = $params['reportTotals'];
$report = $params['report'];
$callback = function() use ($data, $columns) { $filename = "{$params['startDate']}-{$params['endDate']}_invoiceninja-".strtolower(trans("texts.$reportType"))."-report";
$output = fopen('php://output', 'w') or Utils::fatalError();
$columns = array_map(function($key, $val) {
return is_array($val) ? $key : $val;
}, array_keys($columns), $columns);
Utils::exportData($output, $data, Utils::trans($columns)); $formats = ['csv', 'pdf', 'xlsx'];
}; if(!in_array($format, $formats)) {
throw new \Exception("Invalid format request to export report");
/*
fwrite($output, trans('texts.totals'));
foreach ($totals as $currencyId => $fields) {
foreach ($fields as $key => $value) {
fwrite($output, ',' . trans("texts.{$key}"));
}
fwrite($output, "\n");
break;
} }
foreach ($totals as $currencyId => $fields) { //Get labeled header
$csv = Utils::getFromCache($currencyId, 'currencies')->name . ','; $report->tableHeaderArray();
foreach ($fields as $key => $value) {
$csv .= '"' . Utils::formatMoney($value, $currencyId).'",'; /*$summary = [];
} if(count(array_values($totals))) {
fwrite($output, $csv."\n"); $summary[] = array_merge([
trans("texts.totals")
], array_map(function ($key) {return trans("texts.{$key}");}, array_keys(array_values(array_values($totals)[0])[0])));
} }
*/
$headers = [ foreach ($totals as $currencyId => $each) {
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', foreach ($each as $dimension => $val) {
'Content-type' => 'text/csv', $tmp = [];
'Content-Disposition' => "attachment; filename={$date}-invoiceninja-{$reportType}-report.csv", $tmp[] = Utils::getFromCache($currencyId, 'currencies')->name . (($dimension) ? ' - ' . $dimension : '');
'Expires' => '0',
'Pragma' => 'public'
];
return response()->stream($callback, 200, $headers); foreach ($val as $id => $field) $tmp[] = Utils::formatMoney($field, $currencyId);
$summary[] = $tmp;
}
}
dd($summary);*/
return Excel::create($filename, function($excel) use($report, $data, $reportType, $format) {
$excel->sheet(trans("texts.$reportType"), function($sheet) use($report, $data, $format) {
$sheet->setOrientation('landscape');
$sheet->freezeFirstRow();
//Add border on PDF
if($format == 'pdf')
$sheet->setAllBorders('thin');
$sheet->rows(array_merge(
[array_map(function($col) {return $col['label'];}, $report->columns_labeled)],
$data
));
//Styling header
$sheet->cells('A1:'.Utils::num2alpha(count($report->columns_labeled)-1).'1', function($cells) {
$cells->setBackground('#777777');
$cells->setFontColor('#FFFFFF');
$cells->setFontSize(14);
$cells->setFontFamily('Calibri');
$cells->setFontWeight('bold');
});
$sheet->setAutoSize(true);
});
})->export($format);
} }
} }

View File

@ -1241,4 +1241,12 @@ class Utils
fclose($handle); fclose($handle);
return( ord($contents[28]) != 0 ); return( ord($contents[28]) != 0 );
} }
//Source: https://stackoverflow.com/questions/3302857/algorithm-to-get-the-excel-like-column-name-of-a-number
public static function num2alpha($n)
{
for($r = ""; $n >= 0; $n = intval($n / 26) - 1)
$r = chr($n%26 + 0x41) . $r;
return $r;
}
} }

View File

@ -40,7 +40,6 @@
"digitickets/omnipay-realex": "~5.0", "digitickets/omnipay-realex": "~5.0",
"dioscouri/omnipay-cybersource": "dev-master", "dioscouri/omnipay-cybersource": "dev-master",
"doctrine/dbal": "2.5.x", "doctrine/dbal": "2.5.x",
"dompdf/dompdf": "^0.8.0",
"ezyang/htmlpurifier": "~v4.7", "ezyang/htmlpurifier": "~v4.7",
"fotografde/omnipay-checkoutcom": "~2.0", "fotografde/omnipay-checkoutcom": "~2.0",
"fruitcakestudio/omnipay-sisow": "~2.0", "fruitcakestudio/omnipay-sisow": "~2.0",
@ -67,6 +66,7 @@
"meebio/omnipay-creditcall": "dev-master", "meebio/omnipay-creditcall": "dev-master",
"meebio/omnipay-secure-trading": "dev-master", "meebio/omnipay-secure-trading": "dev-master",
"mfauveau/omnipay-pacnet": "~2.0", "mfauveau/omnipay-pacnet": "~2.0",
"mpdf/mpdf": "^6.1",
"nwidart/laravel-modules": "^1.14", "nwidart/laravel-modules": "^1.14",
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248", "omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
"omnipay/bitpay": "dev-master", "omnipay/bitpay": "dev-master",

650
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,21 @@
<?php <?php
//https://github.com/PHPOffice/PHPExcel/issues/556#issuecomment-216722159
switch (PHP_OS) {
case 'WINNT':
PHPExcel_Shared_Font::setTrueTypeFontPath('C:/Windows/Fonts/');
PHPExcel_Shared_Font::setAutoSizeMethod(PHPExcel_Shared_Font::AUTOSIZE_METHOD_EXACT);
break;
case 'Darwin':
PHPExcel_Shared_Font::setTrueTypeFontPath('/Library/Fonts/');
PHPExcel_Shared_Font::setAutoSizeMethod(PHPExcel_Shared_Font::AUTOSIZE_METHOD_EXACT);
break;
case 'Linux':
PHPExcel_Shared_Font::setTrueTypeFontPath('/usr/share/fonts/truetype/');
PHPExcel_Shared_Font::setAutoSizeMethod(PHPExcel_Shared_Font::AUTOSIZE_METHOD_EXACT);
break;
}
return array( return array(
@ -171,7 +188,7 @@ return array(
| having the appropriate fonts installed. | having the appropriate fonts installed.
| |
*/ */
'autosize-method' => PHPExcel_Shared_Font::AUTOSIZE_METHOD_APPROX, 'autosize-method' => PHPExcel_Shared_Font::AUTOSIZE_METHOD_EXACT,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -291,7 +308,7 @@ return array(
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Supported: DomPDF, tcPDF, mPDF | Supported: DomPDF, tcPDF, mPDF
*/ */
'driver' => 'DomPDF', 'driver' => 'mPDF',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -2392,7 +2392,7 @@ $LANG = array(
'tax1' => 'First Tax', 'tax1' => 'First Tax',
'tax2' => 'Second Tax', 'tax2' => 'Second Tax',
'fee_help' => 'Gateway fees are the costs charged for access to the financial networks that handle the processing of online payments.', 'fee_help' => 'Gateway fees are the costs charged for access to the financial networks that handle the processing of online payments.',
'download_pdf' => 'Download PDF' 'format_export' => 'Exporting format'
); );

View File

@ -16,11 +16,6 @@
} }
</style> </style>
@foreach ($account->getFontFolders() as $font)
<script src="{{ asset('js/vfs_fonts/'.$font.'.js') }}" type="text/javascript"></script>
@endforeach
<script src="{{ asset('pdf.built.js') }}?no_cache={{ NINJA_VERSION }}" type="text/javascript"></script>
@stop @stop
@section('content') @section('content')
@ -38,7 +33,6 @@
var chartStartDate = moment("{{ $startDate }}"); var chartStartDate = moment("{{ $startDate }}");
var chartEndDate = moment("{{ $endDate }}"); var chartEndDate = moment("{{ $endDate }}");
var dateRanges = {!! $account->present()->dateRangeOptions !!}; var dateRanges = {!! $account->present()->dateRangeOptions !!};
window.invoiceFonts = {!! json_encode(Cache::get('fonts')) !!};
$(function () { $(function () {
@ -164,12 +158,9 @@
<center> <center>
@if(request()->report_type) {!! Former::select('format')
{!! Button::warning(trans('texts.download_pdf')) ->label(trans('texts.format_export'))
->withAttributes(array('onclick' => 'exportPDF()')) ->options(['csv' => 'CSV', 'pdf' => 'PDF', 'xlsx' => 'Excel']) !!}
->appendIcon(Icon::create('save'))
->large() !!}
@endif
{!! Button::primary(trans('texts.export')) {!! Button::primary(trans('texts.export'))
->withAttributes(array('onclick' => 'onExportClick()')) ->withAttributes(array('onclick' => 'onExportClick()'))
->appendIcon(Icon::create('export')) ->appendIcon(Icon::create('export'))
@ -364,131 +355,6 @@
} }
}); });
}) })
<?php
$summary = [];
if(count(array_values($reportTotals))) {
$summary[] = array_merge([
trans("texts.totals")
], array_map(function ($key) {
return ['text' => trans("texts.{$key}"),
'style' => 'tableHeader'
];
}, array_keys(array_values(array_values($reportTotals)[0])[0])));
}
foreach ($reportTotals as $currencyId => $each) {
foreach ($each as $dimension => $val) {
$tmp = [];
$tmp[] = Utils::getFromCache($currencyId, 'currencies')->name . (($dimension) ? ' - ' . $dimension : '');
foreach ($val as $id => $field) $tmp[] = Utils::formatMoney($field, $currencyId);
$summary[] = $tmp;
}
}
?>
function addFont(font){
if(window.ninjaFontVfs[font.folder]){
folder = 'fonts/'+font.folder;
pdfMake.fonts[font.name] = {
normal: folder+'/'+font.normal,
italics: folder+'/'+font.italics,
bold: folder+'/'+font.bold,
bolditalics: folder+'/'+font.bolditalics
}
}
}
pdfMake.fonts = {}
fonts = window.invoiceFonts || invoice.invoice_fonts;
// Add only the loaded fonts
$.each(fonts, function(i,font){
addFont(font);
});
var dd = {!! html_entity_decode(json_encode( [
'pageOrientation' => 'landscape',
'content' => [
[
'text' => $reportTypes[$reportType],
'style' => 'header'
],
[
'style' => 'reportTable',
'table' => [
'headerRows' => 1,
'widths' => '*',
'body' => $summary
],
'layout' => 'lightHorizontalLines'
],
[
'style' => 'reportTable',
'table' => [
'headerRows' => 1,
'widths' => '*',
'body' =>
array_merge(
[array_map(function($array) {
return [
'text' => $array['label'],
'style' => 'tableHeader'
];
}, $report->columns_labeled)]
, array_map(function($row) {
return array_map(function($col) {
if(strpos($col, "<a href") !== FALSE) {
$hrefs = [];
preg_match('#<a.*href=[\'"](.*)["\'].*>(.*)<.*#', $col, $hrefs);
return [
'text' => $hrefs[2],
'link' => $hrefs[1]
];
}
return $col;
}, $row);
}, $displayData))
],
'layout' => 'lightHorizontalLines'
]
],
'styles' => [
'header' => [
'fontSize' => 18,
'bold' => true,
'margin' => [
0,
0,
0,
10
]
],
'reportTable' => [
'margin' => [
0,
5,
0,
50
]
],
'tableHeader' => [
'bold' => true,
'fontSize' => 13,
'color' => 'black'
]
],
'defaultStyle' => [
'font' => Cache::get('fonts')[0]['name']
]
] , JSON_PRETTY_PRINT)) !!}
function exportPDF() {
pdfMake.createPdf(dd).download($('#reportrange').data('daterangepicker').startDate.format('YYYY-MM-DD') + '-' + $('#reportrange').data('daterangepicker').endDate.format('YYYY-MM-DD')+'_'+'{{'-invoiceninja-'.$reportTypes[$reportType].'-report'}}');
}
</script> </script>
@stop @stop