Здесь у вас есть наш код.
Уведомление
ob_clean перед загрузкой
Это сложный вопрос.Если у вас есть некоторый контент в выходном буфере (возможно, для неверного включаемого файла), он отправляется вместе с файлом.Таким образом, вы должны очистить его перед любой командой загрузки
Добавлен заголовок спецификации в CSV-файл
И, если вы планируете открыть файл в Excel, и файл UTF8, вы должныдобавить заголовок спецификации
public function reportAsset($budgetPeriod_id)
{
$timeProcess = round(microtime(true) / 1000);
if ($budgetPeriod_id) {
$budget = \App\Models\Invoicing\BudgetPeriod::select(['description'])->find((int) $budgetPeriod_id);
$client = \App\Models\Structure\Client::select(['description'])->find($this->client_id);
$filename = date('Ymd').'_'.$budget->description . '_' . $client->description . '.csv';
$headers = [
'Content-type' => 'text/csv;charset=UTF-8',
'Content-Disposition' => 'attachment; filename=' . $filename,
'Pragma' => 'no-cache',
'Expires' => '0',
];
$output = fopen($filename, "w");
// JMA: Add BOM header
fputs($output, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
fputcsv($output, [_i('Asset_id'), _i('Asset'), _i('Client Category'), _i('Budget'), _i('Spent'), _i('Available'),_i('Spent') .' %', _i('# Invoices')], ';');
$query = \App\Models\Invoicing\AssetBudget::query();
$query->has('asset')
->has('clientCategory')
->with('asset:PROCESS_ID,Identificador_Processo', 'clientCategory:id,description')
->orderBy('asset_id', 'clientCategory_id', 'clientCategory.id')
->selectRaw('amount as total, asset_id, budgetPeriod_id, clientCategory_id')
->where('budgetPeriod_id', $budgetPeriod_id)
->chunk($this::BUDGET_CHUNK, function ($chunk_query) use ($budgetPeriod_id, $output, $timeProcess) {
foreach ((array) $chunk_query as $report) {
foreach ($report as $rep) {
$row = [];
// JMA: The amount has to be the individual amount per asset
// So. we read asset_invoices where the invoice is in the budget period and category
// TODO: Replace this piece of code with consumedBudgetByRequest function in Invoicing BudgetController
// TODO: Try with calculateBudget but is not the same structure
//$invoices = \App\Library\Invoicing\BudgetCalculator::calculateBudget($rep->budgetPeriod_id, $rep->clientCategory_id, (array)$rep->asset_id);
$invoices=AssetInvoice::whereHas('invoice' , function ($invoice) use ($rep) {
$invoice->where('budgetPeriod_id',$rep->budgetPeriod_id)
->where('clientCategory_id',$rep->clientCategory_id);
}
)
->selectRaw('count(asset_id) as nInvoices, sum(amount) as spent')
->where('asset_id',$rep->asset_id)
->first();
// Log::debug('BudgetController->reportAsset: Invoices found='.$invoices->nInvoices.' spent='.$invoices->spent);
$row['asset_id'] = $rep->asset->PROCESS_ID;
$row['Identificador_Processo'] = $rep->asset->Identificador_Processo;
$row['clientCategory'] = $rep->clientCategory->description;
$row["budget"] = floatval($rep->total);
$row["spent"] = floatval($invoices->spent);
$row["available"] = $row["budget"] - $row["spent"];
if(floatval($rep->total)==0 ){
$row["percentaje"] = '';
}else{
$row["percentaje"] = number_format((float)(floatval($invoices->spent)*100)/ floatval($rep->total), 2, '.', '');
}
$row["nInvoices"] = floatval($invoices->nInvoices);
// Uncomment this line to monitor time consumption
// $row["times"] = $timeProcess - round(microtime(true) / 1000);
fputcsv($output, $row, ';');
}
}
});
fclose($output);
// CHECK THIS: Clean output buffer before sending files (avoid initial whitespaces)
if (ob_get_contents()) {
ob_clean();
}
// Send csv file as response
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
}