feat: remove export mail and replaced with .csv and .pdf downloads
This commit is contained in:
parent
8fbaa234b4
commit
b7b4013897
19 changed files with 585 additions and 275 deletions
39
app/Enums/Claims/ClaimExportFormat.php
Normal file
39
app/Enums/Claims/ClaimExportFormat.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Claims;
|
||||
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
enum ClaimExportFormat: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case csv = 1;
|
||||
case pdf = 2;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::csv->name => 'CSV',
|
||||
self::pdf->name => 'PDF',
|
||||
];
|
||||
|
||||
public function class()
|
||||
{
|
||||
return match ($this) {
|
||||
self::csv => 'success',
|
||||
self::pdf => 'danger',
|
||||
default => 'primary',
|
||||
};
|
||||
}
|
||||
|
||||
public function picto()
|
||||
{
|
||||
return match ($this) {
|
||||
self::csv => 'fa-solid fa-file-csv',
|
||||
self::pdf => 'fa-solid fa-file-pdf',
|
||||
default => 'fa-solid fa-file',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Claims\ClaimExportFormat;
|
||||
use App\Enums\Claims\ClaimResponseType;
|
||||
use App\Enums\Claims\ClaimStatus;
|
||||
use App\Enums\Users\RoleEnum;
|
||||
|
|
@ -11,7 +12,6 @@ use App\Http\Requests\Bo\Claims\ExportClaimRequest;
|
|||
use App\Http\Requests\Bo\Claims\SendClaimAnswerRequest;
|
||||
use App\Http\Requests\Bo\Claims\UpdateClaimRequest;
|
||||
use App\Http\Requests\Bo\PaginateModelsRequest;
|
||||
use App\Jobs\ExportClaimsAsCsv;
|
||||
use App\Mail\ClaimAnswerMail;
|
||||
use App\Models\Brand;
|
||||
use App\Models\Claim;
|
||||
|
|
@ -20,9 +20,12 @@ use App\Models\ClaimMessage;
|
|||
use App\Models\ClaimSubject;
|
||||
use App\Models\CustomerInfo;
|
||||
use App\Traits\Controllers\UpdateModelPublished;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
||||
|
||||
class ClaimController extends Controller
|
||||
|
|
@ -67,8 +70,6 @@ class ClaimController extends Controller
|
|||
fn($q) => $q->whereNotIn('status', [ClaimStatus::treated, ClaimStatus::refused])
|
||||
);
|
||||
|
||||
// dd($query->toRawSql());
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
if ($search) {
|
||||
|
|
@ -95,7 +96,13 @@ class ClaimController extends Controller
|
|||
/** Custom pagination */
|
||||
$claimModels = $query->simplePaginate($this->getPagination());
|
||||
|
||||
$claimSubjectModels = ClaimSubject::all();
|
||||
$claimSubjectModels = ClaimSubject::query()
|
||||
->when(
|
||||
$request->filled('brand'),
|
||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand)),
|
||||
fn($q) => $q->whereHas('brand', fn($q) => $q->whereIn('id', $userModel->brands()->pluck('id')))
|
||||
)
|
||||
->get();
|
||||
|
||||
return view('bo.pages.claims.index', compact('claimModels', 'search', 'searchFields', 'claimSubjectModels'));
|
||||
}
|
||||
|
|
@ -220,28 +227,89 @@ class ClaimController extends Controller
|
|||
return \response()->json($models);
|
||||
}
|
||||
|
||||
|
||||
// * EXPORT
|
||||
|
||||
/**
|
||||
* CSV File headers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $header = [
|
||||
"Prénom NOM",
|
||||
"Email",
|
||||
"Adresse",
|
||||
"Date de création",
|
||||
"Sujet",
|
||||
"Statut",
|
||||
"Message",
|
||||
"Pièce jointe",
|
||||
];
|
||||
|
||||
public function export(ExportClaimRequest $request)
|
||||
{
|
||||
$claims = Claim::query()->whereIn('id', $request->validated('claimList'))->get();
|
||||
$brandNames = Brand::query()
|
||||
->whereIn(
|
||||
'id',
|
||||
\collect($claims)
|
||||
->pluck('brand_id')
|
||||
->unique()
|
||||
)->pluck('name')
|
||||
->toArray();
|
||||
$format = ClaimExportFormat::from($request->validated('format'));
|
||||
|
||||
// dd($brandNames);
|
||||
\dispatch(new ExportClaimsAsCsv($request->validated('email'), $brandNames, $claims));
|
||||
if ($format->equals(ClaimExportFormat::csv)) {
|
||||
$csvlines[] = $this->header;
|
||||
foreach ($claims as $claim) {
|
||||
$csvlines[] = $this->fillLine($claim);
|
||||
}
|
||||
|
||||
return \redirect()
|
||||
->back()
|
||||
->with('success', trans("Le traitement de l'export partiel a été lancé. Si vous n'avez pas recu de mail
|
||||
cela signifie qu'une erreur est survenue et nous sommes au courant."));
|
||||
return new StreamedResponse(function() use ($csvlines) {
|
||||
$this->array2csv($csvlines, ';');
|
||||
}, 200, [
|
||||
'Content-Type' => 'text/csv',
|
||||
'Content-Disposition' => 'attachment; filename="export.csv"',
|
||||
]);
|
||||
} elseif ($format->equals(ClaimExportFormat::pdf)) {
|
||||
$pdf = Pdf::loadView('bo.pages.claims.pdf', [
|
||||
'claimModels' => $claims
|
||||
]);
|
||||
return $pdf->download('export.pdf');
|
||||
};
|
||||
|
||||
return back()->with('error', __('Une erreur est survenue lors de l\'export. Veuillez réessayer en rafraîchissant la page.'));
|
||||
}
|
||||
|
||||
private function array2csv(
|
||||
array $lines,
|
||||
string $delimiter = ',',
|
||||
string $enclosure = '"',
|
||||
string $escape_char = "\\"
|
||||
){
|
||||
$f = fopen('php://output', 'w');
|
||||
|
||||
// UTF-8 BOM.
|
||||
$BOM = "\xEF\xBB\xBF";
|
||||
fwrite($f, $BOM);
|
||||
|
||||
foreach ($lines as $item) {
|
||||
fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
|
||||
}
|
||||
|
||||
fclose($f);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill one line for csv
|
||||
* @param \App\Models\Claim $claim
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function fillLine(Claim $claim)
|
||||
{
|
||||
$oneline = [
|
||||
sprintf('%s %s', $claim->first_name, Str::upper($claim->last_name)),
|
||||
$claim->email,
|
||||
sprintf('%s, %s, %s', $claim->address, $claim->postcode, $claim->city),
|
||||
$claim->created_at->toDateTimeString(),
|
||||
$claim->claimSubject->label,
|
||||
$claim->status->label(),
|
||||
$claim->message,
|
||||
asset($claim->file),
|
||||
];
|
||||
return $oneline;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Claims;
|
||||
|
||||
use App\Enums\Claims\ClaimResponseType;
|
||||
use App\Enums\Claims\ClaimStatus;
|
||||
use App\Enums\Claims\ClaimType;
|
||||
use App\Enums\Claims\ClaimExportFormat;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ExportClaimRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -35,7 +33,10 @@ class ExportClaimRequest extends FormRequest
|
|||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
'format' => [
|
||||
'required',
|
||||
Rule::enum(ClaimExportFormat::class)
|
||||
],
|
||||
'claimList' => 'required|array',
|
||||
'claimList.*' => 'required|numeric|exists:claims,id',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,134 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Mail\ExportClaims;
|
||||
use App\Models\Claim;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ExportClaimsAsCsv implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use SerializesModels;
|
||||
|
||||
|
||||
/**
|
||||
* CSV File headers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $header = [
|
||||
"Prénom NOM",
|
||||
"Email",
|
||||
"Adresse",
|
||||
"Date de création",
|
||||
"Sujet",
|
||||
"Statut",
|
||||
"Message",
|
||||
"Pièce jointe",
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(private string $recipient, private array $brandNames, private $claims)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$disk = Storage::disk('export');
|
||||
|
||||
$disk->deleteDirectory('export_claims');
|
||||
$disk->makeDirectory('export_claims');
|
||||
|
||||
// Insertion de la ligne d'en-têtes.
|
||||
$csvlines[] = $this->header;
|
||||
foreach ($this->claims as $inscription) {
|
||||
$csvlines[] = $this->fillLine($inscription);
|
||||
}
|
||||
|
||||
$data = $this->array2csv($csvlines, ";");
|
||||
|
||||
$uuid = Str::uuid();
|
||||
$fileName = date('d-m-Y') . '-' . $uuid . '.csv';
|
||||
|
||||
$disk->put("export_claims/{$fileName}", $data);
|
||||
|
||||
if (!$disk->exists("export_claims/{$fileName}")) {
|
||||
throw new \RuntimeException(
|
||||
"The CSV file 'export_claims/{$fileName}' has not been created."
|
||||
);
|
||||
}
|
||||
|
||||
$brandNamesString = implode(', ', $this->brandNames);
|
||||
|
||||
Mail::to($this->recipient)->send(new ExportClaims($fileName, $brandNamesString));
|
||||
}
|
||||
|
||||
/**
|
||||
* fill one line for csv
|
||||
* @param \App\Models\Claim $claim
|
||||
*
|
||||
* @return array
|
||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh, Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||
*/
|
||||
private function fillLine(Claim $claim)
|
||||
{
|
||||
// @phpcs:enable
|
||||
$oneline = [
|
||||
sprintf('%s %s', $claim->first_name, Str::upper($claim->last_name)),
|
||||
$claim->email,
|
||||
$claim->address . "," . $claim->postcode . "," . $claim->city,
|
||||
$claim->created_at->toDateTimeString(),
|
||||
$claim->claimSubject->label,
|
||||
$claim->status->label(),
|
||||
$claim->message,
|
||||
asset($claim->file),
|
||||
];
|
||||
return $oneline;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts an array to a csv stream
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $delimiter
|
||||
* @param string $enclosure
|
||||
* @param string $escape_char
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function array2csv(
|
||||
array $data,
|
||||
string $delimiter = ',',
|
||||
string $enclosure = '"',
|
||||
string $escape_char = "\\"
|
||||
) {
|
||||
$f = fopen('php://memory', 'r+');
|
||||
|
||||
// UTF-8 BOM.
|
||||
$BOM = "\xEF\xBB\xBF";
|
||||
fwrite($f, $BOM);
|
||||
|
||||
foreach ($data as $item) {
|
||||
fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
|
||||
}
|
||||
rewind($f);
|
||||
return stream_get_contents($f);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ExportClaims extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct(private string $fileName, private string $brandName)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: sprintf('Export des réclamations - %s', $this->brandName),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'mail.export-claims',
|
||||
text: 'mail.export-claims-plain'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [
|
||||
Attachment::fromStorageDisk('export', "export_claims/{$this->fileName}")
|
||||
->as(sprintf(
|
||||
'export-reclas-%s.csv',
|
||||
now()->format('Y-m-d')
|
||||
))
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -106,6 +106,18 @@ class ClaimPolicy
|
|||
return $this->checkOnlyMinAdminOrInUserBrands($authUser, $claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a Claim.
|
||||
*
|
||||
* @param \App\Models\User $authUser
|
||||
* @param \App\Models\Claim $claim
|
||||
* @return boolean
|
||||
*/
|
||||
public function export(User $authUser, Claim $claim): bool
|
||||
{
|
||||
return $this->checkOnlyMinAdminOrInUserBrands($authUser, $claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user an access a specific resource.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
"24slides/laravel-saml2": "^2.4",
|
||||
"arondeparon/laravel-request-sanitizer": "^5.0",
|
||||
"axlon/laravel-postal-code-validation": "^3.2",
|
||||
"barryvdh/laravel-dompdf": "^3.1",
|
||||
"diglactic/laravel-breadcrumbs": "^9.0",
|
||||
"doctrine/dbal": "^3.0",
|
||||
"doctrine/inflector": "^2.0",
|
||||
|
|
|
|||
367
composer.lock
generated
367
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c078e9a537be5c78427890f22fc24612",
|
||||
"content-hash": "f04361d9a00c60112340a92b68293a68",
|
||||
"packages": [
|
||||
{
|
||||
"name": "24slides/laravel-saml2",
|
||||
|
|
@ -210,6 +210,83 @@
|
|||
},
|
||||
"time": "2024-09-10T15:23:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-dompdf",
|
||||
"version": "v3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-dompdf.git",
|
||||
"reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d",
|
||||
"reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dompdf/dompdf": "^3.0",
|
||||
"illuminate/support": "^9|^10|^11|^12",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"larastan/larastan": "^2.7|^3.0",
|
||||
"orchestra/testbench": "^7|^8|^9|^10",
|
||||
"phpro/grumphp": "^2.5",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
|
||||
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
|
||||
},
|
||||
"providers": [
|
||||
"Barryvdh\\DomPDF\\ServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Barryvdh\\DomPDF\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A DOMPDF Wrapper for Laravel",
|
||||
"keywords": [
|
||||
"dompdf",
|
||||
"laravel",
|
||||
"pdf"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
|
||||
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://fruitcake.nl",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-13T15:07:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.12.1",
|
||||
|
|
@ -995,6 +1072,161 @@
|
|||
],
|
||||
"time": "2024-02-05T11:56:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/dompdf",
|
||||
"version": "v3.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/dompdf.git",
|
||||
"reference": "db712c90c5b9868df3600e64e68da62e78a34623"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623",
|
||||
"reference": "db712c90c5b9868df3600e64e68da62e78a34623",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dompdf/php-font-lib": "^1.0.0",
|
||||
"dompdf/php-svg-lib": "^1.0.0",
|
||||
"ext-dom": "*",
|
||||
"ext-mbstring": "*",
|
||||
"masterminds/html5": "^2.0",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-gd": "*",
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"mockery/mockery": "^1.3",
|
||||
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gd": "Needed to process images",
|
||||
"ext-gmagick": "Improves image processing performance",
|
||||
"ext-imagick": "Improves image processing performance",
|
||||
"ext-zlib": "Needed for pdf stream compression"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dompdf\\": "src/"
|
||||
},
|
||||
"classmap": [
|
||||
"lib/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The Dompdf Community",
|
||||
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||
}
|
||||
],
|
||||
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||
"homepage": "https://github.com/dompdf/dompdf",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||
"source": "https://github.com/dompdf/dompdf/tree/v3.1.4"
|
||||
},
|
||||
"time": "2025-10-29T12:43:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/php-font-lib",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FontLib\\": "src/FontLib"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The FontLib Community",
|
||||
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||
}
|
||||
],
|
||||
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
|
||||
},
|
||||
"time": "2024-12-02T14:37:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/php-svg-lib",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"sabberworm/php-css-parser": "^8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Svg\\": "src/Svg"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The SvgLib Community",
|
||||
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||
}
|
||||
],
|
||||
"description": "A library to read, parse and export to PDF SVG files.",
|
||||
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
|
||||
},
|
||||
"time": "2024-04-29T13:26:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
"version": "v3.4.0",
|
||||
|
|
@ -3330,6 +3562,73 @@
|
|||
],
|
||||
"time": "2024-12-08T08:18:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Masterminds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "technosophos@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "matt@mattfarina.com"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "goetas@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"dom",
|
||||
"html",
|
||||
"parser",
|
||||
"querypath",
|
||||
"serializer",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
|
||||
},
|
||||
"time": "2025-07-25T09:04:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mews/purifier",
|
||||
"version": "3.4.2",
|
||||
|
|
@ -5115,6 +5414,72 @@
|
|||
},
|
||||
"time": "2024-11-20T21:13:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabberworm/php-css-parser",
|
||||
"version": "v8.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
|
||||
"rawr/cross-data-providers": "^2.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "9.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sabberworm\\CSS\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Raphael Schweikert"
|
||||
},
|
||||
{
|
||||
"name": "Oliver Klee",
|
||||
"email": "github@oliverklee.de"
|
||||
},
|
||||
{
|
||||
"name": "Jake Hotson",
|
||||
"email": "jake.github@qzdesign.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "Parser for CSS Files written in PHP",
|
||||
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
|
||||
"keywords": [
|
||||
"css",
|
||||
"parser",
|
||||
"stylesheet"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
|
||||
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0"
|
||||
},
|
||||
"time": "2025-07-11T13:20:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sentry/sentry",
|
||||
"version": "4.10.0",
|
||||
|
|
|
|||
|
|
@ -67,14 +67,6 @@ return [
|
|||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
'export' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/export'),
|
||||
'visibility' => 'private',
|
||||
'throw' => true,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ return [
|
|||
'delete' => 'delete',
|
||||
'save' => 'save',
|
||||
'edit' => 'edit',
|
||||
'export' => 'export',
|
||||
],
|
||||
|
||||
'helpers' => [
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ return [
|
|||
'delete' => 'supprimer',
|
||||
'save' => 'sauvegarder',
|
||||
'edit' => 'mettre à jour',
|
||||
'export' => 'exporter',
|
||||
],
|
||||
|
||||
'helpers' => [
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
// Type for 'bootstrap modal show' event. Needed for 'relatedTarget'.
|
||||
interface BootstrapModalShowEvent extends CustomEvent {
|
||||
relatedTarget: HTMLElement;
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const exportForm = document.getElementById("claimExportForm");
|
||||
const exportFormBtn = document.getElementById("claimExportFormBtn");
|
||||
const exportFormBtnInside = document.getElementById("claimExportFormBtnInside");
|
||||
const exportFormModal = document.getElementById("exportModal");
|
||||
const claimListInputs = document.getElementsByClassName("claim-list-input");
|
||||
|
||||
if (!exportForm || !exportFormBtn || !exportFormBtnInside || !(exportForm instanceof HTMLFormElement)) {
|
||||
if (!exportFormModal || !claimListInputs) {
|
||||
return;
|
||||
}
|
||||
|
||||
exportFormBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
exportFormModal.addEventListener("show.bs.modal", (event) => {
|
||||
const customEvent = event as BootstrapModalShowEvent;
|
||||
const button = customEvent.relatedTarget as HTMLElement;
|
||||
const datas = button.getAttribute("data-bs-claim-list");
|
||||
|
||||
exportFormBtnInside.click();
|
||||
for (const claimListInput of claimListInputs) {
|
||||
(claimListInput as HTMLInputElement).value = String(datas);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ import {
|
|||
faEye,
|
||||
faEyeSlash,
|
||||
faFile,
|
||||
faFileCsv,
|
||||
faFileExport,
|
||||
faFilePdf,
|
||||
faFolderOpen,
|
||||
faListUl,
|
||||
faPaintRoller,
|
||||
|
|
@ -59,6 +62,9 @@ library.add(
|
|||
faEye,
|
||||
faEyeSlash,
|
||||
faFile,
|
||||
faFileCsv,
|
||||
faFileExport,
|
||||
faFilePdf,
|
||||
faFolderOpen,
|
||||
faCrop,
|
||||
faQuestionCircle,
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
$selectedSubject = request()->subject ?? (isset($modelTable) ? Session::get("crud.$modelTable.subject") : null);
|
||||
@endphp
|
||||
|
||||
<div class="row align-items-center justify-content-between mb-3">
|
||||
<div class="col-3">
|
||||
<button class="btn btn-success d-flex flex-column" id="export-claim" data-bs-toggle="modal" data-bs-target="#exportModal">
|
||||
<i class="fa-solid fa-file"></i>
|
||||
{{ __('Export')}}
|
||||
<div class="row align-items-center mb-3">
|
||||
<div class="col-1">
|
||||
<button class="btn btn-primary d-flex flex-column" id="export-btn" data-bs-toggle="modal" data-bs-target="#exportModal" data-bs-claim-list="@json($claimModels->pluck('id')->toArray())">
|
||||
<i class="fa-solid fa-file-export"></i>
|
||||
{{ __('Exporter')}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="col-3 offset-8">
|
||||
<form action="{{ request()->fullUrlWithQuery(['rstFltrs' => null]) }}" class="row gx-2 mb-2">
|
||||
{{-- SUBJECT SELECT --}}
|
||||
<select class="form-select mb-1 mb-lg-0"
|
||||
|
|
@ -34,27 +34,20 @@
|
|||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{{ route('bo.claims.export') }}" class="row gx-2 mb-2" method="POST" id="claimExportForm">
|
||||
@csrf
|
||||
{{-- EMAIL INPUT --}}
|
||||
<label for="exportEmail" class="form-label">{{ __('Destinataire de l\'export') }} </label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
name="email"
|
||||
id="exportEmail"
|
||||
required
|
||||
pattern="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
|
||||
title="Veuillez saisir une adresse email valide">
|
||||
<div id="emailHelp" class="form-text">{{ __('L\'export sera envoyé en .csv à cette adresse mail.')}}</div>
|
||||
<button type="submit" class="d-none" id="claimExportFormBtnInside"></button>
|
||||
|
||||
<input hidden name="claimList" value="@json($claimModels->pluck('id')->toArray())">
|
||||
</form>
|
||||
@foreach(\App\Enums\Claims\ClaimExportFormat::cases() as $supportedFormat)
|
||||
<form action="{{ route('bo.claims.export', ['format' => $supportedFormat->name]) }}" class="row gx-2 mb-2" method="POST">
|
||||
@csrf
|
||||
<input hidden name="format" value="{{ $supportedFormat }}">
|
||||
<input hidden class="claim-list-input" name="claimList" value="">
|
||||
<button class="btn btn-{{ $supportedFormat->class()}} d-flex flex-column" id="export-{{ $supportedFormat->name }}" type="submit">
|
||||
<i class="{{ $supportedFormat->picto() }}"></i>
|
||||
{{ __('Exporter en .:format', ['format' => $supportedFormat->name])}}
|
||||
</button>
|
||||
</form>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ __('Fermer')}}</button>
|
||||
<button type="button" class="btn btn-primary" type="submit" id="claimExportFormBtn">{{ __('Exporter')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -60,6 +60,16 @@
|
|||
<i class="fa-solid fa-comments"></i>
|
||||
</a>
|
||||
@endcan
|
||||
@can('export', $claimModel)
|
||||
<a class="btn btn-secondary d-flex flex-column"
|
||||
data-bs-tooltip="tooltip"
|
||||
title="{{ str(__('crud.actions.export'))->ucfirst() }}"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#exportModal"
|
||||
data-bs-claim-list="@json([$claimModel->id])">
|
||||
<i class="fa-solid fa-file-export"></i>
|
||||
</a>
|
||||
@endcan
|
||||
</div>
|
||||
@else
|
||||
<span class="text-danger" data-bs-tooltip="tooltip" title="{{ __('list.right') }}">
|
||||
|
|
|
|||
24
resources/views/bo/pages/claims/pdf.blade.php
Normal file
24
resources/views/bo/pages/claims/pdf.blade.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<style>
|
||||
.page-break {
|
||||
page-break-after: always;
|
||||
}
|
||||
</style>
|
||||
|
||||
@foreach($claimModels as $claimModel)
|
||||
<p>{{ __('Référence') }} : {{ $claimModel->reference }} </p>
|
||||
<p>{{ __('Date de la demande') }} : {{ $claimModel->created_at->toDateString() }} </p>
|
||||
<p>{{ __('Prénom NOM') }} : {{ $claimModel->first_name }} {{ str($claimModel->last_name)->upper() }}</p>
|
||||
<p>{{ __('Email') }} : {{ $claimModel->email }} </p>
|
||||
<p>{{ __('Adresse') }} : {{ sprintf('%s, %s, %s', $claimModel->address, $claimModel->postcode, $claimModel->city) }} </p>
|
||||
<p>{{ __('Statut de la réclamation') }} : {{ $claimModel->status->label() }} </p>
|
||||
<p>{{ __('Sujet de la réclamation') }} : {{ $claimModel->claimSubject->label }} </p>
|
||||
<p>{{ __('Type de demande') }} : {{ $claimModel->type->label() }} </p>
|
||||
<p>{{ __('Marque concernée') }} : {{ $claimModel->brand->name }} </p>
|
||||
<p>{{ __('Message') }} : {{ $claimModel->message }} </p>
|
||||
<p>{{ __('Voir la pièce jointe') }} : <a target="blank" href="{{ asset($claimModel->file) }}">{{ __('Cliquez ici') }}</a> </p>
|
||||
|
||||
@if (!$loop->last)
|
||||
<div class="page-break"></div>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
Bonjour,
|
||||
|
||||
Vous trouverez ci-joint l'export des réclamations du {{ now()->isoFormat('DD\/MM\/YYYY à HH:mm') }}
|
||||
|
||||
Ceci est un message automatique, ne pas répondre.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{{-- blade-formatter-disable --}}
|
||||
@component('mail::layout')
|
||||
|
||||
# {{ __('Bonjour,') }}
|
||||
|
||||
{{ __('Vous trouverez ci-joint l\'export des réclamations du') }} {{ now()->isoFormat('DD\/MM\/YYYY à HH:mm') }}
|
||||
|
||||
{{ __('Ceci est un message automatique, ne pas répondre.') }}
|
||||
|
||||
@endcomponent
|
||||
|
|
@ -93,7 +93,8 @@ Route::middleware(['throttle:web', 'admin-secure'])->prefix('bo')->name('bo.')->
|
|||
// * CLAIMS.
|
||||
Route::resource('claims', ClaimController::class)->only(['index', 'edit', 'update']);
|
||||
Route::post('claims/{claim}/answer', [ClaimController::class, 'answer'])->name('claims.answer');
|
||||
Route::post('claims/export', [ClaimController::class, 'export'])->name('claims.export');
|
||||
Route::post('claims/export', [ClaimController::class, 'export'])
|
||||
->name('claims.export');
|
||||
|
||||
// * CLAIM SUBJECTS.
|
||||
Route::get('/{brand}/claim_subjects/json/paginate', [ClaimController::class, 'jsonClaimPaginateModels'])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue