1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-20 00:11:35 +02:00

Merge pull request #1597 from dansleboby/develop

#1226 Add PDF and Excel export on report
This commit is contained in:
Hillel Coren 2017-08-02 18:18:21 +03:00 committed by GitHub
commit 52493d8ee9
8 changed files with 451 additions and 411 deletions

View File

@ -8,6 +8,7 @@ use Input;
use Str;
use Utils;
use View;
use Excel;
/**
* Class ReportController.
@ -53,6 +54,7 @@ class ReportController extends BaseController
}
$action = Input::get('action');
$format = Input::get('format');
if (Input::get('report_type')) {
$reportType = Input::get('report_type');
@ -104,7 +106,7 @@ class ReportController extends BaseController
$params['report'] = $report;
$params = array_merge($params, $report->results());
if ($isExport) {
return self::export($reportType, $params['displayData'], $params['columns'], $params['reportTotals']);
return self::export($format, $reportType, $params);
}
} else {
$params['columns'] = [];
@ -117,56 +119,80 @@ class ReportController extends BaseController
}
/**
* @param $format
* @param $reportType
* @param $data
* @param $columns
* @param $totals
* @param $params
* @todo: Add summary to export
*/
private function export($reportType, $data, $columns, $totals)
{
private function export($format, $reportType, $params)
{
if (! Auth::user()->hasPermission('view_all')) {
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) {
$output = fopen('php://output', 'w') or Utils::fatalError();
$filename = "{$params['startDate']}-{$params['endDate']}_invoiceninja-".strtolower(Utils::normalizeChars(trans("texts.$reportType")))."-report";
$columns = array_map(function($key, $val) {
return is_array($val) ? $key : $val;
}, array_keys($columns), $columns);
Utils::exportData($output, $data, Utils::trans($columns));
};
/*
fwrite($output, trans('texts.totals'));
foreach ($totals as $currencyId => $fields) {
foreach ($fields as $key => $value) {
fwrite($output, ',' . trans("texts.{$key}"));
}
fwrite($output, "\n");
break;
$formats = ['csv', 'pdf', 'xlsx'];
if(!in_array($format, $formats)) {
throw new \Exception("Invalid format request to export report");
}
foreach ($totals as $currencyId => $fields) {
$csv = Utils::getFromCache($currencyId, 'currencies')->name . ',';
foreach ($fields as $key => $value) {
$csv .= '"' . Utils::formatMoney($value, $currencyId).'",';
}
fwrite($output, $csv."\n");
//Get labeled header
$columns_labeled = $report->tableHeaderArray();
/*$summary = [];
if(count(array_values($totals))) {
$summary[] = array_merge([
trans("texts.totals")
], array_map(function ($key) {return trans("texts.{$key}");}, array_keys(array_values(array_values($totals)[0])[0])));
}
*/
$headers = [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-type' => 'text/csv',
'Content-Disposition' => "attachment; filename={$date}-invoiceninja-{$reportType}-report.csv",
'Expires' => '0',
'Pragma' => 'public'
];
foreach ($totals as $currencyId => $each) {
foreach ($each as $dimension => $val) {
$tmp = [];
$tmp[] = Utils::getFromCache($currencyId, 'currencies')->name . (($dimension) ? ' - ' . $dimension : '');
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, $columns_labeled) {
$excel->sheet(trans("texts.$reportType"), function($sheet) use($report, $data, $format, $columns_labeled) {
$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'];}, $columns_labeled)],
$data
));
//Styling header
$sheet->cells('A1:'.Utils::num2alpha(count($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,64 @@ class Utils
fclose($handle);
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;
}
/**
* Replace language-specific characters by ASCII-equivalents.
* @param string $s
* @return string
* Source: https://stackoverflow.com/questions/3371697/replacing-accented-characters-php/16427125#16427125
*/
public static function normalizeChars($s) {
$replace = array(
'ъ'=>'-', 'Ь'=>'-', 'Ъ'=>'-', 'ь'=>'-',
'Ă'=>'A', 'Ą'=>'A', 'À'=>'A', 'Ã'=>'A', 'Á'=>'A', 'Æ'=>'A', 'Â'=>'A', 'Å'=>'A', 'Ä'=>'Ae',
'Þ'=>'B',
'Ć'=>'C', 'ץ'=>'C', 'Ç'=>'C',
'È'=>'E', 'Ę'=>'E', 'É'=>'E', 'Ë'=>'E', 'Ê'=>'E',
'Ğ'=>'G',
'İ'=>'I', 'Ï'=>'I', 'Î'=>'I', 'Í'=>'I', 'Ì'=>'I',
'Ł'=>'L',
'Ñ'=>'N', 'Ń'=>'N',
'Ø'=>'O', 'Ó'=>'O', 'Ò'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'Oe',
'Ş'=>'S', 'Ś'=>'S', 'Ș'=>'S', 'Š'=>'S',
'Ț'=>'T',
'Ù'=>'U', 'Û'=>'U', 'Ú'=>'U', 'Ü'=>'Ue',
'Ý'=>'Y',
'Ź'=>'Z', 'Ž'=>'Z', 'Ż'=>'Z',
'â'=>'a', 'ǎ'=>'a', 'ą'=>'a', 'á'=>'a', 'ă'=>'a', 'ã'=>'a', 'Ǎ'=>'a', 'а'=>'a', 'А'=>'a', 'å'=>'a', 'à'=>'a', 'א'=>'a', 'Ǻ'=>'a', 'Ā'=>'a', 'ǻ'=>'a', 'ā'=>'a', 'ä'=>'ae', 'æ'=>'ae', 'Ǽ'=>'ae', 'ǽ'=>'ae',
'б'=>'b', 'ב'=>'b', 'Б'=>'b', 'þ'=>'b',
'ĉ'=>'c', 'Ĉ'=>'c', 'Ċ'=>'c', 'ć'=>'c', 'ç'=>'c', 'ц'=>'c', 'צ'=>'c', 'ċ'=>'c', 'Ц'=>'c', 'Č'=>'c', 'č'=>'c', 'Ч'=>'ch', 'ч'=>'ch',
'ד'=>'d', 'ď'=>'d', 'Đ'=>'d', 'Ď'=>'d', 'đ'=>'d', 'д'=>'d', 'Д'=>'D', 'ð'=>'d',
'є'=>'e', 'ע'=>'e', 'е'=>'e', 'Е'=>'e', 'Ə'=>'e', 'ę'=>'e', 'ĕ'=>'e', 'ē'=>'e', 'Ē'=>'e', 'Ė'=>'e', 'ė'=>'e', 'ě'=>'e', 'Ě'=>'e', 'Є'=>'e', 'Ĕ'=>'e', 'ê'=>'e', 'ə'=>'e', 'è'=>'e', 'ë'=>'e', 'é'=>'e',
'ф'=>'f', 'ƒ'=>'f', 'Ф'=>'f',
'ġ'=>'g', 'Ģ'=>'g', 'Ġ'=>'g', 'Ĝ'=>'g', 'Г'=>'g', 'г'=>'g', 'ĝ'=>'g', 'ğ'=>'g', 'ג'=>'g', 'Ґ'=>'g', 'ґ'=>'g', 'ģ'=>'g',
'ח'=>'h', 'ħ'=>'h', 'Х'=>'h', 'Ħ'=>'h', 'Ĥ'=>'h', 'ĥ'=>'h', 'х'=>'h', 'ה'=>'h',
'î'=>'i', 'ï'=>'i', 'í'=>'i', 'ì'=>'i', 'į'=>'i', 'ĭ'=>'i', 'ı'=>'i', 'Ĭ'=>'i', 'И'=>'i', 'ĩ'=>'i', 'ǐ'=>'i', 'Ĩ'=>'i', 'Ǐ'=>'i', 'и'=>'i', 'Į'=>'i', 'י'=>'i', 'Ї'=>'i', 'Ī'=>'i', 'І'=>'i', 'ї'=>'i', 'і'=>'i', 'ī'=>'i', 'ij'=>'ij', 'IJ'=>'ij',
'й'=>'j', 'Й'=>'j', 'Ĵ'=>'j', 'ĵ'=>'j', 'я'=>'ja', 'Я'=>'ja', 'Э'=>'je', 'э'=>'je', 'ё'=>'jo', 'Ё'=>'jo', 'ю'=>'ju', 'Ю'=>'ju',
'ĸ'=>'k', 'כ'=>'k', 'Ķ'=>'k', 'К'=>'k', 'к'=>'k', 'ķ'=>'k', 'ך'=>'k',
'Ŀ'=>'l', 'ŀ'=>'l', 'Л'=>'l', 'ł'=>'l', 'ļ'=>'l', 'ĺ'=>'l', 'Ĺ'=>'l', 'Ļ'=>'l', 'л'=>'l', 'Ľ'=>'l', 'ľ'=>'l', 'ל'=>'l',
'מ'=>'m', 'М'=>'m', 'ם'=>'m', 'м'=>'m',
'ñ'=>'n', 'н'=>'n', 'Ņ'=>'n', 'ן'=>'n', 'ŋ'=>'n', 'נ'=>'n', 'Н'=>'n', 'ń'=>'n', 'Ŋ'=>'n', 'ņ'=>'n', 'ʼn'=>'n', 'Ň'=>'n', 'ň'=>'n',
'о'=>'o', 'О'=>'o', 'ő'=>'o', 'õ'=>'o', 'ô'=>'o', 'Ő'=>'o', 'ŏ'=>'o', 'Ŏ'=>'o', 'Ō'=>'o', 'ō'=>'o', 'ø'=>'o', 'ǿ'=>'o', 'ǒ'=>'o', 'ò'=>'o', 'Ǿ'=>'o', 'Ǒ'=>'o', 'ơ'=>'o', 'ó'=>'o', 'Ơ'=>'o', 'œ'=>'oe', 'Œ'=>'oe', 'ö'=>'oe',
'פ'=>'p', 'ף'=>'p', 'п'=>'p', 'П'=>'p',
'ק'=>'q',
'ŕ'=>'r', 'ř'=>'r', 'Ř'=>'r', 'ŗ'=>'r', 'Ŗ'=>'r', 'ר'=>'r', 'Ŕ'=>'r', 'Р'=>'r', 'р'=>'r',
'ș'=>'s', 'с'=>'s', 'Ŝ'=>'s', 'š'=>'s', 'ś'=>'s', 'ס'=>'s', 'ş'=>'s', 'С'=>'s', 'ŝ'=>'s', 'Щ'=>'sch', 'щ'=>'sch', 'ш'=>'sh', 'Ш'=>'sh', 'ß'=>'ss',
'т'=>'t', 'ט'=>'t', 'ŧ'=>'t', 'ת'=>'t', 'ť'=>'t', 'ţ'=>'t', 'Ţ'=>'t', 'Т'=>'t', 'ț'=>'t', 'Ŧ'=>'t', 'Ť'=>'t', '™'=>'tm',
'ū'=>'u', 'у'=>'u', 'Ũ'=>'u', 'ũ'=>'u', 'Ư'=>'u', 'ư'=>'u', 'Ū'=>'u', 'Ǔ'=>'u', 'ų'=>'u', 'Ų'=>'u', 'ŭ'=>'u', 'Ŭ'=>'u', 'Ů'=>'u', 'ů'=>'u', 'ű'=>'u', 'Ű'=>'u', 'Ǖ'=>'u', 'ǔ'=>'u', 'Ǜ'=>'u', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'У'=>'u', 'ǚ'=>'u', 'ǜ'=>'u', 'Ǚ'=>'u', 'Ǘ'=>'u', 'ǖ'=>'u', 'ǘ'=>'u', 'ü'=>'ue',
'в'=>'v', 'ו'=>'v', 'В'=>'v',
'ש'=>'w', 'ŵ'=>'w', 'Ŵ'=>'w',
'ы'=>'y', 'ŷ'=>'y', 'ý'=>'y', 'ÿ'=>'y', 'Ÿ'=>'y', 'Ŷ'=>'y',
'Ы'=>'y', 'ž'=>'z', 'З'=>'z', 'з'=>'z', 'ź'=>'z', 'ז'=>'z', 'ż'=>'z', 'ſ'=>'z', 'Ж'=>'zh', 'ж'=>'zh'
);
return strtr($s, $replace);
}
}

View File

@ -52,9 +52,8 @@ class AbstractReport
$this->totals[$currencyId][$dimension][$field] += $value;
}
public function tableHeader()
{
$str = '';
public function tableHeaderArray() {
$columns_labeled = [];
foreach ($this->columns as $key => $val) {
if (is_array($val)) {
@ -75,9 +74,21 @@ class AbstractReport
$class = count($class) ? implode(' ', $class) : 'group-false';
$label = trans("texts.{$field}");
$str .= "<th class=\"{$class}\">{$label}</th>";
$columns_labeled[] = ['label' => $label, 'class' => $class, 'key' => $field];
}
return $columns_labeled;
}
public function tableHeader()
{
$columns_labeled = $this->tableHeaderArray();
$str = '';
foreach ($columns_labeled as $field => $attr)
$str .= "<th class=\"{$attr['class']}\">{$attr['label']}</th>";
return $str;
}

View File

@ -40,7 +40,6 @@
"digitickets/omnipay-realex": "~5.0",
"dioscouri/omnipay-cybersource": "dev-master",
"doctrine/dbal": "2.5.x",
"dompdf/dompdf": "^0.8.0",
"ezyang/htmlpurifier": "~v4.7",
"fotografde/omnipay-checkoutcom": "~2.0",
"fruitcakestudio/omnipay-sisow": "~2.0",
@ -67,6 +66,7 @@
"meebio/omnipay-creditcall": "dev-master",
"meebio/omnipay-secure-trading": "dev-master",
"mfauveau/omnipay-pacnet": "~2.0",
"mpdf/mpdf": "^6.1",
"nwidart/laravel-modules": "^1.14",
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
"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
//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(
@ -171,7 +188,7 @@ return array(
| having the appropriate fonts installed.
|
*/
'autosize-method' => PHPExcel_Shared_Font::AUTOSIZE_METHOD_APPROX,
'autosize-method' => constant('\PHPExcel_Shared_Font::AUTOSIZE_METHOD_'.env('EXCEL_AUTOSIZE_MODE')),
/*
|--------------------------------------------------------------------------
@ -291,7 +308,7 @@ return array(
|--------------------------------------------------------------------------
| Supported: DomPDF, tcPDF, mPDF
*/
'driver' => 'DomPDF',
'driver' => 'mPDF',
/*
|--------------------------------------------------------------------------

View File

@ -2392,6 +2392,7 @@ $LANG = array(
'tax1' => 'First 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.',
'format_export' => 'Exporting format'
);

View File

@ -157,6 +157,9 @@
<center>
{!! Former::select('format')
->label(trans('texts.format_export'))
->options(['csv' => 'CSV', 'pdf' => 'PDF', 'xlsx' => 'Excel']) !!}
{!! Button::primary(trans('texts.export'))
->withAttributes(array('onclick' => 'onExportClick()'))
->appendIcon(Icon::create('export'))
@ -365,4 +368,4 @@
keyboardNavigation: false
});
@stop
@stop