diff --git a/app/Http/Controllers/StatsController.php b/app/Http/Controllers/StatsController.php index d08fe75..1004e4d 100644 --- a/app/Http/Controllers/StatsController.php +++ b/app/Http/Controllers/StatsController.php @@ -4,10 +4,14 @@ namespace App\Http\Controllers; use App\Http\Requests\StatsByBrandRequest; use App\Http\Requests\StatsByQuestionRequest; +use App\Models\Brand; use App\Models\BrandStat; use App\Models\CustomerAnswer; use App\Models\Question; use Illuminate\Support\Carbon; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Schema; +use League\Csv\Writer; class StatsController extends Controller { @@ -22,6 +26,44 @@ class StatsController extends Controller return view('stats.view-stats-by-brands', \compact('stats')); } + public function exportByBrandCsv(StatsByBrandRequest $request) + { + $brand = Brand::findOrFail($request->brand); + $stats = BrandStat::with('brand')->whereDate('created_at', '>=', $request->start) + ->whereDate('created_at', '<=', $request->end) + ->whereBrandId($request->brand)->get(); + + $columns = collect(Schema::getColumnListing((new BrandStat())->getTable())) + ->filter(function ($value) { + return !in_array($value, ['created_at', 'brand_id']); + })->all(); + + $header = '"date";"marque";' . implode(';', $columns); + + $w = Writer::createFromString($header . PHP_EOL); + $w->setDelimiter(';'); + $w->setEnclosure('"'); + $w->setOutputBOM(Writer::BOM_UTF8); + + foreach ($stats as $stat) { + $cols = [ + $stat->created_at->format('Y-m-d'), + $stat->brand->name + ]; + foreach ($columns as $colname) { + $cols[] = $stat->{$colname}; + } + $w->insertOne($cols); + } + return response((string)$w, 200, [ + 'Content-Encoding' => 'none', + 'Content-Type' => 'text/csv; charset=UTF-8', + // phpcs:ignore Generic.Files.LineLength.TooLong + 'Content-Disposition' => "attachment; filename=\"Statistiques du $request->start au $request->end pour $brand->name.csv\"", + 'Content-Description' => 'File Transfer', + ]); + } + public function viewByQuestion(StatsByQuestionRequest $request) { $question = null; @@ -30,51 +72,92 @@ class StatsController extends Controller if ($request->post()) { $question = Question::findOrFail($request->question); $answers = $question->answers; + $start = Carbon::parse($request->start); + $end = Carbon::parse($request->end); - // Totalize by date all answers - $answersByDays = CustomerAnswer::whereDate('created_at', '>=', $request->start) - ->whereDate('created_at', '<=', $request->end) - ->whereIn('answer_id', $answers->pluck('id')) - ->get()->map(function ($custAnswer) { - return [ - 'answer_id' => $custAnswer->answer_id, - 'created_at' => $custAnswer->created_at->format('Y-m-d'), - ]; - })->groupBy(['created_at', 'answer_id'])->map(function ($day) { - return $day->map(function ($custAnswers) { - return $custAnswers->count(); - }); - }); - - $start = Carbon::parse($request->start); - $end = Carbon::parse($request->end); - - do { - $currentDate = $start->format('Y-m-d'); - /** @var \Illuminate\Support\Collection $answersByDays */ - if (!$answersByDays->has($currentDate)) { - $answersByDays->put( - $currentDate, - $answers->mapWithKeys(function ($answer) { - return [$answer->answer => 0]; - }) - ); - } else { - $curentAnswers = $answersByDays->pull($currentDate); - $answersByDays->put( - $currentDate, - $answers->mapWithKeys(function ($answer) use ($curentAnswers) { - return [$answer->answer => - $curentAnswers->has($answer->id) ? - $curentAnswers->get($answer->id) : 0]; - }) - ); - } - - $start = $start->addDay(); - } while ($start->lessThanOrEqualTo($end)); + $answersByDays = $this->answersByDays($answers, $start, $end); } return view('stats.view-stats-by-questions', \compact('question', 'answers', 'answersByDays')); } + + public function exportByQuestionCsv(StatsByQuestionRequest $request) + { + $question = Question::findOrFail($request->question); + $answers = $question->answers; + $start = Carbon::parse($request->start); + $end = Carbon::parse($request->end); + + $answersByDays = $this->answersByDays($answers, $start, $end); + + $header = '"date";' . implode(';', $answers->map(function ($answer) { + return "\"$answer->answer\""; + })->all()); + + $w = Writer::createFromString($header . PHP_EOL); + $w->setDelimiter(';'); + $w->setEnclosure('"'); + $w->setOutputBOM(Writer::BOM_UTF8); + + foreach ($answersByDays as $day => $dayAnswers) { + $w->insertOne(array_merge( + [ + $day + ], + $dayAnswers->values()->all() + )); + } + return response((string)$w, 200, [ + 'Content-Encoding' => 'none', + 'Content-Type' => 'text/csv; charset=UTF-8', + // phpcs:ignore Generic.Files.LineLength.TooLong + 'Content-Disposition' => "attachment; filename=\"Statistiques du $request->start au $request->end pour $question->question.csv\"", + 'Content-Description' => 'File Transfer', + ]); + } + + private function answersByDays(Collection $answers, Carbon $start, Carbon $end): Collection + { + // Totalize by date all answers + $answersByDays = CustomerAnswer::whereDate('created_at', '>=', $start) + ->whereDate('created_at', '<=', $end) + ->whereIn('answer_id', $answers->pluck('id')) + ->get()->map(function ($custAnswer) { + return [ + 'answer_id' => $custAnswer->answer_id, + 'created_at' => $custAnswer->created_at->format('Y-m-d'), + ]; + })->groupBy(['created_at', 'answer_id'])->map(function ($day) { + return $day->map(function ($custAnswers) { + return $custAnswers->count(); + }); + }); + + do { + $currentDate = $start->format('Y-m-d'); + /** @var \Illuminate\Support\Collection $answersByDays */ + if (!$answersByDays->has($currentDate)) { + $answersByDays->put( + $currentDate, + $answers->mapWithKeys(function ($answer) { + return [$answer->answer => 0]; + }) + ); + } else { + $curentAnswers = $answersByDays->pull($currentDate); + $answersByDays->put( + $currentDate, + $answers->mapWithKeys(function ($answer) use ($curentAnswers) { + return [$answer->answer => + $curentAnswers->has($answer->id) ? + $curentAnswers->get($answer->id) : 0]; + }) + ); + } + + $start = $start->addDay(); + } while ($start->lessThanOrEqualTo($end)); + + return $answersByDays; + } } diff --git a/resources/js/back.js b/resources/js/back.js index 7c36abb..12e5cde 100644 --- a/resources/js/back.js +++ b/resources/js/back.js @@ -3,3 +3,4 @@ require('./bootstrap'); require('./pages/customer.delete') require('./pages/service.index') require('./pages/single_optin.index') +require('./pages/statsExport') diff --git a/resources/js/pages/statsExport.js b/resources/js/pages/statsExport.js new file mode 100644 index 0000000..b4e2fe6 --- /dev/null +++ b/resources/js/pages/statsExport.js @@ -0,0 +1,9 @@ +const { default: axios } = require("axios") + +let statsCSV = document.getElementById('StatsCSV') + +if (statsCSV) { + statsCSV.addEventListener('click', () => { + window.location = statsCSV.dataset['request'] + }) +} diff --git a/resources/views/stats/view-stats-by-brands.blade.php b/resources/views/stats/view-stats-by-brands.blade.php index 3820272..4ed85d6 100644 --- a/resources/views/stats/view-stats-by-brands.blade.php +++ b/resources/views/stats/view-stats-by-brands.blade.php @@ -38,6 +38,17 @@ {{ __('Visualiser') }} + @if($stats) +