mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-07-31 21:51:38 +00:00
Add CSV export for Project BOM tables (#1442)
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / merge (push) Blocked by required conditions
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / merge (push) Blocked by required conditions
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / merge (push) Blocked by required conditions
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / merge (push) Blocked by required conditions
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
* add Export AS CSV button to the Project BOM Entry tab * added Export as CSV translation * add service file for BOM exporter * added controller for handling exporting project BOM data as CSV file * added tests for Export as CSV controller and exporter code * remove hierarchical paths from being exported in CSV to match datatable format * Fixed message id * Use stimulus functions to refer to stimulus controller --------- Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
This commit is contained in:
parent
af2eae75d4
commit
be03d1f503
7 changed files with 1610 additions and 17 deletions
|
|
@ -46,6 +46,10 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use App\Helpers\FilenameSanatizer;
|
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use App\Services\ImportExportSystem\ProjectBomExporter;
|
||||
|
||||
use function Symfony\Component\Translation\t;
|
||||
|
||||
|
|
@ -128,6 +132,148 @@ class ProjectController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
path: '/{id}/bom/export',
|
||||
name: 'project_bom_export',
|
||||
requirements: ['id' => '\d+'],
|
||||
methods: ['POST']
|
||||
)]
|
||||
public function exportBOM(
|
||||
Project $project,
|
||||
Request $request,
|
||||
ProjectBomExporter $projectBomExporter,
|
||||
SerializerInterface $serializer,
|
||||
): Response {
|
||||
$this->denyAccessUnlessGranted('read', $project);
|
||||
|
||||
/*
|
||||
* First run the normal BOM DataTable callback. This applies exactly the
|
||||
* same project restriction, search criteria and active column ordering
|
||||
* as the displayed table.
|
||||
*
|
||||
* We only use its hidden ID column. Rendered cell contents are discarded.
|
||||
*/
|
||||
$table = $this->dataTableFactory->createFromType(
|
||||
ProjectBomEntriesDataTable::class,
|
||||
['project' => $project],
|
||||
);
|
||||
|
||||
$request->request->set('_dt', $table->getName());
|
||||
/*
|
||||
* Export every row matching the current search/filter.
|
||||
* Ignore the page currently displayed in the browser.
|
||||
*/
|
||||
$request->request->set('start', 0);
|
||||
$request->request->set('length', -1);
|
||||
|
||||
$table->handleRequest($request);
|
||||
|
||||
if (!$table->isCallback()) {
|
||||
throw new \RuntimeException(
|
||||
'The BOM export request was not recognised as a DataTable callback.'
|
||||
);
|
||||
}
|
||||
|
||||
$tableResponse = $table->getResponse();
|
||||
|
||||
/** @var array{
|
||||
* data?: list<array<string, mixed>>
|
||||
* } $payload
|
||||
*/
|
||||
$payload = json_decode(
|
||||
$tableResponse->getContent() ?: '{}',
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR,
|
||||
);
|
||||
|
||||
/*
|
||||
* The DataTable already contains a hidden ID column. Collect those IDs in
|
||||
* their returned order. That order is the currently selected table order.
|
||||
*/
|
||||
$orderedIds = [];
|
||||
|
||||
foreach ($payload['data'] ?? [] as $tableRow) {
|
||||
$id = filter_var(
|
||||
$tableRow['id'] ?? null,
|
||||
FILTER_VALIDATE_INT,
|
||||
);
|
||||
|
||||
if ($id !== false) {
|
||||
$orderedIds[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$columns = array_values(
|
||||
array_filter(
|
||||
$request->request->all('exportColumns'),
|
||||
static fn(mixed $column): bool => is_string($column),
|
||||
)
|
||||
);
|
||||
|
||||
$labels = array_values(
|
||||
array_filter(
|
||||
$request->request->all('exportLabels'),
|
||||
static fn(mixed $label): bool => is_string($label),
|
||||
)
|
||||
);
|
||||
|
||||
if ($columns === []) {
|
||||
throw new \InvalidArgumentException(
|
||||
'No columns were specified for BOM export.'
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reload raw entities from Doctrine. The exporter verifies that every
|
||||
* entry belongs to this project and restores the DataTable's ID order.
|
||||
*/
|
||||
$entries = $projectBomExporter->getOrderedEntries(
|
||||
$project,
|
||||
$orderedIds,
|
||||
);
|
||||
|
||||
$rows = [];
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$rows[] = $projectBomExporter->createRow(
|
||||
$entry,
|
||||
$columns,
|
||||
$labels,
|
||||
);
|
||||
}
|
||||
|
||||
$csv = $serializer->serialize($rows, 'csv', [
|
||||
'as_collection' => true,
|
||||
'csv_delimiter' => ';',
|
||||
]);
|
||||
|
||||
$filename = FilenameSanatizer::sanitizeFilename(
|
||||
sprintf(
|
||||
'project_%s_bom.csv',
|
||||
$project->getName(),
|
||||
)
|
||||
);
|
||||
|
||||
$response = new Response($csv);
|
||||
|
||||
$response->headers->set(
|
||||
'Content-Type',
|
||||
'text/csv; charset=UTF-8',
|
||||
);
|
||||
|
||||
$response->headers->set(
|
||||
'Content-Disposition',
|
||||
$response->headers->makeDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
$filename,
|
||||
'project_bom.csv',
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}/import_bom', name: 'project_import_bom', requirements: ['id' => '\d+'])]
|
||||
public function importBOM(
|
||||
Request $request,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue